arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
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}