Skip to content

Commit

Permalink
Merge pull request #21 from mzacho/plain-ecdsa
Browse files Browse the repository at this point in the history
Plain ECDSA implementation
  • Loading branch information
arcuo authored Dec 19, 2023
2 parents 9966c65 + f3d2cd0 commit 3809c2d
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 23 deletions.
135 changes: 113 additions & 22 deletions src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,38 @@ use crate::{
shares::{NatShares, PointShares, Shares},
};

/// Run a ECDSA protocol
// TODO: remame to threshold instead of plain.

/// Run a ECDSA protocol with BeDOZa
///
/// Uses the protocol from Securing DNSSEC Keys via Threshold ECDSA From Generic MPC
///
/// 1. Sign message
/// 2. Verify signature
/// 3. PROFIT!
pub fn run_ecdsa(message: Nat) {
pub fn run_ecdsa_bedoza(message: Nat) {
// Generate a keys
let (_, sk_shared, pk) = keygen();

// Sign message
let signature = sign_message_bedoza(message, sk_shared);

// Verify signature
assert!(verify_signature(message, signature, pk));
}

/// Run a ECDSA protocol without BeDOZa
/// Used for benchmarking
/// Uses the protocol from https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-messages
#[allow(dead_code)]
pub fn run_ecdsa_plain(message: Nat) {
// Generate a keys
let (sk_shared, pk) = keygen();
let (sk, _, pk) = keygen();

// Sign message
let signature = sign_message(message, sk_shared);
let signature = sign_message_plain(message, sk);

// Verify signature
assert!(verify_signature(message, signature, pk));
}

/// Sign a message
/// Sign a message with BeDOZa
///
/// Using ABB+ protocol from Securing DNSSEC Keys via Threshold ECDSA From Generic MPC
///
Expand All @@ -43,7 +56,7 @@ pub fn run_ecdsa(message: Nat) {
/// 2. Generate circuit
/// 3. Evaluate circuit
/// 3. Return signature: (r, s)
fn sign_message(m: Nat, sk_shared: NatShares) -> (Nat, Nat) {
fn sign_message_bedoza(m: Nat, sk_shared: NatShares) -> (Nat, Nat) {
// User independent preprocessing
let preprocessed_tuple = user_independent_preprocessing(&curve::nonzero_order());

Expand Down Expand Up @@ -103,7 +116,7 @@ fn verify_signature(m: Nat, signature: (Nat, Nat), pk: Point) -> bool {
/// Generate public key
///
/// Returns a point on the curve
/// pk = Open(Convert(\[sk\]))
/// `pk = Open(Convert([sk]))` or `pk = sk * G`
fn generate_public_key(sk_shared: NatShares) -> Point {
let sk_convert = PointShares::convert(sk_shared);
let pk = Shares::Point(sk_convert).open().point();
Expand Down Expand Up @@ -192,11 +205,11 @@ fn ecdsa_circuit(
}

/// Generate ECDSA keypair where sk is secret shared
fn keygen() -> (NatShares, Point) {
fn keygen() -> (Nat, NatShares, Point) {
let sk = curve::rand_mod_order();
let sk_shared = NatShares::new(&sk, curve::nonzero_order());
let pk = generate_public_key(sk_shared.clone());
(sk_shared, pk)
(sk, sk_shared, pk)
}

/// Compute H(m) = sha256(m)
Expand All @@ -211,38 +224,116 @@ fn hash_message(m: Nat) -> Nat {
return Nat::from_le_slice(&result[..]);
}

/// Sign a message with plain ECDSA (no BeDOZa)
///
/// Based on https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-messages
#[allow(dead_code)]
fn sign_message_plain(message: Nat, sk: Nat) -> (Nat, Nat) {
// Calculate the hash of the message
let h = hash_message(message);

// Generate a random number k
let k = curve::rand_mod_order();

// Calculate random point R = k * G and take its x coordinate r_x = R.x
let r_x = FieldBytesEncoding::decode_field_bytes(
&AffinePoint::from(Point::mul_by_generator(
&curve::Scalar::from_uint_unchecked(k),
))
.x(),
);

// Calculate the modular inverse of k
let (k_inv, k_inv_exists) = k.inv_mod(&curve::nonzero_order());
if !bool::from(k_inv_exists) {
panic!("k inverse does not exist")
}

// Calculate the signature proof s = (h + r_x * sk) * k_inv
let h_plus_r_x_sk =
mul_mod(&r_x, &sk, &curve::nonzero_order()).add_mod(&h, &curve::nonzero_order());
let s = mul_mod(&h_plus_r_x_sk, &k_inv, &curve::nonzero_order());

(r_x, s)
}

/// Read message after "ecdsa" from command line arguments
pub fn read_args_message(args: env::Args) -> Nat {
let args: Vec<String> = args.collect();
let m = Nat::from(args.get(2).unwrap().parse::<u128>().unwrap());
m
}

#[cfg(test)]
mod tests {
mod tests_bedoza {
use super::*;

#[test]
fn test_run_ecdsa() {
run_ecdsa_bedoza(Nat::from_u16(1337));
}

#[test]
fn test_threshold_ecdsa_bedoza_positive() {
// Test that sign/verify of 100 random messages
let mut i = 0;
while i < 100 {
let message = curve::rand_mod_order();

let (_, sk_shared, pk) = keygen();
let s = sign_message_bedoza(message, sk_shared);
assert!(verify_signature(message, s, pk));
i = i + 1;
}
run_ecdsa_bedoza(Nat::from_u16(1337));
}

#[test]
fn test_threshold_ecdsa_bedoza_negative() {
// Test that sign/verify of 100 random messages
// m1 and m2 where m1 != m2
let mut i = 0;
while i < 100 {
let m1 = curve::rand_mod_order();
let m2 = curve::rand_mod_order();
if m1 == m2 {
continue;
}

let (_, sk_shared, pk) = keygen();
let s = sign_message_bedoza(m1, sk_shared);
assert!(!verify_signature(m2, s, pk));
i = i + 1;
}
}
}

#[cfg(test)]
mod tests_plain {
use super::*;

#[test]
fn test_run_ecdsa() {
run_ecdsa(Nat::from_u16(1337));
run_ecdsa_plain(Nat::from_u16(1337));
}

#[test]
fn test_threshold_ecdsa_positive() {
fn test_threshold_ecdsa_plain_positive() {
// Test that sign/verify of 100 random messages
let mut i = 0;
while i < 100 {
let message = curve::rand_mod_order();

let (sk_shared, pk) = keygen();
let s = sign_message(message, sk_shared);
let (sk, _, pk) = keygen();
let s = sign_message_plain(message, sk);
assert!(verify_signature(message, s, pk));
i = i + 1;
}
run_ecdsa(Nat::from_u16(1337));
run_ecdsa_plain(Nat::from_u16(1337));
}

#[test]
fn test_threshold_ecdsa_negative() {
fn test_threshold_ecdsa_plain_negative() {
// Test that sign/verify of 100 random messages
// m1 and m2 where m1 != m2
let mut i = 0;
Expand All @@ -253,8 +344,8 @@ mod tests {
continue;
}

let (sk_shared, pk) = keygen();
let s = sign_message(m1, sk_shared);
let (sk, _, pk) = keygen();
let s = sign_message_plain(m1, sk);
assert!(!verify_signature(m2, s, pk));
i = i + 1;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn main() {

ECDSA => {
let m = ecdsa::read_args_message(args());
ecdsa::run_ecdsa(m)
ecdsa::run_ecdsa_bedoza(m)
}
_ => panic!(
"Use one of the following commands: \"{cmds}\"",
Expand Down

0 comments on commit 3809c2d

Please sign in to comment.