1use crate::VerificationError;
2use bcx_core::Digest;
3
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub enum SignatureAlgorithm {
7 Ed25519,
9 MlDsa65,
11 SlhDsaSha2_128s,
13 HybridEd25519MlDsa65,
15}
16
17impl SignatureAlgorithm {
18 #[must_use]
20 pub const fn expected_signature_len(self) -> usize {
21 match self {
22 Self::Ed25519 => 64,
23 Self::MlDsa65 => 3_293,
24 Self::SlhDsaSha2_128s => 7_856,
25 Self::HybridEd25519MlDsa65 => 3_357,
26 }
27 }
28}
29
30#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub struct AlgorithmPolicy<'a> {
33 admitted: &'a [SignatureAlgorithm],
34}
35
36impl<'a> AlgorithmPolicy<'a> {
37 #[must_use]
39 pub const fn new(admitted: &'a [SignatureAlgorithm]) -> Self {
40 Self { admitted }
41 }
42
43 #[must_use]
45 pub const fn admits(&self, algorithm: SignatureAlgorithm) -> bool {
46 let mut index = 0;
47 while index < self.admitted.len() {
48 if self.admitted[index].eq_const(algorithm) {
49 return true;
50 }
51 index += 1;
52 }
53 false
54 }
55}
56
57impl SignatureAlgorithm {
58 const fn eq_const(self, other: Self) -> bool {
59 matches!(
60 (self, other),
61 (Self::Ed25519, Self::Ed25519)
62 | (Self::MlDsa65, Self::MlDsa65)
63 | (Self::SlhDsaSha2_128s, Self::SlhDsaSha2_128s)
64 | (Self::HybridEd25519MlDsa65, Self::HybridEd25519MlDsa65)
65 )
66 }
67}
68
69#[derive(Clone, Copy, Debug, Eq, PartialEq)]
71pub struct SignatureEnvelope<'a> {
72 pub key_id: Digest,
74 pub algorithm: SignatureAlgorithm,
76 pub signature: &'a [u8],
78}
79
80impl SignatureEnvelope<'_> {
81 pub const fn validate(&self, maximum_signature_len: usize) -> Result<(), VerificationError> {
83 if self.key_id.is_zero() {
84 return Err(VerificationError::EmptyKeyId);
85 }
86 if self.signature.is_empty() {
87 return Err(VerificationError::EmptySignature);
88 }
89 if self.signature.len() > maximum_signature_len {
90 return Err(VerificationError::SignatureTooLarge);
91 }
92 if self.signature.len() != self.algorithm.expected_signature_len() {
93 return Err(VerificationError::InvalidSignature);
94 }
95 Ok(())
96 }
97}
98
99#[derive(Clone, Copy, Debug, Eq, PartialEq)]
101pub struct SignedEnvelope<'a, T> {
102 pub payload: T,
104 pub signature: SignatureEnvelope<'a>,
106}
107
108impl<'a, T> SignedEnvelope<'a, T> {
109 pub fn verify_bytes<V: Verifier>(
111 &self,
112 verifier: &V,
113 algorithm_policy: &AlgorithmPolicy<'_>,
114 canonical_payload: &[u8],
115 maximum_signature_len: usize,
116 ) -> Result<(), VerificationError> {
117 if !algorithm_policy.admits(self.signature.algorithm) {
118 return Err(VerificationError::AlgorithmNotAdmitted);
119 }
120 self.signature.validate(maximum_signature_len)?;
121 verifier.verify(&self.signature, canonical_payload)
122 }
123}
124
125pub trait Verifier {
127 fn verify(
129 &self,
130 envelope: &SignatureEnvelope<'_>,
131 canonical_payload: &[u8],
132 ) -> Result<(), VerificationError>;
133}