use crate::core::matter::code::VerKeyCode;
use crate::core::primitives::{Cigar, Verfer};
#[cfg(feature = "alloc")]
#[allow(
unused_imports,
reason = "alloc prelude items; subset used per cfg/feature combination"
)]
use alloc::{format, string::ToString, vec};
use terrors::OneOf;
use crate::crypto::error::{CodeMismatchError, SignatureError};
pub fn verify(
verfer: &Verfer<'_>,
data: &[u8],
sig: &Cigar<'_>,
) -> Result<bool, OneOf<(SignatureError, CodeMismatchError)>> {
match verfer.code() {
VerKeyCode::Ed25519 | VerKeyCode::Ed25519N => {
verify_ed25519(verfer.raw(), data, sig.raw()).map_err(OneOf::new)
}
VerKeyCode::ECDSA256k1 | VerKeyCode::ECDSA256k1N => {
verify_secp256k1(verfer.raw(), data, sig.raw()).map_err(OneOf::new)
}
VerKeyCode::ECDSA256r1 | VerKeyCode::ECDSA256r1N => {
verify_secp256r1(verfer.raw(), data, sig.raw()).map_err(OneOf::new)
}
VerKeyCode::Ed448 | VerKeyCode::Ed448N => {
Err(OneOf::new(CodeMismatchError::IncompatibleCodes {
verkey: format!("{:?}", verfer.code()),
signature: "Ed448 not yet supported".into(),
}))
}
}
}
fn verify_ed25519(key: &[u8], data: &[u8], sig: &[u8]) -> Result<bool, SignatureError> {
use ed25519_dalek::{Signature, VerifyingKey};
let vk_bytes: [u8; 32] = key.try_into().map_err(|_| {
SignatureError::VerificationFailed(format!(
"invalid Ed25519 public key length: {}",
key.len()
))
})?;
let verifying_key = VerifyingKey::from_bytes(&vk_bytes)
.map_err(|e| SignatureError::VerificationFailed(e.to_string()))?;
let sig_bytes: [u8; 64] =
sig.try_into()
.map_err(|_| SignatureError::InvalidSignatureLength {
expected: 64,
actual: sig.len(),
})?;
let signature = Signature::from_bytes(&sig_bytes);
Ok(verifying_key.verify_strict(data, &signature).is_ok())
}
fn verify_secp256k1(key: &[u8], data: &[u8], sig: &[u8]) -> Result<bool, SignatureError> {
use k256::ecdsa::{Signature, VerifyingKey, signature::Verifier as _};
let verifying_key = VerifyingKey::from_sec1_bytes(key)
.map_err(|e| SignatureError::VerificationFailed(e.to_string()))?;
if sig.len() != 64 {
return Err(SignatureError::InvalidSignatureLength {
expected: 64,
actual: sig.len(),
});
}
let signature = Signature::from_slice(sig)
.map_err(|e| SignatureError::VerificationFailed(e.to_string()))?;
Ok(verifying_key.verify(data, &signature).is_ok())
}
fn verify_secp256r1(key: &[u8], data: &[u8], sig: &[u8]) -> Result<bool, SignatureError> {
use p256::ecdsa::{Signature, VerifyingKey, signature::Verifier as _};
let verifying_key = VerifyingKey::from_sec1_bytes(key)
.map_err(|e| SignatureError::VerificationFailed(e.to_string()))?;
if sig.len() != 64 {
return Err(SignatureError::InvalidSignatureLength {
expected: 64,
actual: sig.len(),
});
}
let signature = Signature::from_slice(sig)
.map_err(|e| SignatureError::VerificationFailed(e.to_string()))?;
Ok(verifying_key.verify(data, &signature).is_ok())
}
#[cfg(test)]
#[allow(
clippy::disallowed_methods,
reason = "test assertions use unwrap for clarity"
)]
mod tests {
use super::*;
use crate::core::matter::code::VerKeyCode;
use crate::crypto::algo::{Ed25519, Secp256k1, Secp256r1};
use crate::crypto::keypair::KeyPair;
#[test]
fn verify_ed25519_standalone() {
let kp = KeyPair::<Ed25519>::generate().unwrap();
let data = b"standalone verify test";
let sig = kp.sign(data).unwrap();
let verfer = kp.verfer(VerKeyCode::Ed25519).unwrap();
let result = verify(&verfer, data, &sig).unwrap();
assert!(result);
}
#[test]
fn verify_ed25519n_standalone() {
let kp = KeyPair::<Ed25519>::generate().unwrap();
let data = b"non-transferable test";
let sig = kp.sign(data).unwrap();
let verfer = kp.verfer(VerKeyCode::Ed25519N).unwrap();
let result = verify(&verfer, data, &sig).unwrap();
assert!(result);
}
#[test]
fn verify_secp256k1_standalone() {
let kp = KeyPair::<Secp256k1>::generate().unwrap();
let data = b"secp256k1 verify test";
let sig = kp.sign(data).unwrap();
let verfer = kp.verfer(VerKeyCode::ECDSA256k1).unwrap();
let result = verify(&verfer, data, &sig).unwrap();
assert!(result);
}
#[test]
fn verify_secp256r1_standalone() {
let kp = KeyPair::<Secp256r1>::generate().unwrap();
let data = b"secp256r1 verify test";
let sig = kp.sign(data).unwrap();
let verfer = kp.verfer(VerKeyCode::ECDSA256r1).unwrap();
let result = verify(&verfer, data, &sig).unwrap();
assert!(result);
}
#[test]
fn verify_rejects_wrong_data_standalone() {
let kp = KeyPair::<Ed25519>::generate().unwrap();
let sig = kp.sign(b"correct").unwrap();
let verfer = kp.verfer(VerKeyCode::Ed25519).unwrap();
assert!(!verify(&verfer, b"wrong", &sig).unwrap());
}
#[test]
fn verify_rejects_code_mismatch() {
use crate::core::matter::Matter;
use alloc::borrow::Cow;
let kp = KeyPair::<Ed25519>::generate().unwrap();
let sig = kp.sign(b"test").unwrap();
let ed_verfer = kp.verfer(VerKeyCode::Ed25519).unwrap();
let verfer = Matter::new_unchecked(
VerKeyCode::ECDSA256k1,
Cow::Owned(ed_verfer.raw().to_vec()),
Cow::from(""),
);
let result = verify(&verfer, b"test", &sig);
assert!(result.is_err() || !result.unwrap());
}
#[test]
fn verify_rejects_ed448_unsupported() {
use crate::core::matter::builder::MatterBuilder;
let verfer = MatterBuilder::new()
.with_code(VerKeyCode::Ed448)
.with_raw(vec![0u8; 57])
.unwrap()
.build()
.unwrap();
let sig = MatterBuilder::new()
.with_code(crate::core::matter::code::SignatureCode::Ed448Sig)
.with_raw(vec![0u8; 114])
.unwrap()
.build()
.unwrap();
let result = verify(&verfer, b"test", &sig);
assert!(result.is_err());
}
#[test]
fn verify_rejects_ed448n_unsupported() {
use crate::core::matter::builder::MatterBuilder;
let verfer = MatterBuilder::new()
.with_code(VerKeyCode::Ed448N)
.with_raw(vec![0u8; 57])
.unwrap()
.build()
.unwrap();
let sig = MatterBuilder::new()
.with_code(crate::core::matter::code::SignatureCode::Ed448Sig)
.with_raw(vec![0u8; 114])
.unwrap()
.build()
.unwrap();
let result = verify(&verfer, b"test", &sig);
assert!(result.is_err());
}
#[test]
fn verify_secp256k1_sig_with_ed25519_verfer_fails() {
let kp_k = KeyPair::<Secp256k1>::generate().unwrap();
let sig_k = kp_k.sign(b"test").unwrap();
let kp_e = KeyPair::<Ed25519>::generate().unwrap();
let verfer_e = kp_e.verfer(VerKeyCode::Ed25519).unwrap();
assert!(!verify(&verfer_e, b"test", &sig_k).unwrap());
}
#[test]
fn verify_ed25519_sig_with_secp256k1_verfer_fails() {
let kp_e = KeyPair::<Ed25519>::generate().unwrap();
let sig_e = kp_e.sign(b"test").unwrap();
let kp_k = KeyPair::<Secp256k1>::generate().unwrap();
let verfer_k = kp_k.verfer(VerKeyCode::ECDSA256k1).unwrap();
let result = verify(&verfer_k, b"test", &sig_e);
assert!(result.is_err() || !result.unwrap());
}
#[test]
fn verify_ed25519_sig_with_secp256r1_verfer_fails() {
let kp_e = KeyPair::<Ed25519>::generate().unwrap();
let sig_e = kp_e.sign(b"test").unwrap();
let kp_r = KeyPair::<Secp256r1>::generate().unwrap();
let verfer_r = kp_r.verfer(VerKeyCode::ECDSA256r1).unwrap();
let result = verify(&verfer_r, b"test", &sig_e);
assert!(result.is_err() || !result.unwrap());
}
#[test]
fn verify_secp256r1_sig_with_secp256k1_verfer_fails() {
let kp_r = KeyPair::<Secp256r1>::generate().unwrap();
let sig_r = kp_r.sign(b"test").unwrap();
let kp_k = KeyPair::<Secp256k1>::generate().unwrap();
let verfer_k = kp_k.verfer(VerKeyCode::ECDSA256k1).unwrap();
let result = verify(&verfer_k, b"test", &sig_r);
assert!(result.is_err() || !result.unwrap());
}
#[test]
fn verify_secp256k1_sig_with_secp256r1_verfer_fails() {
let kp_k = KeyPair::<Secp256k1>::generate().unwrap();
let sig_k = kp_k.sign(b"test").unwrap();
let kp_r = KeyPair::<Secp256r1>::generate().unwrap();
let verfer_r = kp_r.verfer(VerKeyCode::ECDSA256r1).unwrap();
let result = verify(&verfer_r, b"test", &sig_k);
assert!(result.is_err() || !result.unwrap());
}
#[test]
fn verify_ed25519_with_truncated_sig() {
use crate::core::matter::Matter;
use alloc::borrow::Cow;
let kp = KeyPair::<Ed25519>::generate().unwrap();
let verfer = kp.verfer(VerKeyCode::Ed25519).unwrap();
let bad_sig = Matter::new_unchecked(
crate::core::matter::code::SignatureCode::Ed25519Sig,
Cow::Owned(vec![0u8; 32]),
Cow::from(""),
);
let result = verify(&verfer, b"test", &bad_sig);
assert!(result.is_err());
}
#[test]
fn verify_secp256k1_with_truncated_sig() {
use crate::core::matter::Matter;
use alloc::borrow::Cow;
let kp = KeyPair::<Secp256k1>::generate().unwrap();
let verfer = kp.verfer(VerKeyCode::ECDSA256k1).unwrap();
let bad_sig = Matter::new_unchecked(
crate::core::matter::code::SignatureCode::ECDSA256k1Sig,
Cow::Owned(vec![0u8; 32]),
Cow::from(""),
);
let result = verify(&verfer, b"test", &bad_sig);
assert!(result.is_err());
}
#[test]
fn verify_secp256r1_with_truncated_sig() {
use crate::core::matter::Matter;
use alloc::borrow::Cow;
let kp = KeyPair::<Secp256r1>::generate().unwrap();
let verfer = kp.verfer(VerKeyCode::ECDSA256r1).unwrap();
let bad_sig = Matter::new_unchecked(
crate::core::matter::code::SignatureCode::ECDSA256r1Sig,
Cow::Owned(vec![0u8; 32]),
Cow::from(""),
);
let result = verify(&verfer, b"test", &bad_sig);
assert!(result.is_err());
}
#[test]
fn verify_ed25519_with_oversized_sig() {
use crate::core::matter::Matter;
use alloc::borrow::Cow;
let kp = KeyPair::<Ed25519>::generate().unwrap();
let verfer = kp.verfer(VerKeyCode::Ed25519).unwrap();
let bad_sig = Matter::new_unchecked(
crate::core::matter::code::SignatureCode::Ed25519Sig,
Cow::Owned(vec![0u8; 128]),
Cow::from(""),
);
let result = verify(&verfer, b"test", &bad_sig);
assert!(result.is_err());
}
#[test]
fn verify_with_empty_sig_bytes() {
use crate::core::matter::Matter;
use alloc::borrow::Cow;
let kp = KeyPair::<Ed25519>::generate().unwrap();
let verfer = kp.verfer(VerKeyCode::Ed25519).unwrap();
let bad_sig = Matter::new_unchecked(
crate::core::matter::code::SignatureCode::Ed25519Sig,
Cow::Owned(vec![]),
Cow::from(""),
);
let result = verify(&verfer, b"test", &bad_sig);
assert!(result.is_err());
}
#[test]
fn verify_ed25519_with_invalid_public_key_length() {
use crate::core::matter::Matter;
use alloc::borrow::Cow;
let verfer = Matter::new_unchecked(
VerKeyCode::Ed25519,
Cow::Owned(vec![0u8; 16]),
Cow::from(""),
);
let sig = Matter::new_unchecked(
crate::core::matter::code::SignatureCode::Ed25519Sig,
Cow::Owned(vec![0u8; 64]),
Cow::from(""),
);
let result = verify(&verfer, b"test", &sig);
assert!(result.is_err());
}
}