Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add twisted edwards trait + proper constants #22

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 52 additions & 33 deletions src/ed25519/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ use core::fmt::Debug;
use core::iter::Sum;
use core::ops::{Add, Mul, Neg, Sub};
use ff::{BatchInverter, Field, PrimeField};
use group::{self, Curve, Group};
use group::{self, Curve};
use group::{prime::PrimeCurveAffine, GroupEncoding};
use rand::RngCore;
use serde::{Deserialize, Serialize};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

#[cfg(feature = "derive_serde")]
use serde::{Deserialize, Serialize};

const ED25519_GENERATOR_X: Fq = Fq::from_raw([
0xc956_2d60_8f25_d51a,
0x692c_c760_9525_a7b2,
Expand Down Expand Up @@ -43,21 +45,23 @@ use crate::{
impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
};

#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
pub struct Ed25519 {
pub x: Fq,
pub y: Fq,
pub z: Fq,
pub t: Fq,
}

#[derive(Copy, Clone, Debug, PartialEq, Hash, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug, PartialEq, Hash)]
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
pub struct Ed25519Affine {
pub x: Fq,
pub y: Fq,
}

#[derive(Copy, Clone, Hash)]
#[derive(Copy, Clone, Hash, Default)]
pub struct Ed25519Compressed([u8; 32]);

impl Ed25519 {
Expand Down Expand Up @@ -103,7 +107,7 @@ impl Ed25519 {
.skip(3)
{
acc = acc.double();
acc += Ed25519::conditional_select(&zero, &self, bit);
acc += Ed25519::conditional_select(&zero, self, bit);
}

acc
Expand Down Expand Up @@ -155,12 +159,6 @@ impl Ed25519 {
}
}

impl Ed25519 {
fn endomorphism_base(&self) -> Self {
unimplemented!();
}
}

impl Ed25519Affine {
/// Constructs the neutral element `(0, 1)`.
pub const fn identity() -> Self {
Expand Down Expand Up @@ -287,12 +285,6 @@ impl std::fmt::Debug for Ed25519Compressed {
}
}

impl Default for Ed25519Compressed {
fn default() -> Self {
Ed25519Compressed([0; 32])
}
}

impl AsRef<[u8]> for Ed25519Compressed {
fn as_ref(&self) -> &[u8] {
&self.0
Expand Down Expand Up @@ -357,8 +349,13 @@ impl CurveExt for Ed25519 {

const CURVE_ID: &'static str = "ed25519";

fn is_on_curve(&self) -> Choice {
let affine = Ed25519Affine::from(*self);
!self.z.is_zero() & affine.is_on_curve() & (affine.x * affine.y * self.z).ct_eq(&self.t)
shuklaayush marked this conversation as resolved.
Show resolved Hide resolved
}

fn endo(&self) -> Self {
self.endomorphism_base()
unimplemented!();
}

fn jacobian_coordinates(&self) -> (Fq, Fq, Fq) {
Expand All @@ -369,20 +366,12 @@ impl CurveExt for Ed25519 {
unimplemented!();
}

fn is_on_curve(&self) -> Choice {
let affine = Ed25519Affine::from(*self);

println!("affine: {:?}", affine);

!self.z.is_zero() & affine.is_on_curve() & (affine.x * affine.y * self.z).ct_eq(&self.t)
}

fn a() -> Self::Base {
unimplemented!()
}

fn b() -> Self::Base {
ED25519_D
unimplemented!()
}

fn new_jacobian(_x: Self::Base, _y: Self::Base, _z: Self::Base) -> CtOption<Self> {
Expand All @@ -408,8 +397,8 @@ impl group::Curve for Ed25519 {
let tmp = q.x;

// Set the coordinates to the correct value
q.x = p.x * &tmp; // Multiply by 1/z
q.y = p.y * &tmp; // Multiply by 1/z
q.x = p.x * tmp; // Multiply by 1/z
q.y = p.y * tmp; // Multiply by 1/z
}
}

Expand Down Expand Up @@ -482,7 +471,7 @@ impl crate::serde::SerdeObject for Ed25519 {
x.zip(y).zip(z).zip(t).and_then(|(((x, y), z), t)| {
let res = Self { x, y, z, t };
// Check that the point is on the curve.
bool::from(res.is_on_curve()).then(|| res)
bool::from(res.is_on_curve()).then_some(res)
})
}
fn to_raw_bytes(&self) -> Vec<u8> {
Expand Down Expand Up @@ -601,7 +590,7 @@ impl crate::serde::SerdeObject for Ed25519Affine {
x.zip(y).and_then(|(x, y)| {
let res = Self { x, y };
// Check that the point is on the curve.
bool::from(res.is_on_curve()).then(|| res)
bool::from(res.is_on_curve()).then_some(res)
})
}
fn to_raw_bytes(&self) -> Vec<u8> {
Expand Down Expand Up @@ -697,7 +686,7 @@ impl CurveAffine for Ed25519Affine {
}

fn b() -> Self::Base {
ED25519_D
unimplemented!()
}
}

Expand Down Expand Up @@ -916,6 +905,36 @@ impl CurveAffineExt for Ed25519Affine {
}
}

pub trait TwistedEdwardsCurveExt: CurveExt {
fn a() -> <Self as CurveExt>::Base;
fn d() -> <Self as CurveExt>::Base;
}

impl TwistedEdwardsCurveExt for Ed25519 {
fn a() -> Fq {
-Fq::ONE
}

fn d() -> Fq {
ED25519_D
}
}

pub trait TwistedEdwardsCurveAffineExt: CurveAffineExt {
fn a() -> <Self as CurveAffine>::Base;
fn d() -> <Self as CurveAffine>::Base;
}

impl TwistedEdwardsCurveAffineExt for Ed25519Affine {
fn a() -> Fq {
-Fq::ONE
}

fn d() -> Fq {
ED25519_D
}
}

#[test]
fn test_is_on_curve() {
assert!(bool::from(Ed25519Affine::identity().is_on_curve()));
Expand Down
71 changes: 48 additions & 23 deletions src/ed25519/fq.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use core::convert::TryInto;
use core::fmt;
use core::ops::{Add, Mul, Neg, Sub};

use ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
use rand::RngCore;
use serde::{Deserialize, Serialize};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

#[cfg(feature = "derive_serde")]
use serde::{Deserialize, Serialize};

use crate::arithmetic::{adc, mac, macx, sbb};

/// This represents an element of $\mathbb{F}_q$ where
Expand All @@ -17,7 +18,8 @@ use crate::arithmetic::{adc, mac, macx, sbb};
// The internal representation of this type is four 64-bit unsigned
// integers in little-endian order. `Fq` values are always in
// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256.
#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
pub struct Fq(pub(crate) [u64; 4]);

/// Constant representing the modulus
Expand Down Expand Up @@ -45,11 +47,11 @@ const MODULUS_LIMBS_32: [u32; 8] = [
/// Constant representing the modulus as static str
const MODULUS_STR: &str = "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed";

/// Obtained with:
/// `sage: GF(57896044618658097711785492504343953926634992332820282019728792003956564819949).primitive_element()`
/// Obtained with sage:
/// `GF(q).primitive_element()`
const MULTIPLICATIVE_GENERATOR: Fq = Fq::from_raw([0x02, 0x0, 0x0, 0x0]);

/// INV = -(p^{-1} mod 2^64) mod 2^64
/// INV = -(q^{-1} mod 2^64) mod 2^64
const INV: u64 = 0x86bca1af286bca1b;

/// R = 2^256 mod q
Expand All @@ -72,20 +74,45 @@ const TWO_INV: Fq = Fq::from_raw([
0x3fffffffffffffff,
]);

/// sqrt(-1) mod q = 2^((p - 1) / 4) mod q
/// sqrt(-1) mod q = 2^((q - 1) / 4) mod q
const SQRT_MINUS_ONE: Fq = Fq::from_raw([
0xc4ee1b274a0ea0b0,
0x2f431806ad2fe478,
0x2b4d00993dfbd7a7,
0x2b8324804fc1df0b,
]);

/// TODO
const ZETA: Fq = Fq::zero();
/// TODO
const DELTA: Fq = Fq::zero();
/// TODO
const ROOT_OF_UNITY_INV: Fq = Fq::zero();
// Element in small order subgroup (3-order)
// Sage:
// `GF(q).primitive_element() ** ((q - 1) // N)` where N = 3
const ZETA: Fq = Fq::from_raw([
shuklaayush marked this conversation as resolved.
Show resolved Hide resolved
0xaa86d89d8618e538,
0x1a1aada8413a4550,
0xd9872fccc55bd529,
0x381cba36aa6565b5,
]);
// The `2^s` root of unity.
// It can be calculated by exponentiating `MULTIPLICATIVE_GENERATOR` by `t`,
// where `2^s * t = q - 1` with `t` odd.
// Sage:
// `GF(q).primitive_element() ** t`
const ROOT_OF_UNITY: Fq = Fq::from_raw([
0xc4ee1b274a0ea0b0,
0x2f431806ad2fe478,
0x2b4d00993dfbd7a7,
0x2b8324804fc1df0b,
]);
// Inverse of `ROOT_OF_UNITY`
const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([
0x3b11e4d8b5f15f3d,
0xd0bce7f952d01b87,
0xd4b2ff66c2042858,
0x547cdb7fb03e20f4,
]);
// Generator of the `t-order` multiplicative subgroup
// Sage:
// `GF(q).primitive_element() ** (2**s)`
const DELTA: Fq = Fq::from_raw([0x10, 0, 0, 0]);

use crate::{
field_arithmetic, field_common, field_specific, impl_add_binop_specify_output,
Expand Down Expand Up @@ -151,14 +178,14 @@ impl ff::Field for Fq {
// = a^((q + 3) / 8) * (2^((q - 1) / 4))
// OR
// Doesn't exist
let x1 = self.pow(&[
let x1 = self.pow([
0xfffffffffffffffe,
0xffffffffffffffff,
0xffffffffffffffff,
0x0fffffffffffffff,
]);

let choice1 = x1.square().ct_eq(&self);
let choice1 = x1.square().ct_eq(self);
let choice2 = x1.square().ct_eq(&-self);

let sqrt = Self::conditional_select(&x1, &(x1 * SQRT_MINUS_ONE), choice2);
Expand Down Expand Up @@ -206,17 +233,16 @@ impl ff::Field for Fq {
impl ff::PrimeField for Fq {
type Repr = [u8; 32];

const MODULUS: &'static str = MODULUS_STR;
const NUM_BITS: u32 = 256;
const CAPACITY: u32 = 255;
const MODULUS: &'static str = MODULUS_STR;
const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR;
/// TODO
const ROOT_OF_UNITY: Self = Self::one();
/// TODO
const ROOT_OF_UNITY_INV: Self = Self::zero();
const TWO_INV: Self = TWO_INV;
const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR;
// An integer `s` satisfying the equation `2^s * t = modulus - 1` with `t` odd.
const S: u32 = 2;
const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
const DELTA: Self = DELTA;
const S: u32 = 1;

fn from_repr(repr: Self::Repr) -> CtOption<Self> {
let mut tmp = Fq([0, 0, 0, 0]);
Expand Down Expand Up @@ -281,7 +307,6 @@ impl FromUniformBytes<64> for Fq {
}

impl WithSmallOrderMulGroup<3> for Fq {
/// TODO
const ZETA: Self = ZETA;
}

Expand Down
Loading
Loading