210 lines
4.8 KiB
Go
210 lines
4.8 KiB
Go
package graviton
|
|
|
|
import (
|
|
"math/rand"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestTreeProve(t *testing.T) {
|
|
rand.Seed(100)
|
|
_, tree := setupDeterministicTree(t, 10)
|
|
|
|
key := make([]byte, 20)
|
|
value := make([]byte, 10)
|
|
rand.Read(key)
|
|
rand.Read(value)
|
|
require.NoError(t, tree.Put(key, value))
|
|
|
|
proof, err := tree.GenerateProof(key)
|
|
require.NoError(t, err)
|
|
require.True(t, proof.VerifyMembership(tree.hashSkipError(), key))
|
|
|
|
mproof := proof.Marshal()
|
|
var decoded Proof
|
|
|
|
decoded.Unmarshal(mproof)
|
|
|
|
require.True(t, decoded.VerifyMembership(tree.hashSkipError(), key))
|
|
require.False(t, decoded.VerifyNonMembership(tree.hashSkipError(), key))
|
|
|
|
// value is last 11 bytes
|
|
|
|
copy(mproof[len(mproof)-11:], []byte{0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88})
|
|
require.Error(t, decoded.Unmarshal(mproof))
|
|
|
|
// test malformed proofs, small buffer give array indexing array
|
|
wrong_proof := []byte{1, collision, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}
|
|
require.Error(t, decoded.Unmarshal(wrong_proof))
|
|
|
|
}
|
|
|
|
func TestTreeProvePersistent(t *testing.T) {
|
|
_, tree := setupDeterministicTree(t, 4)
|
|
|
|
var key = make([]byte, 10)
|
|
rand.Read(key)
|
|
require.NoError(t, tree.Put(key, key))
|
|
|
|
root := tree.hashSkipError()
|
|
require.NoError(t, tree.Commit())
|
|
|
|
proof, err := tree.GenerateProof(key)
|
|
require.NoError(t, err)
|
|
require.True(t, proof.VerifyMembership(tree.hashSkipError(), key))
|
|
|
|
require.Equal(t, key, proof.Value())
|
|
require.True(t, proof.VerifyMembership(root, key))
|
|
|
|
proof.Reset()
|
|
|
|
if len(proof.Value()) != 0 {
|
|
t.Fatalf("Proof not successfully reset.")
|
|
}
|
|
}
|
|
|
|
// these cannot be generated using exported api
|
|
func TestProveCollision(t *testing.T) {
|
|
_, tree := setupDeterministicTree(t, 0)
|
|
value := []byte("testcollision")
|
|
|
|
for i := 0; i < 8; i++ {
|
|
key := [HASHSIZE]byte{}
|
|
key[0] = 1 << uint(i)
|
|
require.NoError(t, tree.putRaw(key, nil, value))
|
|
}
|
|
|
|
key := [HASHSIZE]byte{}
|
|
key[0] = 0xf0 // this needs to be flipped if if bit prrocessing is switched
|
|
require.NoError(t, tree.putRaw(key, nil, value))
|
|
root := tree.hashSkipError()
|
|
|
|
//require.NoError(t, tree.Commit())
|
|
|
|
ckey := [HASHSIZE]byte{}
|
|
ckey[0] = 0xf8 // this needs to be flipped if if bit prrocessing is switched
|
|
proof := NewProof()
|
|
require.NoError(t, tree.generateProofRaw(ckey, proof))
|
|
|
|
require.False(t, proof.verifyMembershipRaw(root, key))
|
|
|
|
require.True(t, proof.verifyNonMembershipRaw(root, key))
|
|
|
|
}
|
|
|
|
func TestProveDeadend(t *testing.T) {
|
|
_, tree := setupDeterministicTree(t, 0)
|
|
value := []byte("testdeadend")
|
|
|
|
gET_CHECKED = false // disable error checking of values
|
|
|
|
defer func() {
|
|
gET_CHECKED = true
|
|
}()
|
|
|
|
order := []byte{
|
|
0x0, //00000000,
|
|
0xc0, //11000000,
|
|
0xd0, //11010000,
|
|
0x8, //10000000,
|
|
}
|
|
for i := range order {
|
|
key := [HASHSIZE]byte{}
|
|
key[0] = order[i]
|
|
require.NoError(t, tree.putRaw(key, nil, value))
|
|
}
|
|
|
|
key := [HASHSIZE]byte{}
|
|
key[0] = 0xE0 //11100000
|
|
root := tree.hashSkipError()
|
|
|
|
require.NoError(t, tree.Commit())
|
|
|
|
proof := NewProof()
|
|
require.NoError(t, tree.generateProofRaw(key, proof))
|
|
|
|
require.False(t, proof.verifyMembershipRaw(root, key))
|
|
require.True(t, proof.verifyNonMembershipRaw(root, key))
|
|
|
|
{
|
|
order := []byte{
|
|
0x0, //00000000,
|
|
0x20, //11000000,
|
|
0xd0, //11010000,
|
|
0x8, //10000000,
|
|
}
|
|
for i := range order {
|
|
key := [HASHSIZE]byte{}
|
|
key[0] = order[i]
|
|
require.NoError(t, tree.putRaw(key, nil, value))
|
|
}
|
|
|
|
key := [HASHSIZE]byte{}
|
|
key[0] = 0xE0 //11100000
|
|
//root := tree.Hash()
|
|
|
|
require.NoError(t, tree.Commit())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestProofMarshal(t *testing.T) {
|
|
_, tree := setupDeterministicTree(t, 1000)
|
|
root := tree.hashSkipError()
|
|
|
|
key := make([]byte, 20)
|
|
for i := 0; i < 10; i++ {
|
|
rand.Read(key)
|
|
proof, err := tree.GenerateProof(key[:])
|
|
require.NoError(t, err)
|
|
|
|
member := proof.VerifyMembership(root, key)
|
|
non := proof.VerifyNonMembership(root, key)
|
|
|
|
buf := proof.Marshal()
|
|
|
|
marshalled := NewProof()
|
|
marshalled.Unmarshal(buf)
|
|
|
|
require.Equal(t, proof, marshalled)
|
|
|
|
require.Equal(t, member, marshalled.VerifyMembership(root, key))
|
|
require.Equal(t, non, marshalled.VerifyNonMembership(root, key))
|
|
|
|
proof.Reset()
|
|
}
|
|
}
|
|
|
|
func TestProveAfterDelete(t *testing.T) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
_, tree := setupDeterministicTree(t, 0)
|
|
proof := NewProof()
|
|
|
|
key1 := make([]byte, 20)
|
|
rand.Read(key1)
|
|
|
|
require.NoError(t, tree.Put(key1, key1))
|
|
keys := [][]byte{}
|
|
for i := 0; i < 7; i++ {
|
|
key2 := make([]byte, 20)
|
|
rand.Read(key2)
|
|
require.NoError(t, tree.Put(key2, key2))
|
|
keys = append(keys, key2)
|
|
}
|
|
|
|
proof, err := tree.GenerateProof(key1[:])
|
|
require.NoError(t, err)
|
|
require.True(t, proof.VerifyMembership(tree.hashSkipError(), key1))
|
|
|
|
for _, key := range keys {
|
|
require.NoError(t, tree.Delete(key))
|
|
}
|
|
proof.Reset()
|
|
proof, err = tree.GenerateProof(key1[:])
|
|
require.NoError(t, err)
|
|
require.True(t, proof.VerifyMembership(tree.hashSkipError(), key1))
|
|
}
|