ark_r1cs_std/boolean/cmp.rs
1use crate::cmp::CmpGadget;
2
3use super::*;
4use ark_ff::PrimeField;
5
6impl<F: PrimeField> CmpGadget<F> for Boolean<F> {
7 fn is_ge(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
8 // a | b | (a | !b) | a >= b
9 // --|---|--------|--------
10 // 0 | 0 | 1 | 1
11 // 1 | 0 | 1 | 1
12 // 0 | 1 | 0 | 0
13 // 1 | 1 | 1 | 1
14 Ok(self | &(!other))
15 }
16}
17
18impl<F: PrimeField> Boolean<F> {
19 /// Enforces that `bits`, when interpreted as a integer, is less than
20 /// `F::characteristic()`, That is, interpret bits as a little-endian
21 /// integer, and enforce that this integer is "in the field Z_p", where
22 /// `p = F::characteristic()` .
23 #[tracing::instrument(target = "r1cs")]
24 pub fn enforce_in_field_le(bits: &[Self]) -> Result<(), SynthesisError> {
25 // `bits` < F::characteristic() <==> `bits` <= F::characteristic() -1
26 let mut b = F::characteristic().to_vec();
27 assert_eq!(b[0] % 2, 1);
28 b[0] -= 1; // This works, because the LSB is one, so there's no borrows.
29 let run = Self::enforce_smaller_or_equal_than_le(bits, b)?;
30
31 // We should always end in a "run" of zeros, because
32 // the characteristic is an odd prime. So, this should
33 // be empty.
34 assert!(run.is_empty());
35
36 Ok(())
37 }
38
39 /// Enforces that `bits` is less than or equal to `element`,
40 /// when both are interpreted as (little-endian) integers.
41 #[tracing::instrument(target = "r1cs", skip(element))]
42 pub fn enforce_smaller_or_equal_than_le(
43 bits: &[Self],
44 element: impl AsRef<[u64]>,
45 ) -> Result<Vec<Self>, SynthesisError> {
46 let b: &[u64] = element.as_ref();
47
48 let mut bits_iter = bits.iter().rev(); // Iterate in big-endian
49
50 // Runs of ones in r
51 let mut last_run = Boolean::TRUE;
52 let mut current_run = vec![];
53
54 let mut element_num_bits = 0;
55 for _ in BitIteratorBE::without_leading_zeros(b) {
56 element_num_bits += 1;
57 }
58
59 if bits.len() > element_num_bits {
60 let mut or_result = Boolean::FALSE;
61 for should_be_zero in &bits[element_num_bits..] {
62 or_result |= should_be_zero;
63 let _ = bits_iter.next().unwrap();
64 }
65 or_result.enforce_equal(&Boolean::FALSE)?;
66 }
67
68 for (b, a) in BitIteratorBE::without_leading_zeros(b).zip(bits_iter.by_ref()) {
69 if b {
70 // This is part of a run of ones.
71 current_run.push(a.clone());
72 } else {
73 if !current_run.is_empty() {
74 // This is the start of a run of zeros, but we need
75 // to k-ary AND against `last_run` first.
76
77 current_run.push(last_run.clone());
78 last_run = Self::kary_and(¤t_run)?;
79 current_run.truncate(0);
80 }
81
82 // If `last_run` is true, `a` must be false, or it would
83 // not be in the field.
84 //
85 // If `last_run` is false, `a` can be true or false.
86 //
87 // Ergo, at least one of `last_run` and `a` must be false.
88 Self::enforce_kary_nand(&[last_run.clone(), a.clone()])?;
89 }
90 }
91 assert!(bits_iter.next().is_none());
92
93 Ok(current_run)
94 }
95}