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}