Skip to content

Commit

Permalink
feat!: update wasm and ffi to use domain separated hashes
Browse files Browse the repository at this point in the history
The WASM and FFI library now use the domain-separated hashing algorithm
to generate challenges for signatures.
  • Loading branch information
CjS77 committed Nov 3, 2022
1 parent 8411c64 commit 701f89c
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 35 deletions.
10 changes: 4 additions & 6 deletions benches/signatures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ fn native_keypair(c: &mut Criterion) {
struct SigningData {
k: RistrettoSecretKey,
p: RistrettoPublicKey,
r: RistrettoSecretKey,
m: RistrettoSecretKey,
}

Expand All @@ -39,17 +38,16 @@ fn gen_keypair() -> SigningData {
let mut msg = [0u8; 32];
rng.fill_bytes(&mut msg);
let (k, p) = RistrettoPublicKey::random_keypair(&mut rng);
let r = RistrettoSecretKey::random(&mut rng);
let m = RistrettoSecretKey::from_bytes(&msg).unwrap();
SigningData { k, p, r, m }
SigningData { k, p, m }
}

fn sign_message(c: &mut Criterion) {
c.bench_function("Create RistrettoSchnorr", move |b| {
b.iter_batched(
gen_keypair,
|d| {
let _sig = RistrettoSchnorr::sign(d.k, d.r, &d.m.to_vec()).unwrap();
let _sig = RistrettoSchnorr::sign_message(d.k, d.m.to_vec()).unwrap();
},
BatchSize::SmallInput,
);
Expand All @@ -63,10 +61,10 @@ fn verify_message(c: &mut Criterion) {
b.iter_batched(
|| {
let d = gen_keypair();
let s = RistrettoSchnorr::sign(d.k.clone(), d.r.clone(), &d.m.to_vec()).unwrap();
let s = RistrettoSchnorr::sign_message(d.k.clone(), d.m.to_vec()).unwrap();
(d, s)
},
|(d, s)| assert!(s.verify(&d.p, &d.m)),
|(d, s)| assert!(s.verify_message(&d.p, d.m.as_bytes())),
BatchSize::SmallInput,
);
});
Expand Down
15 changes: 7 additions & 8 deletions src/ffi/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::{
RistrettoSchnorr,
RistrettoSecretKey,
},
signatures::SchnorrSignature,
};

pub const KEY_LENGTH: usize = 32;
Expand Down Expand Up @@ -70,13 +71,15 @@ pub unsafe extern "C" fn sign(
Ok(k) => k,
_ => return INVALID_SECRET_KEY_SER,
};
let pubkey = RistrettoPublicKey::from_secret_key(&k);
let r = RistrettoSecretKey::random(&mut OsRng);
let pub_r = RistrettoPublicKey::from_secret_key(&r);
let msg = match CStr::from_ptr(msg).to_str() {
Ok(s) => s,
_ => return STR_CONV_ERR,
};
let challenge = Blake256::digest(msg.as_bytes());
let sig = match RistrettoSchnorr::sign(k, r, &challenge) {
let e = SchnorrSignature::construct_domain_separated_challenge::<_, Blake256>(&pub_r, &pubkey, msg.as_bytes());
let sig = match RistrettoSchnorr::sign_raw(k, r, e.as_ref()) {
Ok(sig) => sig,
_ => return SIGNING_ERROR,
};
Expand Down Expand Up @@ -123,13 +126,9 @@ pub unsafe extern "C" fn verify(
Ok(s) => s,
_ => return false,
};

let sig = RistrettoSchnorr::new(r_pub, sig);
let challenge = Blake256::digest(msg.as_bytes());
let challenge = match RistrettoSecretKey::from_bytes(challenge.as_slice()) {
Ok(e) => e,
_ => return false,
};
sig.verify(&pk, &challenge)
sig.verify_message(&pk, msg.as_bytes())
}

/// Generate a Pedersen commitment (C) using the provided value and spending key (a, x).
Expand Down
2 changes: 1 addition & 1 deletion src/ristretto/ristretto_sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ mod test {
assert_ne!(hash.as_ref(), naiive.as_bytes());
assert_eq!(
to_hex(hash.as_ref()),
"e64d66b31e2b1c81272f5574f41ab2c997114436c2d3706dca1cf947bed60198"
"d8f6b29b641113c91175b8d44f265ff1167d58d5aa5ee03e6f1f521505b09d80"
);
}

Expand Down
16 changes: 15 additions & 1 deletion src/signatures/schnorr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
};

// Define the hashing domain for Schnorr signatures
hash_domain!(SchnorrSigChallenge, "SchnorrSignature", 1);
hash_domain!(SchnorrSigChallenge, "com.tari.schnorr_signature", 1);

/// An error occurred during construction of a SchnorrSignature
#[derive(Clone, Debug, Error, PartialEq, Eq, Deserialize, Serialize)]
Expand Down Expand Up @@ -266,3 +266,17 @@ where
Some(self.cmp(other))
}
}

#[cfg(test)]
mod test {
use crate::{hashing::DomainSeparation, signatures::SchnorrSigChallenge};

#[test]
fn schnorr_hash_domain() {
assert_eq!(SchnorrSigChallenge::domain(), "com.tari.schnorr_signature");
assert_eq!(
SchnorrSigChallenge::domain_separation_tag("test"),
"com.tari.schnorr_signature.v1.test"
);
}
}
37 changes: 25 additions & 12 deletions src/wasm/key_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::{
RistrettoSchnorr,
RistrettoSecretKey,
},
signatures::SchnorrSignature,
};

/// Result of calling [check_signature] and [check_comsig_signature] and [check_comandpubsig_signature]
Expand Down Expand Up @@ -138,6 +139,7 @@ pub fn sign_challenge_with_nonce(private_key: &str, private_nonce: &str, challen
return JsValue::from_serde(&result).unwrap();
},
};
let pub_r = RistrettoPublicKey::from_secret_key(&r);

let e = match from_hex(challenge_as_hex) {
Ok(e) => e,
Expand All @@ -146,7 +148,16 @@ pub fn sign_challenge_with_nonce(private_key: &str, private_nonce: &str, challen
return JsValue::from_serde(&result).unwrap();
},
};
sign_with_key(&k, &e, Some(&r), &mut result);

let sig = match RistrettoSchnorr::sign_raw(k, r, &e) {
Ok(s) => s,
Err(e) => {
result.error = format!("Could not create signature. {e}");
return JsValue::from_serde(&result).unwrap();
},
};
result.public_nonce = Some(pub_r.to_hex());
result.signature = Some(sig.get_signature().to_hex());
JsValue::from_serde(&result).unwrap()
}

Expand All @@ -156,18 +167,23 @@ pub(super) fn sign_message_with_key(
r: Option<&RistrettoSecretKey>,
result: &mut SignResult,
) {
let e = Blake256::digest(msg.as_bytes());
sign_with_key(k, e.as_slice(), r, result)
sign_with_key(k, msg.as_bytes(), r, result)
}

#[allow(non_snake_case)]
pub(super) fn sign_with_key(k: &RistrettoSecretKey, e: &[u8], r: Option<&RistrettoSecretKey>, result: &mut SignResult) {
pub(super) fn sign_with_key(
k: &RistrettoSecretKey,
msg: &[u8],
r: Option<&RistrettoSecretKey>,
result: &mut SignResult,
) {
let (r, R) = match r {
Some(r) => (r.clone(), RistrettoPublicKey::from_secret_key(r)),
None => RistrettoPublicKey::random_keypair(&mut OsRng),
};

let sig = match RistrettoSchnorr::sign(k.clone(), r, e) {
let P = RistrettoPublicKey::from_secret_key(k);
let e = SchnorrSignature::construct_domain_separated_challenge::<_, Blake256>(&R, &P, msg);
let sig = match RistrettoSchnorr::sign_raw(k.clone(), r, e.as_ref()) {
Ok(s) => s,
Err(e) => {
result.error = format!("Could not create signature. {e}");
Expand Down Expand Up @@ -209,8 +225,7 @@ pub fn check_signature(pub_nonce: &str, signature: &str, pub_key: &str, msg: &st
};

let sig = RistrettoSchnorr::new(R, s);
let msg = Blake256::digest(msg.as_bytes());
result.result = sig.verify_challenge(&P, msg.as_slice());
result.result = sig.verify_message(&P, msg.as_bytes());
JsValue::from_serde(&result).unwrap()
}

Expand Down Expand Up @@ -724,9 +739,7 @@ mod test {

fn create_signature(msg: &str) -> (RistrettoSchnorr, RistrettoPublicKey, RistrettoSecretKey) {
let (sk, pk) = random_keypair();
let (nonce, _) = random_keypair();
let sig = SchnorrSignature::sign(sk.clone(), nonce, &hash(msg)).unwrap();

let sig = SchnorrSignature::sign_message(sk.clone(), msg.as_bytes()).unwrap();
(sig, pk, sk)
}

Expand Down Expand Up @@ -837,7 +850,7 @@ mod test {
assert!(result.error.is_empty());
let p_nonce = RistrettoPublicKey::from_hex(&result.public_nonce.unwrap()).unwrap();
let s = RistrettoSecretKey::from_hex(&result.signature.unwrap()).unwrap();
assert!(SchnorrSignature::new(p_nonce, s).verify_challenge(&pk, &hash(SAMPLE_CHALLENGE)));
assert!(SchnorrSignature::new(p_nonce, s).verify_message(&pk, SAMPLE_CHALLENGE));
}

#[wasm_bindgen_test]
Expand Down
9 changes: 2 additions & 7 deletions src/wasm/keyring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,10 @@ impl KeyRing {

#[cfg(test)]
mod test {
use blake2::{digest::Output, Digest};
use wasm_bindgen_test::*;

use super::*;
use crate::{hash::blake2::Blake256, keys::SecretKey, ristretto::RistrettoSchnorr};
use crate::{keys::SecretKey, ristretto::RistrettoSchnorr};

const SAMPLE_CHALLENGE: &str = "გამარჯობა";

Expand All @@ -163,10 +162,6 @@ mod test {
kr
}

fn hash<T: AsRef<[u8]>>(preimage: T) -> Output<Blake256> {
Blake256::digest(preimage.as_ref())
}

fn create_commitment(k: &RistrettoSecretKey, v: u64) -> PedersenCommitment {
PedersenCommitmentFactory::default().commit_value(k, v)
}
Expand Down Expand Up @@ -240,7 +235,7 @@ mod test {
let kr = new_keyring();
let sig = sign(&kr, "a").unwrap();
let pk = kr.expect_public_key("a");
assert!(sig.verify_challenge(pk, &hash(SAMPLE_CHALLENGE)));
assert!(sig.verify_message(pk, SAMPLE_CHALLENGE));
}
}

Expand Down

0 comments on commit 701f89c

Please sign in to comment.