Skip to content

Commit

Permalink
Some Optimizations (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
davxy authored Jul 14, 2024
1 parent e868d12 commit f774318
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 115 deletions.
3 changes: 3 additions & 0 deletions src/arkworks/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
106 changes: 106 additions & 0 deletions src/arkworks/te_sw_map.rs
Original file line number Diff line number Diff line change
@@ -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: <Self as CurveConfig>::BaseField;
const MONT_B_INV: <Self as CurveConfig>::BaseField;
}

pub fn map_sw_to_te<C: MapConfig>(point: &WeierstrassAffine<C>) -> Option<EdwardsAffine<C>> {
// First map the point from SW to Montgomery
// (Bx - A/3, By)
let mx = <C as MontCurveConfig>::COEFF_B * point.x - C::MONT_A_OVER_THREE;
let my = <C as MontCurveConfig>::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 + <<C as CurveConfig>::BaseField as One>::one();
let w_denom = x_p_1.inverse()?;
let v = mx * v_denom;
let w = (mx - <<C as CurveConfig>::BaseField as One>::one()) * w_denom;

Some(EdwardsAffine::new_unchecked(v, w))
}

pub fn map_te_to_sw<C: MapConfig>(point: &EdwardsAffine<C>) -> Option<WeierstrassAffine<C>> {
// Map from TE to Montgomery: (1+y)/(1-y), (1+y)/(x(1-y))
let v_denom = <<C as CurveConfig>::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 = <<C as CurveConfig>::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<C: SWCurveConfig> {
fn from_sw(sw: WeierstrassAffine<C>) -> Self;

fn into_sw(self) -> WeierstrassAffine<C>;

fn to_sw_slice(slice: &[Self]) -> Cow<[WeierstrassAffine<C>]>
where
Self: Sized;
}

impl<C: SWCurveConfig> SWMapping<C> for WeierstrassAffine<C> {
#[inline(always)]
fn from_sw(sw: WeierstrassAffine<C>) -> Self {
sw
}

#[inline(always)]
fn into_sw(self) -> WeierstrassAffine<C> {
self
}

#[inline(always)]
fn to_sw_slice(slice: &[Self]) -> Cow<[WeierstrassAffine<C>]> {
Cow::Borrowed(slice)
}
}

impl<C: MapConfig> SWMapping<C> for EdwardsAffine<C> {
#[inline(always)]
fn from_sw(sw: WeierstrassAffine<C>) -> 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<C> {
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<C>]> {
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)
}
}
7 changes: 4 additions & 3 deletions src/codec.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use ark_ec::short_weierstrass::SWCurveConfig;
use arkworks::te_sw_map;

use super::*;

Expand Down Expand Up @@ -53,13 +54,13 @@ impl<S: Suite> Codec<S> for Sec1Codec
where
BaseField<S>: ark_ff::PrimeField,
CurveConfig<S>: SWCurveConfig,
AffinePoint<S>: utils::SWMapping<CurveConfig<S>>,
AffinePoint<S>: te_sw_map::SWMapping<CurveConfig<S>>,
{
const BIG_ENDIAN: bool = true;

fn point_encode(pt: &AffinePoint<S>, buf: &mut Vec<u8>) {
use ark_ff::biginteger::BigInteger;
use utils::SWMapping;
use te_sw_map::SWMapping;

if pt.is_zero() {
buf.push(0x00);
Expand All @@ -78,7 +79,7 @@ where

fn point_decode(buf: &[u8]) -> Result<AffinePoint<S>, Error> {
use ark_ff::biginteger::BigInteger;
use utils::SWMapping;
use te_sw_map::SWMapping;
type SWAffine<C> = ark_ec::short_weierstrass::Affine<C>;

if buf.len() == 1 && buf[0] == 0x00 {
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub mod utils;
#[cfg(feature = "ring")]
pub mod ring;

#[allow(unused)]
mod arkworks;

#[cfg(test)]
Expand Down
25 changes: 8 additions & 17 deletions src/ring.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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.
Expand Down Expand Up @@ -156,11 +153,13 @@ where
pub piop_params: PiopParams<S>,
}

#[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<S: RingSuite> RingContext<S>
where
BaseField<S>: ark_ff::PrimeField,
Expand Down Expand Up @@ -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
}
Expand All @@ -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<S>]) -> ProverKey<S> {
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<S>]) -> VerifierKey<S> {
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<S>, key_index: usize) -> RingProver<S> {
Expand Down Expand Up @@ -297,7 +289,6 @@ impl<S: RingSuite> ark_serialize::Valid for RingContext<S>
where
BaseField<S>: ark_ff::PrimeField,
CurveConfig<S>: SWCurveConfig + Clone,
AffinePoint<S>: SWMapping<CurveConfig<S>>,
{
fn check(&self) -> Result<(), ark_serialize::SerializationError> {
self.pcs_params.check()
Expand Down
8 changes: 4 additions & 4 deletions src/suites/bandersnatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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::<SWAffine>(None);

let te_point = ark_next::map_sw_to_te::<BandersnatchConfig>(&org_point).unwrap();
let te_point = map_sw_to_te::<BandersnatchConfig>(&org_point).unwrap();
assert!(te_point.is_on_curve());

let sw_point = ark_next::map_te_to_sw::<BandersnatchConfig>(&te_point).unwrap();
let sw_point = map_te_to_sw::<BandersnatchConfig>(&te_point).unwrap();
assert!(sw_point.is_on_curve());
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub fn ring_prove_verify<S: ring::RingSuite>()
where
BaseField<S>: ark_ff::PrimeField,
CurveConfig<S>: ark_ec::short_weierstrass::SWCurveConfig + Clone,
AffinePoint<S>: utils::SWMapping<CurveConfig<S>>,
AffinePoint<S>: utils::te_sw_map::SWMapping<CurveConfig<S>>,
{
use ring::{Prover, RingContext, Verifier};

Expand Down Expand Up @@ -109,9 +109,9 @@ pub fn check_complement_point<S: ring::RingSuite>()
where
BaseField<S>: ark_ff::PrimeField,
CurveConfig<S>: ark_ec::short_weierstrass::SWCurveConfig + Clone,
AffinePoint<S>: utils::SWMapping<CurveConfig<S>>,
AffinePoint<S>: utils::te_sw_map::SWMapping<CurveConfig<S>>,
{
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());
Expand Down
91 changes: 3 additions & 88 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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: <Self as CurveConfig>::BaseField;
const MONT_B_INV: <Self as CurveConfig>::BaseField;
}

// https://github.com/arkworks-rs/algebra/pull/804
#[allow(unused)]
pub fn map_sw_to_te<C: MapConfig>(point: &WeierstrassAffine<C>) -> Option<EdwardsAffine<C>> {
// First map the point from SW to Montgomery
// (Bx - A/3, By)
let mx = <C as MontCurveConfig>::COEFF_B * point.x - C::MONT_A_OVER_THREE;
let my = <C as MontCurveConfig>::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 + <<C as CurveConfig>::BaseField as One>::one();
let w_denom = x_p_1.inverse()?;
let v = mx * v_denom;
let w = (mx - <<C as CurveConfig>::BaseField as One>::one()) * w_denom;

Some(EdwardsAffine::new_unchecked(v, w))
}

#[allow(unused)]
pub fn map_te_to_sw<C: MapConfig>(point: &EdwardsAffine<C>) -> Option<WeierstrassAffine<C>> {
// Map from TE to Montgomery: (1+y)/(1-y), (1+y)/(x(1-y))
let v_denom = <<C as CurveConfig>::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 = <<C as CurveConfig>::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<C: ark_ec::short_weierstrass::SWCurveConfig> {
fn from_sw(sw: ark_ec::short_weierstrass::Affine<C>) -> Self;
fn into_sw(self) -> ark_ec::short_weierstrass::Affine<C>;
}

impl<C: ark_ec::short_weierstrass::SWCurveConfig> SWMapping<C>
for ark_ec::short_weierstrass::Affine<C>
{
#[inline(always)]
fn from_sw(sw: ark_ec::short_weierstrass::Affine<C>) -> Self {
sw
}

#[inline(always)]
fn into_sw(self) -> ark_ec::short_weierstrass::Affine<C> {
self
}
}

impl<C: ark_next::MapConfig> SWMapping<C> for ark_ec::twisted_edwards::Affine<C> {
#[inline(always)]
fn from_sw(sw: ark_ec::short_weierstrass::Affine<C>) -> 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<C> {
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::*;
Expand Down

0 comments on commit f774318

Please sign in to comment.