1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
use crate::{
error::KyberError,
kem::*,
kex::{Decapsulated, Encapsulated, PublicKey, SecretKey},
params::*,
CryptoRng, RngCore,
};
/// Keypair generation with a provided RNG.
///
/// ### Example
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(), KyberError> {
/// let mut rng = rand::thread_rng();
/// let keys = keypair(&mut rng)?;
/// # Ok(())}
/// ```
pub fn keypair<R>(rng: &mut R) -> Result<Keypair, KyberError>
where
R: RngCore + CryptoRng,
{
let mut public = [0u8; KYBER_PUBLICKEYBYTES];
let mut secret = [0u8; KYBER_SECRETKEYBYTES];
crypto_kem_keypair(&mut public, &mut secret, rng, None)?;
Ok(Keypair { public, secret })
}
/// Encapsulates a public key returning the ciphertext to send
/// and the shared secret
///
/// ### Example
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(), KyberError> {
/// let mut rng = rand::thread_rng();
/// let keys = keypair(&mut rng)?;
/// let (ciphertext, shared_secret) = encapsulate(&keys.public, &mut rng)?;
/// # Ok(())}
/// ```
pub fn encapsulate<R>(pk: &[u8], rng: &mut R) -> Encapsulated
where
R: CryptoRng + RngCore,
{
if pk.len() != KYBER_PUBLICKEYBYTES {
return Err(KyberError::InvalidInput);
}
let mut ct = [0u8; KYBER_CIPHERTEXTBYTES];
let mut ss = [0u8; KYBER_SSBYTES];
crypto_kem_enc(&mut ct, &mut ss, pk, rng, None)?;
Ok((ct, ss))
}
/// Decapsulates ciphertext with a secret key, the result will contain
/// a KyberError if decapsulation fails
///
/// ### Example
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(), KyberError> {
/// let mut rng = rand::thread_rng();
/// let keys = keypair(&mut rng)?;
/// let (ct, ss1) = encapsulate(&keys.public, &mut rng)?;
/// let ss2 = decapsulate(&ct, &keys.secret)?;
/// assert_eq!(ss1, ss2);
/// # Ok(())}
/// ```
pub fn decapsulate(ct: &[u8], sk: &[u8]) -> Decapsulated {
if ct.len() != KYBER_CIPHERTEXTBYTES || sk.len() != KYBER_SECRETKEYBYTES {
return Err(KyberError::InvalidInput);
}
let mut ss = [0u8; KYBER_SSBYTES];
crypto_kem_dec(&mut ss, ct, sk);
Ok(ss)
}
/// A public/secret keypair for use with Kyber.
///
/// Byte lengths of the keys are determined by the security level chosen.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Keypair {
pub public: PublicKey,
pub secret: SecretKey,
}
impl Keypair {
/// Securely generates a new keypair`
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(), KyberError> {
/// let mut rng = rand::thread_rng();
/// let keys = Keypair::generate(&mut rng)?;
/// # let empty_keys = Keypair{
/// public: [0u8; KYBER_PUBLICKEYBYTES], secret: [0u8; KYBER_SECRETKEYBYTES]
/// };
/// # assert!(empty_keys != keys);
/// # Ok(()) }
/// ```
pub fn generate<R: CryptoRng + RngCore>(rng: &mut R) -> Result<Keypair, KyberError> {
keypair(rng)
}
}
struct DummyRng {}
impl CryptoRng for DummyRng {}
impl RngCore for DummyRng {
fn next_u32(&mut self) -> u32 {
panic!()
}
fn next_u64(&mut self) -> u64 {
panic!()
}
fn try_fill_bytes(&mut self, _dest: &mut [u8]) -> Result<(), rand_core::Error> {
panic!()
}
fn fill_bytes(&mut self, _dest: &mut [u8]) {
panic!()
}
}
/// Deterministically derive a keypair from a seed as specified
/// in draft-schwabe-cfrg-kyber.
pub fn derive(seed: &[u8]) -> Result<Keypair, KyberError> {
let mut public = [0u8; KYBER_PUBLICKEYBYTES];
let mut secret = [0u8; KYBER_SECRETKEYBYTES];
let mut _rng = DummyRng {};
if seed.len() != 64 {
return Err(KyberError::InvalidInput);
}
crypto_kem_keypair(
&mut public,
&mut secret,
&mut _rng,
Some((&seed[..32], &seed[32..])),
)?;
Ok(Keypair { public, secret })
}
/// Extracts public key from private key.
pub fn public(sk: &[u8]) -> PublicKey {
let mut pk = [0u8; KYBER_INDCPA_PUBLICKEYBYTES];
pk.copy_from_slice(
&sk[KYBER_INDCPA_SECRETKEYBYTES..KYBER_INDCPA_SECRETKEYBYTES + KYBER_INDCPA_PUBLICKEYBYTES],
);
pk
}