From 55d9376e68972bef136e0d936e74ffc70796a4f5 Mon Sep 17 00:00:00 2001 From: Kohei Taniguchi Date: Thu, 6 Feb 2020 11:12:23 +0900 Subject: [PATCH 1/6] Fix generating wrong e value when the message bytes start with "00" byte. The sha256 hash function which is used in schnorr signature generation receives inputs as BigInt value. But the BigInt value eliminate head bytes if it is zero. So that, the output of hash function was wrong. This commit changes the message into BigInt array for each byte of the message. fix #35 --- Cargo.toml | 1 + src/lib.rs | 3 + src/protocols/thresholdsig/bitcoin_schnorr.rs | 67 ++++++++++++++----- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dae3a36..f74d03a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,5 @@ tag = "v0.2.3" [dev-dependencies] hex = "0.3.2" +sha2 = "0.8.1" diff --git a/src/lib.rs b/src/lib.rs index bfbd076..60fb46e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,9 @@ extern crate serde_derive; extern crate serde; +#[cfg(test)] +extern crate sha2; + extern crate centipede; extern crate curv; pub mod protocols; diff --git a/src/protocols/thresholdsig/bitcoin_schnorr.rs b/src/protocols/thresholdsig/bitcoin_schnorr.rs index 7c2dca8..3532a5b 100644 --- a/src/protocols/thresholdsig/bitcoin_schnorr.rs +++ b/src/protocols/thresholdsig/bitcoin_schnorr.rs @@ -182,18 +182,7 @@ impl LocalSig { let beta_i = local_ephemeral_key.x_i.clone(); let alpha_i = local_private_key.x_i.clone(); - let message_len_bits = message.len() * 8; - let R = local_ephemeral_key.y.bytes_compressed_to_big_int(); - let X = local_private_key.y.bytes_compressed_to_big_int(); - let X_vec = BigInt::to_vec(&X); - let X_vec_len_bits = X_vec.len() * 8; - let e_bn = HSha256::create_hash_from_slice( - &BigInt::to_vec( - &((((R << X_vec_len_bits) + X) << message_len_bits) + BigInt::from(message)), - )[..], - ); - - let e: FE = ECScalar::from(&e_bn); + let e = compute_e(&local_ephemeral_key.y, &local_private_key.y, message); let gamma_i = beta_i + e.clone() * alpha_i; LocalSig { gamma_i, e } @@ -278,12 +267,7 @@ impl Signature { } pub fn verify(&self, message: &[u8], pubkey_y: &GE) -> Result<(), Error> { - let e_bn = HSha256::create_hash(&[ - &self.v.bytes_compressed_to_big_int(), - &pubkey_y.bytes_compressed_to_big_int(), - &BigInt::from(message), - ]); - let e: FE = ECScalar::from(&e_bn); + let e = compute_e(&self.v, pubkey_y, message); let g: GE = GE::generator(); let sigma_g = g * &self.sigma; @@ -297,3 +281,50 @@ impl Signature { } } } + +/// Compute e = h(V || Y || message) +fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { + let message_len_bits = message.len() * 8; + let R = v.bytes_compressed_to_big_int(); + let X = y.bytes_compressed_to_big_int(); + let X_vec = BigInt::to_vec(&X); + let X_vec_len_bits = X_vec.len() * 8; + let e_bn = HSha256::create_hash_from_slice( + &BigInt::to_vec( + &((((R << X_vec_len_bits) + X) << message_len_bits) + BigInt::from(message)), + )[..], + ); + ECScalar::from(&e_bn) +} + +#[cfg(test)] +mod tests { + use super::compute_e; + use curv::elliptic::curves::secp256_k1::Secp256k1Scalar; + use curv::elliptic::curves::traits::{ECPoint, ECScalar}; + use curv::{BigInt, FE, GE}; + use sha2::Digest; + + #[test] + fn test_compute_e() { + let g: GE = ECPoint::generator(); + let v: GE = g * Secp256k1Scalar::new_random(); + let y: GE = g * Secp256k1Scalar::new_random(); + + // It should be equal to expected when the message started with "00" byte. + let message = + hex::decode("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") + .unwrap(); + + let expected: FE = { + let mut hasher = sha2::Sha256::new(); + hasher.input(&v.get_element().serialize()[..]); + hasher.input(&y.get_element().serialize()[..]); + hasher.input(&message[..]); + let bn = BigInt::from(&hasher.result()[..]); + ECScalar::from(&bn) + }; + + assert_eq!(expected, compute_e(&v, &y, &message[..])); + } +} From 3e9161d48b8d6642172bd96236ae83501d63753f Mon Sep 17 00:00:00 2001 From: Kohei Taniguchi Date: Thu, 6 Feb 2020 11:16:28 +0900 Subject: [PATCH 2/6] Fix generating wrong e value when the message bytes start with "00" byte for zilliqa schnorr. --- src/protocols/thresholdsig/zilliqa_schnorr.rs | 65 +++++++++++++++---- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/src/protocols/thresholdsig/zilliqa_schnorr.rs b/src/protocols/thresholdsig/zilliqa_schnorr.rs index 9cb8d9a..db37ff9 100644 --- a/src/protocols/thresholdsig/zilliqa_schnorr.rs +++ b/src/protocols/thresholdsig/zilliqa_schnorr.rs @@ -221,13 +221,8 @@ impl LocalSig { + (BigInt::from(message) << 528); let e_bn = HSha256::create_hash(&[&hash_in_concat]); */ - let e_bn = HSha256::create_hash(&[ - &local_ephemaral_key.y.bytes_compressed_to_big_int(), - &local_private_key.y.bytes_compressed_to_big_int(), - &BigInt::from(message), - ]); - let e: FE = ECScalar::from(&e_bn); + let e = compute_e(&local_ephemaral_key.y, &local_private_key.y, message); let gamma_i = beta_i.sub(&(e.clone() * alpha_i).get_element()); // let gamma_i = e.clone() * alpha_i ; @@ -346,12 +341,7 @@ impl Signature { let r = HSha256::create_hash(&[&hash_in_concat]); */ - let r = HSha256::create_hash(&[ - &sg_plus_ey.bytes_compressed_to_big_int(), - &pubkey_y.bytes_compressed_to_big_int(), - &BigInt::from(message), - ]); - let r: FE = ECScalar::from(&r); + let r = compute_e(&sg_plus_ey, &pubkey_y, message); if r == self.e { Ok(()) @@ -360,3 +350,54 @@ impl Signature { } } } + +/// Compute e = h(V || Y || message) +fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { + let v_bn = v.bytes_compressed_to_big_int(); + let y_bn = y.bytes_compressed_to_big_int(); + + let mut big_ints = vec![&v_bn, &y_bn]; + + let m: Vec = Vec::from(message) + .into_iter() + .map(|i| BigInt::from(i as i32)) + .collect(); + for i in &m { + big_ints.push(i); + } + + let e_bn = HSha256::create_hash(&big_ints); + ECScalar::from(&e_bn) +} + +#[cfg(test)] +mod tests { + use super::compute_e; + use curv::elliptic::curves::secp256_k1::Secp256k1Scalar; + use curv::elliptic::curves::traits::{ECPoint, ECScalar}; + use curv::{BigInt, FE, GE}; + use sha2::Digest; + + #[test] + fn test_compute_e() { + let g: GE = ECPoint::generator(); + let v: GE = g * Secp256k1Scalar::new_random(); + let y: GE = g * Secp256k1Scalar::new_random(); + + // It should be equal to expected when the message started with "00" byte. + let message = + hex::decode("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") + .unwrap(); + + let expected: FE = { + let mut hasher = sha2::Sha256::new(); + hasher.input(&v.get_element().serialize()[..]); + hasher.input(&y.get_element().serialize()[..]); + hasher.input(&message[..]); + let bn = BigInt::from(&hasher.result()[..]); + ECScalar::from(&bn) + }; + + assert_eq!(expected, compute_e(&v, &y, &message[..])); + } +} From 2c512ab341370a64c27b639e5e4b402d1fac2280 Mon Sep 17 00:00:00 2001 From: Kohei Taniguchi Date: Sun, 16 Feb 2020 11:01:48 +0900 Subject: [PATCH 3/6] Make it to compute e without converting through BigInt --- src/protocols/thresholdsig/bitcoin_schnorr.rs | 19 +++++++++---------- src/protocols/thresholdsig/zilliqa_schnorr.rs | 19 +++++++------------ 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/protocols/thresholdsig/bitcoin_schnorr.rs b/src/protocols/thresholdsig/bitcoin_schnorr.rs index 3532a5b..1d356f2 100644 --- a/src/protocols/thresholdsig/bitcoin_schnorr.rs +++ b/src/protocols/thresholdsig/bitcoin_schnorr.rs @@ -284,16 +284,15 @@ impl Signature { /// Compute e = h(V || Y || message) fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { - let message_len_bits = message.len() * 8; - let R = v.bytes_compressed_to_big_int(); - let X = y.bytes_compressed_to_big_int(); - let X_vec = BigInt::to_vec(&X); - let X_vec_len_bits = X_vec.len() * 8; - let e_bn = HSha256::create_hash_from_slice( - &BigInt::to_vec( - &((((R << X_vec_len_bits) + X) << message_len_bits) + BigInt::from(message)), - )[..], - ); + let v = v.get_element().serialize(); + let y = y.get_element().serialize(); + + let mut vec: Vec = Vec::with_capacity(v.len() + y.len() + message.len()); + vec.extend(&v[..]); + vec.extend(&y[..]); + vec.extend(message); + + let e_bn = HSha256::create_hash_from_slice(&vec[..]); ECScalar::from(&e_bn) } diff --git a/src/protocols/thresholdsig/zilliqa_schnorr.rs b/src/protocols/thresholdsig/zilliqa_schnorr.rs index db37ff9..04f397f 100644 --- a/src/protocols/thresholdsig/zilliqa_schnorr.rs +++ b/src/protocols/thresholdsig/zilliqa_schnorr.rs @@ -353,20 +353,15 @@ impl Signature { /// Compute e = h(V || Y || message) fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { - let v_bn = v.bytes_compressed_to_big_int(); - let y_bn = y.bytes_compressed_to_big_int(); + let v = v.get_element().serialize(); + let y = y.get_element().serialize(); - let mut big_ints = vec![&v_bn, &y_bn]; + let mut vec: Vec = Vec::with_capacity(v.len() + y.len() + message.len()); + vec.extend(&v[..]); + vec.extend(&y[..]); + vec.extend(message); - let m: Vec = Vec::from(message) - .into_iter() - .map(|i| BigInt::from(i as i32)) - .collect(); - for i in &m { - big_ints.push(i); - } - - let e_bn = HSha256::create_hash(&big_ints); + let e_bn = HSha256::create_hash_from_slice(&vec[..]); ECScalar::from(&e_bn) } From dda62d9e69ed29da3a0e9aa6e133659943d1828c Mon Sep 17 00:00:00 2001 From: Kohei Taniguchi Date: Thu, 20 Feb 2020 10:50:04 +0900 Subject: [PATCH 4/6] Make the unit test for compute_e check with concrete value and moved to independent file for to share among bitcoin_schnorr and zilliqa_schnorr. Essentialy how to compute e value is depends on each specification of platforms, but current implemented specification is same. For now it can be shared. --- Cargo.toml | 1 - src/lib.rs | 3 - src/protocols/thresholdsig/bitcoin_schnorr.rs | 49 +-------------- src/protocols/thresholdsig/mod.rs | 3 +- src/protocols/thresholdsig/util.rs | 62 +++++++++++++++++++ src/protocols/thresholdsig/zilliqa_schnorr.rs | 49 +-------------- 6 files changed, 67 insertions(+), 100 deletions(-) create mode 100644 src/protocols/thresholdsig/util.rs diff --git a/Cargo.toml b/Cargo.toml index f74d03a..dae3a36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,5 +20,4 @@ tag = "v0.2.3" [dev-dependencies] hex = "0.3.2" -sha2 = "0.8.1" diff --git a/src/lib.rs b/src/lib.rs index 60fb46e..bfbd076 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,9 +18,6 @@ extern crate serde_derive; extern crate serde; -#[cfg(test)] -extern crate sha2; - extern crate centipede; extern crate curv; pub mod protocols; diff --git a/src/protocols/thresholdsig/bitcoin_schnorr.rs b/src/protocols/thresholdsig/bitcoin_schnorr.rs index 1d356f2..eef853b 100644 --- a/src/protocols/thresholdsig/bitcoin_schnorr.rs +++ b/src/protocols/thresholdsig/bitcoin_schnorr.rs @@ -17,6 +17,7 @@ */ /// following the variant used in bip-schnorr: https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki use Error::{self, InvalidKey, InvalidSS, InvalidSig}; +use protocols::thresholdsig::util::compute_e; use curv::arithmetic::traits::*; @@ -24,8 +25,6 @@ use curv::elliptic::curves::traits::*; use curv::cryptographic_primitives::commitments::hash_commitment::HashCommitment; use curv::cryptographic_primitives::commitments::traits::Commitment; -use curv::cryptographic_primitives::hashing::hash_sha256::HSha256; -use curv::cryptographic_primitives::hashing::traits::Hash; use curv::cryptographic_primitives::secret_sharing::feldman_vss::VerifiableSS; use curv::{BigInt, FE, GE}; @@ -281,49 +280,3 @@ impl Signature { } } } - -/// Compute e = h(V || Y || message) -fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { - let v = v.get_element().serialize(); - let y = y.get_element().serialize(); - - let mut vec: Vec = Vec::with_capacity(v.len() + y.len() + message.len()); - vec.extend(&v[..]); - vec.extend(&y[..]); - vec.extend(message); - - let e_bn = HSha256::create_hash_from_slice(&vec[..]); - ECScalar::from(&e_bn) -} - -#[cfg(test)] -mod tests { - use super::compute_e; - use curv::elliptic::curves::secp256_k1::Secp256k1Scalar; - use curv::elliptic::curves::traits::{ECPoint, ECScalar}; - use curv::{BigInt, FE, GE}; - use sha2::Digest; - - #[test] - fn test_compute_e() { - let g: GE = ECPoint::generator(); - let v: GE = g * Secp256k1Scalar::new_random(); - let y: GE = g * Secp256k1Scalar::new_random(); - - // It should be equal to expected when the message started with "00" byte. - let message = - hex::decode("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") - .unwrap(); - - let expected: FE = { - let mut hasher = sha2::Sha256::new(); - hasher.input(&v.get_element().serialize()[..]); - hasher.input(&y.get_element().serialize()[..]); - hasher.input(&message[..]); - let bn = BigInt::from(&hasher.result()[..]); - ECScalar::from(&bn) - }; - - assert_eq!(expected, compute_e(&v, &y, &message[..])); - } -} diff --git a/src/protocols/thresholdsig/mod.rs b/src/protocols/thresholdsig/mod.rs index a54e2ef..f98f355 100644 --- a/src/protocols/thresholdsig/mod.rs +++ b/src/protocols/thresholdsig/mod.rs @@ -15,6 +15,7 @@ */ /// variant (2) pub mod bitcoin_schnorr; +mod util; mod test_bitcoin; mod test_zilliqa; /// Schnorr signature variants: @@ -27,4 +28,4 @@ mod test_zilliqa; /// as there are no elliptic curve operations inside the hashes. /// variant (1) -pub mod zilliqa_schnorr; +pub mod zilliqa_schnorr; \ No newline at end of file diff --git a/src/protocols/thresholdsig/util.rs b/src/protocols/thresholdsig/util.rs new file mode 100644 index 0000000..4b504e9 --- /dev/null +++ b/src/protocols/thresholdsig/util.rs @@ -0,0 +1,62 @@ +#![allow(non_snake_case)] +#[allow(unused_doc_comments)] +/* + Multisig Schnorr + + Copyright 2020 by Kohei Taniguchi + + This file is part of Multisig Schnorr library + (https://github.com/KZen-networks/multisig-schnorr) + + Multisig Schnorr is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation, either + version 3 of the License, or (at your option) any later version. + + @license GPL-3.0+ +*/ + +use curv::{GE, FE}; +use curv::elliptic::curves::traits::{ECPoint, ECScalar}; +use curv::cryptographic_primitives::hashing::hash_sha256::HSha256; +use curv::cryptographic_primitives::hashing::traits::Hash; + +/// Compute e = h(V || Y || message) +pub fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { + let v = v.get_element().serialize(); + let y = y.get_element().serialize(); + + let mut vec: Vec = Vec::with_capacity(v.len() + y.len() + message.len()); + vec.extend(&v[..]); + vec.extend(&y[..]); + vec.extend(message); + + let e_bn = HSha256::create_hash_from_slice(&vec[..]); + ECScalar::from(&e_bn) +} + +#[cfg(test)] +mod tests { + use protocols::thresholdsig::util::compute_e; + use curv::elliptic::curves::traits::{ECPoint, ECScalar}; + use curv::{BigInt, FE, GE}; + + #[test] + fn test_compute_e() { + let v_x_bn = BigInt::from_str_radix("06705d6b7fd5a7a34ea47b6a8d0ce8372a83d2129a65458e2bef6f45892e7d5d", 16).unwrap(); + let v_y_bn = BigInt::from_str_radix("c6441397d43ff1e0bd9d7da39caf55dffbaa246fb70b1d08d2aa85903e7ec3e0", 16).unwrap(); + let v: GE = ECPoint::from_coor(&v_x_bn, &v_y_bn); + + let y_x_bn = BigInt::from_str_radix("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16).unwrap(); + let y_y_bn = BigInt::from_str_radix("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 16).unwrap(); + let y: GE = ECPoint::from_coor(&y_x_bn, &y_y_bn); + + // It should be equal to expected when the message started with "00" byte. + let message = hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap(); + + let expected_bn = BigInt::from_str_radix("85e8da2401b58b960965aab0df09554fde8d1e41b67b9cebac8d8421d6919c2a", 16).unwrap(); + let expected: FE = ECScalar::from(&expected_bn); + + assert_eq!(expected, compute_e(&v, &y, &message[..])); + } +} \ No newline at end of file diff --git a/src/protocols/thresholdsig/zilliqa_schnorr.rs b/src/protocols/thresholdsig/zilliqa_schnorr.rs index 04f397f..a5470ab 100644 --- a/src/protocols/thresholdsig/zilliqa_schnorr.rs +++ b/src/protocols/thresholdsig/zilliqa_schnorr.rs @@ -19,6 +19,7 @@ /// following the signing & verify variant from https://en.wikipedia.org/wiki/Schnorr_signature (classical variant) /// also can be found in zilliqa white paper: https://docs.zilliqa.com/whitepaper.pdf use Error::{self, InvalidKey, InvalidSS, InvalidSig}; +use protocols::thresholdsig::util::compute_e; use curv::arithmetic::traits::*; @@ -349,50 +350,4 @@ impl Signature { Err(InvalidSig) } } -} - -/// Compute e = h(V || Y || message) -fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { - let v = v.get_element().serialize(); - let y = y.get_element().serialize(); - - let mut vec: Vec = Vec::with_capacity(v.len() + y.len() + message.len()); - vec.extend(&v[..]); - vec.extend(&y[..]); - vec.extend(message); - - let e_bn = HSha256::create_hash_from_slice(&vec[..]); - ECScalar::from(&e_bn) -} - -#[cfg(test)] -mod tests { - use super::compute_e; - use curv::elliptic::curves::secp256_k1::Secp256k1Scalar; - use curv::elliptic::curves::traits::{ECPoint, ECScalar}; - use curv::{BigInt, FE, GE}; - use sha2::Digest; - - #[test] - fn test_compute_e() { - let g: GE = ECPoint::generator(); - let v: GE = g * Secp256k1Scalar::new_random(); - let y: GE = g * Secp256k1Scalar::new_random(); - - // It should be equal to expected when the message started with "00" byte. - let message = - hex::decode("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") - .unwrap(); - - let expected: FE = { - let mut hasher = sha2::Sha256::new(); - hasher.input(&v.get_element().serialize()[..]); - hasher.input(&y.get_element().serialize()[..]); - hasher.input(&message[..]); - let bn = BigInt::from(&hasher.result()[..]); - ECScalar::from(&bn) - }; - - assert_eq!(expected, compute_e(&v, &y, &message[..])); - } -} +} \ No newline at end of file From 6c4b6611b07e5d26ad09eab258999f40e1496341 Mon Sep 17 00:00:00 2001 From: Kohei Taniguchi Date: Thu, 20 Feb 2020 10:52:31 +0900 Subject: [PATCH 5/6] fmt --- src/protocols/thresholdsig/bitcoin_schnorr.rs | 2 +- src/protocols/thresholdsig/mod.rs | 4 +- src/protocols/thresholdsig/util.rs | 47 ++++++++++++++----- src/protocols/thresholdsig/zilliqa_schnorr.rs | 4 +- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/protocols/thresholdsig/bitcoin_schnorr.rs b/src/protocols/thresholdsig/bitcoin_schnorr.rs index eef853b..e6bfe04 100644 --- a/src/protocols/thresholdsig/bitcoin_schnorr.rs +++ b/src/protocols/thresholdsig/bitcoin_schnorr.rs @@ -1,4 +1,5 @@ #![allow(non_snake_case)] +use protocols::thresholdsig::util::compute_e; #[allow(unused_doc_comments)] /* Multisig Schnorr @@ -17,7 +18,6 @@ */ /// following the variant used in bip-schnorr: https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki use Error::{self, InvalidKey, InvalidSS, InvalidSig}; -use protocols::thresholdsig::util::compute_e; use curv::arithmetic::traits::*; diff --git a/src/protocols/thresholdsig/mod.rs b/src/protocols/thresholdsig/mod.rs index f98f355..98dd059 100644 --- a/src/protocols/thresholdsig/mod.rs +++ b/src/protocols/thresholdsig/mod.rs @@ -15,9 +15,9 @@ */ /// variant (2) pub mod bitcoin_schnorr; -mod util; mod test_bitcoin; mod test_zilliqa; +mod util; /// Schnorr signature variants: /// Elliptic Curve Schnorr signatures for message m and public key P generally involve /// a point R, integers e and s picked by the signer, and generator G which satisfy e = H(R || m) @@ -28,4 +28,4 @@ mod test_zilliqa; /// as there are no elliptic curve operations inside the hashes. /// variant (1) -pub mod zilliqa_schnorr; \ No newline at end of file +pub mod zilliqa_schnorr; diff --git a/src/protocols/thresholdsig/util.rs b/src/protocols/thresholdsig/util.rs index 4b504e9..c82b4a1 100644 --- a/src/protocols/thresholdsig/util.rs +++ b/src/protocols/thresholdsig/util.rs @@ -1,4 +1,7 @@ #![allow(non_snake_case)] +use curv::cryptographic_primitives::hashing::hash_sha256::HSha256; +use curv::cryptographic_primitives::hashing::traits::Hash; +use curv::elliptic::curves::traits::{ECPoint, ECScalar}; #[allow(unused_doc_comments)] /* Multisig Schnorr @@ -15,11 +18,7 @@ @license GPL-3.0+ */ - -use curv::{GE, FE}; -use curv::elliptic::curves::traits::{ECPoint, ECScalar}; -use curv::cryptographic_primitives::hashing::hash_sha256::HSha256; -use curv::cryptographic_primitives::hashing::traits::Hash; +use curv::{FE, GE}; /// Compute e = h(V || Y || message) pub fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { @@ -37,26 +36,48 @@ pub fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { #[cfg(test)] mod tests { - use protocols::thresholdsig::util::compute_e; use curv::elliptic::curves::traits::{ECPoint, ECScalar}; use curv::{BigInt, FE, GE}; + use protocols::thresholdsig::util::compute_e; #[test] fn test_compute_e() { - let v_x_bn = BigInt::from_str_radix("06705d6b7fd5a7a34ea47b6a8d0ce8372a83d2129a65458e2bef6f45892e7d5d", 16).unwrap(); - let v_y_bn = BigInt::from_str_radix("c6441397d43ff1e0bd9d7da39caf55dffbaa246fb70b1d08d2aa85903e7ec3e0", 16).unwrap(); + let v_x_bn = BigInt::from_str_radix( + "06705d6b7fd5a7a34ea47b6a8d0ce8372a83d2129a65458e2bef6f45892e7d5d", + 16, + ) + .unwrap(); + let v_y_bn = BigInt::from_str_radix( + "c6441397d43ff1e0bd9d7da39caf55dffbaa246fb70b1d08d2aa85903e7ec3e0", + 16, + ) + .unwrap(); let v: GE = ECPoint::from_coor(&v_x_bn, &v_y_bn); - let y_x_bn = BigInt::from_str_radix("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16).unwrap(); - let y_y_bn = BigInt::from_str_radix("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 16).unwrap(); + let y_x_bn = BigInt::from_str_radix( + "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + 16, + ) + .unwrap(); + let y_y_bn = BigInt::from_str_radix( + "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + 16, + ) + .unwrap(); let y: GE = ECPoint::from_coor(&y_x_bn, &y_y_bn); // It should be equal to expected when the message started with "00" byte. - let message = hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let message = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); - let expected_bn = BigInt::from_str_radix("85e8da2401b58b960965aab0df09554fde8d1e41b67b9cebac8d8421d6919c2a", 16).unwrap(); + let expected_bn = BigInt::from_str_radix( + "85e8da2401b58b960965aab0df09554fde8d1e41b67b9cebac8d8421d6919c2a", + 16, + ) + .unwrap(); let expected: FE = ECScalar::from(&expected_bn); assert_eq!(expected, compute_e(&v, &y, &message[..])); } -} \ No newline at end of file +} diff --git a/src/protocols/thresholdsig/zilliqa_schnorr.rs b/src/protocols/thresholdsig/zilliqa_schnorr.rs index a5470ab..c8edc03 100644 --- a/src/protocols/thresholdsig/zilliqa_schnorr.rs +++ b/src/protocols/thresholdsig/zilliqa_schnorr.rs @@ -1,4 +1,5 @@ #![allow(non_snake_case)] +use protocols::thresholdsig::util::compute_e; #[allow(unused_doc_comments)] /* Multisig Schnorr @@ -19,7 +20,6 @@ /// following the signing & verify variant from https://en.wikipedia.org/wiki/Schnorr_signature (classical variant) /// also can be found in zilliqa white paper: https://docs.zilliqa.com/whitepaper.pdf use Error::{self, InvalidKey, InvalidSS, InvalidSig}; -use protocols::thresholdsig::util::compute_e; use curv::arithmetic::traits::*; @@ -350,4 +350,4 @@ impl Signature { Err(InvalidSig) } } -} \ No newline at end of file +} From 4f00076b0f82cb798fe760f8bb624d4b70e5244b Mon Sep 17 00:00:00 2001 From: Kohei Taniguchi Date: Sat, 22 Feb 2020 22:21:34 +0900 Subject: [PATCH 6/6] Move compute_e into each protocol files. Because this function should be changed to adapt for each specification. --- src/protocols/thresholdsig/bitcoin_schnorr.rs | 65 ++++++++++++++- src/protocols/thresholdsig/mod.rs | 1 - src/protocols/thresholdsig/util.rs | 83 ------------------- src/protocols/thresholdsig/zilliqa_schnorr.rs | 63 +++++++++++++- 4 files changed, 126 insertions(+), 86 deletions(-) delete mode 100644 src/protocols/thresholdsig/util.rs diff --git a/src/protocols/thresholdsig/bitcoin_schnorr.rs b/src/protocols/thresholdsig/bitcoin_schnorr.rs index e6bfe04..f45fce9 100644 --- a/src/protocols/thresholdsig/bitcoin_schnorr.rs +++ b/src/protocols/thresholdsig/bitcoin_schnorr.rs @@ -1,5 +1,4 @@ #![allow(non_snake_case)] -use protocols::thresholdsig::util::compute_e; #[allow(unused_doc_comments)] /* Multisig Schnorr @@ -25,6 +24,8 @@ use curv::elliptic::curves::traits::*; use curv::cryptographic_primitives::commitments::hash_commitment::HashCommitment; use curv::cryptographic_primitives::commitments::traits::Commitment; +use curv::cryptographic_primitives::hashing::hash_sha256::HSha256; +use curv::cryptographic_primitives::hashing::traits::Hash; use curv::cryptographic_primitives::secret_sharing::feldman_vss::VerifiableSS; use curv::{BigInt, FE, GE}; @@ -280,3 +281,65 @@ impl Signature { } } } + +/// Compute e = h(V || Y || message) +pub fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { + let v = v.get_element().serialize(); + let y = y.get_element().serialize(); + + let mut vec: Vec = Vec::with_capacity(v.len() + y.len() + message.len()); + vec.extend(&v[..]); + vec.extend(&y[..]); + vec.extend(message); + + let e_bn = HSha256::create_hash_from_slice(&vec[..]); + ECScalar::from(&e_bn) +} + +#[cfg(test)] +mod tests { + use super::compute_e; + use curv::elliptic::curves::traits::{ECPoint, ECScalar}; + use curv::{BigInt, FE, GE}; + + #[test] + fn test_compute_e() { + let v_x_bn = BigInt::from_str_radix( + "06705d6b7fd5a7a34ea47b6a8d0ce8372a83d2129a65458e2bef6f45892e7d5d", + 16, + ) + .unwrap(); + let v_y_bn = BigInt::from_str_radix( + "c6441397d43ff1e0bd9d7da39caf55dffbaa246fb70b1d08d2aa85903e7ec3e0", + 16, + ) + .unwrap(); + let v: GE = ECPoint::from_coor(&v_x_bn, &v_y_bn); + + let y_x_bn = BigInt::from_str_radix( + "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + 16, + ) + .unwrap(); + let y_y_bn = BigInt::from_str_radix( + "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + 16, + ) + .unwrap(); + let y: GE = ECPoint::from_coor(&y_x_bn, &y_y_bn); + + // It should be equal to expected when the message started with "00" byte. + let message = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); + + let expected_bn = BigInt::from_str_radix( + "85e8da2401b58b960965aab0df09554fde8d1e41b67b9cebac8d8421d6919c2a", + 16, + ) + .unwrap(); + let expected: FE = ECScalar::from(&expected_bn); + + assert_eq!(expected, compute_e(&v, &y, &message[..])); + } +} diff --git a/src/protocols/thresholdsig/mod.rs b/src/protocols/thresholdsig/mod.rs index 98dd059..a54e2ef 100644 --- a/src/protocols/thresholdsig/mod.rs +++ b/src/protocols/thresholdsig/mod.rs @@ -17,7 +17,6 @@ pub mod bitcoin_schnorr; mod test_bitcoin; mod test_zilliqa; -mod util; /// Schnorr signature variants: /// Elliptic Curve Schnorr signatures for message m and public key P generally involve /// a point R, integers e and s picked by the signer, and generator G which satisfy e = H(R || m) diff --git a/src/protocols/thresholdsig/util.rs b/src/protocols/thresholdsig/util.rs deleted file mode 100644 index c82b4a1..0000000 --- a/src/protocols/thresholdsig/util.rs +++ /dev/null @@ -1,83 +0,0 @@ -#![allow(non_snake_case)] -use curv::cryptographic_primitives::hashing::hash_sha256::HSha256; -use curv::cryptographic_primitives::hashing::traits::Hash; -use curv::elliptic::curves::traits::{ECPoint, ECScalar}; -#[allow(unused_doc_comments)] -/* - Multisig Schnorr - - Copyright 2020 by Kohei Taniguchi - - This file is part of Multisig Schnorr library - (https://github.com/KZen-networks/multisig-schnorr) - - Multisig Schnorr is free software: you can redistribute - it and/or modify it under the terms of the GNU General Public - License as published by the Free Software Foundation, either - version 3 of the License, or (at your option) any later version. - - @license GPL-3.0+ -*/ -use curv::{FE, GE}; - -/// Compute e = h(V || Y || message) -pub fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { - let v = v.get_element().serialize(); - let y = y.get_element().serialize(); - - let mut vec: Vec = Vec::with_capacity(v.len() + y.len() + message.len()); - vec.extend(&v[..]); - vec.extend(&y[..]); - vec.extend(message); - - let e_bn = HSha256::create_hash_from_slice(&vec[..]); - ECScalar::from(&e_bn) -} - -#[cfg(test)] -mod tests { - use curv::elliptic::curves::traits::{ECPoint, ECScalar}; - use curv::{BigInt, FE, GE}; - use protocols::thresholdsig::util::compute_e; - - #[test] - fn test_compute_e() { - let v_x_bn = BigInt::from_str_radix( - "06705d6b7fd5a7a34ea47b6a8d0ce8372a83d2129a65458e2bef6f45892e7d5d", - 16, - ) - .unwrap(); - let v_y_bn = BigInt::from_str_radix( - "c6441397d43ff1e0bd9d7da39caf55dffbaa246fb70b1d08d2aa85903e7ec3e0", - 16, - ) - .unwrap(); - let v: GE = ECPoint::from_coor(&v_x_bn, &v_y_bn); - - let y_x_bn = BigInt::from_str_radix( - "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", - 16, - ) - .unwrap(); - let y_y_bn = BigInt::from_str_radix( - "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", - 16, - ) - .unwrap(); - let y: GE = ECPoint::from_coor(&y_x_bn, &y_y_bn); - - // It should be equal to expected when the message started with "00" byte. - let message = - hex::decode("0000000000000000000000000000000000000000000000000000000000000000") - .unwrap(); - - let expected_bn = BigInt::from_str_radix( - "85e8da2401b58b960965aab0df09554fde8d1e41b67b9cebac8d8421d6919c2a", - 16, - ) - .unwrap(); - let expected: FE = ECScalar::from(&expected_bn); - - assert_eq!(expected, compute_e(&v, &y, &message[..])); - } -} diff --git a/src/protocols/thresholdsig/zilliqa_schnorr.rs b/src/protocols/thresholdsig/zilliqa_schnorr.rs index c8edc03..c601f11 100644 --- a/src/protocols/thresholdsig/zilliqa_schnorr.rs +++ b/src/protocols/thresholdsig/zilliqa_schnorr.rs @@ -1,5 +1,4 @@ #![allow(non_snake_case)] -use protocols::thresholdsig::util::compute_e; #[allow(unused_doc_comments)] /* Multisig Schnorr @@ -351,3 +350,65 @@ impl Signature { } } } + +/// Compute e = h(V || Y || message) +pub fn compute_e(v: &GE, y: &GE, message: &[u8]) -> FE { + let v = v.get_element().serialize(); + let y = y.get_element().serialize(); + + let mut vec: Vec = Vec::with_capacity(v.len() + y.len() + message.len()); + vec.extend(&v[..]); + vec.extend(&y[..]); + vec.extend(message); + + let e_bn = HSha256::create_hash_from_slice(&vec[..]); + ECScalar::from(&e_bn) +} + +#[cfg(test)] +mod tests { + use super::compute_e; + use curv::elliptic::curves::traits::{ECPoint, ECScalar}; + use curv::{BigInt, FE, GE}; + + #[test] + fn test_compute_e() { + let v_x_bn = BigInt::from_str_radix( + "06705d6b7fd5a7a34ea47b6a8d0ce8372a83d2129a65458e2bef6f45892e7d5d", + 16, + ) + .unwrap(); + let v_y_bn = BigInt::from_str_radix( + "c6441397d43ff1e0bd9d7da39caf55dffbaa246fb70b1d08d2aa85903e7ec3e0", + 16, + ) + .unwrap(); + let v: GE = ECPoint::from_coor(&v_x_bn, &v_y_bn); + + let y_x_bn = BigInt::from_str_radix( + "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + 16, + ) + .unwrap(); + let y_y_bn = BigInt::from_str_radix( + "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + 16, + ) + .unwrap(); + let y: GE = ECPoint::from_coor(&y_x_bn, &y_y_bn); + + // It should be equal to expected when the message started with "00" byte. + let message = + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); + + let expected_bn = BigInt::from_str_radix( + "85e8da2401b58b960965aab0df09554fde8d1e41b67b9cebac8d8421d6919c2a", + 16, + ) + .unwrap(); + let expected: FE = ECScalar::from(&expected_bn); + + assert_eq!(expected, compute_e(&v, &y, &message[..])); + } +}