248 lines
6.8 KiB
Rust
248 lines
6.8 KiB
Rust
use crate::{
|
|
fips202::*, packing::*, params::*, poly::*, polyvec::*, randombytes::*,
|
|
SignError,
|
|
};
|
|
|
|
pub fn crypto_sign_keypair(
|
|
pk: &mut [u8],
|
|
sk: &mut [u8],
|
|
seed: Option<&[u8]>,
|
|
) -> u8 {
|
|
let mut init_seed = [0u8; SEEDBYTES];
|
|
match seed {
|
|
Some(x) => init_seed.copy_from_slice(x),
|
|
None => randombytes(&mut init_seed, SEEDBYTES),
|
|
};
|
|
let mut seedbuf = [0u8; 2 * SEEDBYTES + CRHBYTES];
|
|
let mut tr = [0u8; SEEDBYTES];
|
|
let (mut rho, mut rhoprime, mut key) =
|
|
([0u8; SEEDBYTES], [0u8; CRHBYTES], [0u8; SEEDBYTES]);
|
|
let mut mat = [Polyvecl::default(); K];
|
|
let mut s1 = Polyvecl::default();
|
|
let (mut s2, mut t1, mut t0) = (
|
|
Polyveck::default(),
|
|
Polyveck::default(),
|
|
Polyveck::default(),
|
|
);
|
|
|
|
// Get randomness for rho, rhoprime and key
|
|
shake256(
|
|
&mut seedbuf,
|
|
2 * SEEDBYTES + CRHBYTES,
|
|
&init_seed,
|
|
SEEDBYTES,
|
|
);
|
|
rho.copy_from_slice(&seedbuf[..SEEDBYTES]);
|
|
rhoprime.copy_from_slice(&seedbuf[SEEDBYTES..SEEDBYTES + CRHBYTES]);
|
|
key.copy_from_slice(&seedbuf[SEEDBYTES + CRHBYTES..]);
|
|
|
|
// Expand matrix
|
|
polyvec_matrix_expand(&mut mat, &rho);
|
|
// Sample short vectors s1 and s2
|
|
polyvecl_uniform_eta(&mut s1, &rhoprime, 0);
|
|
polyveck_uniform_eta(&mut s2, &rhoprime, L_U16);
|
|
|
|
// Matrix-vector multiplication
|
|
let mut s1hat = s1;
|
|
polyvecl_ntt(&mut s1hat);
|
|
|
|
polyvec_matrix_pointwise_montgomery(&mut t1, &mat, &s1hat);
|
|
polyveck_reduce(&mut t1);
|
|
polyveck_invntt_tomont(&mut t1);
|
|
|
|
// Add error vector s2
|
|
polyveck_add(&mut t1, &s2);
|
|
// Extract t1 and write public key
|
|
polyveck_caddq(&mut t1);
|
|
polyveck_power2round(&mut t1, &mut t0);
|
|
pack_pk(pk, &rho, &t1);
|
|
|
|
// Compute H(rho, t1) and write secret key
|
|
shake256(&mut tr, SEEDBYTES, pk, PUBLICKEYBYTES);
|
|
pack_sk(sk, &rho, &tr, &key, &t0, &s1, &s2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
pub fn crypto_sign_signature(sig: &mut [u8], m: &[u8], sk: &[u8]) {
|
|
// `key` and `mu` are concatenated
|
|
let mut keymu = [0u8; SEEDBYTES + CRHBYTES];
|
|
|
|
let mut nonce = 0u16;
|
|
let mut mat = [Polyvecl::default(); K];
|
|
let (mut s1, mut y) = (Polyvecl::default(), Polyvecl::default());
|
|
let (mut s2, mut t0) = (Polyveck::default(), Polyveck::default());
|
|
let (mut w1, mut w0) = (Polyveck::default(), Polyveck::default());
|
|
let mut h = Polyveck::default();
|
|
let mut cp = Poly::default();
|
|
let mut state = KeccakState::default(); //shake256_init()
|
|
let mut rho = [0u8; SEEDBYTES];
|
|
let mut tr = [0u8; SEEDBYTES];
|
|
let mut rhoprime = [0u8; CRHBYTES];
|
|
|
|
unpack_sk(
|
|
&mut rho,
|
|
&mut tr,
|
|
&mut keymu[..SEEDBYTES],
|
|
&mut t0,
|
|
&mut s1,
|
|
&mut s2,
|
|
&sk,
|
|
);
|
|
|
|
// Compute CRH(tr, msg)
|
|
shake256_absorb(&mut state, &tr, SEEDBYTES);
|
|
shake256_absorb(&mut state, m, m.len());
|
|
shake256_finalize(&mut state);
|
|
shake256_squeeze(&mut keymu[SEEDBYTES..], CRHBYTES, &mut state);
|
|
|
|
if RANDOMIZED_SIGNING {
|
|
randombytes(&mut rhoprime, CRHBYTES);
|
|
} else {
|
|
shake256(&mut rhoprime, CRHBYTES, &keymu, SEEDBYTES + CRHBYTES);
|
|
}
|
|
|
|
// Expand matrix and transform vectors
|
|
polyvec_matrix_expand(&mut mat, &rho);
|
|
polyvecl_ntt(&mut s1);
|
|
polyveck_ntt(&mut s2);
|
|
polyveck_ntt(&mut t0);
|
|
|
|
loop {
|
|
// Sample intermediate vector y
|
|
polyvecl_uniform_gamma1(&mut y, &rhoprime, nonce);
|
|
nonce += 1;
|
|
|
|
// Matrix-vector multiplication
|
|
let mut z = y;
|
|
polyvecl_ntt(&mut z);
|
|
polyvec_matrix_pointwise_montgomery(&mut w1, &mat, &z);
|
|
polyveck_reduce(&mut w1);
|
|
polyveck_invntt_tomont(&mut w1);
|
|
|
|
// Decompose w and call the random oracle
|
|
polyveck_caddq(&mut w1);
|
|
polyveck_decompose(&mut w1, &mut w0);
|
|
polyveck_pack_w1(sig, &w1);
|
|
|
|
state.init();
|
|
shake256_absorb(&mut state, &keymu[SEEDBYTES..], CRHBYTES);
|
|
shake256_absorb(&mut state, &sig, K * POLYW1_PACKEDBYTES);
|
|
shake256_finalize(&mut state);
|
|
shake256_squeeze(sig, SEEDBYTES, &mut state);
|
|
poly_challenge(&mut cp, sig);
|
|
poly_ntt(&mut cp);
|
|
|
|
// Compute z, reject if it reveals secret
|
|
polyvecl_pointwise_poly_montgomery(&mut z, &cp, &s1);
|
|
polyvecl_invntt_tomont(&mut z);
|
|
polyvecl_add(&mut z, &y);
|
|
polyvecl_reduce(&mut z);
|
|
if polyvecl_chknorm(&z, (GAMMA1 - BETA) as i32) > 0 {
|
|
continue;
|
|
}
|
|
|
|
/* Check that subtracting cs2 does not change high bits of w and low bits
|
|
* do not reveal secret information */
|
|
polyveck_pointwise_poly_montgomery(&mut h, &cp, &s2);
|
|
polyveck_invntt_tomont(&mut h);
|
|
polyveck_sub(&mut w0, &h);
|
|
polyveck_reduce(&mut w0);
|
|
if polyveck_chknorm(&w0, (GAMMA2 - BETA) as i32) > 0 {
|
|
continue;
|
|
}
|
|
|
|
// Compute hints for w1
|
|
polyveck_pointwise_poly_montgomery(&mut h, &cp, &t0);
|
|
polyveck_invntt_tomont(&mut h);
|
|
polyveck_reduce(&mut h);
|
|
if polyveck_chknorm(&h, GAMMA2_I32) > 0 {
|
|
continue;
|
|
}
|
|
|
|
polyveck_add(&mut w0, &h);
|
|
let n = polyveck_make_hint(&mut h, &w0, &w1);
|
|
if n > OMEGA as i32 {
|
|
continue;
|
|
}
|
|
|
|
// Write signature
|
|
pack_sig(sig, None, &z, &h);
|
|
return;
|
|
}
|
|
}
|
|
|
|
pub fn crypto_sign_verify(
|
|
sig: &[u8],
|
|
m: &[u8],
|
|
pk: &[u8],
|
|
) -> Result<(), SignError> {
|
|
let mut buf = [0u8; K * POLYW1_PACKEDBYTES];
|
|
let mut rho = [0u8; SEEDBYTES];
|
|
let mut mu = [0u8; CRHBYTES];
|
|
let mut c = [0u8; SEEDBYTES];
|
|
let mut c2 = [0u8; SEEDBYTES];
|
|
let mut cp = Poly::default();
|
|
let (mut mat, mut z) = ([Polyvecl::default(); K], Polyvecl::default());
|
|
let (mut t1, mut w1, mut h) = (
|
|
Polyveck::default(),
|
|
Polyveck::default(),
|
|
Polyveck::default(),
|
|
);
|
|
let mut state = KeccakState::default(); // shake256_init()
|
|
|
|
if sig.len() != SIGNBYTES {
|
|
return Err(SignError::Input);
|
|
}
|
|
|
|
unpack_pk(&mut rho, &mut t1, pk);
|
|
if let Err(e) = unpack_sig(&mut c, &mut z, &mut h, sig) {
|
|
return Err(e);
|
|
}
|
|
if polyvecl_chknorm(&z, (GAMMA1 - BETA) as i32) > 0 {
|
|
return Err(SignError::Input);
|
|
}
|
|
|
|
// Compute CRH(CRH(rho, t1), msg)
|
|
shake256(&mut mu, SEEDBYTES, pk, PUBLICKEYBYTES);
|
|
shake256_absorb(&mut state, &mu, SEEDBYTES);
|
|
shake256_absorb(&mut state, m, m.len());
|
|
shake256_finalize(&mut state);
|
|
shake256_squeeze(&mut mu, CRHBYTES, &mut state);
|
|
|
|
// Matrix-vector multiplication; compute Az - c2^dt1
|
|
poly_challenge(&mut cp, &c);
|
|
polyvec_matrix_expand(&mut mat, &rho);
|
|
|
|
polyvecl_ntt(&mut z);
|
|
polyvec_matrix_pointwise_montgomery(&mut w1, &mat, &z);
|
|
|
|
poly_ntt(&mut cp);
|
|
polyveck_shiftl(&mut t1);
|
|
polyveck_ntt(&mut t1);
|
|
let t1_2 = t1.clone();
|
|
polyveck_pointwise_poly_montgomery(&mut t1, &cp, &t1_2);
|
|
|
|
polyveck_sub(&mut w1, &t1);
|
|
polyveck_reduce(&mut w1);
|
|
polyveck_invntt_tomont(&mut w1);
|
|
|
|
// Reconstruct w1
|
|
polyveck_caddq(&mut w1);
|
|
polyveck_use_hint(&mut w1, &h);
|
|
polyveck_pack_w1(&mut buf, &w1);
|
|
|
|
// Call random oracle and verify challenge
|
|
state.init();
|
|
shake256_absorb(&mut state, &mu, CRHBYTES);
|
|
shake256_absorb(&mut state, &buf, K * POLYW1_PACKEDBYTES);
|
|
shake256_finalize(&mut state);
|
|
shake256_squeeze(&mut c2, SEEDBYTES, &mut state);
|
|
// Doesn't require constant time equality check
|
|
if c != c2 {
|
|
Err(SignError::Verify)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|