mirror of
https://github.com/vacp2p/stealth-address-kit.git
synced 2026-01-09 14:48:08 -05:00
feat(curves): add secp256r1 (#4)
This commit is contained in:
committed by
GitHub
parent
a7e1fabcf5
commit
f9c8286db0
2
.github/workflows/nightly-release.yml
vendored
2
.github/workflows/nightly-release.yml
vendored
@@ -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
12
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
19
README.md
19
README.md
@@ -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
|
||||
|
||||
|
||||
16
src/ffi.rs
16
src/ffi.rs
@@ -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
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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
120
src/secp256r1_impl.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user