diff --git a/node.go b/node.go index b46007c..678774c 100644 --- a/node.go +++ b/node.go @@ -1,23 +1,22 @@ package merkle import ( - "crypto" - _ "crypto/sha1" // to satisfy our DefaultHash + "crypto/sha1" "fmt" "hash" ) var ( - // DefaultHash is for checksum of blocks and nodes - DefaultHash = crypto.SHA1 + // DefaultHashMaker is for checksum of blocks and nodes + DefaultHashMaker = func() hash.Hash { return sha1.New() } ) // HashMaker produces a new has for use in making checksums type HashMaker func() hash.Hash -// NewNode returns a new Node with the DefaultHash for checksums +// NewNode returns a new Node with the DefaultHashMaker for checksums func NewNode() *Node { - return NewNodeHash(DefaultHash.New) + return NewNodeHash(DefaultHashMaker) } // NewNodeHash returns a new Node using the provided crypto.Hash for checksums @@ -25,13 +24,22 @@ func NewNodeHash(h HashMaker) *Node { return &Node{hash: h} } +// NewNodeHashBlock returns a new Node using the provided crypto.Hash, and calculates the block's checksum +func NewNodeHashBlock(h HashMaker, b []byte) *Node { + n := &Node{hash: h} + h1 := n.hash() + h1.Write(b) + n.checksum = h1.Sum(nil) + return n +} + // Node is a fundamental part of the tree. type Node struct { hash HashMaker checksum []byte Parent, Left, Right *Node - pos int // XXX maybe keep their order when it is a direct block's hash + //pos int // XXX maybe keep their order when it is a direct block's hash } // IsLeaf indicates this node is for specific block (and has no children) diff --git a/node_test.go b/node_test.go index 65c6b89..64acd1f 100644 --- a/node_test.go +++ b/node_test.go @@ -9,7 +9,7 @@ import ( func TestNodeSums(t *testing.T) { var ( nodes []*Node - h = DefaultHash.New() + h = DefaultHashMaker() words = `Who were expelled from the academy for crazy & publishing obscene odes on the windows of the skull` expectedChecksum = "819fe8fed7a46900bd0613344c5ba2be336c74db" ) @@ -19,7 +19,7 @@ func TestNodeSums(t *testing.T) { t.Errorf("on word %q, encountered %s", word, err) } sum := h.Sum(nil) - nodes = append(nodes, &Node{checksum: sum, hash: DefaultHash.New}) + nodes = append(nodes, &Node{checksum: sum, hash: DefaultHashMaker}) } newNodes := nodes diff --git a/stream.go b/stream.go index 7d6b2ed..ed9b708 100644 --- a/stream.go +++ b/stream.go @@ -1,14 +1,18 @@ package merkle -import "hash" +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, merkleBlockSize int) hash.Hash { +func NewHash(hm HashMaker, merkleBlockLength int) hash.Hash { mh := new(merkleHash) - mh.blockSize = merkleBlockSize + mh.blockSize = merkleBlockLength mh.hm = hm + mh.tree = &Tree{Nodes: []*Node{}, BlockLength: merkleBlockLength} return mh } @@ -18,9 +22,11 @@ func NewHash(hm HashMaker, merkleBlockSize int) hash.Hash { // TODO satisfy the hash.Hash interface type merkleHash struct { - blockSize int - tree Tree - hm HashMaker + 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. @@ -32,15 +38,57 @@ type merkleHash struct { // // if that last block was complete, then no worries. start the next node. func (mh *merkleHash) Sum(b []byte) []byte { - return nil + // 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) { - return 0, nil + // 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.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() }