2015-03-19 21:47:43 +00:00
|
|
|
package merkle
|
|
|
|
|
2015-03-25 21:28:17 +00:00
|
|
|
import (
|
|
|
|
"hash"
|
|
|
|
"log"
|
|
|
|
)
|
2015-03-19 21:47:43 +00:00
|
|
|
|
|
|
|
// NewHash provides a hash.Hash to generate a merkle.Tree checksum, given a
|
|
|
|
// HashMaker for the checksums of the blocks written and the blockSize of each
|
|
|
|
// block per node in the tree.
|
2015-03-25 21:28:17 +00:00
|
|
|
func NewHash(hm HashMaker, merkleBlockLength int) hash.Hash {
|
2015-03-19 21:47:43 +00:00
|
|
|
mh := new(merkleHash)
|
2015-03-25 21:28:17 +00:00
|
|
|
mh.blockSize = merkleBlockLength
|
2015-03-19 21:47:43 +00:00
|
|
|
mh.hm = hm
|
2015-03-25 21:28:17 +00:00
|
|
|
mh.tree = &Tree{Nodes: []*Node{}, BlockLength: merkleBlockLength}
|
2015-03-19 21:47:43 +00:00
|
|
|
return mh
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO make a similar hash.Hash, that accepts an argument of a merkle.Tree,
|
|
|
|
// that will validate nodes as the new bytes are written. If a new written
|
|
|
|
// block fails checksum, then return an error on the io.Writer
|
|
|
|
|
|
|
|
// TODO satisfy the hash.Hash interface
|
|
|
|
type merkleHash struct {
|
2015-03-25 21:28:17 +00:00
|
|
|
blockSize int
|
|
|
|
tree *Tree
|
|
|
|
hm HashMaker
|
|
|
|
lastBlock []byte // as needed, for Sum()
|
|
|
|
partialLastBlock bool
|
2015-03-19 21:47:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XXX this will be tricky, as the last block can be less than the BlockSize.
|
|
|
|
// if they get the sum, it will be mh.tree.Root().Checksum() at that point.
|
|
|
|
//
|
|
|
|
// But if they continue writing, it would mean a continuation of the bytes in
|
|
|
|
// the last block. So popping the last node, and having a buffer for the bytes
|
|
|
|
// in that last partial block.
|
|
|
|
//
|
|
|
|
// if that last block was complete, then no worries. start the next node.
|
|
|
|
func (mh *merkleHash) Sum(b []byte) []byte {
|
2015-03-25 21:28:17 +00:00
|
|
|
// TODO check if len(mh.lastBlock) < blockSize
|
|
|
|
sum, err := mh.tree.Root().Checksum()
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
return sum
|
2015-03-19 21:47:43 +00:00
|
|
|
}
|
2015-03-25 21:28:17 +00:00
|
|
|
|
2015-03-19 21:47:43 +00:00
|
|
|
func (mh *merkleHash) Write(b []byte) (int, error) {
|
2015-03-25 21:28:17 +00:00
|
|
|
// basically we need to:
|
|
|
|
// * chunk these writes into blockSize
|
|
|
|
// * create Node of the sum
|
|
|
|
// * add the Node to the tree
|
|
|
|
// * stash remainder in the mh.lastBlock
|
|
|
|
|
|
|
|
var (
|
|
|
|
curBlock = make([]byte, mh.blockSize)
|
|
|
|
numBytes int = 0
|
|
|
|
numWritten int
|
|
|
|
)
|
|
|
|
if mh.lastBlock != nil && len(mh.lastBlock) > 0 {
|
|
|
|
numBytes = copy(curBlock, mh.lastBlock)
|
|
|
|
// not adding to numWritten, since these blocks were accounted for in a
|
|
|
|
// prior Write()
|
|
|
|
}
|
|
|
|
|
|
|
|
if numBytes > 0 {
|
|
|
|
copy(curBlock, b[:(mh.blockSize-numBytes)])
|
|
|
|
numWritten += (mh.blockSize - numBytes)
|
|
|
|
// TODO Node for curBlock
|
|
|
|
n := NewNodeHashBlock(mh.hm, curBlock)
|
|
|
|
_ = n
|
|
|
|
}
|
|
|
|
|
|
|
|
numBytes = len(b) - numBytes
|
|
|
|
for i := 0; i < numBytes/mh.blockSize; i++ {
|
|
|
|
// TODO Node for curBlock
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO stash (numBytes % mh.blockSize) in mh.lastBlock
|
|
|
|
|
|
|
|
// TODO if len(mh.lastBlock) < blockSize, then set that before returning
|
|
|
|
return numWritten, nil
|
2015-03-19 21:47:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (mh *merkleHash) Reset() {
|
2015-03-25 21:28:17 +00:00
|
|
|
mh.tree = &Tree{}
|
|
|
|
mh.lastBlock = nil
|
2015-03-19 21:47:43 +00:00
|
|
|
}
|
|
|
|
|
2015-03-25 21:28:17 +00:00
|
|
|
// likely not the best to pass this through and not use our own node block
|
|
|
|
// size, but let's revisit this.
|
2015-03-19 21:47:43 +00:00
|
|
|
func (mh *merkleHash) BlockSize() int { return mh.hm().BlockSize() }
|
|
|
|
func (mh *merkleHash) Size() int { return mh.hm().Size() }
|