#![cfg(feature = "ed25519")]
use bolero::check;
use evidence::{
codec::Identity,
signature::ed25519::Ed25519,
signed::{Signed, SignedUnchecked},
verified::{Verified, VerifiedUnchecked},
};
fn signing_key_from_seed(seed: [u8; 32]) -> ed25519_dalek::SigningKey {
ed25519_dalek::SigningKey::from_bytes(&seed)
}
#[test]
#[allow(clippy::expect_used)] fn signed_verify_roundtrip() {
check!()
.with_type::<([u8; 32], Vec<u8>)>()
.for_each(|(seed, payload)| {
let signing_key = signing_key_from_seed(*seed);
let signed: Signed<Vec<u8>, Ed25519, Identity> = Signed::seal(&signing_key, payload);
let verified = signed
.try_verify()
.expect("verification should succeed for just-signed payload");
assert_eq!(
verified.payload(),
payload,
"verified payload must match original"
);
assert_eq!(
verified.issuer(),
&signing_key.verifying_key(),
"issuer must match signer's public key"
);
});
}
#[test]
fn signed_deterministic() {
check!()
.with_type::<([u8; 32], Vec<u8>)>()
.for_each(|(seed, payload)| {
let signing_key = signing_key_from_seed(*seed);
let signed1: Signed<Vec<u8>, Ed25519, Identity> = Signed::seal(&signing_key, payload);
let signed2: Signed<Vec<u8>, Ed25519, Identity> = Signed::seal(&signing_key, payload);
assert_eq!(signed1, signed2, "same input must produce same signature");
});
}
#[test]
fn different_payloads_different_signatures() {
check!()
.with_type::<([u8; 32], Vec<u8>, Vec<u8>)>()
.filter(|(_, a, b)| a != b)
.for_each(|(seed, payload_a, payload_b)| {
let signing_key = signing_key_from_seed(*seed);
let signed_a: Signed<Vec<u8>, Ed25519, Identity> =
Signed::seal(&signing_key, payload_a);
let signed_b: Signed<Vec<u8>, Ed25519, Identity> =
Signed::seal(&signing_key, payload_b);
assert_ne!(
signed_a.signature(),
signed_b.signature(),
"different payloads should produce different signatures"
);
});
}
#[test]
fn wrong_key_fails_verification() {
check!()
.with_type::<([u8; 32], [u8; 32], Vec<u8>)>()
.filter(|(a, b, _)| a != b)
.for_each(|(seed_signer, seed_wrong, payload)| {
let signing_key = signing_key_from_seed(*seed_signer);
let wrong_key = signing_key_from_seed(*seed_wrong);
let signed: Signed<Vec<u8>, Ed25519, Identity> = Signed::seal(&signing_key, payload);
let tampered: Signed<Vec<u8>, Ed25519, Identity> = Signed::from_unchecked_parts(
wrong_key.verifying_key(),
*signed.signature(),
signed.encoded_payload().to_vec(),
);
assert!(
tampered.try_verify().is_err(),
"verification must fail with wrong key"
);
});
}
#[test]
#[allow(clippy::indexing_slicing)] fn tampered_payload_fails_verification() {
check!()
.with_type::<([u8; 32], Vec<u8>)>()
.cloned()
.filter(|(_, payload)| !payload.is_empty())
.for_each(|(seed, payload)| {
let signing_key = signing_key_from_seed(seed);
let signed: Signed<Vec<u8>, Ed25519, Identity> = Signed::seal(&signing_key, &payload);
let mut tampered_bytes = signed.encoded_payload().to_vec();
tampered_bytes[0] = tampered_bytes[0].wrapping_add(1);
let tampered: Signed<Vec<u8>, Ed25519, Identity> =
Signed::from_unchecked_parts(*signed.issuer(), *signed.signature(), tampered_bytes);
assert!(
tampered.try_verify().is_err(),
"verification must fail with tampered payload"
);
});
}
#[test]
#[allow(clippy::expect_used)] fn verified_into_parts() {
check!()
.with_type::<([u8; 32], Vec<u8>)>()
.for_each(|(seed, payload)| {
let signing_key = signing_key_from_seed(*seed);
let signed: Signed<Vec<u8>, Ed25519, Identity> = Signed::seal(&signing_key, payload);
let verified = signed.try_verify().expect("verification should succeed");
let expected_issuer = signing_key.verifying_key();
let (recovered_signed, recovered_payload) = verified.into_parts();
assert_eq!(
recovered_signed.issuer(),
&expected_issuer,
"issuer must match"
);
assert_eq!(&recovered_signed, &signed, "signed envelope must match");
assert_eq!(&recovered_payload, payload, "payload must match");
});
}
#[test]
fn verified_unchecked_roundtrip() {
check!()
.with_type::<([u8; 32], Vec<u8>)>()
.for_each(|(seed, payload)| {
let signing_key = signing_key_from_seed(*seed);
let signed: Signed<Vec<u8>, Ed25519, Identity> = Signed::seal(&signing_key, payload);
let verified: Verified<Vec<u8>, Ed25519, Identity> =
Verified::from_unchecked_parts(signed.clone(), payload.clone());
assert_eq!(verified.issuer(), &signing_key.verifying_key());
assert_eq!(verified.payload(), payload);
assert_eq!(verified.signed(), &signed);
});
}
#[test]
#[allow(clippy::expect_used)] fn verified_signed_back_ref() {
check!()
.with_type::<([u8; 32], Vec<u8>)>()
.for_each(|(seed, payload)| {
let signing_key = signing_key_from_seed(*seed);
let signed: Signed<Vec<u8>, Ed25519, Identity> = Signed::seal(&signing_key, payload);
let verified = signed.try_verify().expect("verification should succeed");
assert_eq!(
verified.signed(),
&signed,
"verified must retain the original signed envelope"
);
assert_eq!(
verified.signed().encoded_payload(),
signed.encoded_payload(),
"encoded payload bytes must be preserved"
);
assert_eq!(
verified.signed().signature(),
signed.signature(),
"signature must be preserved"
);
});
}
#[test]
#[allow(clippy::expect_used)] fn into_verified_roundtrip() {
check!()
.with_type::<([u8; 32], Vec<u8>)>()
.for_each(|(seed, payload)| {
let signing_key = signing_key_from_seed(*seed);
let signed: Signed<Vec<u8>, Ed25519, Identity> = Signed::seal(&signing_key, payload);
let signed_clone = signed.clone();
let verified = signed.into_verified().expect("verification should succeed");
assert_eq!(
verified.payload(),
payload,
"verified payload must match original"
);
assert_eq!(
verified.signed(),
&signed_clone,
"signed envelope must be preserved"
);
});
}
#[test]
fn seal_verified_roundtrip() {
check!()
.with_type::<([u8; 32], Vec<u8>)>()
.cloned()
.for_each(|(seed, payload)| {
let signing_key = signing_key_from_seed(seed);
let verified: Verified<Vec<u8>, Ed25519, Identity> =
Signed::seal_verified(&signing_key, payload.clone());
assert_eq!(
verified.payload(),
&payload,
"verified payload must match original"
);
assert_eq!(
verified.issuer(),
&signing_key.verifying_key(),
"issuer must match signer's public key"
);
});
}
#[test]
#[allow(clippy::expect_used)] fn seal_verified_matches_seal_then_verify() {
check!()
.with_type::<([u8; 32], Vec<u8>)>()
.cloned()
.for_each(|(seed, payload)| {
let signing_key = signing_key_from_seed(seed);
let signed: Signed<Vec<u8>, Ed25519, Identity> = Signed::seal(&signing_key, &payload);
let two_step = signed.try_verify().expect("verification should succeed");
let one_step: Verified<Vec<u8>, Ed25519, Identity> =
Signed::seal_verified(&signing_key, payload.clone());
assert_eq!(
two_step.payload(),
one_step.payload(),
"payloads must match"
);
assert_eq!(
two_step.signed(),
one_step.signed(),
"signed envelopes must be identical"
);
});
}
#[test]
#[allow(clippy::expect_used)] fn seal_verified_envelope_verifies_independently() {
check!()
.with_type::<([u8; 32], Vec<u8>)>()
.cloned()
.for_each(|(seed, payload)| {
let signing_key = signing_key_from_seed(seed);
let verified: Verified<Vec<u8>, Ed25519, Identity> =
Signed::seal_verified(&signing_key, payload);
let re_verified = verified
.signed()
.try_verify()
.expect("re-verification should succeed");
assert_eq!(
re_verified.payload(),
verified.payload(),
"re-verified payload must match"
);
});
}