From 9a834bd0cdd6d72b9a72e55f207b4156c3233698 Mon Sep 17 00:00:00 2001 From: Tal Derei Date: Sun, 17 Nov 2024 13:29:25 +0700 Subject: [PATCH 1/8] bump arkworks deps to v0.5 --- Cargo.toml | 20 ++--- src/ark_curve/bls12_377.rs | 4 +- src/ark_curve/element.rs | 60 +++++++++----- src/ark_curve/element/projective.rs | 16 ++-- src/ark_curve/on_curve.rs | 4 +- src/ark_curve/ops/affine.rs | 44 ++++++++-- src/ark_curve/ops/projective.rs | 57 ++++++++++++- src/fields/fp/arkworks.rs | 124 ++++++++++++++++++++++------ src/fields/fp/ops.rs | 30 +++++++ src/fields/fq/arkworks.rs | 54 +++++++----- src/fields/fq/ops.rs | 30 +++++++ src/fields/fr/arkworks.rs | 65 +++++++++------ src/fields/fr/ops.rs | 30 +++++++ 13 files changed, 418 insertions(+), 120 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6897e12..301da77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,16 +22,16 @@ zeroize = { version = "1.7", default-features = false } num-bigint = { version = "0.4.4", optional = true, default-features = false } # std hashbrown = { version = "0.14.3", optional = true } -ark-relations = { version = "0.4", optional = true } -ark-r1cs-std = { version = "0.4", optional = true } -ark-std = { version = "0.4", optional = true } -ark-ec = { version = "0.4", optional = true } -ark-ff = { version = "0.4", optional = true } -ark-serialize = { version = "0.4", optional = true } -ark-bls12-377 = { version = "0.4", optional = true } -ark-ed-on-bls12-377 = { version = "0.4", optional = true } -ark-groth16 = { version = "0.4", optional = true } -ark-snark = { version = "0.4", optional = true } +ark-relations = { version = "0.5", optional = true } +ark-r1cs-std = { version = "0.5", optional = true } +ark-std = { version = "0.5", optional = true } +ark-ec = { version = "0.5", optional = true } +ark-ff = { version = "0.5", optional = true } +ark-serialize = { version = "0.5", optional = true } +ark-bls12-377 = { version = "0.5", optional = true } +ark-ed-on-bls12-377 = { version = "0.5", optional = true } +ark-groth16 = { version = "0.5", optional = true } +ark-snark = { version = "0.5", optional = true } once_cell = { version = "1.8", optional = true, default-features = false } # This matches what ark-std (a library for no_std compatibility) does, having diff --git a/src/ark_curve/bls12_377.rs b/src/ark_curve/bls12_377.rs index 69f48df..8a201e2 100644 --- a/src/ark_curve/bls12_377.rs +++ b/src/ark_curve/bls12_377.rs @@ -5,7 +5,9 @@ use ark_ec::{ models::CurveConfig, short_weierstrass::Affine, }; -use ark_ff::{fields::models::fp2::Fp2Config, Field, Fp12Config, Fp2, Fp6, Fp6Config}; +use ark_ff::{ + fields::models::fp2::Fp2Config, AdditiveGroup, Field, Fp12Config, Fp2, Fp6, Fp6Config, +}; pub struct F2Config; diff --git a/src/ark_curve/element.rs b/src/ark_curve/element.rs index 79a1366..a449b9c 100644 --- a/src/ark_curve/element.rs +++ b/src/ark_curve/element.rs @@ -1,6 +1,8 @@ -use ark_ec::{AffineRepr, CurveGroup, Group, ScalarMul, VariableBaseMSM}; +use ark_ec::{AffineRepr, CurveGroup, PrimeGroup, ScalarMul, VariableBaseMSM}; +use ark_ff::AdditiveGroup; use ark_serialize::Valid; use ark_std::vec::Vec; +use core::ops::AddAssign; use crate::{ ark_curve::{edwards::EdwardsAffine, Decaf377EdwardsConfig, EdwardsProjective}, @@ -36,25 +38,6 @@ impl ScalarMul for Element { impl VariableBaseMSM for Element {} -impl Group for Element { - type ScalarField = Fr; - - fn double_in_place(&mut self) -> &mut Self { - let inner = *self.inner.double_in_place(); - *self = Element { inner }; - self - } - - fn generator() -> Self { - Self::GENERATOR - } - - fn mul_bigint(&self, other: impl AsRef<[u64]>) -> Self { - let inner = self.inner.mul_bigint(other); - Element { inner } - } -} - impl CurveGroup for Element { // We implement `CurveGroup` as it is required by the `CurveVar` // trait used in the R1CS feature. The `ProjectiveCurve` trait requires @@ -100,7 +83,7 @@ impl AffineRepr for AffinePoint { type Group = Element; - fn xy(&self) -> Option<(&Self::BaseField, &Self::BaseField)> { + fn xy(&self) -> Option<(Self::BaseField, Self::BaseField)> { self.inner.xy() } @@ -165,3 +148,38 @@ impl From<&AffinePoint> for Element { } } } + +impl PrimeGroup for Element { + type ScalarField = Fr; + + fn generator() -> Self { + Self::GENERATOR + } + + fn mul_bigint(&self, other: impl AsRef<[u64]>) -> Self { + let inner = self.inner.mul_bigint(other); + Element { inner } + } +} + +impl AdditiveGroup for Element { + type Scalar = Fr; + + const ZERO: Self = Self::ZERO; + + fn double(&self) -> Self { + let mut copy = *self; + copy.double_in_place(); + copy + } + + fn double_in_place(&mut self) -> &mut Self { + self.add_assign(*self); + self + } + + fn neg_in_place(&mut self) -> &mut Self { + *self = -(*self); + self + } +} diff --git a/src/ark_curve/element/projective.rs b/src/ark_curve/element/projective.rs index de75f83..0ae5da0 100644 --- a/src/ark_curve/element/projective.rs +++ b/src/ark_curve/element/projective.rs @@ -1,15 +1,11 @@ -use core::borrow::Borrow; -use core::hash::Hash; - +use super::super::constants::{B_T, B_X, B_Y, B_Z}; +use crate::{ark_curve::EdwardsProjective, Fq, Fr}; use ark_ff::Zero; use ark_std::fmt::{Display, Formatter, Result as FmtResult}; - +use core::borrow::Borrow; +use core::hash::Hash; use zeroize::Zeroize; -use crate::{ark_curve::EdwardsProjective, Fq, Fr}; - -use super::super::constants::{B_T, B_X, B_Y, B_Z}; - #[derive(Copy, Clone)] pub struct Element { pub(crate) inner: EdwardsProjective, @@ -24,6 +20,10 @@ impl Element { pub const IDENTITY: Self = Self { inner: EdwardsProjective::new_unchecked(Fq::ZERO, Fq::ONE, Fq::ZERO, Fq::ONE), }; + + pub const ZERO: Self = Self { + inner: EdwardsProjective::new_unchecked(Fq::ZERO, Fq::ZERO, Fq::ZERO, Fq::ZERO), + }; } impl Hash for Element { diff --git a/src/ark_curve/on_curve.rs b/src/ark_curve/on_curve.rs index 5506786..ab2a139 100644 --- a/src/ark_curve/on_curve.rs +++ b/src/ark_curve/on_curve.rs @@ -1,6 +1,6 @@ use ark_ec::{ - models::{twisted_edwards::Projective, twisted_edwards::TECurveConfig}, - Group, + models::twisted_edwards::{Projective, TECurveConfig}, + PrimeGroup, }; use ark_ff::{BigInteger, Field, PrimeField, Zero}; use ark_serialize::CanonicalSerialize; diff --git a/src/ark_curve/ops/affine.rs b/src/ark_curve/ops/affine.rs index 2568170..a72766c 100644 --- a/src/ark_curve/ops/affine.rs +++ b/src/ark_curve/ops/affine.rs @@ -56,10 +56,10 @@ impl<'a, 'b> Sub<&'b AffinePoint> for &'a AffinePoint { } impl<'b> Sub<&'b AffinePoint> for AffinePoint { - type Output = AffinePoint; + type Output = Element; - fn sub(self, other: &'b AffinePoint) -> AffinePoint { - &self - other + fn sub(self, other: &'b AffinePoint) -> Element { + (&self - other).into() } } @@ -72,9 +72,43 @@ impl<'a> Sub for &'a AffinePoint { } impl Sub for AffinePoint { - type Output = AffinePoint; + type Output = Element; - fn sub(self, other: AffinePoint) -> AffinePoint { + fn sub(self, other: AffinePoint) -> Element { + (&self - &other).into() + } +} + +impl<'a, 'b> Sub<&'b Element> for &'a AffinePoint { + type Output = Element; + + fn sub(self, other: &'b Element) -> Element { + Element { + inner: self.inner - other.inner, + } + } +} + +impl<'b> Sub<&'b Element> for AffinePoint { + type Output = Element; + + fn sub(self, other: &'b Element) -> Element { + &self - other + } +} + +impl<'a> Sub for &'a AffinePoint { + type Output = Element; + + fn sub(self, other: Element) -> Element { + self - &other + } +} + +impl Sub for AffinePoint { + type Output = Element; + + fn sub(self, other: Element) -> Element { &self - &other } } diff --git a/src/ark_curve/ops/projective.rs b/src/ark_curve/ops/projective.rs index da530bc..09f90a0 100644 --- a/src/ark_curve/ops/projective.rs +++ b/src/ark_curve/ops/projective.rs @@ -1,6 +1,5 @@ -use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; - use crate::{ark_curve::element::projective::Element, ark_curve::AffinePoint, Fr}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; impl<'a, 'b> Add<&'b Element> for &'a Element { type Output = Element; @@ -274,3 +273,57 @@ impl Sub for Element { &self - &other.into() } } + +impl<'a> Add<&'a mut Element> for Element { + type Output = Element; + + fn add(self, other: &'a mut Self) -> Element { + Element { + inner: self.inner + other.inner, + } + } +} + +impl<'a> Sub<&'a mut Element> for Element { + type Output = Element; + + fn sub(self, other: &'a mut Element) -> Element { + Element { + inner: self.inner - other.inner, + } + } +} + +impl<'a> AddAssign<&'a mut Element> for Element { + fn add_assign(&mut self, other: &'a mut Element) { + *self = Element { + inner: self.inner + other.inner, + } + } +} + +impl<'a> SubAssign<&'a mut Element> for Element { + fn sub_assign(&mut self, other: &'a mut Element) { + *self = Element { + inner: self.inner - other.inner, + } + } +} + +impl<'a> Mul<&'a mut Fr> for Element { + type Output = Element; + + fn mul(self, point: &'a mut Fr) -> Self::Output { + let mut p = self.inner; + p *= *point; + Element { inner: p } + } +} + +impl<'a> MulAssign<&'a mut Fr> for Element { + fn mul_assign(&mut self, point: &'a mut Fr) { + let mut p = self.inner; + p *= *point; + *self = Element { inner: p } + } +} diff --git a/src/fields/fp/arkworks.rs b/src/fields/fp/arkworks.rs index 2596019..0d4bb6e 100644 --- a/src/fields/fp/arkworks.rs +++ b/src/fields/fp/arkworks.rs @@ -1,12 +1,15 @@ use super::Fp; -use ark_ff::{BigInt, Field, PrimeField, SqrtPrecomputation}; +use ark_ff::{AdditiveGroup, BigInt, Field, PrimeField, SqrtPrecomputation}; use ark_ff::{BigInteger, FftField}; use ark_serialize::{ CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, - CanonicalSerializeWithFlags, Compress, EmptyFlags, Flags, SerializationError, Valid, Validate, + CanonicalSerializeWithFlags, Compress, EmptyFlags, Flags, Read, SerializationError, Valid, + Validate, Write, }; +use ark_std::vec::Vec; use ark_std::{rand, str::FromStr, string::ToString, One, Zero}; use core::convert::TryInto; +use core::ops::AddAssign; use core::{ fmt::{Display, Formatter}, iter, @@ -58,7 +61,6 @@ impl PrimeField for Fp { impl Field for Fp { type BasePrimeField = Self; - type BasePrimeFieldIter = iter::Once; const SQRT_PRECOMP: Option> = Some(SqrtPrecomputation::TonelliShanks { @@ -67,8 +69,6 @@ impl Field for Fp { trace_of_modulus_minus_one_div_two: &Self::TRACE_MINUS_ONE_DIV_TWO_LIMBS, }); - const ZERO: Self = Self::ZERO; - // Montomgery representation of one const ONE: Self = Self::ONE; @@ -76,11 +76,14 @@ impl Field for Fp { 1 } - fn to_base_prime_field_elements(&self) -> Self::BasePrimeFieldIter { + fn to_base_prime_field_elements(&self) -> impl Iterator { iter::once(*self) } - fn from_base_prime_field_elems(elems: &[Self::BasePrimeField]) -> Option { + fn from_base_prime_field_elems( + elems: impl IntoIterator, + ) -> Option { + let elems: Vec<_> = elems.into_iter().collect(); if elems.len() != (Self::extension_degree() as usize) { return None; } @@ -91,21 +94,7 @@ impl Field for Fp { elem } - fn double(&self) -> Self { - self.add(self) - } - - fn double_in_place(&mut self) -> &mut Self { - *self = self.add(self); - self - } - - fn neg_in_place(&mut self) -> &mut Self { - *self = Self::ZERO.sub(self); - self - } - - fn from_random_bytes_with_flags(bytes: &[u8]) -> Option<(Self, F)> { + fn from_random_bytes_with_flags(bytes: &[u8]) -> Option<(Self, F)> { Some((Self::from_le_bytes_mod_order(bytes), F::default())) } @@ -151,6 +140,65 @@ impl Field for Fp { fn characteristic() -> &'static [u64] { &Self::MODULUS_LIMBS } + + fn from_random_bytes(bytes: &[u8]) -> Option { + Self::from_random_bytes_with_flags::(bytes).map(|f| f.0) + } + + fn sqrt(&self) -> Option { + match Self::SQRT_PRECOMP { + Some(tv) => tv.sqrt(self), + None => core::unimplemented!(), + } + } + + fn sqrt_in_place(&mut self) -> Option<&mut Self> { + (*self).sqrt().map(|sqrt| { + *self = sqrt; + self + }) + } + + fn sum_of_products(a: &[Self; T], b: &[Self; T]) -> Self { + let mut sum = Self::zero(); + for i in 0..a.len() { + sum += a[i] * b[i]; + } + sum + } + + fn frobenius_map(&self, power: usize) -> Self { + let mut this = *self; + this.frobenius_map_in_place(power); + this + } + + fn pow>(&self, exp: S) -> Self { + let mut res = Self::one(); + + for i in ark_ff::BitIteratorBE::without_leading_zeros(exp) { + res.square_in_place(); + + if i { + res *= self; + } + } + res + } + + fn pow_with_table>(powers_of_2: &[Self], exp: S) -> Option { + let mut res = Self::one(); + for (pow, bit) in ark_ff::BitIteratorLE::without_trailing_zeros(exp).enumerate() { + if bit { + res *= powers_of_2.get(pow)?; + } + } + Some(res) + } + + fn mul_by_base_prime_field(&self, _elem: &Self::BasePrimeField) -> Self { + unimplemented!() + } } impl FftField for Fp { @@ -162,6 +210,28 @@ impl FftField for Fp { const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; } +impl AdditiveGroup for Fp { + type Scalar = Self; + + const ZERO: Self = Self::ZERO; + + fn double(&self) -> Self { + let mut copy = *self; + copy.double_in_place(); + copy + } + + fn double_in_place(&mut self) -> &mut Self { + self.add_assign(*self); + self + } + + fn neg_in_place(&mut self) -> &mut Self { + *self = -(*self); + self + } +} + impl Zero for Fp { #[inline] fn zero() -> Self { @@ -187,7 +257,7 @@ impl One for Fp { } impl CanonicalDeserializeWithFlags for Fp { - fn deserialize_with_flags( + fn deserialize_with_flags( mut reader: R, ) -> Result<(Self, F), SerializationError> { // Enough for the field element + 8 bits of flags. The last byte may or may not contain flags. @@ -214,7 +284,7 @@ impl Valid for Fp { } impl CanonicalDeserialize for Fp { - fn deserialize_with_mode( + fn deserialize_with_mode( reader: R, _compress: Compress, validate: Validate, @@ -230,7 +300,7 @@ impl CanonicalDeserialize for Fp { impl CanonicalSerialize for Fp { #[inline] - fn serialize_with_mode( + fn serialize_with_mode( &self, writer: W, _compress: Compress, @@ -245,7 +315,8 @@ impl CanonicalSerialize for Fp { } impl CanonicalSerializeWithFlags for Fp { - fn serialize_with_flags( + #[inline] + fn serialize_with_flags( &self, mut writer: W, flags: F, @@ -270,6 +341,7 @@ impl CanonicalSerializeWithFlags for Fp { Ok(()) } + #[inline] fn serialized_size_with_flags(&self) -> usize { (Self::MODULUS_BIT_SIZE as usize + F::BIT_SIZE + 7) / 8 } diff --git a/src/fields/fp/ops.rs b/src/fields/fp/ops.rs index 37a2492..0da5d4d 100644 --- a/src/fields/fp/ops.rs +++ b/src/fields/fp/ops.rs @@ -43,6 +43,36 @@ impl From for Fp { } } +impl From for Fp { + fn from(other: i8) -> Self { + i128::from(other).into() + } +} + +impl From for Fp { + fn from(other: i16) -> Self { + i128::from(other).into() + } +} + +impl From for Fp { + fn from(other: i32) -> Self { + i128::from(other).into() + } +} + +impl From for Fp { + fn from(other: i64) -> Self { + i128::from(other).into() + } +} + +impl From for Fp { + fn from(other: i128) -> Self { + i128::from(other).into() + } +} + impl Neg for Fp { type Output = Self; diff --git a/src/fields/fq/arkworks.rs b/src/fields/fq/arkworks.rs index 51fbb41..3e2121c 100644 --- a/src/fields/fq/arkworks.rs +++ b/src/fields/fq/arkworks.rs @@ -1,13 +1,15 @@ use super::Fq; -use ark_ff::{BigInt, Field, PrimeField, SqrtPrecomputation}; +use ark_ff::{AdditiveGroup, BigInt, Field, PrimeField, SqrtPrecomputation}; use ark_ff::{BigInteger, FftField}; use ark_serialize::{ CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, CanonicalSerializeWithFlags, Compress, EmptyFlags, Flags, SerializationError, Valid, Validate, }; use ark_std::iterable::Iterable; +use ark_std::vec::Vec; use ark_std::{rand, str::FromStr, string::ToString, One, Zero}; use core::convert::TryInto; +use core::ops::AddAssign; use core::{ fmt::{Display, Formatter}, iter, @@ -59,7 +61,6 @@ impl PrimeField for Fq { impl Field for Fq { type BasePrimeField = Self; - type BasePrimeFieldIter = iter::Once; const SQRT_PRECOMP: Option> = Some(SqrtPrecomputation::TonelliShanks { @@ -68,8 +69,6 @@ impl Field for Fq { trace_of_modulus_minus_one_div_two: &Self::TRACE_MINUS_ONE_DIV_TWO_LIMBS, }); - const ZERO: Self = Self::ZERO; - // Montomgery representation of one const ONE: Self = Self::ONE; @@ -77,11 +76,14 @@ impl Field for Fq { 1 } - fn to_base_prime_field_elements(&self) -> Self::BasePrimeFieldIter { + fn to_base_prime_field_elements(&self) -> impl Iterator { iter::once(*self) } - fn from_base_prime_field_elems(elems: &[Self::BasePrimeField]) -> Option { + fn from_base_prime_field_elems( + elems: impl IntoIterator, + ) -> Option { + let elems: Vec<_> = elems.into_iter().collect(); if elems.len() != (Self::extension_degree() as usize) { return None; } @@ -92,20 +94,6 @@ impl Field for Fq { elem } - fn double(&self) -> Self { - self.add(self) - } - - fn double_in_place(&mut self) -> &mut Self { - *self = self.add(self); - self - } - - fn neg_in_place(&mut self) -> &mut Self { - *self = Self::ZERO.sub(self); - self - } - fn from_random_bytes_with_flags(bytes: &[u8]) -> Option<(Self, F)> { Some((Self::from_le_bytes_mod_order(bytes), F::default())) } @@ -152,6 +140,10 @@ impl Field for Fq { fn characteristic() -> &'static [u64] { &Self::MODULUS_LIMBS } + + fn mul_by_base_prime_field(&self, _elem: &Self::BasePrimeField) -> Self { + unimplemented!() + } } impl FftField for Fq { @@ -163,6 +155,28 @@ impl FftField for Fq { const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; } +impl AdditiveGroup for Fq { + type Scalar = Self; + + const ZERO: Self = Self::ZERO; + + fn double(&self) -> Self { + let mut copy = *self; + copy.double_in_place(); + copy + } + + fn double_in_place(&mut self) -> &mut Self { + self.add_assign(*self); + self + } + + fn neg_in_place(&mut self) -> &mut Self { + *self = -(*self); + self + } +} + impl Zero for Fq { #[inline] fn zero() -> Self { diff --git a/src/fields/fq/ops.rs b/src/fields/fq/ops.rs index c56b407..bfa184c 100644 --- a/src/fields/fq/ops.rs +++ b/src/fields/fq/ops.rs @@ -43,6 +43,36 @@ impl From for Fq { } } +impl From for Fq { + fn from(other: i8) -> Self { + i128::from(other).into() + } +} + +impl From for Fq { + fn from(other: i16) -> Self { + i128::from(other).into() + } +} + +impl From for Fq { + fn from(other: i32) -> Self { + i128::from(other).into() + } +} + +impl From for Fq { + fn from(other: i64) -> Self { + i128::from(other).into() + } +} + +impl From for Fq { + fn from(other: i128) -> Self { + i128::from(other).into() + } +} + impl Neg for Fq { type Output = Self; diff --git a/src/fields/fr/arkworks.rs b/src/fields/fr/arkworks.rs index d31e5b5..34b0cf1 100644 --- a/src/fields/fr/arkworks.rs +++ b/src/fields/fr/arkworks.rs @@ -1,12 +1,15 @@ use super::Fr; -use ark_ff::{BigInt, Field, PrimeField, SqrtPrecomputation}; +use ark_ff::{AdditiveGroup, BigInt, Field, PrimeField, SqrtPrecomputation}; use ark_ff::{BigInteger, FftField}; use ark_serialize::{ CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, - CanonicalSerializeWithFlags, Compress, EmptyFlags, Flags, SerializationError, Valid, Validate, + CanonicalSerializeWithFlags, Compress, EmptyFlags, Flags, Read, SerializationError, Valid, + Validate, Write, }; +use ark_std::vec::Vec; use ark_std::{rand, str::FromStr, string::ToString, One, Zero}; use core::convert::TryInto; +use core::ops::AddAssign; use core::{ fmt::{Display, Formatter}, iter, @@ -58,7 +61,6 @@ impl PrimeField for Fr { impl Field for Fr { type BasePrimeField = Self; - type BasePrimeFieldIter = iter::Once; const SQRT_PRECOMP: Option> = Some(SqrtPrecomputation::Case3Mod4 { modulus_plus_one_div_four: &[ @@ -69,8 +71,6 @@ impl Field for Fr { ], }); - const ZERO: Self = Self::ZERO; - // Montomgery representation of one const ONE: Self = Self::ONE; @@ -78,11 +78,14 @@ impl Field for Fr { 1 } - fn to_base_prime_field_elements(&self) -> Self::BasePrimeFieldIter { + fn to_base_prime_field_elements(&self) -> impl Iterator { iter::once(*self) } - fn from_base_prime_field_elems(elems: &[Self::BasePrimeField]) -> Option { + fn from_base_prime_field_elems( + elems: impl IntoIterator, + ) -> Option { + let elems: Vec<_> = elems.into_iter().collect(); if elems.len() != (Self::extension_degree() as usize) { return None; } @@ -93,20 +96,6 @@ impl Field for Fr { elem } - fn double(&self) -> Self { - self.add(self) - } - - fn double_in_place(&mut self) -> &mut Self { - *self = self.add(self); - self - } - - fn neg_in_place(&mut self) -> &mut Self { - *self = Self::ZERO.sub(self); - self - } - fn from_random_bytes_with_flags(bytes: &[u8]) -> Option<(Self, F)> { Some((Self::from_le_bytes_mod_order(bytes), F::default())) } @@ -153,6 +142,10 @@ impl Field for Fr { fn characteristic() -> &'static [u64] { &Self::MODULUS_LIMBS } + + fn mul_by_base_prime_field(&self, _elem: &Self::BasePrimeField) -> Self { + unimplemented!() + } } impl FftField for Fr { @@ -164,6 +157,28 @@ impl FftField for Fr { const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; } +impl AdditiveGroup for Fr { + type Scalar = Self; + + const ZERO: Self = Self::ZERO; + + fn double(&self) -> Self { + let mut copy = *self; + copy.double_in_place(); + copy + } + + fn double_in_place(&mut self) -> &mut Self { + self.add_assign(*self); + self + } + + fn neg_in_place(&mut self) -> &mut Self { + *self = -(*self); + self + } +} + impl Zero for Fr { #[inline] fn zero() -> Self { @@ -188,7 +203,7 @@ impl One for Fr { } } impl CanonicalDeserializeWithFlags for Fr { - fn deserialize_with_flags( + fn deserialize_with_flags( mut reader: R, ) -> Result<(Self, F), SerializationError> { // Enough for the field element + 8 bits of flags. The last byte may or may not contain flags. @@ -216,7 +231,7 @@ impl Valid for Fr { } impl CanonicalDeserialize for Fr { - fn deserialize_with_mode( + fn deserialize_with_mode( reader: R, _compress: Compress, validate: Validate, @@ -232,7 +247,7 @@ impl CanonicalDeserialize for Fr { impl CanonicalSerialize for Fr { #[inline] - fn serialize_with_mode( + fn serialize_with_mode( &self, writer: W, _compress: Compress, @@ -247,7 +262,7 @@ impl CanonicalSerialize for Fr { } impl CanonicalSerializeWithFlags for Fr { - fn serialize_with_flags( + fn serialize_with_flags( &self, mut writer: W, flags: F, diff --git a/src/fields/fr/ops.rs b/src/fields/fr/ops.rs index 1301238..2c36269 100644 --- a/src/fields/fr/ops.rs +++ b/src/fields/fr/ops.rs @@ -43,6 +43,36 @@ impl From for Fr { } } +impl From for Fr { + fn from(other: i8) -> Self { + i128::from(other).into() + } +} + +impl From for Fr { + fn from(other: i16) -> Self { + i128::from(other).into() + } +} + +impl From for Fr { + fn from(other: i32) -> Self { + i128::from(other).into() + } +} + +impl From for Fr { + fn from(other: i64) -> Self { + i128::from(other).into() + } +} + +impl From for Fr { + fn from(other: i128) -> Self { + i128::from(other).into() + } +} + impl Neg for Fr { type Output = Self; From 84b1633ba7acd221bb6a5fb3637f3c23e1bb57fb Mon Sep 17 00:00:00 2001 From: Tal Derei Date: Sun, 17 Nov 2024 13:33:52 +0700 Subject: [PATCH 2/8] provided methods --- src/fields/fp/arkworks.rs | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/src/fields/fp/arkworks.rs b/src/fields/fp/arkworks.rs index 0d4bb6e..9c0171e 100644 --- a/src/fields/fp/arkworks.rs +++ b/src/fields/fp/arkworks.rs @@ -167,35 +167,6 @@ impl Field for Fp { sum } - fn frobenius_map(&self, power: usize) -> Self { - let mut this = *self; - this.frobenius_map_in_place(power); - this - } - - fn pow>(&self, exp: S) -> Self { - let mut res = Self::one(); - - for i in ark_ff::BitIteratorBE::without_leading_zeros(exp) { - res.square_in_place(); - - if i { - res *= self; - } - } - res - } - - fn pow_with_table>(powers_of_2: &[Self], exp: S) -> Option { - let mut res = Self::one(); - for (pow, bit) in ark_ff::BitIteratorLE::without_trailing_zeros(exp).enumerate() { - if bit { - res *= powers_of_2.get(pow)?; - } - } - Some(res) - } - fn mul_by_base_prime_field(&self, _elem: &Self::BasePrimeField) -> Self { unimplemented!() } From 6b6112ffcc9bf727b1ce66fb79124ce7e7027d63 Mon Sep 17 00:00:00 2001 From: Tal Derei Date: Sun, 17 Nov 2024 21:10:42 -0800 Subject: [PATCH 3/8] stub r1cs v0.5 --- src/ark_curve/r1cs/element.rs | 58 +++++++++++++++++++++-- src/ark_curve/r1cs/fqvar_ext.rs | 55 +++++++++++++++++++--- src/ark_curve/r1cs/inner.rs | 81 +++++++++++++++++++++++++++------ tests/groth16_gadgets.rs | 4 +- 4 files changed, 170 insertions(+), 28 deletions(-) diff --git a/src/ark_curve/r1cs/element.rs b/src/ark_curve/r1cs/element.rs index 036b4bd..62b853a 100644 --- a/src/ark_curve/r1cs/element.rs +++ b/src/ark_curve/r1cs/element.rs @@ -1,7 +1,10 @@ #![allow(non_snake_case)] use core::borrow::Borrow; +use core::ops::{Mul, MulAssign}; use ark_ec::AffineRepr; +use ark_r1cs_std::convert::ToConstraintFieldGadget; +use ark_r1cs_std::fields::emulated_fp::EmulatedFpVar; use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, prelude::*, R1CSVar}; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use ark_std::vec::Vec; @@ -9,9 +12,9 @@ use ark_std::vec::Vec; use crate::ark_curve::r1cs::{lazy::LazyElementVar, FqVar}; use crate::ark_curve::{edwards::EdwardsAffine, r1cs::inner::ElementVar as InnerElementVar}; use crate::ark_curve::{AffinePoint, Element}; -use crate::Fq; +use crate::{Fq, Fr}; -use super::inner::Decaf377EdwardsVar; +use super::inner::{Decaf377EdwardsVar, ScalarMultiply, ScalarMultiplyAssign}; #[derive(Clone, Debug)] /// Represents the R1CS equivalent of a `decaf377::Element` @@ -187,13 +190,13 @@ impl ToBitsGadget for ElementVar { } impl ToBytesGadget for ElementVar { - fn to_bytes(&self) -> Result>, SynthesisError> { + fn to_bytes_le(&self) -> Result>, SynthesisError> { let compressed_fq = self .inner .element() .expect("element will exist") - .to_bytes()?; - let encoded_bytes = compressed_fq.to_bytes()?; + .to_bytes_le()?; + let encoded_bytes = compressed_fq.to_bytes_le()?; Ok(encoded_bytes) } } @@ -256,3 +259,48 @@ impl CurveVar for ElementVar { }) } } + +// Scalar multiplication +impl ScalarMultiplyAssign, LazyElementVar> for LazyElementVar { + fn mul_assign_scalar(&mut self, scalar: EmulatedFpVar) { + *self = LazyElementVar::new_from_element(self.element().unwrap() * scalar); + } +} + +impl ScalarMultiply, LazyElementVar> for LazyElementVar { + fn mul_with_scalar(&self, scalar: &EmulatedFpVar) -> LazyElementVar { + LazyElementVar::new_from_element(self.element().unwrap() * scalar.clone()) + } +} + +impl MulAssign> for ElementVar { + fn mul_assign(&mut self, scalar: EmulatedFpVar) { + self.inner.mul_assign_scalar(scalar); + } +} + +impl<'a> Mul<&'a EmulatedFpVar> for ElementVar { + type Output = ElementVar; + + fn mul(self, scalar: &'a EmulatedFpVar) -> Self::Output { + ElementVar { + inner: self.inner.mul_with_scalar(scalar), + } + } +} + +impl Mul> for ElementVar { + type Output = ElementVar; + + fn mul(self, scalar: EmulatedFpVar) -> Self::Output { + self * &scalar + } +} + +impl ToConstraintFieldGadget for ElementVar { + fn to_constraint_field( + &self, + ) -> Result>, ark_relations::r1cs::SynthesisError> { + unimplemented!() + } +} diff --git a/src/ark_curve/r1cs/fqvar_ext.rs b/src/ark_curve/r1cs/fqvar_ext.rs index f3014de..af9bf9e 100644 --- a/src/ark_curve/r1cs/fqvar_ext.rs +++ b/src/ark_curve/r1cs/fqvar_ext.rs @@ -1,7 +1,9 @@ +use ark_ff::Field; use ark_r1cs_std::eq::EqGadget; +use ark_r1cs_std::prelude::ToBitsGadget; use ark_r1cs_std::prelude::{AllocVar, Boolean, FieldVar}; use ark_r1cs_std::select::CondSelectGadget; -use ark_r1cs_std::{R1CSVar, ToBitsGadget}; +use ark_r1cs_std::R1CSVar; use ark_relations::r1cs::SynthesisError; use crate::ark_curve::{constants::ZETA, r1cs::FqVar}; @@ -18,6 +20,43 @@ pub trait FqVarExtension: Sized { fn abs(self) -> Result; } +// The methods for logical operations (and, or, not) were moved from the Boolean +// enum to helper functions in AllocatedBool. Consequently, we need to do some +// cursed redirection for the the Boolean enum to delegate these operations to the +// underlying AllocatedBool when applicable. +fn not(boolean: &Boolean) -> Result, SynthesisError> { + match boolean { + Boolean::Var(allocated) => Ok(Boolean::Var(allocated.not()?)), + Boolean::Constant(value) => Ok(Boolean::Constant(!value)), + } +} + +fn and(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { + match (a, b) { + // Both are AllocatedBool + (Boolean::Var(alloc_a), Boolean::Var(alloc_b)) => Ok(Boolean::Var(alloc_a.and(alloc_b)?)), + // Both are constant + (Boolean::Constant(val_a), Boolean::Constant(val_b)) => { + Ok(Boolean::Constant(*val_a & *val_b)) + } + // One is constant, one is variable + (Boolean::Constant(true), other) | (other, Boolean::Constant(true)) => Ok(other.clone()), + (Boolean::Constant(false), _) | (_, Boolean::Constant(false)) => { + Ok(Boolean::Constant(false)) + } + } +} + +fn or(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { + match (a, b) { + (Boolean::Var(alloc_a), Boolean::Var(alloc_b)) => Ok(Boolean::Var(alloc_a.or(alloc_b)?)), + (Boolean::Constant(val_a), Boolean::Constant(val_b)) => { + Ok(Boolean::Constant(*val_a | *val_b)) + } + _ => Err(SynthesisError::Unsatisfiable), + } +} + impl FqVarExtension for FqVar { /// Inverse square root in R1CS /// @@ -55,27 +94,29 @@ impl FqVarExtension for FqVar { y_squared_var.conditional_enforce_equal(&den_var_inv, &in_case_1)?; // Case 3: `(false, 0)` if `den` is zero - let was_not_square_var = was_square_var.not(); - let in_case_3 = was_not_square_var.and(&den_var_is_zero)?; + + let was_not_square_var = not(&was_square_var)?; + let in_case_3 = and(&was_not_square_var, &den_var_is_zero)?; // Certify the return value y is 0 when we're in case 3. y_squared_var.conditional_enforce_equal(&FqVar::zero(), &in_case_3)?; // Case 4: `(false, sqrt(zeta*num/den))` if `num` and `den` are both nonzero and `num/den` is nonsquare; let zeta_var = FqVar::new_constant(cs, ZETA)?; let zeta_times_one_over_den_var = zeta_var * den_var_inv; - let in_case_4 = was_not_square_var.and(&den_var_is_zero.not())?; + let is_den_var_is_zero = not(&den_var_is_zero)?; + let in_case_4 = and(&was_not_square_var, &is_den_var_is_zero)?; // Certify the return value y is sqrt(zeta * 1/den) y_squared_var.conditional_enforce_equal(&zeta_times_one_over_den_var, &in_case_4)?; // Ensure that we are in case 1, 3, or 4. - let in_case = in_case_1.or(&in_case_3)?.or(&in_case_4)?; + let in_case = or(&in_case_1, &or(&in_case_3, &in_case_4)?)?; in_case.enforce_equal(&Boolean::TRUE)?; Ok((was_square_var, y_var)) } fn is_negative(&self) -> Result, SynthesisError> { - Ok(self.is_nonnegative()?.not()) + Ok(not(&self.is_nonnegative()?)?) } fn is_nonnegative(&self) -> Result, SynthesisError> { @@ -86,7 +127,7 @@ impl FqVarExtension for FqVar { let false_var = Boolean::::FALSE; // Check least significant bit - let lhs = bitvars[0].and(&true_var)?; + let lhs = and(&bitvars[0], &true_var)?; let is_nonnegative_var = lhs.is_eq(&false_var)?; Ok(is_nonnegative_var) diff --git a/src/ark_curve/r1cs/inner.rs b/src/ark_curve/r1cs/inner.rs index 85e8111..d857e4a 100644 --- a/src/ark_curve/r1cs/inner.rs +++ b/src/ark_curve/r1cs/inner.rs @@ -1,21 +1,20 @@ #![allow(non_snake_case)] -use core::borrow::Borrow; -use core::ops::{Add, AddAssign, Sub, SubAssign}; - +use crate::ark_curve::{ + constants::ZETA, edwards::EdwardsAffine, r1cs::fqvar_ext::FqVarExtension, r1cs::FqVar, + AffinePoint, Decaf377EdwardsConfig, Element, +}; +use crate::{Fq, Fr}; use ark_ec::{twisted_edwards::TECurveConfig, AffineRepr}; +use ark_r1cs_std::convert::ToConstraintFieldGadget; +use ark_r1cs_std::fields::emulated_fp::EmulatedFpVar; use ark_r1cs_std::{ alloc::AllocVar, eq::EqGadget, groups::curves::twisted_edwards::AffineVar, prelude::*, R1CSVar, }; use ark_relations::ns; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use ark_std::vec::Vec; - -use crate::ark_curve::{ - constants::ZETA, edwards::EdwardsAffine, r1cs::fqvar_ext::FqVarExtension, r1cs::FqVar, - AffinePoint, Decaf377EdwardsConfig, Element, -}; -use crate::Fq; - +use core::borrow::Borrow; +use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}; pub(crate) type Decaf377EdwardsVar = AffineVar; #[derive(Clone, Debug)] @@ -306,9 +305,9 @@ impl ToBitsGadget for ElementVar { } impl ToBytesGadget for ElementVar { - fn to_bytes(&self) -> Result>, SynthesisError> { - let compressed_fq = self.inner.to_bytes()?; - let encoded_bytes = compressed_fq.to_bytes()?; + fn to_bytes_le(&self) -> Result>, SynthesisError> { + let compressed_fq = self.inner.to_bytes_le()?; + let encoded_bytes = compressed_fq.to_bytes_le()?; Ok(encoded_bytes) } } @@ -409,6 +408,62 @@ impl AddAssign for ElementVar { } } +impl MulAssign> for ElementVar { + fn mul_assign(&mut self, rhs: EmulatedFpVar) { + *self = ElementVar { + inner: self.inner.clone() * rhs, + }; + } +} + +// Scalar multiplication +pub trait ScalarMultiplyAssign { + fn mul_assign_scalar(&mut self, scalar: Scalar); +} + +impl ScalarMultiplyAssign, Decaf377EdwardsVar> for Decaf377EdwardsVar { + fn mul_assign_scalar(&mut self, scalar: EmulatedFpVar) { + let result = self.clone() * scalar; + *self = result; + } +} + +pub trait ScalarMultiply { + fn mul_with_scalar(&self, scalar: &Scalar) -> Output; +} + +impl ScalarMultiply, Decaf377EdwardsVar> for Decaf377EdwardsVar { + fn mul_with_scalar(&self, scalar: &EmulatedFpVar) -> Decaf377EdwardsVar { + self.clone() * scalar.clone() + } +} + +impl<'a> Mul<&'a EmulatedFpVar> for ElementVar { + type Output = ElementVar; + + fn mul(self, scalar: &'a EmulatedFpVar) -> Self::Output { + ElementVar { + inner: self.inner.mul_with_scalar(scalar), + } + } +} + +impl Mul> for ElementVar { + type Output = ElementVar; + + fn mul(self, scalar: EmulatedFpVar) -> Self::Output { + self * &scalar + } +} + +impl ToConstraintFieldGadget for ElementVar { + fn to_constraint_field( + &self, + ) -> Result>, ark_relations::r1cs::SynthesisError> { + unimplemented!() + } +} + impl<'a> GroupOpsBounds<'a, Element, ElementVar> for ElementVar {} impl CurveVar for ElementVar { diff --git a/tests/groth16_gadgets.rs b/tests/groth16_gadgets.rs index 74e1cfd..b3e223f 100644 --- a/tests/groth16_gadgets.rs +++ b/tests/groth16_gadgets.rs @@ -1,11 +1,9 @@ -use ark_ff::UniformRand; use ark_groth16::{r1cs_to_qap::LibsnarkReduction, Groth16, Proof, ProvingKey, VerifyingKey}; use proptest::prelude::*; use ark_r1cs_std::{ - prelude::{AllocVar, CurveVar, EqGadget}, + prelude::{AllocVar, CurveVar, EqGadget, ToBitsGadget}, uint8::UInt8, - ToBitsGadget, }; use ark_relations::r1cs::{ConstraintSynthesizer, ToConstraintField}; use ark_snark::SNARK; From 545b78db733022cc867cc71d495dba0c86d61418 Mon Sep 17 00:00:00 2001 From: Tal Derei Date: Sun, 17 Nov 2024 21:49:51 -0800 Subject: [PATCH 4/8] pub modifier on logical ops --- src/ark_curve/r1cs/element.rs | 4 ++-- src/ark_curve/r1cs/fqvar_ext.rs | 6 +++--- src/ark_curve/r1cs/inner.rs | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ark_curve/r1cs/element.rs b/src/ark_curve/r1cs/element.rs index 62b853a..539a0a5 100644 --- a/src/ark_curve/r1cs/element.rs +++ b/src/ark_curve/r1cs/element.rs @@ -9,12 +9,12 @@ use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, prelude::*, R1CSVar}; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use ark_std::vec::Vec; +use super::inner::{Decaf377EdwardsVar, ScalarMultiply, ScalarMultiplyAssign}; use crate::ark_curve::r1cs::{lazy::LazyElementVar, FqVar}; use crate::ark_curve::{edwards::EdwardsAffine, r1cs::inner::ElementVar as InnerElementVar}; use crate::ark_curve::{AffinePoint, Element}; use crate::{Fq, Fr}; - -use super::inner::{Decaf377EdwardsVar, ScalarMultiply, ScalarMultiplyAssign}; +use ark_r1cs_std::prelude::ToBitsGadget; #[derive(Clone, Debug)] /// Represents the R1CS equivalent of a `decaf377::Element` diff --git a/src/ark_curve/r1cs/fqvar_ext.rs b/src/ark_curve/r1cs/fqvar_ext.rs index af9bf9e..b7b70e9 100644 --- a/src/ark_curve/r1cs/fqvar_ext.rs +++ b/src/ark_curve/r1cs/fqvar_ext.rs @@ -24,14 +24,14 @@ pub trait FqVarExtension: Sized { // enum to helper functions in AllocatedBool. Consequently, we need to do some // cursed redirection for the the Boolean enum to delegate these operations to the // underlying AllocatedBool when applicable. -fn not(boolean: &Boolean) -> Result, SynthesisError> { +pub fn not(boolean: &Boolean) -> Result, SynthesisError> { match boolean { Boolean::Var(allocated) => Ok(Boolean::Var(allocated.not()?)), Boolean::Constant(value) => Ok(Boolean::Constant(!value)), } } -fn and(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { +pub fn and(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { match (a, b) { // Both are AllocatedBool (Boolean::Var(alloc_a), Boolean::Var(alloc_b)) => Ok(Boolean::Var(alloc_a.and(alloc_b)?)), @@ -47,7 +47,7 @@ fn and(a: &Boolean, b: &Boolean) -> Result, Synthesis } } -fn or(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { +pub fn or(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { match (a, b) { (Boolean::Var(alloc_a), Boolean::Var(alloc_b)) => Ok(Boolean::Var(alloc_a.or(alloc_b)?)), (Boolean::Constant(val_a), Boolean::Constant(val_b)) => { diff --git a/src/ark_curve/r1cs/inner.rs b/src/ark_curve/r1cs/inner.rs index d857e4a..a0788df 100644 --- a/src/ark_curve/r1cs/inner.rs +++ b/src/ark_curve/r1cs/inner.rs @@ -16,6 +16,7 @@ use ark_std::vec::Vec; use core::borrow::Borrow; use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}; pub(crate) type Decaf377EdwardsVar = AffineVar; +use ark_r1cs_std::prelude::ToBitsGadget; #[derive(Clone, Debug)] /// Represents the R1CS equivalent of a `decaf377::Element` From 95eb130bfe17ba33461c51f518d7bf15af13cfcc Mon Sep 17 00:00:00 2001 From: Tal Derei Date: Sun, 17 Nov 2024 22:00:44 -0800 Subject: [PATCH 5/8] move logical ops into FqVarExtension trait --- src/ark_curve/r1cs/fqvar_ext.rs | 98 ++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 45 deletions(-) diff --git a/src/ark_curve/r1cs/fqvar_ext.rs b/src/ark_curve/r1cs/fqvar_ext.rs index b7b70e9..5ea20e6 100644 --- a/src/ark_curve/r1cs/fqvar_ext.rs +++ b/src/ark_curve/r1cs/fqvar_ext.rs @@ -1,4 +1,3 @@ -use ark_ff::Field; use ark_r1cs_std::eq::EqGadget; use ark_r1cs_std::prelude::ToBitsGadget; use ark_r1cs_std::prelude::{AllocVar, Boolean, FieldVar}; @@ -18,43 +17,9 @@ pub trait FqVarExtension: Sized { fn is_negative(&self) -> Result, SynthesisError>; fn is_nonnegative(&self) -> Result, SynthesisError>; fn abs(self) -> Result; -} - -// The methods for logical operations (and, or, not) were moved from the Boolean -// enum to helper functions in AllocatedBool. Consequently, we need to do some -// cursed redirection for the the Boolean enum to delegate these operations to the -// underlying AllocatedBool when applicable. -pub fn not(boolean: &Boolean) -> Result, SynthesisError> { - match boolean { - Boolean::Var(allocated) => Ok(Boolean::Var(allocated.not()?)), - Boolean::Constant(value) => Ok(Boolean::Constant(!value)), - } -} - -pub fn and(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { - match (a, b) { - // Both are AllocatedBool - (Boolean::Var(alloc_a), Boolean::Var(alloc_b)) => Ok(Boolean::Var(alloc_a.and(alloc_b)?)), - // Both are constant - (Boolean::Constant(val_a), Boolean::Constant(val_b)) => { - Ok(Boolean::Constant(*val_a & *val_b)) - } - // One is constant, one is variable - (Boolean::Constant(true), other) | (other, Boolean::Constant(true)) => Ok(other.clone()), - (Boolean::Constant(false), _) | (_, Boolean::Constant(false)) => { - Ok(Boolean::Constant(false)) - } - } -} - -pub fn or(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { - match (a, b) { - (Boolean::Var(alloc_a), Boolean::Var(alloc_b)) => Ok(Boolean::Var(alloc_a.or(alloc_b)?)), - (Boolean::Constant(val_a), Boolean::Constant(val_b)) => { - Ok(Boolean::Constant(*val_a | *val_b)) - } - _ => Err(SynthesisError::Unsatisfiable), - } + fn not(boolean: &Boolean) -> Result, SynthesisError>; + fn and(a: &Boolean, b: &Boolean) -> Result, SynthesisError>; + fn or(a: &Boolean, b: &Boolean) -> Result, SynthesisError>; } impl FqVarExtension for FqVar { @@ -95,28 +60,28 @@ impl FqVarExtension for FqVar { // Case 3: `(false, 0)` if `den` is zero - let was_not_square_var = not(&was_square_var)?; - let in_case_3 = and(&was_not_square_var, &den_var_is_zero)?; + let was_not_square_var = Self::not(&was_square_var)?; + let in_case_3 = Self::and(&was_not_square_var, &den_var_is_zero)?; // Certify the return value y is 0 when we're in case 3. y_squared_var.conditional_enforce_equal(&FqVar::zero(), &in_case_3)?; // Case 4: `(false, sqrt(zeta*num/den))` if `num` and `den` are both nonzero and `num/den` is nonsquare; let zeta_var = FqVar::new_constant(cs, ZETA)?; let zeta_times_one_over_den_var = zeta_var * den_var_inv; - let is_den_var_is_zero = not(&den_var_is_zero)?; - let in_case_4 = and(&was_not_square_var, &is_den_var_is_zero)?; + let is_den_var_is_zero = Self::not(&den_var_is_zero)?; + let in_case_4 = Self::and(&was_not_square_var, &is_den_var_is_zero)?; // Certify the return value y is sqrt(zeta * 1/den) y_squared_var.conditional_enforce_equal(&zeta_times_one_over_den_var, &in_case_4)?; // Ensure that we are in case 1, 3, or 4. - let in_case = or(&in_case_1, &or(&in_case_3, &in_case_4)?)?; + let in_case = Self::or(&in_case_1, &Self::or(&in_case_3, &in_case_4)?)?; in_case.enforce_equal(&Boolean::TRUE)?; Ok((was_square_var, y_var)) } fn is_negative(&self) -> Result, SynthesisError> { - Ok(not(&self.is_nonnegative()?)?) + Ok(Self::not(&self.is_nonnegative()?)?) } fn is_nonnegative(&self) -> Result, SynthesisError> { @@ -127,7 +92,7 @@ impl FqVarExtension for FqVar { let false_var = Boolean::::FALSE; // Check least significant bit - let lhs = and(&bitvars[0], &true_var)?; + let lhs = Self::and(&bitvars[0], &true_var)?; let is_nonnegative_var = lhs.is_eq(&false_var)?; Ok(is_nonnegative_var) @@ -138,4 +103,47 @@ impl FqVarExtension for FqVar { FqVar::conditionally_select(&self.is_nonnegative()?, &self, &self.negate()?)?; Ok(absolute_value) } + + // The methods for logical operations (and, or, not) were moved from the Boolean + // enum to helper functions in AllocatedBool. Consequently, we need to do some + // cursed redirection for the the Boolean enum to delegate these operations to the + // underlying AllocatedBool when applicable. + fn not(boolean: &Boolean) -> Result, SynthesisError> { + match boolean { + Boolean::Var(allocated) => Ok(Boolean::Var(allocated.not()?)), + Boolean::Constant(value) => Ok(Boolean::Constant(!value)), + } + } + + fn and(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { + match (a, b) { + // Both are AllocatedBool + (Boolean::Var(alloc_a), Boolean::Var(alloc_b)) => { + Ok(Boolean::Var(alloc_a.and(alloc_b)?)) + } + // Both are constant + (Boolean::Constant(val_a), Boolean::Constant(val_b)) => { + Ok(Boolean::Constant(*val_a & *val_b)) + } + // One is constant, one is variable + (Boolean::Constant(true), other) | (other, Boolean::Constant(true)) => { + Ok(other.clone()) + } + (Boolean::Constant(false), _) | (_, Boolean::Constant(false)) => { + Ok(Boolean::Constant(false)) + } + } + } + + fn or(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { + match (a, b) { + (Boolean::Var(alloc_a), Boolean::Var(alloc_b)) => { + Ok(Boolean::Var(alloc_a.or(alloc_b)?)) + } + (Boolean::Constant(val_a), Boolean::Constant(val_b)) => { + Ok(Boolean::Constant(*val_a | *val_b)) + } + _ => Err(SynthesisError::Unsatisfiable), + } + } } From 5526b26a73cc58b14a20354f25413c0afb7f4d31 Mon Sep 17 00:00:00 2001 From: Tal Derei Date: Tue, 19 Nov 2024 01:58:48 -0800 Subject: [PATCH 6/8] provided methods for AdditiveGroup --- src/fields/fp/arkworks.rs | 16 ---------------- src/fields/fq/arkworks.rs | 16 ---------------- src/fields/fr/arkworks.rs | 16 ---------------- 3 files changed, 48 deletions(-) diff --git a/src/fields/fp/arkworks.rs b/src/fields/fp/arkworks.rs index 9c0171e..9d7effa 100644 --- a/src/fields/fp/arkworks.rs +++ b/src/fields/fp/arkworks.rs @@ -185,22 +185,6 @@ impl AdditiveGroup for Fp { type Scalar = Self; const ZERO: Self = Self::ZERO; - - fn double(&self) -> Self { - let mut copy = *self; - copy.double_in_place(); - copy - } - - fn double_in_place(&mut self) -> &mut Self { - self.add_assign(*self); - self - } - - fn neg_in_place(&mut self) -> &mut Self { - *self = -(*self); - self - } } impl Zero for Fp { diff --git a/src/fields/fq/arkworks.rs b/src/fields/fq/arkworks.rs index 3e2121c..21a0be8 100644 --- a/src/fields/fq/arkworks.rs +++ b/src/fields/fq/arkworks.rs @@ -159,22 +159,6 @@ impl AdditiveGroup for Fq { type Scalar = Self; const ZERO: Self = Self::ZERO; - - fn double(&self) -> Self { - let mut copy = *self; - copy.double_in_place(); - copy - } - - fn double_in_place(&mut self) -> &mut Self { - self.add_assign(*self); - self - } - - fn neg_in_place(&mut self) -> &mut Self { - *self = -(*self); - self - } } impl Zero for Fq { diff --git a/src/fields/fr/arkworks.rs b/src/fields/fr/arkworks.rs index 34b0cf1..3b98d69 100644 --- a/src/fields/fr/arkworks.rs +++ b/src/fields/fr/arkworks.rs @@ -161,22 +161,6 @@ impl AdditiveGroup for Fr { type Scalar = Self; const ZERO: Self = Self::ZERO; - - fn double(&self) -> Self { - let mut copy = *self; - copy.double_in_place(); - copy - } - - fn double_in_place(&mut self) -> &mut Self { - self.add_assign(*self); - self - } - - fn neg_in_place(&mut self) -> &mut Self { - *self = -(*self); - self - } } impl Zero for Fr { From 0d3421081de00951ff04ac3bf49d7bf19e9558a1 Mon Sep 17 00:00:00 2001 From: Tal Derei Date: Tue, 19 Nov 2024 02:00:22 -0800 Subject: [PATCH 7/8] provided methods for PrimeField trait for Fp --- src/fields/fp/arkworks.rs | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/fields/fp/arkworks.rs b/src/fields/fp/arkworks.rs index 9d7effa..d70a7aa 100644 --- a/src/fields/fp/arkworks.rs +++ b/src/fields/fp/arkworks.rs @@ -145,28 +145,7 @@ impl Field for Fp { Self::from_random_bytes_with_flags::(bytes).map(|f| f.0) } - fn sqrt(&self) -> Option { - match Self::SQRT_PRECOMP { - Some(tv) => tv.sqrt(self), - None => core::unimplemented!(), - } - } - - fn sqrt_in_place(&mut self) -> Option<&mut Self> { - (*self).sqrt().map(|sqrt| { - *self = sqrt; - self - }) - } - - fn sum_of_products(a: &[Self; T], b: &[Self; T]) -> Self { - let mut sum = Self::zero(); - for i in 0..a.len() { - sum += a[i] * b[i]; - } - sum - } - + // Stub fn mul_by_base_prime_field(&self, _elem: &Self::BasePrimeField) -> Self { unimplemented!() } From 6751f969e1a6b9b15800d3783ed58e9bbd703077 Mon Sep 17 00:00:00 2001 From: Tal Derei Date: Tue, 19 Nov 2024 02:01:17 -0800 Subject: [PATCH 8/8] modify logical ops to match arkworks impl --- src/ark_curve/r1cs/fqvar_ext.rs | 51 +++++++++++++++------------------ 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/src/ark_curve/r1cs/fqvar_ext.rs b/src/ark_curve/r1cs/fqvar_ext.rs index 5ea20e6..95865d8 100644 --- a/src/ark_curve/r1cs/fqvar_ext.rs +++ b/src/ark_curve/r1cs/fqvar_ext.rs @@ -1,12 +1,13 @@ +use crate::ark_curve::{constants::ZETA, r1cs::FqVar}; +use crate::Fq; use ark_r1cs_std::eq::EqGadget; use ark_r1cs_std::prelude::ToBitsGadget; use ark_r1cs_std::prelude::{AllocVar, Boolean, FieldVar}; use ark_r1cs_std::select::CondSelectGadget; use ark_r1cs_std::R1CSVar; use ark_relations::r1cs::SynthesisError; - -use crate::ark_curve::{constants::ZETA, r1cs::FqVar}; -use crate::Fq; +use ark_std::println; +use Boolean::*; pub trait FqVarExtension: Sized { fn isqrt(&self) -> Result<(Boolean, FqVar), SynthesisError>; @@ -18,6 +19,7 @@ pub trait FqVarExtension: Sized { fn is_nonnegative(&self) -> Result, SynthesisError>; fn abs(self) -> Result; fn not(boolean: &Boolean) -> Result, SynthesisError>; + fn not_in_place(boolean: Boolean) -> Result, SynthesisError>; fn and(a: &Boolean, b: &Boolean) -> Result, SynthesisError>; fn or(a: &Boolean, b: &Boolean) -> Result, SynthesisError>; } @@ -31,6 +33,8 @@ impl FqVarExtension for FqVar { /// - Case 3: `(false, 0)` if `den` is zero; /// - Case 4: `(false, sqrt(zeta*num/den))` if `num` and `den` are both nonzero and `num/den` is nonsquare; fn isqrt(&self) -> Result<(Boolean, FqVar), SynthesisError> { + println!("isSqrt!"); + // During mode `SynthesisMode::Setup`, value() will not provide a field element. let den = self.value().unwrap_or(Fq::ONE); @@ -109,41 +113,32 @@ impl FqVarExtension for FqVar { // cursed redirection for the the Boolean enum to delegate these operations to the // underlying AllocatedBool when applicable. fn not(boolean: &Boolean) -> Result, SynthesisError> { - match boolean { - Boolean::Var(allocated) => Ok(Boolean::Var(allocated.not()?)), - Boolean::Constant(value) => Ok(Boolean::Constant(!value)), + Ok(Self::not_in_place(boolean.clone())?) + } + + fn not_in_place(mut boolean: Boolean) -> Result, SynthesisError> { + match &mut boolean { + Boolean::Constant(c) => *c = !*c, + Boolean::Var(v) => *v = v.not()?, } + Ok(boolean) } fn and(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { match (a, b) { - // Both are AllocatedBool - (Boolean::Var(alloc_a), Boolean::Var(alloc_b)) => { - Ok(Boolean::Var(alloc_a.and(alloc_b)?)) - } - // Both are constant - (Boolean::Constant(val_a), Boolean::Constant(val_b)) => { - Ok(Boolean::Constant(*val_a & *val_b)) - } - // One is constant, one is variable - (Boolean::Constant(true), other) | (other, Boolean::Constant(true)) => { - Ok(other.clone()) - } - (Boolean::Constant(false), _) | (_, Boolean::Constant(false)) => { - Ok(Boolean::Constant(false)) - } + // false AND x is always false + (&Constant(false), _) | (_, &Constant(false)) => Ok(Constant(false)), + // true AND x is always x + (&Constant(true), x) | (x, &Constant(true)) => Ok(x.clone()), + (Var(ref x), Var(ref y)) => Ok(Var(x.and(y)?)), } } fn or(a: &Boolean, b: &Boolean) -> Result, SynthesisError> { match (a, b) { - (Boolean::Var(alloc_a), Boolean::Var(alloc_b)) => { - Ok(Boolean::Var(alloc_a.or(alloc_b)?)) - } - (Boolean::Constant(val_a), Boolean::Constant(val_b)) => { - Ok(Boolean::Constant(*val_a | *val_b)) - } - _ => Err(SynthesisError::Unsatisfiable), + (&Constant(false), x) | (x, &Constant(false)) => Ok(x.clone()), + (&Constant(true), _) | (_, &Constant(true)) => Ok(Constant(true)), + (Var(ref x), Var(ref y)) => Ok(Var(x.or(y)?)), } } }