1use midnight_proofs::{
15 circuit::{Layouter, Value},
16 plonk::Error,
17};
18use num_bigint::BigUint;
19
20use crate::{
21 field::{
22 decomposition::chip::P2RDecompositionChip, AssignedBounded, AssignedNative, NativeChip,
23 NativeGadget,
24 },
25 instructions::{
26 division::DivisionInstructions,
27 vector::{VectorBounds, VectorInstructions},
28 ArithInstructions, AssertionInstructions, AssignmentInstructions, BinaryInstructions,
29 ComparisonInstructions, ControlFlowInstructions, EqualityInstructions,
30 RangeCheckInstructions,
31 },
32 types::{AssignedBit, AssignedVector, InnerValue, Vectorizable},
33 vec::get_lims,
34 CircuitField,
35};
36
37type NG<F> = NativeGadget<F, P2RDecompositionChip<F>, NativeChip<F>>;
38
39#[derive(Clone, Debug)]
40pub struct VectorGadget<F: CircuitField> {
43 native_gadget: NG<F>,
44}
45
46impl<F> VectorGadget<F>
47where
48 F: CircuitField,
49{
50 pub fn new(native_gadget: &NG<F>) -> Self {
52 Self {
53 native_gadget: native_gadget.clone(),
54 }
55 }
56}
57
58impl<F, T, const M: usize, const A: usize> VectorInstructions<F, T, M, A> for VectorGadget<F>
59where
60 F: CircuitField,
61 T: Vectorizable,
62 T::Element: Copy,
63 NG<F>: RangeCheckInstructions<F, AssignedNative<F>>
64 + AssignmentInstructions<F, T>
65 + AssignmentInstructions<F, AssignedNative<F>>
66 + AssignmentInstructions<F, AssignedBit<F>>
67 + EqualityInstructions<F, AssignedNative<F>>
68 + BinaryInstructions<F>
69 + ControlFlowInstructions<F, AssignedNative<F>>
70 + ControlFlowInstructions<F, T>
71 + DivisionInstructions<F, AssignedNative<F>>
72 + AssertionInstructions<F, AssignedBit<F>>
73 + ArithInstructions<F, AssignedNative<F>>,
74{
75 fn resize<const L: usize>(
76 &self,
77 layouter: &mut impl Layouter<F>,
78 input: AssignedVector<F, T, M, A>,
79 ) -> Result<AssignedVector<F, T, L, A>, Error> {
80 assert_eq!(L % A, 0);
81 assert!(L > M);
82
83 let extra_pad = self
84 .native_gadget
85 .assign_many(layouter, &vec![Value::known(T::FILLER); L - M])?;
86
87 let buffer: Box<[T; L]> =
88 Box::new([extra_pad.as_slice(), input.buffer.as_slice()].concat().try_into().unwrap());
89
90 Ok(AssignedVector {
91 buffer,
92 len: input.len.clone(),
93 })
94 }
95
96 fn assign_with_filler(
97 &self,
98 layouter: &mut impl Layouter<F>,
99 value: Value<Vec<T::Element>>,
100 filler: Option<T::Element>,
101 ) -> Result<AssignedVector<F, T, M, A>, Error> {
102 assert!(M >= A, "AssignedVector requires M >= A (got M={M}, A={A})");
103 assert!(A > 0, "AssignedVector requires A positive (A={A})");
104 assert!(
105 M.is_multiple_of(A),
106 "AssignedVector requires M % A == 0 (got M={M}, A={A})"
107 );
108 let ng = &self.native_gadget;
109 let filler = filler.unwrap_or(T::FILLER);
110 let (data_val, len_val) = value
111 .map(|v| {
112 assert!(v.len() <= M);
115 let len = F::from(v.len() as u64);
116 let mut buffer = [filler; M];
117 buffer[get_lims::<M, A>(v.len())].copy_from_slice(v.as_slice());
118 (buffer, len)
119 })
120 .unzip();
121
122 let data: Box<[T; M]> = Box::new(
123 ng.assign_many(layouter, &data_val.transpose_array())?
124 .try_into()
125 .expect("Length mismatch in AssignedVector."),
126 );
127 let len = ng.assign_lower_than_fixed(layouter, len_val, &(M + 1).into())?;
128 Ok(AssignedVector { buffer: data, len })
129 }
130
131 fn padding_flag(
132 &self,
133 layouter: &mut impl Layouter<F>,
134 input: &AssignedVector<F, T, M, A>,
135 ) -> Result<(Box<[AssignedBit<F>; M]>, VectorBounds<F>), Error> {
136 let ng = &self.native_gadget;
137 let limits = self.get_limits(layouter, input)?;
138 let (start, end) = &limits;
139 let mut is_data: AssignedBit<F> = ng.assign_fixed(layouter, true)?;
140
141 let result = (0..=M - A)
142 .map(|i| {
143 let is_start = ng.is_equal_to_fixed(layouter, start, F::from(i as u64))?;
144 is_data = ng.xor(layouter, &[is_data.clone(), is_start])?;
145 Ok(is_data.clone())
146 })
147 .collect::<Result<Vec<_>, Error>>()?;
148
149 let last_chunk = (M - A + 1..M)
150 .map(|i| {
151 let is_end = ng.is_equal_to_fixed(layouter, end, F::from(i as u64))?;
152 is_data = ng.xor(layouter, &[is_data.clone(), is_end])?;
153 Ok(is_data.clone())
154 })
155 .collect::<Result<Vec<_>, Error>>()?;
156
157 let flags: Box<[AssignedBit<F>; M]> =
158 Box::new([result, last_chunk].concat().try_into().expect("Mismatch in vector lengths"));
159 Ok((flags, limits))
160 }
161
162 fn get_limits(
163 &self,
164 layouter: &mut impl Layouter<F>,
165 input: &AssignedVector<F, T, M, A>,
166 ) -> Result<(AssignedNative<F>, AssignedNative<F>), Error> {
167 let ng = &self.native_gadget;
168 let end: AssignedNative<F> = {
169 let offset = ng.rem(layouter, &input.len, A.into(), Some(M.into()))?;
172
173 let end1 = ng.add_constant(layouter, &offset, F::from(M as u64 - A as u64))?;
175 let end2 = ng.add_constant(layouter, &end1, F::from(A as u64))?;
177 let is_zero = ng.is_equal_to_fixed(layouter, &offset, F::ZERO)?;
178 ng.select(layouter, &is_zero, &end2, &end1)
179 }?;
180
181 let start: AssignedNative<F> = ng.sub(layouter, &end, &input.len)?;
183
184 Ok((start, end))
185 }
186
187 fn trim_beginning(
188 &self,
189 layouter: &mut impl Layouter<F>,
190 input: &AssignedVector<F, T, M, A>,
191 n_elems: usize,
192 ) -> Result<AssignedVector<F, T, M, A>, Error> {
193 let ng = &self.native_gadget;
194 let a_max_bits = (usize::BITS - A.leading_zeros()) as usize;
195
196 let len_complement =
198 ng.linear_combination(layouter, &[(-F::ONE, input.len.clone())], F::from(M as u64))?;
199 ng.assert_lower_than_fixed(layouter, &len_complement, &BigUint::from(M + 1 - n_elems))?;
200
201 let last_trim = n_elems % A;
210
211 let last_len = ng.rem(layouter, &input.len, A.into(), Some(M.into()))?;
213
214 let bounded_last_len =
217 AssignedBounded::to_assigned_bounded_unsafe(&last_len, a_max_bits as u32);
218
219 let needs_adjust = {
222 let leq_shift = ng.leq_fixed(layouter, &bounded_last_len, F::from(last_trim as u64))?;
223 let full_last = ng.is_equal_to_fixed(layouter, &last_len, F::ZERO)?;
224
225 ng.xor(layouter, &[full_last, leq_shift])
230 }?;
231
232 let buffer = {
236 let filler = ng.assign_many_fixed(layouter, &vec![T::FILLER; A + last_trim])?;
237 [&filler[..A], &input.buffer[last_trim..], &filler[A..]].concat()
238 };
239 debug_assert_eq!(buffer.len(), M + A);
240
241 let buffer: Box<[_; M]> = Box::new(
242 (0..M)
243 .map(|i| ng.select(layouter, &needs_adjust, &buffer[i], &buffer[A + i]))
244 .collect::<Result<Vec<_>, Error>>()?
245 .try_into()
246 .unwrap(),
247 );
248
249 let len = ng.add_constant(layouter, &input.len, -F::from(n_elems as u64))?;
251
252 Ok(AssignedVector { buffer, len })
253 }
254}
255
256impl<F, const M: usize, T, const A: usize> AssignmentInstructions<F, AssignedVector<F, T, M, A>>
257 for VectorGadget<F>
258where
259 F: CircuitField,
260 T: Vectorizable,
261 T::Element: Copy,
262 Self: VectorInstructions<F, T, M, A>,
263{
264 fn assign_fixed(
265 &self,
266 _layouter: &mut impl Layouter<F>,
267 _constant: <AssignedVector<F, T, M, A> as InnerValue>::Element,
268 ) -> Result<AssignedVector<F, T, M, A>, Error> {
269 unimplemented!("You should not be assigining a fixed `AssignedVector`")
270 }
271
272 fn assign(
273 &self,
274 layouter: &mut impl Layouter<F>,
275 value: Value<<AssignedVector<F, T, M, A> as InnerValue>::Element>,
276 ) -> Result<AssignedVector<F, T, M, A>, Error> {
277 self.assign_with_filler(layouter, value, None)
278 }
279}
280
281impl<F, const M: usize, T, const A: usize> EqualityInstructions<F, AssignedVector<F, T, M, A>>
282 for VectorGadget<F>
283where
284 F: CircuitField,
285 T: Vectorizable,
286 T::Element: Copy,
287 Self: VectorInstructions<F, T, M, A>,
288 NG<F>: ArithInstructions<F, AssignedNative<F>>
289 + EqualityInstructions<F, T>
290 + EqualityInstructions<F, AssignedNative<F>>
291 + BinaryInstructions<F>,
292{
293 fn is_equal(
294 &self,
295 layouter: &mut impl Layouter<F>,
296 x: &AssignedVector<F, T, M, A>,
297 y: &AssignedVector<F, T, M, A>,
298 ) -> Result<AssignedBit<F>, Error> {
299 let ng = &self.native_gadget;
300 let val_checks = self
302 .padding_flag(layouter, x)?
303 .0
304 .into_iter()
305 .zip(x.buffer.iter().zip(y.buffer.iter()))
306 .map(|(is_padding, (a, b))| {
307 let a_eq_b = ng.is_equal(layouter, a, b)?;
308 ng.or(layouter, &[is_padding, a_eq_b])
309 })
310 .collect::<Result<Vec<_>, Error>>()?;
311
312 let len_check = ng.is_equal(layouter, &x.len, &y.len)?;
314
315 ng.and(layouter, &[val_checks.as_slice(), &[len_check]].concat())
316 }
317
318 fn is_not_equal(
319 &self,
320 layouter: &mut impl Layouter<F>,
321 x: &AssignedVector<F, T, M, A>,
322 y: &AssignedVector<F, T, M, A>,
323 ) -> Result<AssignedBit<F>, Error> {
324 let b = self.is_equal(layouter, x, y)?;
325 self.native_gadget.not(layouter, &b)
326 }
327
328 fn is_equal_to_fixed(
329 &self,
330 layouter: &mut impl Layouter<F>,
331 x: &AssignedVector<F, T, M, A>,
332 constant: Vec<T::Element>,
333 ) -> Result<AssignedBit<F>, Error> {
334 let ng = &self.native_gadget;
335 let ct_len = constant.len();
336
337 let eq_len = ng.is_equal_to_fixed(layouter, &x.len, F::from(ct_len as u64))?;
338
339 let mut element_checks = x.buffer[get_lims::<M, A>(ct_len)]
340 .iter()
341 .zip(constant.iter())
342 .map(|(a, c)| ng.is_equal_to_fixed(layouter, a, *c))
343 .collect::<Result<Vec<_>, Error>>()?;
344 element_checks.push(eq_len);
345
346 ng.and(layouter, &element_checks)
347 }
348
349 fn is_not_equal_to_fixed(
350 &self,
351 layouter: &mut impl Layouter<F>,
352 x: &AssignedVector<F, T, M, A>,
353 constant: Vec<T::Element>,
354 ) -> Result<AssignedBit<F>, Error> {
355 let b = self.is_equal_to_fixed(layouter, x, constant)?;
356 self.native_gadget.not(layouter, &b)
357 }
358}
359
360impl<F, T, const M: usize, const A: usize> AssertionInstructions<F, AssignedVector<F, T, M, A>>
361 for VectorGadget<F>
362where
363 F: CircuitField,
364 T: Vectorizable,
365 T::Element: Copy,
366 Self: VectorInstructions<F, T, M, A> + EqualityInstructions<F, AssignedVector<F, T, M, A>>,
367 NG<F>: ArithInstructions<F, AssignedNative<F>>
368 + EqualityInstructions<F, T>
369 + EqualityInstructions<F, AssignedNative<F>>
370 + AssertionInstructions<F, AssignedBit<F>>
371 + AssertionInstructions<F, T>
372 + BinaryInstructions<F>,
373{
374 fn assert_equal(
375 &self,
376 layouter: &mut impl Layouter<F>,
377 x: &AssignedVector<F, T, M, A>,
378 y: &AssignedVector<F, T, M, A>,
379 ) -> Result<(), Error> {
380 let is_equal = self.is_equal(layouter, x, y)?;
381 self.native_gadget.assert_equal_to_fixed(layouter, &is_equal, true)
382 }
383
384 fn assert_not_equal(
385 &self,
386 layouter: &mut impl Layouter<F>,
387 x: &AssignedVector<F, T, M, A>,
388 y: &AssignedVector<F, T, M, A>,
389 ) -> Result<(), Error> {
390 let x_eq_y = self.is_equal(layouter, x, y)?;
391 self.native_gadget.assert_equal_to_fixed(layouter, &x_eq_y, false)
392 }
393
394 fn assert_equal_to_fixed(
395 &self,
396 layouter: &mut impl Layouter<F>,
397 x: &AssignedVector<F, T, M, A>,
398 constant: <AssignedVector<F, T, M, A> as InnerValue>::Element,
399 ) -> Result<(), Error> {
400 let ng = &self.native_gadget;
401 let ct_len = constant.len();
402 ng.assert_equal_to_fixed(layouter, &x.len, F::from(ct_len as u64))?;
403
404 x.buffer[get_lims::<M, A>(ct_len)]
405 .iter()
406 .zip(constant.iter())
407 .map(|(a, c)| ng.assert_equal_to_fixed(layouter, a, *c))
408 .collect::<Result<Vec<()>, Error>>()?;
409 Ok(())
410 }
411
412 fn assert_not_equal_to_fixed(
413 &self,
414 layouter: &mut impl Layouter<F>,
415 x: &AssignedVector<F, T, M, A>,
416 constant: <AssignedVector<F, T, M, A> as InnerValue>::Element,
417 ) -> Result<(), Error> {
418 let is_equal = self.is_equal_to_fixed(layouter, x, constant)?;
419 self.native_gadget.assert_equal_to_fixed(layouter, &is_equal, false)
420 }
421}
422
423#[cfg(any(test, feature = "testing"))]
424use midnight_proofs::plonk::{Advice, Column, ConstraintSystem, Fixed, Instance};
425
426#[cfg(any(test, feature = "testing"))]
427use crate::testing_utils::FromScratch;
428
429#[cfg(any(test, feature = "testing"))]
430impl<F: CircuitField> FromScratch<F> for VectorGadget<F> {
431 type Config = <NG<F> as FromScratch<F>>::Config;
432
433 fn new_from_scratch(config: &Self::Config) -> Self {
434 Self {
435 native_gadget: <NG<F> as FromScratch<F>>::new_from_scratch(config),
436 }
437 }
438
439 fn configure_from_scratch(
440 meta: &mut ConstraintSystem<F>,
441 advice_columns: &mut Vec<Column<Advice>>,
442 fixed_columns: &mut Vec<Column<Fixed>>,
443 instance_columns: &[Column<Instance>; 2],
444 ) -> Self::Config {
445 <NG<F>>::configure_from_scratch(meta, advice_columns, fixed_columns, instance_columns)
446 }
447
448 fn load_from_scratch(&self, layouter: &mut impl Layouter<F>) -> Result<(), Error> {
449 self.native_gadget.load_from_scratch(layouter)
450 }
451}
452
453#[cfg(test)]
454mod tests {
455 use ff::{Field, FromUniformBytes};
456 use midnight_proofs::{
457 circuit::{Layouter, SimpleFloorPlanner, Value},
458 dev::MockProver,
459 plonk::{Circuit, ConstraintSystem},
460 };
461 use rand_chacha::{rand_core::SeedableRng, ChaCha12Rng};
462
463 use super::*;
464 use crate::{
465 field::{
466 decomposition::chip::{P2RDecompositionChip, P2RDecompositionConfig},
467 AssignedNative, NativeChip, NativeGadget,
468 },
469 testing_utils::FromScratch,
470 utils::circuit_modeling::{circuit_to_json, cost_measure_end, cost_measure_start},
471 };
472
473 struct TestCircuit<F: CircuitField, const M: usize, const A: usize> {
474 input_1: Value<Vec<F>>,
475 input_2: Vec<F>, opts: TestOpts,
477 }
478
479 enum TestOpts {
480 Eq { mutate_padding: bool, equal: bool },
482 Limits,
484 Padding,
486 Trim { trim_size: usize },
488 }
489
490 type NG<F> = NativeGadget<F, P2RDecompositionChip<F>, NativeChip<F>>;
491
492 impl<F: CircuitField, const M: usize, const A: usize> Circuit<F> for TestCircuit<F, M, A> {
493 type Config = P2RDecompositionConfig;
494
495 type FloorPlanner = SimpleFloorPlanner;
496
497 type Params = ();
498
499 fn without_witnesses(&self) -> Self {
500 unreachable!();
501 }
502
503 fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
504 let comm_ic = meta.instance_column();
505 let instance_column = meta.instance_column();
506 NativeGadget::configure_from_scratch(
507 meta,
508 &mut vec![],
509 &mut vec![],
510 &[comm_ic, instance_column],
511 )
512 }
513
514 fn synthesize(
515 &self,
516 config: Self::Config,
517 mut layouter: impl Layouter<F>,
518 ) -> Result<(), Error> {
519 let ng = NG::<F>::new_from_scratch(&config);
520 let vg = VectorGadget::new(&ng);
521
522 cost_measure_start(&mut layouter);
523 match self.opts {
524 TestOpts::Eq {
525 mutate_padding,
526 equal,
527 } => {
528 let vec_1: AssignedVector<F, AssignedNative<F>, M, A> =
529 vg.assign(&mut layouter, self.input_1.clone())?;
530
531 let mut vec_2: AssignedVector<F, AssignedNative<F>, M, A> =
532 vg.assign(&mut layouter, Value::known(self.input_2.clone()))?;
533
534 if mutate_padding {
536 let range = get_lims::<M, A>(self.input_2.len());
537 for i in 0..range.start {
538 vec_2.buffer[i] =
539 ng.add_constant(&mut layouter, &vec_2.buffer[i], F::ONE)?;
540 }
541 for i in range.end..M {
542 vec_2.buffer[i] =
543 ng.add_constant(&mut layouter, &vec_2.buffer[i], F::ONE)?;
544 }
545 }
546
547 let check = vg.is_equal(&mut layouter, &vec_1, &vec_2)?;
548
549 ng.assert_equal_to_fixed(&mut layouter, &check, equal)?;
550 }
551 TestOpts::Limits => {
552 let vec_1: AssignedVector<F, AssignedNative<F>, M, A> =
553 vg.assign(&mut layouter, self.input_1.clone())?;
554
555 let limits = vg.get_limits(&mut layouter, &vec_1)?;
556 let (start, end) = vec_1
557 .len
558 .value()
559 .map(|l| {
560 let len: usize = l.to_biguint().try_into().unwrap();
561 let range = get_lims::<M, A>(len);
562 (F::from(range.start as u64), F::from(range.end as u64))
563 })
564 .unzip();
565 let start = ng.assign(&mut layouter, start)?;
566 let end = ng.assign(&mut layouter, end)?;
567 ng.assert_equal(&mut layouter, &limits.0, &start)?;
568 ng.assert_equal(&mut layouter, &limits.1, &end)?;
569 }
570
571 TestOpts::Padding => {
572 let vec_1: AssignedVector<F, AssignedNative<F>, M, A> =
573 vg.assign(&mut layouter, self.input_1.clone())?;
574
575 let expected: [Value<bool>; M] = vec_1
576 .len
577 .value()
578 .map(|l| {
579 let len: usize = l.to_biguint().try_into().unwrap();
580 let range = get_lims::<M, A>(len);
581 let mut result = vec![true; M];
582 result[range].iter_mut().for_each(|r| {
583 *r = false;
584 });
585 result.try_into().unwrap()
586 })
587 .transpose_array();
588
589 let (result, _limits) = vg.padding_flag(&mut layouter, &vec_1)?;
590
591 for (r, e) in result.iter().zip(expected.iter()) {
592 let e: AssignedBit<F> = ng.assign(&mut layouter, *e)?;
593 ng.assert_equal(&mut layouter, &e, r)?;
594 }
595 }
596
597 TestOpts::Trim { trim_size: n_elems } => {
598 let vec_1: AssignedVector<F, AssignedNative<F>, M, A> =
599 vg.assign(&mut layouter, self.input_1.clone())?;
600
601 let result = vg.trim_beginning(&mut layouter, &vec_1, n_elems)?;
602
603 vg.assert_equal_to_fixed(&mut layouter, &result, self.input_2.clone())?;
604 }
605 }
606 cost_measure_end(&mut layouter);
607
608 ng.load_from_scratch(&mut layouter)
609 }
610 }
611
612 fn run_eq_vec_test<F, const M: usize, const A: usize>(
613 input_1: &[F],
614 input_2: &[F],
615 equal: bool,
616 mutate_padding: bool,
617 cost_model: bool,
618 ) where
619 F: CircuitField + FromUniformBytes<64> + Ord,
620 {
621 let circuit = TestCircuit::<F, M, A> {
622 input_1: Value::known(input_1.to_vec()),
623 input_2: input_2.to_vec(),
624 opts: TestOpts::Eq {
625 equal,
626 mutate_padding,
627 },
628 };
629
630 MockProver::run(&circuit, vec![vec![], vec![]]).unwrap().assert_satisfied();
631
632 if cost_model {
633 circuit_to_json(
634 "Vector equality",
635 format!("Vector equality check with M={M}").as_str(),
636 circuit,
637 );
638 }
639 }
640
641 fn run_limit_vec_test<F, const M: usize, const A: usize>(input_1: &[F], cost_model: bool)
642 where
643 F: CircuitField + FromUniformBytes<64> + Ord,
644 {
645 let circuit = TestCircuit::<F, M, A> {
646 input_1: Value::known(input_1.to_vec()),
647 input_2: vec![],
648 opts: TestOpts::Limits,
649 };
650
651 MockProver::run(&circuit, vec![vec![], vec![]]).unwrap().assert_satisfied();
652
653 if cost_model {
654 circuit_to_json(
655 "Vector limits check",
656 format!("Vector limit check with M={M}").as_str(),
657 circuit,
658 );
659 }
660 }
661
662 fn run_padding_flags_test<F, const M: usize, const A: usize>(input_1: &[F], cost_model: bool)
663 where
664 F: CircuitField + FromUniformBytes<64> + Ord,
665 {
666 let circuit = TestCircuit::<F, M, A> {
667 input_1: Value::known(input_1.to_vec()),
668 input_2: vec![],
669 opts: TestOpts::Padding,
670 };
671
672 MockProver::run(&circuit, vec![vec![], vec![]]).unwrap().assert_satisfied();
673
674 if cost_model {
675 circuit_to_json(
676 "Vector padding flags.",
677 format!("Vector padding flags with M={M}").as_str(),
678 circuit,
679 );
680 }
681 }
682
683 fn run_trim_vec_test<F, const M: usize, const A: usize>(
684 input_1: &[F],
685 trim_size: usize,
686 cost_model: bool,
687 ) where
688 F: CircuitField + FromUniformBytes<64> + Ord,
689 {
690 let input = input_1.to_vec();
691 assert!(trim_size <= input.len());
692 let circuit = TestCircuit::<F, M, A> {
693 input_1: Value::known(input.clone()),
694 input_2: input[trim_size..].to_vec(),
695 opts: TestOpts::Trim { trim_size },
696 };
697
698 MockProver::run(&circuit, vec![vec![], vec![]]).unwrap().assert_satisfied();
699
700 if cost_model {
701 circuit_to_json(
702 "Vector trim beginning.",
703 format!("Vector trim_beginning with M={M}").as_str(),
704 circuit,
705 );
706 }
707 }
708
709 #[test]
710 fn vector_eq() {
711 type F = midnight_curves::Fq;
712
713 let mut rng = ChaCha12Rng::seed_from_u64(0xdeadcafe);
715 let inputs = (0..100).map(|_| F::random(&mut rng)).collect::<Vec<_>>();
716
717 run_eq_vec_test::<_, 128, 2>(&inputs, &inputs, true, true, true);
719 run_eq_vec_test::<_, 126, 3>(&inputs, &inputs, true, true, false);
720
721 run_eq_vec_test::<_, 128, 2>(&inputs, &inputs, true, false, false);
723
724 run_eq_vec_test::<_, 128, 2>(&inputs[..80], &inputs[..81], false, false, false);
726
727 run_eq_vec_test::<_, 128, 2>(
729 &[&[F::ZERO], &inputs[..80]].concat(),
730 &[&[F::ONE], &inputs[..80]].concat(),
731 false,
732 false,
733 false,
734 );
735 }
736
737 #[test]
738 fn vector_limits() {
739 type F = midnight_curves::Fq;
740
741 let mut rng = ChaCha12Rng::seed_from_u64(0xdeadcafe);
743 let inputs = (0..100).map(|_| F::random(&mut rng)).collect::<Vec<_>>();
744
745 run_limit_vec_test::<_, 128, 1>(&inputs, true);
747 run_limit_vec_test::<_, 128, 2>(&inputs, false);
748 run_limit_vec_test::<_, 126, 3>(&inputs, false);
749 run_limit_vec_test::<_, 128, 4>(&inputs, false);
750 run_limit_vec_test::<_, 130, 5>(&inputs, false);
751
752 run_limit_vec_test::<_, 64, 2>(&inputs[..64], false);
754 run_limit_vec_test::<F, 64, 2>(&[], false);
755 }
756
757 #[test]
758 fn vector_padding_flags() {
759 type F = midnight_curves::Fq;
760
761 let mut rng = ChaCha12Rng::seed_from_u64(0xdeadcafe);
763 let inputs = (0..100).map(|_| F::random(&mut rng)).collect::<Vec<_>>();
764
765 run_padding_flags_test::<_, 128, 1>(&inputs, true);
766 run_padding_flags_test::<_, 128, 2>(&inputs, false);
767 run_padding_flags_test::<_, 126, 3>(&inputs, false);
768 run_padding_flags_test::<_, 128, 64>(&inputs, false);
769 run_padding_flags_test::<F, 128, 64>(&[], false);
770 run_padding_flags_test::<F, 64, 16>(&inputs[..64], false);
771 }
772
773 #[test]
774 fn vector_trim_beginning() {
775 type F = midnight_curves::Fq;
776
777 let mut rng = ChaCha12Rng::seed_from_u64(0xdeadcafe);
779 let inputs = (0..100).map(|_| F::random(&mut rng)).collect::<Vec<_>>();
780
781 run_trim_vec_test::<_, 128, 64>(&[F::ONE, F::ONE], 1, true);
783 run_trim_vec_test::<_, 128, 32>(&inputs, 0, false);
784 run_trim_vec_test::<_, 128, 32>(&inputs, 1, false);
785 run_trim_vec_test::<_, 128, 32>(&inputs, 2, false);
786 run_trim_vec_test::<_, 128, 32>(&inputs, 3, false);
787 run_trim_vec_test::<_, 128, 32>(&inputs, 4, false);
788 run_trim_vec_test::<_, 128, 32>(&inputs, 5, false);
789 run_trim_vec_test::<_, 128, 32>(&inputs, 30, false);
790 run_trim_vec_test::<_, 128, 32>(&inputs, 31, false);
791
792 run_trim_vec_test::<_, 126, 3>(&inputs, 3, false);
794 run_trim_vec_test::<_, 126, 3>(&inputs, 4, false);
795 run_trim_vec_test::<_, 126, 3>(&inputs, 5, false);
796 run_trim_vec_test::<_, 126, 3>(&inputs, 6, false);
797 run_trim_vec_test::<_, 126, 3>(&inputs, 10, false);
798 run_trim_vec_test::<_, 126, 3>(&inputs, 20, false);
799 run_trim_vec_test::<_, 126, 3>(&inputs, 30, false);
800 run_trim_vec_test::<_, 126, 3>(&inputs, 40, false);
801
802 run_trim_vec_test::<_, 128, 32>(&inputs[..96], 23, false);
804
805 run_trim_vec_test::<_, 64, 32>(&inputs[..64], 20, false);
807
808 run_trim_vec_test::<_, 64, 32>(&inputs[..64], 64, false);
810
811 run_trim_vec_test::<_, 128, 64>(&inputs, 39, false);
813 }
814}