1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5use std::error::Error;
6use std::fmt;
7use std::ptr;
8
9pub(crate) mod bindings_include;
12use bindings_include::*;
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum PqcError {
18 BadArgument,
20 BadKey,
22 BadSignature,
24 NotImplemented,
26 Other(i32),
28}
29
30impl fmt::Display for PqcError {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 match self {
33 PqcError::BadArgument => write!(f, "Invalid arguments provided"),
34 PqcError::BadKey => write!(f, "Invalid key provided"),
35 PqcError::BadSignature => write!(f, "Invalid signature provided"),
36 PqcError::NotImplemented => write!(f, "Algorithm not implemented"),
37 PqcError::Other(code) => write!(f, "Unexpected error code: {}", code),
38 }
39 }
40}
41
42impl Error for PqcError {}
43
44impl From<bitcoin_pqc_error_t> for Result<(), PqcError> {
45 fn from(error: bitcoin_pqc_error_t) -> Self {
46 match error {
47 bitcoin_pqc_error_t::BITCOIN_PQC_OK => Ok(()),
48 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_ARG => Err(PqcError::BadArgument),
49 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_KEY => Err(PqcError::BadKey),
50 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_SIGNATURE => Err(PqcError::BadSignature),
51 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_NOT_IMPLEMENTED => Err(PqcError::NotImplemented),
52 _ => Err(PqcError::Other(error.0)),
53 }
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum Algorithm {
60 SECP256K1_SCHNORR,
62 FN_DSA_512,
64 ML_DSA_44,
66 SLH_DSA_128S,
68}
69
70impl From<Algorithm> for bitcoin_pqc_algorithm_t {
71 fn from(alg: Algorithm) -> Self {
72 match alg {
73 Algorithm::SECP256K1_SCHNORR => bitcoin_pqc_algorithm_t::BITCOIN_PQC_SECP256K1_SCHNORR,
74 Algorithm::FN_DSA_512 => bitcoin_pqc_algorithm_t::BITCOIN_PQC_FN_DSA_512,
75 Algorithm::ML_DSA_44 => bitcoin_pqc_algorithm_t::BITCOIN_PQC_ML_DSA_44,
76 Algorithm::SLH_DSA_128S => bitcoin_pqc_algorithm_t::BITCOIN_PQC_SLH_DSA_SHAKE_128S,
77 }
78 }
79}
80
81#[derive(Debug)]
83pub struct PublicKey {
84 pub algorithm: Algorithm,
86 pub bytes: Vec<u8>,
88}
89
90#[derive(Debug)]
92pub struct SecretKey {
93 pub algorithm: Algorithm,
95 pub bytes: Vec<u8>,
97}
98
99#[derive(Debug, Clone)]
101pub struct Signature {
102 pub algorithm: Algorithm,
104 pub bytes: Vec<u8>,
106}
107
108impl Drop for SecretKey {
109 fn drop(&mut self) {
110 for byte in &mut self.bytes {
112 *byte = 0;
113 }
114 }
115}
116
117#[derive(Debug)]
119pub struct KeyPair {
120 pub public_key: PublicKey,
122 pub secret_key: SecretKey,
124}
125
126pub fn generate_keypair(algorithm: Algorithm, random_data: &[u8]) -> Result<KeyPair, PqcError> {
137 if random_data.len() < 128 {
138 return Err(PqcError::BadArgument);
139 }
140
141 unsafe {
142 let mut keypair = bitcoin_pqc_keypair_t {
143 algorithm: algorithm.into(),
144 public_key: ptr::null_mut(),
145 secret_key: ptr::null_mut(),
146 public_key_size: 0,
147 secret_key_size: 0,
148 };
149
150 let result = bitcoin_pqc_keygen(
151 algorithm.into(),
152 &mut keypair,
153 random_data.as_ptr(),
154 random_data.len(),
155 );
156
157 if result != bitcoin_pqc_error_t::BITCOIN_PQC_OK {
158 return Err(match result {
159 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_ARG => PqcError::BadArgument,
160 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_KEY => PqcError::BadKey,
161 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_NOT_IMPLEMENTED => PqcError::NotImplemented,
162 _ => PqcError::Other(result.0 as i32),
163 });
164 }
165
166 let pk_slice =
168 std::slice::from_raw_parts(keypair.public_key as *const u8, keypair.public_key_size);
169 let sk_slice =
170 std::slice::from_raw_parts(keypair.secret_key as *const u8, keypair.secret_key_size);
171
172 let pk_bytes = pk_slice.to_vec();
173 let sk_bytes = sk_slice.to_vec();
174
175 bitcoin_pqc_keypair_free(&mut keypair);
177
178 Ok(KeyPair {
179 public_key: PublicKey {
180 algorithm,
181 bytes: pk_bytes,
182 },
183 secret_key: SecretKey {
184 algorithm,
185 bytes: sk_bytes,
186 },
187 })
188 }
189}
190
191pub fn sign(secret_key: &SecretKey, message: &[u8]) -> Result<Signature, PqcError> {
202 unsafe {
203 let mut signature = bitcoin_pqc_signature_t {
204 algorithm: secret_key.algorithm.into(),
205 signature: ptr::null_mut(),
206 signature_size: 0,
207 };
208
209 let result = bitcoin_pqc_sign(
210 secret_key.algorithm.into(),
211 secret_key.bytes.as_ptr(),
212 secret_key.bytes.len(),
213 message.as_ptr(),
214 message.len(),
215 &mut signature,
216 );
217
218 if result != bitcoin_pqc_error_t::BITCOIN_PQC_OK {
219 return Err(match result {
220 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_ARG => PqcError::BadArgument,
221 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_KEY => PqcError::BadKey,
222 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_SIGNATURE => PqcError::BadSignature,
223 bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_NOT_IMPLEMENTED => PqcError::NotImplemented,
224 _ => PqcError::Other(result.0 as i32),
225 });
226 }
227
228 let sig_slice =
230 std::slice::from_raw_parts(signature.signature as *const u8, signature.signature_size);
231 let sig_bytes = sig_slice.to_vec();
232
233 bitcoin_pqc_signature_free(&mut signature);
235
236 Ok(Signature {
237 algorithm: secret_key.algorithm,
238 bytes: sig_bytes,
239 })
240 }
241}
242
243pub fn verify(
255 public_key: &PublicKey,
256 message: &[u8],
257 signature: &Signature,
258) -> Result<(), PqcError> {
259 if public_key.algorithm != signature.algorithm {
260 return Err(PqcError::BadArgument);
261 }
262
263 unsafe {
264 let result = bitcoin_pqc_verify(
265 public_key.algorithm.into(),
266 public_key.bytes.as_ptr(),
267 public_key.bytes.len(),
268 message.as_ptr(),
269 message.len(),
270 signature.bytes.as_ptr(),
271 signature.bytes.len(),
272 );
273
274 result.into()
275 }
276}
277
278pub fn public_key_size(algorithm: Algorithm) -> usize {
288 unsafe { bitcoin_pqc_public_key_size(algorithm.into()) }
289}
290
291pub fn secret_key_size(algorithm: Algorithm) -> usize {
301 unsafe { bitcoin_pqc_secret_key_size(algorithm.into()) }
302}
303
304pub fn signature_size(algorithm: Algorithm) -> usize {
314 unsafe { bitcoin_pqc_signature_size(algorithm.into()) }
315}