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

Add curves #912

Merged
merged 9 commits into from
Sep 16, 2024
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ List of symbols:
| Pallas | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| Vesta | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| Bandersnatch | 🏗️ | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| secp256k1 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| **STARKs** | **Lambdaworks** | **Arkworks** | **Halo2** | **gnark** | **Constantine** |
| STARK Prover | :heavy_check_mark: | :x: | :x: | :x: | :x: |
| CAIRO Prover | 🏗️ | :x: | :x: | :x: | :x: |
Expand Down
3 changes: 3 additions & 0 deletions math/src/elliptic_curve/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The following curves are currently supported:
- [Pallas](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve/short_weierstrass/curves/pallas), useful for recursive SNARKs when used with Vesta.
- [Vesta](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve/short_weierstrass/curves/vesta), useful for recursive SNARKs when used with Pallas.
- [Starknet's curve](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/stark_curve.rs)
- [secp256k1](./short_weierstrass/curves/secp256k1/curve.rs): Bitcoin's curve. The implementation is not constant time, so it cannot be used to sign messages!

## Twisted Edwards

Expand Down Expand Up @@ -170,3 +171,5 @@ In many curves, the base field contains some spare bits (as is the case of BLS12
- [What every developer needs to know about elliptic curves](https://blog.lambdaclass.com/what-every-developer-needs-to-know-about-elliptic-curves/)
- [How we implemented the BN254 Ate pairing in lambdaworks](https://blog.lambdaclass.com/how-we-implemented-the-bn254-ate-pairing-in-lambdaworks/)
- [Exploring elliptic curve pairings by Vitalik](https://medium.com/@VitalikButerin/exploring-elliptic-curve-pairings-c73c1864e627)
- [A survey of elliptic curves for proof systems](https://eprint.iacr.org/2022/586.pdf)
- [Taxonomy of pairing-friendly elliptic curves](https://eprint.iacr.org/2006/372.pdf)
1 change: 1 addition & 0 deletions math/src/elliptic_curve/short_weierstrass/curves/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod bls12_381;
pub mod bn_254;
pub mod grumpkin;
pub mod pallas;
pub mod secp256k1;
pub mod stark_curve;
pub mod test_curve_1;
pub mod test_curve_2;
Expand Down
165 changes: 165 additions & 0 deletions math/src/elliptic_curve/short_weierstrass/curves/secp256k1/curve.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
use crate::elliptic_curve::short_weierstrass::point::ShortWeierstrassProjectivePoint;
use crate::elliptic_curve::traits::IsEllipticCurve;
use crate::field::fields::secp256k1_field::Secp256k1PrimeField;
use crate::{
elliptic_curve::short_weierstrass::traits::IsShortWeierstrass, field::element::FieldElement,
};

/// This implementation is not constant time and cannot be used to sign messages. You can use it to check signatures
#[derive(Clone, Debug)]
pub struct Secp256k1Curve;

impl IsEllipticCurve for Secp256k1Curve {
type BaseField = Secp256k1PrimeField;
type PointRepresentation = ShortWeierstrassProjectivePoint<Self>;

fn generator() -> Self::PointRepresentation {
Self::PointRepresentation::new([
FieldElement::<Self::BaseField>::from_hex_unchecked(
"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
),
FieldElement::<Self::BaseField>::from_hex_unchecked(
"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
),
FieldElement::one(),
])
}
}

impl IsShortWeierstrass for Secp256k1Curve {
fn a() -> FieldElement<Self::BaseField> {
FieldElement::from(0)
}

fn b() -> FieldElement<Self::BaseField> {
FieldElement::from(7)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{
cyclic_group::IsGroup, elliptic_curve::traits::EllipticCurveError,
field::element::FieldElement, unsigned_integer::element::U256,
};

use super::Secp256k1Curve;

#[allow(clippy::upper_case_acronyms)]
type FE = FieldElement<Secp256k1PrimeField>;

fn point_1() -> ShortWeierstrassProjectivePoint<Secp256k1Curve> {
let x = FE::from_hex_unchecked(
"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
);
let y = FE::from_hex_unchecked(
"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
);
Secp256k1Curve::create_point_from_affine(x, y).unwrap()
}

fn point_1_times_5() -> ShortWeierstrassProjectivePoint<Secp256k1Curve> {
let x = FE::from_hex_unchecked(
"2F8BDE4D1A07209355B4A7250A5C5128E88B84BDDC619AB7CBA8D569B240EFE4",
);
let y = FE::from_hex_unchecked(
"D8AC222636E5E3D6D4DBA9DDA6C9C426F788271BAB0D6840DCA87D3AA6AC62D6",
);
Secp256k1Curve::create_point_from_affine(x, y).unwrap()
}

#[test]
fn adding_five_times_point_1_works() {
let point_1 = point_1();
let point_1_times_5 = point_1_times_5();
assert_eq!(point_1.operate_with_self(5_u16), point_1_times_5);
}

#[test]
fn create_valid_point_works() {
let p = point_1();
assert_eq!(
*p.x(),
FE::from_hex_unchecked(
"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
)
);
assert_eq!(
*p.y(),
FE::from_hex_unchecked(
"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"
)
);
assert_eq!(*p.z(), FE::from_hex_unchecked("1"));
}

#[test]
fn create_invalid_points_returns_an_error() {
assert_eq!(
Secp256k1Curve::create_point_from_affine(FE::from(0), FE::from(1)),
Err(EllipticCurveError::InvalidPoint)
);
}

#[test]
fn equality_works() {
let g = Secp256k1Curve::generator();
let g2 = g.operate_with_self(2_u16);
let g2_other = g.operate_with(&g);
assert_ne!(&g2, &g);
assert_eq!(&g, &g);
assert_eq!(&g2, &g2_other);
}

#[test]
fn g_operated_with_g_satifies_ec_equation() {
let g = Secp256k1Curve::generator();
let g2 = g.operate_with_self(2_u16);

// get x and y from affine coordinates
let g2_affine = g2.to_affine();
let x = g2_affine.x();
let y = g2_affine.y();

// calculate both sides of secp256k1 curve equation
let five = Secp256k1Curve::b();
let y_sq_0 = x.pow(3_u16) + five;
let y_sq_1 = y.pow(2_u16);

assert_eq!(y_sq_0, y_sq_1);
}

#[test]
fn operate_with_self_works_1() {
let g = Secp256k1Curve::generator();
assert_eq!(
g.operate_with(&g).operate_with(&g),
g.operate_with_self(3_u16)
);
}

#[test]
fn generator_has_right_order() {
let g = Secp256k1Curve::generator();
assert_eq!(
g.operate_with_self(U256::from_hex_unchecked(
"fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
))
.to_affine(),
ShortWeierstrassProjectivePoint::neutral_element()
);
}

#[test]
fn inverse_works() {
let g = Secp256k1Curve::generator();
assert_eq!(
g.operate_with_self(U256::from_hex_unchecked(
"fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413C"
))
.to_affine(),
g.operate_with_self(5u64).neg().to_affine()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod curve;
10 changes: 6 additions & 4 deletions math/src/field/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ This folder contains the different field backends, including field extensions. T
- [Base field of BLS12-381](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs) and its quadratic, sextic and twelth degree extensions.
- [Scalar field of BLS12-377](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/curve.rs)
- [Base field of BLS12-377](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/field_extension.rs)
- [Base field of secp256k1](./fields/secp256k1_field.rs): the base field of Bitcoin's elliptic curve.
- [Scalar field of secp256k1](./fields/secp256k1_scalarfield.rs): the scalar field of Bitcoin's elliptic curve.

You also have the tooling to define quadratic and cubic extension fields.

Expand All @@ -27,11 +29,11 @@ Differences of 3% are common for some measurements, so small differences are not

ARM - M1

| Operation| N | Arkworks | lambdaworks |
| -------- | --- | --------- | ----------- |
| Operation| N | Arkworks | lambdaworks |
| -------- | --- | --------- | ----------- |
| `mul` | 10k | 112 μs | 115 μs |
| `add` | 1M | 8.5 ms | 7.0 ms |
| `sub` | 1M | 7.53 ms | 7.12 ms |
| `add` | 1M | 8.5 ms | 7.0 ms |
| `sub` | 1M | 7.53 ms | 7.12 ms |
| `pow` | 10k | 11.2 ms | 12.4 ms |
| `invert` | 10k | 30.0 ms | 27.2 ms |

Expand Down
4 changes: 4 additions & 0 deletions math/src/field/fields/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ pub mod montgomery_backed_prime_fields;
pub mod p448_goldilocks_prime_field;
/// Implemenation of Pallas field
pub mod pallas_field;
/// Implementation of secp256k1 base field.
pub mod secp256k1_field;
/// Implementation of secp256k1 scalar field.
pub mod secp256k1_scalarfield;
/// Implementation of the u64 Goldilocks Prime field (p = 2^64 - 2^32 + 1)
pub mod u64_goldilocks_field;
/// Implementation of prime fields over 64 bit unsigned integers.
Expand Down
17 changes: 17 additions & 0 deletions math/src/field/fields/secp256k1_field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::{
field::fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField},
unsigned_integer::element::U256,
};

type Secp256k1MontgomeryBackendPrimeField<T> = MontgomeryBackendPrimeField<T, 4>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MontgomeryConfigSecp256k1PrimeField;
impl IsModulus<U256> for MontgomeryConfigSecp256k1PrimeField {
const MODULUS: U256 = U256::from_hex_unchecked(
"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
);
}

pub type Secp256k1PrimeField =
Secp256k1MontgomeryBackendPrimeField<MontgomeryConfigSecp256k1PrimeField>;
17 changes: 17 additions & 0 deletions math/src/field/fields/secp256k1_scalarfield.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::{
field::fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField},
unsigned_integer::element::U256,
};

type Secp256k1MontgomeryBackendScalarField<T> = MontgomeryBackendPrimeField<T, 4>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MontgomeryConfigSecp256k1ScalarField;
impl IsModulus<U256> for MontgomeryConfigSecp256k1ScalarField {
const MODULUS: U256 = U256::from_hex_unchecked(
"fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
);
}

pub type Secp256k1ScalarField =
Secp256k1MontgomeryBackendScalarField<MontgomeryConfigSecp256k1ScalarField>;
Loading