#![allow(clippy::needless_range_loop)]
mod encode;
mod fft;
mod fpr;
#[cfg(feature = "key")]
mod key_impl;
mod keygen;
mod sampler;
mod sign;
mod tree;
mod zint;
use crate::hash::{ExtendableOutput, Shake256, XofReader};
const Q: u32 = 12289;
const HASH_REJECT: u32 = 5 * Q;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Error {
InvalidLength,
Malformed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Degree {
Falcon512,
Falcon1024,
}
impl Degree {
const fn n(self) -> usize {
match self {
Degree::Falcon512 => 512,
Degree::Falcon1024 => 1024,
}
}
const fn pubkey_len(self) -> usize {
match self {
Degree::Falcon512 => 897,
Degree::Falcon1024 => 1793,
}
}
const fn sig_len(self) -> usize {
match self {
Degree::Falcon512 => 666,
Degree::Falcon1024 => 1280,
}
}
const fn sig_bound(self) -> u64 {
match self {
Degree::Falcon512 => 34_034_726,
Degree::Falcon1024 => 70_265_242,
}
}
const fn logn(self) -> u8 {
match self {
Degree::Falcon512 => 9,
Degree::Falcon1024 => 10,
}
}
const fn from_logn(logn: u8) -> Option<Degree> {
match logn {
9 => Some(Degree::Falcon512),
10 => Some(Degree::Falcon1024),
_ => None,
}
}
}
const NONCE_LEN: usize = 40;
pub struct FalconPublicKey {
degree: Degree,
h: alloc::vec::Vec<u16>,
}
use alloc::vec::Vec;
impl FalconPublicKey {
pub fn from_bytes(pk: &[u8]) -> Result<FalconPublicKey, Error> {
let header = *pk.first().ok_or(Error::InvalidLength)?;
if header & 0xF0 != 0x00 {
return Err(Error::Malformed);
}
let degree = Degree::from_logn(header & 0x0F).ok_or(Error::Malformed)?;
let n = degree.n();
if pk.len() != degree.pubkey_len() {
return Err(Error::InvalidLength);
}
let body = &pk[1..];
let mut h = Vec::with_capacity(n);
let mut acc: u32 = 0;
let mut acc_bits: u32 = 0;
let mut idx = 0usize;
while h.len() < n {
while acc_bits < 14 {
let byte = *body.get(idx).ok_or(Error::InvalidLength)?;
idx += 1;
acc = (acc << 8) | byte as u32;
acc_bits += 8;
}
acc_bits -= 14;
let coeff = (acc >> acc_bits) & 0x3FFF;
if coeff >= Q {
return Err(Error::Malformed);
}
h.push(coeff as u16);
}
let leftover_mask = if acc_bits == 0 {
0
} else {
(1u32 << acc_bits) - 1
};
if acc & leftover_mask != 0 {
return Err(Error::Malformed);
}
if idx != body.len() {
return Err(Error::Malformed);
}
Ok(FalconPublicKey { degree, h })
}
pub fn degree(&self) -> Degree {
self.degree
}
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> Result<bool, Error> {
let n = self.degree.n();
let header = *sig.first().ok_or(Error::InvalidLength)?;
if Degree::from_logn(header & 0x0F) != Some(self.degree) {
return Err(Error::Malformed);
}
match header & 0xF0 {
0x30 => {
if sig.len() != self.degree.sig_len() {
return Err(Error::InvalidLength);
}
}
0x20 => {
if sig.len() <= 1 + NONCE_LEN || sig.len() > self.degree.sig_len() {
return Err(Error::InvalidLength);
}
}
_ => return Err(Error::Malformed),
}
let nonce = &sig[1..1 + NONCE_LEN];
let s_bytes = &sig[1 + NONCE_LEN..];
let s2 = match decompress(s_bytes, n) {
Some(v) => v,
None => return Ok(false),
};
let c = hash_to_point(nonce, msg, n);
let prod = poly_mul_mod_q(&s2, &self.h, n);
let bound = self.degree.sig_bound();
let mut norm: u64 = 0;
for i in 0..n {
let mut v = c[i] as i32 - prod[i] as i32;
v = v.rem_euclid(Q as i32); let centered = center(v as u32);
norm += (centered as i64 * centered as i64) as u64;
let s2v = s2[i] as i64;
norm += (s2v * s2v) as u64;
if norm > bound {
return Ok(false);
}
}
Ok(norm <= bound)
}
}
#[inline]
fn center(v: u32) -> i32 {
let v = v as i32;
if v > (Q as i32) / 2 { v - Q as i32 } else { v }
}
fn hash_to_point(nonce: &[u8], msg: &[u8], n: usize) -> Vec<u16> {
let mut xof = Shake256::new();
xof.update(nonce);
xof.update(msg);
let mut reader = xof.finalize_xof();
let mut c = Vec::with_capacity(n);
let mut buf = [0u8; 2];
while c.len() < n {
reader.read(&mut buf);
let t = ((buf[0] as u32) << 8) | buf[1] as u32;
if t < HASH_REJECT {
c.push((t % Q) as u16);
}
}
c
}
fn poly_mul_mod_q(a: &[i16], b: &[u16], n: usize) -> Vec<u16> {
let mut acc = alloc::vec![0i64; n];
for i in 0..n {
let ai = a[i] as i64;
if ai == 0 {
continue;
}
for j in 0..n {
let term = ai * b[j] as i64;
let k = i + j;
if k < n {
acc[k] += term;
} else {
acc[k - n] -= term;
}
}
}
let q = Q as i64;
acc.iter().map(|&v| v.rem_euclid(q) as u16).collect()
}
fn decompress(s_bytes: &[u8], n: usize) -> Option<Vec<i16>> {
let total_bits = s_bytes.len() * 8;
let mut pos = 0usize;
let get_bit = |s: &[u8], p: &mut usize| -> Option<u32> {
if *p >= total_bits {
return None;
}
let byte = s[*p >> 3];
let bit = (byte >> (7 - (*p & 7))) & 1;
*p += 1;
Some(bit as u32)
};
let mut out = Vec::with_capacity(n);
for _ in 0..n {
let sign = get_bit(s_bytes, &mut pos)?;
let mut low: u32 = 0;
for _ in 0..7 {
low = (low << 1) | get_bit(s_bytes, &mut pos)?;
}
let mut high: u32 = 0;
loop {
let b = get_bit(s_bytes, &mut pos)?;
if b == 1 {
break;
}
high += 1;
if high > 2048 {
return None;
}
}
let magnitude = (high << 7) | low;
if magnitude == 0 && sign == 1 {
return None;
}
let val = if sign == 1 {
-(magnitude as i32)
} else {
magnitude as i32
};
if !(-(i16::MAX as i32)..=i16::MAX as i32).contains(&val) {
return None;
}
out.push(val as i16);
}
while pos < total_bits {
if get_bit(s_bytes, &mut pos)? != 0 {
return None;
}
}
Some(out)
}
pub struct FalconPrivateKey {
degree: Degree,
f: Vec<i64>,
g: Vec<i64>,
cap_f: Vec<i64>,
cap_g: Vec<i64>,
h: Vec<u16>,
expanded: sign::ExpandedKey,
}
struct RngBytes<'a, R>(&'a mut R);
impl<R: crate::rng::RngCore> sampler::SamplerRng for RngBytes<'_, R> {
fn next_bytes(&mut self, buf: &mut [u8]) {
self.0.fill_bytes(buf);
}
}
impl FalconPrivateKey {
pub fn generate<R: crate::rng::RngCore + crate::rng::CryptoRng>(
degree: Degree,
rng: &mut R,
) -> FalconPrivateKey {
let n = degree.n();
let (f, g, cap_f, cap_g, h) = {
let mut src = RngBytes(rng);
keygen::ntru_gen(n, &mut src)
};
let expanded = sign::expand_key(&f, &g, &cap_f, &cap_g, degree);
FalconPrivateKey {
degree,
f,
g,
cap_f,
cap_g,
h,
expanded,
}
}
pub fn degree(&self) -> Degree {
self.degree
}
pub fn sign<R: crate::rng::RngCore + crate::rng::CryptoRng>(
&self,
msg: &[u8],
rng: &mut R,
) -> Vec<u8> {
let mut salt = [0u8; NONCE_LEN];
rng.fill_bytes(&mut salt);
let mut src = RngBytes(rng);
sign::sign_internal(&self.expanded, msg, &salt, &mut src)
}
pub fn public_key(&self) -> FalconPublicKey {
FalconPublicKey {
degree: self.degree,
h: self.h.clone(),
}
}
pub fn public_key_bytes(&self) -> Vec<u8> {
encode::encode_pubkey(&self.h, self.degree.logn())
}
pub fn to_bytes(&self) -> Vec<u8> {
encode::encode_privkey(&self.f, &self.g, &self.cap_f, self.degree.logn())
}
pub fn from_bytes(sk: &[u8]) -> Result<FalconPrivateKey, Error> {
let header = *sk.first().ok_or(Error::InvalidLength)?;
if header & 0xF0 != 0x50 {
return Err(Error::Malformed);
}
let degree = Degree::from_logn(header & 0x0F).ok_or(Error::Malformed)?;
let n = degree.n();
let (f, g, cap_f) = encode::decode_privkey(sk, n).ok_or(Error::InvalidLength)?;
let h = keygen::compute_h(&f, &g, n).ok_or(Error::Malformed)?;
let cap_g = keygen::recompute_g(&f, &g, &cap_f, n);
let expanded = sign::expand_key(&f, &g, &cap_f, &cap_g, degree);
Ok(FalconPrivateKey {
degree,
f,
g,
cap_f,
cap_g,
h,
expanded,
})
}
}
impl Drop for FalconPrivateKey {
fn drop(&mut self) {
for v in [&mut self.f, &mut self.g, &mut self.cap_f, &mut self.cap_g] {
for x in v.iter_mut() {
*x = 0;
}
let _ = core::hint::black_box(&*v);
}
}
}
pub fn verify(pk: &[u8], msg: &[u8], sig: &[u8]) -> bool {
match FalconPublicKey::from_bytes(pk) {
Ok(key) => key.verify(msg, sig).unwrap_or(false),
Err(_) => false,
}
}
#[cfg(test)]
mod tests;