Skip to content

Commit

Permalink
Generic test vectors with IETF specialization
Browse files Browse the repository at this point in the history
  • Loading branch information
davxy committed Jun 22, 2024
1 parent effcdb7 commit ace79c2
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 197 deletions.
198 changes: 51 additions & 147 deletions src/ietf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,178 +129,82 @@ impl<S: IetfSuite> Verifier<S> for Public<S> {
#[cfg(test)]
pub mod testing {
use super::*;

pub const TEST_FLAG_SKIP_PROOF_CHECK: u8 = 1 << 0;
use crate::testing as common;

pub struct TestVector<S: IetfSuite> {
pub comment: String,
pub sk: ScalarField<S>,
pub pk: AffinePoint<S>,
pub alpha: Vec<u8>,
pub ad: Vec<u8>,
pub h: AffinePoint<S>,
pub gamma: AffinePoint<S>,
pub beta: Vec<u8>,
pub base: common::TestVector<S>,
pub c: ScalarField<S>,
pub s: ScalarField<S>,
pub flags: u8,
}

impl<S: IetfSuite + std::fmt::Debug> TestVector<S> {
pub fn new(
impl<S: IetfSuite> core::fmt::Debug for TestVector<S> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let c = hex::encode(utils::encode_scalar::<S>(&self.c));
let s = hex::encode(utils::encode_scalar::<S>(&self.s));
f.debug_struct("TestVector")
.field("base", &self.base)
.field("proof_c", &c)
.field("proof_s", &s)
.finish()
}
}

impl<S: IetfSuite + std::fmt::Debug> common::TestVectorTrait for TestVector<S> {
fn new(
comment: &str,
seed: &[u8],
alpha: &[u8],
salt: Option<&[u8]>,
ad: &[u8],
flags: u8,
) -> Self {
let sk = Secret::<S>::from_seed(seed);
let pk = sk.public().0;

let salt = salt
.map(|v| v.to_vec())
.unwrap_or_else(|| utils::encode_point::<S>(&pk));

let h2c_data = [&salt[..], alpha].concat();
let h = <S as Suite>::data_to_point(&h2c_data).unwrap();
let input = Input::from(h);

let alpha = alpha.to_vec();
let output = sk.output(input);
let gamma = output.0;
let beta = output.hash().to_vec();

let proof = sk.prove(input, output, ad);

TestVector {
comment: comment.to_string(),
sk: sk.scalar,
pk,
alpha,
ad: ad.to_vec(),
h,
gamma,
beta,
use super::Prover;
let base = common::TestVector::new(comment, seed, alpha, salt, ad, flags);
// TODO: store constructed types in the vectors
let input = Input::from(base.h);
let output = Output::from(base.gamma);
let sk = Secret::from_scalar(base.sk);
let proof: Proof<S> = sk.prove(input, output, &ad);
Self {
base,
c: proof.c,
s: proof.s,
flags,
}
}

pub fn run(&self) {
println!("Running test vector: {}", self.comment);

let sk = Secret::<S>::from_scalar(self.sk);

let pk = sk.public();
assert_eq!(self.pk, pk.0, "public key ('pk') mismatch");

// Prepare hash_to_curve data = salt || alpha
// Salt is defined to be pk (adjust it to make the encoding to match)
let pk_bytes = utils::encode_point::<S>(&pk.0);
let h2c_data = [&pk_bytes[..], &self.alpha[..]].concat();

let h = S::data_to_point(&h2c_data).unwrap();
assert_eq!(self.h, h, "hash-to-curve ('h') mismatch");
let input = Input::<S>::from(h);

let output = sk.output(input);
assert_eq!(self.gamma, output.0, "VRF pre-output ('gamma') mismatch");

if self.flags & TEST_FLAG_SKIP_PROOF_CHECK != 0 {
return;
}

let beta = output.hash().to_vec();
assert_eq!(self.beta, beta, "VRF output ('beta') mismatch");

let proof = sk.prove(input, output, &self.ad);
assert_eq!(self.c, proof.c, "VRF proof challenge ('c') mismatch");
assert_eq!(self.s, proof.s, "VRF proof response ('s') mismatch");

assert!(pk.verify(input, output, &self.ad, &proof).is_ok());
}
}

impl<S: IetfSuite> core::fmt::Debug for TestVector<S> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let sk = hex::encode(utils::encode_scalar::<S>(&self.sk));
let pk = hex::encode(utils::encode_point::<S>(&self.pk));
let alpha = hex::encode(&self.alpha);
let ad = hex::encode(&self.ad);
let h = hex::encode(utils::encode_point::<S>(&self.h));
let gamma = hex::encode(utils::encode_point::<S>(&self.gamma));
let beta = hex::encode(&self.beta);
let c = hex::encode(utils::encode_scalar::<S>(&self.c));
let s = hex::encode(utils::encode_scalar::<S>(&self.s));
f.debug_struct("TestVector")
.field("comment", &self.comment)
.field("sk", &sk)
.field("pk", &pk)
.field("alpha", &alpha)
.field("ad", &ad)
.field("h", &h)
.field("gamma", &gamma)
.field("beta", &beta)
.field("proof_c", &c)
.field("proof_s", &s)
.field("flags", &self.flags)
.finish()
fn from_map(map: &common::TestVectorMap) -> Self {
let base = common::TestVector::from_map(map);
let c = utils::decode_scalar::<S>(&map.item_bytes("proof_c"));
let s = utils::decode_scalar::<S>(&map.item_bytes("proof_s"));
Self { base, c, s }
}
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct TestVectorMap(indexmap::IndexMap<String, String>);

impl<S: IetfSuite> From<TestVector<S>> for TestVectorMap {
fn from(v: TestVector<S>) -> Self {
fn into_map(&self) -> common::TestVectorMap {
let items = [
("comment", v.comment),
("sk", hex::encode(utils::encode_scalar::<S>(&v.sk))),
("pk", hex::encode(utils::encode_point::<S>(&v.pk))),
("alpha", hex::encode(&v.alpha)),
("ad", hex::encode(&v.ad)),
("h", hex::encode(utils::encode_point::<S>(&v.h))),
("gamma", hex::encode(utils::encode_point::<S>(&v.gamma))),
("beta", hex::encode(&v.beta)),
("proof_c", hex::encode(utils::encode_scalar::<S>(&v.c))),
("proof_s", hex::encode(utils::encode_scalar::<S>(&v.s))),
("flags", hex::encode([v.flags])),
("proof_c", hex::encode(utils::encode_scalar::<S>(&self.c))),
("proof_s", hex::encode(utils::encode_scalar::<S>(&self.s))),
];
let map: indexmap::IndexMap<String, String> =
items.into_iter().map(|(k, v)| (k.to_string(), v)).collect();
Self(map)
let mut map = self.base.into_map();
items.into_iter().for_each(|(name, value)| {
map.0.insert(name.to_string(), value);
});
map
}
}

impl<S: IetfSuite> From<TestVectorMap> for TestVector<S> {
fn from(map: TestVectorMap) -> Self {
let item_bytes = |field| hex::decode(map.0.get(field).unwrap()).unwrap();
let comment = map.0.get("comment").unwrap().to_string();
let sk = utils::decode_scalar::<S>(&item_bytes("sk"));
let pk = utils::decode_point::<S>(&item_bytes("pk"));
let alpha = item_bytes("alpha");
let ad = item_bytes("ad");
let h = utils::decode_point::<S>(&item_bytes("h"));
let gamma = utils::decode_point::<S>(&item_bytes("gamma"));
let beta = item_bytes("beta");
let c = utils::decode_scalar::<S>(&item_bytes("proof_c"));
let s = utils::decode_scalar::<S>(&item_bytes("proof_s"));
let flags = item_bytes("flags")[0];
Self {
comment,
sk,
pk,
alpha,
ad,
h,
gamma,
beta,
c,
s,
flags,
fn run(&self) {
self.base.run();
if self.base.flags & common::TEST_FLAG_SKIP_PROOF_CHECK != 0 {
return;
}
let input = Input::<S>::from(self.base.h);
let output = Output::from(self.base.gamma);
let sk = Secret::from_scalar(self.base.sk);
let proof = sk.prove(input, output, &self.base.ad);
assert_eq!(self.c, proof.c, "VRF proof challenge ('c') mismatch");
assert_eq!(self.s, proof.s, "VRF proof response ('s') mismatch");

let pk = Public(self.base.pk);
assert!(pk.verify(input, output, &self.base.ad, &proof).is_ok());
}
}
}
Expand Down
25 changes: 13 additions & 12 deletions src/suites/bandersnatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ pub mod edwards {
suite_types!(BandersnatchSha512Ell2);

impl Suite for BandersnatchSha512Ell2 {
const SUITE_ID: &'static [u8] = b"Bandersnatch_SHA-512-ELL2";
const SUITE_ID: &'static [u8] = b"Bandersnatch_SHA-512_ELL2";
const CHALLENGE_LEN: usize = 32;

type Affine = ark_ed_on_bls12_381_bandersnatch::EdwardsAffine;
Expand Down Expand Up @@ -244,11 +244,12 @@ mod tests {
}

#[cfg(test)]
mod test_vectors_ed {
mod test_vectors_ietf_ed {
use super::edwards::*;
use crate::testing;

type S = BandersnatchSha512Ell2;
type V = crate::ietf::testing::TestVector<S>;

const TEST_VECTORS_FILE: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
Expand All @@ -257,22 +258,22 @@ mod test_vectors_ed {

#[test]
#[ignore = "test vectors generator"]
fn test_vectors_generate() {
testing::test_vectors_generate::<S>(TEST_VECTORS_FILE);
fn generate() {
testing::test_vectors_generate::<V>(TEST_VECTORS_FILE, "Bandersnatch_SHA-512_ELL2");
}

#[test]
fn test_vectors_process() {
testing::test_vectors_process::<S>(TEST_VECTORS_FILE);
fn process() {
testing::test_vectors_process::<V>(TEST_VECTORS_FILE);
}
}

#[cfg(test)]
mod test_vectors_sw {
mod test_vectors_ietf_sw {
use super::weierstrass::*;
use crate::testing;

type S = BandersnatchSha512Tai;
type V = crate::ietf::testing::TestVector<BandersnatchSha512Tai>;

const TEST_VECTORS_FILE: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
Expand All @@ -281,12 +282,12 @@ mod test_vectors_sw {

#[test]
#[ignore = "test vectors generator"]
fn test_vectors_generate() {
testing::test_vectors_generate::<S>(TEST_VECTORS_FILE);
fn generate() {
testing::test_vectors_generate::<V>(TEST_VECTORS_FILE, "Bandersnatch_SW_SHA-512_ELL2");
}

#[test]
fn test_vectors_process() {
testing::test_vectors_process::<S>(TEST_VECTORS_FILE);
fn process() {
testing::test_vectors_process::<V>(TEST_VECTORS_FILE);
}
}
14 changes: 7 additions & 7 deletions src/suites/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub struct Ed25519Sha512Tai;
suite_types!(Ed25519Sha512Tai);

impl Suite for Ed25519Sha512Tai {
const SUITE_ID: &'static [u8] = b"ed25519-sha512-tai";
const SUITE_ID: &'static [u8] = b"Ed25519_SHA-512_TAI";
const CHALLENGE_LEN: usize = 16;

type Affine = ark_ed25519::EdwardsAffine;
Expand All @@ -79,10 +79,10 @@ impl PedersenSuite for Ed25519Sha512Tai {
suite_tests!(Ed25519Sha512Tai);

#[cfg(test)]
mod test_vectors {
mod test_vectors_ietf {
use super::*;

type S = Ed25519Sha512Tai;
type V = crate::ietf::testing::TestVector<Ed25519Sha512Tai>;

const TEST_VECTORS_FILE: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
Expand All @@ -91,12 +91,12 @@ mod test_vectors {

#[test]
#[ignore = "test vectors generator"]
fn test_vectors_generate() {
testing::test_vectors_generate::<S>(TEST_VECTORS_FILE);
fn generate() {
testing::test_vectors_generate::<V>(TEST_VECTORS_FILE, "Ed25519_SHA-512_TAI");
}

#[test]
fn test_vectors_process() {
testing::test_vectors_process::<S>(TEST_VECTORS_FILE);
fn process() {
testing::test_vectors_process::<V>(TEST_VECTORS_FILE);
}
}
16 changes: 8 additions & 8 deletions src/suites/secp256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ impl PedersenSuite for P256Sha256Tai {
}

#[cfg(test)]
mod test_vectors {
mod test_vectors_ietf {
use super::*;

type S = P256Sha256Tai;
type V = crate::ietf::testing::TestVector<P256Sha256Tai>;

const TEST_VECTORS_FILE: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
Expand All @@ -156,17 +156,17 @@ mod test_vectors {

#[test]
#[ignore = "test vectors generator"]
fn test_vectors_generate() {
testing::test_vectors_generate::<S>(TEST_VECTORS_FILE);
fn generate() {
testing::test_vectors_generate::<V>(TEST_VECTORS_FILE, "secp256r1_SHA-256_TAI");
}

#[test]
fn test_vectors_process() {
testing::test_vectors_process::<S>(TEST_VECTORS_FILE);
fn process() {
testing::test_vectors_process::<V>(TEST_VECTORS_FILE);
}

#[test]
fn test_vectors_process_rfc_9381() {
testing::test_vectors_process::<S>(TEST_VECTORS_FILE_RFC_9381);
fn process_rfc_9381() {
testing::test_vectors_process::<V>(TEST_VECTORS_FILE_RFC_9381);
}
}
Loading

0 comments on commit ace79c2

Please sign in to comment.