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

feat: algebra #135

Merged
merged 16 commits into from
Jul 31, 2024
8 changes: 5 additions & 3 deletions src/curve/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ When working over a finite field so that $x, y a, b \in \mathbb{F}_q$, we put $E
It turns out that the set of points $E(\mathbb{F}_q)$ forms a group under a certain operation called point addition.
This group, in at least certain cases, is discrete logarithm hard, which is the basis for much of modern day cryptography.

## Pluto Curve
## Curve Group and Pluto Curve
For the sake of `ronkathon`, we use a specific curve which we affectionately call the "Pluto Curve."
Our equation is:
$$y^2 = x^3 + 3$$
Expand All @@ -14,6 +14,8 @@ Predominantly, we use the extension $F_{p^2}$ since we need this for the [Tate p
We refer to $F_{101}$ as the `PlutoBaseField` and $F_{101^2}$ as the `PlutoBaseFieldExtension` within `ronkathon`.
From which, we also use the terminology of `PlutoCurve` to refer to $E(F_{101})$ and `PlutoExtendedCurve` to refer to $E(F_{101^2})$.

We also define a `CurveGroup`, an extension of [`FiniteGroup`](../field/group.rs) trait representing the group law of the curve.

### Type B curve and type 1 pairing

Investigating our curve and choice of field, we find that the curve is Type B since:
Expand Down Expand Up @@ -63,11 +65,11 @@ Here are a few related definitions that might be helpful to understand the curve

### roots of unity

the $rth$ root of unity in $F_p$ is some number $h$ such that $h^r \equiv 1$, For example in our field scaler field $F_{101}$ the $4th$ roots of unity are $\{1,10,91,100\}$.
the $rth$ root of unity in $F_p$ is some number $h$ such that $h^r \equiv 1$, For example in our field scaler field $F_{101}$ the $4th$ roots of unity are $\{1,10,91,100\}$.

### $r$-torsion

$r$-torsion points are points $P \in E(K) | rP = O$ for some point $P$ so that $P$ has order $r$ or is a factor of $r$. The set of r-torsion points in $E(K)$ is denoted $E(K)[r]$. If $\bar{K}$ is the [algebraic closure](https://en.wikipedia.org/wiki/Algebraic_closure) of $K$ then the number of r-torsion points in $E(K)$ is the number of points in $E(\bar{K})[r] = r^2$.
$r$-torsion points are points $P \in E(K) | rP = O$ for some point $P$ so that $P$ has order $r$ or is a factor of $r$. The set of r-torsion points in $E(K)$ is denoted $E(K)[r]$. If $\bar{K}$ is the [algebraic closure](https://en.wikipedia.org/wiki/Algebraic_closure) of $K$ then the number of r-torsion points in $E(K)$ is the number of points in $E(\bar{K})[r] = r^2$.

- *Security note: If* $r$ and $q$ are not co-prime then the discrete log is solvable in linear time with something called an anomaly attack.

Expand Down
170 changes: 114 additions & 56 deletions src/curve/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! Elliptic curve operations and types.

use field::group::FiniteGroup;
use fmt::Debug;

use self::field::prime::PlutoScalarField;
use super::*;

Expand All @@ -9,12 +12,16 @@ pub mod pluto_curve;

/// Elliptic curve parameters for a curve over a finite field in Weierstrass form
/// `y^2 = x^3 + ax + b`
pub trait EllipticCurve: Copy {
pub trait EllipticCurve: Copy + Debug + Eq {
/// The field for the curve coefficients.
type Coefficient: FiniteField + Into<Self::BaseField>;

/// Integer field element type
type BaseField: FiniteField;
/// curve base field element type
/// TODO: need to be converted for big integers later
type BaseField: FiniteField + Into<usize>;

/// Curve scalar field type
type ScalarField: FiniteField + Into<usize>;

/// Order of this elliptic curve, i.e. number of elements in the scalar field.
const ORDER: usize;
Expand All @@ -29,6 +36,20 @@ pub trait EllipticCurve: Copy {
const GENERATOR: (Self::BaseField, Self::BaseField);
}

/// Curve group representing curve element
pub trait CurveGroup: FiniteGroup {
/// Curve group's base field
type BaseField: FiniteField + Into<usize>;

/// Point doubling
fn double(self) -> Self;
/// Checks whether a point is on curve
fn is_on_curve(&self) -> bool;

/// Returns affine point `(x, y)`, returns `(_, _, true)` if point is `infinity`
fn xy(&self) -> (Self::BaseField, Self::BaseField, bool);
}

// TODO: A potential issue here is that you can have a point that is not on the curve created via
// this enum. This is a potential issue that should be addressed.
/// An Affine Coordinate Point on a Weierstrass elliptic curve
Expand All @@ -44,17 +65,98 @@ pub enum AffinePoint<C: EllipticCurve> {
impl<C: EllipticCurve> AffinePoint<C> {
/// Create a new point on the curve so long as it satisfies the curve equation.
pub fn new(x: C::BaseField, y: C::BaseField) -> Self {
assert_eq!(
y * y,
x * x * x + C::EQUATION_A.into() * x + C::EQUATION_B.into(),
"Point is not on curve"
);
Self::Point(x, y)
let point = Self::Point(x, y);
assert!(point.is_on_curve(), "Point is not on curve");
point
}
}

impl<C: EllipticCurve> FiniteGroup for AffinePoint<C> {
type Scalar = C::ScalarField;

const GENERATOR: Self = AffinePoint::Point(C::GENERATOR.0, C::GENERATOR.1);
const IDENTITY: Self = AffinePoint::Infinity;
const ORDER: usize = C::ORDER;

fn operation(a: &Self, b: &Self) -> Self { AffinePoint::add(*a, *b) }

fn inverse(&self) -> Self {
let (x, y) = match self {
AffinePoint::Infinity => return *self,
AffinePoint::Point(x, y) => (*x, *y),
};
AffinePoint::Point(-x, y)
}

fn scalar_mul(&self, b: &Self::Scalar) -> Self { *self * *b }
}

impl<C: EllipticCurve> CurveGroup for AffinePoint<C> {
type BaseField = C::BaseField;

// NOTE: Apparently there is a faster way to do this with twisted curve methods
fn double(self) -> Self {
let (x, y) = match self {
AffinePoint::Point(x, y) => (x, y),
AffinePoint::Infinity => return AffinePoint::Infinity,
};
// m = (3x^2) / (2y)
let m = (((C::BaseField::ONE + C::BaseField::ONE) + C::BaseField::ONE) * x * x
+ C::EQUATION_A.into())
/ ((C::BaseField::ONE + C::BaseField::ONE) * y);

// 2P = (m^2 - 2x, m(3x - m^2)- y)
let x_new = m * m - (C::BaseField::ONE + C::BaseField::ONE) * x;
let y_new = m * ((C::BaseField::ONE + C::BaseField::ONE + C::BaseField::ONE) * x - m * m) - y;
AffinePoint::new(x_new, y_new)
}

fn is_on_curve(&self) -> bool {
match self {
AffinePoint::Infinity => true,
AffinePoint::Point(x, y) => {
let a: C::BaseField = C::EQUATION_A.into();
let b: C::BaseField = C::EQUATION_B.into();
*y * *y == *x * *x * *x + a * *x + b
},
}
}

fn xy(&self) -> (Self::BaseField, Self::BaseField, bool) {
match self {
AffinePoint::Infinity => (Self::BaseField::ZERO, Self::BaseField::ZERO, true),
AffinePoint::Point(x, y) => (*x, *y, false),
}
}
}

impl<C: EllipticCurve> Default for AffinePoint<C> {
fn default() -> Self { <Self as FiniteGroup>::GENERATOR }
}

impl<C: EllipticCurve> Mul<C::ScalarField> for AffinePoint<C> {
type Output = Self;

/// This is the naive implementation of scalar multiplication
/// There is a faster way to do this but this is simpler to reason about for now
fn mul(self, rhs: C::ScalarField) -> Self::Output {
if rhs == C::ScalarField::ZERO {
return AffinePoint::Infinity;
}
let mut val = self;
for _ in 1..rhs.into() {
val += self;
}
val
}
}

impl<C: EllipticCurve> MulAssign<C::ScalarField> for AffinePoint<C> {
fn mul_assign(&mut self, rhs: C::ScalarField) { *self = *self * rhs }
}

impl<C: EllipticCurve> Add for AffinePoint<C> {
type Output = AffinePoint<C>;
type Output = Self;

fn add(self, rhs: Self) -> Self::Output {
// infty checks
Expand Down Expand Up @@ -112,34 +214,16 @@ impl<C: EllipticCurve> Neg for AffinePoint<C> {
}
}

/// This is the niave implementation of scalar multiplication
/// There is a faster way to do this but this is simpler to reason about for now
#[allow(clippy::suspicious_arithmetic_impl)]
impl<C: EllipticCurve> Mul<u32> for AffinePoint<C> {
type Output = AffinePoint<C>;

fn mul(mut self, scalar: u32) -> Self::Output {
if scalar == 0 {
return AffinePoint::Infinity;
}
let val = self;
for _ in 1..scalar {
self += val;
}
self
}
}

impl<C: EllipticCurve> Sub for AffinePoint<C> {
type Output = AffinePoint<C>;

fn sub(self, rhs: Self) -> Self::Output { self + -rhs }
}

impl<C: EllipticCurve> Mul<PlutoScalarField> for AffinePoint<C> {
type Output = AffinePoint<C>;

fn mul(self, scalar: PlutoScalarField) -> Self::Output { scalar.value as u32 * self }
impl<C: EllipticCurve> SubAssign for AffinePoint<C> {
fn sub_assign(&mut self, rhs: Self) { *self = *self - rhs; }
}

#[allow(clippy::suspicious_arithmetic_impl)]
Expand All @@ -157,29 +241,3 @@ impl<C: EllipticCurve> std::ops::Mul<AffinePoint<C>> for u32 {
out
}
}

// NOTE: Apparently there is a faster way to do this with twisted curve methods
impl<C: EllipticCurve> AffinePoint<C> {
/// Compute the point doubling operation on this point.
pub fn point_doubling(self) -> AffinePoint<C> {
let (x, y) = match self {
AffinePoint::Point(x, y) => (x, y),
AffinePoint::Infinity => return AffinePoint::Infinity,
};
// m = (3x^2) / (2y)
let m = (((C::BaseField::ONE + C::BaseField::ONE) + C::BaseField::ONE) * x * x
+ C::EQUATION_A.into())
/ ((C::BaseField::ONE + C::BaseField::ONE) * y);

// 2P = (m^2 - 2x, m(3x - m^2)- y)
let x_new = m * m - (C::BaseField::ONE + C::BaseField::ONE) * x;
let y_new = m * ((C::BaseField::ONE + C::BaseField::ONE + C::BaseField::ONE) * x - m * m) - y;
AffinePoint::new(x_new, y_new)
}

/// Get the generator point of this curve.
pub fn generator() -> Self {
let (x, y) = C::GENERATOR;
AffinePoint::new(x, y)
}
}
22 changes: 11 additions & 11 deletions src/curve/pairing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,10 @@ mod tests {

#[test]
fn torsion_generators() {
let generator = AffinePoint::<PlutoBaseCurve>::generator();
let generator = AffinePoint::<PlutoBaseCurve>::GENERATOR;
println!("Generator: {:?}", generator);
for i in 1..PlutoPrime::Scalar as usize + 1 {
let point = generator * i as u32;
let point = generator * PlutoScalarField::new(i);
println!("{:?} * P = {:?}", i, point);
if i == PlutoPrime::Scalar as usize {
assert_eq!(point, AffinePoint::Infinity);
Expand All @@ -281,7 +281,7 @@ mod tests {

let cube_root_of_unity = PlutoBaseFieldExtension::primitive_root_of_unity(3);
let torsion_generator = if let AffinePoint::<PlutoBaseCurve>::Point(x, y) =
AffinePoint::<PlutoBaseCurve>::generator()
AffinePoint::<PlutoBaseCurve>::GENERATOR
{
AffinePoint::<PlutoExtendedCurve>::new(
cube_root_of_unity * PlutoBaseFieldExtension::from(x),
Expand All @@ -291,7 +291,7 @@ mod tests {
panic!("Generator is not a point");
};
for i in 1..PlutoPrime::Scalar as usize + 1 {
let point = torsion_generator * i as u32;
let point = torsion_generator * PlutoScalarField::new(i);
println!("{:?} * P = {:?}", i, point);
if i == PlutoPrime::Scalar as usize {
assert_eq!(point, AffinePoint::Infinity);
Expand All @@ -305,10 +305,10 @@ mod tests {

#[test]
fn pairing_test() {
let p = AffinePoint::<PlutoExtendedCurve>::from(AffinePoint::<PlutoBaseCurve>::generator());
let p = AffinePoint::<PlutoExtendedCurve>::from(AffinePoint::<PlutoBaseCurve>::GENERATOR);
let cube_root_of_unity = PlutoBaseFieldExtension::primitive_root_of_unity(3);
let q = if let AffinePoint::<PlutoBaseCurve>::Point(x, y) =
AffinePoint::<PlutoBaseCurve>::generator()
AffinePoint::<PlutoBaseCurve>::GENERATOR
{
AffinePoint::<PlutoExtendedCurve>::new(
cube_root_of_unity * PlutoBaseFieldExtension::from(x),
Expand Down Expand Up @@ -358,10 +358,10 @@ mod tests {

#[test]
fn weil_from_tate_paring() {
let p = AffinePoint::<PlutoExtendedCurve>::from(AffinePoint::<PlutoBaseCurve>::generator());
let p = AffinePoint::<PlutoExtendedCurve>::from(AffinePoint::<PlutoBaseCurve>::GENERATOR);
let cube_root_of_unity = PlutoBaseFieldExtension::primitive_root_of_unity(3);
let q = if let AffinePoint::<PlutoBaseCurve>::Point(x, y) =
AffinePoint::<PlutoBaseCurve>::generator()
AffinePoint::<PlutoBaseCurve>::GENERATOR
{
AffinePoint::<PlutoExtendedCurve>::new(
cube_root_of_unity * PlutoBaseFieldExtension::from(x),
Expand Down Expand Up @@ -391,10 +391,10 @@ mod tests {
let a = PlutoScalarField::new(3);
let b = PlutoScalarField::new(5);

let p = AffinePoint::<PlutoExtendedCurve>::from(AffinePoint::<PlutoBaseCurve>::generator());
let p = AffinePoint::<PlutoExtendedCurve>::from(AffinePoint::<PlutoBaseCurve>::GENERATOR);
let cube_root_of_unity = PlutoBaseFieldExtension::primitive_root_of_unity(3);
let q = if let AffinePoint::<PlutoBaseCurve>::Point(x, y) =
AffinePoint::<PlutoBaseCurve>::generator()
AffinePoint::<PlutoBaseCurve>::GENERATOR
{
AffinePoint::<PlutoExtendedCurve>::new(
cube_root_of_unity * PlutoBaseFieldExtension::from(x),
Expand All @@ -417,7 +417,7 @@ mod tests {
assert_eq!(lhs, rhs);

let r = if let AffinePoint::<PlutoBaseCurve>::Point(x, y) =
AffinePoint::<PlutoBaseCurve>::generator().point_doubling()
AffinePoint::<PlutoBaseCurve>::GENERATOR.double()
{
AffinePoint::<PlutoExtendedCurve>::new(
cube_root_of_unity * PlutoBaseFieldExtension::from(x),
Expand Down
Loading