add test vectors

This commit is contained in:
Sergio Chouhy 2025-08-12 16:45:07 -03:00
parent 927254f6ce
commit 066aa8f3f7
4 changed files with 133 additions and 39 deletions

View File

@ -11,6 +11,7 @@ program-methods = { path = "program_methods" }
serde = "1.0.219"
sha2 = "0.10.9"
secp256k1 = "0.31.1"
rand = "0.8"
[dev-dependencies]
test-program-methods = { path = "test_program_methods" }

View File

@ -1,8 +1,76 @@
mod encoding;
mod private_key;
mod public_key;
mod signature;
mod encoding;
pub use private_key::PrivateKey;
pub use public_key::PublicKey;
pub use signature::Signature;
#[cfg(test)]
mod tests {
use crate::{PrivateKey, PublicKey, Signature};
fn hex_to_bytes<const N: usize>(hex: &str) -> [u8; N] {
hex::decode(hex).unwrap().try_into().unwrap()
}
pub struct TestVector {
pub seckey: Option<PrivateKey>,
pub pubkey: PublicKey,
pub aux_rand: Option<[u8; 32]>,
pub message: Option<Vec<u8>>,
pub signature: Signature,
pub verification_result: bool,
}
/// Test vectors from
/// https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv
//
pub fn test_vectors() -> Vec<TestVector> {
vec![
TestVector {
seckey: Some(PrivateKey(hex_to_bytes(
"0000000000000000000000000000000000000000000000000000000000000003",
))),
pubkey: PublicKey(hex_to_bytes(
"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
)),
aux_rand: Some(hex_to_bytes::<32>(
"0000000000000000000000000000000000000000000000000000000000000000",
)),
message: Some(
hex::decode("0000000000000000000000000000000000000000000000000000000000000000")
.unwrap(),
),
signature: Signature {
value: hex_to_bytes(
"E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0",
),
},
verification_result: true,
},
TestVector {
seckey: Some(PrivateKey(hex_to_bytes(
"B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF",
))),
pubkey: PublicKey(hex_to_bytes(
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
)),
aux_rand: Some(hex_to_bytes::<32>(
"0000000000000000000000000000000000000000000000000000000000000001",
)),
message: Some(
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
.unwrap(),
),
signature: Signature {
value: hex_to_bytes(
"6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A",
),
},
verification_result: true,
},
]
}
}

View File

@ -23,45 +23,21 @@ impl PublicKey {
#[cfg(test)]
mod tests {
use crate::{PrivateKey, PublicKey};
fn hex_to_32_bytes(hex: &str) -> [u8; 32] {
hex::decode(hex).unwrap().try_into().unwrap()
}
/// Test vectors from
/// https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv
const BIP340_PK_TEST_VECTORS: [(&str, &str); 5] = [
(
"0000000000000000000000000000000000000000000000000000000000000003",
"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
),
(
"B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF",
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
),
(
"C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9",
"DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8",
),
(
"0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710",
"25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517",
),
(
"0340034003400340034003400340034003400340034003400340034003400340",
"778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117",
),
];
use crate::{PrivateKey, PublicKey, signature::tests::test_vectors};
#[test]
fn test_bip340_pk_test_vectors() {
for (i, (private_key_hex, expected_public_key_hex)) in
BIP340_PK_TEST_VECTORS.iter().enumerate()
{
let key = PrivateKey::try_new(hex_to_32_bytes(private_key_hex)).unwrap();
let public_key = PublicKey::new(&key);
let expected_public_key = PublicKey(hex_to_32_bytes(expected_public_key_hex));
assert_eq!(public_key, expected_public_key, "Failed test vector at index {i}");
fn test_public_key_generation_from_bip340_test_vectors() {
for (i, test_vector) in test_vectors().iter().enumerate() {
let Some(private_key) = &test_vector.seckey else {
continue;
};
let public_key = PublicKey::new(private_key);
let expected_public_key = &test_vector.pubkey;
assert_eq!(
&public_key, expected_public_key,
"Failed test vector at index {i}"
);
}
}
}

View File

@ -1,5 +1,7 @@
use std::io::{Cursor, Read};
use rand::{rngs::OsRng, RngCore};
use crate::{PrivateKey, PublicKey, error::NssaError, public_transaction::Message};
#[derive(Debug, Clone, PartialEq, Eq)]
@ -9,11 +11,17 @@ pub struct Signature {
impl Signature {
pub(crate) fn new(key: &PrivateKey, message: &[u8]) -> Self {
let mut aux_random = [0u8; 32];
OsRng.fill_bytes(&mut aux_random);
Self::new_with_aux_random(key, message, aux_random)
}
fn new_with_aux_random(key: &PrivateKey, message: &[u8], aux_random: [u8; 32]) -> Self {
let value = {
let secp = secp256k1::Secp256k1::new();
let secret_key = secp256k1::SecretKey::from_byte_array(key.0).unwrap();
let keypair = secp256k1::Keypair::from_secret_key(&secp, &secret_key);
let signature = secp.sign_schnorr_no_aux_rand(message, &keypair);
let signature = secp.sign_schnorr_with_aux_rand(message, &keypair, &aux_random);
signature.to_byte_array()
};
Self { value }
@ -27,3 +35,44 @@ impl Signature {
}
}
#[cfg(test)]
mod tests {
use crate::{Signature, signature::tests::test_vectors};
#[test]
fn test_signature_generation_from_bip340_test_vectors() {
for (i, test_vector) in test_vectors().into_iter().enumerate() {
let Some(private_key) = test_vector.seckey else {
continue;
};
let Some(aux_random) = test_vector.aux_rand else {
continue;
};
let Some(message) = test_vector.message else {
continue;
};
if !test_vector.verification_result {
continue;
}
let expected_signature = &test_vector.signature;
let signature = Signature::new_with_aux_random(&private_key, &message, aux_random);
assert_eq!(&signature, expected_signature, "Failed test vector {i}");
}
}
#[test]
fn test_signature_verification_from_bip340_test_vectors() {
for (i, test_vector) in test_vectors().into_iter().enumerate() {
let message = test_vector.message.unwrap_or(vec![]);
let expected_result = test_vector.verification_result;
let result = test_vector
.signature
.is_valid_for(&message, &test_vector.pubkey);
assert_eq!(result, expected_result, "Failed test vector {i}");
}
}
}