@@ -14,31 +14,66 @@ pub fn words_to_bytes_le(words: &[u32; 8]) -> [u8; 32] {
14
14
bytes
15
15
}
16
16
17
- /// Encode a list of vkeys and committed values into a single byte array. In the future this could
18
- /// be a merkle tree or some other commitment scheme.
17
+ /// Encode a vkey and a committed value into a single byte array.
19
18
///
20
- /// ( vkeys.len() || vkeys || committed_values[0].len as u32 || committed_values[0] || ... )
21
- pub fn commit_proof_pairs ( vkeys : & [ [ u32 ; 8 ] ] , committed_values : & [ Vec < u8 > ] ) -> Vec < u8 > {
22
- assert_eq ! ( vkeys. len( ) , committed_values. len( ) ) ;
23
- let mut res = Vec :: with_capacity (
24
- 4 + vkeys. len ( ) * 32
25
- + committed_values. len ( ) * 4
26
- + committed_values. iter ( ) . map ( |vals| vals. len ( ) ) . sum :: < usize > ( ) ,
27
- ) ;
28
-
19
+ /// ( words_to_bytes_le(vkey) || (committed_value.len() as u32).to_be_bytes() || committed_value )
20
+ pub fn commit_proof_pair ( vkey : & [ u32 ; 8 ] , committed_value : & Vec < u8 > ) -> Vec < u8 > {
21
+ let mut res = Vec :: new ( ) ;
22
+ res. extend_from_slice ( & words_to_bytes_le ( vkey) ) ;
29
23
// Note we use big endian because abi.encodePacked in solidity does also
30
- res. extend_from_slice ( & ( vkeys. len ( ) as u32 ) . to_be_bytes ( ) ) ;
31
- for vkey in vkeys. iter ( ) {
32
- res. extend_from_slice ( & words_to_bytes_le ( vkey) ) ;
33
- }
34
- for vals in committed_values. iter ( ) {
35
- res. extend_from_slice ( & ( vals. len ( ) as u32 ) . to_be_bytes ( ) ) ;
36
- res. extend_from_slice ( vals) ;
37
- }
24
+ res. extend_from_slice ( & ( committed_value. len ( ) as u32 ) . to_be_bytes ( ) ) ;
25
+ res. extend_from_slice ( committed_value) ;
26
+ res
27
+ }
38
28
29
+ /// Computes hash of a leaf in a merkle tree.
30
+ ///
31
+ /// A leaf in a merkle tree is a pair of a verification key and a committed value.
32
+ /// The leaf is encoded as a byte array using `commit_proof_pair` and then hashed using sha256.
33
+ pub fn compute_leaf_hash ( vkey : & [ u32 ; 8 ] , committed_value : & Vec < u8 > ) -> [ u8 ; 32 ] {
34
+ // encode the leaf as a byte array
35
+ let leaf = commit_proof_pair ( vkey, committed_value) ;
36
+ let digest = Sha256 :: digest ( & leaf) ;
37
+ let mut res = [ 0u8 ; 32 ] ;
38
+ res. copy_from_slice ( & digest) ;
39
+ res
40
+ }
41
+
42
+ /// Hashes a pair of already hashed leaves.
43
+ ///
44
+ /// The hash is computed as sha256(left || right).
45
+ pub fn hash_pair ( left : & [ u8 ] , right : & [ u8 ] ) -> [ u8 ; 32 ] {
46
+ let mut hasher = Sha256 :: new ( ) ;
47
+ hasher. update ( left) ;
48
+ hasher. update ( right) ;
49
+ let digest = hasher. finalize ( ) ;
50
+ let mut res = [ 0u8 ; 32 ] ;
51
+ res. copy_from_slice ( & digest) ;
39
52
res
40
53
}
41
54
55
+ /// Computes the root of a merkle tree given the leaves.
56
+ ///
57
+ /// The leaves are hashed using `compute_leaf_hash` and then the hashes are combined to form the root.
58
+ /// The root is computed by hashing pairs of hashes until only one hash remains.
59
+ pub fn compute_merkle_root ( mut leaves : Vec < [ u8 ; 32 ] > ) -> [ u8 ; 32 ] {
60
+ if leaves. is_empty ( ) {
61
+ return [ 0u8 ; 32 ] ;
62
+ }
63
+
64
+
65
+ while leaves. len ( ) > 1 {
66
+ let mut next = Vec :: new ( ) ;
67
+ for i in ( 0 ..leaves. len ( ) ) . step_by ( 2 ) {
68
+ let left = & leaves[ i] ;
69
+ let right = if i + 1 < leaves. len ( ) { & leaves[ i + 1 ] } else { & leaves[ i] } ;
70
+ next. push ( hash_pair ( left, right) ) ;
71
+ }
72
+ leaves = next;
73
+ }
74
+ leaves[ 0 ]
75
+ }
76
+
42
77
pub fn main ( ) {
43
78
// Read the verification keys.
44
79
let vkeys = sp1_zkvm:: io:: read :: < Vec < [ u32 ; 8 ] > > ( ) ;
@@ -55,10 +90,16 @@ pub fn main() {
55
90
sp1_zkvm:: lib:: verify:: verify_sp1_proof ( vkey, & public_values_digest. into ( ) ) ;
56
91
}
57
92
58
- // TODO: Do something interesting with the proofs here.
59
- //
60
- // For example, commit to the verified proofs in a merkle tree. For now, we'll just commit to
61
- // all the (vkey, input) pairs.
62
- let commitment = commit_proof_pairs ( & vkeys, & public_values) ;
63
- sp1_zkvm:: io:: commit_slice ( & commitment) ;
93
+ // Convert the (vkey, public_value) pairs into leaves of a merkle tree.
94
+ let leaves: Vec < [ u8 ; 32 ] > = vkeys
95
+ . iter ( )
96
+ . zip ( public_values. iter ( ) )
97
+ . map ( |( vkey, public_value) | compute_leaf_hash ( vkey, public_value) )
98
+ . collect ( ) ;
99
+
100
+ // Traverse the merkle tree bottom-up to compute the root.
101
+ let merkle_root = compute_merkle_root ( leaves) ;
102
+
103
+ // Commit the root.
104
+ sp1_zkvm:: io:: commit_slice ( & merkle_root) ;
64
105
}
0 commit comments