celestiaorg / nmt

Namespaced Merkle Tree
Apache License 2.0
112 stars 39 forks source link

Inconsistency in the EmptyRoot values #196

Closed staheri14 closed 1 year ago

staheri14 commented 1 year ago

Problem

An empty root represents the root of a tree with no leaves. It is obtained using the EmptyRoot() method of the Hasher type. However, the root generated by this method may not be consistent, even when the hasher is configured identically. Below, this inconsistency is shown by an example:

nIDSzie := 1
ignoreMaxNS := true
nIDList := []byte{1, 2, 3, 4}

// Create an nmt using the above configs
tree := New(sha256.New(), NamespaceIDSize(nIDSzie), IgnoreMaxNamespace(ignoreMaxNS))
    for i, nid := range nIDList {
        namespace := bytes.Repeat([]byte{nid}, nIDSzie)
        d := append(namespace, []byte(fmt.Sprintf("leaf_%d", i))...)
        if err := tree.Push(d); err != nil {
            panic(fmt.Sprintf("unexpected error: %v", err))
        }
    }
// Calculate the empty root by accessing the `Hasher` field of the tree
expectedEmptyRoot := tree.treeHasher.EmptyRoot()

// Create  a hasher identical to the one used for the tree
hasher := NewNmtHasher(sha256.New(), namespace.IDSize(nIDSzie), ignoreMaxNS)
gotEmptyRoot := hasher.EmptyRoot()

assert.True(t, bytes.Equal(gotEmptyRoot, expectedEmptyRoot)) // it panics, they are not equal