feat(curves): add secp256r1 (#4)

This commit is contained in:
Aaryamann Challani
2024-05-21 08:58:03 +05:30
committed by GitHub
parent a7e1fabcf5
commit f9c8286db0
8 changed files with 170 additions and 8 deletions

View File

@@ -14,6 +14,7 @@ jobs:
- bls12_381
- bls12_377
- secp256k1
- secp256r1
- all
target:
- x86_64-unknown-linux-gnu
@@ -58,6 +59,7 @@ jobs:
- bls12_381
- bls12_377
- secp256k1
- secp256r1
- all
target:
- x86_64-apple-darwin

12
Cargo.lock generated
View File

@@ -244,6 +244,17 @@ dependencies = [
"ark-std",
]
[[package]]
name = "ark-secp256r1"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633"
dependencies = [
"ark-ec",
"ark-ff",
"ark-std",
]
[[package]]
name = "ark-serialize"
version = "0.4.1"
@@ -776,6 +787,7 @@ dependencies = [
"ark-ec",
"ark-ff",
"ark-secp256k1",
"ark-secp256r1",
"ark-serialize",
"ark-std",
"cfg-if",

View File

@@ -13,9 +13,10 @@ ffi = []
bls12_381 = []
bls12_377 = []
secp256k1 = []
secp256r1 = []
bn254 = []
default = ["ffi", "secp256k1"]
all = ["ffi", "secp256k1", "bls12_381", "bls12_377", "bn254"]
all = ["ffi", "secp256k1", "bls12_381", "bls12_377", "bn254", "secp256r1"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -29,6 +30,7 @@ ark-bn254 = "0.4.0"
ark-bls12-381 = "0.4.0"
ark-bls12-377 = "0.4.0"
ark-secp256k1 = "0.4.0"
ark-secp256r1 = "0.4.0"
tiny-keccak = { version = "=2.0.2", features = ["keccak"] }
ark-ec = "0.4.1"
ark-serialize = "0.4.1"

View File

@@ -1,4 +1,4 @@
# erc-5564-rs
# stealth-address-kit
Uses the [arkworks-rs](https://github.com/arkworks-rs/curves) suite of libraries, and utilities from [rln](https://github.com/vacp2p/zerokit)
@@ -8,12 +8,13 @@ Uses the [arkworks-rs](https://github.com/arkworks-rs/curves) suite of libraries
2. `ark_bls_12_381`
3. `ark_bls_12_377`
4. `secp256k1`
5. `secp256r1`
## Usage
```rust
use erc_5564_rs::{StealthAddressOnCurve};
use ark_bn254::Bn254; // or ark_bls_12_381::Bls12_381 or ark_bls_12_377::Bls12_377, or erc_5564_rs::Secp256k1
use ark_bn254::Bn254; // or ark_bls_12_381::Bls12_381 or ark_bls_12_377::Bls12_377, erc_5564_rs::Secp256k1, erc_5564_rs::Secp256r1
fn main() {
let (spending_key, spending_public_key) = Bn254::random_keypair();
@@ -35,13 +36,23 @@ fn main() {
}
```
## Adding a new curve
1. Add the curve to the `Cargo.toml` file, as a feature
2. Create a new module in the `src` directory, with the curve name, suffixed by `_impl.rs`
3. Implement the `StealthAddressOnCurve` trait for the curve
4. Add the curve to the `lib.rs` file, in the `mod` declaration
5. Add the curve to the FFI API, in the `ffi.rs` file
6. Add the curve to the README
7. Add the curve to the nightly release workflow
## Building and Testing
1. Building
`cargo build --release --features <bn254/bls12_381/bls12_377/secp256k1>`
`cargo build --release --features <bn254/bls12_381/bls12_377/secp256k1/secp256r1>`
2. Testing
`cargo test --release --features <bn254/bls12_381/bls12_377/secp256k1>`
`cargo test --release --features <bn254/bls12_381/bls12_377/secp256k1/secp256r1>`
## FFI Api

View File

@@ -631,7 +631,7 @@ cfg_if!(
cfg_if!(
if #[cfg(feature = "secp256k1")] {
use crate::secp256k1::Secp256k1;
use crate::secp256k1_impl::Secp256k1;
use ark_secp256k1::{Fr as Secp256k1_Fr, Projective as Secp256k1_Projective};
define_curve_ffi!(
secp256k1,
@@ -642,3 +642,17 @@ cfg_if!(
);
}
);
cfg_if!(
if #[cfg(feature = "secp256r1")] {
use crate::secp256r1_impl::Secp256r1;
use ark_secp256r1::{Fr as Secp256r1_Fr, Projective as Secp256r1_Projective};
define_curve_ffi!(
secp256r1,
Secp256r1,
Secp256r1_Fr,
Secp256r1_Projective,
33
);
}
);

View File

@@ -6,9 +6,10 @@ mod bls12_377_impl;
mod bls12_381_impl;
#[cfg(feature = "bn254")]
mod bn254_impl;
#[cfg(feature = "secp256k1")]
mod secp256k1;
mod secp256k1_impl;
#[cfg(feature = "secp256r1")]
mod secp256r1_impl;
#[cfg(feature = "ffi")]
mod ffi;

120
src/secp256r1_impl.rs Normal file
View File

@@ -0,0 +1,120 @@
use crate::stealth_commitments::{AffineWrapper, RawFr, StealthAddressOnCurve};
use ark_ff::PrimeField;
use ark_secp256r1::{Affine as G1Affine, Fq, Fr, Projective as G1Projective};
use ark_secp256r1::{G_GENERATOR_X, G_GENERATOR_Y};
use tiny_keccak::{Hasher, Keccak};
#[allow(non_camel_case_types)]
pub struct Secp256r1_G1Affine(G1Affine);
impl AffineWrapper for Secp256r1_G1Affine {
type Fq = Fq;
fn new(x: Self::Fq, y: Self::Fq) -> Self {
Secp256r1_G1Affine(G1Affine::new(x, y))
}
}
impl From<Secp256r1_G1Affine> for G1Projective {
fn from(value: Secp256r1_G1Affine) -> Self {
G1Projective::from(value.0)
}
}
impl RawFr for Fr {
type Fr = Fr;
fn as_u64(&self) -> u64 {
self.0 .0[0]
}
}
pub struct Secp256r1;
impl StealthAddressOnCurve for Secp256r1 {
type Projective = G1Projective;
type Affine = Secp256r1_G1Affine;
type Fr = Fr;
fn derive_public_key(private_key: &Self::Fr) -> Self::Projective {
let g1_generator_affine = Self::Affine::new(G_GENERATOR_X, G_GENERATOR_Y);
(Self::Projective::from(g1_generator_affine)) * *private_key
}
fn hash_to_fr(input: &[u8]) -> Self::Fr {
let mut hash = [0; 32];
let mut hasher = Keccak::v256();
hasher.update(input);
hasher.finalize(&mut hash);
// We export the hash as a field element
Self::Fr::from_le_bytes_mod_order(hash.as_slice())
}
}
#[cfg(test)]
mod tests {
use super::*;
use ark_ec::CurveGroup;
type Curve = Secp256r1;
#[test]
fn test_random_keypair() {
let (key, pub_key) = Curve::random_keypair();
// Check the derived key matches the one generated from original key
assert_eq!(Curve::derive_public_key(&key), pub_key);
}
#[test]
fn test_hash_to_fr() {
// Test that hash_to_fr(input_1) != hash_to_fr(input_2) when input_1 != input_2
let input_1 = b"input_1";
let input_2 = b"input_2";
assert_ne!(Curve::hash_to_fr(input_1), Curve::hash_to_fr(input_2));
}
#[test]
fn test_compute_shared_point() {
// In a multiple participant scenario, any participant's public key
// combined with any other participant's private key should arrive at the same shared key
let (key1, pub_key1) = Curve::random_keypair();
let (key2, pub_key2) = Curve::random_keypair();
let shared1 = Curve::compute_shared_point(key1, pub_key2);
let shared2 = Curve::compute_shared_point(key2, pub_key1);
// Convert Projective to Affine for equality comparison
let shared1_affine = shared1.into_affine();
let shared2_affine = shared2.into_affine();
assert_eq!(shared1_affine.x, shared2_affine.x);
assert_eq!(shared1_affine.y, shared2_affine.y);
}
#[test]
fn test_stealth_commitment_generation() {
let (spending_key, spending_public_key) = Curve::random_keypair();
let (viewing_key, viewing_public_key) = Curve::random_keypair();
// generate ephemeral keypair
let (ephemeral_private_key, ephemeral_public_key) = Curve::random_keypair();
let (stealth_commitment, view_tag) = Curve::generate_stealth_commitment(
viewing_public_key,
spending_public_key,
ephemeral_private_key,
);
let stealth_private_key_opt = Curve::generate_stealth_private_key(
ephemeral_public_key,
viewing_key,
spending_key,
view_tag,
);
if stealth_private_key_opt.is_none() {
panic!("View tags did not match");
}
let derived_commitment = Curve::derive_public_key(&stealth_private_key_opt.unwrap());
assert_eq!(derived_commitment, stealth_commitment);
}
}