falcon/safe_api.rs
1//! High-level safe Rust SDK for Falcon post-quantum digital signatures.
2//!
3//! This module provides ergonomic types for key generation, signing,
4//! verification, and key/signature serialization — hiding all `unsafe`
5//! operations behind a safe Rust interface.
6//!
7//! # Quick Start
8//!
9//! ```rust
10//! use falcon::safe_api::{FalconKeyPair, FalconSignature};
11//!
12//! // Generate a Falcon-512 key pair
13//! let kp = FalconKeyPair::generate(9).unwrap();
14//!
15//! // Sign a message
16//! let sig = kp.sign(b"Hello, post-quantum world!").unwrap();
17//!
18//! // Verify the signature
19//! FalconSignature::verify(sig.to_bytes(), kp.public_key(), b"Hello, post-quantum world!").unwrap();
20//! ```
21//!
22//! # Serialization
23//!
24//! Keys and signatures can be serialized to bytes and restored:
25//!
26//! ```rust
27//! # use falcon::safe_api::FalconKeyPair;
28//! let kp = FalconKeyPair::generate(9).unwrap();
29//!
30//! // Export keys
31//! let sk_bytes = kp.private_key().to_vec();
32//! let pk_bytes = kp.public_key().to_vec();
33//!
34//! // Reconstruct key pair from exported bytes
35//! let kp2 = FalconKeyPair::from_keys(&sk_bytes, &pk_bytes).unwrap();
36//!
37//! // Or reconstruct public key from private key alone
38//! let pk_only = FalconKeyPair::public_key_from_private(&sk_bytes).unwrap();
39//! assert_eq!(pk_bytes, pk_only);
40//! ```
41//!
42//! # Security Levels
43//!
44//! | logn | Variant | NIST Level | Private Key | Public Key | Signature |
45//! |------|---------|------------|-------------|------------|-----------|
46//! | 9 | Falcon-512 | I | 1281 B | 897 B | ~666 B |
47//! | 10 | Falcon-1024 | V | 2305 B | 1793 B | ~1280 B |
48
49use alloc::vec;
50use alloc::vec::Vec;
51use core::fmt;
52
53use crate::falcon as falcon_api;
54use crate::rng::get_seed;
55use crate::shake::{i_shake256_flip, i_shake256_init, i_shake256_inject, InnerShake256Context};
56
57// ======================================================================
58// Error type
59// ======================================================================
60
61/// Errors returned by the safe Falcon API.
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
64pub enum FalconError {
65 /// Random number generation failed.
66 RandomError,
67 /// A buffer was too small.
68 SizeError,
69 /// Invalid key or signature format.
70 FormatError,
71 /// Signature verification failed.
72 BadSignature,
73 /// An argument was invalid (e.g., logn out of range).
74 BadArgument,
75 /// Internal error in the Falcon algorithm.
76 InternalError,
77}
78
79impl fmt::Display for FalconError {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 match self {
82 FalconError::RandomError => write!(f, "random number generation failed"),
83 FalconError::SizeError => write!(f, "buffer size error"),
84 FalconError::FormatError => write!(f, "invalid format"),
85 FalconError::BadSignature => write!(f, "invalid signature"),
86 FalconError::BadArgument => write!(f, "invalid argument"),
87 FalconError::InternalError => write!(f, "internal error"),
88 }
89 }
90}
91
92fn translate_error(rc: i32) -> FalconError {
93 match rc {
94 falcon_api::FALCON_ERR_RANDOM => FalconError::RandomError,
95 falcon_api::FALCON_ERR_SIZE => FalconError::SizeError,
96 falcon_api::FALCON_ERR_FORMAT => FalconError::FormatError,
97 falcon_api::FALCON_ERR_BADSIG => FalconError::BadSignature,
98 falcon_api::FALCON_ERR_BADARG => FalconError::BadArgument,
99 falcon_api::FALCON_ERR_INTERNAL => FalconError::InternalError,
100 _ => FalconError::InternalError,
101 }
102}
103
104// ======================================================================
105// Key pair
106// ======================================================================
107
108/// A Falcon key pair (private key + public key).
109///
110/// The key pair stores encoded keys in the Falcon wire format.
111/// Use `logn = 9` for Falcon-512 (NIST Level I) or `logn = 10`
112/// for Falcon-1024 (NIST Level V).
113///
114/// # Serialization
115///
116/// ```rust
117/// # use falcon::safe_api::FalconKeyPair;
118/// let kp = FalconKeyPair::generate(9).unwrap();
119///
120/// // Export
121/// let sk = kp.private_key().to_vec();
122/// let pk = kp.public_key().to_vec();
123///
124/// // Import
125/// let kp2 = FalconKeyPair::from_keys(&sk, &pk).unwrap();
126/// assert_eq!(kp.public_key(), kp2.public_key());
127/// ```
128#[derive(Debug, Clone)]
129#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
130pub struct FalconKeyPair {
131 privkey: Vec<u8>,
132 pubkey: Vec<u8>,
133 logn: u32,
134}
135
136impl FalconKeyPair {
137 /// Generate a new Falcon key pair using OS entropy.
138 ///
139 /// # Arguments
140 ///
141 /// * `logn` — Degree parameter: 9 for Falcon-512, 10 for Falcon-1024.
142 /// Values 1–8 are research-only reduced variants.
143 ///
144 /// # Errors
145 ///
146 /// * [`FalconError::BadArgument`] if `logn` is outside 1–10.
147 /// * [`FalconError::RandomError`] if the OS RNG is unavailable.
148 pub fn generate(logn: u32) -> Result<Self, FalconError> {
149 if logn < 1 || logn > 10 {
150 return Err(FalconError::BadArgument);
151 }
152
153 let mut seed = [0u8; 48];
154 if !get_seed(&mut seed) {
155 return Err(FalconError::RandomError);
156 }
157
158 let result = Self::generate_deterministic(&seed, logn);
159
160 // Zeroize seed
161 for b in seed.iter_mut() {
162 unsafe {
163 core::ptr::write_volatile(b, 0);
164 }
165 }
166
167 result
168 }
169
170 /// Generate a new Falcon key pair from a deterministic seed.
171 ///
172 /// The seed is fed into a SHAKE256-based PRNG. The **same seed
173 /// always produces the same key pair**, making this ideal for
174 /// test vector reproducibility.
175 ///
176 /// # Arguments
177 ///
178 /// * `seed` — Entropy seed (≥ 32 bytes recommended).
179 /// * `logn` — Degree parameter: 9 for Falcon-512, 10 for Falcon-1024.
180 pub fn generate_deterministic(seed: &[u8], logn: u32) -> Result<Self, FalconError> {
181 if logn < 1 || logn > 10 {
182 return Err(FalconError::BadArgument);
183 }
184
185 let sk_len = falcon_api::falcon_privkey_size(logn);
186 let pk_len = falcon_api::falcon_pubkey_size(logn);
187 let tmp_len = falcon_api::falcon_tmpsize_keygen(logn);
188
189 let mut rng = InnerShake256Context::new();
190 i_shake256_init(&mut rng);
191 i_shake256_inject(&mut rng, seed);
192 i_shake256_flip(&mut rng);
193
194 let mut privkey = vec![0u8; sk_len];
195 let mut pubkey = vec![0u8; pk_len];
196 let mut tmp = vec![0u8; tmp_len];
197
198 let rc = falcon_api::falcon_keygen_make(
199 &mut rng,
200 logn,
201 &mut privkey,
202 Some(&mut pubkey),
203 &mut tmp,
204 );
205 if rc != 0 {
206 return Err(translate_error(rc));
207 }
208
209 Ok(FalconKeyPair {
210 privkey,
211 pubkey,
212 logn,
213 })
214 }
215
216 /// Reconstruct a key pair from previously exported private and public key bytes.
217 ///
218 /// Both keys must be valid Falcon-encoded keys with matching degree.
219 ///
220 /// # Example
221 ///
222 /// ```rust
223 /// # use falcon::safe_api::FalconKeyPair;
224 /// let kp = FalconKeyPair::generate(9).unwrap();
225 /// let sk = kp.private_key().to_vec();
226 /// let pk = kp.public_key().to_vec();
227 ///
228 /// let restored = FalconKeyPair::from_keys(&sk, &pk).unwrap();
229 /// assert_eq!(kp.logn(), restored.logn());
230 /// ```
231 pub fn from_keys(privkey: &[u8], pubkey: &[u8]) -> Result<Self, FalconError> {
232 if privkey.is_empty() || pubkey.is_empty() {
233 return Err(FalconError::FormatError);
234 }
235
236 let sk_logn = falcon_api::falcon_get_logn(privkey);
237 let pk_logn = falcon_api::falcon_get_logn(pubkey);
238 if sk_logn < 0 || pk_logn < 0 {
239 return Err(FalconError::FormatError);
240 }
241
242 // Validate header types: privkey = 0x5X, pubkey = 0x0X
243 if (privkey[0] & 0xF0) != 0x50 {
244 return Err(FalconError::FormatError);
245 }
246 if (pubkey[0] & 0xF0) != 0x00 {
247 return Err(FalconError::FormatError);
248 }
249
250 let logn = (sk_logn & 0x0F) as u32;
251 if logn != (pk_logn & 0x0F) as u32 {
252 return Err(FalconError::FormatError);
253 }
254
255 // Validate sizes
256 if privkey.len() != falcon_api::falcon_privkey_size(logn) {
257 return Err(FalconError::FormatError);
258 }
259 if pubkey.len() != falcon_api::falcon_pubkey_size(logn) {
260 return Err(FalconError::FormatError);
261 }
262
263 Ok(FalconKeyPair {
264 privkey: privkey.to_vec(),
265 pubkey: pubkey.to_vec(),
266 logn,
267 })
268 }
269
270 /// Reconstruct a key pair from a private key only.
271 ///
272 /// The public key is recomputed from the private key. This is slightly
273 /// slower than [`from_keys`](Self::from_keys) but only requires the
274 /// private key to be stored.
275 ///
276 /// # Example
277 ///
278 /// ```rust
279 /// # use falcon::safe_api::FalconKeyPair;
280 /// let kp = FalconKeyPair::generate(9).unwrap();
281 /// let sk = kp.private_key().to_vec();
282 ///
283 /// let restored = FalconKeyPair::from_private_key(&sk).unwrap();
284 /// assert_eq!(kp.public_key(), restored.public_key());
285 /// ```
286 pub fn from_private_key(privkey: &[u8]) -> Result<Self, FalconError> {
287 if privkey.is_empty() {
288 return Err(FalconError::FormatError);
289 }
290 if (privkey[0] & 0xF0) != 0x50 {
291 return Err(FalconError::FormatError);
292 }
293
294 let logn_val = falcon_api::falcon_get_logn(privkey);
295 if logn_val < 0 {
296 return Err(FalconError::FormatError);
297 }
298 let logn = logn_val as u32;
299
300 if privkey.len() != falcon_api::falcon_privkey_size(logn) {
301 return Err(FalconError::FormatError);
302 }
303
304 let pk_len = falcon_api::falcon_pubkey_size(logn);
305 let tmp_len = falcon_api::falcon_tmpsize_makepub(logn);
306 let mut pubkey = vec![0u8; pk_len];
307 let mut tmp = vec![0u8; tmp_len];
308
309 let rc = falcon_api::falcon_make_public(&mut pubkey, privkey, &mut tmp);
310 if rc != 0 {
311 return Err(translate_error(rc));
312 }
313
314 Ok(FalconKeyPair {
315 privkey: privkey.to_vec(),
316 pubkey,
317 logn,
318 })
319 }
320
321 /// Compute the public key bytes from a private key without creating a key pair.
322 ///
323 /// Useful when you only need the public key for distribution.
324 pub fn public_key_from_private(privkey: &[u8]) -> Result<Vec<u8>, FalconError> {
325 let kp = Self::from_private_key(privkey)?;
326 Ok(kp.pubkey)
327 }
328
329 /// Sign a message using this key pair.
330 ///
331 /// Uses the constant-time (CT) signature format and OS entropy.
332 /// Each call produces a **different signature** due to random nonce
333 /// generation.
334 ///
335 /// # Example
336 ///
337 /// ```rust
338 /// # use falcon::safe_api::{FalconKeyPair, FalconSignature};
339 /// let kp = FalconKeyPair::generate(9).unwrap();
340 /// let sig = kp.sign(b"my message").unwrap();
341 ///
342 /// // Signature can be exported and sent over the wire
343 /// let sig_bytes = sig.to_bytes().to_vec();
344 /// ```
345 pub fn sign(&self, message: &[u8]) -> Result<FalconSignature, FalconError> {
346 let sig_max = falcon_api::falcon_sig_ct_size(self.logn);
347 let tmp_len = falcon_api::falcon_tmpsize_signdyn(self.logn);
348
349 let mut seed = [0u8; 48];
350 if !get_seed(&mut seed) {
351 return Err(FalconError::RandomError);
352 }
353
354 let mut rng = InnerShake256Context::new();
355 i_shake256_init(&mut rng);
356 i_shake256_inject(&mut rng, &seed);
357 i_shake256_flip(&mut rng);
358
359 // Zeroize seed
360 for b in seed.iter_mut() {
361 unsafe {
362 core::ptr::write_volatile(b, 0);
363 }
364 }
365
366 let mut sig = vec![0u8; sig_max];
367 let mut sig_len = sig_max;
368 let mut tmp = vec![0u8; tmp_len];
369
370 let rc = falcon_api::falcon_sign_dyn(
371 &mut rng,
372 &mut sig,
373 &mut sig_len,
374 falcon_api::FALCON_SIG_CT,
375 &self.privkey,
376 message,
377 &mut tmp,
378 );
379 if rc != 0 {
380 return Err(translate_error(rc));
381 }
382
383 sig.truncate(sig_len);
384 Ok(FalconSignature { data: sig })
385 }
386
387 /// Sign a message with a deterministic seed (for testing / reproducibility).
388 ///
389 /// The same `(key, message, seed)` triple **always produces the same
390 /// signature**.
391 pub fn sign_deterministic(
392 &self,
393 message: &[u8],
394 seed: &[u8],
395 ) -> Result<FalconSignature, FalconError> {
396 let sig_max = falcon_api::falcon_sig_ct_size(self.logn);
397 let tmp_len = falcon_api::falcon_tmpsize_signdyn(self.logn);
398
399 let mut rng = InnerShake256Context::new();
400 i_shake256_init(&mut rng);
401 i_shake256_inject(&mut rng, seed);
402 i_shake256_flip(&mut rng);
403
404 let mut sig = vec![0u8; sig_max];
405 let mut sig_len = sig_max;
406 let mut tmp = vec![0u8; tmp_len];
407
408 let rc = falcon_api::falcon_sign_dyn(
409 &mut rng,
410 &mut sig,
411 &mut sig_len,
412 falcon_api::FALCON_SIG_CT,
413 &self.privkey,
414 message,
415 &mut tmp,
416 );
417 if rc != 0 {
418 return Err(translate_error(rc));
419 }
420
421 sig.truncate(sig_len);
422 Ok(FalconSignature { data: sig })
423 }
424
425 /// Get the encoded public key bytes.
426 ///
427 /// The returned bytes are in the standard Falcon wire format and can
428 /// be safely distributed, stored, or passed to [`FalconSignature::verify`].
429 pub fn public_key(&self) -> &[u8] {
430 &self.pubkey
431 }
432
433 /// Get the encoded private key bytes.
434 ///
435 /// ⚠️ **Secret material** — handle with care. These bytes can be used
436 /// to reconstruct the key pair via [`from_keys`](Self::from_keys) or
437 /// [`from_private_key`](Self::from_private_key).
438 pub fn private_key(&self) -> &[u8] {
439 &self.privkey
440 }
441
442 /// Get the Falcon degree parameter.
443 ///
444 /// Returns 9 for Falcon-512, 10 for Falcon-1024.
445 pub fn logn(&self) -> u32 {
446 self.logn
447 }
448
449 /// Get the security variant name.
450 pub fn variant_name(&self) -> &'static str {
451 match self.logn {
452 9 => "Falcon-512",
453 10 => "Falcon-1024",
454 n => {
455 // Reduced variants (research only)
456 match n {
457 1 => "Falcon-2",
458 2 => "Falcon-4",
459 3 => "Falcon-8",
460 4 => "Falcon-16",
461 5 => "Falcon-32",
462 6 => "Falcon-64",
463 7 => "Falcon-128",
464 8 => "Falcon-256",
465 _ => "Falcon-unknown",
466 }
467 }
468 }
469 }
470}
471
472// ======================================================================
473// Signature
474// ======================================================================
475
476/// A Falcon digital signature.
477///
478/// Contains the encoded signature bytes in constant-time (CT) format.
479/// Signatures can be exported with [`to_bytes`](Self::to_bytes) and
480/// imported with [`from_bytes`](Self::from_bytes).
481///
482/// # Wire Format
483///
484/// The signature bytes include a 1-byte header, 40-byte nonce, and the
485/// encoded signature coefficients. The total size is fixed for CT format
486/// (809 bytes for Falcon-512, 1577 bytes for Falcon-1024).
487#[derive(Debug, Clone)]
488#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
489pub struct FalconSignature {
490 data: Vec<u8>,
491}
492
493impl FalconSignature {
494 /// Create a signature from raw bytes (deserialization).
495 ///
496 /// The bytes must be a valid Falcon signature in any supported format.
497 /// No verification is performed — use [`verify`](Self::verify) to
498 /// check validity.
499 ///
500 /// # Example
501 ///
502 /// ```rust
503 /// # use falcon::safe_api::{FalconKeyPair, FalconSignature};
504 /// let kp = FalconKeyPair::generate(9).unwrap();
505 /// let sig = kp.sign(b"msg").unwrap();
506 ///
507 /// // Round-trip through bytes
508 /// let bytes = sig.to_bytes().to_vec();
509 /// let sig2 = FalconSignature::from_bytes(bytes);
510 /// ```
511 pub fn from_bytes(data: Vec<u8>) -> Self {
512 FalconSignature { data }
513 }
514
515 /// Verify a signature against a public key and message.
516 ///
517 /// Accepts signatures in any Falcon format (COMPRESSED, PADDED, CT) —
518 /// the format is auto-detected from the header byte.
519 ///
520 /// # Arguments
521 ///
522 /// * `sig` — The encoded signature bytes.
523 /// * `pubkey` — The encoded public key bytes.
524 /// * `message` — The original message that was signed.
525 ///
526 /// # Returns
527 ///
528 /// `Ok(())` if valid, `Err(FalconError::BadSignature)` otherwise.
529 ///
530 /// # Example
531 ///
532 /// ```rust
533 /// # use falcon::safe_api::{FalconKeyPair, FalconSignature};
534 /// let kp = FalconKeyPair::generate(9).unwrap();
535 /// let sig = kp.sign(b"msg").unwrap();
536 /// FalconSignature::verify(sig.to_bytes(), kp.public_key(), b"msg").unwrap();
537 /// ```
538 pub fn verify(sig: &[u8], pubkey: &[u8], message: &[u8]) -> Result<(), FalconError> {
539 if pubkey.is_empty() || sig.is_empty() {
540 return Err(FalconError::FormatError);
541 }
542 let logn_val = falcon_api::falcon_get_logn(pubkey);
543 if logn_val < 0 {
544 return Err(FalconError::FormatError);
545 }
546 let logn = logn_val as u32;
547 let tmp_len = falcon_api::falcon_tmpsize_verify(logn);
548 let mut tmp = vec![0u8; tmp_len];
549
550 // Auto-detect signature format (sig_type = 0).
551 let rc = falcon_api::falcon_verify(sig, 0, pubkey, message, &mut tmp);
552 if rc != 0 {
553 return Err(translate_error(rc));
554 }
555 Ok(())
556 }
557
558 /// Get the raw signature bytes (serialization).
559 ///
560 /// The returned bytes can be stored, transmitted, and later restored
561 /// with [`from_bytes`](Self::from_bytes).
562 pub fn to_bytes(&self) -> &[u8] {
563 &self.data
564 }
565
566 /// Consume the signature and return the owned byte vector.
567 pub fn into_bytes(self) -> Vec<u8> {
568 self.data
569 }
570
571 /// Get the length of the signature in bytes.
572 pub fn len(&self) -> usize {
573 self.data.len()
574 }
575
576 /// Check if the signature is empty.
577 pub fn is_empty(&self) -> bool {
578 self.data.is_empty()
579 }
580}