ark_r1cs_std/uint/
cmp.rs

1use crate::cmp::CmpGadget;
2
3use super::*;
4
5impl<const N: usize, T: PrimUInt, F: PrimeField + From<T>> CmpGadget<F> for UInt<N, T, F> {
6    fn is_ge(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
7        if N + 1 < ((F::MODULUS_BIT_SIZE - 1) as usize) {
8            let a = self.to_fp()?;
9            let b = other.to_fp()?;
10            let (bits, _) = (a - b + F::from(T::max_value()) + F::one())
11                .to_bits_le_with_top_bits_zero(N + 1)?;
12            Ok(bits.last().unwrap().clone())
13        } else {
14            unimplemented!("bit sizes larger than modulus size not yet supported")
15        }
16    }
17}
18
19#[cfg(test)]
20mod tests {
21    use super::*;
22    use crate::{
23        alloc::{AllocVar, AllocationMode},
24        prelude::EqGadget,
25        uint::test_utils::{run_binary_exhaustive, run_binary_random},
26        R1CSVar,
27    };
28    use ark_ff::PrimeField;
29    use ark_test_curves::bls12_381::Fr;
30
31    fn uint_gt<T: PrimUInt, const N: usize, F: PrimeField + From<T>>(
32        a: UInt<N, T, F>,
33        b: UInt<N, T, F>,
34    ) -> Result<(), SynthesisError> {
35        let cs = a.cs().or(b.cs());
36        let both_constant = a.is_constant() && b.is_constant();
37        let expected_mode = if both_constant {
38            AllocationMode::Constant
39        } else {
40            AllocationMode::Witness
41        };
42        let computed = a.is_gt(&b)?;
43        let expected =
44            Boolean::new_variable(cs.clone(), || Ok(a.value()? > b.value()?), expected_mode)?;
45        assert_eq!(expected.value(), computed.value());
46        expected.enforce_equal(&computed)?;
47        if !both_constant {
48            assert!(cs.is_satisfied().unwrap());
49        }
50        Ok(())
51    }
52
53    fn uint_lt<T: PrimUInt, const N: usize, F: PrimeField + From<T>>(
54        a: UInt<N, T, F>,
55        b: UInt<N, T, F>,
56    ) -> Result<(), SynthesisError> {
57        let cs = a.cs().or(b.cs());
58        let both_constant = a.is_constant() && b.is_constant();
59        let expected_mode = if both_constant {
60            AllocationMode::Constant
61        } else {
62            AllocationMode::Witness
63        };
64        let computed = a.is_lt(&b)?;
65        let expected =
66            Boolean::new_variable(cs.clone(), || Ok(a.value()? < b.value()?), expected_mode)?;
67        assert_eq!(expected.value(), computed.value());
68        expected.enforce_equal(&computed)?;
69        if !both_constant {
70            assert!(cs.is_satisfied().unwrap());
71        }
72        Ok(())
73    }
74
75    fn uint_ge<T: PrimUInt, const N: usize, F: PrimeField + From<T>>(
76        a: UInt<N, T, F>,
77        b: UInt<N, T, F>,
78    ) -> Result<(), SynthesisError> {
79        let cs = a.cs().or(b.cs());
80        let both_constant = a.is_constant() && b.is_constant();
81        let expected_mode = if both_constant {
82            AllocationMode::Constant
83        } else {
84            AllocationMode::Witness
85        };
86        let computed = a.is_ge(&b)?;
87        let expected =
88            Boolean::new_variable(cs.clone(), || Ok(a.value()? >= b.value()?), expected_mode)?;
89        assert_eq!(expected.value(), computed.value());
90        expected.enforce_equal(&computed)?;
91        if !both_constant {
92            assert!(cs.is_satisfied().unwrap());
93        }
94        Ok(())
95    }
96
97    fn uint_le<T: PrimUInt, const N: usize, F: PrimeField + From<T>>(
98        a: UInt<N, T, F>,
99        b: UInt<N, T, F>,
100    ) -> Result<(), SynthesisError> {
101        let cs = a.cs().or(b.cs());
102        let both_constant = a.is_constant() && b.is_constant();
103        let expected_mode = if both_constant {
104            AllocationMode::Constant
105        } else {
106            AllocationMode::Witness
107        };
108        let computed = a.is_le(&b)?;
109        let expected =
110            Boolean::new_variable(cs.clone(), || Ok(a.value()? <= b.value()?), expected_mode)?;
111        assert_eq!(expected.value(), computed.value());
112        expected.enforce_equal(&computed)?;
113        if !both_constant {
114            assert!(cs.is_satisfied().unwrap());
115        }
116        Ok(())
117    }
118
119    #[test]
120    fn u8_gt() {
121        run_binary_exhaustive(uint_gt::<u8, 8, Fr>).unwrap()
122    }
123
124    #[test]
125    fn u16_gt() {
126        run_binary_random::<1000, 16, _, _>(uint_gt::<u16, 16, Fr>).unwrap()
127    }
128
129    #[test]
130    fn u32_gt() {
131        run_binary_random::<1000, 32, _, _>(uint_gt::<u32, 32, Fr>).unwrap()
132    }
133
134    #[test]
135    fn u64_gt() {
136        run_binary_random::<1000, 64, _, _>(uint_gt::<u64, 64, Fr>).unwrap()
137    }
138
139    #[test]
140    fn u128_gt() {
141        run_binary_random::<1000, 128, _, _>(uint_gt::<u128, 128, Fr>).unwrap()
142    }
143
144    #[test]
145    fn u8_lt() {
146        run_binary_exhaustive(uint_lt::<u8, 8, Fr>).unwrap()
147    }
148
149    #[test]
150    fn u16_lt() {
151        run_binary_random::<1000, 16, _, _>(uint_lt::<u16, 16, Fr>).unwrap()
152    }
153
154    #[test]
155    fn u32_lt() {
156        run_binary_random::<1000, 32, _, _>(uint_lt::<u32, 32, Fr>).unwrap()
157    }
158
159    #[test]
160    fn u64_lt() {
161        run_binary_random::<1000, 64, _, _>(uint_lt::<u64, 64, Fr>).unwrap()
162    }
163
164    #[test]
165    fn u128_lt() {
166        run_binary_random::<1000, 128, _, _>(uint_lt::<u128, 128, Fr>).unwrap()
167    }
168
169    #[test]
170    fn u8_le() {
171        run_binary_exhaustive(uint_le::<u8, 8, Fr>).unwrap()
172    }
173
174    #[test]
175    fn u16_le() {
176        run_binary_random::<1000, 16, _, _>(uint_le::<u16, 16, Fr>).unwrap()
177    }
178
179    #[test]
180    fn u32_le() {
181        run_binary_random::<1000, 32, _, _>(uint_le::<u32, 32, Fr>).unwrap()
182    }
183
184    #[test]
185    fn u64_le() {
186        run_binary_random::<1000, 64, _, _>(uint_le::<u64, 64, Fr>).unwrap()
187    }
188
189    #[test]
190    fn u128_le() {
191        run_binary_random::<1000, 128, _, _>(uint_le::<u128, 128, Fr>).unwrap()
192    }
193
194    #[test]
195    fn u8_ge() {
196        run_binary_exhaustive(uint_ge::<u8, 8, Fr>).unwrap()
197    }
198
199    #[test]
200    fn u16_ge() {
201        run_binary_random::<1000, 16, _, _>(uint_ge::<u16, 16, Fr>).unwrap()
202    }
203
204    #[test]
205    fn u32_ge() {
206        run_binary_random::<1000, 32, _, _>(uint_ge::<u32, 32, Fr>).unwrap()
207    }
208
209    #[test]
210    fn u64_ge() {
211        run_binary_random::<1000, 64, _, _>(uint_ge::<u64, 64, Fr>).unwrap()
212    }
213
214    #[test]
215    fn u128_ge() {
216        run_binary_random::<1000, 128, _, _>(uint_ge::<u128, 128, Fr>).unwrap()
217    }
218}