merkle/stream.go

95 lines
2.7 KiB
Go

package merkle
import (
"hash"
"log"
)
// 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.
func NewHash(hm HashMaker, merkleBlockLength int) hash.Hash {
mh := new(merkleHash)
mh.blockSize = merkleBlockLength
mh.hm = hm
mh.tree = &Tree{Nodes: []*Node{}, BlockLength: merkleBlockLength}
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 {
blockSize int
tree *Tree
hm HashMaker
lastBlock []byte // as needed, for Sum()
partialLastBlock bool
}
// 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 {
// TODO check if len(mh.lastBlock) < blockSize
sum, err := mh.tree.Root().Checksum()
if err != nil {
log.Println(err)
}
return sum
}
func (mh *merkleHash) Write(b []byte) (int, error) {
// 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
}
func (mh *merkleHash) Reset() {
mh.tree = &Tree{}
mh.lastBlock = nil
}
// likely not the best to pass this through and not use our own node block
// size, but let's revisit this.
func (mh *merkleHash) BlockSize() int { return mh.hm().BlockSize() }
func (mh *merkleHash) Size() int { return mh.hm().Size() }