1use super::nonnative::bignat::{nat_to_limbs, BigNat};
3use crate::{
4 constants::{BN_LIMB_WIDTH, BN_N_LIMBS},
5 frontend::{
6 num::AllocatedNum, AllocatedBit, Assignment, Boolean, ConstraintSystem, LinearCombination,
7 SynthesisError,
8 },
9 gadgets::nonnative::util::f_to_nat,
10 traits::Engine,
11};
12use ff::{Field, PrimeField, PrimeFieldBits};
13use num_bigint::BigInt;
14
15pub fn le_bits_to_num<Scalar, CS>(
17 mut cs: CS,
18 bits: &[AllocatedBit],
19) -> Result<AllocatedNum<Scalar>, SynthesisError>
20where
21 Scalar: PrimeField + PrimeFieldBits,
22 CS: ConstraintSystem<Scalar>,
23{
24 let mut lc = LinearCombination::zero();
27 let mut coeff = Scalar::ONE;
28 let mut fe = Some(Scalar::ZERO);
29 for bit in bits.iter() {
30 lc = lc + (coeff, bit.get_variable());
31 fe = bit
32 .get_value()
33 .and_then(|val| fe.map(|f| if val { f + coeff } else { f }));
34 coeff = coeff.double();
35 }
36 let num = AllocatedNum::alloc(cs.namespace(|| "Field element"), || {
37 fe.ok_or(SynthesisError::AssignmentMissing)
38 })?;
39 lc = lc - num.get_variable();
40 cs.enforce(|| "compute number from bits", |lc| lc, |lc| lc, |_| lc);
41 Ok(num)
42}
43
44pub fn alloc_zero<F: PrimeField, CS: ConstraintSystem<F>>(mut cs: CS) -> AllocatedNum<F> {
46 let zero = AllocatedNum::alloc_infallible(cs.namespace(|| "alloc"), || F::ZERO);
47 cs.enforce(
48 || "check zero is valid",
49 |lc| lc,
50 |lc| lc,
51 |lc| lc + zero.get_variable(),
52 );
53 zero
54}
55
56pub fn alloc_one<F: PrimeField, CS: ConstraintSystem<F>>(mut cs: CS) -> AllocatedNum<F> {
58 let one = AllocatedNum::alloc_infallible(cs.namespace(|| "alloc"), || F::ONE);
59 cs.enforce(
60 || "check one is valid",
61 |lc| lc + CS::one(),
62 |lc| lc + CS::one(),
63 |lc| lc + one.get_variable(),
64 );
65
66 one
67}
68
69pub fn alloc_scalar_as_base<E, CS>(
71 mut cs: CS,
72 input: Option<E::Scalar>,
73) -> Result<AllocatedNum<E::Base>, SynthesisError>
74where
75 E: Engine,
76 <E as Engine>::Scalar: PrimeFieldBits,
77 CS: ConstraintSystem<<E as Engine>::Base>,
78{
79 AllocatedNum::alloc(cs.namespace(|| "allocate scalar as base"), || {
80 let input_bits = input.unwrap_or(E::Scalar::ZERO).clone().to_le_bits();
81 let mut mult = E::Base::ONE;
82 let mut val = E::Base::ZERO;
83 for bit in input_bits {
84 if bit {
85 val += mult;
86 }
87 mult = mult + mult;
88 }
89 Ok(val)
90 })
91}
92
93pub fn scalar_as_base<E: Engine>(input: E::Scalar) -> E::Base {
96 field_switch::<E::Scalar, E::Base>(input)
97}
98
99pub fn base_as_scalar<E: Engine>(input: E::Base) -> E::Scalar {
102 field_switch::<E::Base, E::Scalar>(input)
103}
104
105pub fn field_switch<F1: PrimeField + PrimeFieldBits, F2: PrimeField>(x: F1) -> F2 {
107 let input_bits = x.to_le_bits();
108 let mut mult = F2::ONE;
109 let mut val = F2::ZERO;
110 for bit in input_bits {
111 if bit {
112 val += mult;
113 }
114 mult += mult;
115 }
116 val
117}
118
119pub fn to_bignat_repr<F1: PrimeField + PrimeFieldBits, F2: PrimeField>(x: &F1) -> Vec<F2> {
121 let limbs: Vec<F1> = nat_to_limbs(&f_to_nat(x), BN_LIMB_WIDTH, BN_N_LIMBS).unwrap();
122 limbs
123 .iter()
124 .map(|limb| field_switch::<F1, F2>(*limb))
125 .collect()
126}
127
128pub fn alloc_bignat_constant<F: PrimeField, CS: ConstraintSystem<F>>(
130 mut cs: CS,
131 val: &BigInt,
132 limb_width: usize,
133 n_limbs: usize,
134) -> Result<BigNat<F>, SynthesisError> {
135 let limbs = nat_to_limbs(val, limb_width, n_limbs).unwrap();
136 let bignat = BigNat::alloc_from_limbs(
137 cs.namespace(|| "alloc bignat"),
138 || Ok(limbs.clone()),
139 None,
140 limb_width,
141 n_limbs,
142 )?;
143 (0..n_limbs).for_each(|i| {
145 cs.enforce(
146 || format!("check limb {i}"),
147 |lc| lc + &bignat.limbs[i],
148 |lc| lc + CS::one(),
149 |lc| lc + (limbs[i], CS::one()),
150 );
151 });
152 Ok(bignat)
153}
154
155pub fn alloc_num_equals<F: PrimeField, CS: ConstraintSystem<F>>(
157 mut cs: CS,
158 a: &AllocatedNum<F>,
159 b: &AllocatedNum<F>,
160) -> Result<AllocatedBit, SynthesisError> {
161 let r_value = match (a.get_value(), b.get_value()) {
164 (Some(a), Some(b)) => Some(a == b),
165 _ => None,
166 };
167
168 let r = AllocatedBit::alloc(cs.namespace(|| "r"), r_value)?;
169
170 let t = AllocatedNum::alloc(cs.namespace(|| "t"), || {
173 Ok(if *a.get_value().get()? == *b.get_value().get()? {
174 F::ONE
175 } else {
176 (*a.get_value().get()? - *b.get_value().get()?)
177 .invert()
178 .unwrap()
179 })
180 })?;
181
182 cs.enforce(
183 || "t*(a - b) = 1 - r",
184 |lc| lc + t.get_variable(),
185 |lc| lc + a.get_variable() - b.get_variable(),
186 |lc| lc + CS::one() - r.get_variable(),
187 );
188
189 cs.enforce(
190 || "r*(a - b) = 0",
191 |lc| lc + r.get_variable(),
192 |lc| lc + a.get_variable() - b.get_variable(),
193 |lc| lc,
194 );
195
196 Ok(r)
197}
198
199pub fn conditionally_select<F: PrimeField, CS: ConstraintSystem<F>>(
201 mut cs: CS,
202 a: &AllocatedNum<F>,
203 b: &AllocatedNum<F>,
204 condition: &Boolean,
205) -> Result<AllocatedNum<F>, SynthesisError> {
206 let c = AllocatedNum::alloc(cs.namespace(|| "conditional select result"), || {
207 if *condition.get_value().get()? {
208 Ok(*a.get_value().get()?)
209 } else {
210 Ok(*b.get_value().get()?)
211 }
212 })?;
213
214 cs.enforce(
217 || "conditional select constraint",
218 |lc| lc + a.get_variable() - b.get_variable(),
219 |_| condition.lc(CS::one(), F::ONE),
220 |lc| lc + c.get_variable() - b.get_variable(),
221 );
222
223 Ok(c)
224}
225
226pub fn conditionally_select_vec<F: PrimeField, CS: ConstraintSystem<F>>(
228 mut cs: CS,
229 a: &[AllocatedNum<F>],
230 b: &[AllocatedNum<F>],
231 condition: &Boolean,
232) -> Result<Vec<AllocatedNum<F>>, SynthesisError> {
233 a.iter()
234 .zip(b.iter())
235 .enumerate()
236 .map(|(i, (a, b))| {
237 conditionally_select(cs.namespace(|| format!("select_{i}")), a, b, condition)
238 })
239 .collect::<Result<Vec<AllocatedNum<F>>, SynthesisError>>()
240}
241
242pub fn conditionally_select_bignat<F: PrimeField, CS: ConstraintSystem<F>>(
244 mut cs: CS,
245 a: &BigNat<F>,
246 b: &BigNat<F>,
247 condition: &Boolean,
248) -> Result<BigNat<F>, SynthesisError> {
249 assert!(a.limbs.len() == b.limbs.len());
250 let c = BigNat::alloc_from_nat(
251 cs.namespace(|| "conditional select result"),
252 || {
253 if *condition.get_value().get()? {
254 Ok(a.value.get()?.clone())
255 } else {
256 Ok(b.value.get()?.clone())
257 }
258 },
259 a.params.limb_width,
260 a.params.n_limbs,
261 )?;
262
263 for i in 0..c.limbs.len() {
266 cs.enforce(
267 || format!("conditional select constraint {i}"),
268 |lc| lc + &a.limbs[i] - &b.limbs[i],
269 |_| condition.lc(CS::one(), F::ONE),
270 |lc| lc + &c.limbs[i] - &b.limbs[i],
271 );
272 }
273 Ok(c)
274}
275
276pub fn conditionally_select2<F: PrimeField, CS: ConstraintSystem<F>>(
279 mut cs: CS,
280 a: &AllocatedNum<F>,
281 b: &AllocatedNum<F>,
282 condition: &AllocatedNum<F>,
283) -> Result<AllocatedNum<F>, SynthesisError> {
284 let c = AllocatedNum::alloc(cs.namespace(|| "conditional select result"), || {
285 if *condition.get_value().get()? == F::ONE {
286 Ok(*a.get_value().get()?)
287 } else {
288 Ok(*b.get_value().get()?)
289 }
290 })?;
291
292 cs.enforce(
295 || "conditional select constraint",
296 |lc| lc + a.get_variable() - b.get_variable(),
297 |lc| lc + condition.get_variable(),
298 |lc| lc + c.get_variable() - b.get_variable(),
299 );
300
301 Ok(c)
302}
303
304pub fn select_zero_or_num2<F: PrimeField, CS: ConstraintSystem<F>>(
306 mut cs: CS,
307 a: &AllocatedNum<F>,
308 condition: &AllocatedNum<F>,
309) -> Result<AllocatedNum<F>, SynthesisError> {
310 let c = AllocatedNum::alloc(cs.namespace(|| "conditional select result"), || {
311 if *condition.get_value().get()? == F::ONE {
312 Ok(F::ZERO)
313 } else {
314 Ok(*a.get_value().get()?)
315 }
316 })?;
317
318 cs.enforce(
320 || "conditional select constraint",
321 |lc| lc + a.get_variable(),
322 |lc| lc + CS::one() - condition.get_variable(),
323 |lc| lc + c.get_variable(),
324 );
325
326 Ok(c)
327}
328
329pub fn select_num_or_zero2<F: PrimeField, CS: ConstraintSystem<F>>(
331 mut cs: CS,
332 a: &AllocatedNum<F>,
333 condition: &AllocatedNum<F>,
334) -> Result<AllocatedNum<F>, SynthesisError> {
335 let c = AllocatedNum::alloc(cs.namespace(|| "conditional select result"), || {
336 if *condition.get_value().get()? == F::ONE {
337 Ok(*a.get_value().get()?)
338 } else {
339 Ok(F::ZERO)
340 }
341 })?;
342
343 cs.enforce(
344 || "conditional select constraint",
345 |lc| lc + a.get_variable(),
346 |lc| lc + condition.get_variable(),
347 |lc| lc + c.get_variable(),
348 );
349
350 Ok(c)
351}
352
353pub fn select_num_or_zero<F: PrimeField, CS: ConstraintSystem<F>>(
355 mut cs: CS,
356 a: &AllocatedNum<F>,
357 condition: &Boolean,
358) -> Result<AllocatedNum<F>, SynthesisError> {
359 let c = AllocatedNum::alloc(cs.namespace(|| "conditional select result"), || {
360 if *condition.get_value().get()? {
361 Ok(*a.get_value().get()?)
362 } else {
363 Ok(F::ZERO)
364 }
365 })?;
366
367 cs.enforce(
368 || "conditional select constraint",
369 |lc| lc + a.get_variable(),
370 |_| condition.lc(CS::one(), F::ONE),
371 |lc| lc + c.get_variable(),
372 );
373
374 Ok(c)
375}
376
377pub fn select_one_or_num2<F: PrimeField, CS: ConstraintSystem<F>>(
379 mut cs: CS,
380 a: &AllocatedNum<F>,
381 condition: &AllocatedNum<F>,
382) -> Result<AllocatedNum<F>, SynthesisError> {
383 let c = AllocatedNum::alloc(cs.namespace(|| "conditional select result"), || {
384 if *condition.get_value().get()? == F::ONE {
385 Ok(F::ONE)
386 } else {
387 Ok(*a.get_value().get()?)
388 }
389 })?;
390
391 cs.enforce(
392 || "conditional select constraint",
393 |lc| lc + CS::one() - a.get_variable(),
394 |lc| lc + condition.get_variable(),
395 |lc| lc + c.get_variable() - a.get_variable(),
396 );
397 Ok(c)
398}
399
400pub fn select_one_or_diff2<F: PrimeField, CS: ConstraintSystem<F>>(
402 mut cs: CS,
403 a: &AllocatedNum<F>,
404 b: &AllocatedNum<F>,
405 condition: &AllocatedNum<F>,
406) -> Result<AllocatedNum<F>, SynthesisError> {
407 let c = AllocatedNum::alloc(cs.namespace(|| "conditional select result"), || {
408 if *condition.get_value().get()? == F::ONE {
409 Ok(F::ONE)
410 } else {
411 Ok(*a.get_value().get()? - *b.get_value().get()?)
412 }
413 })?;
414
415 cs.enforce(
416 || "conditional select constraint",
417 |lc| lc + CS::one() - a.get_variable() + b.get_variable(),
418 |lc| lc + condition.get_variable(),
419 |lc| lc + c.get_variable() - a.get_variable() + b.get_variable(),
420 );
421 Ok(c)
422}
423
424pub fn select_num_or_one<F: PrimeField, CS: ConstraintSystem<F>>(
426 mut cs: CS,
427 a: &AllocatedNum<F>,
428 condition: &Boolean,
429) -> Result<AllocatedNum<F>, SynthesisError> {
430 let c = AllocatedNum::alloc(cs.namespace(|| "conditional select result"), || {
431 if *condition.get_value().get()? {
432 Ok(*a.get_value().get()?)
433 } else {
434 Ok(F::ONE)
435 }
436 })?;
437
438 cs.enforce(
439 || "conditional select constraint",
440 |lc| lc + a.get_variable() - CS::one(),
441 |_| condition.lc(CS::one(), F::ONE),
442 |lc| lc + c.get_variable() - CS::one(),
443 );
444
445 Ok(c)
446}
447
448pub fn alloc_constant<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
450 mut cs: CS,
451 c: &Scalar,
452) -> Result<AllocatedNum<Scalar>, SynthesisError> {
453 let constant = AllocatedNum::alloc(cs.namespace(|| "constant"), || Ok(*c))?;
454
455 cs.enforce(
456 || "check eq given constant",
457 |lc| lc + constant.get_variable(),
458 |lc| lc + CS::one(),
459 |lc| lc + (*c, CS::one()),
460 );
461
462 Ok(constant)
463}
464
465pub fn base_as_bigint<E: Engine>(input: E::Base) -> BigInt {
467 let input_bits = input.to_le_bits();
468 let mut mult = BigInt::from(1);
469 let mut val = BigInt::from(0);
470 for bit in input_bits {
471 if bit {
472 val += &mult;
473 }
474 mult *= BigInt::from(2);
475 }
476 val
477}
478
479pub fn le_num_to_num<Scalar, CS>(
485 mut cs: CS,
486 bits: &[AllocatedNum<Scalar>],
487) -> Result<AllocatedNum<Scalar>, SynthesisError>
488where
489 Scalar: PrimeField + PrimeFieldBits,
490 CS: ConstraintSystem<Scalar>,
491{
492 let mut lc = LinearCombination::zero();
495 let mut coeff = Scalar::ONE;
496 let mut fe = Some(Scalar::ZERO);
497 for bit in bits.iter() {
498 lc = lc + (coeff, bit.get_variable());
499 fe = bit.get_value().map(|val| {
500 if val == Scalar::ONE {
501 fe.unwrap() + coeff
502 } else {
503 fe.unwrap()
504 }
505 });
506 coeff = coeff.double();
507 }
508 let num = AllocatedNum::alloc(cs.namespace(|| "Field element"), || {
509 fe.ok_or(SynthesisError::AssignmentMissing)
510 })?;
511 lc = lc - num.get_variable();
512 cs.enforce(|| "compute number from bits", |lc| lc, |lc| lc, |_| lc);
513 Ok(num)
514}
515
516pub fn fingerprint<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
520 mut cs: CS,
521 acc: &AllocatedNum<Scalar>,
522 c: &AllocatedNum<Scalar>,
523 c_i: &AllocatedNum<Scalar>,
524 v: &AllocatedNum<Scalar>,
525) -> Result<(AllocatedNum<Scalar>, AllocatedNum<Scalar>), SynthesisError> {
526 let acc_out = AllocatedNum::alloc(cs.namespace(|| "acc_out"), || {
531 Ok(*acc.get_value().get()? + *c_i.get_value().get()? * *v.get_value().get()?)
532 })?;
533 cs.enforce(
534 || "acc_out = acc + c_i * v",
535 |lc| lc + c_i.get_variable(),
536 |lc| lc + v.get_variable(),
537 |lc| lc + acc_out.get_variable() - acc.get_variable(),
538 );
539
540 let c_i_out = AllocatedNum::alloc(cs.namespace(|| "c_i_out"), || {
542 Ok(*c_i.get_value().get()? * *c.get_value().get()?)
543 })?;
544 cs.enforce(
545 || "c_i_out = c * c^i",
546 |lc| lc + c.get_variable(),
547 |lc| lc + c_i.get_variable(),
548 |lc| lc + c_i_out.get_variable(),
549 );
550
551 Ok((acc_out, c_i_out))
552}