Skip to content

Commit c3f2044

Browse files
authored
fix: removed array_contains and handled partial subarray case for get_fixed_subarray (#346)
1 parent 0637395 commit c3f2044

File tree

1 file changed

+56
-15
lines changed

1 file changed

+56
-15
lines changed

plonky2x/core/src/frontend/vars/array.rs

+56-15
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use plonky2::iop::challenger::RecursiveChallenger;
99
use plonky2::iop::target::Target;
1010
use serde::{Deserialize, Serialize};
1111

12-
use super::{BoolVariable, ByteVariable, CircuitVariable, ValueStream, Variable, VariableStream};
12+
use super::{ByteVariable, CircuitVariable, ValueStream, Variable, VariableStream};
1313
use crate::backend::circuit::PlonkParameters;
1414
use crate::frontend::builder::CircuitBuilder;
1515
use crate::frontend::hint::simple::hint::Hint;
@@ -180,7 +180,8 @@ impl<L: PlonkParameters<D>, const D: usize> CircuitBuilder<L, D> {
180180
/// Given an `array` of variables, and a dynamic `index` start_idx, returns
181181
/// `array[start_idx..start_idx+sub_array_size]` as an `array`.
182182
///
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.
184185
///
185186
/// The security of each challenge is log2(field_size) - log2(array_size), so the total security
186187
/// is (log2(field_size) - log2(array_size)) * num_loops.
@@ -252,6 +253,7 @@ impl<L: PlonkParameters<D>, const D: usize> CircuitBuilder<L, D> {
252253
let one: Variable = self.one();
253254

254255
let mut accumulator1 = self.zero::<Variable>();
256+
let mut subarray_size: Variable = self.zero();
255257

256258
// r is the source of randomness from the challenger for this loop.
257259
let mut r = one;
@@ -266,6 +268,8 @@ impl<L: PlonkParameters<D>, const D: usize> CircuitBuilder<L, D> {
266268
let at_end_idx = self.is_equal(idx, end_idx);
267269
within_sub_array = self.select(at_end_idx, false_v, within_sub_array);
268270

271+
subarray_size = self.add(subarray_size, within_sub_array.variable);
272+
269273
// If within the subarray, multiply the current r by the challenge.
270274
let multiplier = self.select(within_sub_array, challenges[i], one);
271275
// 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> {
280284
accumulator1 = self.add(accumulator1, temp_accum);
281285
}
282286

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+
283292
let mut accumulator2 = self.zero();
284293
let mut r = one;
285294
for j in 0..SUB_ARRAY_SIZE {
@@ -293,19 +302,6 @@ impl<L: PlonkParameters<D>, const D: usize> CircuitBuilder<L, D> {
293302

294303
sub_array
295304
}
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-
}
309305
}
310306

311307
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -511,4 +507,49 @@ mod tests {
511507
expected_sub_array
512508
);
513509
}
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+
}
514555
}

0 commit comments

Comments
 (0)