ark_r1cs_std/uint/
rotate.rs

1use super::*;
2
3impl<const N: usize, T: PrimUInt, ConstraintF: Field> UInt<N, T, ConstraintF> {
4    /// Rotates `self` to the right by `by` steps, wrapping around.
5    ///
6    /// # Examples
7    /// ```
8    /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
9    /// // We'll use the BLS12-381 scalar field for our constraints.
10    /// use ark_test_curves::bls12_381::Fr;
11    /// use ark_relations::r1cs::*;
12    /// use ark_r1cs_std::prelude::*;
13    ///
14    /// let cs = ConstraintSystem::<Fr>::new_ref();
15    /// let a = UInt32::new_witness(cs.clone(), || Ok(0xb301u32))?;
16    /// let b = UInt32::new_witness(cs.clone(), || Ok(0x10000b3))?;
17    ///
18    /// a.rotate_right(8).enforce_equal(&b)?;
19    /// assert!(cs.is_satisfied().unwrap());
20    /// # Ok(())
21    /// # }
22    /// ```
23    #[tracing::instrument(target = "r1cs", skip(self))]
24    pub fn rotate_right(&self, by: usize) -> Self {
25        let mut result = self.clone();
26        result.rotate_right_in_place(by);
27        result
28    }
29    /// Rotates `self` to the right *in place* by `by` steps, wrapping around.
30    ///
31    /// # Examples
32    /// ```
33    /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
34    /// // We'll use the BLS12-381 scalar field for our constraints.
35    /// use ark_test_curves::bls12_381::Fr;
36    /// use ark_relations::r1cs::*;
37    /// use ark_r1cs_std::prelude::*;
38    ///
39    /// let cs = ConstraintSystem::<Fr>::new_ref();
40    /// let mut a = UInt32::new_witness(cs.clone(), || Ok(0xb301u32))?;
41    /// let b = UInt32::new_witness(cs.clone(), || Ok(0x10000b3))?;
42    ///
43    /// a.rotate_right_in_place(8);
44    /// a.enforce_equal(&b)?;
45    /// assert!(cs.is_satisfied().unwrap());
46    /// # Ok(())
47    /// # }
48    /// ```
49    #[tracing::instrument(target = "r1cs", skip(self))]
50    pub fn rotate_right_in_place(&mut self, by: usize) {
51        let by = by % N;
52        // `[T]::rotate_left` corresponds to a `rotate_right` of the bits.
53        self.bits.rotate_left(by);
54        self.value = self.value.map(|v| v.rotate_right(by as u32));
55    }
56
57    /// Rotates `self` to the left by `by` steps, wrapping around.
58    ///
59    /// # Examples
60    /// ```
61    /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
62    /// // We'll use the BLS12-381 scalar field for our constraints.
63    /// use ark_test_curves::bls12_381::Fr;
64    /// use ark_relations::r1cs::*;
65    /// use ark_r1cs_std::prelude::*;
66    ///
67    /// let cs = ConstraintSystem::<Fr>::new_ref();
68    /// let a = UInt32::new_witness(cs.clone(), || Ok(0x10000b3))?;
69    /// let b = UInt32::new_witness(cs.clone(), || Ok(0xb301u32))?;
70    ///
71    /// a.rotate_left(8).enforce_equal(&b)?;
72    /// assert!(cs.is_satisfied().unwrap());
73    /// # Ok(())
74    /// # }
75    /// ```
76    #[tracing::instrument(target = "r1cs", skip(self))]
77    pub fn rotate_left(&self, by: usize) -> Self {
78        let mut result = self.clone();
79        result.rotate_left_in_place(by);
80        result
81    }
82
83    /// Rotates `self` to the left *in place* by `by` steps, wrapping around.
84    ///
85    /// # Examples
86    /// ```
87    /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
88    /// // We'll use the BLS12-381 scalar field for our constraints.
89    /// use ark_test_curves::bls12_381::Fr;
90    /// use ark_relations::r1cs::*;
91    /// use ark_r1cs_std::prelude::*;
92    ///
93    /// let cs = ConstraintSystem::<Fr>::new_ref();
94    /// let mut a = UInt32::new_witness(cs.clone(), || Ok(0x10000b3))?;
95    /// let b = UInt32::new_witness(cs.clone(), || Ok(0xb301u32))?;
96    ///
97    /// a.rotate_left_in_place(8);
98    /// a.enforce_equal(&b)?;
99    /// assert!(cs.is_satisfied().unwrap());
100    /// # Ok(())
101    /// # }
102    /// ```
103    pub fn rotate_left_in_place(&mut self, by: usize) {
104        let by = by % N;
105        // `[T]::rotate_right` corresponds to a `rotate_left` of the bits.
106        self.bits.rotate_right(by);
107        self.value = self.value.map(|v| v.rotate_left(by as u32));
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114    use crate::{
115        alloc::{AllocVar, AllocationMode},
116        prelude::EqGadget,
117        uint::test_utils::{run_unary_exhaustive, run_unary_random},
118        R1CSVar,
119    };
120    use ark_ff::PrimeField;
121    use ark_test_curves::bls12_381::Fr;
122
123    fn uint_rotate_left<T: PrimUInt, const N: usize, F: PrimeField>(
124        a: UInt<N, T, F>,
125    ) -> Result<(), SynthesisError> {
126        let cs = a.cs();
127        let expected_mode = if a.is_constant() {
128            AllocationMode::Constant
129        } else {
130            AllocationMode::Witness
131        };
132        for shift in 0..N {
133            let computed = a.rotate_left(shift);
134            let expected = UInt::<N, T, F>::new_variable(
135                cs.clone(),
136                || Ok(a.value()?.rotate_left(shift as u32)),
137                expected_mode,
138            )?;
139            assert_eq!(expected.value(), computed.value());
140            expected.enforce_equal(&computed)?;
141            if !a.is_constant() {
142                assert!(cs.is_satisfied().unwrap());
143            }
144        }
145        Ok(())
146    }
147
148    fn uint_rotate_right<T: PrimUInt, const N: usize, F: PrimeField>(
149        a: UInt<N, T, F>,
150    ) -> Result<(), SynthesisError> {
151        let cs = a.cs();
152        let expected_mode = if a.is_constant() {
153            AllocationMode::Constant
154        } else {
155            AllocationMode::Witness
156        };
157        for shift in 0..N {
158            let computed = a.rotate_right(shift);
159            let expected = UInt::<N, T, F>::new_variable(
160                cs.clone(),
161                || Ok(a.value()?.rotate_right(shift as u32)),
162                expected_mode,
163            )?;
164            assert_eq!(expected.value(), computed.value());
165            expected.enforce_equal(&computed)?;
166            if !a.is_constant() {
167                assert!(cs.is_satisfied().unwrap());
168            }
169        }
170        Ok(())
171    }
172
173    #[test]
174    fn u8_rotate_left() {
175        run_unary_exhaustive(uint_rotate_left::<u8, 8, Fr>).unwrap()
176    }
177
178    #[test]
179    fn u16_rotate_left() {
180        run_unary_random::<1000, 16, _, _>(uint_rotate_left::<u16, 16, Fr>).unwrap()
181    }
182
183    #[test]
184    fn u32_rotate_left() {
185        run_unary_random::<1000, 32, _, _>(uint_rotate_left::<u32, 32, Fr>).unwrap()
186    }
187
188    #[test]
189    fn u64_rotate_left() {
190        run_unary_random::<200, 64, _, _>(uint_rotate_left::<u64, 64, Fr>).unwrap()
191    }
192
193    #[test]
194    fn u128_rotate_left() {
195        run_unary_random::<100, 128, _, _>(uint_rotate_left::<u128, 128, Fr>).unwrap()
196    }
197
198    #[test]
199    fn u8_rotate_right() {
200        run_unary_exhaustive(uint_rotate_right::<u8, 8, Fr>).unwrap()
201    }
202
203    #[test]
204    fn u16_rotate_right() {
205        run_unary_random::<1000, 16, _, _>(uint_rotate_right::<u16, 16, Fr>).unwrap()
206    }
207
208    #[test]
209    fn u32_rotate_right() {
210        run_unary_random::<1000, 32, _, _>(uint_rotate_right::<u32, 32, Fr>).unwrap()
211    }
212
213    #[test]
214    fn u64_rotate_right() {
215        run_unary_random::<200, 64, _, _>(uint_rotate_right::<u64, 64, Fr>).unwrap()
216    }
217
218    #[test]
219    fn u128_rotate_right() {
220        run_unary_random::<100, 128, _, _>(uint_rotate_right::<u128, 128, Fr>).unwrap()
221    }
222}