Skip to main content

confium_tc_frost_p256/
sign.rs

1//! P-256 ECDSA signing.
2//!
3//! Wraps `p256::ecdsa` for standard signature production and verification.
4//! Combined with `crate::shamir`, this provides a complete (if simplified)
5//! threshold ECDSA workflow for testing and integration.
6
7use crate::keys::Keypair;
8use p256::ecdsa::{Signature, signature::Signer};
9use thiserror::Error;
10
11/// Result of signing: DER-encoded signature bytes plus the raw signature object.
12#[derive(Debug, Clone)]
13pub struct Signed {
14    /// DER-encoded signature (ANS.1 SEQUENCE of two INTEGERs).
15    pub der_bytes: Vec<u8>,
16    /// Raw fixed-size signature (r || s, 64 bytes).
17    pub fixed_bytes: Vec<u8>,
18}
19
20/// Errors during signing.
21#[derive(Debug, Error)]
22pub enum SignError {
23    /// Signing failed (e.g., RNG failure).
24    #[error("signing failed: {0}")]
25    Sign(String),
26}
27
28/// Sign `message` with the keypair. Uses SHA-256 as the digest.
29pub fn sign_message(keypair: &Keypair, message: &[u8]) -> Result<Signed, SignError> {
30    let signing_key = keypair.to_signing_key();
31    let sig: Signature = signing_key
32        .try_sign(message)
33        .map_err(|e| SignError::Sign(format!("p256 sign: {e:?}")))?;
34    Ok(Signed {
35        der_bytes: sig.to_der().to_bytes().to_vec(),
36        fixed_bytes: sig.to_bytes().to_vec(),
37    })
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43    use crate::keys::generate_keypair;
44    use p256::ecdsa::signature::Verifier;
45
46    #[test]
47    fn sign_and_verify_round_trip() {
48        let keypair = generate_keypair();
49        let msg = b"hello, threshold world";
50        let signed = sign_message(&keypair, msg).unwrap();
51
52        let verifying = keypair.to_verifying_key();
53        let sig = Signature::from_der(&signed.der_bytes).unwrap();
54        verifying.verify(msg, &sig).unwrap();
55    }
56
57    #[test]
58    fn signature_bytes_are_distinct() {
59        let keypair = generate_keypair();
60        let s1 = sign_message(&keypair, b"message one").unwrap();
61        let s2 = sign_message(&keypair, b"message two").unwrap();
62        assert_ne!(s1.der_bytes, s2.der_bytes);
63    }
64
65    #[test]
66    fn fixed_size_signature_is_64_bytes() {
67        let keypair = generate_keypair();
68        let signed = sign_message(&keypair, b"x").unwrap();
69        assert_eq!(signed.fixed_bytes.len(), 64);
70    }
71}