mirror of
https://github.com/vbatts/merkle.git
synced 2024-11-27 08:45:39 +00:00
progress on a streaming interface
This commit is contained in:
parent
949cec0dce
commit
fd362c6aa5
3 changed files with 74 additions and 18 deletions
22
node.go
22
node.go
|
@ -1,23 +1,22 @@
|
||||||
package merkle
|
package merkle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto/sha1"
|
||||||
_ "crypto/sha1" // to satisfy our DefaultHash
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultHash is for checksum of blocks and nodes
|
// DefaultHashMaker is for checksum of blocks and nodes
|
||||||
DefaultHash = crypto.SHA1
|
DefaultHashMaker = func() hash.Hash { return sha1.New() }
|
||||||
)
|
)
|
||||||
|
|
||||||
// HashMaker produces a new has for use in making checksums
|
// HashMaker produces a new has for use in making checksums
|
||||||
type HashMaker func() hash.Hash
|
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 {
|
func NewNode() *Node {
|
||||||
return NewNodeHash(DefaultHash.New)
|
return NewNodeHash(DefaultHashMaker)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNodeHash returns a new Node using the provided crypto.Hash for checksums
|
// 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}
|
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.
|
// Node is a fundamental part of the tree.
|
||||||
type Node struct {
|
type Node struct {
|
||||||
hash HashMaker
|
hash HashMaker
|
||||||
checksum []byte
|
checksum []byte
|
||||||
Parent, Left, Right *Node
|
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)
|
// IsLeaf indicates this node is for specific block (and has no children)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
func TestNodeSums(t *testing.T) {
|
func TestNodeSums(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
nodes []*Node
|
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`
|
words = `Who were expelled from the academy for crazy & publishing obscene odes on the windows of the skull`
|
||||||
expectedChecksum = "819fe8fed7a46900bd0613344c5ba2be336c74db"
|
expectedChecksum = "819fe8fed7a46900bd0613344c5ba2be336c74db"
|
||||||
)
|
)
|
||||||
|
@ -19,7 +19,7 @@ func TestNodeSums(t *testing.T) {
|
||||||
t.Errorf("on word %q, encountered %s", word, err)
|
t.Errorf("on word %q, encountered %s", word, err)
|
||||||
}
|
}
|
||||||
sum := h.Sum(nil)
|
sum := h.Sum(nil)
|
||||||
nodes = append(nodes, &Node{checksum: sum, hash: DefaultHash.New})
|
nodes = append(nodes, &Node{checksum: sum, hash: DefaultHashMaker})
|
||||||
}
|
}
|
||||||
|
|
||||||
newNodes := nodes
|
newNodes := nodes
|
||||||
|
|
62
stream.go
62
stream.go
|
@ -1,14 +1,18 @@
|
||||||
package merkle
|
package merkle
|
||||||
|
|
||||||
import "hash"
|
import (
|
||||||
|
"hash"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
// NewHash provides a hash.Hash to generate a merkle.Tree checksum, given a
|
// 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
|
// HashMaker for the checksums of the blocks written and the blockSize of each
|
||||||
// block per node in the tree.
|
// 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 := new(merkleHash)
|
||||||
mh.blockSize = merkleBlockSize
|
mh.blockSize = merkleBlockLength
|
||||||
mh.hm = hm
|
mh.hm = hm
|
||||||
|
mh.tree = &Tree{Nodes: []*Node{}, BlockLength: merkleBlockLength}
|
||||||
return mh
|
return mh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +23,10 @@ func NewHash(hm HashMaker, merkleBlockSize int) hash.Hash {
|
||||||
// TODO satisfy the hash.Hash interface
|
// TODO satisfy the hash.Hash interface
|
||||||
type merkleHash struct {
|
type merkleHash struct {
|
||||||
blockSize int
|
blockSize int
|
||||||
tree Tree
|
tree *Tree
|
||||||
hm HashMaker
|
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.
|
// 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.
|
// if that last block was complete, then no worries. start the next node.
|
||||||
func (mh *merkleHash) Sum(b []byte) []byte {
|
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) {
|
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() {
|
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) BlockSize() int { return mh.hm().BlockSize() }
|
||||||
func (mh *merkleHash) Size() int { return mh.hm().Size() }
|
func (mh *merkleHash) Size() int { return mh.hm().Size() }
|
||||||
|
|
Loading…
Reference in a new issue