@@ -34,7 +34,6 @@ use openvm_instructions::{
34
34
LocalOpcode ,
35
35
} ;
36
36
use openvm_memcpy_transpiler:: Rv32MemcpyOpcode ;
37
- use openvm_rv32im_circuit:: adapters:: { read_rv32_register, tracing_read, tracing_write} ;
38
37
use openvm_stark_backend:: {
39
38
interaction:: InteractionBuilder ,
40
39
p3_air:: { Air , AirBuilder , BaseAir } ,
@@ -45,8 +44,7 @@ use openvm_stark_backend::{
45
44
} ;
46
45
47
46
use crate :: {
48
- bus:: MemcpyBus , MemcpyLoopChip , A1_REGISTER_PTR , A2_REGISTER_PTR , A3_REGISTER_PTR ,
49
- A4_REGISTER_PTR ,
47
+ bus:: MemcpyBus , read_rv32_register, tracing_read, tracing_write, MemcpyLoopChip , A1_REGISTER_PTR , A2_REGISTER_PTR , A3_REGISTER_PTR , A4_REGISTER_PTR
50
48
} ;
51
49
// Import constants from lib.rs
52
50
use crate :: { MEMCPY_LOOP_LIMB_BITS , MEMCPY_LOOP_NUM_LIMBS } ;
@@ -58,10 +56,12 @@ pub struct MemcpyIterCols<T> {
58
56
pub dest : T ,
59
57
pub source : T ,
60
58
pub len : [ T ; 2 ] ,
61
- pub shift : [ T ; 2 ] ,
59
+ // 0: [0, 0, 0], 1: [1, 0, 0], 2: [0, 1, 0], 3: [0, 0, 1]
60
+ pub shift : [ T ; 3 ] ,
62
61
pub is_valid : T ,
63
62
pub is_valid_not_start : T ,
64
- pub is_shift_non_zero : T ,
63
+ // This should be 0 if is_valid = 0. We use this to determine whether we need ro read data_4.
64
+ pub is_shift_non_zero_or_not_start : T ,
65
65
// -1 for the first iteration, 1 for the last iteration, 0 for the middle iterations
66
66
pub is_boundary : T ,
67
67
pub data_1 : [ T ; MEMCPY_LOOP_NUM_LIMBS ] ,
@@ -100,16 +100,21 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
100
100
101
101
let timestamp: AB :: Var = local. timestamp ;
102
102
let mut timestamp_delta: AB :: Expr = AB :: Expr :: ZERO ;
103
- let mut timestamp_pp = |timestamp_increase_value : AB :: Expr | {
104
- timestamp_delta += timestamp_increase_value. clone ( ) ;
103
+ let mut timestamp_pp = |timestamp_increase_value : AB :: Var | {
104
+ timestamp_delta += timestamp_increase_value. into ( ) ;
105
105
timestamp + timestamp_delta. clone ( ) - timestamp_increase_value. clone ( )
106
106
} ;
107
107
108
- let shift = local. shift [ 1 ] * AB :: Expr :: TWO + local. shift [ 0 ] ;
109
- let is_shift_zero = not :: < AB :: Expr > ( local. is_shift_non_zero ) ;
110
- let is_shift_one = and :: < AB :: Expr > ( local. shift [ 0 ] , not :: < AB :: Expr > ( local. shift [ 1 ] ) ) ;
111
- let is_shift_two = and :: < AB :: Expr > ( not :: < AB :: Expr > ( local. shift [ 0 ] ) , local. shift [ 1 ] ) ;
112
- let is_shift_three = and :: < AB :: Expr > ( local. shift [ 0 ] , local. shift [ 1 ] ) ;
108
+ let shift = local. shift . iter ( ) . enumerate ( ) . fold ( AB :: Expr :: ZERO , |acc, ( i, x) | {
109
+ acc + ( * x) * AB :: Expr :: from_canonical_u32 ( i as u32 + 1 )
110
+ } ) ;
111
+ let is_shift_non_zero = local. shift . iter ( ) . fold ( AB :: Expr :: ZERO , |acc, x| {
112
+ acc + ( * x)
113
+ } ) ;
114
+ let is_shift_zero = not :: < AB :: Expr > ( is_shift_non_zero. clone ( ) ) ;
115
+ let is_shift_one = local. shift [ 0 ] ;
116
+ let is_shift_two = local. shift [ 1 ] ;
117
+ let is_shift_three = local. shift [ 2 ] ;
113
118
114
119
let is_end =
115
120
( local. is_boundary + AB :: Expr :: ONE ) * local. is_boundary * ( AB :: F :: TWO ) . inverse ( ) ;
@@ -166,8 +171,9 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
166
171
167
172
builder. assert_bool ( local. is_valid ) ;
168
173
local. shift . iter ( ) . for_each ( |x| builder. assert_bool ( * x) ) ;
174
+ builder. assert_bool ( is_shift_non_zero. clone ( ) ) ;
169
175
builder. assert_bool ( local. is_valid_not_start ) ;
170
- builder. assert_bool ( local. is_shift_non_zero ) ;
176
+ builder. assert_bool ( local. is_shift_non_zero_or_not_start ) ;
171
177
// is_boundary is either -1, 0 or 1
172
178
builder. assert_tern ( local. is_boundary + AB :: Expr :: ONE ) ;
173
179
@@ -177,8 +183,8 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
177
183
and :: < AB :: Expr > ( local. is_valid , is_not_start) ,
178
184
) ;
179
185
180
- // is_shift_non_zero is correct
181
- builder. assert_eq ( local. is_shift_non_zero , or :: < AB :: Expr > ( local . shift [ 0 ] , local. shift [ 1 ] ) ) ;
186
+ // is_shift_non_zero_or_not_start is correct
187
+ builder. assert_eq ( local. is_shift_non_zero_or_not_start , or :: < AB :: Expr > ( is_shift_non_zero . clone ( ) , local. is_valid_not_start ) ) ;
182
188
183
189
// if !is_valid, then is_boundary = 0, shift = 0 (we will use this assumption later)
184
190
let mut is_not_valid_when = builder. when ( not :: < AB :: Expr > ( local. is_valid ) ) ;
@@ -193,8 +199,9 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
193
199
is_valid_not_start_when
194
200
. assert_eq ( local. source , prev. source + AB :: Expr :: from_canonical_u32 ( 16 ) ) ;
195
201
is_valid_not_start_when. assert_eq ( local. dest , prev. dest + AB :: Expr :: from_canonical_u32 ( 16 ) ) ;
196
- is_valid_not_start_when. assert_eq ( local. shift [ 0 ] , prev. shift [ 0 ] ) ;
197
- is_valid_not_start_when. assert_eq ( local. shift [ 1 ] , prev. shift [ 1 ] ) ;
202
+ local. shift . iter ( ) . zip ( prev. shift . iter ( ) ) . for_each ( |( local_shift, prev_shift) | {
203
+ is_valid_not_start_when. assert_eq ( * local_shift, * prev_shift) ;
204
+ } ) ;
198
205
199
206
// make sure if previous row is valid and not end, then local.is_valid = 1
200
207
builder
@@ -205,7 +212,7 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
205
212
// since is_shift_non_zero degree is 2, we need to keep the degree of the condition to 1
206
213
builder
207
214
. when ( not :: < AB :: Expr > ( prev. is_valid_not_start ) - not :: < AB :: Expr > ( prev. is_valid ) )
208
- . assert_eq ( local. timestamp , prev. timestamp + local . is_shift_non_zero ) ;
215
+ . assert_eq ( local. timestamp , prev. timestamp + is_shift_non_zero) ;
209
216
210
217
// if prev.is_valid_not_start and local.is_valid_not_start, then timestamp=prev_timestamp+8
211
218
// prev.is_valid_not_start is the opposite of previous condition
@@ -247,9 +254,9 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
247
254
. enumerate ( )
248
255
. for_each ( |( idx, data) | {
249
256
let is_valid_read = if idx == 3 {
250
- or :: < AB :: Expr > ( local. is_shift_non_zero , local . is_valid_not_start )
257
+ local. is_shift_non_zero_or_not_start
251
258
} else {
252
- local. is_valid_not_start . into ( )
259
+ local. is_valid_not_start
253
260
} ;
254
261
255
262
self . memory_bridge
@@ -274,7 +281,7 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
274
281
local. dest - AB :: Expr :: from_canonical_usize ( 16 - idx * 4 ) ,
275
282
) ,
276
283
data. clone ( ) ,
277
- timestamp_pp ( local. is_valid_not_start . into ( ) ) ,
284
+ timestamp_pp ( local. is_valid_not_start ) ,
278
285
& local. write_aux [ idx] ,
279
286
)
280
287
. eval ( builder, local. is_valid_not_start ) ;
@@ -701,11 +708,15 @@ impl<F: PrimeField32> TraceFiller<F> for MemcpyIterFiller {
701
708
} else {
702
709
F :: ZERO
703
710
} ;
704
- cols. is_shift_non_zero = F :: from_canonical_u8 ( ( record. inner . shift != 0 ) as u8 ) ;
705
- cols. is_valid_not_start = F :: from_canonical_u8 ( 1 - is_start as u8 ) ;
711
+ cols. is_shift_non_zero_or_not_start = F :: from_bool ( record. inner . shift != 0 || !is_start ) ;
712
+ cols. is_valid_not_start = F :: from_bool ( ! is_start) ;
706
713
cols. is_valid = F :: ONE ;
707
- cols. shift = [ record. inner . shift & 1 , record. inner . shift >> 1 ]
708
- . map ( F :: from_canonical_u8) ;
714
+ cols. shift = [
715
+ record. inner . shift == 1 ,
716
+ record. inner . shift == 2 ,
717
+ record. inner . shift == 3 ,
718
+ ]
719
+ . map ( F :: from_bool) ;
709
720
cols. len = [ len & 0xffff , len >> 16 ] . map ( F :: from_canonical_u32) ;
710
721
cols. source = F :: from_canonical_u32 ( source) ;
711
722
cols. dest = F :: from_canonical_u32 ( dest) ;
0 commit comments