use std::io;
use std::convert::TryFrom;
use seckey::Key;
use rand::{ Rand, Rng, OsRng };
use newhope::{
N, POLY_BYTES, SENDABYTES, SENDBBYTES,
poly_frombytes, poly_tobytes,
rec_frombytes, rec_tobytes,
keygen, sharedb, shareda,
sha3_256
};
use super::KeyExchange;
pub struct NewHope;
impl KeyExchange for NewHope {
type PrivateKey = PrivateKey;
type PublicKey = PublicKey;
type Reconciliation = Reconciliation;
const SK_LENGTH: usize = POLY_BYTES;
const PK_LENGTH: usize = SENDABYTES;
const REC_LENGTH: usize = SENDBBYTES;
fn keygen<R: Rand + Rng>() -> (Self::PrivateKey, Self::PublicKey) {
let (mut sk, mut pk) = (Key::from([0; N]), [0; SENDABYTES]);
{
let mut pka = [0; N];
let mut rng = OsRng::new().unwrap().gen::<R>();
rng.fill_bytes(&mut pk[POLY_BYTES..]);
keygen(&mut *sk, &mut pka, &pk[POLY_BYTES..], rng);
pk[..POLY_BYTES].clone_from_slice(&poly_tobytes(&pka));
}
(PrivateKey(sk), PublicKey(pk))
}
fn exchange<R: Rand + Rng>(sharedkey: &mut [u8], &PublicKey(ref pka): &Self::PublicKey) -> Self::Reconciliation {
let (mut key, mut pkb, mut rec) = (Key::from([0u8; 32]), [0; N], [0; N]);
let (pk, nonce) = pka.split_at(POLY_BYTES);
sharedb(
&mut *key, &mut pkb, &mut rec,
&poly_frombytes(pk), nonce, OsRng::new().unwrap().gen::<R>()
);
sha3_256(sharedkey, &*key);
let mut output = [0; SENDBBYTES];
output[..POLY_BYTES].clone_from_slice(&poly_tobytes(&pkb));
output[POLY_BYTES..].clone_from_slice(&rec_tobytes(&rec));
Reconciliation(output)
}
fn exchange_from(
sharedkey: &mut [u8],
&PrivateKey(ref sk): &Self::PrivateKey,
&Reconciliation(ref pk): &Self::Reconciliation
) {
let mut key = Key::from([0u8; 32]);
let (pkb, rec) = pk.split_at(POLY_BYTES);
shareda(
&mut *key, &sk[..],
&poly_frombytes(pkb),
&rec_frombytes(rec)
);
sha3_256(sharedkey, &key[..]);
}
}
new_type!(
pub struct PrivateKey(pub Key<[u16; N]>);
from: (input) {
if input.len() == POLY_BYTES {
Ok(PrivateKey(Key::from(poly_frombytes(input))))
} else {
err!(InvalidInput, "PrivateKey: invalid input length.")
}
},
into: (self) -> Vec<u8> {
let PrivateKey(ref input) = self;
Vec::from(&poly_tobytes(input) as &[u8])
}
);
new_type!(
pub struct PublicKey(pub [u8; SENDABYTES]);
from: (input) {
if input.len() == SENDABYTES {
let mut pk = [0; SENDABYTES];
pk.clone_from_slice(input);
Ok(PublicKey(pk))
} else {
err!(InvalidInput, "PublicKey: invalid input length.")
}
},
into: (self) -> Vec<u8> {
let PublicKey(ref input) = self;
Vec::from(input as &[u8])
}
);
new_type!(
pub struct Reconciliation(pub [u8; SENDBBYTES]);
from: (input) {
if input.len() == SENDBBYTES {
let mut rec = [0; SENDBBYTES];
rec.clone_from_slice(input);
Ok(Reconciliation(rec))
} else {
err!(InvalidInput, "Reconciliation: invalid input length.")
}
},
into: (self) -> Vec<u8> {
let Reconciliation(ref input) = self;
Vec::from(input as &[u8])
}
);