sare_lib/signing/
mod.rs

1use sare_core::{
2    format::signature::{SignatureFormat, SignatureHeaderFormat, SignatureMetadataFormat},
3    hybrid_sign::{ECSignature, PQSignature},
4};
5
6use crate::{SARE_VERSION, SareError, keys::MasterKey};
7
8pub struct Signing(MasterKey);
9
10impl Signing {
11    /// Create a new signing instance
12    pub fn new(master_key: MasterKey) -> Self {
13        Self(master_key)
14    }
15
16    /// Internal signing function
17    fn sign(&self, raw_message: &[u8], attached: bool) -> SignatureHeaderFormat {
18        let fullchain_fingerprint = self.0.get_fullchain_public_fingerprint();
19        let merged_message =
20            Self::merge_message_with_fingerprint(raw_message, &fullchain_fingerprint);
21
22        let (ec_keypair, pq_keypair) = self.0.get_signing_keypair();
23
24        let message_for_attached = if attached {
25            Some(raw_message.to_vec())
26        } else {
27            None
28        };
29
30        let ec_signature = ECSignature::new(&ec_keypair).hash_and_sign(&merged_message);
31        let pq_signature = PQSignature::new(&pq_keypair).hash_and_sign(&merged_message);
32
33        let signature_metadata = SignatureMetadataFormat {
34            ec_algorithm: ec_keypair.algorithm,
35            pq_algorithm: pq_keypair.algorithm,
36        };
37
38        let signature = SignatureFormat {
39            ec_public_key: ec_keypair.public_key,
40            pq_public_key: pq_keypair.public_key,
41            signature_metadata: Some(signature_metadata),
42            message: message_for_attached,
43            ec_signature,
44            pq_signature,
45            fullchain_fingerprint,
46        };
47
48        SignatureHeaderFormat {
49            version: SARE_VERSION,
50            signature,
51        }
52    }
53
54    /// Sign with attached message
55    pub fn sign_attached(&self, raw_message: &[u8]) -> SignatureHeaderFormat {
56        self.sign(raw_message, true)
57    }
58
59    /// Sign with detached message
60    pub fn sign_detached(&self, raw_message: &[u8]) -> SignatureHeaderFormat {
61        self.sign(raw_message, false)
62    }
63
64    /// Verify a signature with a provided message
65    fn verify(signature_header: &SignatureHeaderFormat, message: &[u8]) -> Result<bool, SareError> {
66        if signature_header.version > SARE_VERSION {
67            return Err(SareError::Unexpected(format!(
68                "sare version {} or higher is required, your version is {}",
69                signature_header.version, SARE_VERSION
70            )));
71        }
72
73        let signature = &signature_header.signature;
74        let merged_message =
75            Self::merge_message_with_fingerprint(message, &signature.fullchain_fingerprint);
76
77        let signature_metadata = signature.signature_metadata.as_ref().ok_or_else(|| {
78            SareError::CoreError(sare_core::CoreErrorKind::HybridSign(
79                sare_core::hybrid_sign::error::HybridSignError::Unexpected,
80            ))
81        })?;
82
83        let ec_valid = ECSignature::hash_and_verify(
84            &signature_metadata.ec_algorithm,
85            &signature.ec_public_key,
86            &merged_message,
87            &signature.ec_signature,
88        )?;
89
90        let pq_valid = PQSignature::hash_and_verify(
91            &signature_metadata.pq_algorithm,
92            &signature.pq_public_key,
93            &merged_message,
94            &signature.pq_signature,
95        )?;
96
97        Ok(ec_valid && pq_valid)
98    }
99
100    /// Verify a detached signature
101    pub fn verify_detached(
102        signature_header: &SignatureHeaderFormat,
103        raw_message: &[u8],
104    ) -> Result<bool, SareError> {
105        Self::verify(signature_header, raw_message)
106    }
107
108    /// Verify an attached signature
109    pub fn verify_attached(signature_header: &SignatureHeaderFormat) -> Result<bool, SareError> {
110        let signature = &signature_header.signature;
111        let message = signature.message.as_ref().ok_or_else(|| {
112            SareError::CoreError(sare_core::CoreErrorKind::HybridSign(
113                sare_core::hybrid_sign::error::HybridSignError::Unexpected,
114            ))
115        })?;
116
117        Self::verify(signature_header, message)
118    }
119
120    /// Helper to merge message with fullchain fingerprint
121    fn merge_message_with_fingerprint(message: &[u8], fingerprint: &[u8]) -> Vec<u8> {
122        let mut merged = Vec::with_capacity(message.len() + fingerprint.len());
123        merged.extend_from_slice(message);
124        merged.extend_from_slice(fingerprint);
125        merged
126    }
127}