diff --git a/swarm/storage/binarymerkle.go b/swarm/storage/binarymerkle.go index 0c31db1698..972dea17cc 100644 --- a/swarm/storage/binarymerkle.go +++ b/swarm/storage/binarymerkle.go @@ -6,13 +6,21 @@ import ( "bytes" _ "crypto/sha256" "encoding/binary" + "errors" "fmt" + "hash" + "io" "github.com/ethereum/go-ethereum/crypto/sha3" ) var hashFunc Hasher = sha3.NewKeccak256 //default hasher +type state struct { + btree BTree + root Root +} + // A merkle tree for a user that stores the entire tree // Specifically this tree is left a leaning balanced binary tree // Where each node holds the hash of its leaves @@ -313,3 +321,64 @@ func checkNode(height int, proof [][]byte, index, count uint64) ([]byte, bool) { hash := h.Sum(make([]byte, 0)) return hash, ok } + +// ShakeHash defines the interface to hash functions that +// support arbitrary-length output. +type BMTHash interface { + // Write absorbs more data into the hash's state. It panics if input is + // written to it after output has been read from it. + io.Writer + + // Read reads more output from the hash; reading affects the hash's + // state. (ShakeHash.Read is thus very different from Hash.Sum) + // It never returns an error. + io.Reader + + // Clone returns a copy of the ShakeHash in its current state. + Clone() BMTHash + + // Reset resets the ShakeHash to its initial state. + Reset() +} + +// Reset clears the internal state by zeroing the sponge state and +func (d *state) Reset() { + d.root = Root{Count: 0, Base: nil} + d.btree = BTree{count: 0, root: nil, rootHash: nil} +} + +// Write absorbs more data into the hash's state. It produces an error +// if more data is written to the ShakeHash after writing +func (d *state) Write(p []byte) (written int, err error) { + tree, r, count, err1 := BuildBMT(hashFunc, p, 32) + d.btree = *tree + d.root = *r + + if err1 != 0 { + err = errors.New("bmt write error") + } + + return count, err +} + +func (d *state) Get(p []byte) (written int) { + return 3 +} + +// Sum return the root hash of the BMT +func (d *state) Sum(in []byte) []byte { + return d.root.Base +} + +// BlockSize returns the rate of sponge underlying this hash function. +func (d *state) BlockSize() int { return 0 } + +// Size returns the output size of the hash function in bytes. +func (d *state) Size() int { return 32 } + +// NewBMTSHA3 creates a new BMT hash +func NewBMTSHA3() hash.Hash { + tmpbtree := BTree{count: 0, root: nil, rootHash: nil} + troot := Root{Count: 0, Base: nil} + return &state{btree: tmpbtree, root: troot} +} diff --git a/swarm/storage/binarymerkle_test.go b/swarm/storage/binarymerkle_test.go index 98ddc13fbe..28faea5032 100644 --- a/swarm/storage/binarymerkle_test.go +++ b/swarm/storage/binarymerkle_test.go @@ -41,6 +41,35 @@ func TestGetHeight2(t *testing.T) { } } +func TestBuildBMT3(t *testing.T) { + + // Grab some data to make the tree out of, and partition + data, err := ioutil.ReadFile("binarymerkle_test.go") // assume testdata exists + if err != nil { + fmt.Println(err) + return + } + var thashFunc = MakeHashFunc("BMTSHA3") + var h = thashFunc() + h.Reset() + h.Write(data) + var key = h.Sum(nil) + + fmt.Println(key) + + // for i := 0; i < count; i++ { + // p := tree.InclusionProof(i) + // + // fmt.Println(p) + // + // ok := r.CheckProof(sha3.NewKeccak256, p, i) + // if !ok { + // t.Errorf("proof %d failed", i) + // } + // } + // fmt.Println("done") +} + func TestBuildBMT(t *testing.T) { // Grab some data to make the tree out of, and partition @@ -50,7 +79,7 @@ func TestBuildBMT(t *testing.T) { return } - tree, r, count, err1 := BuildBMT(sha3.NewKeccak256, data, 32) + tree, r, count, err1 := BuildBMT(sha3.NewKeccak256, data, 1) switch err1 { case -1: @@ -61,7 +90,7 @@ func TestBuildBMT(t *testing.T) { t.Errorf("BMT leaf count validation error") return case 0: - fmt.Println("Build BMT OK") + fmt.Println("Build BMT OK ", count) } fmt.Println(tree.Root()) @@ -76,6 +105,7 @@ func TestBuildBMT(t *testing.T) { t.Errorf("proof %d failed", i) } } + fmt.Println("done") } func TestBuildBMT2(t *testing.T) { @@ -88,7 +118,7 @@ func TestBuildBMT2(t *testing.T) { } fmt.Println(len(data)) - blocks := splitData(data, 32) + blocks := splitData(data, 2) count := len(blocks) diff --git a/swarm/storage/chunker.go b/swarm/storage/chunker.go index d55875369d..a2eda3fdf7 100644 --- a/swarm/storage/chunker.go +++ b/swarm/storage/chunker.go @@ -51,7 +51,8 @@ data_{i} := size(subtree_{i}) || key_{j} || key_{j+1} .... || key_{j+n-1} */ const ( - defaultHash = "SHA3" // http://golang.org/pkg/hash/#Hash + //defaultHash = "SHA3" + defaultHash = "BMTSHA3" // http://golang.org/pkg/hash/#Hash // defaultHash = "SHA256" // http://golang.org/pkg/hash/#Hash defaultBranches int64 = 128 // hashSize int64 = hasherfunc.New().Size() // hasher knows about its own length in bytes diff --git a/swarm/storage/types.go b/swarm/storage/types.go index cc5ded931d..1afb82e48e 100644 --- a/swarm/storage/types.go +++ b/swarm/storage/types.go @@ -83,6 +83,8 @@ func MakeHashFunc(hash string) Hasher { return crypto.SHA256.New case "SHA3": return sha3.NewKeccak256 + case "BMTSHA3": + return NewBMTSHA3 } return nil }