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

Implement new_from_x for AffinePoint to create a new point from compressed representation. #115

Closed
wants to merge 4 commits into from
Closed
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
138 changes: 132 additions & 6 deletions crates/starknet-types-core/src/curve/affine_point.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use crate::curve::curve_errors::CurveError;
use crate::felt::Felt;
use lambdaworks_math::cyclic_group::IsGroup;
use lambdaworks_math::elliptic_curve::short_weierstrass::curves::stark_curve::StarkCurve;
use lambdaworks_math::elliptic_curve::short_weierstrass::point::ShortWeierstrassProjectivePoint;
use lambdaworks_math::elliptic_curve::traits::FromAffine;
use crate::{curve::curve_errors::CurveError, felt::Felt};
use lambdaworks_math::{
cyclic_group::IsGroup,
elliptic_curve::{
short_weierstrass::{
curves::stark_curve::StarkCurve, point::ShortWeierstrassProjectivePoint,
traits::IsShortWeierstrass,
},
traits::{FromAffine, IsEllipticCurve},
},
};

/// Represents a point on the Stark elliptic curve.
/// Doc: https://docs.starkware.co/starkex/crypto/stark-curve.html
Expand All @@ -29,6 +34,28 @@ impl AffinePoint {
]))
}

/// Construct new affine point from the `x` coordinate and the parity bit.
/// If the parity bit is false, choose the y-coordinate with even parity.
/// If the parity bit is true, choose the y-coordinate with odd parity.
pub fn new_from_x(x: &Felt, y_parity: bool) -> Option<Self> {
// right hand side of the stark curve equation `y^2 = x^3 + α*x + β (mod p)`.
let rhs = x * x * x + Felt(StarkCurve::a()) * x + Felt(StarkCurve::b());

let (root_1, root_2) = rhs.0.sqrt()?;

let root_1_le_bits = root_1.to_bits_le();
let first_bit = root_1_le_bits.first()?;

let y = if *first_bit == y_parity {
root_1
} else {
root_2
};

// the curve equation is already satisfied above and is safe to create a new unchecked point
Some(Self::new_unchecked(*x, Felt(y)))
}

/// The point at infinity.
pub fn identity() -> AffinePoint {
Self(ShortWeierstrassProjectivePoint::neutral_element())
Expand All @@ -47,6 +74,11 @@ impl AffinePoint {
pub fn y(&self) -> Felt {
Felt(*self.0.y())
}

// Returns the generator point of the StarkCurve
pub fn generator() -> Self {
AffinePoint(StarkCurve::generator())
}
}

impl core::ops::Neg for &AffinePoint {
Expand All @@ -57,8 +89,26 @@ impl core::ops::Neg for &AffinePoint {
}
}

impl core::ops::Add<AffinePoint> for AffinePoint {
type Output = AffinePoint;

fn add(self, rhs: Self) -> Self::Output {
AffinePoint(self.0.operate_with_affine(&rhs.0))
}
}

impl core::ops::Mul<Felt> for &AffinePoint {
type Output = AffinePoint;

// Add the point (`self`) to itself for `scalar` many times
fn mul(self, rhs: Felt) -> AffinePoint {
AffinePoint(self.0.operate_with_self(rhs.0.representative()))
}
}

#[cfg(test)]
mod test {
use std::ops::Neg;
use super::*;

#[test]
Expand Down Expand Up @@ -117,4 +167,80 @@ mod test {
);
assert_eq!(-&AffinePoint::identity(), AffinePoint::identity());
}

#[test]
fn affine_add() {
let p = AffinePoint::new(
Felt::from_hex_unchecked("0x2d39148a92f479fb077389d"),
Felt::from_hex_unchecked(
"0x6e5d97edf7283fe7a7fe9deef2619224f42cb1bd531dd23380ad066c61ee20b",
),
)
.unwrap();

assert_eq!(
p.clone() + p,
AffinePoint::new(
Felt::from_hex_unchecked(
"0x23a1c9a32dd397fb1e7f758b9089757c1223057aea1d8b52cbec583ad74eaab",
),
Felt::from_hex_unchecked(
"0x466880caf4086bac129ae52ee98ddf75b2b394ae7c7ed1a19d9c61aa1f69f62",
),
)
.unwrap()
);
}

#[test]
fn affine_mul() {
let p = AffinePoint::new(
Felt::from_hex_unchecked("0x2d39148a92f479fb077389d"),
Felt::from_hex_unchecked(
"0x6e5d97edf7283fe7a7fe9deef2619224f42cb1bd531dd23380ad066c61ee20b",
),
)
.unwrap();

assert_eq!(
&p * Felt::from(2),
AffinePoint::new(
Felt::from_hex_unchecked(
"0x23a1c9a32dd397fb1e7f758b9089757c1223057aea1d8b52cbec583ad74eaab",
),
Felt::from_hex_unchecked(
"0x466880caf4086bac129ae52ee98ddf75b2b394ae7c7ed1a19d9c61aa1f69f62",
),
)
.unwrap()
);
}

#[test]
fn affine_new_from_x_odd() {
let p = AffinePoint::new(
Felt::from_hex_unchecked("0x2d39148a92f479fb077389d"),
Felt::from_hex_unchecked(
"0x6e5d97edf7283fe7a7fe9deef2619224f42cb1bd531dd23380ad066c61ee20b",
),
)
.unwrap();

let x = p.x();
assert_eq!(p, AffinePoint::new_from_x(&x, true).unwrap());
}

#[test]
fn affine_new_from_x_even() {
let p = AffinePoint::new(
Felt::from_hex_unchecked("0x2d39148a92f479fb077389d"),
Felt::from_hex_unchecked(
"0x6e5d97edf7283fe7a7fe9deef2619224f42cb1bd531dd23380ad066c61ee20b",
),
)
.unwrap();

let x = p.x();
assert_eq!(p.neg(), AffinePoint::new_from_x(&x, false).unwrap());
}
}