@@ -111,15 +111,17 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
111
111
let is_shift_two = and :: < AB :: Expr > ( not :: < AB :: Expr > ( local. shift [ 0 ] ) , local. shift [ 1 ] ) ;
112
112
let is_shift_three = and :: < AB :: Expr > ( local. shift [ 0 ] , local. shift [ 1 ] ) ;
113
113
114
- // TODO:since if is_valid = 0, then is_boundary = 0, we can reduce the degree of the following expressions by removing the is_valid term
115
114
let is_end =
116
115
( local. is_boundary + AB :: Expr :: ONE ) * local. is_boundary * ( AB :: F :: TWO ) . inverse ( ) ;
117
116
let is_not_start = ( local. is_boundary + AB :: Expr :: ONE )
118
117
* ( AB :: Expr :: TWO - local. is_boundary )
119
118
* ( AB :: F :: TWO ) . inverse ( ) ;
119
+ let prev_is_not_end = not :: < AB :: Expr > (
120
+ ( prev. is_boundary + AB :: Expr :: ONE ) * prev. is_boundary * ( AB :: F :: TWO ) . inverse ( ) ,
121
+ ) ;
120
122
121
123
let len = local. len [ 0 ]
122
- + local. len [ 1 ] * AB :: F :: from_canonical_u32 ( 1 << ( 2 * MEMCPY_LOOP_LIMB_BITS ) ) ;
124
+ + local. len [ 1 ] * AB :: Expr :: from_canonical_u32 ( 1 << ( 2 * MEMCPY_LOOP_LIMB_BITS ) ) ;
123
125
124
126
// write_data =
125
127
// (local.data_1[shift..4], prev.data_4[0..shift]),
@@ -136,7 +138,7 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
136
138
let write_data = write_data_pairs
137
139
. iter ( )
138
140
. map ( |( prev_data, next_data) | {
139
- array:: from_fn ( |i| {
141
+ array:: from_fn :: < _ , MEMCPY_LOOP_NUM_LIMBS , _ > ( |i| {
140
142
is_shift_zero. clone ( ) * ( next_data[ i] )
141
143
+ is_shift_one. clone ( )
142
144
* ( if i < 3 {
@@ -161,35 +163,44 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
161
163
. collect :: < Vec < _ > > ( ) ;
162
164
163
165
builder. assert_bool ( local. is_valid ) ;
164
- for i in 0 ..2 {
165
- builder. assert_bool ( local. shift [ i] ) ;
166
- }
166
+ local. shift . iter ( ) . for_each ( |x| builder. assert_bool ( * x) ) ;
167
167
builder. assert_bool ( local. is_valid_not_start ) ;
168
168
// is_boundary is either -1, 0 or 1
169
169
builder. assert_tern ( local. is_boundary + AB :: Expr :: ONE ) ;
170
170
171
171
// is_valid_not_start = is_valid and is_not_start:
172
- builder. assert_eq ( local. is_valid_not_start , local. is_valid * is_not_start) ;
172
+ builder. assert_eq (
173
+ local. is_valid_not_start ,
174
+ and :: < AB :: Expr > ( local. is_valid , is_not_start) ,
175
+ ) ;
173
176
174
- // if is_valid = 0 , then is_boundary = 0, shift = 0
177
+ // if ! is_valid, then is_boundary = 0, shift = 0 (we will use this assumption later)
175
178
let mut is_not_valid_when = builder. when ( not :: < AB :: Expr > ( local. is_valid ) ) ;
176
179
is_not_valid_when. assert_zero ( local. is_boundary ) ;
177
180
is_not_valid_when. assert_zero ( shift. clone ( ) ) ;
178
181
179
- // if is_valid_not_start = 1 , then len = prev_len - 16, source = prev_source + 16,
180
- // and dest = prev_dest + 16
182
+ // if is_valid_not_start, then len = prev_len - 16, source = prev_source + 16,
183
+ // and dest = prev_dest + 16, shift = prev_shift
181
184
let mut is_valid_not_start_when = builder. when ( local. is_valid_not_start ) ;
182
185
is_valid_not_start_when
183
186
. assert_eq ( local. len [ 0 ] , prev. len [ 0 ] - AB :: Expr :: from_canonical_u32 ( 16 ) ) ;
184
187
is_valid_not_start_when
185
188
. assert_eq ( local. source , prev. source + AB :: Expr :: from_canonical_u32 ( 16 ) ) ;
186
189
is_valid_not_start_when. assert_eq ( local. dest , prev. dest + AB :: Expr :: from_canonical_u32 ( 16 ) ) ;
190
+ is_valid_not_start_when. assert_eq ( local. shift [ 0 ] , prev. shift [ 0 ] ) ;
191
+ is_valid_not_start_when. assert_eq ( local. shift [ 1 ] , prev. shift [ 1 ] ) ;
192
+
193
+ // make sure if previous row is valid and not end, then local.is_valid = 1
194
+ builder
195
+ . when ( prev_is_not_end - not :: < AB :: Expr > ( prev. is_valid ) )
196
+ . assert_one ( local. is_valid ) ;
187
197
188
198
// if prev.is_valid_start, then timestamp = prev_timestamp + is_shift_non_zero
189
199
// since is_shift_non_zero degree is 2, we need to keep the degree of the condition to 1
190
200
builder
191
201
. when ( not :: < AB :: Expr > ( prev. is_valid_not_start ) - not :: < AB :: Expr > ( prev. is_valid ) )
192
202
. assert_eq ( local. timestamp , prev. timestamp + is_shift_non_zero. clone ( ) ) ;
203
+
193
204
// if prev.is_valid_not_start and local.is_valid_not_start, then timestamp=prev_timestamp+8
194
205
// prev.is_valid_not_start is the opposite of previous condition
195
206
builder
@@ -239,7 +250,7 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
239
250
. read (
240
251
MemoryAddress :: new (
241
252
AB :: Expr :: from_canonical_u32 ( RV32_MEMORY_AS ) ,
242
- local. source + AB :: Expr :: from_canonical_usize ( idx * 4 ) ,
253
+ local. source - AB :: Expr :: from_canonical_usize ( 16 - idx * 4 ) ,
243
254
) ,
244
255
* data,
245
256
timestamp_pp ( ) ,
@@ -254,7 +265,7 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
254
265
. write (
255
266
MemoryAddress :: new (
256
267
AB :: Expr :: from_canonical_u32 ( RV32_MEMORY_AS ) ,
257
- local. dest + AB :: Expr :: from_canonical_usize ( idx * 4 ) ,
268
+ local. dest - AB :: Expr :: from_canonical_usize ( 16 - idx * 4 ) ,
258
269
) ,
259
270
data. clone ( ) ,
260
271
timestamp_pp ( ) ,
@@ -286,7 +297,9 @@ impl<AB: InteractionBuilder> Air<AB> for MemcpyIterAir {
286
297
}
287
298
288
299
#[ derive( derive_new:: new, Clone , Copy ) ]
289
- pub struct MemcpyIterExecutor { }
300
+ pub struct MemcpyIterExecutor {
301
+ pub offset : usize ,
302
+ }
290
303
291
304
#[ derive( Copy , Clone , Debug ) ]
292
305
pub struct MemcpyIterMetadata {
@@ -378,12 +391,6 @@ pub struct MemcpyIterFiller {
378
391
379
392
pub type MemcpyIterChip < F > = VmChipWrapper < F , MemcpyIterFiller > ;
380
393
381
- #[ derive( AlignedBytesBorrow , Clone ) ]
382
- #[ repr( C ) ]
383
- struct MemcpyIterPreCompute {
384
- c : u8 ,
385
- }
386
-
387
394
impl < F , RA > PreflightExecutor < F , RA > for MemcpyIterExecutor
388
395
where
389
396
F : PrimeField32 ,
@@ -452,6 +459,8 @@ where
452
459
let write_data: [ u8 ; MEMCPY_LOOP_NUM_LIMBS ] = array:: from_fn ( |j| {
453
460
if j < 4 - shift as usize {
454
461
record. var [ idx] . data [ i] [ j + shift as usize ]
462
+ } else if i > 0 {
463
+ record. var [ idx] . data [ i - 1 ] [ j - ( 4 - shift as usize ) ]
455
464
} else {
456
465
record. var [ idx - 1 ] . data [ i] [ j - ( 4 - shift as usize ) ]
457
466
}
@@ -565,6 +574,18 @@ impl<F: PrimeField32> TraceFiller<F> for MemcpyIterFiller {
565
574
)
566
575
} ;
567
576
577
+ // Fill memcpy loop record
578
+ self . memcpy_loop_chip . add_new_loop (
579
+ mem_helper,
580
+ record. inner . from_pc ,
581
+ record. inner . from_timestamp ,
582
+ record. inner . dest ,
583
+ record. inner . source ,
584
+ record. inner . len ,
585
+ record. inner . shift ,
586
+ record. inner . register_aux . clone ( ) ,
587
+ ) ;
588
+
568
589
// 4 reads + 4 writes per iteration + (shift != 0) read for the loop header
569
590
let timestamp = record. inner . from_timestamp
570
591
+ ( ( num_rows - 1 ) << 3 ) as u32
@@ -583,27 +604,15 @@ impl<F: PrimeField32> TraceFiller<F> for MemcpyIterFiller {
583
604
let mut len =
584
605
record. inner . len - ( ( num_rows - 1 ) << 4 ) as u32 - record. inner . shift as u32 ;
585
606
586
- // Fill memcpy loop record
587
- self . memcpy_loop_chip . add_new_loop (
588
- mem_helper,
589
- record. inner . from_pc ,
590
- record. inner . from_timestamp ,
591
- record. inner . dest ,
592
- record. inner . source ,
593
- record. inner . len ,
594
- record. inner . shift ,
595
- record. inner . register_aux . clone ( ) ,
596
- ) ;
597
-
598
607
// We are going to fill row in the reverse order
599
608
chunk
600
609
. rchunks_exact_mut ( width)
601
610
. zip ( record. var . iter ( ) . enumerate ( ) . rev ( ) )
602
611
. for_each ( |( row, ( idx, var) ) | {
603
612
let cols: & mut MemcpyIterCols < F > = row. borrow_mut ( ) ;
604
613
605
- let is_end = idx == 0 ;
606
- let is_start = idx == num_rows - 1 ;
614
+ let is_start = idx == 0 ;
615
+ let is_end = idx == num_rows - 1 ;
607
616
608
617
// Range check len
609
618
let len_u16_limbs = [ len & 0xffff , len >> 16 ] ;
@@ -621,8 +630,6 @@ impl<F: PrimeField32> TraceFiller<F> for MemcpyIterFiller {
621
630
622
631
// Fill memory read/write auxiliary columns
623
632
if is_start {
624
- debug_assert_eq ! ( get_timestamp( false ) , record. inner. from_timestamp) ;
625
-
626
633
cols. write_aux . iter_mut ( ) . rev ( ) . for_each ( |aux_col| {
627
634
mem_helper. fill_zero ( aux_col. as_mut ( ) ) ;
628
635
} ) ;
@@ -632,18 +639,20 @@ impl<F: PrimeField32> TraceFiller<F> for MemcpyIterFiller {
632
639
} else {
633
640
mem_helper. fill (
634
641
var. read_aux [ 3 ] . prev_timestamp ,
635
- timestamp ,
642
+ get_timestamp ( true ) ,
636
643
cols. read_aux [ 3 ] . as_mut ( ) ,
637
644
) ;
638
645
}
639
646
cols. read_aux [ ..2 ] . iter_mut ( ) . rev ( ) . for_each ( |aux_col| {
640
647
mem_helper. fill_zero ( aux_col. as_mut ( ) ) ;
641
648
} ) ;
649
+
650
+ debug_assert_eq ! ( get_timestamp( false ) , record. inner. from_timestamp) ;
642
651
} else {
643
652
var. write_aux
644
653
. iter ( )
654
+ . zip ( cols. write_aux . iter_mut ( ) )
645
655
. rev ( )
646
- . zip ( cols. write_aux . iter_mut ( ) . rev ( ) )
647
656
. for_each ( |( aux_record, aux_col) | {
648
657
mem_helper. fill (
649
658
aux_record. prev_timestamp ,
@@ -657,8 +666,8 @@ impl<F: PrimeField32> TraceFiller<F> for MemcpyIterFiller {
657
666
658
667
var. read_aux
659
668
. iter ( )
669
+ . zip ( cols. read_aux . iter_mut ( ) )
660
670
. rev ( )
661
- . zip ( cols. read_aux . iter_mut ( ) . rev ( ) )
662
671
. for_each ( |( aux_record, aux_col) | {
663
672
mem_helper. fill (
664
673
aux_record. prev_timestamp ,
@@ -672,10 +681,16 @@ impl<F: PrimeField32> TraceFiller<F> for MemcpyIterFiller {
672
681
cols. data_3 = var. data [ 2 ] . map ( F :: from_canonical_u8) ;
673
682
cols. data_2 = var. data [ 1 ] . map ( F :: from_canonical_u8) ;
674
683
cols. data_1 = var. data [ 0 ] . map ( F :: from_canonical_u8) ;
675
- cols. is_boundary = F :: from_canonical_u8 ( is_end as u8 - is_start as u8 ) ;
684
+ cols. is_boundary = if is_end {
685
+ F :: ONE
686
+ } else if is_start {
687
+ F :: NEG_ONE
688
+ } else {
689
+ F :: ZERO
690
+ } ;
676
691
cols. is_valid_not_start = F :: from_canonical_u8 ( 1 - is_start as u8 ) ;
677
692
cols. is_valid = F :: ONE ;
678
- cols. shift = [ record. inner . shift % 2 , record. inner . shift / 2 ]
693
+ cols. shift = [ record. inner . shift & 1 , record. inner . shift >> 1 ]
679
694
. map ( F :: from_canonical_u8) ;
680
695
cols. len = [ len & 0xffff , len >> 16 ] . map ( F :: from_canonical_u32) ;
681
696
cols. source = F :: from_canonical_u32 ( source) ;
@@ -690,6 +705,12 @@ impl<F: PrimeField32> TraceFiller<F> for MemcpyIterFiller {
690
705
}
691
706
}
692
707
708
+ #[ derive( AlignedBytesBorrow , Clone ) ]
709
+ #[ repr( C ) ]
710
+ struct MemcpyIterPreCompute {
711
+ c : u8 ,
712
+ }
713
+
693
714
impl < F : PrimeField32 > Executor < F > for MemcpyIterExecutor {
694
715
fn pre_compute_size ( & self ) -> usize {
695
716
size_of :: < MemcpyIterPreCompute > ( )
0 commit comments