Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: change prehash value back to sha256 from noop #19002

Merged
merged 4 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions store/commit_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ func (ci *CommitInfo) Hash() []byte {
return rootHash
}

// GetStoreProof takes in a storeKey and returns a proof of the store key in addition
// to the root hash it should be proved against. If an empty string is provided, the first
// store based on lexographical ordering will be proved.
func (ci *CommitInfo) GetStoreProof(storeKey string) ([]byte, *CommitmentOp, error) {
sort.Slice(ci.StoreInfos, func(i, j int) bool {
return ci.StoreInfos[i].Name < ci.StoreInfos[j].Name
Expand Down
52 changes: 46 additions & 6 deletions store/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var (
LeafSpec: &ics23.LeafOp{
Prefix: leafPrefix,
PrehashKey: ics23.HashOp_NO_HASH,
PrehashValue: ics23.HashOp_NO_HASH,
PrehashValue: ics23.HashOp_SHA256,
Hash: ics23.HashOp_SHA256,
Length: ics23.LengthOp_VAR_PROTO,
},
Expand Down Expand Up @@ -122,31 +122,70 @@ func (op CommitmentOp) Run(args [][]byte) ([][]byte, error) {
return [][]byte{root}, nil
}

// ProofFromByteSlices computes the proof from the given leaves.
// ProofFromByteSlices computes the proof from the given leaves. An iteration will be
// perfomed for each level of the tree, where each iteration hashes together the bottom most
// nodes. If the length of the bottom most nodes is odd, then the last node will be saved
// for the next iteration.
//
// Example:
// Iteration 1:
// n = 5
// leaves = a, b, c, d, e.
// index = 2 (prove c)
//
// Iteration 2:
// n = 3
// leaves = ab, cd, e
// index = 1 (prove c, so index of cd)
//
// Iteration 3:
// n = 2
// leaves = abcd, e
// index = 0 (prove c, so index of abcd)
//
// Final iteration:
// n = 1
// leaves = abcde
// index = 0
//
// The bitwise & operator allows us to determine if the index or length is odd or even.
// The bitwise ^ operator allows us to increment when the value is even and decrement when it is odd.
func ProofFromByteSlices(leaves [][]byte, index int) (rootHash []byte, inners []*ics23.InnerOp) {
if len(leaves) == 0 {
return emptyHash(), nil
}

n := len(leaves)
for n > 1 {
// begin by constructing the proof for the inner node of the requested index
// a proof of the inner node is skipped only in the case where the requested index
// is the last element and it does not have a leaf pair (resulting in it being
// saved until the next iteration)
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
if index < n-1 || index&1 == 1 {
inner := &ics23.InnerOp{Hash: ics23.HashOp_SHA256}
// if proof index is even then child is from left, suffix is populated
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
// otherwise, child is from right and the prefix is populated.
if index&1 == 0 {
// inner op(prefix=0x01 | child | suffix=leaves[index+1])
inner.Prefix = innerPrefix
inner.Suffix = leaves[index^1]
inner.Suffix = leaves[index^1] // XOR op is index+1 because index is even
} else {
inner.Prefix = append(innerPrefix, leaves[index^1]...)
// inner op(prefix=0x01 | leaves[index-1] | child | suffix=nil)
inner.Prefix = append(innerPrefix, leaves[index^1]...) // XOR op is index-1 because index is odd
}
inners = append(inners, inner)
}

// hash together all leaf pairs
for i := 0; i < n/2; i++ {
leaves[i] = InnerHash(leaves[2*i], leaves[2*i+1])
}

// save any leftover leaf for the next iteration
if n&1 == 1 {
leaves[n/2] = leaves[n-1]
}
n = (n + 1) / 2
n = (n + 1) / 2 // n + 1 accounts for any leaves which are added to the next iteration
index /= 2
}

Expand Down Expand Up @@ -178,7 +217,8 @@ func LeafHash(key, value []byte) ([]byte, error) {
return SimpleMerkleSpec.LeafSpec.Apply(key, value)
}

// InnerHash computes the hash of an inner node.
// InnerHash computes the hash of an inner node as defined by ics23:
// https://github.com/cosmos/ics23/blob/go/v0.10.0/proto/cosmos/ics23/v1/proofs.proto#L130
func InnerHash(left, right []byte) []byte {
data := make([]byte, len(innerPrefix)+len(left)+len(right))
n := copy(data, innerPrefix)
Expand Down
12 changes: 6 additions & 6 deletions store/proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,29 @@ func TestProofFromBytesSlices(t *testing.T) {
want string
}{
{[]string{}, []string{}, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
{[]string{"key1"}, []string{"value1"}, "09c468a07fe9bc1f14e754cff0acbad4faf9449449288be8e1d5d1199a247034"},
{[]string{"key1"}, []string{"value2"}, "2131d85de3a8ded5d3a72bfc657f7324138540c520de7401ac8594785a3082fb"},
{[]string{"key1"}, []string{"value1"}, "a44d3cc7daba1a4600b00a2434b30f8b970652169810d6dfa9fb1793a2189324"},
{[]string{"key1"}, []string{"value2"}, "0638e99b3445caec9d95c05e1a3fc1487b4ddec6a952ff337080360b0dcc078c"},
// swap order with 2 keys
{
[]string{"key1", "key2"},
[]string{"value1", "value2"},
"017788f37362dd0687beb59c0b3bfcc17a955120a4cb63dbdd4a0fdf9e07730e",
"8fd19b19e7bb3f2b3ee0574027d8a5a4cec370464ea2db2fbfa5c7d35bb0cff3",
},
{
[]string{"key2", "key1"},
[]string{"value2", "value1"},
"ad2b0c23dbd3376440a5347fba02ff35cfad7930daa5e733930315b6fbb03b26",
"55d4bce1c53b7d394bd41bbfc2b239cc2e1c7e36423612a97181c47e79bb713c",
},
// swap order with 3 keys
{
[]string{"key1", "key2", "key3"},
[]string{"value1", "value2", "value3"},
"68f41a8a3508cb5f8eb3f1c7534a86fea9f59aa4898a5aac2f1bb92834ae2a36",
"1dd674ec6782a0d586a903c9c63326a41cbe56b3bba33ed6ff5b527af6efb3dc",
},
{
[]string{"key1", "key3", "key2"},
[]string{"value1", "value3", "value2"},
"92cd50420c22d0c79f64dd1b04bfd5f5d73265f7ac37e65cf622f3cf8b963805",
"443382fbb629e0d50e86d6ea49e22aa4e27ba50262730b0122cec36860c903a2",
},
}
for i, tc := range tests {
Expand Down
Loading