Skip to content

Commit

Permalink
chore: revert back key recovery mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Al-Kindi-0 committed Mar 21, 2024
1 parent 0dc684b commit 1e4e11b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 56 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ std = [
"blake3/std",
"dep:cc",
"rand/std",
"rand/std_rng",
"winter-crypto/std",
"winter-math/std",
"winter-utils/std",
Expand Down
46 changes: 15 additions & 31 deletions src/dsa/rpo_falcon512/keys/secret_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@ 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, Zero};
use num::Complex;
use num_complex::Complex64;
use rand::Rng;

#[cfg(feature = "std")]
use rand::{rngs::OsRng, RngCore};
use rand::{Rng, RngCore};

Check warning on line 16 in src/dsa/rpo_falcon512/keys/secret_key.rs

View workflow job for this annotation

GitHub Actions / build nightly no-std for wasm32-unknown-unknown

unused import: `RngCore`

Check warning on line 16 in src/dsa/rpo_falcon512/keys/secret_key.rs

View workflow job for this annotation

GitHub Actions / build stable no-std for wasm32-unknown-unknown

unused import: `RngCore`

Check warning on line 16 in src/dsa/rpo_falcon512/keys/secret_key.rs

View workflow job for this annotation

GitHub Actions / test nightly on ubuntu with --no-default-features

unused import: `RngCore`

Check warning on line 16 in src/dsa/rpo_falcon512/keys/secret_key.rs

View workflow job for this annotation

GitHub Actions / test stable on ubuntu with --no-default-features

unused import: `RngCore`

#[cfg(not(feature = "std"))]
use num::Float;

Check warning on line 19 in src/dsa/rpo_falcon512/keys/secret_key.rs

View workflow job for this annotation

GitHub Actions / test nightly on ubuntu with --no-default-features

unused import: `num::Float`

Check warning on line 19 in src/dsa/rpo_falcon512/keys/secret_key.rs

View workflow job for this annotation

GitHub Actions / test stable on ubuntu with --no-default-features

unused import: `num::Float`
Expand Down Expand Up @@ -45,7 +42,7 @@ const WIDTH_SMALL_POLY_COEFFICIENT: usize = 6;
/// The secret key is generated by first sampling a random pair (f, g) of polynomials using
/// an appropriate distribution that yields short but not too short polynomials with integer
/// coefficients modulo ϕ. The NTRU equation is then used to find a matching pair (F, G).
/// The public key is then derived from the secret key using equation 2.
/// The public key is then derived from the secret key using equation 1.
///
/// To allow for fast signature generation, the secret key is pre-processed into a more suitable
/// form, called the LDL tree, and this allows for fast sampling of short vectors in the lattice
Expand All @@ -66,9 +63,12 @@ impl SecretKey {
/// Generates a secret key from OS-provided randomness.
#[cfg(feature = "std")]
pub fn new() -> Self {
use rand::{rngs::StdRng, SeedableRng};

let mut seed: [u8; 32] = [0; 32];
OsRng.fill_bytes(&mut seed);
Self::with_rng(&mut OsRng)
let mut rng = StdRng::from_entropy();
rng.fill_bytes(&mut seed);
Self::with_rng(&mut rng)
}

/// Generates a secret_key using the provided random number generator `Rng`.
Expand Down Expand Up @@ -122,10 +122,11 @@ impl SecretKey {
rng.fill_bytes(&mut nonce_bytes);
let nonce = Nonce::new(nonce_bytes);

let h = self.compute_pub_key_poly();
let c = hash_to_point_rpo256(message, &nonce);
let (s1, s2) = self.sign_helper(c, rng);
let s2 = self.sign_helper(c, rng);

Signature::new(nonce, s1, s2)
Signature::new(nonce, h, s2)
}

// HELPER METHODS
Expand All @@ -145,13 +146,8 @@ impl SecretKey {
/// Signs a message polynomial with the secret key.
///
/// Takes a randomness generator implementing `Rng` and message polynomial representing `c`
/// the hash-to-point of the message to be signed. It outputs a tuple of signature polynomials
/// `(s1, s2)`.
fn sign_helper<R: Rng>(
&self,
c: Polynomial<FalconFelt>,
rng: &mut R,
) -> (SignaturePoly, SignaturePoly) {
/// the hash-to-point of the message to be signed. It outputs a signature polynomial `s2`.
fn sign_helper<R: Rng>(&self, c: Polynomial<FalconFelt>, rng: &mut R) -> SignaturePoly {
let one_over_q = 1.0 / (MODULUS as f64);
let c_over_q_fft = c.map(|cc| Complex::new(one_over_q * cc.value() as f64, 0.0)).fft();

Expand Down Expand Up @@ -184,15 +180,7 @@ impl SecretKey {
break [-s0, s1];
};

let s1 = bold_s[0].ifft();
let s2 = bold_s[1].ifft();
let s1_coef: [i16; N] = s1
.coefficients
.iter()
.map(|a| a.re.round() as i16)
.collect::<Vec<i16>>()
.try_into()
.expect("The number of coefficients should be equal to N");
let s2_coef: [i16; N] = s2
.coefficients
.iter()
Expand All @@ -201,12 +189,8 @@ impl SecretKey {
.try_into()
.expect("The number of coefficients should be equal to N");

if let Ok(s1) = SignaturePoly::try_from(&s1_coef) {
if let Ok(s2) = SignaturePoly::try_from(&s2_coef) {
if s2.fft().coefficients.iter().all(|&c| c != FalconFelt::zero()) {
return (s1, s2);
}
}
if let Ok(s2) = SignaturePoly::try_from(&s2_coef) {
return s2;
}
}
}
Expand Down
52 changes: 27 additions & 25 deletions src/dsa/rpo_falcon512/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use num::Zero;

/// An RPO Falcon512 signature over a message.
///
/// The signature is a pair of polynomials (s1, s2) in (Z_p\[x\]/(phi))^2 and a nonce `r`,
/// where:
/// The signature is a pair of polynomials (s1, s2) in (Z_p\[x\]/(phi))^2 a nonce `r`, and a public
/// key polynomial `h` where:
/// - p := 12289
/// - phi := x^512 + 1
///
Expand All @@ -26,12 +26,16 @@ use num::Zero;
///
/// where |.| is the norm and:
/// - c = HashToPoint(r || message)
/// - h = s2^(-1) * (c - s1)
/// - pk = Rpo256::hash(h)
///
/// Here h is a polynomial representing the public key and pk is its digest using the Rpo256 hash
/// function. c is a polynomial that is the hash-to-point of the message being signed.
///
/// The polynomial h is serialized as:
///
/// 1. 1 byte representing the log2(512) i.e., 9.
/// 2. 896 bytes for the public key itself.
///
/// 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.
Expand All @@ -42,36 +46,40 @@ use num::Zero;
/// The current implementation works always with cc equal to 0b01 and nnnn equal to 0b1001 and
/// thus the header byte is always equal to 0b00111001.
/// 2. 40 bytes for the nonce.
/// 3. 625 bytes encoding the `s1` polynomial above.
/// 4. 625 bytes encoding the `s2` polynomial above.
///
/// The total size of the signature is 1291 bytes.
/// The total size of the signature is (including the extended public key) is 1563 bytes.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Signature {
header: SignatureHeader,
nonce: Nonce,
s1: SignaturePoly,
s2: SignaturePoly,
h: PubKeyPoly,
}

impl Signature {
// CONSTRUCTOR
// --------------------------------------------------------------------------------------------
pub fn new(nonce: Nonce, s1: SignaturePoly, s2: SignaturePoly) -> Signature {
pub fn new(nonce: Nonce, h: PubKeyPoly, s2: SignaturePoly) -> Signature {
Self {
header: SignatureHeader::default(),
nonce,
s1,
s2,
h,
}
}

// PUBLIC ACCESSORS
// --------------------------------------------------------------------------------------------

/// Returns the public key polynomial h.
pub fn pk_poly(&self) -> &PubKeyPoly {
&self.h
}

// Returns the polynomial representation of the signature in Z_p[x]/(phi).
pub fn sig_poly(&self) -> (&Polynomial<FalconFelt>, &Polynomial<FalconFelt>) {
(&self.s1, &self.s2)
pub fn sig_poly(&self) -> &Polynomial<FalconFelt> {
&self.s2
}

/// Returns the nonce component of the signature.
Expand All @@ -85,41 +93,35 @@ impl Signature {
/// Returns true if this signature is a valid signature for the specified message generated
/// against the secret key matching the specified public key commitment.
pub fn verify(&self, message: Word, pubkey_com: Word) -> bool {
let c = hash_to_point_rpo256(message, &self.nonce);

let s1_fft = self.s1.fft();
let s2_fft = self.s2.fft();
let c_fft = c.fft();

// recover the public key polynomial using h = s2^(-1) * (c - s1)
let h_fft = (c_fft - s1_fft).hadamard_div(&s2_fft);
let h = h_fft.ifft();

// compute the hash of the public key polynomial
let h_felt: Polynomial<Felt> = h.clone().into();
let h_felt: Polynomial<Felt> = (&**self.pk_poly()).into();
let h_digest: Word = Rpo256::hash_elements(&h_felt.coefficients).into();
if h_digest != pubkey_com {
return false;
}

h_digest == pubkey_com && verify_helper(&c, &self.s2, &h.into())
let c = hash_to_point_rpo256(message, &self.nonce);
h_digest == pubkey_com && verify_helper(&c, &self.s2, self.pk_poly())
}
}

impl Serializable for Signature {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write(&self.header);
target.write(&self.nonce);
target.write(&self.s1);
target.write(&self.s2);
target.write(&self.h);
}
}

impl Deserializable for Signature {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let header = source.read()?;
let nonce = source.read()?;
let s1 = source.read()?;
let s2 = source.read()?;
let h = source.read()?;

Ok(Self { header, nonce, s1, s2 })
Ok(Self { header, nonce, s2, h })
}
}

Expand Down

0 comments on commit 1e4e11b

Please sign in to comment.