ark-r1cs-std/src/uint/rotate.rs
src/uint/rotate.rsRaw
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 by = by % N;
26 let mut result = self.clone();
27 // `[T]::rotate_left` corresponds to a `rotate_right` of the bits.
28 result.bits.rotate_left(by);
29 result.value = self.value.map(|v| v.rotate_right(by as u32));
30 result
31 }
32
33 /// Rotates `self` to the left by `by` steps, wrapping around.
34 ///
35 /// # Examples
36 /// ```
37 /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
38 /// // We'll use the BLS12-381 scalar field for our constraints.
39 /// use ark_test_curves::bls12_381::Fr;
40 /// use ark_relations::r1cs::*;
41 /// use ark_r1cs_std::prelude::*;
42 ///
43 /// let cs = ConstraintSystem::<Fr>::new_ref();
44 /// let a = UInt32::new_witness(cs.clone(), || Ok(0x10000b3))?;
45 /// let b = UInt32::new_witness(cs.clone(), || Ok(0xb301u32))?;
46 ///
47 /// a.rotate_left(8).enforce_equal(&b)?;
48 /// assert!(cs.is_satisfied().unwrap());
49 /// # Ok(())
50 /// # }
51 /// ```
52 #[tracing::instrument(target = "r1cs", skip(self))]
53 pub fn rotate_left(&self, by: usize) -> Self {
54 let by = by % N;
55 let mut result = self.clone();
56 // `[T]::rotate_right` corresponds to a `rotate_left` of the bits.
57 result.bits.rotate_right(by);
58 result.value = self.value.map(|v| v.rotate_left(by as u32));
59 result
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use crate::{
67 alloc::{AllocVar, AllocationMode},
68 prelude::EqGadget,
69 uint::test_utils::{run_unary_exhaustive, run_unary_random},
70 R1CSVar,
71 };
72 use ark_ff::PrimeField;
73 use ark_test_curves::bls12_381::Fr;
74
75 fn uint_rotate_left<T: PrimUInt, const N: usize, F: PrimeField>(
76 a: UInt<N, T, F>,
77 ) -> Result<(), SynthesisError> {
78 let cs = a.cs();
79 let expected_mode = if a.is_constant() {
80 AllocationMode::Constant
81 } else {
82 AllocationMode::Witness
83 };
84 for shift in 0..N {
85 let computed = a.rotate_left(shift);
86 let expected = UInt::<N, T, F>::new_variable(
87 cs.clone(),
88 || Ok(a.value()?.rotate_left(shift as u32)),
89 expected_mode,
90 )?;
91 assert_eq!(expected.value(), computed.value());
92 expected.enforce_equal(&computed)?;
93 if !a.is_constant() {
94 assert!(cs.is_satisfied().unwrap());
95 }
96 }
97 Ok(())
98 }
99
100 fn uint_rotate_right<T: PrimUInt, const N: usize, F: PrimeField>(
101 a: UInt<N, T, F>,
102 ) -> Result<(), SynthesisError> {
103 let cs = a.cs();
104 let expected_mode = if a.is_constant() {
105 AllocationMode::Constant
106 } else {
107 AllocationMode::Witness
108 };
109 for shift in 0..N {
110 let computed = a.rotate_right(shift);
111 let expected = UInt::<N, T, F>::new_variable(
112 cs.clone(),
113 || Ok(a.value()?.rotate_right(shift as u32)),
114 expected_mode,
115 )?;
116 assert_eq!(expected.value(), computed.value());
117 expected.enforce_equal(&computed)?;
118 if !a.is_constant() {
119 assert!(cs.is_satisfied().unwrap());
120 }
121 }
122 Ok(())
123 }
124
125 #[test]
126 fn u8_rotate_left() {
127 run_unary_exhaustive(uint_rotate_left::<u8, 8, Fr>).unwrap()
128 }
129
130 #[test]
131 fn u16_rotate_left() {
132 run_unary_random::<1000, 16, _, _>(uint_rotate_left::<u16, 16, Fr>).unwrap()
133 }
134
135 #[test]
136 fn u32_rotate_left() {
137 run_unary_random::<1000, 32, _, _>(uint_rotate_left::<u32, 32, Fr>).unwrap()
138 }
139
140 #[test]
141 fn u64_rotate_left() {
142 run_unary_random::<200, 64, _, _>(uint_rotate_left::<u64, 64, Fr>).unwrap()
143 }
144
145 #[test]
146 fn u128_rotate_left() {
147 run_unary_random::<100, 128, _, _>(uint_rotate_left::<u128, 128, Fr>).unwrap()
148 }
149
150 #[test]
151 fn u8_rotate_right() {
152 run_unary_exhaustive(uint_rotate_right::<u8, 8, Fr>).unwrap()
153 }
154
155 #[test]
156 fn u16_rotate_right() {
157 run_unary_random::<1000, 16, _, _>(uint_rotate_right::<u16, 16, Fr>).unwrap()
158 }
159
160 #[test]
161 fn u32_rotate_right() {
162 run_unary_random::<1000, 32, _, _>(uint_rotate_right::<u32, 32, Fr>).unwrap()
163 }
164
165 #[test]
166 fn u64_rotate_right() {
167 run_unary_random::<200, 64, _, _>(uint_rotate_right::<u64, 64, Fr>).unwrap()
168 }
169
170 #[test]
171 fn u128_rotate_right() {
172 run_unary_random::<100, 128, _, _>(uint_rotate_right::<u128, 128, Fr>).unwrap()
173 }
174}