diff --git a/config.go b/config.go index e9c168b2..c6c93ee6 100644 --- a/config.go +++ b/config.go @@ -37,7 +37,7 @@ const ( ) func equalPaths(key1, key2 []byte) bool { - return bytes.Equal(key1[:StemSize], key2[:StemSize]) + return bytes.Equal(KeyToStem(key1), KeyToStem(key2)) } // offset2key extracts the n bits of a key that correspond to the diff --git a/conversion.go b/conversion.go index 3504d88a..58fdba6a 100644 --- a/conversion.go +++ b/conversion.go @@ -13,7 +13,7 @@ import ( // BatchNewLeafNodeData is a struct that contains the data needed to create a new leaf node. type BatchNewLeafNodeData struct { - Stem []byte + Stem Stem Values map[byte][]byte } diff --git a/debug.go b/debug.go index b6a73b5f..055e200a 100644 --- a/debug.go +++ b/debug.go @@ -36,7 +36,7 @@ type ( } ExportableLeafNode struct { - Stem []byte `json:"stem"` + Stem Stem `json:"stem"` Values [][]byte `json:"values"` C [32]byte `json:"commitment"` diff --git a/empty.go b/empty.go index 8139a829..2115c9db 100644 --- a/empty.go +++ b/empty.go @@ -53,7 +53,7 @@ func (Empty) Commitment() *Point { return &id } -func (Empty) GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, [][]byte, error) { +func (Empty) GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, []Stem, error) { return nil, nil, nil, errors.New("trying to produce a commitment for an empty subtree") } diff --git a/hashednode.go b/hashednode.go index 41d96ea5..bd53c9dc 100644 --- a/hashednode.go +++ b/hashednode.go @@ -58,7 +58,7 @@ func (HashedNode) Commitment() *Point { panic("can not get commitment of a hash node") } -func (HashedNode) GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, [][]byte, error) { +func (HashedNode) GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, []Stem, error) { return nil, nil, nil, errors.New("can not get the full path, and there is no proof of absence") } diff --git a/proof_ipa.go b/proof_ipa.go index 091922cf..3f7af941 100644 --- a/proof_ipa.go +++ b/proof_ipa.go @@ -45,16 +45,16 @@ type IPAProof struct { } type VerkleProof struct { - OtherStems [][31]byte `json:"otherStems"` - DepthExtensionPresent []byte `json:"depthExtensionPresent"` - CommitmentsByPath [][32]byte `json:"commitmentsByPath"` - D [32]byte `json:"d"` - IPAProof *IPAProof `json:"ipa_proof"` + OtherStems [][StemSize]byte `json:"otherStems"` + DepthExtensionPresent []byte `json:"depthExtensionPresent"` + CommitmentsByPath [][32]byte `json:"commitmentsByPath"` + D [32]byte `json:"d"` + IPAProof *IPAProof `json:"ipa_proof"` } func (vp *VerkleProof) Copy() *VerkleProof { ret := &VerkleProof{ - OtherStems: make([][31]byte, len(vp.OtherStems)), + OtherStems: make([][StemSize]byte, len(vp.OtherStems)), DepthExtensionPresent: make([]byte, len(vp.DepthExtensionPresent)), CommitmentsByPath: make([][32]byte, len(vp.CommitmentsByPath)), IPAProof: &IPAProof{}, @@ -77,7 +77,7 @@ type Proof struct { Multipoint *ipa.MultiProof // multipoint argument ExtStatus []byte // the extension status of each stem Cs []*Point // commitments, sorted by their path in the tree - PoaStems [][]byte // stems proving another stem is absent + PoaStems []Stem // stems proving another stem is absent Keys [][]byte PreValues [][]byte PostValues [][]byte @@ -92,7 +92,7 @@ type SuffixStateDiff struct { type SuffixStateDiffs []SuffixStateDiff type StemStateDiff struct { - Stem [31]byte `json:"stem"` + Stem [StemSize]byte `json:"stem"` SuffixDiffs SuffixStateDiffs `json:"suffixDiffs"` } @@ -118,7 +118,7 @@ func (sd StateDiff) Copy() StateDiff { return ret } -func GetCommitmentsForMultiproof(root VerkleNode, keys [][]byte, resolver NodeResolverFn) (*ProofElements, []byte, [][]byte, error) { +func GetCommitmentsForMultiproof(root VerkleNode, keys [][]byte, resolver NodeResolverFn) (*ProofElements, []byte, []Stem, error) { sort.Sort(keylist(keys)) return root.GetProofItems(keylist(keys), resolver) } @@ -126,7 +126,7 @@ func GetCommitmentsForMultiproof(root VerkleNode, keys [][]byte, resolver NodeRe // getProofElementsFromTree factors the logic that is used both in the proving and verification methods. It takes a pre-state // tree and an optional post-state tree, extracts the proof data from them and returns all the items required to build/verify // a proof. -func getProofElementsFromTree(preroot, postroot VerkleNode, keys [][]byte, resolver NodeResolverFn) (*ProofElements, []byte, [][]byte, [][]byte, error) { +func getProofElementsFromTree(preroot, postroot VerkleNode, keys [][]byte, resolver NodeResolverFn) (*ProofElements, []byte, []Stem, [][]byte, error) { // go-ipa won't accept no key as an input, catch this corner case // and return an empty result. if len(keys) == 0 { @@ -228,7 +228,7 @@ func VerifyVerkleProof(proof *Proof, Cs []*Point, indices []uint8, ys []*Fr, tc // * Multipoint proof // it also returns the serialized keys and values func SerializeProof(proof *Proof) (*VerkleProof, StateDiff, error) { - otherstems := make([][31]byte, len(proof.PoaStems)) + otherstems := make([][StemSize]byte, len(proof.PoaStems)) for i, stem := range proof.PoaStems { copy(otherstems[i][:], stem) } @@ -251,12 +251,13 @@ func SerializeProof(proof *Proof) (*VerkleProof, StateDiff, error) { var stemdiff *StemStateDiff var statediff StateDiff for i, key := range proof.Keys { - if stemdiff == nil || !bytes.Equal(stemdiff.Stem[:], key[:31]) { + stem := KeyToStem(key) + if stemdiff == nil || !bytes.Equal(stemdiff.Stem[:], stem) { statediff = append(statediff, StemStateDiff{}) stemdiff = &statediff[len(statediff)-1] - copy(stemdiff.Stem[:], key[:31]) + copy(stemdiff.Stem[:], stem) } - stemdiff.SuffixDiffs = append(stemdiff.SuffixDiffs, SuffixStateDiff{Suffix: key[31]}) + stemdiff.SuffixDiffs = append(stemdiff.SuffixDiffs, SuffixStateDiff{Suffix: key[StemSize]}) newsd := &stemdiff.SuffixDiffs[len(stemdiff.SuffixDiffs)-1] var valueLen = len(proof.PreValues[i]) @@ -302,14 +303,15 @@ func SerializeProof(proof *Proof) (*VerkleProof, StateDiff, error) { // can be used to rebuild a stateless version of the tree. func DeserializeProof(vp *VerkleProof, statediff StateDiff) (*Proof, error) { var ( - poaStems, keys [][]byte + poaStems []Stem + keys [][]byte prevalues, postvalues [][]byte extStatus []byte commitments []*Point multipoint ipa.MultiProof ) - poaStems = make([][]byte, len(vp.OtherStems)) + poaStems = make([]Stem, len(vp.OtherStems)) for i, poaStem := range vp.OtherStems { poaStems[i] = make([]byte, len(poaStem)) copy(poaStems[i], poaStem[:]) @@ -347,8 +349,8 @@ func DeserializeProof(vp *VerkleProof, statediff StateDiff) (*Proof, error) { for _, stemdiff := range statediff { for _, suffixdiff := range stemdiff.SuffixDiffs { var k [32]byte - copy(k[:31], stemdiff.Stem[:]) - k[31] = suffixdiff.Suffix + copy(k[:StemSize], stemdiff.Stem[:]) + k[StemSize] = suffixdiff.Suffix keys = append(keys, k[:]) if suffixdiff.CurrentValue != nil { prevalues = append(prevalues, suffixdiff.CurrentValue[:]) @@ -394,8 +396,9 @@ func PreStateTreeFromProof(proof *Proof, rootC *Point) (VerkleNode, error) { // } stems := make([][]byte, 0, len(proof.Keys)) for _, k := range proof.Keys { - if len(stems) == 0 || !bytes.Equal(stems[len(stems)-1], k[:31]) { - stems = append(stems, k[:31]) + stem := KeyToStem(k) + if len(stems) == 0 || !bytes.Equal(stems[len(stems)-1], stem) { + stems = append(stems, stem) } } if len(stems) != len(proof.ExtStatus) { @@ -469,10 +472,10 @@ func PreStateTreeFromProof(proof *Proof, rootC *Point) (VerkleNode, error) { // si.values = map[byte][]byte{} si.stem = stems[i] for j, k := range proof.Keys { // TODO: DoS risk, use map or binary search. - if bytes.Equal(k[:31], si.stem) { - si.values[k[31]] = proof.PreValues[j] - si.has_c1 = si.has_c1 || (k[31] < 128) - si.has_c2 = si.has_c2 || (k[31] >= 128) + if bytes.Equal(KeyToStem(k), si.stem) { + si.values[k[StemSize]] = proof.PreValues[j] + si.has_c1 = si.has_c1 || (k[StemSize] < 128) + si.has_c2 = si.has_c2 || (k[StemSize] >= 128) } } default: @@ -501,8 +504,8 @@ func PreStateTreeFromProof(proof *Proof, rootC *Point) (VerkleNode, error) { // continue } - if bytes.Equal(k[:31], info[string(p)].stem) { - values[k[31]] = proof.PreValues[i] + if bytes.Equal(KeyToStem(k), info[string(p)].stem) { + values[k[StemSize]] = proof.PreValues[i] } } comms, err = root.CreatePath(p, info[string(p)], comms, values) @@ -535,8 +538,8 @@ func PostStateTreeFromStateDiff(preroot VerkleNode, statediff StateDiff) (Verkle } if overwrites { - var stem [31]byte - copy(stem[:31], stemstatediff.Stem[:]) + var stem [StemSize]byte + copy(stem[:StemSize], stemstatediff.Stem[:]) if err := postroot.(*InternalNode).InsertValuesAtStem(stem[:], values, nil); err != nil { return nil, fmt.Errorf("error overwriting value in post state: %w", err) } @@ -547,7 +550,7 @@ func PostStateTreeFromStateDiff(preroot VerkleNode, statediff StateDiff) (Verkle return postroot, nil } -type bytesSlice [][]byte +type bytesSlice []Stem func (x bytesSlice) Len() int { return len(x) } func (x bytesSlice) Less(i, j int) bool { return bytes.Compare(x[i], x[j]) < 0 } diff --git a/proof_json.go b/proof_json.go index 8d775ee0..7828697e 100644 --- a/proof_json.go +++ b/proof_json.go @@ -170,7 +170,7 @@ func (vp *VerkleProof) UnmarshalJSON(data []byte) error { } copy(vp.D[:], currentValueBytes) - vp.OtherStems = make([][31]byte, len(aux.OtherStems)) + vp.OtherStems = make([][StemSize]byte, len(aux.OtherStems)) for i, c := range aux.OtherStems { val, err := PrefixedHexStringToBytes(c) if err != nil { diff --git a/proof_test.go b/proof_test.go index 9dc97c3a..075f75b9 100644 --- a/proof_test.go +++ b/proof_test.go @@ -136,7 +136,7 @@ func TestMultiProofVerifyMultipleLeavesWithAbsentStem(t *testing.T) { const leafCount = 10 var keys [][]byte - var absentstem [31]byte + var absentstem [StemSize]byte root := New() for i := 0; i < leafCount; i++ { key := make([]byte, 32) @@ -148,7 +148,7 @@ func TestMultiProofVerifyMultipleLeavesWithAbsentStem(t *testing.T) { keys = append(keys, key) } if i == 3 { - copy(absentstem[:], key[:31]) + copy(absentstem[:], key[:StemSize]) } } root.Commit() @@ -610,7 +610,7 @@ func TestStemStateDiffJSONMarshalUn(t *testing.T) { t.Parallel() ssd := StemStateDiff{ - Stem: [31]byte{10}, + Stem: [StemSize]byte{10}, SuffixDiffs: []SuffixStateDiff{{ Suffix: 0x41, CurrentValue: &[32]byte{ @@ -702,7 +702,7 @@ func TestVerkleProofMarshalUnmarshalJSON(t *testing.T) { t.Parallel() vp1 := &VerkleProof{ - OtherStems: [][31]byte{{1}, {2}, {3}}, + OtherStems: [][StemSize]byte{{1}, {2}, {3}}, DepthExtensionPresent: []byte{4, 5, 6}, CommitmentsByPath: [][32]byte{{7}, {8}, {9}}, D: [32]byte{10}, @@ -1125,7 +1125,7 @@ func TestGenerateProofWithOnlyAbsentKeys(t *testing.T) { for i := 0; i < common.VectorLength; i++ { var key [32]byte copy(key[:], presentKey) - key[31] = byte(i) + key[StemSize] = byte(i) if _, err := droot.Get(key[:], nil); err != errIsPOAStub { t.Fatalf("expected ErrPOALeafValue, got %v", err) } @@ -1136,7 +1136,7 @@ func TestGenerateProofWithOnlyAbsentKeys(t *testing.T) { for i := 0; i < common.VectorLength; i++ { var key [32]byte copy(key[:], presentKey) - key[31] = byte(i) + key[StemSize] = byte(i) if err := droot.Insert(key[:], zeroKeyTest, nil); err != errIsPOAStub { t.Fatalf("expected ErrPOALeafValue, got %v", err) } diff --git a/tree.go b/tree.go index 44d61c85..9a57cfae 100644 --- a/tree.go +++ b/tree.go @@ -55,6 +55,15 @@ func (kl keylist) Swap(i, j int) { kl[i], kl[j] = kl[j], kl[i] } +type Stem []byte + +func KeyToStem(key []byte) Stem { + if len(key) < StemSize { + panic(fmt.Errorf("key length (%d) is shorter than expected stem size (%d)", len(key), StemSize)) + } + return Stem(key[:StemSize]) +} + type VerkleNode interface { // Insert or Update value into the tree Insert([]byte, []byte, NodeResolverFn) error @@ -80,7 +89,7 @@ type VerkleNode interface { // returns them breadth-first. On top of that, it returns // one "extension status" per stem, and an alternate stem // if the key is missing but another stem has been found. - GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, [][]byte, error) + GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, []Stem, error) // Serialize encodes the node to RLP. Serialize() ([]byte, error) @@ -176,7 +185,7 @@ type ( } LeafNode struct { - stem []byte + stem Stem values [][]byte commitment *Point @@ -254,7 +263,7 @@ func NewStatelessInternal(depth byte, comm *Point) VerkleNode { } // New creates a new leaf node -func NewLeafNode(stem []byte, values [][]byte) (*LeafNode, error) { +func NewLeafNode(stem Stem, values [][]byte) (*LeafNode, error) { cfg := GetConfig() // C1. @@ -312,7 +321,7 @@ func NewLeafNode(stem []byte, values [][]byte) (*LeafNode, error) { // NewLeafNodeWithNoComms create a leaf node but does not compute its // commitments. The created node's commitments are intended to be // initialized with `SetTrustedBytes` in a deserialization context. -func NewLeafNodeWithNoComms(stem []byte, values [][]byte) *LeafNode { +func NewLeafNodeWithNoComms(stem Stem, values [][]byte) *LeafNode { return &LeafNode{ // depth will be 0, but the commitment calculation // does not need it, and so it won't be free. @@ -349,11 +358,11 @@ func (n *InternalNode) cowChild(index byte) { func (n *InternalNode) Insert(key []byte, value []byte, resolver NodeResolverFn) error { values := make([][]byte, NodeWidth) - values[key[31]] = value - return n.InsertValuesAtStem(key[:31], values, resolver) + values[key[StemSize]] = value + return n.InsertValuesAtStem(KeyToStem(key), values, resolver) } -func (n *InternalNode) InsertValuesAtStem(stem []byte, values [][]byte, resolver NodeResolverFn) error { +func (n *InternalNode) InsertValuesAtStem(stem Stem, values [][]byte, resolver NodeResolverFn) error { nChild := offset2key(stem, n.depth) // index of the child pointed by the next byte in the key switch child := n.children[nChild].(type) { @@ -532,7 +541,7 @@ func (n *InternalNode) CreatePath(path []byte, stemInfo stemInfo, comms []*Point // GetValuesAtStem returns the all NodeWidth values of the stem. // The returned slice is internal to the tree, so it *must* be considered readonly // for callers. -func (n *InternalNode) GetValuesAtStem(stem []byte, resolver NodeResolverFn) ([][]byte, error) { +func (n *InternalNode) GetValuesAtStem(stem Stem, resolver NodeResolverFn) ([][]byte, error) { nchild := offset2key(stem, n.depth) // index of the child pointed by the next byte in the key switch child := n.children[nchild].(type) { case UnknownNode: @@ -684,7 +693,7 @@ func (n *InternalNode) Get(key []byte, resolver NodeResolverFn) ([]byte, error) if len(key) != StemSize+1 { return nil, fmt.Errorf("invalid key length, expected %d, got %d", StemSize+1, len(key)) } - stemValues, err := n.GetValuesAtStem(key[:StemSize], resolver) + stemValues, err := n.GetValuesAtStem(KeyToStem(key), resolver) if err != nil { return nil, err } @@ -855,7 +864,7 @@ func groupKeys(keys keylist, depth byte) []keylist { return groups } -func (n *InternalNode) GetProofItems(keys keylist, resolver NodeResolverFn) (*ProofElements, []byte, [][]byte, error) { +func (n *InternalNode) GetProofItems(keys keylist, resolver NodeResolverFn) (*ProofElements, []byte, []Stem, error) { var ( groups = groupKeys(keys, n.depth) pe = &ProofElements{ @@ -866,8 +875,8 @@ func (n *InternalNode) GetProofItems(keys keylist, resolver NodeResolverFn) (*Pr ByPath: map[string]*Point{}, } - esses []byte = nil // list of extension statuses - poass [][]byte // list of proof-of-absence stems + esses []byte = nil // list of extension statuses + poass []Stem // list of proof-of-absence stems ) // fill in the polynomial for this node @@ -937,13 +946,14 @@ func (n *InternalNode) GetProofItems(keys keylist, resolver NodeResolverFn) (*Pr if isempty { addedStems := map[string]struct{}{} for i := 0; i < len(group); i++ { - if _, ok := addedStems[string(group[i][:StemSize])]; !ok { + stemStr := string(KeyToStem(group[i])) + if _, ok := addedStems[stemStr]; !ok { // A question arises here: what if this proof of absence // corresponds to several stems? Should the ext status be // repeated as many times? It's wasteful, so consider if the // decoding code can be aware of this corner case. esses = append(esses, extStatusAbsentEmpty|((n.depth+1)<<3)) - addedStems[string(group[i][:StemSize])] = struct{}{} + addedStems[stemStr] = struct{}{} } // Append one nil value per key in this missing stem pe.Vals = append(pe.Vals, nil) @@ -1070,15 +1080,17 @@ func (n *LeafNode) Insert(key []byte, value []byte, _ NodeResolverFn) error { if len(key) != StemSize+1 { return fmt.Errorf("invalid key size: %d", len(key)) } - if !bytes.Equal(key[:StemSize], n.stem) { - return fmt.Errorf("stems doesn't match: %x != %x", key[:StemSize], n.stem) + + stem := KeyToStem(key) + if !bytes.Equal(stem, n.stem) { + return fmt.Errorf("stems doesn't match: %x != %x", stem, n.stem) } values := make([][]byte, NodeWidth) values[key[StemSize]] = value - return n.insertMultiple(key[:StemSize], values) + return n.insertMultiple(stem, values) } -func (n *LeafNode) insertMultiple(stem []byte, values [][]byte) error { +func (n *LeafNode) insertMultiple(stem Stem, values [][]byte) error { // Sanity check: ensure the stems are the same. if !equalPaths(stem, n.stem) { return errInsertIntoOtherStem @@ -1236,8 +1248,8 @@ func (n *LeafNode) Delete(k []byte, _ NodeResolverFn) (bool, error) { } // Erase the value it used to contain - original := n.values[k[31]] // save original value - n.values[k[31]] = nil + original := n.values[k[StemSize]] // save original value + n.values[k[StemSize]] = nil // Check if a Cn subtree is entirely empty, or if // the entire subtree is empty. @@ -1247,18 +1259,18 @@ func (n *LeafNode) Delete(k []byte, _ NodeResolverFn) (bool, error) { ) for i := 0; i < NodeWidth; i++ { if len(n.values[i]) > 0 { - // if i and k[31] are in the same subtree, + // if i and k[StemSize] are in the same subtree, // set both values and return. - if byte(i/128) == k[31]/128 { + if byte(i/128) == k[StemSize]/128 { isCnempty = false isCempty = false break } - // i and k[31] were in a different subtree, + // i and k[StemSize] were in a different subtree, // so all we can say at this stage, is that // the whole tree isn't empty. - // TODO if i < 128, then k[31] >= 128 and + // TODO if i < 128, then k[StemSize] >= 128 and // we could skip to 128, but that's an // optimization for later. isCempty = false @@ -1277,10 +1289,10 @@ func (n *LeafNode) Delete(k []byte, _ NodeResolverFn) (bool, error) { if isCnempty { var ( cn *Point - subtreeindex = 2 + k[31]/128 + subtreeindex = 2 + k[StemSize]/128 ) - if k[31] < 128 { + if k[StemSize] < 128 { cn = n.c1 } else { cn = n.c2 @@ -1297,7 +1309,7 @@ func (n *LeafNode) Delete(k []byte, _ NodeResolverFn) (bool, error) { n.commitment.Sub(n.commitment, cfg.CommitToPoly(poly[:], 0)) // Clear the corresponding commitment - if k[31] < 128 { + if k[StemSize] < 128 { n.c1 = nil } else { n.c2 = nil @@ -1316,8 +1328,8 @@ func (n *LeafNode) Delete(k []byte, _ NodeResolverFn) (bool, error) { // Note that the value is set to nil by // the method, as it needs the original // value to compute the commitment diffs. - n.values[k[31]] = original - return false, n.updateLeaf(k[31], nil) + n.values[k[StemSize]] = original + return false, n.updateLeaf(k[StemSize], nil) } func (n *LeafNode) Get(k []byte, _ NodeResolverFn) ([]byte, error) { @@ -1404,7 +1416,7 @@ func leafToComms(poly []Fr, val []byte) error { return nil } -func (n *LeafNode) GetProofItems(keys keylist, _ NodeResolverFn) (*ProofElements, []byte, [][]byte, error) { // skipcq: GO-R1005 +func (n *LeafNode) GetProofItems(keys keylist, _ NodeResolverFn) (*ProofElements, []byte, []Stem, error) { // skipcq: GO-R1005 var ( poly [NodeWidth]Fr // top-level polynomial pe = &ProofElements{ @@ -1416,8 +1428,8 @@ func (n *LeafNode) GetProofItems(keys keylist, _ NodeResolverFn) (*ProofElements ByPath: map[string]*Point{}, } - esses []byte = nil // list of extension statuses - poass [][]byte // list of proof-of-absence stems + esses []byte = nil // list of extension statuses + poass []Stem // list of proof-of-absence stems ) // Initialize the top-level polynomial with 1 + stem + C1 + C2 @@ -1433,8 +1445,8 @@ func (n *LeafNode) GetProofItems(keys keylist, _ NodeResolverFn) (*ProofElements // We should only analize the inclusion of C1/C2 for keys corresponding to this // leaf node stem. if equalPaths(n.stem, key) { - hasC1 = hasC1 || (key[31] < 128) - hasC2 = hasC2 || (key[31] >= 128) + hasC1 = hasC1 || (key[StemSize] < 128) + hasC2 = hasC2 || (key[StemSize] >= 128) if hasC2 { break } @@ -1486,9 +1498,10 @@ func (n *LeafNode) GetProofItems(keys keylist, _ NodeResolverFn) (*ProofElements // Add an extension status absent other for this stem. // Note we keep a cache to avoid adding the same stem twice (or more) if // there're multiple keys with the same stem. - if _, ok := addedStems[string(key[:StemSize])]; !ok { + stemStr := string(KeyToStem(key)) + if _, ok := addedStems[stemStr]; !ok { esses = append(esses, extStatusAbsentOther|(n.depth<<3)) - addedStems[string(key[:StemSize])] = struct{}{} + addedStems[stemStr] = struct{}{} } pe.Vals = append(pe.Vals, nil) continue @@ -1504,7 +1517,7 @@ func (n *LeafNode) GetProofItems(keys keylist, _ NodeResolverFn) (*ProofElements } var ( - suffix = key[31] + suffix = key[StemSize] suffPoly [NodeWidth]Fr // suffix-level polynomial err error scomm *Point @@ -1539,11 +1552,12 @@ func (n *LeafNode) GetProofItems(keys keylist, _ NodeResolverFn) (*ProofElements pe.Zis = append(pe.Zis, 2*suffix, 2*suffix+1) pe.Yis = append(pe.Yis, &leaves[0], &leaves[1]) pe.Fis = append(pe.Fis, suffPoly[:], suffPoly[:]) - pe.Vals = append(pe.Vals, n.values[key[31]]) + pe.Vals = append(pe.Vals, n.values[key[StemSize]]) - if _, ok := addedStems[string(key[:StemSize])]; !ok { + stemStr := string(KeyToStem(key)) + if _, ok := addedStems[stemStr]; !ok { esses = append(esses, extStatusPresent|(n.depth<<3)) - addedStems[string(key[:StemSize])] = struct{}{} + addedStems[stemStr] = struct{}{} } slotPath := string(key[:n.depth]) + string([]byte{2 + suffix/128}) @@ -1590,7 +1604,7 @@ func (n *LeafNode) Copy() VerkleNode { func (n *LeafNode) Key(i int) []byte { var ret [32]byte copy(ret[:], n.stem) - ret[31] = byte(i) + ret[StemSize] = byte(i) return ret[:] } diff --git a/tree_ipa_test.go b/tree_ipa_test.go index eb468acd..afb0508a 100644 --- a/tree_ipa_test.go +++ b/tree_ipa_test.go @@ -53,7 +53,7 @@ func extensionAndSuffixOneKey(t *testing.T, key, value []byte, ret *Point) { t1, t2, c1 Point ) stemComm0 := srs[0] - err := StemFromBytes(&v, key[:31]) + err := StemFromBytes(&v, KeyToStem(key)) if err != nil { panic(err) } @@ -62,7 +62,7 @@ func extensionAndSuffixOneKey(t *testing.T, key, value []byte, ret *Point) { if err := leafToComms(vs[:], value); err != nil { t.Fatalf("leafToComms failed: %s", err) } - c1.Add(t1.ScalarMul(&srs[2*key[31]], &vs[0]), t2.ScalarMul(&srs[2*key[31]+1], &vs[1])) + c1.Add(t1.ScalarMul(&srs[2*key[StemSize]], &vs[0]), t2.ScalarMul(&srs[2*key[StemSize]+1], &vs[1])) c1.MapToScalarField(&v) stemComm2.ScalarMul(&srs[2], &v) @@ -165,7 +165,7 @@ func TestInsertSameStemTwoLeaves(t *testing.T) { comm := root.Commit() stemComm0 := srs[0] - err := StemFromBytes(&v, key_a[:31]) + err := StemFromBytes(&v, KeyToStem(key_a)) if err != nil { t.Fatal(err) } @@ -309,7 +309,7 @@ func TestPaddingInFromLEBytes(t *testing.T) { t.Fatal(err) } key, _ := hex.DecodeString("ffffffffffffffffffffffffffffffff00000000000000000000000000000000") - err := StemFromBytes(&fr2, key[:StemSize]) + err := StemFromBytes(&fr2, KeyToStem(key)) if err != nil { t.Fatal(err) } diff --git a/tree_test.go b/tree_test.go index fb49f622..4d65e236 100644 --- a/tree_test.go +++ b/tree_test.go @@ -69,8 +69,8 @@ func TestInsertIntoRoot(t *testing.T) { t.Fatalf("invalid leaf node type %v", root.(*InternalNode).children[0]) } - if !bytes.Equal(leaf.values[zeroKeyTest[31]], testValue) { - t.Fatalf("did not find correct value in trie %x != %x", testValue, leaf.values[zeroKeyTest[31]]) + if !bytes.Equal(leaf.values[zeroKeyTest[StemSize]], testValue) { + t.Fatalf("did not find correct value in trie %x != %x", testValue, leaf.values[zeroKeyTest[StemSize]]) } } @@ -95,12 +95,12 @@ func TestInsertTwoLeaves(t *testing.T) { t.Fatalf("invalid leaf node type %v", root.(*InternalNode).children[255]) } - if !bytes.Equal(leaf0.values[zeroKeyTest[31]], testValue) { - t.Fatalf("did not find correct value in trie %x != %x", testValue, leaf0.values[zeroKeyTest[31]]) + if !bytes.Equal(leaf0.values[zeroKeyTest[StemSize]], testValue) { + t.Fatalf("did not find correct value in trie %x != %x", testValue, leaf0.values[zeroKeyTest[StemSize]]) } if !bytes.Equal(leaff.values[255], testValue) { - t.Fatalf("did not find correct value in trie %x != %x", testValue, leaff.values[ffx32KeyTest[31]]) + t.Fatalf("did not find correct value in trie %x != %x", testValue, leaff.values[ffx32KeyTest[StemSize]]) } } @@ -872,10 +872,10 @@ func TestGetKey(t *testing.T) { root := &LeafNode{stem: fourtyKeyTest} for i := 0; i < NodeWidth; i++ { k := root.Key(i) - if !bytes.Equal(k[:31], fourtyKeyTest[:31]) { + if !bytes.Equal(KeyToStem(k), KeyToStem(fourtyKeyTest)) { t.Fatal("invalid stem") } - if int(k[31]) != i { + if int(k[StemSize]) != i { t.Fatal("invalid selector") } } @@ -901,7 +901,7 @@ func TestInsertIntoHashedNode(t *testing.T) { resolver := func(h []byte) ([]byte, error) { values := make([][]byte, NodeWidth) values[0] = zeroKeyTest - node, _ := NewLeafNode(zeroKeyTest[:31], values) + node, _ := NewLeafNode(KeyToStem(zeroKeyTest), values) return node.Serialize() } @@ -914,7 +914,7 @@ func TestInsertIntoHashedNode(t *testing.T) { invalidRLPResolver := func(h []byte) ([]byte, error) { values := make([][]byte, NodeWidth) values[0] = zeroKeyTest - node, _ := NewLeafNode(zeroKeyTest[:31], values) + node, _ := NewLeafNode(KeyToStem(zeroKeyTest), values) rlp, _ := node.Serialize() return rlp[:len(rlp)-10], nil @@ -1106,16 +1106,16 @@ func TestInsertStem(t *testing.T) { values[5] = zeroKeyTest values[192] = fourtyKeyTest - if err := root1.(*InternalNode).InsertValuesAtStem(fourtyKeyTest[:31], values, nil); err != nil { + if err := root1.(*InternalNode).InsertValuesAtStem(KeyToStem(fourtyKeyTest), values, nil); err != nil { t.Fatalf("error inserting: %s", err) } r1c := root1.Commit() var key5, key192 [32]byte - copy(key5[:], fourtyKeyTest[:31]) - copy(key192[:], fourtyKeyTest[:31]) - key5[31] = 5 - key192[31] = 192 + copy(key5[:], KeyToStem(fourtyKeyTest)) + copy(key192[:], KeyToStem(fourtyKeyTest)) + key5[StemSize] = 5 + key192[StemSize] = 192 if err := root2.Insert(key5[:], zeroKeyTest, nil); err != nil { t.Fatalf("error inserting: %s", err) } @@ -1154,7 +1154,7 @@ func TestInsertStemTouchingBothHalves(t *testing.T) { newValues := make([][]byte, NodeWidth) newValues[1] = testValue newValues[NodeWidth-2] = testValue - if err := root.(*InternalNode).InsertValuesAtStem(zeroKeyTest[:StemSize], newValues, nil); err != nil { + if err := root.(*InternalNode).InsertValuesAtStem(KeyToStem(zeroKeyTest), newValues, nil); err != nil { t.Fatalf("error inserting stem: %v", err) } root.Commit() @@ -1217,7 +1217,7 @@ func TestInsertResolveSplitLeaf(t *testing.T) { if !ok { t.Fatal("resolve with resolver didn't produce a leaf node where expected") } - if !bytes.Equal(l.stem, zeroKeyTest[:31]) && !bytes.Equal(l.values[0], ffx32KeyTest) { + if !bytes.Equal(l.stem, KeyToStem(zeroKeyTest)) && !bytes.Equal(l.values[0], ffx32KeyTest) { t.Fatal("didn't find the resolved leaf where expected") } } @@ -1434,17 +1434,18 @@ func TestBatchMigratedKeyValues(t *testing.T) { // Create LeafNodes in batch mode. nodeValues := make([]BatchNewLeafNodeData, 0, len(randomKeyValues)) curr := BatchNewLeafNodeData{ - Stem: randomKeyValues[0].key[:StemSize], + Stem: KeyToStem(randomKeyValues[0].key), Values: map[byte][]byte{randomKeyValues[0].key[StemSize]: randomKeyValues[0].value}, } for _, kv := range randomKeyValues[1:] { - if bytes.Equal(curr.Stem, kv.key[:StemSize]) { + stem := KeyToStem(kv.key) + if bytes.Equal(curr.Stem, stem) { curr.Values[kv.key[StemSize]] = kv.value continue } nodeValues = append(nodeValues, curr) curr = BatchNewLeafNodeData{ - Stem: kv.key[:StemSize], + Stem: stem, Values: map[byte][]byte{kv.key[StemSize]: kv.value}, } } @@ -1525,17 +1526,18 @@ func BenchmarkBatchLeavesInsert(b *testing.B) { // Create LeafNodes in batch mode. nodeValues := make([]BatchNewLeafNodeData, 0, len(randomKeyValues)) curr := BatchNewLeafNodeData{ - Stem: randomKeyValues[0].key[:StemSize], + Stem: KeyToStem(randomKeyValues[0].key), Values: map[byte][]byte{randomKeyValues[0].key[StemSize]: randomKeyValues[0].value}, } for _, kv := range randomKeyValues[1:] { - if bytes.Equal(curr.Stem, kv.key[:StemSize]) { + stem := KeyToStem(kv.key) + if bytes.Equal(curr.Stem, stem) { curr.Values[kv.key[StemSize]] = kv.value continue } nodeValues = append(nodeValues, curr) curr = BatchNewLeafNodeData{ - Stem: kv.key[:StemSize], + Stem: stem, Values: map[byte][]byte{kv.key[StemSize]: kv.value}, } } @@ -1570,7 +1572,7 @@ func TestManipulateChildren(t *testing.T) { if !ok { t.Fatalf("failed to get expected leaf node") } - if !bytes.Equal(ln.stem, ffx32KeyTest[:StemSize]) || !bytes.Equal(ln.values[NodeWidth-1], testValue) { + if !bytes.Equal(ln.stem, KeyToStem(ffx32KeyTest)) || !bytes.Equal(ln.values[NodeWidth-1], testValue) { t.Fatalf("failed to get expected leaf node stem and values") } @@ -1596,13 +1598,13 @@ func TestLeafNodeInsert(t *testing.T) { values := make([][]byte, NodeWidth) valIdx := 42 values[valIdx] = testValue - ln, err := NewLeafNode(keyTest[:StemSize], values) + ln, err := NewLeafNode(KeyToStem(keyTest), values) if err != nil { t.Fatalf("failed to create leaf node: %v", err) } // Check we get the value correctly via Get(...). - getValue, err := ln.Get(append(keyTest[:StemSize], byte(valIdx)), nil) + getValue, err := ln.Get(append(KeyToStem(keyTest), byte(valIdx)), nil) if err != nil { t.Fatalf("failed to get leaf node key/value: %v", err) } @@ -1637,7 +1639,7 @@ func TestLeafNodeInsert(t *testing.T) { } // Check wrong *key* length. - if err := ln.Insert(ffx32KeyTest2[:StemSize], newValue, nil); err == nil { + if err := ln.Insert(KeyToStem(ffx32KeyTest2), newValue, nil); err == nil { t.Fatalf("key with size 31 should not be accepted, keys must have length StemSize+1") } diff --git a/unknown.go b/unknown.go index a8348eb9..28d28666 100644 --- a/unknown.go +++ b/unknown.go @@ -51,7 +51,7 @@ func (UnknownNode) Commitment() *Point { return &id } -func (UnknownNode) GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, [][]byte, error) { +func (UnknownNode) GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, []Stem, error) { return nil, nil, nil, errors.New("can't generate proof items for unknown node") }