use super::proof_certificate::{ProofCertificate, Verified};
use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
use rand::rngs::OsRng;
pub const ED25519_VERIFY_CORRECTNESS_CERT: ProofCertificate = ProofCertificate::new(
400, 1, 2026_0205, 1, );
pub const ED25519_EUF_CMA_CERT: ProofCertificate = ProofCertificate::new(
401, 1, 2026_0205, 2, );
pub const ED25519_DETERMINISM_CERT: ProofCertificate = ProofCertificate::new(
402, 1, 2026_0205, 1, );
pub const KEY_DERIVATION_UNIQUENESS_CERT: ProofCertificate = ProofCertificate::new(
403, 1, 2026_0205, 2, );
pub struct VerifiedSigningKey {
inner: SigningKey,
}
impl std::fmt::Debug for VerifiedSigningKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VerifiedSigningKey")
.field("inner", &"<redacted>")
.finish()
}
}
impl VerifiedSigningKey {
pub fn generate() -> Self {
let inner = SigningKey::generate(&mut OsRng);
Self { inner }
}
pub fn from_bytes(bytes: &[u8; 32]) -> Self {
assert_ne!(
bytes, &[0u8; 32],
"Ed25519 secret key seed is all zeros (degenerate key)"
);
let inner = SigningKey::from_bytes(bytes);
Self { inner }
}
pub fn to_bytes(&self) -> [u8; 32] {
self.inner.to_bytes()
}
pub fn verifying_key(&self) -> VerifiedVerifyingKey {
VerifiedVerifyingKey {
inner: self.inner.verifying_key(),
}
}
pub fn sign(&self, message: &[u8]) -> VerifiedSignature {
let inner = self.inner.sign(message);
VerifiedSignature { inner }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VerifiedVerifyingKey {
inner: VerifyingKey,
}
impl VerifiedVerifyingKey {
pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, String> {
assert_ne!(
bytes, &[0u8; 32],
"Ed25519 public key is all zeros (degenerate key)"
);
let inner = VerifyingKey::from_bytes(bytes).map_err(|e| e.to_string())?;
Ok(Self { inner })
}
pub fn to_bytes(&self) -> [u8; 32] {
self.inner.to_bytes()
}
pub fn verify(&self, message: &[u8], signature: &VerifiedSignature) -> Result<(), String> {
self.inner
.verify_strict(message, &signature.inner)
.map_err(|_| "Signature verification failed".to_string())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VerifiedSignature {
inner: Signature,
}
impl VerifiedSignature {
pub fn from_bytes(bytes: &[u8; 64]) -> Self {
assert_ne!(
bytes, &[0u8; 64],
"Ed25519 signature is all zeros (degenerate signature)"
);
let inner = Signature::from_bytes(bytes);
Self { inner }
}
pub fn to_bytes(&self) -> [u8; 64] {
self.inner.to_bytes()
}
}
impl Verified for VerifiedSigningKey {
fn proof_certificate() -> ProofCertificate {
ED25519_VERIFY_CORRECTNESS_CERT
}
fn theorem_name() -> &'static str {
"ed25519_verify_correct"
}
fn theorem_description() -> &'static str {
"Ed25519 signature verification correctness: valid signatures always verify"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sign_and_verify() {
let signing_key = VerifiedSigningKey::generate();
let verifying_key = signing_key.verifying_key();
let message = b"test message";
let signature = signing_key.sign(message);
assert!(verifying_key.verify(message, &signature).is_ok());
}
#[test]
fn test_wrong_message_fails() {
let signing_key = VerifiedSigningKey::generate();
let verifying_key = signing_key.verifying_key();
let signature = signing_key.sign(b"original message");
let result = verifying_key.verify(b"tampered message", &signature);
assert!(result.is_err());
}
#[test]
fn test_wrong_key_fails() {
let signing_key1 = VerifiedSigningKey::generate();
let signing_key2 = VerifiedSigningKey::generate();
let verifying_key2 = signing_key2.verifying_key();
let message = b"test message";
let signature = signing_key1.sign(message);
let result = verifying_key2.verify(message, &signature);
assert!(result.is_err());
}
#[test]
fn test_deterministic_signatures() {
let seed = [0x42; 32];
let signing_key = VerifiedSigningKey::from_bytes(&seed);
let message = b"deterministic test";
let sig1 = signing_key.sign(message);
let sig2 = signing_key.sign(message);
assert_eq!(sig1, sig2);
}
#[test]
fn test_different_messages_different_signatures() {
let signing_key = VerifiedSigningKey::generate();
let sig1 = signing_key.sign(b"message1");
let sig2 = signing_key.sign(b"message2");
assert_ne!(sig1, sig2);
}
#[test]
fn test_empty_message() {
let signing_key = VerifiedSigningKey::generate();
let verifying_key = signing_key.verifying_key();
let signature = signing_key.sign(b"");
assert!(verifying_key.verify(b"", &signature).is_ok());
}
#[test]
fn test_large_message() {
let signing_key = VerifiedSigningKey::generate();
let verifying_key = signing_key.verifying_key();
let message = vec![0xAB; 100_000];
let signature = signing_key.sign(&message);
assert!(verifying_key.verify(&message, &signature).is_ok());
}
#[test]
fn test_key_serialization_roundtrip() {
let signing_key = VerifiedSigningKey::generate();
let bytes = signing_key.to_bytes();
let restored = VerifiedSigningKey::from_bytes(&bytes);
let message = b"test";
let sig1 = signing_key.sign(message);
let sig2 = restored.sign(message);
assert_eq!(sig1, sig2);
}
#[test]
fn test_verifying_key_serialization_roundtrip() {
let signing_key = VerifiedSigningKey::generate();
let verifying_key = signing_key.verifying_key();
let bytes = verifying_key.to_bytes();
let restored =
VerifiedVerifyingKey::from_bytes(&bytes).expect("failed to restore verifying key");
assert_eq!(verifying_key, restored);
}
#[test]
fn test_signature_serialization_roundtrip() {
let signing_key = VerifiedSigningKey::generate();
let signature = signing_key.sign(b"test");
let bytes = signature.to_bytes();
let restored = VerifiedSignature::from_bytes(&bytes);
assert_eq!(signature, restored);
}
#[test]
fn test_key_derivation_deterministic() {
let seed = [0x42; 32];
let key1 = VerifiedSigningKey::from_bytes(&seed);
let key2 = VerifiedSigningKey::from_bytes(&seed);
let vk1 = key1.verifying_key();
let vk2 = key2.verifying_key();
assert_eq!(vk1, vk2);
}
#[test]
fn test_different_seeds_different_keys() {
let seed1 = [0x42; 32];
let seed2 = [0x43; 32];
let key1 = VerifiedSigningKey::from_bytes(&seed1);
let key2 = VerifiedSigningKey::from_bytes(&seed2);
let vk1 = key1.verifying_key();
let vk2 = key2.verifying_key();
assert_ne!(vk1, vk2);
}
#[test]
fn test_proof_certificate() {
let cert = VerifiedSigningKey::proof_certificate();
assert_eq!(cert.theorem_id, 400);
assert_eq!(cert.proof_system_id, 1);
assert_eq!(cert.verified_at, 20_260_205);
assert_eq!(cert.assumption_count, 1);
}
#[test]
fn test_verified_trait() {
assert_eq!(VerifiedSigningKey::theorem_name(), "ed25519_verify_correct");
assert!(VerifiedSigningKey::theorem_description().contains("correctness"));
}
#[test]
fn test_tampered_signature_fails() {
let signing_key = VerifiedSigningKey::generate();
let verifying_key = signing_key.verifying_key();
let message = b"test message";
let signature = signing_key.sign(message);
let mut sig_bytes = signature.to_bytes();
sig_bytes[0] ^= 0xFF;
let tampered_sig = VerifiedSignature::from_bytes(&sig_bytes);
let result = verifying_key.verify(message, &tampered_sig);
assert!(result.is_err());
}
#[test]
fn test_verifying_key_from_signing_key() {
let signing_key = VerifiedSigningKey::generate();
let vk1 = signing_key.verifying_key();
let vk2 = signing_key.verifying_key();
assert_eq!(vk1, vk2);
}
#[test]
fn test_multiple_signatures_from_same_key() {
let signing_key = VerifiedSigningKey::generate();
let verifying_key = signing_key.verifying_key();
let messages = [b"msg1" as &[u8], b"msg2", b"msg3", b"msg4", b"msg5"];
for msg in &messages {
let signature = signing_key.sign(msg);
assert!(verifying_key.verify(msg, &signature).is_ok());
}
}
#[test]
fn test_non_canonical_signature_rejected() {
let signing_key = VerifiedSigningKey::generate();
let verifying_key = signing_key.verifying_key();
let message = b"test message";
let signature = signing_key.sign(message);
assert!(verifying_key.verify(message, &signature).is_ok());
}
#[test]
#[should_panic(expected = "Ed25519 secret key seed is all zeros")]
fn test_all_zero_signing_key_panics() {
let _ = VerifiedSigningKey::from_bytes(&[0u8; 32]);
}
#[test]
#[should_panic(expected = "Ed25519 public key is all zeros")]
fn test_all_zero_verifying_key_panics() {
let _ = VerifiedVerifyingKey::from_bytes(&[0u8; 32]);
}
#[test]
#[should_panic(expected = "Ed25519 signature is all zeros")]
fn test_all_zero_signature_panics() {
let _ = VerifiedSignature::from_bytes(&[0u8; 64]);
}
}
#[cfg(test)]
mod proptests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn prop_sign_verify_roundtrip(message in prop::collection::vec(any::<u8>(), 0..10000)) {
let signing_key = VerifiedSigningKey::generate();
let verifying_key = signing_key.verifying_key();
let signature = signing_key.sign(&message);
prop_assert!(verifying_key.verify(&message, &signature).is_ok());
}
#[test]
fn prop_different_messages_different_signatures(
msg1 in prop::collection::vec(any::<u8>(), 1..1000),
msg2 in prop::collection::vec(any::<u8>(), 1..1000)
) {
prop_assume!(msg1 != msg2);
let signing_key = VerifiedSigningKey::generate();
let sig1 = signing_key.sign(&msg1);
let sig2 = signing_key.sign(&msg2);
prop_assert_ne!(sig1, sig2);
}
#[test]
fn prop_signature_determinism(
seed in prop::array::uniform32(any::<u8>()),
message in prop::collection::vec(any::<u8>(), 0..1000)
) {
prop_assume!(seed != [0u8; 32]);
let signing_key = VerifiedSigningKey::from_bytes(&seed);
let sig1 = signing_key.sign(&message);
let sig2 = signing_key.sign(&message);
prop_assert_eq!(sig1, sig2);
}
#[test]
fn prop_key_derivation_uniqueness(
seed1 in prop::array::uniform32(any::<u8>()),
seed2 in prop::array::uniform32(any::<u8>())
) {
prop_assume!(seed1 != [0u8; 32] && seed2 != [0u8; 32]);
prop_assume!(seed1 != seed2);
let key1 = VerifiedSigningKey::from_bytes(&seed1);
let key2 = VerifiedSigningKey::from_bytes(&seed2);
let vk1 = key1.verifying_key();
let vk2 = key2.verifying_key();
prop_assert_ne!(vk1, vk2);
}
#[test]
fn prop_tampered_signature_fails(
message in prop::collection::vec(any::<u8>(), 1..1000),
tamper_index in 0usize..64,
tamper_xor in 1u8..=255
) {
let signing_key = VerifiedSigningKey::generate();
let verifying_key = signing_key.verifying_key();
let signature = signing_key.sign(&message);
let mut sig_bytes = signature.to_bytes();
sig_bytes[tamper_index] ^= tamper_xor;
let tampered_sig = VerifiedSignature::from_bytes(&sig_bytes);
let result = verifying_key.verify(&message, &tampered_sig);
prop_assert!(result.is_err());
}
#[test]
fn prop_wrong_key_fails(message in prop::collection::vec(any::<u8>(), 1..1000)) {
let key1 = VerifiedSigningKey::generate();
let key2 = VerifiedSigningKey::generate();
let vk2 = key2.verifying_key();
let signature = key1.sign(&message);
let result = vk2.verify(&message, &signature);
prop_assert!(result.is_err());
}
}
}