chaincraft_rust/crypto/
ecdsa.rs

1//! ECDSA signature implementation
2
3use crate::crypto::{KeyType, KeyedCryptoPrimitive, PrivateKey, PublicKey, Signature};
4use crate::error::{ChaincraftError, CryptoError, Result};
5use async_trait::async_trait;
6use base64::{engine::general_purpose, Engine as _};
7use serde::{Deserialize, Serialize};
8
9/// ECDSA signature provider
10#[derive(Debug, Clone)]
11pub struct EcdsaSignature {
12    pub key_type: KeyType,
13}
14
15impl EcdsaSignature {
16    pub fn new(key_type: KeyType) -> Self {
17        Self { key_type }
18    }
19
20    pub fn ed25519() -> Self {
21        Self::new(KeyType::Ed25519)
22    }
23
24    pub fn secp256k1() -> Self {
25        Self::new(KeyType::Secp256k1)
26    }
27}
28
29impl Default for EcdsaSignature {
30    fn default() -> Self {
31        Self::ed25519()
32    }
33}
34
35#[async_trait]
36impl KeyedCryptoPrimitive for EcdsaSignature {
37    type PublicKey = PublicKey;
38    type PrivateKey = PrivateKey;
39    type Input = Vec<u8>;
40    type Output = Vec<u8>;
41    type Message = Vec<u8>;
42    type Signature = Signature;
43
44    async fn generate_keypair(&self) -> Result<(Self::PrivateKey, Self::PublicKey)> {
45        crate::crypto::utils::generate_keypair(self.key_type)
46    }
47
48    async fn compute(&self, key: &Self::PrivateKey, input: Self::Input) -> Result<Self::Output> {
49        // For ECDSA, compute is the same as signing
50        let signature = self.sign(key, &input).await?;
51        Ok(signature.to_bytes())
52    }
53
54    async fn sign(
55        &self,
56        private_key: &Self::PrivateKey,
57        message: &Self::Message,
58    ) -> Result<Self::Signature> {
59        crate::crypto::utils::sign_message(private_key, message)
60    }
61
62    async fn verify(
63        &self,
64        key: &Self::PublicKey,
65        input: Self::Input,
66        output: &Self::Output,
67    ) -> Result<bool> {
68        // For ed25519-dalek v1.0.1, the API is different
69        match key {
70            PublicKey::Ed25519(pk) => {
71                // For Ed25519, we need a 64-byte signature
72                if output.len() != 64 {
73                    return Err(ChaincraftError::Crypto(CryptoError::InvalidSignature));
74                }
75
76                // With v1.0.1, the signature requires a direct array conversion
77                let mut sig_bytes = [0u8; 64];
78                sig_bytes.copy_from_slice(&output[0..64]);
79
80                // Direct creation (v1.0.1 has a different API)
81                let signature = ed25519_dalek::Signature::from(sig_bytes);
82
83                // Verify the signature
84                use ed25519_dalek::Verifier;
85                match pk.verify(&input, &signature) {
86                    Ok(_) => Ok(true),
87                    Err(_) => Ok(false), // This is a verification failure, not an error
88                }
89            },
90            PublicKey::Secp256k1(pk) => {
91                // For Secp256k1, parse the signature and verify
92                let signature = match k256::ecdsa::Signature::from_slice(output.as_slice()) {
93                    Ok(s) => s,
94                    Err(_) => return Err(ChaincraftError::Crypto(CryptoError::InvalidSignature)),
95                };
96
97                use k256::ecdsa::{signature::Verifier, VerifyingKey};
98                let verifying_key = VerifyingKey::from(pk);
99                Ok(verifying_key.verify(&input, &signature).is_ok())
100            },
101        }
102    }
103}
104
105/// High-level ECDSA signature wrapper
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct ECDSASignature {
108    data: Vec<u8>,
109}
110
111impl ECDSASignature {
112    pub fn new(data: Vec<u8>) -> Self {
113        Self { data }
114    }
115
116    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
117        Ok(Self {
118            data: bytes.to_vec(),
119        })
120    }
121
122    pub fn to_bytes(&self) -> Vec<u8> {
123        self.data.clone()
124    }
125}
126
127/// High-level ECDSA signer
128#[derive(Debug)]
129pub struct ECDSASigner {
130    private_key: PrivateKey,
131    public_key: PublicKey,
132    provider: EcdsaSignature,
133}
134
135impl ECDSASigner {
136    pub fn new() -> Result<Self> {
137        // Use async context if available, otherwise create a simple fallback
138        let provider = EcdsaSignature::ed25519();
139        let (private_key, public_key) = futures::executor::block_on(provider.generate_keypair())?;
140
141        Ok(Self {
142            private_key,
143            public_key,
144            provider,
145        })
146    }
147
148    pub fn sign(&self, message: &[u8]) -> Result<ECDSASignature> {
149        let signature =
150            futures::executor::block_on(self.provider.sign(&self.private_key, &message.to_vec()))?;
151        Ok(ECDSASignature::new(signature.to_bytes()))
152    }
153
154    pub fn get_public_key_pem(&self) -> Result<String> {
155        match &self.public_key {
156            PublicKey::Ed25519(pk) => {
157                // Convert to PEM-like format
158                let bytes = pk.to_bytes();
159                let b64 = general_purpose::STANDARD.encode(bytes);
160                Ok(format!("-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----", b64))
161            },
162            PublicKey::Secp256k1(pk) => {
163                // For secp256k1, use the compressed format
164                use k256::elliptic_curve::sec1::ToEncodedPoint;
165                let point = pk.to_encoded_point(true);
166                let b64 = general_purpose::STANDARD.encode(point.as_bytes());
167                Ok(format!("-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----", b64))
168            },
169        }
170    }
171}
172
173/// High-level ECDSA verifier
174#[derive(Debug, Clone)]
175pub struct ECDSAVerifier {
176    provider: EcdsaSignature,
177}
178
179impl ECDSAVerifier {
180    pub fn new() -> Self {
181        Self {
182            provider: EcdsaSignature::ed25519(),
183        }
184    }
185
186    pub fn verify(
187        &self,
188        message: &[u8],
189        signature: &ECDSASignature,
190        public_key_pem: &str,
191    ) -> Result<bool> {
192        // Parse PEM format
193        let public_key = self.parse_public_key_pem(public_key_pem)?;
194
195        futures::executor::block_on(self.provider.verify(
196            &public_key,
197            message.to_vec(),
198            &signature.data,
199        ))
200    }
201
202    fn parse_public_key_pem(&self, pem: &str) -> Result<PublicKey> {
203        // Remove PEM headers and whitespace
204        let cleaned_pem = pem
205            .replace("-----BEGIN PUBLIC KEY-----", "")
206            .replace("-----END PUBLIC KEY-----", "")
207            .replace(['\n', '\r', ' '], "");
208
209        // Decode base64
210        let key_bytes = general_purpose::STANDARD
211            .decode(cleaned_pem)
212            .map_err(|_| ChaincraftError::Crypto(CryptoError::InvalidSignature))?;
213
214        // Try to parse as Ed25519 first (32 bytes)
215        if key_bytes.len() == 32 {
216            let mut array = [0u8; 32];
217            array.copy_from_slice(&key_bytes);
218
219            match ed25519_dalek::VerifyingKey::from_bytes(&array) {
220                Ok(pk) => Ok(PublicKey::Ed25519(pk)),
221                Err(_) => Err(ChaincraftError::Crypto(CryptoError::InvalidSignature)),
222            }
223        } else if key_bytes.len() == 33 {
224            // Try secp256k1 compressed format
225            match k256::PublicKey::from_sec1_bytes(&key_bytes) {
226                Ok(pk) => Ok(PublicKey::Secp256k1(pk)),
227                Err(_) => Err(ChaincraftError::Crypto(CryptoError::InvalidSignature)),
228            }
229        } else {
230            Err(ChaincraftError::Crypto(CryptoError::InvalidSignature))
231        }
232    }
233}
234
235impl Default for ECDSAVerifier {
236    fn default() -> Self {
237        Self::new()
238    }
239}