From 1c8ff1440fa9f5b64adf232e80bfc89273f0b1f3 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 3 Jan 2024 12:44:09 -0500 Subject: [PATCH 1/8] Add back `ToBytesGadget` and `ToBitsGadget` to `prelude` --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 74c9dc21..a2bdc104 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,6 +90,7 @@ pub mod prelude { pub use crate::{ alloc::*, boolean::Boolean, + convert::{ToBitsGadget, ToBytesGadget}, eq::*, fields::{FieldOpsBounds, FieldVar}, groups::{CurveVar, GroupOpsBounds}, From 715d94a08bdaf69bc1816240e5dcb74d94155366 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 3 Jan 2024 13:08:24 -0500 Subject: [PATCH 2/8] Add operations with native types for `UInt`s --- src/uint/and.rs | 37 +++++++++++++++++++++++++++++++++++++ src/uint/or.rs | 37 +++++++++++++++++++++++++++++++++++++ src/uint/xor.rs | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) diff --git a/src/uint/and.rs b/src/uint/and.rs index 4fb1b5b6..1fe7d998 100644 --- a/src/uint/and.rs +++ b/src/uint/and.rs @@ -137,6 +137,43 @@ impl BitAnd for UInt { } } +impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd for UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitand(self, other: T) -> Self::Output { + self._and(&UInt::constant(other)).unwrap() + } +} + +impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd<&'a T> for UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitand(self, other: &'a T) -> Self::Output { + self._and(&Self::constant(*other)).unwrap() + } +} + +impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd<&'a T> for &'a UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitand(self, other: &'a T) -> Self::Output { + self._and(&UInt::constant(*other)).unwrap() + } +} + +impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd for &'a UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitand(self, other: T) -> Self::Output { + self._and(&UInt::constant(other)).unwrap() + } +} + + impl BitAndAssign for UInt { /// Sets `self = self & other`. /// diff --git a/src/uint/or.rs b/src/uint/or.rs index c69fc8db..e9178b5e 100644 --- a/src/uint/or.rs +++ b/src/uint/or.rs @@ -73,6 +73,43 @@ impl BitOr for UInt { } } +impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOr for UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitor(self, other: T) -> Self::Output { + self._or(&UInt::constant(other)).unwrap() + } +} + +impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOr<&'a T> for UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitor(self, other: &'a T) -> Self::Output { + self._or(&Self::constant(*other)).unwrap() + } +} + +impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOr<&'a T> for &'a UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitor(self, other: &'a T) -> Self::Output { + self._or(&UInt::constant(*other)).unwrap() + } +} + +impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOr for &'a UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitor(self, other: T) -> Self::Output { + self._or(&UInt::constant(other)).unwrap() + } +} + + impl BitOrAssign for UInt { /// Sets `self = self | other`. /// diff --git a/src/uint/xor.rs b/src/uint/xor.rs index 22f52398..22fdb5d2 100644 --- a/src/uint/xor.rs +++ b/src/uint/xor.rs @@ -72,6 +72,42 @@ impl BitXor for UInt { } } +impl<'a, const N: usize, T: PrimUInt, F: Field> BitXor for UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitxor(self, other: T) -> Self::Output { + self._xor(&UInt::constant(other)).unwrap() + } +} + +impl<'a, const N: usize, T: PrimUInt, F: Field> BitXor<&'a T> for UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitxor(self, other: &'a T) -> Self::Output { + self._xor(&Self::constant(*other)).unwrap() + } +} + +impl<'a, const N: usize, T: PrimUInt, F: Field> BitXor<&'a T> for &'a UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitxor(self, other: &'a T) -> Self::Output { + self._xor(&UInt::constant(*other)).unwrap() + } +} + +impl<'a, const N: usize, T: PrimUInt, F: Field> BitXor for &'a UInt { + type Output = UInt; + + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitxor(self, other: T) -> Self::Output { + self._xor(&UInt::constant(other)).unwrap() + } +} + impl BitXorAssign for UInt { /// Sets `self = self ^ other`. /// From b03717aeb74bb3dd67d9ae9f0f29bf7031e59e64 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 3 Jan 2024 14:34:16 -0500 Subject: [PATCH 3/8] Better tests and in place operations --- src/boolean/not.rs | 11 ++++- src/cmp.rs | 4 +- src/uint/and.rs | 98 ++++++++++++++++++++++++++++++++---------- src/uint/not.rs | 18 +++++--- src/uint/or.rs | 98 ++++++++++++++++++++++++++++++++---------- src/uint/shl.rs | 12 +++--- src/uint/shr.rs | 12 +++--- src/uint/test_utils.rs | 45 ++++++++++++++++++- src/uint/xor.rs | 97 ++++++++++++++++++++++++++++++++--------- 9 files changed, 306 insertions(+), 89 deletions(-) diff --git a/src/boolean/not.rs b/src/boolean/not.rs index 1c7de2e6..2745526d 100644 --- a/src/boolean/not.rs +++ b/src/boolean/not.rs @@ -6,10 +6,17 @@ use super::Boolean; impl Boolean { fn _not(&self) -> Result { + let mut result = self.clone(); + result.not_in_place()?; + Ok(result) + } + + pub fn not_in_place(&mut self) -> Result<(), SynthesisError> { match *self { - Boolean::Constant(c) => Ok(Boolean::Constant(!c)), - Boolean::Var(ref v) => Ok(Boolean::Var(v.not().unwrap())), + Boolean::Constant(ref mut c) => *c = !*c, + Boolean::Var(ref mut v) => *v = v.not()?, } + Ok(()) } } diff --git a/src/cmp.rs b/src/cmp.rs index 2765415f..3281195d 100644 --- a/src/cmp.rs +++ b/src/cmp.rs @@ -1,10 +1,10 @@ use ark_ff::Field; use ark_relations::r1cs::SynthesisError; -use crate::boolean::Boolean; +use crate::{boolean::Boolean, R1CSVar}; /// Specifies how to generate constraints for comparing two variables. -pub trait CmpGadget { +pub trait CmpGadget: R1CSVar { fn is_gt(&self, other: &Self) -> Result, SynthesisError> { other.is_lt(self) } diff --git a/src/uint/and.rs b/src/uint/and.rs index 1fe7d998..cfe711a2 100644 --- a/src/uint/and.rs +++ b/src/uint/and.rs @@ -7,11 +7,16 @@ use super::*; impl UInt { fn _and(&self, other: &Self) -> Result { let mut result = self.clone(); - for (a, b) in result.bits.iter_mut().zip(&other.bits) { + result._and_in_place(other)?; + Ok(result) + } + + fn _and_in_place(&mut self, other: &Self) -> Result<(), SynthesisError> { + for (a, b) in self.bits.iter_mut().zip(&other.bits) { *a &= b; } - result.value = self.value.and_then(|a| Some(a & other.value?)); - Ok(result) + self.value = self.value.and_then(|a| Some(a & other.value?)); + Ok(()) } } @@ -70,8 +75,9 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd<&'a Self> for UInt Self::Output { - self._and(&other).unwrap() + fn bitand(mut self, other: &Self) -> Self::Output { + self._and_in_place(other).unwrap(); + self } } @@ -102,7 +108,7 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd> for &'a UI /// ``` #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitand(self, other: UInt) -> Self::Output { - self._and(&other).unwrap() + other & self } } @@ -133,7 +139,7 @@ impl BitAnd for UInt { /// ``` #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitand(self, other: Self) -> Self::Output { - self._and(&other).unwrap() + self & &other } } @@ -142,7 +148,7 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd for UInt { #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitand(self, other: T) -> Self::Output { - self._and(&UInt::constant(other)).unwrap() + self & UInt::constant(other) } } @@ -151,7 +157,7 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd<&'a T> for UInt #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitand(self, other: &'a T) -> Self::Output { - self._and(&Self::constant(*other)).unwrap() + self & UInt::constant(*other) } } @@ -160,7 +166,7 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd<&'a T> for &'a UInt Self::Output { - self._and(&UInt::constant(*other)).unwrap() + self & UInt::constant(*other) } } @@ -169,11 +175,10 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd for &'a UInt #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitand(self, other: T) -> Self::Output { - self._and(&UInt::constant(other)).unwrap() + self & UInt::constant(other) } } - impl BitAndAssign for UInt { /// Sets `self = self & other`. /// @@ -200,8 +205,7 @@ impl BitAndAssign for UInt /// ``` #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitand_assign(&mut self, other: Self) { - let result = self._and(&other).unwrap(); - *self = result; + self._and_in_place(&other).unwrap(); } } @@ -231,8 +235,21 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitAndAssign<&'a Self> for UInt< /// ``` #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitand_assign(&mut self, other: &'a Self) { - let result = self._and(other).unwrap(); - *self = result; + self._and_in_place(&other).unwrap(); + } +} + +impl BitAndAssign for UInt { + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitand_assign(&mut self, other: T) { + *self &= &Self::constant(other); + } +} + +impl<'a, const N: usize, T: PrimUInt, F: Field> BitAndAssign<&'a T> for UInt { + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitand_assign(&mut self, other: &'a T) { + *self &= &Self::constant(*other); } } @@ -242,7 +259,7 @@ mod tests { use crate::{ alloc::{AllocVar, AllocationMode}, prelude::EqGadget, - uint::test_utils::{run_binary_exhaustive, run_binary_random}, + uint::test_utils::{run_binary_exhaustive_both, run_binary_random_both}, R1CSVar, }; use ark_ff::PrimeField; @@ -273,28 +290,65 @@ mod tests { Ok(()) } + fn uint_and_native( + a: UInt, + b: T, + ) -> Result<(), SynthesisError> { + let cs = a.cs(); + let computed = &a & b; + let expected_mode = if a.is_constant() { + AllocationMode::Constant + } else { + AllocationMode::Witness + }; + let expected = + UInt::::new_variable(cs.clone(), || Ok(a.value()? & b), expected_mode)?; + assert_eq!(expected.value(), computed.value()); + expected.enforce_equal(&computed)?; + if !a.is_constant() { + assert!(cs.is_satisfied().unwrap()); + } + Ok(()) + } + #[test] fn u8_and() { - run_binary_exhaustive(uint_and::).unwrap() + run_binary_exhaustive_both(uint_and::, uint_and_native::).unwrap() } #[test] fn u16_and() { - run_binary_random::<1000, 16, _, _>(uint_and::).unwrap() + run_binary_random_both::<1000, 16, _, _>( + uint_and::, + uint_and_native::, + ) + .unwrap() } #[test] fn u32_and() { - run_binary_random::<1000, 32, _, _>(uint_and::).unwrap() + run_binary_random_both::<1000, 32, _, _>( + uint_and::, + uint_and_native::, + ) + .unwrap() } #[test] fn u64_and() { - run_binary_random::<1000, 64, _, _>(uint_and::).unwrap() + run_binary_random_both::<1000, 64, _, _>( + uint_and::, + uint_and_native::, + ) + .unwrap() } #[test] fn u128_and() { - run_binary_random::<1000, 128, _, _>(uint_and::).unwrap() + run_binary_random_both::<1000, 128, _, _>( + uint_and::, + uint_and_native::, + ) + .unwrap() } } diff --git a/src/uint/not.rs b/src/uint/not.rs index 1bb883d5..8457f2ec 100644 --- a/src/uint/not.rs +++ b/src/uint/not.rs @@ -7,12 +7,17 @@ use super::*; impl UInt { fn _not(&self) -> Result { let mut result = self.clone(); - for a in &mut result.bits { - *a = !&*a - } - result.value = self.value.map(Not::not); + result._not_in_place()?; Ok(result) } + + fn _not_in_place(&mut self) -> Result<(), SynthesisError> { + for a in &mut self.bits { + a.not_in_place()?; + } + self.value = self.value.map(Not::not); + Ok(()) + } } impl<'a, const N: usize, T: PrimUInt, F: Field> Not for &'a UInt { @@ -67,8 +72,9 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> Not for UInt { /// # } /// ``` #[tracing::instrument(target = "r1cs", skip(self))] - fn not(self) -> Self::Output { - self._not().unwrap() + fn not(mut self) -> Self::Output { + self._not_in_place().unwrap(); + self } } diff --git a/src/uint/or.rs b/src/uint/or.rs index e9178b5e..0ca124ec 100644 --- a/src/uint/or.rs +++ b/src/uint/or.rs @@ -7,11 +7,16 @@ use super::{PrimUInt, UInt}; impl UInt { fn _or(&self, other: &Self) -> Result { let mut result = self.clone(); - for (a, b) in result.bits.iter_mut().zip(&other.bits) { + result._or_in_place(other)?; + Ok(result) + } + + fn _or_in_place(&mut self, other: &Self) -> Result<(), SynthesisError> { + for (a, b) in self.bits.iter_mut().zip(&other.bits) { *a |= b; } - result.value = self.value.and_then(|a| Some(a | other.value?)); - Ok(result) + self.value = self.value.and_then(|a| Some(a | other.value?)); + Ok(()) } } @@ -50,8 +55,9 @@ impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOr<&'a Self> for UInt; #[tracing::instrument(target = "r1cs", skip(self, other))] - fn bitor(self, other: &Self) -> Self::Output { - self._or(&other).unwrap() + fn bitor(mut self, other: &Self) -> Self::Output { + self._or_in_place(&other).unwrap(); + self } } @@ -60,7 +66,7 @@ impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOr> for &' #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitor(self, other: UInt) -> Self::Output { - self._or(&other).unwrap() + other | self } } @@ -69,7 +75,7 @@ impl BitOr for UInt { #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitor(self, other: Self) -> Self::Output { - self._or(&other).unwrap() + self | &other } } @@ -78,7 +84,7 @@ impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOr for UInt #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitor(self, other: T) -> Self::Output { - self._or(&UInt::constant(other)).unwrap() + self | &UInt::constant(other) } } @@ -87,7 +93,7 @@ impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOr<&'a T> for UInt Self::Output { - self._or(&Self::constant(*other)).unwrap() + self | &UInt::constant(*other) } } @@ -96,7 +102,7 @@ impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOr<&'a T> for &'a UInt Self::Output { - self._or(&UInt::constant(*other)).unwrap() + self | &UInt::constant(*other) } } @@ -105,11 +111,10 @@ impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOr for &'a UInt Self::Output { - self._or(&UInt::constant(other)).unwrap() + self | &UInt::constant(other) } } - impl BitOrAssign for UInt { /// Sets `self = self | other`. /// @@ -136,16 +141,28 @@ impl BitOrAssign for UInt BitOrAssign<&'a Self> for UInt { #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitor_assign(&mut self, other: &'a Self) { - let result = self._or(other).unwrap(); - *self = result; + self._or_in_place(other).unwrap(); + } +} + +impl BitOrAssign for UInt { + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitor_assign(&mut self, other: T) { + *self |= &UInt::constant(other); + } +} + +impl<'a, const N: usize, T: PrimUInt, F: PrimeField> BitOrAssign<&'a T> for UInt { + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitor_assign(&mut self, other: &'a T) { + *self |= &UInt::constant(*other); } } @@ -155,7 +172,7 @@ mod tests { use crate::{ alloc::{AllocVar, AllocationMode}, prelude::EqGadget, - uint::test_utils::{run_binary_exhaustive, run_binary_random}, + uint::test_utils::{run_binary_exhaustive_both, run_binary_random_both}, R1CSVar, }; use ark_ff::PrimeField; @@ -186,28 +203,65 @@ mod tests { Ok(()) } + fn uint_or_native( + a: UInt, + b: T, + ) -> Result<(), SynthesisError> { + let cs = a.cs(); + let computed = &a | &b; + let expected_mode = if a.is_constant() { + AllocationMode::Constant + } else { + AllocationMode::Witness + }; + let expected = + UInt::::new_variable(cs.clone(), || Ok(a.value()? | b), expected_mode)?; + assert_eq!(expected.value(), computed.value()); + expected.enforce_equal(&computed)?; + if !a.is_constant() { + assert!(cs.is_satisfied().unwrap()); + } + Ok(()) + } + #[test] fn u8_or() { - run_binary_exhaustive(uint_or::).unwrap() + run_binary_exhaustive_both(uint_or::, uint_or_native::).unwrap() } #[test] fn u16_or() { - run_binary_random::<1000, 16, _, _>(uint_or::).unwrap() + run_binary_random_both::<1000, 16, _, _>( + uint_or::, + uint_or_native::, + ) + .unwrap() } #[test] fn u32_or() { - run_binary_random::<1000, 32, _, _>(uint_or::).unwrap() + run_binary_random_both::<1000, 32, _, _>( + uint_or::, + uint_or_native::, + ) + .unwrap() } #[test] fn u64_or() { - run_binary_random::<1000, 64, _, _>(uint_or::).unwrap() + run_binary_random_both::<1000, 64, _, _>( + uint_or::, + uint_or_native::, + ) + .unwrap() } #[test] fn u128_or() { - run_binary_random::<1000, 128, _, _>(uint_or::).unwrap() + run_binary_random_both::<1000, 128, _, _>( + uint_or::, + uint_or_native::, + ) + .unwrap() } } diff --git a/src/uint/shl.rs b/src/uint/shl.rs index 645a07a4..4382ce64 100644 --- a/src/uint/shl.rs +++ b/src/uint/shl.rs @@ -99,7 +99,7 @@ mod tests { use crate::{ alloc::{AllocVar, AllocationMode}, prelude::EqGadget, - uint::test_utils::{run_binary_exhaustive_with_native, run_binary_random_with_native}, + uint::test_utils::{run_binary_exhaustive_native_only, run_binary_random_native_only}, R1CSVar, }; use ark_ff::PrimeField; @@ -129,26 +129,26 @@ mod tests { #[test] fn u8_shl() { - run_binary_exhaustive_with_native(uint_shl::).unwrap() + run_binary_exhaustive_native_only(uint_shl::).unwrap() } #[test] fn u16_shl() { - run_binary_random_with_native::<1000, 16, _, _>(uint_shl::).unwrap() + run_binary_random_native_only::<1000, 16, _, _>(uint_shl::).unwrap() } #[test] fn u32_shl() { - run_binary_random_with_native::<1000, 32, _, _>(uint_shl::).unwrap() + run_binary_random_native_only::<1000, 32, _, _>(uint_shl::).unwrap() } #[test] fn u64_shl() { - run_binary_random_with_native::<1000, 64, _, _>(uint_shl::).unwrap() + run_binary_random_native_only::<1000, 64, _, _>(uint_shl::).unwrap() } #[test] fn u128_shl() { - run_binary_random_with_native::<1000, 128, _, _>(uint_shl::).unwrap() + run_binary_random_native_only::<1000, 128, _, _>(uint_shl::).unwrap() } } diff --git a/src/uint/shr.rs b/src/uint/shr.rs index 7630855c..7368a3fb 100644 --- a/src/uint/shr.rs +++ b/src/uint/shr.rs @@ -99,7 +99,7 @@ mod tests { use crate::{ alloc::{AllocVar, AllocationMode}, prelude::EqGadget, - uint::test_utils::{run_binary_exhaustive_with_native, run_binary_random_with_native}, + uint::test_utils::{run_binary_exhaustive_native_only, run_binary_random_native_only}, R1CSVar, }; use ark_ff::PrimeField; @@ -129,26 +129,26 @@ mod tests { #[test] fn u8_shr() { - run_binary_exhaustive_with_native(uint_shr::).unwrap() + run_binary_exhaustive_native_only(uint_shr::).unwrap() } #[test] fn u16_shr() { - run_binary_random_with_native::<1000, 16, _, _>(uint_shr::).unwrap() + run_binary_random_native_only::<1000, 16, _, _>(uint_shr::).unwrap() } #[test] fn u32_shr() { - run_binary_random_with_native::<1000, 32, _, _>(uint_shr::).unwrap() + run_binary_random_native_only::<1000, 32, _, _>(uint_shr::).unwrap() } #[test] fn u64_shr() { - run_binary_random_with_native::<1000, 64, _, _>(uint_shr::).unwrap() + run_binary_random_native_only::<1000, 64, _, _>(uint_shr::).unwrap() } #[test] fn u128_shr() { - run_binary_random_with_native::<1000, 128, _, _>(uint_shr::).unwrap() + run_binary_random_native_only::<1000, 128, _, _>(uint_shr::).unwrap() } } diff --git a/src/uint/test_utils.rs b/src/uint/test_utils.rs index 0600bbeb..4987a2a7 100644 --- a/src/uint/test_utils.rs +++ b/src/uint/test_utils.rs @@ -39,6 +39,29 @@ pub(crate) fn test_binary_op_with_native( + test: impl Fn(UInt, UInt) -> Result<(), SynthesisError> + Copy, + test_native: impl Fn(UInt, T) -> Result<(), SynthesisError> + Copy, +) -> Result<(), SynthesisError> +where + T: PrimUInt, + F: PrimeField, +{ + let mut rng = ark_std::test_rng(); + + for _ in 0..ITERATIONS { + for mode_a in modes() { + let a = T::rand(&mut rng); + for mode_b in modes() { + let b = T::rand(&mut rng); + test_binary_op(a, b, mode_a, mode_b, test)?; + test_binary_op_with_native(a, b, mode_a, test_native)?; + } + } + } + Ok(()) +} + pub(crate) fn run_binary_random( test: impl Fn(UInt, UInt) -> Result<(), SynthesisError> + Copy, ) -> Result<(), SynthesisError> @@ -76,7 +99,25 @@ where Ok(()) } -pub(crate) fn run_binary_random_with_native( +pub(crate) fn run_binary_exhaustive_both( + test: impl Fn(UInt, UInt) -> Result<(), SynthesisError> + Copy, + test_native: impl Fn(UInt, T) -> Result<(), SynthesisError> + Copy, +) -> Result<(), SynthesisError> +where + T: PrimUInt, + F: PrimeField, + RangeInclusive: Iterator, +{ + for (mode_a, a) in test_utils::combination(T::min_value()..=T::max_value()) { + for (mode_b, b) in test_utils::combination(T::min_value()..=T::max_value()) { + test_binary_op(a, b, mode_a, mode_b, test)?; + test_binary_op_with_native(a, b, mode_a, test_native)?; + } + } + Ok(()) +} + +pub(crate) fn run_binary_random_native_only( test: impl Fn(UInt, T) -> Result<(), SynthesisError> + Copy, ) -> Result<(), SynthesisError> where @@ -95,7 +136,7 @@ where Ok(()) } -pub(crate) fn run_binary_exhaustive_with_native( +pub(crate) fn run_binary_exhaustive_native_only( test: impl Fn(UInt, T) -> Result<(), SynthesisError> + Copy, ) -> Result<(), SynthesisError> where diff --git a/src/uint/xor.rs b/src/uint/xor.rs index 22fdb5d2..56546ba7 100644 --- a/src/uint/xor.rs +++ b/src/uint/xor.rs @@ -7,11 +7,16 @@ use super::*; impl UInt { fn _xor(&self, other: &Self) -> Result { let mut result = self.clone(); - for (a, b) in result.bits.iter_mut().zip(&other.bits) { + result._xor_in_place(other)?; + Ok(result) + } + + fn _xor_in_place(&mut self, other: &Self) -> Result<(), SynthesisError> { + for (a, b) in self.bits.iter_mut().zip(&other.bits) { *a ^= b; } - result.value = self.value.and_then(|a| Some(a ^ other.value?)); - Ok(result) + self.value = self.value.and_then(|a| Some(a ^ other.value?)); + Ok(()) } } @@ -49,8 +54,9 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitXor<&'a Self> for UInt; #[tracing::instrument(target = "r1cs", skip(self, other))] - fn bitxor(self, other: &Self) -> Self::Output { - self._xor(&other).unwrap() + fn bitxor(mut self, other: &Self) -> Self::Output { + self._xor_in_place(&other).unwrap(); + self } } @@ -59,7 +65,7 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitXor> for &'a UI #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitxor(self, other: UInt) -> Self::Output { - self._xor(&other).unwrap() + other ^ self } } @@ -68,7 +74,7 @@ impl BitXor for UInt { #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitxor(self, other: Self) -> Self::Output { - self._xor(&other).unwrap() + self ^ &other } } @@ -77,7 +83,7 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitXor for UInt { #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitxor(self, other: T) -> Self::Output { - self._xor(&UInt::constant(other)).unwrap() + self ^ &UInt::constant(other) } } @@ -86,7 +92,7 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitXor<&'a T> for UInt #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitxor(self, other: &'a T) -> Self::Output { - self._xor(&Self::constant(*other)).unwrap() + self ^ &UInt::constant(*other) } } @@ -95,7 +101,7 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitXor<&'a T> for &'a UInt Self::Output { - self._xor(&UInt::constant(*other)).unwrap() + self ^ UInt::constant(*other) } } @@ -104,7 +110,7 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> BitXor for &'a UInt #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitxor(self, other: T) -> Self::Output { - self._xor(&UInt::constant(other)).unwrap() + self ^ UInt::constant(other) } } @@ -134,16 +140,28 @@ impl BitXorAssign for UInt /// ``` #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitxor_assign(&mut self, other: Self) { - let result = self._xor(&other).unwrap(); - *self = result; + self._xor_in_place(&other).unwrap(); } } impl<'a, const N: usize, T: PrimUInt, F: Field> BitXorAssign<&'a Self> for UInt { #[tracing::instrument(target = "r1cs", skip(self, other))] fn bitxor_assign(&mut self, other: &'a Self) { - let result = self._xor(other).unwrap(); - *self = result; + self._xor_in_place(other).unwrap(); + } +} + +impl BitXorAssign for UInt { + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitxor_assign(&mut self, other: T) { + *self ^= Self::constant(other); + } +} + +impl<'a, const N: usize, T: PrimUInt, F: Field> BitXorAssign<&'a T> for UInt { + #[tracing::instrument(target = "r1cs", skip(self, other))] + fn bitxor_assign(&mut self, other: &'a T) { + *self ^= Self::constant(*other); } } @@ -153,7 +171,7 @@ mod tests { use crate::{ alloc::{AllocVar, AllocationMode}, prelude::EqGadget, - uint::test_utils::{run_binary_exhaustive, run_binary_random}, + uint::test_utils::{run_binary_exhaustive_both, run_binary_random_both}, R1CSVar, }; use ark_ff::PrimeField; @@ -184,28 +202,65 @@ mod tests { Ok(()) } + fn uint_xor_native( + a: UInt, + b: T, + ) -> Result<(), SynthesisError> { + let cs = a.cs(); + let computed = &a ^ &b; + let expected_mode = if a.is_constant() { + AllocationMode::Constant + } else { + AllocationMode::Witness + }; + let expected = + UInt::::new_variable(cs.clone(), || Ok(a.value()? ^ b), expected_mode)?; + assert_eq!(expected.value(), computed.value()); + expected.enforce_equal(&computed)?; + if !a.is_constant() { + assert!(cs.is_satisfied().unwrap()); + } + Ok(()) + } + #[test] fn u8_xor() { - run_binary_exhaustive(uint_xor::).unwrap() + run_binary_exhaustive_both(uint_xor::, uint_xor_native::).unwrap() } #[test] fn u16_xor() { - run_binary_random::<1000, 16, _, _>(uint_xor::).unwrap() + run_binary_random_both::<1000, 16, _, _>( + uint_xor::, + uint_xor_native::, + ) + .unwrap() } #[test] fn u32_xor() { - run_binary_random::<1000, 32, _, _>(uint_xor::).unwrap() + run_binary_random_both::<1000, 32, _, _>( + uint_xor::, + uint_xor_native::, + ) + .unwrap() } #[test] fn u64_xor() { - run_binary_random::<1000, 64, _, _>(uint_xor::).unwrap() + run_binary_random_both::<1000, 64, _, _>( + uint_xor::, + uint_xor_native::, + ) + .unwrap() } #[test] fn u128_xor() { - run_binary_random::<1000, 128, _, _>(uint_xor::).unwrap() + run_binary_random_both::<1000, 128, _, _>( + uint_xor::, + uint_xor_native::, + ) + .unwrap() } } From 2b979b6afffb12cf8027cf135fdaafb8bff99fdc Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 3 Jan 2024 14:40:30 -0500 Subject: [PATCH 4/8] Add in place rotations --- src/uint/rotate.rs | 65 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/src/uint/rotate.rs b/src/uint/rotate.rs index f2d50d5d..6f2a7698 100644 --- a/src/uint/rotate.rs +++ b/src/uint/rotate.rs @@ -22,13 +22,38 @@ impl UInt { /// ``` #[tracing::instrument(target = "r1cs", skip(self))] pub fn rotate_right(&self, by: usize) -> Self { - let by = by % N; let mut result = self.clone(); - // `[T]::rotate_left` corresponds to a `rotate_right` of the bits. - result.bits.rotate_left(by); - result.value = self.value.map(|v| v.rotate_right(by as u32)); + result.rotate_right_in_place(by); result } + /// Rotates `self` to the right *in place* by `by` steps, wrapping around. + /// + /// # Examples + /// ``` + /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> { + /// // We'll use the BLS12-381 scalar field for our constraints. + /// use ark_test_curves::bls12_381::Fr; + /// use ark_relations::r1cs::*; + /// use ark_r1cs_std::prelude::*; + /// + /// let cs = ConstraintSystem::::new_ref(); + /// let a = UInt32::new_witness(cs.clone(), || Ok(0xb301u32))?; + /// let b = UInt32::new_witness(cs.clone(), || Ok(0x10000b3))?; + /// + /// a.rotate_right_in_place(8); + /// a.enforce_equal(&b)?; + /// assert!(cs.is_satisfied().unwrap()); + /// # Ok(()) + /// # } + /// ``` + + #[tracing::instrument(target = "r1cs", skip(self))] + pub fn rotate_right_in_place(&mut self, by: usize) { + let by = by % N; + // `[T]::rotate_left` corresponds to a `rotate_right` of the bits. + self.bits.rotate_left(by); + self.value = self.value.map(|v| v.rotate_right(by as u32)); + } /// Rotates `self` to the left by `by` steps, wrapping around. /// @@ -51,13 +76,37 @@ impl UInt { /// ``` #[tracing::instrument(target = "r1cs", skip(self))] pub fn rotate_left(&self, by: usize) -> Self { - let by = by % N; let mut result = self.clone(); - // `[T]::rotate_right` corresponds to a `rotate_left` of the bits. - result.bits.rotate_right(by); - result.value = self.value.map(|v| v.rotate_left(by as u32)); + result.rotate_left_in_place(by); result } + + /// Rotates `self` to the left *in place* by `by` steps, wrapping around. + /// + /// # Examples + /// ``` + /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> { + /// // We'll use the BLS12-381 scalar field for our constraints. + /// use ark_test_curves::bls12_381::Fr; + /// use ark_relations::r1cs::*; + /// use ark_r1cs_std::prelude::*; + /// + /// let cs = ConstraintSystem::::new_ref(); + /// let a = UInt32::new_witness(cs.clone(), || Ok(0x10000b3))?; + /// let b = UInt32::new_witness(cs.clone(), || Ok(0xb301u32))?; + /// + /// a.rotate_left_in_place(8); + /// a.enforce_equal(&b)?; + /// assert!(cs.is_satisfied().unwrap()); + /// # Ok(()) + /// # } + /// ``` + pub fn rotate_left_in_place(&mut self, by: usize) { + let by = by % N; + // `[T]::rotate_right` corresponds to a `rotate_left` of the bits. + self.bits.rotate_right(by); + self.value = self.value.map(|v| v.rotate_left(by as u32)); + } } #[cfg(test)] From 6e8673dcde2e55ecd81ebb7c67d3c23774a0decf Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 3 Jan 2024 14:57:53 -0500 Subject: [PATCH 5/8] Rename `to_{non_unique_}bytes` -> `to_{non_unique_}bytes_le` --- src/boolean/convert.rs | 2 +- src/boolean/mod.rs | 2 +- src/convert.rs | 16 ++-- src/fields/cubic_extension.rs | 16 ++-- src/fields/emulated_fp/allocated_field_var.rs | 2 +- src/fields/emulated_fp/field_var.rs | 8 +- src/fields/fp/mod.rs | 12 +-- src/fields/quadratic_extension.rs | 12 +-- .../curves/short_weierstrass/bls12/mod.rs | 28 +++---- .../curves/short_weierstrass/mnt4/mod.rs | 80 +++++++++---------- .../curves/short_weierstrass/mnt6/mod.rs | 80 +++++++++---------- src/groups/curves/short_weierstrass/mod.rs | 16 ++-- src/groups/curves/twisted_edwards/mod.rs | 12 +-- src/uint/convert.rs | 14 ++-- 14 files changed, 152 insertions(+), 148 deletions(-) diff --git a/src/boolean/convert.rs b/src/boolean/convert.rs index 21e9fc09..d4ce1518 100644 --- a/src/boolean/convert.rs +++ b/src/boolean/convert.rs @@ -4,7 +4,7 @@ use crate::convert::{ToBytesGadget, ToConstraintFieldGadget}; impl ToBytesGadget for Boolean { /// Outputs `1u8` if `self` is true, and `0u8` otherwise. #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { + fn to_bytes_le(&self) -> Result>, SynthesisError> { let value = self.value().map(u8::from).ok(); let mut bits = [Boolean::FALSE; 8]; bits[0] = self.clone(); diff --git a/src/boolean/mod.rs b/src/boolean/mod.rs index 0193f58b..f32c4a45 100644 --- a/src/boolean/mod.rs +++ b/src/boolean/mod.rs @@ -215,7 +215,7 @@ mod test { for val in [true, false].iter() { let cs = ConstraintSystem::::new_ref(); let a = Boolean::new_witness(cs.clone(), || Ok(*val))?; - let bytes = a.to_bytes()?; + let bytes = a.to_bytes_le()?; assert_eq!(bytes.len(), 1); let byte = &bytes[0]; assert_eq!(byte.value()?, *val as u8); diff --git a/src/convert.rs b/src/convert.rs index e04abc48..c6f6b1e7 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -69,20 +69,24 @@ pub trait ToBytesGadget { /// Outputs a canonical, little-endian, byte decomposition of `self`. /// /// This is the correct default for 99% of use cases. - fn to_bytes(&self) -> Result>, SynthesisError>; + fn to_bytes_le(&self) -> Result>, SynthesisError>; /// Outputs a possibly non-unique byte decomposition of `self`. /// /// If you're not absolutely certain that your usecase can get away with a - /// non-canonical representation, please use `self.to_bytes(cs)` instead. - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - self.to_bytes() + /// non-canonical representation, please use `self.to_bytes_le(cs)` instead. + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + self.to_bytes_le() } } impl<'a, F: Field, T: 'a + ToBytesGadget> ToBytesGadget for &'a T { - fn to_bytes(&self) -> Result>, SynthesisError> { - (*self).to_bytes() + fn to_bytes_le(&self) -> Result>, SynthesisError> { + (*self).to_bytes_le() + } + + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + (*self).to_non_unique_bytes_le() } } diff --git a/src/fields/cubic_extension.rs b/src/fields/cubic_extension.rs index 20c040f4..d0b64a71 100644 --- a/src/fields/cubic_extension.rs +++ b/src/fields/cubic_extension.rs @@ -435,10 +435,10 @@ where P: CubicExtVarConfig, { #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut c0 = self.c0.to_bytes()?; - let mut c1 = self.c1.to_bytes()?; - let mut c2 = self.c2.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut c0 = self.c0.to_bytes_le()?; + let mut c1 = self.c1.to_bytes_le()?; + let mut c2 = self.c2.to_bytes_le()?; c0.append(&mut c1); c0.append(&mut c2); @@ -446,10 +446,10 @@ where } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut c0 = self.c0.to_non_unique_bytes()?; - let mut c1 = self.c1.to_non_unique_bytes()?; - let mut c2 = self.c2.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut c0 = self.c0.to_non_unique_bytes_le()?; + let mut c1 = self.c1.to_non_unique_bytes_le()?; + let mut c2 = self.c2.to_non_unique_bytes_le()?; c0.append(&mut c1); c0.append(&mut c2); diff --git a/src/fields/emulated_fp/allocated_field_var.rs b/src/fields/emulated_fp/allocated_field_var.rs index 92b575fd..095563a7 100644 --- a/src/fields/emulated_fp/allocated_field_var.rs +++ b/src/fields/emulated_fp/allocated_field_var.rs @@ -681,7 +681,7 @@ impl ToBytesGadget for AllocatedEmulatedFpVar { #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> R1CSResult>> { + fn to_bytes_le(&self) -> R1CSResult>> { let mut bits = self.to_bits_le()?; let num_bits = TargetF::BigInt::NUM_LIMBS * 64; diff --git a/src/fields/emulated_fp/field_var.rs b/src/fields/emulated_fp/field_var.rs index 09fcc22b..b8ad9052 100644 --- a/src/fields/emulated_fp/field_var.rs +++ b/src/fields/emulated_fp/field_var.rs @@ -297,23 +297,23 @@ impl ToBytesGadget /// Outputs the unique byte decomposition of `self` in *little-endian* /// form. #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> R1CSResult>> { + fn to_bytes_le(&self) -> R1CSResult>> { match self { Self::Constant(c) => Ok(UInt8::constant_vec( c.into_bigint().to_bytes_le().as_slice(), )), - Self::Var(v) => v.to_bytes(), + Self::Var(v) => v.to_bytes_le(), } } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> R1CSResult>> { + fn to_non_unique_bytes_le(&self) -> R1CSResult>> { match self { Self::Constant(c) => Ok(UInt8::constant_vec( c.into_bigint().to_bytes_le().as_slice(), )), - Self::Var(v) => v.to_non_unique_bytes(), + Self::Var(v) => v.to_non_unique_bytes_le(), } } } diff --git a/src/fields/fp/mod.rs b/src/fields/fp/mod.rs index ae01d9b3..eff7cf67 100644 --- a/src/fields/fp/mod.rs +++ b/src/fields/fp/mod.rs @@ -552,7 +552,7 @@ impl ToBytesGadget for AllocatedFp { /// This method enforces that the decomposition represents /// an integer that is less than `F::MODULUS`. #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { + fn to_bytes_le(&self) -> Result>, SynthesisError> { let num_bits = F::BigInt::NUM_LIMBS * 64; let mut bits = self.to_bits_le()?; let remainder = core::iter::repeat(Boolean::constant(false)).take(num_bits - bits.len()); @@ -565,7 +565,7 @@ impl ToBytesGadget for AllocatedFp { } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { let num_bits = F::BigInt::NUM_LIMBS * 64; let mut bits = self.to_non_unique_bits_le()?; let remainder = core::iter::repeat(Boolean::constant(false)).take(num_bits - bits.len()); @@ -957,22 +957,22 @@ impl ToBytesGadget for FpVar { /// Outputs the unique byte decomposition of `self` in *little-endian* /// form. #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { + fn to_bytes_le(&self) -> Result>, SynthesisError> { match self { Self::Constant(c) => Ok(UInt8::constant_vec( c.into_bigint().to_bytes_le().as_slice(), )), - Self::Var(v) => v.to_bytes(), + Self::Var(v) => v.to_bytes_le(), } } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { match self { Self::Constant(c) => Ok(UInt8::constant_vec( c.into_bigint().to_bytes_le().as_slice(), )), - Self::Var(v) => v.to_non_unique_bytes(), + Self::Var(v) => v.to_non_unique_bytes_le(), } } } diff --git a/src/fields/quadratic_extension.rs b/src/fields/quadratic_extension.rs index da944cfd..a38f47c1 100644 --- a/src/fields/quadratic_extension.rs +++ b/src/fields/quadratic_extension.rs @@ -435,17 +435,17 @@ where P: QuadExtVarConfig, { #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut c0 = self.c0.to_bytes()?; - let mut c1 = self.c1.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut c0 = self.c0.to_bytes_le()?; + let mut c1 = self.c1.to_bytes_le()?; c0.append(&mut c1); Ok(c0) } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut c0 = self.c0.to_non_unique_bytes()?; - let mut c1 = self.c1.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut c0 = self.c0.to_non_unique_bytes_le()?; + let mut c1 = self.c1.to_non_unique_bytes_le()?; c0.append(&mut c1); Ok(c0) } diff --git a/src/groups/curves/short_weierstrass/bls12/mod.rs b/src/groups/curves/short_weierstrass/bls12/mod.rs index 7ac9f9b8..deb6b19a 100644 --- a/src/groups/curves/short_weierstrass/bls12/mod.rs +++ b/src/groups/curves/short_weierstrass/bls12/mod.rs @@ -79,20 +79,20 @@ impl AllocVar, P::Fp> for G1PreparedVar

{ impl ToBytesGadget for G1PreparedVar

{ #[inline] #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut bytes = self.0.x.to_bytes()?; - let y_bytes = self.0.y.to_bytes()?; - let inf_bytes = self.0.infinity.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut bytes = self.0.x.to_bytes_le()?; + let y_bytes = self.0.y.to_bytes_le()?; + let inf_bytes = self.0.infinity.to_bytes_le()?; bytes.extend_from_slice(&y_bytes); bytes.extend_from_slice(&inf_bytes); Ok(bytes) } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut bytes = self.0.x.to_non_unique_bytes()?; - let y_bytes = self.0.y.to_non_unique_bytes()?; - let inf_bytes = self.0.infinity.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut bytes = self.0.x.to_non_unique_bytes_le()?; + let y_bytes = self.0.y.to_non_unique_bytes_le()?; + let inf_bytes = self.0.infinity.to_non_unique_bytes_le()?; bytes.extend_from_slice(&y_bytes); bytes.extend_from_slice(&inf_bytes); Ok(bytes) @@ -174,21 +174,21 @@ impl AllocVar, P::Fp> for G2PreparedVar

{ impl ToBytesGadget for G2PreparedVar

{ #[inline] #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { + fn to_bytes_le(&self) -> Result>, SynthesisError> { let mut bytes = Vec::new(); for coeffs in &self.ell_coeffs { - bytes.extend_from_slice(&coeffs.0.to_bytes()?); - bytes.extend_from_slice(&coeffs.1.to_bytes()?); + bytes.extend_from_slice(&coeffs.0.to_bytes_le()?); + bytes.extend_from_slice(&coeffs.1.to_bytes_le()?); } Ok(bytes) } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { let mut bytes = Vec::new(); for coeffs in &self.ell_coeffs { - bytes.extend_from_slice(&coeffs.0.to_non_unique_bytes()?); - bytes.extend_from_slice(&coeffs.1.to_non_unique_bytes()?); + bytes.extend_from_slice(&coeffs.0.to_non_unique_bytes_le()?); + bytes.extend_from_slice(&coeffs.1.to_non_unique_bytes_le()?); } Ok(bytes) } diff --git a/src/groups/curves/short_weierstrass/mnt4/mod.rs b/src/groups/curves/short_weierstrass/mnt4/mod.rs index 7908852e..3b960c82 100644 --- a/src/groups/curves/short_weierstrass/mnt4/mod.rs +++ b/src/groups/curves/short_weierstrass/mnt4/mod.rs @@ -105,11 +105,11 @@ impl G1PreparedVar

{ impl ToBytesGadget for G1PreparedVar

{ #[inline] #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut x = self.x.to_bytes()?; - let mut y = self.y.to_bytes()?; - let mut x_twist = self.x_twist.to_bytes()?; - let mut y_twist = self.y_twist.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut x = self.x.to_bytes_le()?; + let mut y = self.y.to_bytes_le()?; + let mut x_twist = self.x_twist.to_bytes_le()?; + let mut y_twist = self.y_twist.to_bytes_le()?; x.append(&mut y); x.append(&mut x_twist); @@ -118,11 +118,11 @@ impl ToBytesGadget for G1PreparedVar

{ } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut x = self.x.to_non_unique_bytes()?; - let mut y = self.y.to_non_unique_bytes()?; - let mut x_twist = self.x_twist.to_non_unique_bytes()?; - let mut y_twist = self.y_twist.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut x = self.x.to_non_unique_bytes_le()?; + let mut y = self.y.to_non_unique_bytes_le()?; + let mut x_twist = self.x_twist.to_non_unique_bytes_le()?; + let mut y_twist = self.y_twist.to_non_unique_bytes_le()?; x.append(&mut y); x.append(&mut x_twist); @@ -201,41 +201,41 @@ impl AllocVar, P::Fp> for G2PreparedVar

{ impl ToBytesGadget for G2PreparedVar

{ #[inline] #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut x = self.x.to_bytes()?; - let mut y = self.y.to_bytes()?; - let mut x_over_twist = self.x_over_twist.to_bytes()?; - let mut y_over_twist = self.y_over_twist.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut x = self.x.to_bytes_le()?; + let mut y = self.y.to_bytes_le()?; + let mut x_over_twist = self.x_over_twist.to_bytes_le()?; + let mut y_over_twist = self.y_over_twist.to_bytes_le()?; x.append(&mut y); x.append(&mut x_over_twist); x.append(&mut y_over_twist); for coeff in &self.double_coefficients { - x.extend_from_slice(&coeff.to_bytes()?); + x.extend_from_slice(&coeff.to_bytes_le()?); } for coeff in &self.addition_coefficients { - x.extend_from_slice(&coeff.to_bytes()?); + x.extend_from_slice(&coeff.to_bytes_le()?); } Ok(x) } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut x = self.x.to_non_unique_bytes()?; - let mut y = self.y.to_non_unique_bytes()?; - let mut x_over_twist = self.x_over_twist.to_non_unique_bytes()?; - let mut y_over_twist = self.y_over_twist.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut x = self.x.to_non_unique_bytes_le()?; + let mut y = self.y.to_non_unique_bytes_le()?; + let mut x_over_twist = self.x_over_twist.to_non_unique_bytes_le()?; + let mut y_over_twist = self.y_over_twist.to_non_unique_bytes_le()?; x.append(&mut y); x.append(&mut x_over_twist); x.append(&mut y_over_twist); for coeff in &self.double_coefficients { - x.extend_from_slice(&coeff.to_non_unique_bytes()?); + x.extend_from_slice(&coeff.to_non_unique_bytes_le()?); } for coeff in &self.addition_coefficients { - x.extend_from_slice(&coeff.to_non_unique_bytes()?); + x.extend_from_slice(&coeff.to_non_unique_bytes_le()?); } Ok(x) } @@ -379,11 +379,11 @@ impl AllocVar, P::Fp> for AteDoubleCoeff impl ToBytesGadget for AteDoubleCoefficientsVar

{ #[inline] #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut c_h = self.c_h.to_bytes()?; - let mut c_4c = self.c_4c.to_bytes()?; - let mut c_j = self.c_j.to_bytes()?; - let mut c_l = self.c_l.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut c_h = self.c_h.to_bytes_le()?; + let mut c_4c = self.c_4c.to_bytes_le()?; + let mut c_j = self.c_j.to_bytes_le()?; + let mut c_l = self.c_l.to_bytes_le()?; c_h.append(&mut c_4c); c_h.append(&mut c_j); @@ -392,11 +392,11 @@ impl ToBytesGadget for AteDoubleCoefficientsVar

{ } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut c_h = self.c_h.to_non_unique_bytes()?; - let mut c_4c = self.c_4c.to_non_unique_bytes()?; - let mut c_j = self.c_j.to_non_unique_bytes()?; - let mut c_l = self.c_l.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut c_h = self.c_h.to_non_unique_bytes_le()?; + let mut c_4c = self.c_4c.to_non_unique_bytes_le()?; + let mut c_j = self.c_j.to_non_unique_bytes_le()?; + let mut c_l = self.c_l.to_non_unique_bytes_le()?; c_h.append(&mut c_4c); c_h.append(&mut c_j); @@ -456,18 +456,18 @@ impl AllocVar, P::Fp> for AteAdditionC impl ToBytesGadget for AteAdditionCoefficientsVar

{ #[inline] #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut c_l1 = self.c_l1.to_bytes()?; - let mut c_rz = self.c_rz.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut c_l1 = self.c_l1.to_bytes_le()?; + let mut c_rz = self.c_rz.to_bytes_le()?; c_l1.append(&mut c_rz); Ok(c_l1) } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut c_l1 = self.c_l1.to_non_unique_bytes()?; - let mut c_rz = self.c_rz.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut c_l1 = self.c_l1.to_non_unique_bytes_le()?; + let mut c_rz = self.c_rz.to_non_unique_bytes_le()?; c_l1.append(&mut c_rz); Ok(c_l1) diff --git a/src/groups/curves/short_weierstrass/mnt6/mod.rs b/src/groups/curves/short_weierstrass/mnt6/mod.rs index 9e534298..3fdf923d 100644 --- a/src/groups/curves/short_weierstrass/mnt6/mod.rs +++ b/src/groups/curves/short_weierstrass/mnt6/mod.rs @@ -105,11 +105,11 @@ impl AllocVar, P::Fp> for G1PreparedVar

{ impl ToBytesGadget for G1PreparedVar

{ #[inline] #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut x = self.x.to_bytes()?; - let mut y = self.y.to_bytes()?; - let mut x_twist = self.x_twist.to_bytes()?; - let mut y_twist = self.y_twist.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut x = self.x.to_bytes_le()?; + let mut y = self.y.to_bytes_le()?; + let mut x_twist = self.x_twist.to_bytes_le()?; + let mut y_twist = self.y_twist.to_bytes_le()?; x.append(&mut y); x.append(&mut x_twist); @@ -118,11 +118,11 @@ impl ToBytesGadget for G1PreparedVar

{ } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut x = self.x.to_non_unique_bytes()?; - let mut y = self.y.to_non_unique_bytes()?; - let mut x_twist = self.x_twist.to_non_unique_bytes()?; - let mut y_twist = self.y_twist.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut x = self.x.to_non_unique_bytes_le()?; + let mut y = self.y.to_non_unique_bytes_le()?; + let mut x_twist = self.x_twist.to_non_unique_bytes_le()?; + let mut y_twist = self.y_twist.to_non_unique_bytes_le()?; x.append(&mut y); x.append(&mut x_twist); @@ -201,41 +201,41 @@ impl AllocVar, P::Fp> for G2PreparedVar

{ impl ToBytesGadget for G2PreparedVar

{ #[inline] #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut x = self.x.to_bytes()?; - let mut y = self.y.to_bytes()?; - let mut x_over_twist = self.x_over_twist.to_bytes()?; - let mut y_over_twist = self.y_over_twist.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut x = self.x.to_bytes_le()?; + let mut y = self.y.to_bytes_le()?; + let mut x_over_twist = self.x_over_twist.to_bytes_le()?; + let mut y_over_twist = self.y_over_twist.to_bytes_le()?; x.append(&mut y); x.append(&mut x_over_twist); x.append(&mut y_over_twist); for coeff in self.double_coefficients.iter() { - x.extend_from_slice(&coeff.to_bytes()?); + x.extend_from_slice(&coeff.to_bytes_le()?); } for coeff in self.addition_coefficients.iter() { - x.extend_from_slice(&coeff.to_bytes()?); + x.extend_from_slice(&coeff.to_bytes_le()?); } Ok(x) } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut x = self.x.to_non_unique_bytes()?; - let mut y = self.y.to_non_unique_bytes()?; - let mut x_over_twist = self.x_over_twist.to_non_unique_bytes()?; - let mut y_over_twist = self.y_over_twist.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut x = self.x.to_non_unique_bytes_le()?; + let mut y = self.y.to_non_unique_bytes_le()?; + let mut x_over_twist = self.x_over_twist.to_non_unique_bytes_le()?; + let mut y_over_twist = self.y_over_twist.to_non_unique_bytes_le()?; x.append(&mut y); x.append(&mut x_over_twist); x.append(&mut y_over_twist); for coeff in self.double_coefficients.iter() { - x.extend_from_slice(&coeff.to_non_unique_bytes()?); + x.extend_from_slice(&coeff.to_non_unique_bytes_le()?); } for coeff in self.addition_coefficients.iter() { - x.extend_from_slice(&coeff.to_non_unique_bytes()?); + x.extend_from_slice(&coeff.to_non_unique_bytes_le()?); } Ok(x) } @@ -379,11 +379,11 @@ impl AllocVar, P::Fp> for AteDoubleCoeff impl ToBytesGadget for AteDoubleCoefficientsVar

{ #[inline] #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut c_h = self.c_h.to_bytes()?; - let mut c_4c = self.c_4c.to_bytes()?; - let mut c_j = self.c_j.to_bytes()?; - let mut c_l = self.c_l.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut c_h = self.c_h.to_bytes_le()?; + let mut c_4c = self.c_4c.to_bytes_le()?; + let mut c_j = self.c_j.to_bytes_le()?; + let mut c_l = self.c_l.to_bytes_le()?; c_h.append(&mut c_4c); c_h.append(&mut c_j); @@ -392,11 +392,11 @@ impl ToBytesGadget for AteDoubleCoefficientsVar

{ } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut c_h = self.c_h.to_non_unique_bytes()?; - let mut c_4c = self.c_4c.to_non_unique_bytes()?; - let mut c_j = self.c_j.to_non_unique_bytes()?; - let mut c_l = self.c_l.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut c_h = self.c_h.to_non_unique_bytes_le()?; + let mut c_4c = self.c_4c.to_non_unique_bytes_le()?; + let mut c_j = self.c_j.to_non_unique_bytes_le()?; + let mut c_l = self.c_l.to_non_unique_bytes_le()?; c_h.append(&mut c_4c); c_h.append(&mut c_j); @@ -454,18 +454,18 @@ impl AllocVar, P::Fp> for AteAdditionC impl ToBytesGadget for AteAdditionCoefficientsVar

{ #[inline] #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>, SynthesisError> { - let mut c_l1 = self.c_l1.to_bytes()?; - let mut c_rz = self.c_rz.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let mut c_l1 = self.c_l1.to_bytes_le()?; + let mut c_rz = self.c_rz.to_bytes_le()?; c_l1.append(&mut c_rz); Ok(c_l1) } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let mut c_l1 = self.c_l1.to_non_unique_bytes()?; - let mut c_rz = self.c_rz.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>, SynthesisError> { + let mut c_l1 = self.c_l1.to_non_unique_bytes_le()?; + let mut c_rz = self.c_rz.to_non_unique_bytes_le()?; c_l1.append(&mut c_rz); Ok(c_l1) diff --git a/src/groups/curves/short_weierstrass/mod.rs b/src/groups/curves/short_weierstrass/mod.rs index 82743058..d18f7209 100644 --- a/src/groups/curves/short_weierstrass/mod.rs +++ b/src/groups/curves/short_weierstrass/mod.rs @@ -953,22 +953,22 @@ where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>>, SynthesisError> { + fn to_bytes_le(&self) -> Result>>, SynthesisError> { let g = self.to_affine()?; - let mut bytes = g.x.to_bytes()?; - let y_bytes = g.y.to_bytes()?; - let inf_bytes = g.infinity.to_bytes()?; + let mut bytes = g.x.to_bytes_le()?; + let y_bytes = g.y.to_bytes_le()?; + let inf_bytes = g.infinity.to_bytes_le()?; bytes.extend_from_slice(&y_bytes); bytes.extend_from_slice(&inf_bytes); Ok(bytes) } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>>, SynthesisError> { + fn to_non_unique_bytes_le(&self) -> Result>>, SynthesisError> { let g = self.to_affine()?; - let mut bytes = g.x.to_non_unique_bytes()?; - let y_bytes = g.y.to_non_unique_bytes()?; - let inf_bytes = g.infinity.to_non_unique_bytes()?; + let mut bytes = g.x.to_non_unique_bytes_le()?; + let y_bytes = g.y.to_non_unique_bytes_le()?; + let inf_bytes = g.infinity.to_non_unique_bytes_le()?; bytes.extend_from_slice(&y_bytes); bytes.extend_from_slice(&inf_bytes); Ok(bytes) diff --git a/src/groups/curves/twisted_edwards/mod.rs b/src/groups/curves/twisted_edwards/mod.rs index f88431d9..82095bfd 100644 --- a/src/groups/curves/twisted_edwards/mod.rs +++ b/src/groups/curves/twisted_edwards/mod.rs @@ -920,17 +920,17 @@ where for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { #[tracing::instrument(target = "r1cs")] - fn to_bytes(&self) -> Result>>, SynthesisError> { - let mut x_bytes = self.x.to_bytes()?; - let y_bytes = self.y.to_bytes()?; + fn to_bytes_le(&self) -> Result>>, SynthesisError> { + let mut x_bytes = self.x.to_bytes_le()?; + let y_bytes = self.y.to_bytes_le()?; x_bytes.extend_from_slice(&y_bytes); Ok(x_bytes) } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes(&self) -> Result>>, SynthesisError> { - let mut x_bytes = self.x.to_non_unique_bytes()?; - let y_bytes = self.y.to_non_unique_bytes()?; + fn to_non_unique_bytes_le(&self) -> Result>>, SynthesisError> { + let mut x_bytes = self.x.to_non_unique_bytes_le()?; + let y_bytes = self.y.to_non_unique_bytes_le()?; x_bytes.extend_from_slice(&y_bytes); Ok(x_bytes) diff --git a/src/uint/convert.rs b/src/uint/convert.rs index 45ceb3e5..51522e77 100644 --- a/src/uint/convert.rs +++ b/src/uint/convert.rs @@ -97,7 +97,7 @@ impl ToBytesGadget for UInt { #[tracing::instrument(target = "r1cs", skip(self))] - fn to_bytes(&self) -> Result>, SynthesisError> { + fn to_bytes_le(&self) -> Result>, SynthesisError> { Ok(self .to_bits_le()? .chunks(8) @@ -107,23 +107,23 @@ impl ToBytesGadget } impl ToBytesGadget for [UInt] { - fn to_bytes(&self) -> Result>, SynthesisError> { + fn to_bytes_le(&self) -> Result>, SynthesisError> { let mut bytes = Vec::with_capacity(self.len() * (N / 8)); for elem in self { - bytes.extend_from_slice(&elem.to_bytes()?); + bytes.extend_from_slice(&elem.to_bytes_le()?); } Ok(bytes) } } impl ToBytesGadget for Vec> { - fn to_bytes(&self) -> Result>, SynthesisError> { - self.as_slice().to_bytes() + fn to_bytes_le(&self) -> Result>, SynthesisError> { + self.as_slice().to_bytes_le() } } impl<'a, const N: usize, T: PrimUInt, F: Field> ToBytesGadget for &'a [UInt] { - fn to_bytes(&self) -> Result>, SynthesisError> { - (*self).to_bytes() + fn to_bytes_le(&self) -> Result>, SynthesisError> { + (*self).to_bytes_le() } } From 439d55c7caf2a41ebea092217da7af65508febc0 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 3 Jan 2024 15:01:06 -0500 Subject: [PATCH 6/8] Fix rotate doc-test --- src/uint/rotate.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/uint/rotate.rs b/src/uint/rotate.rs index 6f2a7698..62cd39f3 100644 --- a/src/uint/rotate.rs +++ b/src/uint/rotate.rs @@ -37,7 +37,7 @@ impl UInt { /// use ark_r1cs_std::prelude::*; /// /// let cs = ConstraintSystem::::new_ref(); - /// let a = UInt32::new_witness(cs.clone(), || Ok(0xb301u32))?; + /// let mut a = UInt32::new_witness(cs.clone(), || Ok(0xb301u32))?; /// let b = UInt32::new_witness(cs.clone(), || Ok(0x10000b3))?; /// /// a.rotate_right_in_place(8); @@ -46,7 +46,6 @@ impl UInt { /// # Ok(()) /// # } /// ``` - #[tracing::instrument(target = "r1cs", skip(self))] pub fn rotate_right_in_place(&mut self, by: usize) { let by = by % N; @@ -92,7 +91,7 @@ impl UInt { /// use ark_r1cs_std::prelude::*; /// /// let cs = ConstraintSystem::::new_ref(); - /// let a = UInt32::new_witness(cs.clone(), || Ok(0x10000b3))?; + /// let mut a = UInt32::new_witness(cs.clone(), || Ok(0x10000b3))?; /// let b = UInt32::new_witness(cs.clone(), || Ok(0xb301u32))?; /// /// a.rotate_left_in_place(8); From 24217f2e29a6b83334d5ea67915f67b31580c1de Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 3 Jan 2024 15:49:16 -0500 Subject: [PATCH 7/8] Add big-endian conversions for `UInt` --- CHANGELOG.md | 12 +++ src/uint/convert.rs | 257 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 269 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2397f878..82ac112a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,14 +4,26 @@ ### Breaking changes +- [\#121](https://github.com/arkworks-rs/r1cs-std/pull/121) + - Refactor `UInt{8,16,64,128}` into one struct `UInt`. + - Remove `bits` module. + - Use `std::ops` traits for `UInt` and `Boolean`. - [\#134](https://github.com/arkworks-rs/r1cs-std/pull/134) Add `Mul` bounds and impls for `CurveVar`. - [\#135](https://github.com/arkworks-rs/r1cs-std/pull/135) - Rename `NonNativeFieldVar` to `EmulatedFpVar`. - Rename `fields::nonnative` to `fields::emulated_fp`. - Rename `fields::nonnative::{Allocated}NonNativeMulResultVar` to `fields::emulated_fp::{Allocated}MulResultVar`. +- [\#136](https://github.com/arkworks-rs/r1cs-std/pull/136) + - Rename `ToBytesGadget::to_{non_unique_}bytes` → `ToBytesGadget::to_{non_unique_}bytes_in_le`. ### Features +- [\#136](https://github.com/arkworks-rs/r1cs-std/pull/136) + - Add `{BitAnd,BitOr,BitXor,BitAndAssign,BitOrAssign,BitXorAssign} for UInt`. + - Add `UInt::rotate_{left,right}_in_place`. + - Add `{Boolean,UInt}::not_in_place`. + - Add `UInt::{from_bytes_le, from_bytes_be, to_bytes_be}`. + ### Improvements ### Bug Fixes diff --git a/src/uint/convert.rs b/src/uint/convert.rs index 51522e77..da99196b 100644 --- a/src/uint/convert.rs +++ b/src/uint/convert.rs @@ -72,6 +72,77 @@ impl UInt { let value = value_exists.then_some(value); Self { bits, value } } + + /// Converts a big-endian list of bytes into a `UInt`. + /// + /// ``` + /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> { + /// // We'll use the BLS12-381 scalar field for our constraints. + /// use ark_test_curves::bls12_381::Fr; + /// use ark_relations::r1cs::*; + /// use ark_r1cs_std::prelude::*; + /// + /// let cs = ConstraintSystem::::new_ref(); + /// let var = UInt16::new_witness(cs.clone(), || Ok(2 * (u8::MAX as u16)))?; + /// + /// let f = Boolean::FALSE; + /// let t = Boolean::TRUE; + /// + /// // Construct u8::MAX * 2 + /// let bytes = UInt16::constant_vec(&(2 * (u8::MAX as u16)).to_be_bytes()); + /// + /// let c = UInt16::from_bytes_be(&bits); + /// var.enforce_equal(&c)?; + /// assert!(cs.is_satisfied().unwrap()); + /// # Ok(()) + /// # } + /// ``` + pub fn from_bytes_be(bytes: &[UInt8]) -> Result { + let bits = bytes + .iter() + .rev() + .flat_map(|b| b.to_bits_le().unwrap()) + .collect::>(); + Ok(Self::from_bits_le(&bits)) + } + + /// Converts a little-endian byte order list of bytes into a `UInt`. + /// + /// ``` + /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> { + /// // We'll use the BLS12-381 scalar field for our constraints. + /// use ark_test_curves::bls12_381::Fr; + /// use ark_relations::r1cs::*; + /// use ark_r1cs_std::prelude::*; + /// + /// let cs = ConstraintSystem::::new_ref(); + /// let var = UInt16::new_witness(cs.clone(), || Ok(2 * (u8::MAX as u16)))?; + /// + /// let f = Boolean::FALSE; + /// let t = Boolean::TRUE; + /// + /// // Construct u8::MAX * 2 + /// let bytes = UInt16::constant_vec(&(2 * (u8::MAX as u16)).to_le_bytes()); + /// + /// let c = UInt16::from_bytes_le(&bits); + /// var.enforce_equal(&c)?; + /// assert!(cs.is_satisfied().unwrap()); + /// # Ok(()) + /// # } + /// ``` + pub fn from_bytes_le(bytes: &[UInt8]) -> Result { + let bits = bytes + .iter() + .flat_map(|b| b.to_bits_le().unwrap()) + .collect::>(); + Ok(Self::from_bits_le(&bits)) + } + + pub fn to_bytes_be(&self) -> Result>, SynthesisError> { + let mut bytes = self.to_bytes_le()?; + bytes.reverse(); + Ok(bytes) + } } impl ToBitsGadget for UInt { @@ -127,3 +198,189 @@ impl<'a, const N: usize, T: PrimUInt, F: Field> ToBytesGadget for &'a [UInt( + a: UInt, + ) -> Result<(), SynthesisError> { + let cs = a.cs(); + let computed = a.to_bytes_le()?; + let expected = UInt8::constant_vec(a.value()?.to_le_bytes().as_ref()); + assert_eq!(expected.len(), computed.len()); + assert_eq!(expected.value(), computed.value()); + expected.enforce_equal(&computed)?; + if !a.is_constant() { + assert!(cs.is_satisfied().unwrap()); + } + Ok(()) + } + + fn uint_to_bytes_be( + a: UInt, + ) -> Result<(), SynthesisError> { + let cs = a.cs(); + let computed = a.to_bytes_be()?; + let expected = UInt8::constant_vec(a.value()?.to_be_bytes().as_ref()); + assert_eq!(expected.len(), computed.len()); + assert_eq!(expected.value(), computed.value()); + expected.enforce_equal(&computed)?; + if !a.is_constant() { + assert!(cs.is_satisfied().unwrap()); + } + Ok(()) + } + + fn uint_from_bytes_le( + expected: UInt, + ) -> Result<(), SynthesisError> { + let cs = expected.cs(); + let mode = if expected.is_constant() { + AllocationMode::Constant + } else { + AllocationMode::Witness + }; + let computed = { + let value = expected.value()?.to_le_bytes(); + let a = Vec::>::new_variable(cs.clone(), || Ok(value.as_ref()), mode)?; + UInt::from_bytes_le(&a)? + }; + assert_eq!(expected.value(), computed.value()); + expected.enforce_equal(&computed)?; + if !expected.is_constant() { + assert!(cs.is_satisfied().unwrap()); + } + Ok(()) + } + + fn uint_from_bytes_be( + expected: UInt, + ) -> Result<(), SynthesisError> { + let cs = expected.cs(); + let mode = if expected.is_constant() { + AllocationMode::Constant + } else { + AllocationMode::Witness + }; + let computed = { + let value = expected.value()?.to_be_bytes(); + let a = Vec::>::new_variable(cs.clone(), || Ok(value.as_ref()), mode)?; + UInt::from_bytes_be(&a)? + }; + assert_eq!(expected.value(), computed.value()); + expected.enforce_equal(&computed)?; + if !expected.is_constant() { + assert!(cs.is_satisfied().unwrap()); + } + Ok(()) + } + + #[test] + fn u8_to_bytes_le() { + run_unary_exhaustive(uint_to_bytes_le::).unwrap() + } + + #[test] + fn u16_to_bytes_le() { + run_unary_random::<1000, 16, _, _>(uint_to_bytes_le::).unwrap() + } + + #[test] + fn u32_to_bytes_le() { + run_unary_random::<1000, 32, _, _>(uint_to_bytes_le::).unwrap() + } + + #[test] + fn u64_to_bytes_le() { + run_unary_random::<1000, 64, _, _>(uint_to_bytes_le::).unwrap() + } + + #[test] + fn u128_to_bytes_le() { + run_unary_random::<1000, 128, _, _>(uint_to_bytes_le::).unwrap() + } + + #[test] + fn u8_to_bytes_be() { + run_unary_exhaustive(uint_to_bytes_be::).unwrap() + } + + #[test] + fn u16_to_bytes_be() { + run_unary_random::<1000, 16, _, _>(uint_to_bytes_be::).unwrap() + } + + #[test] + fn u32_to_bytes_be() { + run_unary_random::<1000, 32, _, _>(uint_to_bytes_be::).unwrap() + } + + #[test] + fn u64_to_bytes_be() { + run_unary_random::<1000, 64, _, _>(uint_to_bytes_be::).unwrap() + } + + #[test] + fn u128_to_bytes_be() { + run_unary_random::<1000, 128, _, _>(uint_to_bytes_be::).unwrap() + } + + #[test] + fn u8_from_bytes_le() { + run_unary_exhaustive(uint_from_bytes_le::).unwrap() + } + + #[test] + fn u16_from_bytes_le() { + run_unary_random::<1000, 16, _, _>(uint_from_bytes_le::).unwrap() + } + + #[test] + fn u32_from_bytes_le() { + run_unary_random::<1000, 32, _, _>(uint_from_bytes_le::).unwrap() + } + + #[test] + fn u64_from_bytes_le() { + run_unary_random::<1000, 64, _, _>(uint_from_bytes_le::).unwrap() + } + + #[test] + fn u128_from_bytes_le() { + run_unary_random::<1000, 128, _, _>(uint_from_bytes_le::).unwrap() + } + + #[test] + fn u8_from_bytes_be() { + run_unary_exhaustive(uint_from_bytes_be::).unwrap() + } + + #[test] + fn u16_from_bytes_be() { + run_unary_random::<1000, 16, _, _>(uint_from_bytes_be::).unwrap() + } + + #[test] + fn u32_from_bytes_be() { + run_unary_random::<1000, 32, _, _>(uint_from_bytes_be::).unwrap() + } + + #[test] + fn u64_from_bytes_be() { + run_unary_random::<1000, 64, _, _>(uint_from_bytes_be::).unwrap() + } + + #[test] + fn u128_from_bytes_be() { + run_unary_random::<1000, 128, _, _>(uint_from_bytes_be::).unwrap() + } +} From 55d8215e9d7226617d0c79f616e416c235e988c2 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 3 Jan 2024 16:58:14 -0500 Subject: [PATCH 8/8] Fix doc-tests --- src/uint/convert.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/uint/convert.rs b/src/uint/convert.rs index da99196b..e4411019 100644 --- a/src/uint/convert.rs +++ b/src/uint/convert.rs @@ -85,13 +85,10 @@ impl UInt { /// let cs = ConstraintSystem::::new_ref(); /// let var = UInt16::new_witness(cs.clone(), || Ok(2 * (u8::MAX as u16)))?; /// - /// let f = Boolean::FALSE; - /// let t = Boolean::TRUE; - /// /// // Construct u8::MAX * 2 - /// let bytes = UInt16::constant_vec(&(2 * (u8::MAX as u16)).to_be_bytes()); + /// let bytes = UInt8::constant_vec(&(2 * (u8::MAX as u16)).to_be_bytes()); /// - /// let c = UInt16::from_bytes_be(&bits); + /// let c = UInt16::from_bytes_be(&bytes)?; /// var.enforce_equal(&c)?; /// assert!(cs.is_satisfied().unwrap()); /// # Ok(()) @@ -118,13 +115,10 @@ impl UInt { /// let cs = ConstraintSystem::::new_ref(); /// let var = UInt16::new_witness(cs.clone(), || Ok(2 * (u8::MAX as u16)))?; /// - /// let f = Boolean::FALSE; - /// let t = Boolean::TRUE; - /// /// // Construct u8::MAX * 2 - /// let bytes = UInt16::constant_vec(&(2 * (u8::MAX as u16)).to_le_bytes()); + /// let bytes = UInt8::constant_vec(&(2 * (u8::MAX as u16)).to_le_bytes()); /// - /// let c = UInt16::from_bytes_le(&bits); + /// let c = UInt16::from_bytes_le(&bytes)?; /// var.enforce_equal(&c)?; /// assert!(cs.is_satisfied().unwrap()); /// # Ok(())