Skip to content

Commit

Permalink
use seeds as private key default behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
supinie committed Jan 9, 2025
1 parent abc0774 commit b928484
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 95 deletions.
2 changes: 2 additions & 0 deletions src/indcpa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ impl PrivateKey {
}

// buf should be of length indcpa_private_key_bytes
#[cfg(feature = "decap_key")]
pub(crate) fn pack(&self, buf: &mut [u8]) -> Result<(), PackingError> {
self.secret.pack(buf)
}

// buf should be of length indcpa_private_key_bytes
#[cfg(feature = "decap_key")]
pub(crate) fn unpack(buf: &[u8]) -> Result<Self, PackingError> {
let secret = PolyVec::unpack(buf)?.normalise();
Ok(Self { secret })
Expand Down
211 changes: 160 additions & 51 deletions src/kem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,24 @@ use sha3::{
use subtle::{ConditionallySelectable, ConstantTimeEq};
use tinyvec::ArrayVec;

/// `PrivateKey` struct that can only be generated via the [`generate_keypair_512`], [`generate_keypair_768`], or [`generate_keypair_1024`] functions
/// and is used to [`decapsulate`](PrivateKey::decapsulate) a shared secret from a given ciphertext.
/// `PrivateKey` struct that can only be generated via the [`generate_keypair_512`], [`generate_keypair_768`], or
/// [`generate_keypair_1024`] functions and is used to [`decapsulate`](PrivateKey::decapsulate) a shared secret from a given ciphertext.
///
/// Can be accessed in byte form by packing into a `u8` array using the [`pack`](PrivateKey::pack) method,
/// and made available for use again using the [`unpack`](PrivateKey::unpack) method. If using
/// `decap_key` feature, the
/// array used to pack must be of the correct length for the given security level, see
/// and made available for use again using the [`unpack`](PrivateKey::unpack) method.
///
/// If using `decap_key` feature, the array used to pack must be of the correct length for the given security level, see
/// [`pack`](PrivateKey::pack) for more.
#[derive(Debug, Eq, PartialEq)]
pub struct PrivateKey {
#[cfg(not(feature = "decap_key"))]
key: PrivateSeed,
#[cfg(feature = "decap_key")]
key: PrivateKeyInner,
sec_level: SecurityLevel,
}

#[cfg(not(feature = "decap_key"))]
#[derive(Debug, Eq, PartialEq)]
struct PrivateSeed {
seed: [u8; 2 * SYMBYTES],
Expand Down Expand Up @@ -57,6 +59,7 @@ pub struct PublicKey {
}

/// `Ciphertext` struct that can only be generated by [`encapsulate`](PublicKey::encapsulate).
///
/// Should be converted to bytes using the [`as_bytes`](Ciphertext::as_bytes) method to be transmitted and decapsulated.
pub struct Ciphertext {
bytes: [u8; MAX_CIPHERTEXT], // max ciphertext_bytes()
Expand Down Expand Up @@ -112,13 +115,9 @@ fn shake256_from(input: &[u8]) -> [u8; SHAREDSECRETBYTES] {

// derived new keypair deterministically from a given 64 (2 * 32) byte seed.
fn new_key_from_seed(
seed: &[u8],
seed: [u8; 2 * SYMBYTES],
sec_level: SecurityLevel,
) -> Result<(PublicKey, PrivateKeyInner), KeyGenerationError> {
if seed.len() != 2 * SYMBYTES {
return Err(CrystalsError::InvalidSeedLength(seed.len(), 2 * SYMBYTES).into());
}

let (sk, pk) = generate_indcpa_key_pair(&seed[..SYMBYTES], sec_level)?;

let z: [u8; SYMBYTES] = seed[SYMBYTES..].try_into()?;
Expand Down Expand Up @@ -151,15 +150,17 @@ pub(crate) fn generate_key_pair(

let sec_level = SecurityLevel::new(k);

let (pk, sk_inner) = new_key_from_seed(&seed, sec_level)?;
let (pk, _sk_inner) = new_key_from_seed(seed, sec_level)?;

Ok((
pk,
PrivateKey {
#[cfg(not(feature = "decap_key"))]
key: PrivateSeed { seed },
#[cfg(feature = "decap_key")]
key: sk_inner,
#[allow(clippy::used_underscore_binding)]
key: _sk_inner,
sec_level,
},
))
}
Expand Down Expand Up @@ -266,32 +267,55 @@ impl PrivateKey {
self.key.sk.sec_level()
}

// /// Returns the corresponding public key for a given private key
// ///
// /// # Example
// /// ```
// /// # use enc_rust::kem::*;
// /// let (_, sk) = generate_keypair_768(None)?;
// /// let pk = sk.get_public_key();
// ///
// /// # Ok::<(), enc_rust::errors::KeyGenerationError>(())
// /// ```
// #[must_use]
// pub const fn get_public_key(&self) -> PublicKey {
// #[cfg(not(feature = "decap_key"))]
// {
// let (pk, _) = new_key_from_seed(&self.key.seed, self.key.sec_level).unwrap();

// pk
// }
// #[cfg(feature = "decap_key")]
// {
// PublicKey {
// pk: self.key.pk,
// h_pk: self.key.h_pk,
// }
// }
// }
/// Returns the corresponding public key for a given private key
///
/// # Example
/// ```
/// # use enc_rust::kem::*;
/// let (_, sk) = generate_keypair_768(None)?;
/// let pk = sk.get_public_key();
///
/// # Ok::<(), enc_rust::errors::KeyGenerationError>(())
/// ```
#[allow(clippy::missing_panics_doc, clippy::unwrap_used)]
#[must_use]
pub fn get_public_key(&self) -> PublicKey {
#[cfg(not(feature = "decap_key"))]
{
let (pk, _) = new_key_from_seed(self.key.seed, self.sec_level).unwrap();

pk
}
#[cfg(feature = "decap_key")]
{
PublicKey {
pk: self.key.pk,
h_pk: self.key.h_pk,
}
}
}

/// Packs the private key as bytes and returns it as a 64 byte array
///
/// # Example
/// ```
/// # use enc_rust::kem::*;
/// let (_, sk) = generate_keypair_768(None).unwrap();
/// #[cfg(feature = "decap_key")]
/// {
/// let mut sk_bytes = [0u8; 2400];
/// sk.pack(&mut sk_bytes)?;
/// }
/// #[cfg(not(feature = "decap_key"))]
/// let sk_bytes = sk.pack();
///
/// # Ok::<(), enc_rust::errors::PackingError>(())
/// ```
#[must_use]
#[cfg(not(feature = "decap_key"))]
pub const fn pack(&self) -> [u8; 2 * SYMBYTES] {
self.key.seed
}

/// Packs private key into a given buffer
///
Expand Down Expand Up @@ -322,11 +346,6 @@ impl PrivateKey {
///
/// # Ok::<(), enc_rust::errors::PackingError>(())
/// ```
#[must_use]
#[cfg(not(feature = "decap_key"))]
pub const fn pack(&self) -> [u8; 2 * SYMBYTES] {
self.key.seed
}
#[cfg(feature = "decap_key")]
pub fn pack(&self, bytes: &mut [u8]) -> Result<(), PackingError> {
let sec_level = self.sec_level();
Expand Down Expand Up @@ -358,8 +377,39 @@ impl PrivateKey {
/// # Outputs
/// - [`PrivateKey`] object
///
/// # Errors
/// Will return a [`PackingError`] if the buffer is of the wrong length
/// # Example
/// ```
/// # use enc_rust::kem::*;
/// # let (pk, new_sk) = generate_keypair_768(None).unwrap();
/// # #[cfg(feature = "decap_key")]
/// # {
/// # let mut sk_bytes = [0u8; 2400];
/// # new_sk.pack(&mut sk_bytes)?;
/// # }
/// # #[cfg(not(feature = "decap_key"))]
/// # let sk_bytes = new_sk.pack();
///
/// # #[cfg(not(feature = "decap_key"))]
/// let sk = PrivateKey::unpack_512(sk_bytes);
///
/// # Ok::<(), enc_rust::errors::PackingError>(())
/// ```
#[must_use]
#[cfg(not(feature = "decap_key"))]
pub const fn unpack_512(bytes: [u8; 2 * SYMBYTES]) -> Self {
Self {
key: PrivateSeed { seed: bytes },
sec_level: SecurityLevel::new(K::Two),
}
}

/// Unpacks a buffer of bytes into a [`PrivateKey`]
///
/// # Inputs
/// - `bytes`: Buffer for the private key to be extracted from
///
/// # Outputs
/// - [`PrivateKey`] object
///
/// # Example
/// ```
Expand All @@ -373,21 +423,79 @@ impl PrivateKey {
/// # #[cfg(not(feature = "decap_key"))]
/// # let sk_bytes = new_sk.pack();
///
/// #[cfg(feature = "decap_key")]
/// let sk = PrivateKey::unpack(&sk_bytes)?;
/// # #[cfg(not(feature = "decap_key"))]
/// let sk = PrivateKey::unpack_768(sk_bytes);
///
/// #[cfg(not(feature = "decap_key"))]
/// let sk = PrivateKey::unpack(sk_bytes);
/// # Ok::<(), enc_rust::errors::PackingError>(())
/// ```
#[must_use]
#[cfg(not(feature = "decap_key"))]
pub const fn unpack_768(bytes: [u8; 2 * SYMBYTES]) -> Self {
Self {
key: PrivateSeed { seed: bytes },
sec_level: SecurityLevel::new(K::Three),
}
}

/// Unpacks a buffer of bytes into a [`PrivateKey`]
///
/// # Inputs
/// - `bytes`: Buffer for the private key to be extracted from
///
/// # Outputs
/// - [`PrivateKey`] object
///
/// # Example
/// ```
/// # use enc_rust::kem::*;
/// # let (pk, new_sk) = generate_keypair_768(None).unwrap();
/// # #[cfg(feature = "decap_key")]
/// # {
/// # let mut sk_bytes = [0u8; 2400];
/// # new_sk.pack(&mut sk_bytes)?;
/// # }
/// # #[cfg(not(feature = "decap_key"))]
/// # let sk_bytes = new_sk.pack();
///
/// # #[cfg(not(feature = "decap_key"))]
/// let sk = PrivateKey::unpack_1024(sk_bytes);
///
/// # Ok::<(), enc_rust::errors::PackingError>(())
/// ```
#[must_use]
#[cfg(not(feature = "decap_key"))]
pub const fn unpack(bytes: [u8; 2 * SYMBYTES]) -> Self {
pub const fn unpack_1024(bytes: [u8; 2 * SYMBYTES]) -> Self {
Self {
key: PrivateSeed { seed: bytes },
sec_level: SecurityLevel::new(K::Four),
}
}

/// Unpacks a buffer of bytes into a [`PrivateKey`]
///
/// # Inputs
/// - `bytes`: Buffer for the private key to be extracted from
///
/// # Outputs
/// - [`PrivateKey`] object
///
/// # Errors
/// Will return a [`PackingError`] if the buffer is of the wrong length
///
/// # Example
/// ```
/// # use enc_rust::kem::*;
/// # let (pk, new_sk) = generate_keypair_768(None).unwrap();
/// # #[cfg(feature = "decap_key")]
/// # {
/// # let mut sk_bytes = [0u8; 2400];
/// # new_sk.pack(&mut sk_bytes)?;
///
/// let sk = PrivateKey::unpack(&sk_bytes)?;
/// # }
///
/// # Ok::<(), enc_rust::errors::PackingError>(())
/// ```
#[cfg(feature = "decap_key")]
pub fn unpack(bytes: &[u8]) -> Result<Self, PackingError> {
let sec_level = match bytes.len() {
Expand All @@ -409,6 +517,7 @@ impl PrivateKey {

Ok(Self {
key: PrivateKeyInner { sk, pk, h_pk, z },
sec_level,
})
}

Expand Down Expand Up @@ -458,7 +567,7 @@ impl PrivateKey {
}?;

#[cfg(not(feature = "decap_key"))]
let (_, inner) = new_key_from_seed(&self.key.seed, sec_level)?;
let (_, inner) = new_key_from_seed(self.key.seed, sec_level)?;
#[cfg(feature = "decap_key")]
let inner = &self.key;

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![allow(unused)]
#![forbid(unsafe_code)]
#![warn(
clippy::cast_lossless,
Expand All @@ -17,6 +16,7 @@
unused_lifetimes,
unused_qualifications
)]
#![allow(clippy::too_long_first_doc_paragraph)]
#![no_std]

//! ### About
Expand Down
6 changes: 1 addition & 5 deletions src/matrix.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
errors::CrystalsError,
params::{SecurityLevel, K},
params::K,
polynomials::{Montgomery, Poly, State},
vectors::PolyVec,
};
Expand All @@ -13,10 +13,6 @@ pub struct Matrix<S: State> {
}

impl<S: State + Copy> Matrix<S> {
pub(crate) const fn sec_level(&self) -> SecurityLevel {
SecurityLevel::new(self.sec_level)
}

pub(crate) fn vectors(&self) -> &[PolyVec<S>] {
&self.polyvecs.as_slice()[..self.sec_level.into()]
}
Expand Down
2 changes: 2 additions & 0 deletions src/polynomials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ impl Poly<Normalised> {
// ```
// let poly = Poly::new();
// ```
// This is actually used, removing it creates errors but clippy thinks its not...
#[allow(dead_code)]
pub const fn new() -> Self {
Self {
coeffs: [0; N],
Expand Down
9 changes: 0 additions & 9 deletions src/polynomials/sample.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,11 @@ use crate::{
polynomials::{Montgomery, Poly},
};
use byteorder::{ByteOrder, LittleEndian};
use rand_core::{CryptoRng, Error, RngCore};
use sha3::{
digest::{ExtendableOutput, Update, XofReader},
Shake128, Shake256,
};

pub fn random_bytes<R>(buf: &mut [u8], len: usize, rng: &mut R) -> Result<(), Error>
where
R: RngCore + CryptoRng,
{
rng.try_fill_bytes(&mut buf[..len])?;
Ok(())
}

impl Poly<Montgomery> {
// Sample our polynomial from a centered binomial distribution
// given a uniformly distributed array of bytes
Expand Down
1 change: 1 addition & 0 deletions src/tests/indcpa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ pub(in crate::tests) mod indcpa_tests {
assert_eq!(message, plaintext, "security level: {:?}", sec_level);
}

#[cfg(feature = "decap_key")]
#[test]
fn key_pack_unpack(
(priv_key, pub_key) in new_indcpa_keypair(),
Expand Down
Loading

0 comments on commit b928484

Please sign in to comment.