Updated Makefile and Readme

This commit is contained in:
Paul-Henry Kajfasz
2024-08-16 15:07:27 -07:00
parent d92fae7f82
commit ad0f472708
50 changed files with 416 additions and 278 deletions

View File

@@ -1,7 +1,9 @@
use super::{math::FalconFelt, Nonce, Polynomial, Rpo256, Word, MODULUS, N, ZERO};
use alloc::vec::Vec;
use num::Zero;
use super::{math::FalconFelt, Nonce, Polynomial, Rpo256, Word, MODULUS, N, ZERO};
// HASH-TO-POINT FUNCTIONS
// ================================================================================================

View File

@@ -15,12 +15,13 @@ pub use secret_key::SecretKey;
#[cfg(test)]
mod tests {
use crate::{dsa::rpo_falcon512::SecretKey, Word, ONE};
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
use winter_math::FieldElement;
use winter_utils::{Deserializable, Serializable};
use crate::{dsa::rpo_falcon512::SecretKey, Word, ONE};
#[test]
fn test_falcon_verification() {
let seed = [0_u8; 32];

View File

@@ -1,13 +1,14 @@
use crate::dsa::rpo_falcon512::FALCON_ENCODING_BITS;
use alloc::string::ToString;
use core::ops::Deref;
use num::Zero;
use super::{
super::{Rpo256, LOG_N, N, PK_LEN},
ByteReader, ByteWriter, Deserializable, DeserializationError, FalconFelt, Felt, Polynomial,
Serializable, Signature, Word,
};
use alloc::string::ToString;
use core::ops::Deref;
use num::Zero;
use crate::dsa::rpo_falcon512::FALCON_ENCODING_BITS;
// PUBLIC KEY
// ================================================================================================
@@ -116,7 +117,7 @@ impl Deserializable for PubKeyPoly {
if acc_len >= FALCON_ENCODING_BITS {
acc_len -= FALCON_ENCODING_BITS;
let w = (acc >> acc_len) & 0x3FFF;
let w = (acc >> acc_len) & 0x3fff;
let element = w.try_into().map_err(|err| {
DeserializationError::InvalidValue(format!(
"Failed to decode public key: {err}"

View File

@@ -1,3 +1,11 @@
use alloc::{string::ToString, vec::Vec};
use num::Complex;
#[cfg(not(feature = "std"))]
use num::Float;
use num_complex::Complex64;
use rand::Rng;
use super::{
super::{
math::{ffldl, ffsampling, gram, normalize_tree, FalconFelt, FastFft, LdlTree, Polynomial},
@@ -10,13 +18,6 @@ use super::{
use crate::dsa::rpo_falcon512::{
hash_to_point::hash_to_point_rpo256, math::ntru_gen, SIG_NONCE_LEN, SK_LEN,
};
use alloc::{string::ToString, vec::Vec};
use num::Complex;
use num_complex::Complex64;
use rand::Rng;
#[cfg(not(feature = "std"))]
use num::Float;
// CONSTANTS
// ================================================================================================

View File

@@ -1,11 +1,12 @@
use super::{fft::FastFft, polynomial::Polynomial, samplerz::sampler_z};
use alloc::boxed::Box;
#[cfg(not(feature = "std"))]
use num::Float;
use num::{One, Zero};
use num_complex::{Complex, Complex64};
use rand::Rng;
#[cfg(not(feature = "std"))]
use num::Float;
use super::{fft::FastFft, polynomial::Polynomial, samplerz::sampler_z};
const SIGMIN: f64 = 1.2778336969128337;
@@ -80,11 +81,11 @@ pub fn normalize_tree(tree: &mut LdlTree, sigma: f64) {
LdlTree::Branch(_ell, left, right) => {
normalize_tree(left, sigma);
normalize_tree(right, sigma);
}
},
LdlTree::Leaf(vector) => {
vector[0] = Complex::new(sigma / vector[0].re.sqrt(), 0.0);
vector[1] = Complex64::zero();
}
},
}
}
@@ -110,7 +111,7 @@ pub fn ffsampling<R: Rng>(
let z0 = Polynomial::<Complex64>::merge_fft(&bold_z0.0, &bold_z0.1);
(z0, z1)
}
},
LdlTree::Leaf(value) => {
let z0 = sampler_z(t.0.coefficients[0].re, value[0].re, SIGMIN, &mut rng);
let z1 = sampler_z(t.1.coefficients[0].re, value[0].re, SIGMIN, &mut rng);
@@ -118,6 +119,6 @@ pub fn ffsampling<R: Rng>(
Polynomial::new(vec![Complex64::new(z0 as f64, 0.0)]),
Polynomial::new(vec![Complex64::new(z1 as f64, 0.0)]),
)
}
},
}
}

View File

@@ -1,14 +1,15 @@
use super::{field::FalconFelt, polynomial::Polynomial, Inverse};
use alloc::vec::Vec;
use core::{
f64::consts::PI,
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use num::{One, Zero};
use num_complex::Complex64;
#[cfg(not(feature = "std"))]
use num::Float;
use num::{One, Zero};
use num_complex::Complex64;
use super::{field::FalconFelt, polynomial::Polynomial, Inverse};
/// Implements Cyclotomic FFT without bitreversing the outputs, and using precomputed powers of the
/// 2n-th primitive root of unity.
@@ -102,7 +103,8 @@ where
array
}
/// Reorders the given elements in the array by reversing the binary expansions of their indices.
/// Reorders the given elements in the array by reversing the binary expansions of their
/// indices.
fn bitreverse_array<T>(array: &mut [T]) {
let n = array.len();
for i in 0..n {
@@ -118,19 +120,14 @@ where
///
/// Arguments:
///
/// - a : &mut [Self]
/// (a reference to) a mutable array of field elements which is to
/// be transformed under the FFT. The transformation happens in-
/// place.
/// - a : &mut [Self] (a reference to) a mutable array of field elements which is to be
/// transformed under the FFT. The transformation happens in- place.
///
/// - psi_rev: &[Self]
/// (a reference to) an array of powers of psi, from 0 to n-1,
/// but ordered by bit-reversed index. Here psi is a primitive root
/// of order 2n. You can use
/// `Self::bitreversed_powers(psi, n)` for this purpose, but this
/// trait implementation is not const. For the performance benefit
/// you want a precompiled array, which you can get if you can get
/// by implementing the same method and marking it "const".
/// - psi_rev: &[Self] (a reference to) an array of powers of psi, from 0 to n-1, but ordered
/// by bit-reversed index. Here psi is a primitive root of order 2n. You can use
/// `Self::bitreversed_powers(psi, n)` for this purpose, but this trait implementation is not
/// const. For the performance benefit you want a precompiled array, which you can get if you
/// can get by implementing the same method and marking it "const".
fn fft(a: &mut [Self], psi_rev: &[Self]) {
let n = a.len();
let mut t = n;
@@ -158,20 +155,15 @@ where
///
/// Arguments:
///
/// - a : &mut [Self]
/// (a reference to) a mutable array of field elements which is to
/// be transformed under the IFFT. The transformation happens in-
/// place.
/// - a : &mut [Self] (a reference to) a mutable array of field elements which is to be
/// transformed under the IFFT. The transformation happens in- place.
///
/// - psi_inv_rev: &[Self]
/// (a reference to) an array of powers of psi^-1, from 0 to n-1,
/// but ordered by bit-reversed index. Here psi is a primitive root of
/// order 2n. You can use
/// `Self::bitreversed_powers(Self::inverse_or_zero(psi), n)` for
/// this purpose, but this trait implementation is not const. For
/// the performance benefit you want a precompiled array, which you
/// can get if you can get by implementing the same methods and marking
/// them "const".
/// - psi_inv_rev: &[Self] (a reference to) an array of powers of psi^-1, from 0 to n-1, but
/// ordered by bit-reversed index. Here psi is a primitive root of order 2n. You can use
/// `Self::bitreversed_powers(Self::inverse_or_zero(psi), n)` for this purpose, but this
/// trait implementation is not const. For the performance benefit you want a precompiled
/// array, which you can get if you can get by implementing the same methods and marking them
/// "const".
fn ifft(a: &mut [Self], psi_inv_rev: &[Self], ninv: Self) {
let n = a.len();
let mut t = 1;

View File

@@ -1,8 +1,10 @@
use super::{fft::CyclotomicFourier, Inverse, MODULUS};
use alloc::string::String;
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use num::{One, Zero};
use super::{fft::CyclotomicFourier, Inverse, MODULUS};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct FalconFelt(u32);

View File

@@ -2,17 +2,19 @@
//!
//! It uses and acknowledges the work in:
//!
//! 1. The [reference](https://falcon-sign.info/impl/README.txt.html) implementation by Thomas Pornin.
//! 1. The [reference](https://falcon-sign.info/impl/README.txt.html) implementation by Thomas
//! Pornin.
//! 2. The [Rust](https://github.com/aszepieniec/falcon-rust) implementation by Alan Szepieniec.
use super::MODULUS;
use alloc::{string::String, vec::Vec};
use core::ops::MulAssign;
#[cfg(not(feature = "std"))]
use num::Float;
use num::{BigInt, FromPrimitive, One, Zero};
use num_complex::Complex64;
use rand::Rng;
#[cfg(not(feature = "std"))]
use num::Float;
use super::MODULUS;
mod fft;
pub use fft::{CyclotomicFourier, FastFft};
@@ -152,7 +154,7 @@ fn ntru_solve(
{
None
}
}
},
}
}

View File

@@ -1,12 +1,18 @@
use super::{field::FalconFelt, Inverse};
use crate::dsa::rpo_falcon512::{MODULUS, N};
use crate::Felt;
use alloc::vec::Vec;
use core::default::Default;
use core::fmt::Debug;
use core::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign};
use core::{
default::Default,
fmt::Debug,
ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign},
};
use num::{One, Zero};
use super::{field::FalconFelt, Inverse};
use crate::{
dsa::rpo_falcon512::{MODULUS, N},
Felt,
};
#[derive(Debug, Clone, Default)]
pub struct Polynomial<F> {
pub coefficients: Vec<F>,
@@ -134,8 +140,8 @@ impl<
Self::new(coefficients)
}
/// Computes the galois adjoint of the polynomial in the cyclotomic ring F\[ X \] / < X^n + 1 > ,
/// which corresponds to f(x^2).
/// Computes the galois adjoint of the polynomial in the cyclotomic ring F\[ X \] / < X^n + 1 >
/// , which corresponds to f(x^2).
pub fn galois_adjoint(&self) -> Self {
Self::new(
self.coefficients

View File

@@ -1,8 +1,8 @@
use core::f64::consts::LN_2;
use rand::Rng;
#[cfg(not(feature = "std"))]
use num::Float;
use rand::Rng;
/// Samples an integer from {0, ..., 18} according to the distribution χ, which is close to
/// the half-Gaussian distribution on the natural numbers with mean 0 and standard deviation
@@ -40,18 +40,18 @@ fn approx_exp(x: f64, ccs: f64) -> u64 {
// https://eprint.iacr.org/2018/1234
// https://github.com/raykzhao/gaussian
const C: [u64; 13] = [
0x00000004741183A3u64,
0x00000036548CFC06u64,
0x0000024FDCBF140Au64,
0x0000171D939DE045u64,
0x0000D00CF58F6F84u64,
0x000680681CF796E3u64,
0x002D82D8305B0FEAu64,
0x011111110E066FD0u64,
0x0555555555070F00u64,
0x155555555581FF00u64,
0x400000000002B400u64,
0x7FFFFFFFFFFF4800u64,
0x00000004741183a3u64,
0x00000036548cfc06u64,
0x0000024fdcbf140au64,
0x0000171d939de045u64,
0x0000d00cf58f6f84u64,
0x000680681cf796e3u64,
0x002d82d8305b0feau64,
0x011111110e066fd0u64,
0x0555555555070f00u64,
0x155555555581ff00u64,
0x400000000002b400u64,
0x7fffffffffff4800u64,
0x8000000000000000u64,
];
@@ -116,9 +116,10 @@ pub(crate) fn sampler_z<R: Rng>(mu: f64, sigma: f64, sigma_min: f64, rng: &mut R
#[cfg(all(test, feature = "std"))]
mod test {
use alloc::vec::Vec;
use rand::RngCore;
use std::{thread::sleep, time::Duration};
use rand::RngCore;
use super::{approx_exp, ber_exp, sampler_z};
/// RNG used only for testing purposes, whereby the produced

View File

@@ -9,9 +9,11 @@ mod keys;
mod math;
mod signature;
pub use self::keys::{PubKeyPoly, PublicKey, SecretKey};
pub use self::math::Polynomial;
pub use self::signature::{Signature, SignatureHeader, SignaturePoly};
pub use self::{
keys::{PubKeyPoly, PublicKey, SecretKey},
math::Polynomial,
signature::{Signature, SignatureHeader, SignaturePoly},
};
// CONSTANTS
// ================================================================================================

View File

@@ -1,6 +1,8 @@
use alloc::{string::ToString, vec::Vec};
use core::ops::Deref;
use num::Zero;
use super::{
hash_to_point::hash_to_point_rpo256,
keys::PubKeyPoly,
@@ -8,7 +10,6 @@ use super::{
ByteReader, ByteWriter, Deserializable, DeserializationError, Felt, Nonce, Rpo256,
Serializable, Word, LOG_N, MODULUS, N, SIG_L2_BOUND, SIG_POLY_BYTE_LEN,
};
use num::Zero;
// FALCON SIGNATURE
// ================================================================================================
@@ -38,8 +39,8 @@ use num::Zero;
/// The signature is serialized as:
/// 1. A header byte specifying the algorithm used to encode the coefficients of the `s2` polynomial
/// together with the degree of the irreducible polynomial phi. For RPO Falcon512, the header
/// byte is set to `10111001` which differentiates it from the standardized instantiation of
/// the Falcon signature.
/// byte is set to `10111001` which differentiates it from the standardized instantiation of the
/// Falcon signature.
/// 2. 40 bytes for the nonce.
/// 4. 625 bytes encoding the `s2` polynomial above.
///
@@ -355,10 +356,11 @@ fn are_coefficients_valid(x: &[i16]) -> bool {
#[cfg(test)]
mod tests {
use super::{super::SecretKey, *};
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
use super::{super::SecretKey, *};
#[test]
fn test_serialization_round_trip() {
let seed = [0_u8; 32];