montana/Монтана-Протокол/Код/crates/mt-crypto-native/tests/regression_baselines.rs

229 lines
7.4 KiB
Rust
Raw Normal View History

use mt_crypto_native::{
mt_keypair_from_seed_mldsa, mt_keypair_from_seed_mlkem, mt_self_test, mt_sign_mldsa,
mt_verify_mldsa, MLDSA65_PUBKEY_SIZE, MLDSA65_SECRETKEY_SIZE, MLDSA65_SEED_SIZE,
MLDSA65_SIGNATURE_SIZE, MLKEM768_PUBKEY_SIZE, MLKEM768_SECRETKEY_SIZE, MLKEM768_SEED_SIZE,
MT_OK,
};
fn sha256_hex(data: &[u8]) -> String {
use std::io::Write;
use std::process::{Command, Stdio};
let mut child = Command::new("shasum")
.args(["-a", "256"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("shasum spawn");
child
.stdin
.as_mut()
.expect("stdin")
.write_all(data)
.expect("write");
let out = child.wait_with_output().expect("wait");
let s = String::from_utf8(out.stdout).expect("utf8");
s.split_whitespace().next().expect("hash").to_string()
}
#[test]
fn mldsa_keypair_from_zero_seed_deterministic() {
let seed = [0u8; MLDSA65_SEED_SIZE];
let mut pk1 = vec![0u8; MLDSA65_PUBKEY_SIZE];
let mut sk1 = vec![0u8; MLDSA65_SECRETKEY_SIZE];
let mut pk2 = vec![0u8; MLDSA65_PUBKEY_SIZE];
let mut sk2 = vec![0u8; MLDSA65_SECRETKEY_SIZE];
unsafe {
assert_eq!(
mt_keypair_from_seed_mldsa(seed.as_ptr(), pk1.as_mut_ptr(), sk1.as_mut_ptr()),
MT_OK
);
assert_eq!(
mt_keypair_from_seed_mldsa(seed.as_ptr(), pk2.as_mut_ptr(), sk2.as_mut_ptr()),
MT_OK
);
}
assert_eq!(pk1, pk2, "ML-DSA pubkey deterministic из одного seed");
assert_eq!(sk1, sk2, "ML-DSA secretkey deterministic из одного seed");
let pk_hash = sha256_hex(&pk1);
let sk_hash = sha256_hex(&sk1);
println!("ML-DSA-65 zero-seed pk SHA-256: {pk_hash}");
println!("ML-DSA-65 zero-seed sk SHA-256: {sk_hash}");
assert_eq!(
pk_hash, "085ba380ff386dd52e42349c6eb88489d6058ea541a4e3fb0dce9a3fd1f7a911",
"ML-DSA-65 zero-seed pubkey baseline (M1-F Phase 1.3 первый прогон)"
);
assert_eq!(
sk_hash, "cfcb5e7edf4348f712b7002b0553d28929856936c98e4adf172e51d5c9934262",
"ML-DSA-65 zero-seed secretkey baseline (M1-F Phase 1.3 первый прогон)"
);
}
#[test]
fn mldsa_keypair_from_montana_seed_deterministic() {
let mut seed = [0u8; MLDSA65_SEED_SIZE];
let bytes = b"Montana test vector ML-DSA-65 \x00\x00";
seed.copy_from_slice(&bytes[..MLDSA65_SEED_SIZE]);
let mut pk = vec![0u8; MLDSA65_PUBKEY_SIZE];
let mut sk = vec![0u8; MLDSA65_SECRETKEY_SIZE];
unsafe {
assert_eq!(
mt_keypair_from_seed_mldsa(seed.as_ptr(), pk.as_mut_ptr(), sk.as_mut_ptr()),
MT_OK
);
}
let pk_hash = sha256_hex(&pk);
let sk_hash = sha256_hex(&sk);
println!("ML-DSA-65 montana-seed pk SHA-256: {pk_hash}");
println!("ML-DSA-65 montana-seed sk SHA-256: {sk_hash}");
assert_eq!(
pk_hash, "aa6bc11dd32e4aa8ccf3d43400c4ef29ab86582bdc83738aa5f302a63e38bfba",
"ML-DSA-65 montana-seed pubkey baseline"
);
assert_eq!(
sk_hash, "c6acdd04cdbe004977db8297cf3c7dfb6d5733ebb5bb6d64fc0259c933902fda",
"ML-DSA-65 montana-seed secretkey baseline"
);
}
#[test]
fn mlkem_keypair_from_zero_seed_deterministic() {
let seed = [0u8; MLKEM768_SEED_SIZE];
let mut pk1 = vec![0u8; MLKEM768_PUBKEY_SIZE];
let mut sk1 = vec![0u8; MLKEM768_SECRETKEY_SIZE];
let mut pk2 = vec![0u8; MLKEM768_PUBKEY_SIZE];
let mut sk2 = vec![0u8; MLKEM768_SECRETKEY_SIZE];
unsafe {
assert_eq!(
mt_keypair_from_seed_mlkem(seed.as_ptr(), pk1.as_mut_ptr(), sk1.as_mut_ptr()),
MT_OK
);
assert_eq!(
mt_keypair_from_seed_mlkem(seed.as_ptr(), pk2.as_mut_ptr(), sk2.as_mut_ptr()),
MT_OK
);
}
assert_eq!(pk1, pk2, "ML-KEM pubkey deterministic из одного seed");
assert_eq!(sk1, sk2, "ML-KEM secretkey deterministic из одного seed");
let pk_hash = sha256_hex(&pk1);
let sk_hash = sha256_hex(&sk1);
println!("ML-KEM-768 zero-seed pk SHA-256: {pk_hash}");
println!("ML-KEM-768 zero-seed sk SHA-256: {sk_hash}");
assert_eq!(
pk_hash, "f95c185fe5b2335d2fc938dd889c6425944acd74376b6952bf1130f720f6ba99",
"ML-KEM-768 zero-seed pubkey baseline"
);
assert_eq!(
sk_hash, "a5e078867af0c0a9702149b3af1adf208dccf878bc9f9e32d4fb028473addd09",
"ML-KEM-768 zero-seed secretkey baseline"
);
}
#[test]
fn mlkem_keypair_from_ones_seed_deterministic() {
let seed = [0xFFu8; MLKEM768_SEED_SIZE];
let mut pk = vec![0u8; MLKEM768_PUBKEY_SIZE];
let mut sk = vec![0u8; MLKEM768_SECRETKEY_SIZE];
unsafe {
assert_eq!(
mt_keypair_from_seed_mlkem(seed.as_ptr(), pk.as_mut_ptr(), sk.as_mut_ptr()),
MT_OK
);
}
let pk_hash = sha256_hex(&pk);
let sk_hash = sha256_hex(&sk);
println!("ML-KEM-768 ones-seed pk SHA-256: {pk_hash}");
println!("ML-KEM-768 ones-seed sk SHA-256: {sk_hash}");
assert_eq!(
pk_hash, "b212c1e61145cc7f4fb3ff1e6adf823f66a69e0fca3cd7d571ab259a96348509",
"ML-KEM-768 ones-seed pubkey baseline"
);
assert_eq!(
sk_hash, "a958f21bfaf882fdeada66f18774b8dc10ff7e3f7fcacc8e295b2dc138d23998",
"ML-KEM-768 ones-seed secretkey baseline"
);
}
#[test]
fn mldsa_sign_verify_roundtrip() {
let seed = [0u8; MLDSA65_SEED_SIZE];
let mut pk = vec![0u8; MLDSA65_PUBKEY_SIZE];
let mut sk = vec![0u8; MLDSA65_SECRETKEY_SIZE];
unsafe {
assert_eq!(
mt_keypair_from_seed_mldsa(seed.as_ptr(), pk.as_mut_ptr(), sk.as_mut_ptr()),
MT_OK
);
}
let msg = b"Montana protocol test message for ML-DSA-65 sign/verify roundtrip";
let mut sig1 = vec![0u8; MLDSA65_SIGNATURE_SIZE];
let mut sig2 = vec![0u8; MLDSA65_SIGNATURE_SIZE];
unsafe {
assert_eq!(
mt_sign_mldsa(sk.as_ptr(), msg.as_ptr(), msg.len(), sig1.as_mut_ptr()),
MT_OK
);
assert_eq!(
mt_sign_mldsa(sk.as_ptr(), msg.as_ptr(), msg.len(), sig2.as_mut_ptr()),
MT_OK
);
}
assert_eq!(sig1, sig2, "ML-DSA подпись deterministic per FIPS 204");
unsafe {
assert_eq!(
mt_verify_mldsa(pk.as_ptr(), msg.as_ptr(), msg.len(), sig1.as_ptr()),
MT_OK,
"verify должен принять корректную подпись"
);
}
let bad_msg = b"Montana protocol DIFFERENT message for ML-DSA-65 sign/verify roundtrip";
unsafe {
let rc = mt_verify_mldsa(pk.as_ptr(), bad_msg.as_ptr(), bad_msg.len(), sig1.as_ptr());
assert_ne!(
rc, MT_OK,
"verify должен отклонить подпись на изменённое сообщение"
);
}
let mut tampered_sig = sig1.clone();
tampered_sig[0] ^= 0x01;
unsafe {
let rc = mt_verify_mldsa(pk.as_ptr(), msg.as_ptr(), msg.len(), tampered_sig.as_ptr());
assert_ne!(rc, MT_OK, "verify должен отклонить tampered подпись");
}
let sig_hash = sha256_hex(&sig1);
println!("ML-DSA-65 zero-seed roundtrip sig SHA-256: {sig_hash}");
assert_eq!(
sig_hash, "56a3c55492021ce47a4dbab2ee7965b9d52979650184973177f2c7d9f66aad03",
"ML-DSA-65 deterministic signature baseline (zero-seed key, fixed test message)"
);
}
#[test]
fn self_test_passes() {
unsafe {
assert_eq!(mt_self_test(), MT_OK);
}
}