From 40585c220206745bdd3e0498b613cd6b6d3bfcfd Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Thu, 24 Nov 2022 11:21:40 -0300 Subject: [PATCH] trie: avoid endianness conversion in GetTreeKey (#140) * trie/utils: add concrete expected value in trie key generation test Signed-off-by: Ignacio Hagopian * mod: update to latest go-verkle Signed-off-by: Ignacio Hagopian * trie/utils: avoid endianness conversions Signed-off-by: Ignacio Hagopian * apply review changes & update to official go-verkle version Signed-off-by: Ignacio Hagopian Signed-off-by: Ignacio Hagopian --- cmd/geth/verkle.go | 6 +++--- go.mod | 4 ++-- go.sum | 10 ++++------ trie/utils/verkle.go | 35 +++++++++++++++++++---------------- trie/utils/verkle_test.go | 11 +++++++++-- trie/verkle.go | 11 ++++------- trie/verkle_iterator.go | 8 ++++---- trie/verkle_test.go | 12 ++++++------ 8 files changed, 51 insertions(+), 46 deletions(-) diff --git a/cmd/geth/verkle.go b/cmd/geth/verkle.go index f85ec37ea924..fcd4a0bf513a 100644 --- a/cmd/geth/verkle.go +++ b/cmd/geth/verkle.go @@ -75,7 +75,7 @@ func checkChildren(root verkle.VerkleNode, resolver verkle.NodeResolverFn) error switch node := root.(type) { case *verkle.InternalNode: for i, child := range node.Children() { - childC := child.ComputeCommitment().Bytes() + childC := child.Commitment().Bytes() childS, err := resolver(childC[:]) if bytes.Equal(childC[:], zero[:]) { @@ -87,7 +87,7 @@ func checkChildren(root verkle.VerkleNode, resolver verkle.NodeResolverFn) error // depth is set to 0, the tree isn't rebuilt so it's not a problem childN, err := verkle.ParseNode(childS, 0, childC[:]) if err != nil { - return fmt.Errorf("decode error child %x in db: %w", child.ComputeCommitment().Bytes(), err) + return fmt.Errorf("decode error child %x in db: %w", child.Commitment().Bytes(), err) } if err := checkChildren(childN, resolver); err != nil { return fmt.Errorf("%x%w", i, err) // write the path to the erroring node @@ -204,7 +204,7 @@ func expandVerkle(ctx *cli.Context) error { root.Get(key, chaindb.Get) } - if err := os.WriteFile("dump.dot", []byte(verkle.ToDot(root)), 0600); err != nil { + if err := os.WriteFile("dump.dot", []byte(verkle.ToDot(root)), 0o600); err != nil { log.Error("Failed to dump file", "err", err) } else { log.Info("Tree was dumped to file", "file", "dump.dot") diff --git a/go.mod b/go.mod index 0797f0dbb5c0..0f7a3f9af981 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.14.0 github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f - github.com/crate-crypto/go-ipa v0.0.0-20220916134416-c5abbdbdf644 + github.com/crate-crypto/go-ipa v0.0.0-20221111143132-9aa5d42120bc github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v1.8.0 github.com/docker/docker v1.6.2 @@ -23,7 +23,7 @@ require ( github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff - github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 + github.com/gballet/go-verkle v0.0.0-20221122140954-75ceda26b7db github.com/go-stack/stack v1.8.0 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.5.2 diff --git a/go.sum b/go.sum index c36d5b0f564f..96a0d52a7892 100644 --- a/go.sum +++ b/go.sum @@ -86,9 +86,8 @@ github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= -github.com/crate-crypto/go-ipa v0.0.0-20220916134416-c5abbdbdf644 h1:1BOsVjUetPH2Lqv71Dh6uKLVj9WKdDr5KY57KZBbsWU= -github.com/crate-crypto/go-ipa v0.0.0-20220916134416-c5abbdbdf644/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= +github.com/crate-crypto/go-ipa v0.0.0-20221111143132-9aa5d42120bc h1:mtR7MuscVeP/s0/ERWA2uSr5QOrRYy1pdvZqG1USfXI= +github.com/crate-crypto/go-ipa v0.0.0-20221111143132-9aa5d42120bc/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= @@ -136,8 +135,8 @@ github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgx github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 h1:AB7YjNrzlVHsYz06zCULVV2zYCEft82P86dSmtwxKL0= -github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732/go.mod h1:o/XfIXWi4/GqbQirfRm5uTbXMG5NpqxkxblnbZ+QM9I= +github.com/gballet/go-verkle v0.0.0-20221122140954-75ceda26b7db h1:YvtZfE11QEYWPjsQCyZLoZCGMsxJs9mTEbhF3MnM32Q= +github.com/gballet/go-verkle v0.0.0-20221122140954-75ceda26b7db/go.mod h1:DMDd04jjQgdynaAwbEgiRERIGpC8fDjx0+y06an7Psg= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -552,7 +551,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go index 33bf8dc45b0a..e4e263bc6d76 100644 --- a/trie/utils/verkle.go +++ b/trie/utils/verkle.go @@ -63,31 +63,35 @@ func GetTreeKey(address []byte, treeIndex *uint256.Int, subIndex byte) []byte { var aligned [32]byte address = append(aligned[:32-len(address)], address...) } - var poly [5]fr.Element - poly[0].SetZero() + // poly = [2+256*64, address_le_low, address_le_high, tree_index_le_low, tree_index_le_high] + var poly [5]fr.Element // 32-byte address, interpreted as two little endian // 16-byte numbers. verkle.FromLEBytes(&poly[1], address[:16]) verkle.FromLEBytes(&poly[2], address[16:]) - // little-endian, 32-byte aligned treeIndex - var index [32]byte - for i, b := range treeIndex.Bytes() { - index[len(treeIndex.Bytes())-1-i] = b - } - verkle.FromLEBytes(&poly[3], index[:16]) - verkle.FromLEBytes(&poly[4], index[16:]) - - cfg, _ := verkle.GetConfig() + // treeIndex must be interpreted as a 32-byte aligned little-endian integer. + // e.g: if treeIndex is 0xAABBCC, we need the byte representation to be 0xCCBBAA00...00. + // poly[3] = LE({CC,BB,AA,00...0}) (16 bytes), poly[4]=LE({00,00,...}) (16 bytes). + // + // To avoid unnecessary endianness conversions for go-ipa, we do some trick: + // - poly[3]'s byte representation is the same as the *top* 16 bytes (trieIndexBytes[16:]) of + // 32-byte aligned big-endian representation (BE({00,...,AA,BB,CC})). + // - poly[4]'s byte representation is the same as the *low* 16 bytes (trieIndexBytes[:16]) of + // the 32-byte aligned big-endian representation (BE({00,00,...}). + trieIndexBytes := treeIndex.Bytes32() + verkle.FromBytes(&poly[3], trieIndexBytes[16:]) + verkle.FromBytes(&poly[4], trieIndexBytes[:16]) + + cfg := verkle.GetConfig() ret := cfg.CommitToPoly(poly[:], 0) - // add a constant point + // add a constant point corresponding to poly[0]=[2+256*64]. ret.Add(ret, getTreePolyIndex0Point) return PointToHash(ret, subIndex) - } func GetTreeKeyAccountLeaf(address []byte, leaf byte) []byte { @@ -187,14 +191,13 @@ func getTreeKeyWithEvaluatedAddess(evaluated *verkle.Point, treeIndex *uint256.I verkle.FromLEBytes(&poly[3], index[:16]) verkle.FromLEBytes(&poly[4], index[16:]) - cfg, _ := verkle.GetConfig() + cfg := verkle.GetConfig() ret := cfg.CommitToPoly(poly[:], 0) // add the pre-evaluated address ret.Add(ret, evaluated) return PointToHash(ret, subIndex) - } func EvaluateAddressPoint(address []byte) *verkle.Point { @@ -211,7 +214,7 @@ func EvaluateAddressPoint(address []byte) *verkle.Point { verkle.FromLEBytes(&poly[1], address[:16]) verkle.FromLEBytes(&poly[2], address[16:]) - cfg, _ := verkle.GetConfig() + cfg := verkle.GetConfig() ret := cfg.CommitToPoly(poly[:], 0) // add a constant point diff --git a/trie/utils/verkle_test.go b/trie/utils/verkle_test.go index 2ea9c8742a35..744df9df26ac 100644 --- a/trie/utils/verkle_test.go +++ b/trie/utils/verkle_test.go @@ -18,6 +18,7 @@ package utils import ( "crypto/sha256" + "encoding/hex" "math/big" "math/rand" "testing" @@ -34,13 +35,19 @@ func TestGetTreeKey(t *testing.T) { n := uint256.NewInt(1) n = n.Lsh(n, 129) n.Add(n, uint256.NewInt(3)) - GetTreeKey(addr[:], n, 1) + tk := GetTreeKey(addr[:], n, 1) + + got := hex.EncodeToString(tk) + exp := "f42f932f43faf5d14b292b9009c45c28da61dbf66e20dbedc2e02dfd64ff5a01" + if got != exp { + t.Fatalf("Generated trie key is incorrect: %s != %s", got, exp) + } } func TestConstantPoint(t *testing.T) { var expectedPoly [1]verkle.Fr - cfg, _ := verkle.GetConfig() + cfg := verkle.GetConfig() verkle.FromLEBytes(&expectedPoly[0], []byte{2, 64}) expected := cfg.CommitToPoly(expectedPoly[:], 1) diff --git a/trie/verkle.go b/trie/verkle.go index 7c3741be7a2f..18517ab29ad6 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -105,7 +105,6 @@ func (t *VerkleTrie) TryGetAccount(key []byte) (*types.StateAccount, error) { ck, err := t.TryGet(ckkey[:]) if err != nil { return nil, fmt.Errorf("updateStateObject (%x) error: %v", key, err) - } acc.CodeHash = ck @@ -220,11 +219,11 @@ func (trie *VerkleTrie) TryDelete(key []byte) error { // Hash returns the root hash of the trie. It does not write to the database and // can be used even if the trie doesn't have one. func (trie *VerkleTrie) Hash() common.Hash { - return trie.root.ComputeCommitment().Bytes() + return trie.root.Commit().Bytes() } func nodeToDBKey(n verkle.VerkleNode) []byte { - ret := n.ComputeCommitment().Bytes() + ret := n.Commitment().Bytes() return ret[:] } @@ -277,6 +276,7 @@ func (trie *VerkleTrie) Copy(db *Database) *VerkleTrie { db: db, } } + func (trie *VerkleTrie) IsVerkle() bool { return true } @@ -306,10 +306,7 @@ func DeserializeAndVerifyVerkleProof(serialized []byte, rootC *verkle.Point, key if err != nil { return fmt.Errorf("could not deserialize proof: %w", err) } - cfg, err := verkle.GetConfig() - if err != nil { - return fmt.Errorf("could not get configuration %w", err) - } + cfg := verkle.GetConfig() if !verkle.VerifyVerkleProof(proof, cis, indices, yis, cfg) { return errInvalidProof } diff --git a/trie/verkle_iterator.go b/trie/verkle_iterator.go index 0fbcc3c4f84e..9c57e5da1956 100644 --- a/trie/verkle_iterator.go +++ b/trie/verkle_iterator.go @@ -41,7 +41,7 @@ func newVerkleNodeIterator(trie *VerkleTrie, start []byte) NodeIterator { return new(nodeIterator) } it := &verkleNodeIterator{trie: trie, current: trie.root} - //it.err = it.seek(start) + // it.err = it.seek(start) return it } @@ -129,13 +129,13 @@ func (it *verkleNodeIterator) Error() error { // Hash returns the hash of the current node. func (it *verkleNodeIterator) Hash() common.Hash { - return it.current.ComputeCommitment().Bytes() + return it.current.Commit().Bytes() } // Parent returns the hash of the parent of the current node. The hash may be the one // grandparent if the immediate parent is an internal node with no hash. func (it *verkleNodeIterator) Parent() common.Hash { - return it.stack[len(it.stack)-1].Node.ComputeCommitment().Bytes() + return it.stack[len(it.stack)-1].Node.Commit().Bytes() } // Path returns the hex-encoded path to the current node. @@ -188,7 +188,7 @@ func (it *verkleNodeIterator) LeafProof() [][]byte { panic("LeafProof() called on an verkle node iterator not at a leaf location") } - //return it.trie.Prove(leaf.Key()) + // return it.trie.Prove(leaf.Key()) panic("not completely implemented") } diff --git a/trie/verkle_test.go b/trie/verkle_test.go index 3c02d49f3cfd..52f75eb0a797 100644 --- a/trie/verkle_test.go +++ b/trie/verkle_test.go @@ -73,7 +73,7 @@ func TestReproduceTree(t *testing.T) { } proof, Cs, zis, yis, _ := verkle.MakeVerkleMultiProof(root, append(presentKeys, absentKeys...), kv) - cfg, _ := verkle.GetConfig() + cfg := verkle.GetConfig() if !verkle.VerifyVerkleProof(proof, Cs, zis, yis, cfg) { t.Fatal("could not verify proof") } @@ -88,7 +88,7 @@ func TestReproduceTree(t *testing.T) { t.Fatal(err) } t.Logf("serialized: %x", p) - t.Logf("tree: %s\n%x\n", verkle.ToDot(root), root.ComputeCommitment().Bytes()) + t.Logf("tree: %s\n%x\n", verkle.ToDot(root), root.Commitment().Bytes()) } func TestChunkifyCodeTestnet(t *testing.T) { @@ -294,7 +294,7 @@ func TestReproduceCondrieuStemAggregationInProofOfAbsence(t *testing.T) { } proof, Cs, zis, yis, _ := verkle.MakeVerkleMultiProof(root, append(presentKeys, absentKeys...), kv) - cfg, _ := verkle.GetConfig() + cfg := verkle.GetConfig() if !verkle.VerifyVerkleProof(proof, Cs, zis, yis, cfg) { t.Fatal("could not verify proof") } @@ -309,7 +309,7 @@ func TestReproduceCondrieuStemAggregationInProofOfAbsence(t *testing.T) { t.Fatal(err) } t.Logf("serialized: %x", p) - t.Logf("tree: %s\n%x\n", verkle.ToDot(root), root.ComputeCommitment().Bytes()) + t.Logf("tree: %s\n%x\n", verkle.ToDot(root), root.Commitment().Bytes()) t.Logf("%d", len(proof.ExtStatus)) if len(proof.ExtStatus) != 5 { @@ -341,7 +341,7 @@ func TestReproduceCondrieuPoAStemConflictWithAnotherStem(t *testing.T) { } proof, Cs, zis, yis, _ := verkle.MakeVerkleMultiProof(root, append(presentKeys, absentKeys...), kv) - cfg, _ := verkle.GetConfig() + cfg := verkle.GetConfig() if !verkle.VerifyVerkleProof(proof, Cs, zis, yis, cfg) { t.Fatal("could not verify proof") } @@ -356,7 +356,7 @@ func TestReproduceCondrieuPoAStemConflictWithAnotherStem(t *testing.T) { t.Fatal(err) } t.Logf("serialized: %x", p) - t.Logf("tree: %s\n%x\n", verkle.ToDot(root), root.ComputeCommitment().Bytes()) + t.Logf("tree: %s\n%x\n", verkle.ToDot(root), root.Commitment().Bytes()) t.Logf("%d", len(proof.ExtStatus)) if len(proof.PoaStems) != 0 {