diff --git a/src/dsa/rpo_falcon512/keys/mod.rs b/src/dsa/rpo_falcon512/keys/mod.rs index 548542a5..83a58d6b 100644 --- a/src/dsa/rpo_falcon512/keys/mod.rs +++ b/src/dsa/rpo_falcon512/keys/mod.rs @@ -1,10 +1,8 @@ use super::{ - math::{FalconFelt, FastFft, Polynomial}, + math::{FalconFelt, Polynomial}, ByteReader, ByteWriter, Deserializable, DeserializationError, Felt, Serializable, Signature, Word, MODULUS, }; -use num::Complex; -use num_complex::Complex64; mod public_key; pub use public_key::{PubKeyPoly, PublicKey}; @@ -12,19 +10,6 @@ pub use public_key::{PubKeyPoly, PublicKey}; mod secret_key; pub use secret_key::SecretKey; -// HELPER -// ================================================================================================ - -/// Computes the complex FFT of the secret key polynomials. -fn to_complex_fft(basis: &[Polynomial; 4]) -> [Polynomial>; 4] { - let [g, f, big_g, big_f] = basis.clone(); - let g_fft = g.map(|cc| Complex64::new(*cc as f64, 0.0)).fft(); - let minus_f_fft = f.map(|cc| -Complex64::new(*cc as f64, 0.0)).fft(); - let big_g_fft = big_g.map(|cc| Complex64::new(*cc as f64, 0.0)).fft(); - let minus_big_f_fft = big_f.map(|cc| -Complex64::new(*cc as f64, 0.0)).fft(); - [g_fft, minus_f_fft, big_g_fft, minus_big_f_fft] -} - // TESTS // ================================================================================================ diff --git a/src/dsa/rpo_falcon512/keys/secret_key.rs b/src/dsa/rpo_falcon512/keys/secret_key.rs index 86872a8b..64204a7d 100644 --- a/src/dsa/rpo_falcon512/keys/secret_key.rs +++ b/src/dsa/rpo_falcon512/keys/secret_key.rs @@ -8,13 +8,15 @@ use super::{ ByteReader, ByteWriter, Deserializable, DeserializationError, FalconError, Nonce, Serializable, ShortLatticeBasis, Signature, Word, MODULUS, N, SIGMA, SIG_L2_BOUND, }, - to_complex_fft, PubKeyPoly, PublicKey, + PubKeyPoly, PublicKey, }; use crate::dsa::rpo_falcon512::{hash_to_point::hash_to_point_rpo256, SIG_NONCE_LEN, SK_LEN}; use alloc::{string::ToString, vec::Vec}; use num::{Complex, Zero}; use rand::{thread_rng, Rng}; +use num_complex::Complex64; + // SECRET KEY // ================================================================================================ @@ -76,17 +78,6 @@ impl SecretKey { Self { secret_key: basis, tree } } - /// Derives the public key corresponding to this secret key using h = g /f [mod ϕ][mod p]. - pub fn compute_pub_key_poly(&self) -> PubKeyPoly { - let g: Polynomial = self.secret_key[0].clone().into(); - let g_fft = g.fft(); - let minus_f: Polynomial = self.secret_key[1].clone().into(); - let f = -minus_f; - let f_fft = f.fft(); - let h_fft = g_fft.hadamard_div(&f_fft); - h_fft.ifft().into() - } - // PUBLIC ACCESSORS // -------------------------------------------------------------------------------------------- @@ -97,7 +88,6 @@ impl SecretKey { /// Returns the public key corresponding to this secret key. pub fn public_key(&self) -> PublicKey { - // TODO: memoize public key commitment as computing it requires quite a bit of hashing. self.compute_pub_key_poly().into() } @@ -126,6 +116,20 @@ impl SecretKey { Ok(Signature::new(nonce, s1, s2)) } + // HELPER METHODS + // -------------------------------------------------------------------------------------------- + + /// Derives the public key corresponding to this secret key using h = g /f [mod ϕ][mod p]. + fn compute_pub_key_poly(&self) -> PubKeyPoly { + let g: Polynomial = self.secret_key[0].clone().into(); + let g_fft = g.fft(); + let minus_f: Polynomial = self.secret_key[1].clone().into(); + let f = -minus_f; + let f_fft = f.fft(); + let h_fft = g_fft.hadamard_div(&f_fft); + h_fft.ifft().into() + } + /// Signs a message polynomial with the secret key. /// /// Takes a randomness generator implementing `Rng` and message polynomial representing `c` @@ -133,7 +137,7 @@ impl SecretKey { /// /// # Errors /// Returns an error of signature generation fails. - pub fn sign_helper( + fn sign_helper( &self, c: Polynomial, rng: &mut R, @@ -196,16 +200,6 @@ impl SecretKey { }; Ok(s) } - - /// Determines how many bits to use for each field element of a given polynomial of the secret - /// key during decoding. - fn field_element_width(polynomial_index: usize) -> usize { - if polynomial_index == 2 { - 8 - } else { - 6 - } - } } // SERIALIZATION / DESERIALIZATION @@ -270,9 +264,9 @@ impl Deserializable for SecretKey { )); } - let width_f = Self::field_element_width(0); - let width_g = Self::field_element_width(1); - let width_big_f = Self::field_element_width(2); + let width_f = field_element_width(0); + let width_g = field_element_width(1); + let width_big_f = field_element_width(2); if byte_vector.len() != SK_LEN { return Err(DeserializationError::InvalidValue("Invalid encoding length: Failed to decode as length is different from the one expected".to_string())); @@ -308,3 +302,26 @@ impl Deserializable for SecretKey { Ok(Self::from_short_lattice_basis(basis)) } } + +// HELPER FUNCTIONS +// ================================================================================================ + +/// Computes the complex FFT of the secret key polynomials. +fn to_complex_fft(basis: &[Polynomial; 4]) -> [Polynomial>; 4] { + let [g, f, big_g, big_f] = basis.clone(); + let g_fft = g.map(|cc| Complex64::new(*cc as f64, 0.0)).fft(); + let minus_f_fft = f.map(|cc| -Complex64::new(*cc as f64, 0.0)).fft(); + let big_g_fft = big_g.map(|cc| Complex64::new(*cc as f64, 0.0)).fft(); + let minus_big_f_fft = big_f.map(|cc| -Complex64::new(*cc as f64, 0.0)).fft(); + [g_fft, minus_f_fft, big_g_fft, minus_big_f_fft] +} + +/// Determines how many bits to use for each field element of a given polynomial of the secret +/// key during decoding. +fn field_element_width(polynomial_index: usize) -> usize { + if polynomial_index == 2 { + 8 + } else { + 6 + } +} diff --git a/src/dsa/rpo_falcon512/signature.rs b/src/dsa/rpo_falcon512/signature.rs index f0839ec2..c9a49aae 100644 --- a/src/dsa/rpo_falcon512/signature.rs +++ b/src/dsa/rpo_falcon512/signature.rs @@ -87,35 +87,7 @@ impl Signature { let c = hash_to_point_rpo256(message, &self.nonce); let s1 = self.s1.clone(); let s2 = self.s2.clone(); - Self::verify_helper(c, s1, s2, pubkey_com) - } - - /// Takes the hash-to-point polynomial `c` of a message and the signature polynomials over - /// the message `(s1, s2)` and returns `true` is the signature is a valid signature for - /// the given parameters, otherwise it returns `false`. - pub fn verify_helper( - c: Polynomial, - s1: SignaturePoly, - s2: SignaturePoly, - pubkey_com: Word, - ) -> bool { - let s1_fft = s1.fft(); - let s2_fft = s2.fft(); - let c_fft = c.fft(); - - // h = s2^(-1) * (c - s1) - let h_fft = (c_fft - s1_fft).hadamard_div(&s2_fft); - let h = h_fft.ifft(); - - let length_squared_s1 = s1.norm_squared(); - let length_squared_s2 = s2.norm_squared(); - let length_squared = length_squared_s1 + length_squared_s2; - let is_short = length_squared < SIG_L2_BOUND; - - let h: Polynomial = h.into(); - let h_digest: Word = Rpo256::hash_elements(&h.coefficients).into(); - - h_digest == pubkey_com && is_short + verify_helper(c, s1, s2, pubkey_com) } } @@ -230,6 +202,34 @@ impl Deserializable for SignaturePoly { // HELPER FUNCTIONS // ================================================================================================ +/// Takes the hash-to-point polynomial `c` of a message and the signature polynomials over +/// the message `(s1, s2)` and returns `true` is the signature is a valid signature for +/// the given parameters, otherwise it returns `false`. +fn verify_helper( + c: Polynomial, + s1: SignaturePoly, + s2: SignaturePoly, + pubkey_com: Word, +) -> bool { + let s1_fft = s1.fft(); + let s2_fft = s2.fft(); + let c_fft = c.fft(); + + // h = s2^(-1) * (c - s1) + let h_fft = (c_fft - s1_fft).hadamard_div(&s2_fft); + let h = h_fft.ifft(); + + let length_squared_s1 = s1.norm_squared(); + let length_squared_s2 = s2.norm_squared(); + let length_squared = length_squared_s1 + length_squared_s2; + let is_short = length_squared < SIG_L2_BOUND; + + let h: Polynomial = h.into(); + let h_digest: Word = Rpo256::hash_elements(&h.coefficients).into(); + + h_digest == pubkey_com && is_short +} + /// Checks whether a set of coefficients is a valid one for a signature polynomial. fn are_coefficients_valid(x: &[i16]) -> bool { if x.len() != N {