Skip to content

Commit

Permalink
Fix generating wrong e value when the message bytes start with "00" b…
Browse files Browse the repository at this point in the history
…yte.

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 ZenGo-X#35
  • Loading branch information
rantan committed Feb 6, 2020
1 parent 3a4bf00 commit 8183eee
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 12 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ crate-type = ["lib"]
serde = "1.0"
serde_derive = "1.0"
curv = { git = "https://github.com/KZen-networks/curv" , tag = "v0.2.3", features = ["ec_secp256k1","merkle"]}
sha2 = "0.8.1"

[dependencies.centipede]
git = "https://github.com/KZen-networks/centipede"
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
65 changes: 53 additions & 12 deletions src/protocols/thresholdsig/bitcoin_schnorr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,7 @@ impl LocalSig {
let beta_i = local_ephemaral_key.x_i.clone();
let alpha_i = local_private_key.x_i.clone();

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 + e.clone() * alpha_i;
// let gamma_i = e.clone() * alpha_i ;

Expand Down Expand Up @@ -273,12 +268,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;
Expand All @@ -292,3 +282,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<BigInt> = 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[..]));
}
}

0 comments on commit 8183eee

Please sign in to comment.