Skip to content

Commit

Permalink
ecdsa/ecc: cavp tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ctz committed Oct 26, 2024
1 parent 520d44b commit 03d2c08
Show file tree
Hide file tree
Showing 3 changed files with 292 additions and 4 deletions.
144 changes: 144 additions & 0 deletions graviola/src/high/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,147 @@ impl Scalar<P384> for p384::Scalar {
target.copy_from_slice(&self.as_bytes());
}
}

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

#[test]
fn cavp_pkv() {
#[derive(Debug, Default)]
struct State {
curve: String,
px: Vec<u8>,
py: Vec<u8>,
}

impl CavpSink for State {
fn on_meta(&mut self, meta: &str) {
self.curve = meta.to_string();
}

fn on_value(&mut self, name: &str, value: Value<'_>) {
match name {
"Qx" => self.px = value.bytes(),
"Qy" => self.py = value.bytes(),
"Result" => match self.curve.as_ref() {
"P-256" => {
pad(&mut self.px, 32);
pad(&mut self.py, 32);
let mut point = vec![0x04];
point.extend_from_slice(&self.px);
point.extend_from_slice(&self.py);
let res = <P256 as Curve>::PublicKey::from_x962_uncompressed(&point);

match value.str().chars().next() {
Some('F') => {
res.unwrap_err();
}
Some('P') => {
res.unwrap();
}
_ => {}
};
}
"P-384" => {
pad(&mut self.px, 48);
pad(&mut self.py, 48);
let mut point = vec![0x04];
point.extend_from_slice(&self.px);
point.extend_from_slice(&self.py);
let res = <P384 as Curve>::PublicKey::from_x962_uncompressed(&point);

match value.str().chars().next() {
Some('F') => {
res.unwrap_err();
}
Some('P') => {
res.unwrap();
}
_ => {}
};
}
_ => {
println!("unhandled curve {}", self.curve);
}
},
_ => {}
}
}
}

process_cavp("../thirdparty/cavp/ecdsa/PKV.rsp", &mut State::default());
}

#[test]
fn cavp_keypair() {
#[derive(Debug, Default)]
struct State {
curve: String,
d: Vec<u8>,
px: Vec<u8>,
py: Vec<u8>,
}

impl CavpSink for State {
fn on_meta(&mut self, meta: &str) {
if meta.starts_with("P-") {
self.curve = meta.to_string();
}
}

fn on_value(&mut self, name: &str, value: Value<'_>) {
match name {
"d" => self.d = value.bytes(),
"Qx" => self.px = value.bytes(),
"Qy" => {
self.py = value.bytes();

match self.curve.as_ref() {
"P-256" => {
pad(&mut self.px, 32);
pad(&mut self.py, 32);
let mut point = vec![0x04];
point.extend_from_slice(&self.px);
point.extend_from_slice(&self.py);

let res = <P256 as Curve>::PrivateKey::from_bytes(&self.d).unwrap();
let mut buffer = [0u8; 65];
let got = res.public_key_encode_uncompressed(&mut buffer).unwrap();
assert_eq!(point, got);
}
"P-384" => {
pad(&mut self.px, 48);
pad(&mut self.py, 48);
let mut point = vec![0x04];
point.extend_from_slice(&self.px);
point.extend_from_slice(&self.py);

let res = <P384 as Curve>::PrivateKey::from_bytes(&self.d).unwrap();
let mut buffer = [0u8; 97];
let got = res.public_key_encode_uncompressed(&mut buffer).unwrap();
assert_eq!(point, got);
}
_ => {
println!("unhandled curve {}", self.curve);
}
};
}
_ => {}
}
}
}

process_cavp(
"../thirdparty/cavp/ecdsa/KeyPair.rsp",
&mut State::default(),
);
}

fn pad(v: &mut Vec<u8>, l: usize) {
while v.len() < l {
v.insert(0, 0x00);
}
}
}
131 changes: 131 additions & 0 deletions graviola/src/high/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ mod tests {
use crate::high::{curve, hash};
use crate::mid::rng::SliceRandomSource;
use crate::mid::rng::SystemRandom;
use crate::test::*;

#[test]
fn smoke_test_loading_keys() {
Expand Down Expand Up @@ -448,4 +449,134 @@ mod tests {
);
v.verify::<hash::Sha256>(&[b"wv[vnX"], &signature).unwrap();
}

#[test]
fn cavp_sigver() {
#[derive(Debug, Default)]
struct State {
param: String,
msg: Vec<u8>,
px: Vec<u8>,
py: Vec<u8>,
r: Vec<u8>,
s: Vec<u8>,
}

impl CavpSink for State {
fn on_meta(&mut self, meta: &str) {
self.param = meta.to_string();
}

fn on_value(&mut self, name: &str, value: Value<'_>) {
match name {
"Msg" => self.msg = value.bytes(),
"Qx" => self.px = value.bytes(),
"Qy" => self.py = value.bytes(),
"R" => self.r = value.bytes(),
"S" => self.s = value.bytes(),
"Result" => {
match self.param.as_ref() {
"P-256,SHA-256" | "P-256,SHA-384" | "P-256,SHA-512" => {
pad(&mut self.px, 32);
pad(&mut self.py, 32);
pad(&mut self.r, 32);
pad(&mut self.s, 32);

let mut point = vec![0x04];
point.extend_from_slice(&self.px);
point.extend_from_slice(&self.py);

let mut sig = vec![];
sig.extend_from_slice(&self.r);
sig.extend_from_slice(&self.s);

let vkey =
VerifyingKey::<curve::P256>::from_x962_uncompressed(&point)
.unwrap();

let result = match self.param.as_ref() {
"P-256,SHA-256" => {
vkey.verify::<hash::Sha256>(&[&self.msg], &sig)
}
"P-256,SHA-384" => {
vkey.verify::<hash::Sha384>(&[&self.msg], &sig)
}
"P-256,SHA-512" => {
vkey.verify::<hash::Sha512>(&[&self.msg], &sig)
}
_ => todo!("unhandled param"),
};

match value.str().chars().next() {
Some('F') => {
result.unwrap_err();
}
Some('P') => {
result.unwrap();
}
_ => todo!("unrecognised Result {:?}", value.str()),
};
println!("PASS: {}", value.str());
}
"P-384,SHA-256" | "P-384,SHA-384" | "P-384,SHA-512" => {
pad(&mut self.px, 48);
pad(&mut self.py, 48);
pad(&mut self.r, 48);
pad(&mut self.s, 48);

let mut point = vec![0x04];
point.extend_from_slice(&self.px);
point.extend_from_slice(&self.py);

let mut sig = vec![];
sig.extend_from_slice(&self.r);
sig.extend_from_slice(&self.s);

let vkey =
VerifyingKey::<curve::P384>::from_x962_uncompressed(&point)
.unwrap();

let result = match self.param.as_ref() {
"P-384,SHA-256" => {
vkey.verify::<hash::Sha256>(&[&self.msg], &sig)
}
"P-384,SHA-384" => {
vkey.verify::<hash::Sha384>(&[&self.msg], &sig)
}
"P-384,SHA-512" => {
vkey.verify::<hash::Sha512>(&[&self.msg], &sig)
}
_ => todo!("unhandled param"),
};

match value.str().chars().next() {
Some('F') => {
result.unwrap_err();
}
Some('P') => {
result.unwrap();
}
_ => todo!("unrecognised Result {:?}", value.str()),
};
println!("PASS: {}", value.str());
}

_ => {
println!("unhandled params {}", self.param);
}
};
}
_ => {}
}
}
}

process_cavp("../thirdparty/cavp/ecdsa/SigVer.rsp", &mut State::default());
}

fn pad(v: &mut Vec<u8>, l: usize) {
while v.len() < l {
v.insert(0, 0x00);
}
}
}
21 changes: 17 additions & 4 deletions graviola/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,28 @@ pub(crate) struct Value<'a>(&'a str);

impl Value<'_> {
pub(crate) fn bytes(&self) -> Vec<u8> {
(0..self.0.len())
.step_by(2)
.map(|i| u8::from_str_radix(&self.0[i..i + 2], 16).unwrap())
.collect()
if self.0.len() % 2 == 0 {
(0..self.0.len())
.step_by(2)
.map(|i| u8::from_str_radix(&self.0[i..i + 2], 16).unwrap())
.collect()
} else {
let mut buf = self.0.to_string();
buf.insert(0, '0');
(0..buf.len())
.step_by(2)
.map(|i| u8::from_str_radix(&buf[i..i + 2], 16).unwrap())
.collect()
}
}

pub(crate) fn int(&self) -> u64 {
self.0.parse::<u64>().unwrap()
}

pub(crate) fn str(&self) -> &str {
self.0
}
}

pub(crate) fn process_cavp(filename: impl AsRef<Path>, sink: &mut dyn CavpSink) {
Expand Down

0 comments on commit 03d2c08

Please sign in to comment.