diff --git a/benches/README.md b/benches/README.md index 0970400..5cbdead 100644 --- a/benches/README.md +++ b/benches/README.md @@ -6,28 +6,28 @@ Near-obvious uplift can be had with more careful modular multiplication & additi using fewer reductions. Also, 'u16' arithmetic has a performance penalty. ~~~ -May 1, 2024 +May 2, 2024 Intel® Core™ i7-7700K CPU @ 4.20GHz × 8 Circa 2017 w/ Rust 1.77 $ RUSTFLAGS="-C target-cpu=native" cargo bench -ml_dsa_44 keygen time: [91.264 µs 91.402 µs 91.555 µs] -ml_dsa_65 keygen time: [169.11 µs 169.23 µs 169.39 µs] -ml_dsa_87 keygen time: [247.51 µs 247.91 µs 248.34 µs] +ml_dsa_44 keygen time: [96.321 µs 96.430 µs 96.588 µs] +ml_dsa_65 keygen time: [178.26 µs 180.06 µs 182.69 µs] +ml_dsa_87 keygen time: [260.61 µs 261.11 µs 262.06 µs] -ml_dsa_44 sk sign time: [369.67 µs 373.75 µs 378.01 µs] -ml_dsa_65 sk sign time: [597.12 µs 606.37 µs 615.55 µs] -ml_dsa_87 sk sign time: [734.89 µs 742.40 µs 750.00 µs] +ml_dsa_44 sk sign time: [373.45 µs 376.67 µs 379.81 µs] +ml_dsa_65 sk sign time: [644.92 µs 653.32 µs 662.09 µs] +ml_dsa_87 sk sign time: [777.73 µs 788.49 µs 799.28 µs] -ml_dsa_44 esk sign time: [313.36 µs 317.30 µs 321.32 µs] // Fast sign, 15% improvement -ml_dsa_65 esk sign time: [495.20 µs 505.25 µs 515.57 µs] -ml_dsa_87 esk sign time: [532.84 µs 541.26 µs 550.20 µs] +ml_dsa_44 esk sign time: [307.48 µs 311.03 µs 314.53 µs] +ml_dsa_65 esk sign time: [525.53 µs 533.96 µs 541.88 µs] +ml_dsa_87 esk sign time: [552.76 µs 562.43 µs 572.18 µs] -ml_dsa 44 pk verify time: [129.28 µs 129.40 µs 129.55 µs] -ml_dsa 65 pk verify time: [223.02 µs 223.11 µs 223.23 µs] -ml_dsa 87 pk verify time: [381.66 µs 382.84 µs 384.46 µs] +ml_dsa 44 pk verify time: [135.45 µs 135.48 µs 135.53 µs] +ml_dsa 65 pk verify time: [231.73 µs 231.76 µs 231.81 µs] +ml_dsa 87 pk verify time: [424.19 µs 424.34 µs 424.55 µs] -ml_dsa 44 epk verify time: [71.255 µs 71.320 µs 71.414 µs] // Fast verif, 45% improvement -ml_dsa 65 epk verify time: [123.49 µs 123.57 µs 123.67 µs] -ml_dsa 87 epk verify time: [205.28 µs 205.45 µs 205.65 µs] +ml_dsa 44 epk verify time: [75.541 µs 75.563 µs 75.585 µs] +ml_dsa 65 epk verify time: [124.11 µs 124.25 µs 124.41 µs] +ml_dsa 87 epk verify time: [236.60 µs 236.74 µs 236.91 µs] ~~~ \ No newline at end of file diff --git a/src/encodings.rs b/src/encodings.rs index 941c476..e140cb2 100644 --- a/src/encodings.rs +++ b/src/encodings.rs @@ -3,7 +3,7 @@ use crate::conversion::{ bit_pack, bit_unpack, hint_bit_pack, hint_bit_unpack, simple_bit_pack, simple_bit_unpack, }; -use crate::helpers::{bit_length, ensure, is_in_range}; +use crate::helpers::{bit_length, is_in_range}; use crate::types::R; use crate::{D, Q}; @@ -19,6 +19,7 @@ pub(crate) fn pk_encode( ) -> [u8; PK_LEN] { let blqd = bit_length(Q - 1) - D as usize; debug_assert!(t1.iter().all(|t| is_in_range(t, 0, (1 << blqd) - 1)), "Alg 16: t1 out of range"); + debug_assert_eq!(PK_LEN, 32 + 32 * K * blqd, "Alg 17: bad pk/config size"); let mut pk = [0u8; PK_LEN]; // 1: pk ← BitsToBytes(ρ) @@ -50,13 +51,15 @@ pub(crate) fn pk_encode( /// **Output**: `ρ ∈ {0, 1}^256`, `t1 ∈ R^k` with coefficients in `[0, 2^{bitlen(q−1)−d} − 1]`). /// /// # Errors -/// Returns an error when `simple_bit_unpack()` invocation finds an element of `t1` is out of range. +/// Returns an error when the internal `simple_bit_unpack()` invocation finds an element of +/// `t1` is out of range. #[allow(clippy::cast_possible_truncation)] pub(crate) fn pk_decode( pk: &[u8; PK_LEN], ) -> Result<(&[u8; 32], [R; K]), &'static str> { let blqd = bit_length(Q - 1) - D as usize; debug_assert_eq!(pk.len(), 32 + 32 * K * blqd, "Alg 17: incorrect pk length"); + debug_assert_eq!(PK_LEN, 32 + 32 * K * blqd, "Alg 17: bad pk/config size"); // 1: (y, z_0 , . . . , z_{k−1}) ∈ B^{32} × (B^{32(bitlen(q−1)−d))^k} ← pk @@ -89,7 +92,7 @@ pub(crate) fn pk_decode( /// `s2 ∈ R^k` with coefficients in `[−η, η]`, /// `t0 ∈ R^k` with coefficients in `[−2^{d-1} + 1, 2^{d-1}]`. /// Security parameter `η` (eta) must be either 2 or 4.
-/// **Output**: Private key, `sk ∈ B^{32+32+64+32·((k+ℓ)·bitlen(2η)+dk)}` +/// **Output**: Private key, `sk ∈ B^{32+32+64+32·((k+ℓ)·bitlen(2·η)+d·k)}` pub(crate) fn sk_encode( eta: i32, rho: &[u8; 32], k: &[u8; 32], tr: &[u8; 64], s1: &[R; L], s2: &[R; K], t0: &[R; K], ) -> [u8; SK_LEN] { @@ -97,7 +100,12 @@ pub(crate) fn sk_encode( debug_assert!((eta == 2) | (eta == 4), "Alg 18: incorrect eta"); debug_assert!(s1.iter().all(|x| is_in_range(x, eta, eta)), "Alg 18: s1 out of range"); debug_assert!(s2.iter().all(|x| is_in_range(x, eta, eta)), "Alg 18: s2 out of range"); - debug_assert!(t0.iter().all(|x| is_in_range(x, top - 1, top)), "Alg18: t0 out of range"); + debug_assert!(t0.iter().all(|x| is_in_range(x, top - 1, top)), "Alg 18: t0 out of range"); + debug_assert_eq!( + SK_LEN, + 128 + 32 * ((K + L) * bit_length(2 * eta) + D as usize * K), + "Alg 18: bad sk/config size" + ); let mut sk = [0u8; SK_LEN]; @@ -160,6 +168,11 @@ pub(crate) fn sk_decode( eta: i32, sk: &[u8; SK_LEN], ) -> Result<(&[u8; 32], &[u8; 32], &[u8; 64], [R; L], [R; K], [R; K]), &'static str> { debug_assert!((eta == 2) | (eta == 4), "Alg 19: incorrect eta"); + debug_assert_eq!( + SK_LEN, + 128 + 32 * ((K + L) * bit_length(2 * eta) + D as usize * K), + "Alg 19: bad sk/config size" + ); let top = 1 << (D - 1); let (mut s1, mut s2, mut t0) = ([[0i32; 256]; L], [[0i32; 256]; K], [[0i32; 256]; K]); @@ -235,7 +248,7 @@ pub(crate) fn sig_encode< debug_assert_eq!( SIG_LEN, LAMBDA_DIV4 + L * 32 * (1 + bit_length(gamma1 - 1)) + omega.unsigned_abs() as usize + K, - "Alg 20: bad output size" + "Alg 20: bad sig/config size" ); let mut sigma = [0u8; SIG_LEN]; @@ -273,13 +286,18 @@ pub(crate) fn sig_encode< /// # Errors /// Returns an error when decoded coefficients fall out of range. #[allow(clippy::type_complexity)] -pub(crate) fn sig_decode( +pub(crate) fn sig_decode< + const K: usize, + const L: usize, + const LAMBDA_DIV4: usize, + const SIG_LEN: usize, +>( gamma1: i32, omega: i32, sigma: &[u8; SIG_LEN], ) -> Result<([u8; LAMBDA_DIV4], [R; L], Option<[R; K]>), &'static str> { debug_assert_eq!( SIG_LEN, LAMBDA_DIV4 + L * 32 * (1 + bit_length(gamma1 - 1)) + omega.unsigned_abs() as usize + K, - "Alg 21: bad output size" + "Alg 21: bad sig/config size" ); let mut c_tilde = [0u8; LAMBDA_DIV4]; @@ -310,27 +328,19 @@ pub(crate) fn sig_decode( - gamma2: i32, w1: &[R; K], w1_tilde: &mut [u8], -) -> Result<(), &'static str> { +pub(crate) fn w1_encode(gamma2: i32, w1: &[R; K], w1_tilde: &mut [u8]) { let qm1_d_2g_m1 = (Q - 1) / (2 * gamma2) - 1; debug_assert_eq!( w1_tilde.len(), 32 * K * bit_length(qm1_d_2g_m1), - "Alg22: incorrect size for w1_tilde" + "Alg 22: bad w1_tilde/config size" ); - ensure!(w1.iter().all(|r| is_in_range(r, 0, qm1_d_2g_m1)), "Alg22: w1 out of range"); + debug_assert!(w1.iter().all(|r| is_in_range(r, 0, qm1_d_2g_m1)), "Alg 22: w1 out of range"); // 1: w1_tilde ← () @@ -345,7 +355,6 @@ pub(crate) fn w1_encode( } // 5: return w^tilde_1 - Ok(()) } @@ -445,8 +454,7 @@ mod tests { let z = [get_vec(2), get_vec(2), get_vec(2), get_vec(2)]; let h = [get_vec(1), get_vec(1), get_vec(1), get_vec(1)]; //let mut sigma = [0u8; 2420]; - let sigma = - sig_encode::<4, 4, { 128 / 4 }, 2420>(1 << 17, 80, &c_tilde.clone(), &z, &h); + let sigma = sig_encode::<4, 4, { 128 / 4 }, 2420>(1 << 17, 80, &c_tilde.clone(), &z, &h); // let mut c_test = [0u8; 2 * 128 / 8]; // let mut z_test = [[0i32; 256]; 4]; // let mut h_test = [[0i32; 256]; 4]; diff --git a/src/hashing.rs b/src/hashing.rs index 29cf013..b4b16ca 100644 --- a/src/hashing.rs +++ b/src/hashing.rs @@ -1,7 +1,7 @@ //! This file implements functionality from FIPS 204 section 8.3 Hashing and Pseudorandom Sampling -use crate::conversion; -use crate::helpers::{bit_length, ensure, is_in_range}; +use crate::conversion::{bit_unpack, coef_from_half_byte_vartime, coef_from_three_bytes_vartime}; +use crate::helpers::{bit_length, is_in_range}; use crate::types::{R, T}; use sha3::digest::{ExtendableOutput, Update, XofReader}; use sha3::{Shake128, Shake256}; @@ -29,15 +29,12 @@ pub(crate) fn h128_xof(v: &[&[u8]]) -> impl XofReader { /// # Algorithm 23: `SampleInBall(ρ)` on page 30. /// Samples a polynomial `c ∈ Rq` with coefficients from `{−1, 0, 1}` and Hamming weight `τ`. +/// Used in `ml_dsa:sign_finish()` and `ml_dsa::verify_finish()`. TODO: review constant-time aspects /// /// **Input**: A seed `ρ ∈{0,1}^256`
/// **Output**: A polynomial `c` in `Rq`. -/// -/// # Errors -/// Returns an error on incorrectly constructed `c`. -/// Propagates any errors generated by called functions. -pub(crate) fn sample_in_ball(tau: i32, rho: &[u8; 32]) -> Result { - let tau = usize::try_from(tau).expect("Alg23: bad tau"); +pub(crate) fn sample_in_ball(tau: i32, rho: &[u8; 32]) -> R { + let tau = usize::try_from(tau).expect("cannot fail"); let mut xof = h_xof(&[rho]); let mut hpk8 = [0u8; 8]; xof.read(&mut hpk8); // Save the first 8 bytes for step 9 @@ -80,8 +77,8 @@ pub(crate) fn sample_in_ball(tau: i32, rho: &[u8; 32]) -> Result Result +/// **Input**: A seed `ρ ∈ {0,1}^{272}`.
/// **Output**: An element `a_hat ∈ Tq`. -/// -/// # Panics -/// In debug, requires correctly sized `p`. pub(crate) fn rej_ntt_poly_vartime(rhos: &[&[u8]]) -> T { - debug_assert_eq!( - rhos.iter().map(|&i| i.len()).sum::(), - 272 / 8, - "Alg24: wrong size rho" - ); + debug_assert_eq!(rhos.iter().map(|&i| i.len()).sum::(), 272 / 8, "Alg 24: bad rho size"); let mut a_hat = [0i32; 256]; let mut xof = h128_xof(rhos); @@ -116,7 +106,7 @@ pub(crate) fn rej_ntt_poly_vartime(rhos: &[&[u8]]) -> T { // 4: a_hat[j] ← CoefFromThreeBytes(H128(ρ)[[c]], H128(ρ)[[c + 1]], H128(ρ)[[c + 2]]) let mut h128pc = [0u8; 3]; xof.read(&mut h128pc); // implicit c += 3 - let a_hat_j = conversion::coef_from_three_bytes_vartime(h128pc); // gets a result + let a_hat_j = coef_from_three_bytes_vartime(h128pc); // gets a result // 5: c ← c + 3 (implicit) @@ -147,11 +137,7 @@ pub(crate) fn rej_ntt_poly_vartime(rhos: &[&[u8]]) -> T { /// # Panics /// In debug, requires correctly sized `p`. pub(crate) fn rej_bounded_poly_vartime(eta: i32, rhos: &[&[u8]]) -> R { - debug_assert_eq!( - rhos.iter().map(|&i| i.len()).sum::(), - 528 / 8, - "Alg25: wrong size rho" - ); + debug_assert_eq!(rhos.iter().map(|&i| i.len()).sum::(), 528 / 8, "Alg25: bad rho size"); let mut z = [0u8]; let mut a = [0i32; 256]; let mut xof = h_xof(rhos); @@ -168,10 +154,10 @@ pub(crate) fn rej_bounded_poly_vartime(eta: i32, rhos: &[&[u8]]) -> R { xof.read(&mut z); // 5: z0 ← CoefFromHalfByte(z mod 16, η) - let z0 = conversion::coef_from_half_byte_vartime(eta, z[0] & 0x0f); + let z0 = coef_from_half_byte_vartime(eta, z[0] & 0x0f); // 6: z1 ← CoefFromHalfByte(⌊z/16⌋, η) - let z1 = conversion::coef_from_half_byte_vartime(eta, z[0] >> 4); + let z1 = coef_from_half_byte_vartime(eta, z[0] >> 4); // 7: if z0 != ⊥ then if let Ok(z0) = z0 { @@ -217,23 +203,17 @@ pub(crate) fn rej_bounded_poly_vartime(eta: i32, rhos: &[&[u8]]) -> R { /// /// **Input**: `ρ ∈ {0,1}^256`.
/// **Output**: Matrix `A_hat` +#[allow(clippy::cast_possible_truncation)] // s and r pub(crate) fn expand_a_vartime(rho: &[u8; 32]) -> [[T; L]; K] { - let mut cap_a_hat = [[[0i32; 256]; L]; K]; - // 1: for r from 0 to k − 1 do - for (a_row, r) in cap_a_hat.iter_mut().zip(0..u8::try_from(K).unwrap()) { - // - // 2: for s from 0 to ℓ − 1 do - for (a_element, s) in a_row.iter_mut().zip(0..u8::try_from(L).unwrap()) { - // - // 3: A_hat[r, s] ← RejNTTPoly(ρ||IntegerToBits(s, 8)||IntegerToBits(r, 8)) - *a_element = rej_ntt_poly_vartime(&[&rho[..], &[s], &[r]]); - - // 4: end for - } - - // 5: end for - } + // 2: for s from 0 to ℓ − 1 do + // 3: A_hat[r, s] ← RejNTTPoly(ρ||IntegerToBits(s, 8)||IntegerToBits(r, 8)) + // 4: end for + // 5: end for + + let cap_a_hat: [[[i32; 256]; L]; K] = core::array::from_fn(|r| { + core::array::from_fn(|s| rej_ntt_poly_vartime(&[&rho[..], &[s as u8], &[r as u8]])) + }); cap_a_hat } @@ -241,7 +221,7 @@ pub(crate) fn expand_a_vartime(rho: &[u8; 32]) - /// # Algorithm 27: `ExpandS(ρ)` on page 32. /// Samples vectors `s1 ∈ R^ℓ_q` and `s2 ∈ R^k_q`, each with coefficients in the interval `[−η, η]`. /// Note that this function is only used in the `ml_dsa::keygen_vartime()` functionality using the -/// `rho_prime` private random seed. +/// `rho_prime` private random seed. It is not exposed to untrusted input. /// /// **Input**: `ρ ∈ {0,1}^512`
/// **Output**: Vectors `s1`, `s2` of polynomials in `Rq`. @@ -249,62 +229,49 @@ pub(crate) fn expand_a_vartime(rho: &[u8; 32]) - /// # Errors /// Returns an error on out of range s1 s2 coefficients. /// Propagates any errors generated by called functions. +#[allow(clippy::cast_possible_truncation)] // r and r+L pub(crate) fn expand_s_vartime( eta: i32, rho: &[u8; 64], -) -> Result<([R; L], [R; K]), &'static str> { - let (mut s1, mut s2) = ([[0i32; 256]; L], [[0i32; 256]; K]); - +) -> ([R; L], [R; K]) { + // // 1: for r from 0 to ℓ − 1 do - for (s1r, r) in s1.iter_mut().zip(0..u8::try_from(L).unwrap()) { - // - // 2: s1[r] ← RejBoundedPoly(ρ||IntegerToBits(r, 16)) - *s1r = rej_bounded_poly_vartime(eta, &[rho, &[r], &[0]]); - - // 3: end for - } + // 2: s1[r] ← RejBoundedPoly(ρ||IntegerToBits(r, 16)) + // 3: end for + let s1: [[i32; 256]; L] = + core::array::from_fn(|r| rej_bounded_poly_vartime(eta, &[rho, &[r as u8], &[0]])); // 4: for r from 0 to k − 1 do - for (s2r, r) in s2.iter_mut().zip(0..u8::try_from(K).unwrap()) { - // - // 5: s2[r] ← RejBoundedPoly(ρ||IntegerToBits(r + ℓ, 16)) - ensure!((r as usize + L) < 255, "Alg27: r + L out of range u8"); - *s2r = rej_bounded_poly_vartime(eta, &[rho, &[r + u8::try_from(L).unwrap()], &[0]]); - - // 6: end for - } + // 5: s2[r] ← RejBoundedPoly(ρ||IntegerToBits(r + ℓ, 16)) + // 6: end for + let s2: [[i32; 256]; K] = + core::array::from_fn(|r| rej_bounded_poly_vartime(eta, &[rho, &[(r + L) as u8], &[0]])); // 7: return (s_1 , s_2) - ensure!(s1.iter().all(|r| is_in_range(r, eta, eta)), "Alg27: s1 out of range"); - ensure!(s2.iter().all(|r| is_in_range(r, eta, eta)), "Alg27: s2 out of range"); - Ok((s1, s2)) + debug_assert!(s1.iter().all(|r| is_in_range(r, eta, eta)), "Alg 27: s1 out of range"); + debug_assert!(s2.iter().all(|r| is_in_range(r, eta, eta)), "Alg 27: s2 out of range"); + (s1, s2) } /// # Algorithm 28: `ExpandMask(ρ,µ)` from page 32. /// Samples a vector `s ∈ R^ℓ_q` such that each polynomial `s_j` has coefficients between −γ1 + 1 and γ1. +/// This function is not exposed to untrusted input. /// /// **Input**: A bit string `ρ ∈ {0,1}^512` and a non-negative integer `µ`.
/// **Output**: Vector `s ∈ R^ℓ_q`. -/// -/// # Errors -/// Returns an error on internal errors -/// Returns an error on out of range s coefficients. -/// Propagates any errors generated by called functions. -pub(crate) fn expand_mask( - gamma1: i32, rho: &[u8; 64], mu: u16, -) -> Result<[R; L], &'static str> { +pub(crate) fn expand_mask(gamma1: i32, rho: &[u8; 64], mu: u16) -> [R; L] { let mut s = [[0i32; 256]; L]; let mut v = [0u8; 32 * 20]; // TODO: 640? // 1: c ← 1 + bitlen (γ1 − 1) ▷ γ1 is always a power of 2 let c = 1 + bit_length(gamma1 - 1); // c will either be 18 or 20 - ensure!((c == 18) | (c == 20), "Alg28: illegal c"); + debug_assert!((c == 18) | (c == 20), "Alg 28: illegal c"); // 2: for r from 0 to ℓ − 1 do for r in 0..u16::try_from(L).unwrap() { // // 3: n ← IntegerToBits(µ + r, 16) - ensure!((mu + r < 512), "Alg28: mu + r out of range"); + debug_assert!((mu + r < 512), "Alg 28: mu + r out of range"); let n = mu + r; // 4: v ← (H(ρ||n)[[32rc]], H(ρ||n)[[32rc+1]], ... , H(ρ||n)[[32rc+32c − 1]]) @@ -312,12 +279,15 @@ pub(crate) fn expand_mask( xof.read(&mut v); // 5: s[r] ← BitUnpack(v, γ1 − 1, γ1) - s[r as usize] = conversion::bit_unpack(&v[0..32 * c], gamma1 - 1, gamma1)?; - ensure!(s.iter().all(|r| is_in_range(r, gamma1, gamma1)), "Alg28: s coeff out of range"); + s[r as usize] = bit_unpack(&v[0..32 * c], gamma1 - 1, gamma1).expect("cannot fail"); + debug_assert!( + s.iter().all(|r| is_in_range(r, gamma1, gamma1)), + "Alg 28: s coeff out of range" + ); // 6: end for } // 7: return s - Ok(s) + s } diff --git a/src/helpers.rs b/src/helpers.rs index 6fcaa04..7c05da1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -20,7 +20,7 @@ pub(crate) use ensure; // make available throughout crate /// Ensure all coefficients of polynomial `w` are within -lo to +hi (inclusive) pub(crate) fn is_in_range(w: &R, lo: i32, hi: i32) -> bool { - w.iter().all(|&e| (e >= -lo) && (e <= hi)) // sucess is CT, failure vartime + w.iter().all(|&e| (e >= -lo) && (e <= hi)) // success is CT, failure vartime } @@ -33,7 +33,6 @@ pub(crate) const fn partial_reduce64(a: i64) -> i32 { (a - (q as i64) * (Q as i64)) as i32 } - /// Partially reduce a signed 32-bit value mod Q ---> `-Q <~ result <~ Q` // Considering the positive case for `a`, bits 23 and above can be loosely // viewed as the 'number of Q' contained within `a` (with some rounding-down diff --git a/src/lib.rs b/src/lib.rs index 3505929..f607129 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,7 +88,7 @@ mod types; pub mod traits; // Applies across all security parameter sets -const Q: i32 = 8_380_417; // 2^23 - 2^13 + 1; See https://oeis.org/A234388 +const Q: i32 = 8_380_417; // 2^23 - 2^13 + 1 = 0x7FE001; See https://oeis.org/A234388 const ZETA: i32 = 1753; // See line 906 et al of FIPS 204 const D: u32 = 13; diff --git a/src/ml_dsa.rs b/src/ml_dsa.rs index d8c8d9d..c967cf5 100644 --- a/src/ml_dsa.rs +++ b/src/ml_dsa.rs @@ -46,7 +46,7 @@ pub(crate) fn key_gen(gamma2, &w_1, &mut w1_tilde[0..w1e_len])?; + w1_encode::(gamma2, &w_1, &mut w1_tilde[0..w1e_len]); let mut h15 = h_xof(&[&mu, &w1_tilde[0..w1e_len]]); h15.read(&mut c_tilde); @@ -186,7 +186,7 @@ pub(crate) fn sign_finish< // c_tilde_2 is never used! // 17: c ← SampleInBall(c_tilde_1) ▷ Verifier’s challenge - let c: R = sample_in_ball(tau, &c_tilde_1)?; + let c: R = sample_in_ball(tau, &c_tilde_1); // 18: c_hat ← NTT(c) let c_hat: T = ntt(&[c])[0]; @@ -365,7 +365,7 @@ pub(crate) fn verify_finish< c_tilde_1.copy_from_slice(&c_tilde[0..32]); // c_tilde_2 is just discarded... // 9: c ← SampleInBall(c_tilde_1) ▷ Compute verifier’s challenge from c_tilde - let c: R = sample_in_ball(tau, &c_tilde_1)?; + let c: R = sample_in_ball(tau, &c_tilde_1); // 10: w′_Approx ← invNTT(cap_A_hat ◦ NTT(z) - NTT(c) ◦ NTT(t_1 · 2^d) ▷ w′_Approx = Az − ct1·2^d let z_hat: [T; L] = ntt(&z); @@ -402,7 +402,7 @@ pub(crate) fn verify_finish< let bl = bit_length(qm12gm1); let t_max = 32 * K * bl; let mut tmp = [0u8; 1024]; // TODO: Revisit potential waste of 256 bytes - w1_encode::(gamma2, &wp_1, &mut tmp[..t_max])?; + w1_encode::(gamma2, &wp_1, &mut tmp[..t_max]); let mut hasher = h_xof(&[&mu, &tmp[..t_max]]); let mut c_tilde_p = [0u8; 64]; hasher.read(&mut c_tilde_p); // leftover to be ignored