1
1
use crate :: {
2
2
evm_circuit:: {
3
3
execution:: ExecutionGadget ,
4
- param:: { N_BYTES_MEMORY_ADDRESS , N_BYTES_MEMORY_WORD_SIZE } ,
4
+ param:: { N_BYTES_MEMORY_ADDRESS , N_BYTES_MEMORY_CHUNK , N_BYTES_MEMORY_WORD_SIZE } ,
5
5
step:: ExecutionState ,
6
6
util:: {
7
7
common_gadget:: SameContextGadget ,
@@ -11,13 +11,14 @@ use crate::{
11
11
} ,
12
12
from_bytes,
13
13
math_gadget:: IsEqualGadget ,
14
- memory_gadget:: { MemoryExpansionGadget , MemoryWordAddress } ,
14
+ memory_gadget:: { MemoryExpansionGadget , MemoryMask , MemoryWordAddress } ,
15
15
not, CachedRegion , Cell , MemoryAddress , Word ,
16
16
} ,
17
17
witness:: { Block , Call , ExecStep , Transaction } ,
18
18
} ,
19
19
util:: Expr ,
20
20
} ;
21
+ use array_init:: array_init;
21
22
use eth_types:: { evm_types:: OpcodeId , Field , ToLittleEndian , U256 } ;
22
23
use halo2_proofs:: { circuit:: Value , plonk:: Error } ;
23
24
@@ -31,14 +32,20 @@ pub(crate) struct MemoryGadget<F> {
31
32
//address: MemoryAddress<F>,
32
33
address : MemoryWordAddress < F > ,
33
34
// consider move to MemoryWordAddress ?
35
+ /// The value poped from or pushed to the stack.
34
36
value : Word < F > ,
37
+ /// The left memory word read or written.
35
38
value_left : Word < F > ,
39
+ /// The left memory word before the write.
40
+ value_left_prev : Word < F > ,
41
+ /// The right memory word read or written.
36
42
value_right : Word < F > ,
43
+ /// The right memory word before the write.
44
+ value_right_prev : Word < F > ,
37
45
memory_expansion : MemoryExpansionGadget < F , 1 , N_BYTES_MEMORY_WORD_SIZE > ,
38
46
is_mload : IsEqualGadget < F > ,
39
47
is_mstore8 : IsEqualGadget < F > ,
40
- // TODO: add mask
41
- // mask: [Cell<F>, 5]
48
+ mask : MemoryMask < F > ,
42
49
}
43
50
44
51
impl < F : Field > ExecutionGadget < F > for MemoryGadget < F > {
@@ -52,9 +59,12 @@ impl<F: Field> ExecutionGadget<F> for MemoryGadget<F> {
52
59
// In successful case the address must be in 5 bytes
53
60
let address = cb. query_word_rlc ( ) ;
54
61
let address_word = MemoryWordAddress :: construct ( cb, address. clone ( ) ) ;
62
+ // TODO: we do not need the 32 bytes of the value, only the RLC.
55
63
let value = cb. query_word_rlc ( ) ;
56
64
let value_left = cb. query_word_rlc ( ) ;
65
+ let value_left_prev = cb. query_word_rlc ( ) ;
57
66
let value_right = cb. query_word_rlc ( ) ;
67
+ let value_right_prev = cb. query_word_rlc ( ) ;
58
68
59
69
// Check if this is an MLOAD
60
70
let is_mload = IsEqualGadget :: construct ( cb, opcode. expr ( ) , OpcodeId :: MLOAD . expr ( ) ) ;
@@ -72,6 +82,33 @@ impl<F: Field> ExecutionGadget<F> for MemoryGadget<F> {
72
82
[ from_bytes:: expr ( & address. cells ) + 1 . expr ( ) + ( is_not_mstore8. clone ( ) * 31 . expr ( ) ) ] ,
73
83
) ;
74
84
85
+ let shift_bits = address_word. shift_bits ( ) ;
86
+
87
+ let mask = MemoryMask :: construct ( cb, & shift_bits, is_mstore8. expr ( ) ) ;
88
+
89
+ // Extract word parts. Example with shift=4:
90
+ // Left = Aaaa Bbbbbbbbbbbbbbbbbbbbbbbbbbbb
91
+ // Right = Cccc Dddddddddddddddddddddddddddd
92
+ let a = mask. get_left ( cb, & value_left) ;
93
+ let a_prev = mask. get_left ( cb, & value_left_prev) ;
94
+ let b = mask. get_right ( cb, & value_left) ;
95
+ let c = mask. get_left ( cb, & value_right) ;
96
+ let d = mask. get_right ( cb, & value_right) ;
97
+ let d_prev = mask. get_right ( cb, & value_right_prev) ;
98
+
99
+ cb. require_equal ( "unchanged left bytes: L' & M == L & M" , a, a_prev) ;
100
+
101
+ cb. require_equal ( "unchanged right bytes: R' & !M == R & !M" , d, d_prev) ;
102
+
103
+ // Compute powers of the RLC challenge. These are used to shift bytes in equations below.
104
+ let x = cb. challenges ( ) . evm_word ( ) ;
105
+ // X**32
106
+ let x32 = MemoryMask :: make_x32 ( x. clone ( ) ) ;
107
+ // X**(31-shift)
108
+ let x31_shift = MemoryMask :: make_x31_off ( x. clone ( ) , & shift_bits) ;
109
+ // X**(32-shift)
110
+ let x32_shift = x * x31_shift. clone ( ) ;
111
+
75
112
// Stack operations
76
113
// Pop the address from the stack
77
114
cb. stack_pop ( address. expr ( ) ) ;
@@ -83,8 +120,12 @@ impl<F: Field> ExecutionGadget<F> for MemoryGadget<F> {
83
120
value. expr ( ) ,
84
121
) ;
85
122
86
- // TODO: replace with value_left = instruction.memory_lookup(RW.Write, addr_left)
87
123
cb. condition ( is_mstore8. expr ( ) , |cb| {
124
+ cb. require_equal (
125
+ "W[0] * X³¹⁻ˢʰⁱᶠᵗ = B(X)" ,
126
+ value. cells [ 0 ] . expr ( ) * x31_shift. clone ( ) ,
127
+ b. clone ( ) ,
128
+ ) ;
88
129
cb. memory_lookup_word ( 1 . expr ( ) , address_word. addr_left ( ) , value_left. expr ( ) , None ) ;
89
130
} ) ;
90
131
@@ -95,6 +136,12 @@ impl<F: Field> ExecutionGadget<F> for MemoryGadget<F> {
95
136
// RW.Write if is_store == FQ(1) else RW.Read, addr_right
96
137
// )
97
138
cb. condition ( is_not_mstore8, |cb| {
139
+ cb. require_equal (
140
+ "W(X) * X³²⁻ˢʰⁱᶠᵗ = B(X) * X³² + C(X)" ,
141
+ value. expr ( ) * x32_shift,
142
+ b * x32 + c,
143
+ ) ;
144
+
98
145
cb. memory_lookup_word (
99
146
is_store. clone ( ) ,
100
147
address_word. addr_left ( ) ,
@@ -132,10 +179,13 @@ impl<F: Field> ExecutionGadget<F> for MemoryGadget<F> {
132
179
address : address_word,
133
180
value,
134
181
value_left,
182
+ value_left_prev,
135
183
value_right,
184
+ value_right_prev,
136
185
memory_expansion,
137
186
is_mload,
138
187
is_mstore8,
188
+ mask,
139
189
}
140
190
}
141
191
@@ -167,11 +217,6 @@ impl<F: Field> ExecutionGadget<F> for MemoryGadget<F> {
167
217
self . value
168
218
. assign ( region, offset, Some ( value. to_le_bytes ( ) ) ) ?;
169
219
170
- // TODO: assign value_right
171
- let address_u64 = address. as_u64 ( ) ;
172
- let shift = address_u64 % 32 ;
173
- let slot = address_u64 - shift;
174
- println ! ( "slot {}, shift {}" , slot, shift) ;
175
220
// Check if this is an MLOAD
176
221
self . is_mload . assign (
177
222
region,
@@ -187,6 +232,10 @@ impl<F: Field> ExecutionGadget<F> for MemoryGadget<F> {
187
232
F :: from ( OpcodeId :: MSTORE8 . as_u64 ( ) ) ,
188
233
) ?;
189
234
235
+ let shift = address. as_u64 ( ) % 32 ;
236
+ self . mask
237
+ . assign ( region, offset, shift, is_mstore8 == F :: one ( ) ) ?;
238
+
190
239
// Memory expansion
191
240
self . memory_expansion . assign (
192
241
region,
@@ -203,11 +252,22 @@ impl<F: Field> ExecutionGadget<F> for MemoryGadget<F> {
203
252
block. rws [ step. rw_indices [ 3 ] ] . memory_word_value ( )
204
253
} ;
205
254
255
+ // TODO: rm.
256
+ println ! ( "address: {:?}" , address) ;
257
+ println ! ( "value (LE): {:?}" , value. to_le_bytes( ) ) ;
258
+ println ! ( "value_left: {:?}" , value_left. to_le_bytes( ) ) ;
259
+ println ! ( "value_right: {:?}" , value_right. to_le_bytes( ) ) ;
260
+
261
+ // TODO: updated values for MSTORE.
206
262
self . value_left
207
263
. assign ( region, offset, Some ( value_left. to_le_bytes ( ) ) ) ?;
264
+ self . value_left_prev
265
+ . assign ( region, offset, Some ( value_left. to_le_bytes ( ) ) ) ?;
208
266
209
267
self . value_right
210
268
. assign ( region, offset, Some ( value_right. to_le_bytes ( ) ) ) ?;
269
+ self . value_right_prev
270
+ . assign ( region, offset, Some ( value_right. to_le_bytes ( ) ) ) ?;
211
271
Ok ( ( ) )
212
272
}
213
273
}
0 commit comments