Skip to main content

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}