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..faa5580 --- /dev/null +++ b/src/arkworks/te_sw_map.rs @@ -0,0 +1,123 @@ +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: ark_ec::short_weierstrass::Affine) -> Self; + fn into_sw(&self) -> Cow>; +} + +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) -> Cow> { + Cow::Borrowed(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"; + map_sw_to_te(&sw).expect(ERR_MSG) + } + + #[inline(always)] + fn into_sw(&self) -> Cow> { + const ERR_MSG: &str = + "TE to SW is expected to be implemented only for curves supporting the mapping"; + Cow::Owned(map_te_to_sw(&self).expect(ERR_MSG)) + } +} + +pub(crate) trait SWMappingSeq { + #[inline(always)] + fn into_sw_seq(&self) -> Cow<[ark_ec::short_weierstrass::Affine]>; +} + +impl SWMappingSeq for [ark_ec::short_weierstrass::Affine] +where + ark_ec::short_weierstrass::Affine: SWMapping, +{ + #[inline(always)] + fn into_sw_seq(&self) -> Cow<[ark_ec::short_weierstrass::Affine]> { + Cow::Borrowed(self) + } +} + +impl SWMappingSeq for [ark_ec::twisted_edwards::Affine] +where + ark_ec::twisted_edwards::Affine: SWMapping, +{ + #[inline(always)] + fn into_sw_seq(&self) -> Cow<[WeierstrassAffine]> { + #[cfg(feature = "parallel")] + use rayon::prelude::*; + + const ERR_MSG: &str = + "TE to SW is expected to be implemented only for curves supporting the mapping"; + #[cfg(feature = "parallel")] + let pks: Vec<_> = self + .par_iter() + .map(|p| map_te_to_sw(p).expect(ERR_MSG)) + .collect(); + #[cfg(not(feature = "parallel"))] + let pks: Vec<_> = self + .iter() + .map(|p| map_te_to_sw(p).expect(ERR_MSG)) + .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 88152e4..0b74b85 100644 --- a/src/ring.rs +++ b/src/ring.rs @@ -1,4 +1,4 @@ -use crate::utils::SWMapping; +use crate::arkworks::te_sw_map::{SWMapping, SWMappingSeq}; 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. @@ -138,7 +135,7 @@ where ) -> Result<(), Error> { use pedersen::Verifier as PedersenVerifier; >::verify(input, output, ad, &sig.pedersen_proof)?; - let key_commitment = sig.pedersen_proof.key_commitment().into_sw(); + let key_commitment = *sig.pedersen_proof.key_commitment().into_sw(); if !verifier.verify_ring_proof(sig.ring_proof.clone(), key_commitment) { return Err(Error::VerificationFailure); } @@ -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, @@ -194,8 +193,8 @@ where let piop_params = PiopParams::::setup( ring_proof::Domain::new(domain_size, true), - S::BLINDING_BASE.into_sw(), - S::COMPLEMENT_POINT.into_sw(), + *S::BLINDING_BASE.into_sw(), + *S::COMPLEMENT_POINT.into_sw(), ); Ok(Self { @@ -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 } @@ -212,24 +212,22 @@ where /// Construct a `ProverKey` instance for the given ring. /// /// 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(); + pub fn prover_key(&self, pks: &[AffinePoint]) -> ProverKey + where + [AffinePoint]: SWMappingSeq>, + { + let pks = pks[..pks.len().min(self.max_ring_size())].into_sw_seq(); 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(); + pub fn verifier_key(&self, pks: &[AffinePoint]) -> VerifierKey + where + [AffinePoint]: SWMappingSeq>, + { + let pks = pks[..pks.len().min(self.max_ring_size())].into_sw_seq(); ring_proof::index(&self.pcs_params, &self.piop_params, &pks).1 } @@ -297,7 +295,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..041ae59 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -76,7 +76,8 @@ 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>, + [AffinePoint]: utils::te_sw_map::SWMappingSeq>, { use ring::{Prover, RingContext, Verifier}; @@ -109,10 +110,11 @@ 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>, + [AffinePoint]: utils::te_sw_map::SWMappingSeq>, { - use utils::SWMapping; - let pt = S::COMPLEMENT_POINT.into_sw(); + 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::*;