Skip to content

Commit

Permalink
refactor: implement our own TE config
Browse files Browse the repository at this point in the history
Previously defining the cofactor was done on `AffineCurve`: this
let us set it to 1 since decaf377 provides a prime-order group.
However, the cofactor is now moved to the curve configuration
via the trait `CurveConfig`.

This means we can no longer use the upstream `ark_ed_on_bls12_377`
curve configuration type: we need to define our own and implement
the required traits, and then use that to define `EdwardsAffine`,
`EdwardsProjective`, and `EdwardsVar` (R1CS) instead of the upstream
provided definitions of those types.
  • Loading branch information
redshiftzero committed Apr 25, 2023
1 parent d762be0 commit db7879d
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 47 deletions.
6 changes: 6 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ pub static B_T: Lazy<Fq> = Lazy::new(|| {
});
pub static B_Z: Lazy<Fq> = Lazy::new(|| ark_ff::MontFp!("1"));

// Canonical basepoint affine coordinates
pub const GENERATOR_X: Fq =
ark_ff::MontFp!("4959445789346820725352484487855828915252512307947624787834978378872129235627");
pub const GENERATOR_Y: Fq =
ark_ff::MontFp!("6060471950081851567114691557659790004756535011754163002297540472747064943288");

// Modulus of basefield
pub static R: Lazy<Fr> = Lazy::new(|| {
ark_ff::MontFp!("2111115437357092606062206234695386632838870926408408195193685246394721360383")
Expand Down
67 changes: 62 additions & 5 deletions src/element.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,75 @@
use ark_ec::{AffineRepr, CurveGroup, Group, ScalarMul, VariableBaseMSM};
use ark_ed_on_bls12_377::{EdwardsAffine, EdwardsConfig, EdwardsProjective};
use ark_ec::{
twisted_edwards::{Affine, MontCurveConfig, Projective, TECurveConfig},
AffineRepr, CurveConfig, CurveGroup, Group, ScalarMul, VariableBaseMSM,
};
use ark_ed_on_bls12_377::EdwardsConfig;
use ark_ff::MontFp;
use ark_serialize::Valid;

use crate::{Fq, Fr};
use crate::{
constants::{GENERATOR_X, GENERATOR_Y},
Fq, Fr,
};

pub mod affine;
pub mod projective;

pub use affine::AffineElement;
pub use projective::Element;

#[derive(Clone, Default, PartialEq, Eq)]
pub struct Decaf377EdwardsConfig;

// These types should not be exported. They are similar to `EdwardsAffine` and
// `EdwardsProjective` from the `ark_ed_on_bls12_377` crate, except using our own
// `Decaf377Config` that has the cofactor set to 1. Consumers of this
// library should use the `AffineElement` and `Element` (projective)
// types.
pub(crate) type EdwardsAffine = Affine<Decaf377EdwardsConfig>;
pub(crate) type EdwardsProjective = Projective<Decaf377EdwardsConfig>;

impl CurveConfig for Decaf377EdwardsConfig {
type BaseField = Fq;
type ScalarField = Fr;

const COFACTOR: &'static [u64] = &[1];

const COFACTOR_INV: Fr = MontFp!("1");
}

impl TECurveConfig for Decaf377EdwardsConfig {
/// COEFF_A = -1
const COEFF_A: Fq = <EdwardsConfig as ark_ec::twisted_edwards::TECurveConfig>::COEFF_A;

/// COEFF_D = 3021
const COEFF_D: Fq = <EdwardsConfig as ark_ec::twisted_edwards::TECurveConfig>::COEFF_D;

const GENERATOR: EdwardsAffine = EdwardsAffine::new_unchecked(GENERATOR_X, GENERATOR_Y);

type MontCurveConfig = EdwardsConfig;

/// Multiplication by `a` is just negation.
#[inline(always)]
fn mul_by_a(elem: Self::BaseField) -> Self::BaseField {
-elem
}

fn is_in_correct_subgroup_assuming_on_curve(_: &Affine<Self>) -> bool {
true
}
}

impl MontCurveConfig for Decaf377EdwardsConfig {
const COEFF_A: Fq = <EdwardsConfig as ark_ec::twisted_edwards::MontCurveConfig>::COEFF_A;

const COEFF_B: Fq = <EdwardsConfig as ark_ec::twisted_edwards::MontCurveConfig>::COEFF_B;

type TECurveConfig = Decaf377EdwardsConfig;
}

impl Valid for Element {
fn check(&self) -> Result<(), ark_serialize::SerializationError> {
todo!()
Ok(())
}
}

Expand Down Expand Up @@ -84,7 +141,7 @@ impl CurveGroup for Element {

impl Valid for AffineElement {
fn check(&self) -> Result<(), ark_serialize::SerializationError> {
todo!()
Ok(())
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/element/affine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::hash::Hash;

use ark_ed_on_bls12_377::EdwardsAffine;
use crate::element::EdwardsAffine;
use ark_std::fmt::{Display, Formatter, Result as FmtResult};
use ark_std::Zero;

Expand Down
3 changes: 1 addition & 2 deletions src/element/projective.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use std::borrow::Borrow;
use std::hash::Hash;

use ark_ed_on_bls12_377::EdwardsProjective;
use ark_ff::Zero;
use ark_std::fmt::{Display, Formatter, Result as FmtResult};

use zeroize::Zeroize;

use crate::{Fq, Fr};
use crate::{EdwardsProjective, Fq, Fr};

#[derive(Copy, Clone)]
pub struct Element {
Expand Down
13 changes: 7 additions & 6 deletions src/elligator.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#![allow(non_snake_case)]
use ark_ec::twisted_edwards::TECurveConfig;
use ark_ed_on_bls12_377::{EdwardsConfig, EdwardsProjective};
use ark_ff::Field;

use crate::element::{Decaf377EdwardsConfig, EdwardsProjective};

use crate::{
constants::{ONE, TWO, ZETA},
Element, Fq, OnCurve, Sign, SqrtRatioZeta,
Expand All @@ -12,8 +13,8 @@ impl Element {
/// Elligator 2 map to decaf377 point
fn elligator_map(r_0: &Fq) -> Element {
// Ref: `Decaf_1_1_Point.elligator` (optimized) in `ristretto.sage`
let A = EdwardsConfig::COEFF_A;
let D = EdwardsConfig::COEFF_D;
let A = Decaf377EdwardsConfig::COEFF_A;
let D = Decaf377EdwardsConfig::COEFF_D;

let r = *ZETA * r_0.square();

Expand Down Expand Up @@ -44,8 +45,8 @@ impl Element {

// Convert point to extended projective (X : Y : Z : T)
let E = *TWO * s;
let F = *ONE + EdwardsConfig::COEFF_A * s.square();
let G = *ONE - EdwardsConfig::COEFF_A * s.square();
let F = *ONE + Decaf377EdwardsConfig::COEFF_A * s.square();
let G = *ONE - Decaf377EdwardsConfig::COEFF_A * s.square();
let H = t;
let result = Element {
inner: EdwardsProjective::new(E * H, F * G, E * G, F * H),
Expand Down Expand Up @@ -86,7 +87,7 @@ impl Element {

#[cfg(test)]
mod tests {
use ark_ed_on_bls12_377::EdwardsAffine;
use crate::element::EdwardsAffine;

use super::*;

Expand Down
10 changes: 6 additions & 4 deletions src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
use std::convert::{TryFrom, TryInto};

use ark_ec::twisted_edwards::TECurveConfig;
use ark_ed_on_bls12_377::{EdwardsConfig, EdwardsProjective};
use ark_ff::{Field, One};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};

use crate::{constants::TWO, Element, EncodingError, Fq, OnCurve, Sign, SqrtRatioZeta};
use crate::{
constants::TWO, element::Decaf377EdwardsConfig, EdwardsProjective, Element, EncodingError, Fq,
OnCurve, Sign, SqrtRatioZeta,
};

#[derive(Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq)]
pub struct Encoding(pub [u8; 32]);
Expand Down Expand Up @@ -35,7 +37,7 @@ impl Encoding {

// This isn't a constant, only because traits don't have const methods
// yet and multiplication is only implemented as part of the Mul trait.
let D4: Fq = EdwardsConfig::COEFF_D * Fq::from(4u32);
let D4: Fq = Decaf377EdwardsConfig::COEFF_D * Fq::from(4u32);

// 1/2. Reject unless s is canonically encoded and nonnegative.
let s =
Expand Down Expand Up @@ -90,7 +92,7 @@ impl Element {
pub fn vartime_compress_to_field(&self) -> Fq {
// This isn't a constant, only because traits don't have const methods
// yet and subtraction is only implemented as part of the Sub trait.
let A_MINUS_D = EdwardsConfig::COEFF_A - EdwardsConfig::COEFF_D;
let A_MINUS_D = Decaf377EdwardsConfig::COEFF_A - Decaf377EdwardsConfig::COEFF_D;
let p = &self.inner;

// 1.
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ pub mod rand;
pub mod serialize;
mod sign;

use ark_ed_on_bls12_377::EdwardsProjective;
pub use constants::ZETA;
pub use element::{AffineElement, Element};
pub(crate) use element::{Decaf377EdwardsConfig, EdwardsProjective};
pub use encoding::Encoding;
pub use error::EncodingError;
pub use field_ext::FieldExt;
Expand Down
7 changes: 3 additions & 4 deletions src/ops/affine.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};

use ark_ec::twisted_edwards::Projective;
use ark_ed_on_bls12_377::EdwardsConfig;

use crate::{element::AffineElement, Element, Fr};
use crate::{element::AffineElement, Decaf377EdwardsConfig, Element, Fr};

impl<'a, 'b> Add<&'b AffineElement> for &'a AffineElement {
type Output = AffineElement;
Expand Down Expand Up @@ -102,7 +101,7 @@ impl Neg for AffineElement {

impl<'b> MulAssign<&'b Fr> for AffineElement {
fn mul_assign(&mut self, point: &'b Fr) {
let mut p: Projective<EdwardsConfig> = self.inner.into();
let mut p: Projective<Decaf377EdwardsConfig> = self.inner.into();
p *= *point;
*self = AffineElement { inner: p.into() }
}
Expand All @@ -118,7 +117,7 @@ impl<'a, 'b> Mul<&'b Fr> for &'a AffineElement {
type Output = AffineElement;

fn mul(self, point: &'b Fr) -> AffineElement {
let mut p: Projective<EdwardsConfig> = self.inner.into();
let mut p: Projective<Decaf377EdwardsConfig> = self.inner.into();
p *= *point;
AffineElement { inner: p.into() }
}
Expand Down
2 changes: 1 addition & 1 deletion src/ops/projective.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl Neg for Element {

impl<'b> MulAssign<&'b Fr> for Element {
// Scalar multiplication is performed through the implementation
// of `MulAssign` on `EdwardsProjective` which is a type alias for
// of `MulAssign` on `ProjectiveDecaf377` which is a type alias for
// `Group<EdwardsConfig>`.
fn mul_assign(&mut self, point: &'b Fr) {
let mut p = self.inner;
Expand Down
11 changes: 5 additions & 6 deletions src/r1cs/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@
use std::borrow::Borrow;

use ark_ec::AffineRepr;
use ark_ed_on_bls12_377::{
constraints::{EdwardsVar, FqVar},
EdwardsAffine,
};
use ark_ed_on_bls12_377::constraints::FqVar;
use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, prelude::*, R1CSVar};
use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};

use crate::r1cs::inner::ElementVar as InnerElementVar;
use crate::r1cs::lazy::LazyElementVar;
use crate::{element::EdwardsAffine, r1cs::inner::ElementVar as InnerElementVar};
use crate::{AffineElement, Element, Fq};

use super::inner::Decaf377EdwardsVar;

#[derive(Clone, Debug)]
/// Represents the R1CS equivalent of a `decaf377::Element`
///
Expand Down Expand Up @@ -115,7 +114,7 @@ impl CondSelectGadget<Fq> for ElementVar {
let y = cond.select(&true_element.inner.y, &false_element.inner.y)?;

let new_element = InnerElementVar {
inner: EdwardsVar::new(x, y),
inner: Decaf377EdwardsVar::new(x, y),
};
Ok(Self {
inner: LazyElementVar::new_from_element(new_element),
Expand Down
32 changes: 17 additions & 15 deletions src/r1cs/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,27 @@ use std::borrow::Borrow;
use std::ops::{Add, AddAssign, Sub, SubAssign};

use ark_ec::{twisted_edwards::TECurveConfig, AffineRepr};
use ark_ed_on_bls12_377::{
constraints::{EdwardsVar, FqVar},
EdwardsAffine, EdwardsConfig,
};
use ark_ed_on_bls12_377::constraints::FqVar;
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 crate::element::EdwardsAffine;
use crate::Decaf377EdwardsConfig;
use crate::{constants::ZETA, r1cs::fqvar_ext::FqVarExtension, AffineElement, Element, Fq};

pub(crate) type Decaf377EdwardsVar = AffineVar<Decaf377EdwardsConfig, FqVar>;

#[derive(Clone, Debug)]
/// Represents the R1CS equivalent of a `decaf377::Element`
///
/// Generally the suffix -`Var` will indicate that the type or variable
/// represents in R1CS.
pub struct ElementVar {
/// Inner type is an alias for `AffineVar<EdwardsConfig, FqVar>`
pub(crate) inner: EdwardsVar,
pub(crate) inner: Decaf377EdwardsVar,
}

impl ElementVar {
Expand All @@ -38,8 +39,10 @@ impl ElementVar {
let Z_var = FqVar::one();
let T_var = X_var * Y_var;

let A_MINUS_D_VAR =
FqVar::new_constant(self.cs(), EdwardsConfig::COEFF_A - EdwardsConfig::COEFF_D)?;
let A_MINUS_D_VAR = FqVar::new_constant(
self.cs(),
Decaf377EdwardsConfig::COEFF_A - Decaf377EdwardsConfig::COEFF_D,
)?;

// 1.
let u_1_var = (X_var.clone() + T_var.clone()) * (X_var.clone() - T_var.clone());
Expand All @@ -62,7 +65,7 @@ impl ElementVar {

/// R1CS equivalent of `Encoding::vartime_decompress`
pub fn decompress_from_field(s_var: FqVar) -> Result<ElementVar, SynthesisError> {
let D4: Fq = EdwardsConfig::COEFF_D * Fq::from(4u32);
let D4: Fq = Decaf377EdwardsConfig::COEFF_D * Fq::from(4u32);
let D4_VAR = FqVar::constant(D4);

// 1. We do not check if canonically encoded here since we know FqVar is already
Expand Down Expand Up @@ -107,8 +110,8 @@ impl ElementVar {
pub(crate) fn elligator_map(r_0_var: &FqVar) -> Result<ElementVar, SynthesisError> {
let cs = r_0_var.cs();

let A_VAR = FqVar::new_constant(cs.clone(), EdwardsConfig::COEFF_A)?;
let D_VAR = FqVar::new_constant(cs.clone(), EdwardsConfig::COEFF_D)?;
let A_VAR = FqVar::new_constant(cs.clone(), Decaf377EdwardsConfig::COEFF_A)?;
let D_VAR = FqVar::new_constant(cs.clone(), Decaf377EdwardsConfig::COEFF_D)?;
let ZETA_VAR = FqVar::new_constant(cs, *ZETA)?;

let r_var = ZETA_VAR * r_0_var.square()?;
Expand Down Expand Up @@ -219,7 +222,7 @@ impl CondSelectGadget<Fq> for ElementVar {
let y = cond.select(&true_value.inner.y, &false_value.inner.y)?;

Ok(ElementVar {
inner: EdwardsVar::new(x, y),
inner: Decaf377EdwardsVar::new(x, y),
})
}
}
Expand All @@ -244,7 +247,7 @@ impl AllocVar<Element, Fq> for ElementVar {
// where they check that the point is in the right subgroup prior to witnessing.
match mode {
AllocationMode::Constant => Ok(Self {
inner: EdwardsVar::new_variable_omit_prime_order_check(
inner: Decaf377EdwardsVar::new_variable_omit_prime_order_check(
cs,
|| Ok(group_projective_point.inner),
mode,
Expand All @@ -254,7 +257,6 @@ impl AllocVar<Element, Fq> for ElementVar {
unreachable!()
}
AllocationMode::Witness => {
//let ge: EdwardsAffine = group_projective_point.inner.into();
let P_var = AffineVar::new_variable_omit_prime_order_check(
ns!(cs, "P_affine"),
|| Ok(group_projective_point.inner),
Expand Down Expand Up @@ -410,13 +412,13 @@ impl<'a> GroupOpsBounds<'a, Element, ElementVar> for ElementVar {}
impl CurveVar<Element, Fq> for ElementVar {
fn zero() -> Self {
Self {
inner: AffineVar::<EdwardsConfig, FqVar>::zero(),
inner: AffineVar::<Decaf377EdwardsConfig, FqVar>::zero(),
}
}

fn constant(other: Element) -> Self {
Self {
inner: AffineVar::<EdwardsConfig, FqVar>::constant(other.inner),
inner: AffineVar::<Decaf377EdwardsConfig, FqVar>::constant(other.inner),
}
}

Expand Down
Loading

0 comments on commit db7879d

Please sign in to comment.