From 8dac888b1a6d7b66d1a03c19c2479f8e02a01acb Mon Sep 17 00:00:00 2001 From: Nickolai Zeldovich Date: Tue, 22 Aug 2023 20:43:32 -0400 Subject: [PATCH] simplify single-leaf merklearray proofs No need to explicitly specify tree depth for merklearray proofs of a single leaf node, because the tree depth is exactly the number of sibling hashes in the proof. This allows simplifying the format for sending single-leaf merklearray proofs, sending just the proofBytes []byte, and not having to send along an extra treeDepth. The current algod API for fetching a proof still sends the tree depth along, for any clients that might care about it, but future APIs won't need to pass treeDepth. --- crypto/merklearray/proof.go | 5 +++-- crypto/merklearray/proof_test.go | 8 ++++---- daemon/algod/api/server/v2/test/handlers_test.go | 4 +++- test/framework/fixtures/libgoalFixture.go | 4 ++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/crypto/merklearray/proof.go b/crypto/merklearray/proof.go index 0489312035..3455baa08f 100644 --- a/crypto/merklearray/proof.go +++ b/crypto/merklearray/proof.go @@ -149,7 +149,7 @@ func (p *SingleLeafProof) GetConcatenatedProof() []byte { } // ProofDataToSingleLeafProof receives serialized proof data and uses it to construct a proof object. -func ProofDataToSingleLeafProof(hashTypeData string, treeDepth uint64, proofBytes []byte) (SingleLeafProof, error) { +func ProofDataToSingleLeafProof(hashTypeData string, proofBytes []byte) (SingleLeafProof, error) { hashType, err := crypto.UnmarshalHashType(hashTypeData) if err != nil { return SingleLeafProof{}, err @@ -158,7 +158,7 @@ func ProofDataToSingleLeafProof(hashTypeData string, treeDepth uint64, proofByte var proof SingleLeafProof proof.HashFactory = crypto.HashFactory{HashType: hashType} - proof.TreeDepth = uint8(treeDepth) + proof.TreeDepth = 0 digestSize := proof.HashFactory.NewHash().Size() if len(proofBytes)%digestSize != 0 { @@ -172,6 +172,7 @@ func ProofDataToSingleLeafProof(hashTypeData string, treeDepth uint64, proofByte copy(d[:], proofBytes) proofPath = append(proofPath, d[:]) proofBytes = proofBytes[len(d):] + proof.TreeDepth++ } proof.Path = proofPath diff --git a/crypto/merklearray/proof_test.go b/crypto/merklearray/proof_test.go index 9591d6ee41..2fb1a3819c 100644 --- a/crypto/merklearray/proof_test.go +++ b/crypto/merklearray/proof_test.go @@ -157,7 +157,7 @@ func TestConcatenatedProofsMissingChild(t *testing.T) { err = Verify(tree.Root(), map[uint64]crypto.Hashable{6: array[6]}, newP.ToProof()) a.NoError(err) - recomputedProof, err := ProofDataToSingleLeafProof(p.HashFactory.HashType.String(), uint64(p.TreeDepth), concatenatedProof) + recomputedProof, err := ProofDataToSingleLeafProof(p.HashFactory.HashType.String(), concatenatedProof) a.NoError(err) // verify that we can reconstruct the original singleLeafProof from the concatenated proof @@ -189,7 +189,7 @@ func TestConcatenatedProofsFullTree(t *testing.T) { err = Verify(tree.Root(), map[uint64]crypto.Hashable{6: array[6]}, newP.ToProof()) a.NoError(err) - recomputedProof, err := ProofDataToSingleLeafProof(p.HashFactory.HashType.String(), uint64(p.TreeDepth), concatenatedProof) + recomputedProof, err := ProofDataToSingleLeafProof(p.HashFactory.HashType.String(), concatenatedProof) a.NoError(err) // verify that we can reconstruct the original singleLeafProof from the concatenated proof @@ -218,7 +218,7 @@ func TestConcatenatedProofsOneLeaf(t *testing.T) { err = Verify(tree.Root(), map[uint64]crypto.Hashable{0: array[0]}, newP.ToProof()) a.NoError(err) - recomputedProof, err := ProofDataToSingleLeafProof(p.HashFactory.HashType.String(), uint64(p.TreeDepth), concatenatedProof) + recomputedProof, err := ProofDataToSingleLeafProof(p.HashFactory.HashType.String(), concatenatedProof) a.NoError(err) // verify that we can reconstruct the original singleLeafProof from the concatenated proof @@ -230,7 +230,7 @@ func TestProofDeserializationError(t *testing.T) { partitiontest.PartitionTest(t) a := require.New(t) - _, err := ProofDataToSingleLeafProof(crypto.Sha256.String(), 1, []byte{1}) + _, err := ProofDataToSingleLeafProof(crypto.Sha256.String(), []byte{1}) a.ErrorIs(err, ErrProofLengthDigestSizeMismatch) } diff --git a/daemon/algod/api/server/v2/test/handlers_test.go b/daemon/algod/api/server/v2/test/handlers_test.go index d59d9c971c..48f89538bb 100644 --- a/daemon/algod/api/server/v2/test/handlers_test.go +++ b/daemon/algod/api/server/v2/test/handlers_test.go @@ -1810,9 +1810,11 @@ func TestGetProofDefault(t *testing.T) { blkHdr, err := l.BlockHdr(1) a.NoError(err) - singleLeafProof, err := merklearray.ProofDataToSingleLeafProof(string(resp.Hashtype), resp.Treedepth, resp.Proof) + singleLeafProof, err := merklearray.ProofDataToSingleLeafProof(string(resp.Hashtype), resp.Proof) a.NoError(err) + a.Equal(uint64(singleLeafProof.TreeDepth), resp.Treedepth) + element := TxnMerkleElemRaw{Txn: crypto.Digest(txid)} copy(element.Stib[:], resp.Stibhash[:]) elems := make(map[uint64]crypto.Hashable) diff --git a/test/framework/fixtures/libgoalFixture.go b/test/framework/fixtures/libgoalFixture.go index c0527fdd62..1cc0b24fb8 100644 --- a/test/framework/fixtures/libgoalFixture.go +++ b/test/framework/fixtures/libgoalFixture.go @@ -534,7 +534,7 @@ func (f *LibGoalFixture) TransactionProof(txid string, round uint64, hashType cr return model.TransactionProofResponse{}, merklearray.SingleLeafProof{}, err } - proof, err := merklearray.ProofDataToSingleLeafProof(string(proofResp.Hashtype), proofResp.Treedepth, proofResp.Proof) + proof, err := merklearray.ProofDataToSingleLeafProof(string(proofResp.Hashtype), proofResp.Proof) if err != nil { return model.TransactionProofResponse{}, merklearray.SingleLeafProof{}, err } @@ -550,7 +550,7 @@ func (f *LibGoalFixture) LightBlockHeaderProof(round uint64) (model.LightBlockHe return model.LightBlockHeaderProofResponse{}, merklearray.SingleLeafProof{}, err } - proof, err := merklearray.ProofDataToSingleLeafProof(crypto.Sha256.String(), proofResp.Treedepth, proofResp.Proof) + proof, err := merklearray.ProofDataToSingleLeafProof(crypto.Sha256.String(), proofResp.Proof) if err != nil { return model.LightBlockHeaderProofResponse{}, merklearray.SingleLeafProof{}, err }