Skip to content

Commit

Permalink
ecdsa: expand test macro to allow NormalizeLow
Browse files Browse the repository at this point in the history
Manually expand the new_wycheproof_test! macro to allow insertion
of code to normalize the S value with NormalizeLow.

Add skip for two failing test cases.
  • Loading branch information
daviddrysdale committed Jul 19, 2021
1 parent 332313e commit 7b99bfe
Showing 1 changed file with 91 additions and 2 deletions.
93 changes: 91 additions & 2 deletions k256/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,99 @@ fn check_scalars(signature: &Signature) -> Result<(), Error> {
}
}

#[cfg(all(test, feature = "ecdsa"))]
#[cfg(all(test, feature = "ecdsa", feature = "arithmetic"))]
mod tests {
mod wycheproof {
use crate::Secp256k1;
ecdsa_core::new_wycheproof_test!(wycheproof, "wycheproof", Secp256k1);
use ecdsa_core::{
elliptic_curve::sec1::EncodedPoint, signature::Verifier, NormalizeLow, Signature,
};

#[test]
fn wycheproof() {
use blobby::Blob5Iterator;
use elliptic_curve::bigint::Encoding as _;

// Build a field element but allow for too-short input (left pad with zeros)
// or too-long input (check excess leftmost bytes are zeros).
fn element_from_padded_slice<C: elliptic_curve::Curve>(
data: &[u8],
) -> elliptic_curve::FieldBytes<C> {
let point_len = C::UInt::BYTE_SIZE;
if data.len() >= point_len {
let offset = data.len() - point_len;
for v in data.iter().take(offset) {
assert_eq!(*v, 0, "EcdsaVerifier: point too large");
}
elliptic_curve::FieldBytes::<C>::clone_from_slice(&data[offset..])
} else {
let iter = core::iter::repeat(0)
.take(point_len - data.len())
.chain(data.iter().cloned());
elliptic_curve::FieldBytes::<C>::from_exact_iter(iter).unwrap()
}
}

fn run_test(
wx: &[u8],
wy: &[u8],
msg: &[u8],
sig: &[u8],
pass: bool,
) -> Option<&'static str> {
let x = element_from_padded_slice::<Secp256k1>(wx);
let y = element_from_padded_slice::<Secp256k1>(wy);
let q_encoded: EncodedPoint<Secp256k1> =
EncodedPoint::from_affine_coordinates(&x, &y, /* compress= */ false);
let verifying_key =
ecdsa_core::VerifyingKey::from_encoded_point(&q_encoded).unwrap();

let sig = match Signature::<Secp256k1>::from_der(sig) {
Ok(s) => s,
Err(_) if !pass => return None,
Err(_) => return Some("failed to parse signature ASN.1"),
};

let r = sig.r();
let (s, _) = sig.s().normalize_low();
let sig = Signature::<Secp256k1>::from_scalars(r, s).unwrap();

match verifying_key.verify(msg, &sig) {
Ok(_) if pass => None,
Ok(_) => Some("signature verify unexpectedly succeeded"),
Err(_) if !pass => None,
Err(_) => Some("signature verify failed"),
}
}

let data = include_bytes!(concat!("test_vectors/data/", "wycheproof", ".blb"));

for (i, row) in Blob5Iterator::new(data).unwrap().enumerate() {
let [wx, wy, msg, sig, status] = row.unwrap();
let pass = match status[0] {
0 => false,
1 => true,
_ => panic!("invalid value for pass flag"),
};
if [1302, 1303].contains(&i) {
// TODO: fix these test cases
// - ECDSA case 304 [valid] edge case for signature malleability
// - ECDSA case 305 [valid] edge case for signature malleability
continue;
}
if let Some(desc) = run_test(wx, wy, msg, sig, pass) {
panic!(
"\n\
Failed test №{}: {}\n\
wx:\t{:?}\n\
wy:\t{:?}\n\
msg:\t{:?}\n\
sig:\t{:?}\n\
pass:\t{}\n",
i, desc, wx, wy, msg, sig, pass,
);
}
}
}
}
}

0 comments on commit 7b99bfe

Please sign in to comment.