Skip to main content

ri/protocol/
falcon.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of Ri.
4//! The Ri project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18#![allow(non_snake_case)]
19
20//! # Falcon Signature
21//!
22//! This module implements the Falcon digital signature algorithm
23//! using liboqs. Falcon is EUF-CMA secure and is based on the hardness
24//! of the Shortest Integer Solution (SIS) problem over NTRU lattices.
25//!
26//! ## Security Level
27//!
28//! - **Falcon512**: NIST Level 1 ≈ AES-128 (compact signatures)
29//! - **Falcon1024**: NIST Level 5 ≈ AES-256 (compact signatures)
30//!
31//! ## Advantages
32//!
33//! Falcon provides the smallest signature sizes among NIST PQC finalists,
34//! making it ideal for bandwidth-constrained scenarios.
35//!
36//! ## Usage
37//!
38//! ```rust,ignore
39//! use ri::protocol::falcon::FalconSigner;
40//!
41//! let signer = FalconSigner::new();
42//! let (public_key, secret_key) = signer.keygen()?;
43//! let message = b"Hello, Post-Quantum World!";
44//! let signature = signer.sign(&secret_key, message)?;
45//! assert!(signer.verify(&public_key, message, &signature)?);
46//! ```
47
48use std::sync::Arc;
49use crate::core::{RiResult, RiError};
50
51#[derive(Debug, Clone)]
52#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
53pub struct FalconPublicKey(pub Vec<u8>);
54
55#[derive(Debug, Clone)]
56#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
57pub struct FalconSecretKey(pub Vec<u8>);
58
59#[derive(Debug, Clone)]
60#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
61pub struct FalconSignature(pub Vec<u8>);
62
63#[derive(Debug, Clone)]
64#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
65pub struct FalconSigner {
66    algorithm: Arc<std::sync::RwLock<FalconAlgorithm>>,
67}
68
69#[derive(Debug, Clone, Copy)]
70enum FalconAlgorithm {
71    Falcon512,
72    Falcon1024,
73}
74
75impl FalconSigner {
76    pub fn new() -> Self {
77        Self {
78            algorithm: Arc::new(std::sync::RwLock::new(FalconAlgorithm::Falcon512)),
79        }
80    }
81
82    pub fn with_algorithm(algorithm: super::RiPostQuantumAlgorithm) -> Self {
83        let algo = match algorithm {
84            super::RiPostQuantumAlgorithm::Falcon512 => FalconAlgorithm::Falcon512,
85            super::RiPostQuantumAlgorithm::Falcon1024 => FalconAlgorithm::Falcon1024,
86            _ => FalconAlgorithm::Falcon512,
87        };
88        Self {
89            algorithm: Arc::new(std::sync::RwLock::new(algo)),
90        }
91    }
92
93    #[cfg(feature = "protocol")]
94    pub fn keygen(&self) -> RiResult<(Vec<u8>, Vec<u8>)> {
95        use oqs::sig::Sig;
96
97        let algo = *self.algorithm.read().map_err(|e| 
98            RiError::InvalidState(format!("Lock error: {}", e))
99        )?;
100        let sig = match algo {
101            FalconAlgorithm::Falcon512 => Sig::new(oqs::sig::Algorithm::Falcon512),
102            FalconAlgorithm::Falcon1024 => Sig::new(oqs::sig::Algorithm::Falcon1024),
103        }.map_err(|e| RiError::Other(format!("Failed to initialize Falcon: {:?}", e)))?;
104
105        let (pk, sk) = sig.keypair()
106            .map_err(|e| RiError::Other(format!("Falcon keygen failed: {:?}", e)))?;
107        Ok((pk.into_vec(), sk.into_vec()))
108    }
109
110    #[cfg(not(feature = "protocol"))]
111    pub fn keygen(&self) -> RiResult<(Vec<u8>, Vec<u8>)> {
112        Err(RiError::Other(
113            "Post-quantum cryptography requires the 'protocol' feature. \
114             Enable with: cargo build --features protocol".to_string()
115        ))
116    }
117
118    #[cfg(feature = "protocol")]
119    pub fn sign(&self, secret_key: &[u8], message: &[u8]) -> RiResult<Vec<u8>> {
120        use oqs::sig::Sig;
121
122        let algo = *self.algorithm.read().map_err(|e| 
123            RiError::InvalidState(format!("Lock error: {}", e))
124        )?;
125        let sig = match algo {
126            FalconAlgorithm::Falcon512 => Sig::new(oqs::sig::Algorithm::Falcon512),
127            FalconAlgorithm::Falcon1024 => Sig::new(oqs::sig::Algorithm::Falcon1024),
128        }.map_err(|e| RiError::Other(format!("Failed to initialize Falcon: {:?}", e)))?;
129
130        let sk = sig.secret_key_from_bytes(secret_key)
131            .ok_or_else(|| RiError::Other("Invalid secret key".to_string()))?;
132        let signature = sig.sign(message, &sk)
133            .map_err(|e| RiError::Other(format!("Falcon sign failed: {:?}", e)))?;
134        Ok(signature.into_vec())
135    }
136
137    #[cfg(not(feature = "protocol"))]
138    pub fn sign(&self, _secret_key: &[u8], _message: &[u8]) -> RiResult<Vec<u8>> {
139        Err(RiError::Other(
140            "Post-quantum cryptography requires the 'protocol' feature. \
141             Enable with: cargo build --features protocol".to_string()
142        ))
143    }
144
145    #[cfg(feature = "protocol")]
146    pub fn verify(&self, public_key: &[u8], message: &[u8], signature: &[u8]) -> RiResult<bool> {
147        use oqs::sig::Sig;
148
149        let algo = *self.algorithm.read().map_err(|e| 
150            RiError::InvalidState(format!("Lock error: {}", e))
151        )?;
152        let sig = match algo {
153            FalconAlgorithm::Falcon512 => Sig::new(oqs::sig::Algorithm::Falcon512),
154            FalconAlgorithm::Falcon1024 => Sig::new(oqs::sig::Algorithm::Falcon1024),
155        }.map_err(|e| RiError::Other(format!("Failed to initialize Falcon: {:?}", e)))?;
156
157        let pk = sig.public_key_from_bytes(public_key)
158            .ok_or_else(|| RiError::Other("Invalid public key".to_string()))?;
159        let sig_bytes = sig.signature_from_bytes(signature)
160            .ok_or_else(|| RiError::Other("Invalid signature".to_string()))?;
161        let result = sig.verify(message, &sig_bytes, &pk);
162        Ok(result.is_ok())
163    }
164
165    #[cfg(not(feature = "protocol"))]
166    pub fn verify(&self, _public_key: &[u8], _message: &[u8], _signature: &[u8]) -> RiResult<bool> {
167        Err(RiError::Other(
168            "Post-quantum cryptography requires the 'protocol' feature. \
169             Enable with: cargo build --features protocol".to_string()
170        ))
171    }
172}
173
174impl Default for FalconSigner {
175    fn default() -> Self {
176        Self::new()
177    }
178}
179
180#[cfg(feature = "pyo3")]
181#[pyo3::prelude::pymethods]
182impl FalconSigner {
183    #[new]
184    pub fn new_py() -> Self {
185        Self::new()
186    }
187
188    pub fn keygen_py(&self) -> Option<(Vec<u8>, Vec<u8>)> {
189        self.keygen().ok()
190    }
191
192    pub fn sign_py(&self, secret_key: &[u8], message: &[u8]) -> Option<Vec<u8>> {
193        self.sign(secret_key, message).ok()
194    }
195
196    pub fn verify_py(&self, public_key: &[u8], message: &[u8], signature: &[u8]) -> bool {
197        self.verify(public_key, message, signature).unwrap_or(false)
198    }
199}