From f774318355779975e3cad7be9ddebd2fd2b647aa Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Sun, 14 Jul 2024 12:34:19 +0200 Subject: [PATCH] Some Optimizations (#26) --- src/arkworks/mod.rs | 3 ++ src/arkworks/te_sw_map.rs | 106 +++++++++++++++++++++++++++++++++++++ src/codec.rs | 7 +-- src/lib.rs | 1 + src/ring.rs | 25 +++------ src/suites/bandersnatch.rs | 8 +-- src/testing.rs | 6 +-- src/utils.rs | 91 ++----------------------------- 8 files changed, 132 insertions(+), 115 deletions(-) create mode 100644 src/arkworks/te_sw_map.rs diff --git a/src/arkworks/mod.rs b/src/arkworks/mod.rs index 1f1e0eb..3772695 100644 --- a/src/arkworks/mod.rs +++ b/src/arkworks/mod.rs @@ -1,3 +1,6 @@ //! Features expected to land into Arkworks at some point in the future +/// Elligator 2 hash-to-curve. pub mod elligator2; +/// Twisted Edwards to Short Weierstrass mapping. +pub mod te_sw_map; diff --git a/src/arkworks/te_sw_map.rs b/src/arkworks/te_sw_map.rs new file mode 100644 index 0000000..a4c84d0 --- /dev/null +++ b/src/arkworks/te_sw_map.rs @@ -0,0 +1,106 @@ +use crate::*; +use ark_ec::{ + short_weierstrass::{Affine as WeierstrassAffine, SWCurveConfig}, + twisted_edwards::{Affine as EdwardsAffine, MontCurveConfig, TECurveConfig}, + CurveConfig, +}; +use ark_ff::{Field, One}; +use ark_std::borrow::Cow; + +// Constants used in mapping TE form to SW form and vice versa +pub trait MapConfig: TECurveConfig + SWCurveConfig + MontCurveConfig { + const MONT_A_OVER_THREE: ::BaseField; + const MONT_B_INV: ::BaseField; +} + +pub fn map_sw_to_te(point: &WeierstrassAffine) -> Option> { + // First map the point from SW to Montgomery + // (Bx - A/3, By) + let mx = ::COEFF_B * point.x - C::MONT_A_OVER_THREE; + let my = ::COEFF_B * point.y; + + // Then we map the TE point to Montgamory + // (x,y) -> (x/y,(x−1)/(x+1)) + let v_denom = my.inverse()?; + let x_p_1 = mx + <::BaseField as One>::one(); + let w_denom = x_p_1.inverse()?; + let v = mx * v_denom; + let w = (mx - <::BaseField as One>::one()) * w_denom; + + Some(EdwardsAffine::new_unchecked(v, w)) +} + +pub fn map_te_to_sw(point: &EdwardsAffine) -> Option> { + // Map from TE to Montgomery: (1+y)/(1-y), (1+y)/(x(1-y)) + let v_denom = <::BaseField as One>::one() - point.y; + let w_denom = point.x - point.x * point.y; + let v_denom_inv = v_denom.inverse()?; + let w_denom_inv = w_denom.inverse()?; + let v_w_num = <::BaseField as One>::one() + point.y; + let v = v_w_num * v_denom_inv; + let w = v_w_num * w_denom_inv; + + // Map Montgamory to SW: ((x+A/3)/B,y/B) + let x = C::MONT_B_INV * (v + C::MONT_A_OVER_THREE); + let y = C::MONT_B_INV * w; + + Some(WeierstrassAffine::new_unchecked(x, y)) +} + +pub trait SWMapping { + fn from_sw(sw: WeierstrassAffine) -> Self; + + fn into_sw(self) -> WeierstrassAffine; + + fn to_sw_slice(slice: &[Self]) -> Cow<[WeierstrassAffine]> + where + Self: Sized; +} + +impl SWMapping for WeierstrassAffine { + #[inline(always)] + fn from_sw(sw: WeierstrassAffine) -> Self { + sw + } + + #[inline(always)] + fn into_sw(self) -> WeierstrassAffine { + self + } + + #[inline(always)] + fn to_sw_slice(slice: &[Self]) -> Cow<[WeierstrassAffine]> { + Cow::Borrowed(slice) + } +} + +impl SWMapping for EdwardsAffine { + #[inline(always)] + fn from_sw(sw: WeierstrassAffine) -> Self { + const ERR_MSG: &str = + "SW to TE is expected to be implemented only for curves supporting the mapping"; + map_sw_to_te(&sw).expect(ERR_MSG) + } + + #[inline(always)] + fn into_sw(self) -> WeierstrassAffine { + const ERR_MSG: &str = + "TE to SW is expected to be implemented only for curves supporting the mapping"; + map_te_to_sw(&self).expect(ERR_MSG) + } + + #[inline(always)] + fn to_sw_slice(slice: &[Self]) -> Cow<[WeierstrassAffine]> { + let pks; + #[cfg(feature = "parallel")] + { + use rayon::prelude::*; + pks = slice.par_iter().map(|p| p.into_sw()).collect(); + } + #[cfg(not(feature = "parallel"))] + { + pks = slice.iter().map(|p| p.into_sw()).collect(); + } + Cow::Owned(pks) + } +} diff --git a/src/codec.rs b/src/codec.rs index a6d9dc5..bbb803e 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -1,4 +1,5 @@ use ark_ec::short_weierstrass::SWCurveConfig; +use arkworks::te_sw_map; use super::*; @@ -53,13 +54,13 @@ impl Codec for Sec1Codec where BaseField: ark_ff::PrimeField, CurveConfig: SWCurveConfig, - AffinePoint: utils::SWMapping>, + AffinePoint: te_sw_map::SWMapping>, { const BIG_ENDIAN: bool = true; fn point_encode(pt: &AffinePoint, buf: &mut Vec) { use ark_ff::biginteger::BigInteger; - use utils::SWMapping; + use te_sw_map::SWMapping; if pt.is_zero() { buf.push(0x00); @@ -78,7 +79,7 @@ where fn point_decode(buf: &[u8]) -> Result, Error> { use ark_ff::biginteger::BigInteger; - use utils::SWMapping; + use te_sw_map::SWMapping; type SWAffine = ark_ec::short_weierstrass::Affine; if buf.len() == 1 && buf[0] == 0x00 { diff --git a/src/lib.rs b/src/lib.rs index acf2be7..0c760fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub mod utils; #[cfg(feature = "ring")] pub mod ring; +#[allow(unused)] mod arkworks; #[cfg(test)] diff --git a/src/ring.rs b/src/ring.rs index 9128be4..747e507 100644 --- a/src/ring.rs +++ b/src/ring.rs @@ -1,4 +1,4 @@ -use crate::utils::SWMapping; +use crate::arkworks::te_sw_map::SWMapping; use crate::*; use ark_ec::short_weierstrass::SWCurveConfig; use pedersen::{PedersenSuite, Proof as PedersenProof}; @@ -8,9 +8,6 @@ pub mod prelude { pub use ring_proof; } -#[cfg(feature = "parallel")] -use rayon::prelude::*; - /// Ring suite. pub trait RingSuite: PedersenSuite { /// Pairing type. @@ -156,11 +153,13 @@ where pub piop_params: PiopParams, } +#[inline(always)] fn domain_size(ring_size: usize) -> usize { const RING_DOMAIN_OVERHEAD: usize = 257; 1 << ark_std::log2(ring_size + RING_DOMAIN_OVERHEAD) } +#[allow(private_bounds)] impl RingContext where BaseField: ark_ff::PrimeField, @@ -205,6 +204,7 @@ where } /// The max ring size this context is able to manage. + #[inline(always)] pub fn max_ring_size(&self) -> usize { self.piop_params.keyset_part_size } @@ -213,24 +213,16 @@ where /// /// Note: if `pks.len() > self.max_ring_size()` the extra keys in the tail are ignored. pub fn prover_key(&self, pks: &[AffinePoint]) -> ProverKey { - let pks = &pks[..pks.len().min(self.max_ring_size())]; - #[cfg(feature = "parallel")] - let pks: Vec<_> = pks.par_iter().map(|p| p.into_sw()).collect(); - #[cfg(not(feature = "parallel"))] - let pks: Vec<_> = pks.iter().map(|p| p.into_sw()).collect(); - ring_proof::index(self.pcs_params.clone(), &self.piop_params, pks).0 + let pks = SWMapping::to_sw_slice(&pks[..pks.len().min(self.max_ring_size())]); + ring_proof::index(&self.pcs_params, &self.piop_params, &pks).0 } /// Construct a `VerifierKey` instance for the given ring. /// /// Note: if `pks.len() > self.max_ring_size()` the extra keys in the tail are ignored. pub fn verifier_key(&self, pks: &[AffinePoint]) -> VerifierKey { - let pks = &pks[..pks.len().min(self.max_ring_size())]; - #[cfg(feature = "parallel")] - let pks: Vec<_> = pks.par_iter().map(|p| p.into_sw()).collect(); - #[cfg(not(feature = "parallel"))] - let pks: Vec<_> = pks.iter().map(|p| p.into_sw()).collect(); - ring_proof::index(self.pcs_params.clone(), &self.piop_params, pks).1 + let pks = SWMapping::to_sw_slice(&pks[..pks.len().min(self.max_ring_size())]); + ring_proof::index(&self.pcs_params, &self.piop_params, &pks).1 } pub fn prover(&self, prover_key: ProverKey, key_index: usize) -> RingProver { @@ -297,7 +289,6 @@ impl ark_serialize::Valid for RingContext where BaseField: ark_ff::PrimeField, CurveConfig: SWCurveConfig + Clone, - AffinePoint: SWMapping>, { fn check(&self) -> Result<(), ark_serialize::SerializationError> { self.pcs_params.check() diff --git a/src/suites/bandersnatch.rs b/src/suites/bandersnatch.rs index 35a777a..1b7268e 100644 --- a/src/suites/bandersnatch.rs +++ b/src/suites/bandersnatch.rs @@ -50,7 +50,7 @@ //! with `h2c_suite_ID_string` = `"Bandersnatch_XMD:SHA-512_ELL2_RO_"` //! and domain separation tag `DST = "ECVRF_" || h2c_suite_ID_string || suite_string`. -use crate::{pedersen::PedersenSuite, utils::ark_next::*, *}; +use crate::{arkworks::te_sw_map::*, pedersen::PedersenSuite, *}; use ark_ff::MontFp; pub mod weierstrass { @@ -228,17 +228,17 @@ impl MapConfig for ark_ed_on_bls12_381_bandersnatch::BandersnatchConfig { #[cfg(test)] mod tests { - use crate::{testing, utils::ark_next}; + use crate::{testing, utils::te_sw_map::*}; use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, SWAffine}; #[test] fn sw_to_te_roundtrip() { let org_point = testing::random_val::(None); - let te_point = ark_next::map_sw_to_te::(&org_point).unwrap(); + let te_point = map_sw_to_te::(&org_point).unwrap(); assert!(te_point.is_on_curve()); - let sw_point = ark_next::map_te_to_sw::(&te_point).unwrap(); + let sw_point = map_te_to_sw::(&te_point).unwrap(); assert!(sw_point.is_on_curve()); } } diff --git a/src/testing.rs b/src/testing.rs index 9c8ed6b..489db3a 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -76,7 +76,7 @@ pub fn ring_prove_verify() where BaseField: ark_ff::PrimeField, CurveConfig: ark_ec::short_weierstrass::SWCurveConfig + Clone, - AffinePoint: utils::SWMapping>, + AffinePoint: utils::te_sw_map::SWMapping>, { use ring::{Prover, RingContext, Verifier}; @@ -109,9 +109,9 @@ pub fn check_complement_point() where BaseField: ark_ff::PrimeField, CurveConfig: ark_ec::short_weierstrass::SWCurveConfig + Clone, - AffinePoint: utils::SWMapping>, + AffinePoint: utils::te_sw_map::SWMapping>, { - use utils::SWMapping; + use utils::te_sw_map::SWMapping; let pt = S::COMPLEMENT_POINT.into_sw(); assert!(pt.is_on_curve()); assert!(!pt.is_in_correct_subgroup_assuming_on_curve()); diff --git a/src/utils.rs b/src/utils.rs index a1d4393..4107926 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,8 @@ use crate::*; +#[allow(unused)] +pub(crate) use crate::arkworks::{elligator2, te_sw_map}; + use ark_ec::AffineRepr; use ark_ff::PrimeField; use digest::{Digest, FixedOutputReset}; @@ -236,94 +239,6 @@ where S::Codec::scalar_decode(&v) } -// Upcoming Arkworks features. -pub(crate) mod ark_next { - use ark_ec::{ - short_weierstrass::{Affine as WeierstrassAffine, SWCurveConfig}, - twisted_edwards::{Affine as EdwardsAffine, MontCurveConfig, TECurveConfig}, - CurveConfig, - }; - use ark_ff::{Field, One}; - - // Constants used in mapping TE form to SW form and vice versa - pub trait MapConfig: TECurveConfig + SWCurveConfig + MontCurveConfig { - const MONT_A_OVER_THREE: ::BaseField; - const MONT_B_INV: ::BaseField; - } - - // https://github.com/arkworks-rs/algebra/pull/804 - #[allow(unused)] - pub fn map_sw_to_te(point: &WeierstrassAffine) -> Option> { - // First map the point from SW to Montgomery - // (Bx - A/3, By) - let mx = ::COEFF_B * point.x - C::MONT_A_OVER_THREE; - let my = ::COEFF_B * point.y; - - // Then we map the TE point to Montgamory - // (x,y)↦(x/y,(x−1)/(x+1)) - let v_denom = my.inverse()?; - let x_p_1 = mx + <::BaseField as One>::one(); - let w_denom = x_p_1.inverse()?; - let v = mx * v_denom; - let w = (mx - <::BaseField as One>::one()) * w_denom; - - Some(EdwardsAffine::new_unchecked(v, w)) - } - - #[allow(unused)] - pub fn map_te_to_sw(point: &EdwardsAffine) -> Option> { - // Map from TE to Montgomery: (1+y)/(1-y), (1+y)/(x(1-y)) - let v_denom = <::BaseField as One>::one() - point.y; - let w_denom = point.x - point.x * point.y; - let v_denom_inv = v_denom.inverse()?; - let w_denom_inv = w_denom.inverse()?; - let v_w_num = <::BaseField as One>::one() + point.y; - let v = v_w_num * v_denom_inv; - let w = v_w_num * w_denom_inv; - - // Map Montgamory to SW: ((x+A/3)/B,y/B) - let x = C::MONT_B_INV * (v + C::MONT_A_OVER_THREE); - let y = C::MONT_B_INV * w; - - Some(WeierstrassAffine::new_unchecked(x, y)) - } -} - -pub trait SWMapping { - fn from_sw(sw: ark_ec::short_weierstrass::Affine) -> Self; - fn into_sw(self) -> ark_ec::short_weierstrass::Affine; -} - -impl SWMapping - for ark_ec::short_weierstrass::Affine -{ - #[inline(always)] - fn from_sw(sw: ark_ec::short_weierstrass::Affine) -> Self { - sw - } - - #[inline(always)] - fn into_sw(self) -> ark_ec::short_weierstrass::Affine { - self - } -} - -impl SWMapping for ark_ec::twisted_edwards::Affine { - #[inline(always)] - fn from_sw(sw: ark_ec::short_weierstrass::Affine) -> Self { - const ERR_MSG: &str = - "SW to TE is expected to be implemented only for curves supporting the mapping"; - ark_next::map_sw_to_te(&sw).expect(ERR_MSG) - } - - #[inline(always)] - fn into_sw(self) -> ark_ec::short_weierstrass::Affine { - const ERR_MSG: &str = - "TE to SW is expected to be implemented only for curves supporting the mapping"; - ark_next::map_te_to_sw(&self).expect(ERR_MSG) - } -} - #[cfg(test)] mod tests { use super::*;