@@ -9,7 +9,7 @@ use plonky2::iop::challenger::RecursiveChallenger;
9
9
use plonky2:: iop:: target:: Target ;
10
10
use serde:: { Deserialize , Serialize } ;
11
11
12
- use super :: { BoolVariable , ByteVariable , CircuitVariable , ValueStream , Variable , VariableStream } ;
12
+ use super :: { ByteVariable , CircuitVariable , ValueStream , Variable , VariableStream } ;
13
13
use crate :: backend:: circuit:: PlonkParameters ;
14
14
use crate :: frontend:: builder:: CircuitBuilder ;
15
15
use crate :: frontend:: hint:: simple:: hint:: Hint ;
@@ -180,7 +180,8 @@ impl<L: PlonkParameters<D>, const D: usize> CircuitBuilder<L, D> {
180
180
/// Given an `array` of variables, and a dynamic `index` start_idx, returns
181
181
/// `array[start_idx..start_idx+sub_array_size]` as an `array`.
182
182
///
183
- /// `seed` is used to generate randomness for the proof.
183
+ /// `seed` is used to generate randomness for the proof. Note that the seed should be the
184
+ /// Fiat-Shamir of the entire array and claimed subarray.
184
185
///
185
186
/// The security of each challenge is log2(field_size) - log2(array_size), so the total security
186
187
/// is (log2(field_size) - log2(array_size)) * num_loops.
@@ -252,6 +253,7 @@ impl<L: PlonkParameters<D>, const D: usize> CircuitBuilder<L, D> {
252
253
let one: Variable = self . one ( ) ;
253
254
254
255
let mut accumulator1 = self . zero :: < Variable > ( ) ;
256
+ let mut subarray_size: Variable = self . zero ( ) ;
255
257
256
258
// r is the source of randomness from the challenger for this loop.
257
259
let mut r = one;
@@ -266,6 +268,8 @@ impl<L: PlonkParameters<D>, const D: usize> CircuitBuilder<L, D> {
266
268
let at_end_idx = self . is_equal ( idx, end_idx) ;
267
269
within_sub_array = self . select ( at_end_idx, false_v, within_sub_array) ;
268
270
271
+ subarray_size = self . add ( subarray_size, within_sub_array. variable ) ;
272
+
269
273
// If within the subarray, multiply the current r by the challenge.
270
274
let multiplier = self . select ( within_sub_array, challenges[ i] , one) ;
271
275
// For subarray[i], the multiplier should be r^i. i is the index within the subarray.
@@ -280,6 +284,11 @@ impl<L: PlonkParameters<D>, const D: usize> CircuitBuilder<L, D> {
280
284
accumulator1 = self . add ( accumulator1, temp_accum) ;
281
285
}
282
286
287
+ // Assert that the returned subarray's length is == SUB_ARRAY_SIZE.
288
+ let expected_subarray_size =
289
+ self . constant ( L :: Field :: from_canonical_usize ( SUB_ARRAY_SIZE ) ) ;
290
+ self . assert_is_equal ( subarray_size, expected_subarray_size) ;
291
+
283
292
let mut accumulator2 = self . zero ( ) ;
284
293
let mut r = one;
285
294
for j in 0 ..SUB_ARRAY_SIZE {
@@ -293,19 +302,6 @@ impl<L: PlonkParameters<D>, const D: usize> CircuitBuilder<L, D> {
293
302
294
303
sub_array
295
304
}
296
-
297
- pub fn array_contains < V : CircuitVariable > ( & mut self , array : & [ V ] , element : V ) -> BoolVariable {
298
- assert ! ( array. len( ) < 1 << 16 ) ;
299
- let mut accumulator = self . constant :: < Variable > ( L :: Field :: from_canonical_usize ( 0 ) ) ;
300
-
301
- for i in 0 ..array. len ( ) {
302
- let element_equal = self . is_equal ( array[ i] . clone ( ) , element. clone ( ) ) ;
303
- accumulator = self . add ( accumulator, element_equal. variable ) ;
304
- }
305
-
306
- let one = self . constant :: < Variable > ( L :: Field :: from_canonical_usize ( 1 ) ) ;
307
- self . is_equal ( one, accumulator)
308
- }
309
305
}
310
306
311
307
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
@@ -511,4 +507,49 @@ mod tests {
511
507
expected_sub_array
512
508
) ;
513
509
}
510
+
511
+ #[ test]
512
+ #[ should_panic]
513
+ fn test_get_fixed_subarray_bad_case ( ) {
514
+ utils:: setup_logger ( ) ;
515
+ type F = GoldilocksField ;
516
+ const ARRAY_SIZE : usize = 12800 ;
517
+ const SUB_ARRAY_SIZE : usize = 3200 ;
518
+ const START_IDX : usize = 12000 ;
519
+
520
+ let mut builder = DefaultBuilder :: new ( ) ;
521
+
522
+ let array = builder. read :: < ArrayVariable < Variable , ARRAY_SIZE > > ( ) ;
523
+ let start_idx = builder. constant ( F :: from_canonical_usize ( START_IDX ) ) ;
524
+ let seed = builder. read :: < Bytes32Variable > ( ) ;
525
+ let result = builder. get_fixed_subarray :: < ARRAY_SIZE , SUB_ARRAY_SIZE > (
526
+ & array,
527
+ start_idx,
528
+ & seed. as_bytes ( ) ,
529
+ ) ;
530
+ builder. write ( result) ;
531
+
532
+ let circuit = builder. build ( ) ;
533
+
534
+ // The last 20 elements are dummy
535
+ let mut rng = OsRng ;
536
+ let mut array_input = [ F :: default ( ) ; ARRAY_SIZE ] ;
537
+ for elem in array_input. iter_mut ( ) {
538
+ * elem = F :: from_canonical_u64 ( rng. gen ( ) ) ;
539
+ }
540
+
541
+ let mut seed_input = [ 0u8 ; 15 ] ;
542
+ for elem in seed_input. iter_mut ( ) {
543
+ * elem = rng. gen ( ) ;
544
+ }
545
+
546
+ let mut input = circuit. input ( ) ;
547
+ input. write :: < ArrayVariable < Variable , ARRAY_SIZE > > ( array_input. to_vec ( ) ) ;
548
+ input. write :: < Bytes32Variable > ( bytes32 ! (
549
+ "0x7c38fc8356aa20394c7f538e3cee3f924e6d9252494c8138d1a6aabfc253118f"
550
+ ) ) ;
551
+
552
+ let ( proof, output) = circuit. prove ( & input) ;
553
+ circuit. verify ( & proof, & input, & output) ;
554
+ }
514
555
}
0 commit comments