Skip to content

Commit

Permalink
Use constant generics
Browse files Browse the repository at this point in the history
  • Loading branch information
tbrezot committed Sep 2, 2022
1 parent e5448fb commit 092558e
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 166 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
All notable changes to this project will be documented in this file.

---
## [2.0.1] - 2022-09-02
## [3.0.0] - 2022-09-02
### Added
- `Hash` super trait to `SymKey`
### Changed
- use constant generics
### Fixed
### Removed
---
Expand Down
6 changes: 2 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description = "Crypto lib for pure crypto primitives"
edition = "2021"
license = "MIT/Apache-2.0"
name = "cosmian_crypto_core"
version = "2.0.1"
version = "3.0.0"

[lib]
crate-type = ["cdylib", "rlib"]
Expand All @@ -15,7 +15,6 @@ path = "src/lib.rs"
aes = "0.8"
aes-gcm = "0.9"
curve25519-dalek = "3.2"
generic-array = { version = "0.14.5", features = ["serde"] }
# specify the js feature for the WASM target
getrandom = { version = "0.2", features = ["js"] }
hex = "0.4"
Expand Down
64 changes: 30 additions & 34 deletions src/asymmetric_crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use curve25519_dalek::{
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
};
use generic_array::{typenum::U32, GenericArray};
use rand_core::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use std::{
Expand All @@ -21,6 +20,12 @@ use std::{
};
use zeroize::{Zeroize, ZeroizeOnDrop};

/// X25519 secret key length
const X25519_SK_LENGTH: usize = 32;

/// X25519 public key length
const X25519_PK_LENGTH: usize = 32;

/// Asymmetric private key based on Curve25519.
///
/// Internally, a curve scalar is used. It is 128-bits long.
Expand Down Expand Up @@ -52,25 +57,22 @@ impl X25519PrivateKey {
}
}

impl KeyTrait for X25519PrivateKey {
type Length = U32;

/// Convert the given private key into bytes.
#[inline]
#[must_use]
fn to_bytes(&self) -> GenericArray<u8, Self::Length> {
GenericArray::<u8, Self::Length>::from(self.0.to_bytes())
impl KeyTrait<X25519_SK_LENGTH> for X25519PrivateKey {
/// Converts the given key into bytes.
fn to_bytes(&self) -> [u8; Self::LENGTH] {
self.0.to_bytes()
}

/// Converts the given bytes into key.
fn try_from_bytes(bytes: &[u8]) -> Result<Self, CryptoCoreError> {
Self::try_from(bytes)
}
}

impl TryFrom<[u8; 32]> for X25519PrivateKey {
impl TryFrom<[u8; Self::LENGTH]> for X25519PrivateKey {
type Error = CryptoCoreError;

fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
fn try_from(bytes: [u8; Self::LENGTH]) -> Result<Self, Self::Error> {
let scalar = Scalar::from_canonical_bytes(bytes).ok_or_else(|| {
Self::Error::ConversionError(
"Given bytes do not represent a canonical Scalar!".to_string(),
Expand All @@ -84,7 +86,7 @@ impl TryFrom<&[u8]> for X25519PrivateKey {
type Error = CryptoCoreError;

fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes: [u8; 32] = bytes.try_into().map_err(|e| {
let bytes: [u8; Self::LENGTH] = bytes.try_into().map_err(|e| {
Self::Error::ConversionError(format!(
"Error while converting slice of size {} to `X25519PublicKey`: {}",
bytes.len(),
Expand All @@ -95,15 +97,9 @@ impl TryFrom<&[u8]> for X25519PrivateKey {
}
}

impl From<&X25519PrivateKey> for [u8; 32] {
fn from(key: &X25519PrivateKey) -> Self {
key.0.to_bytes()
}
}

// Needed by serde to derive `Deserialize`. Do not use otherwise since there
// is a copy anyway
impl From<X25519PrivateKey> for [u8; 32] {
impl From<X25519PrivateKey> for [u8; X25519_SK_LENGTH] {
fn from(key: X25519PrivateKey) -> Self {
key.0.to_bytes()
}
Expand Down Expand Up @@ -240,14 +236,11 @@ impl X25519PublicKey {
}
}

impl KeyTrait for X25519PublicKey {
type Length = U32;

/// Convert the given public key into an array of bytes.
impl KeyTrait<X25519_PK_LENGTH> for X25519PublicKey {
/// Converts the given public key into an array of bytes.
#[inline]
#[must_use]
fn to_bytes(&self) -> GenericArray<u8, Self::Length> {
GenericArray::<u8, Self::Length>::from(self.0.compress().to_bytes())
fn to_bytes(&self) -> [u8; Self::LENGTH] {
self.0.compress().to_bytes()
}

fn try_from_bytes(bytes: &[u8]) -> Result<Self, CryptoCoreError> {
Expand All @@ -261,10 +254,10 @@ impl From<&X25519PrivateKey> for X25519PublicKey {
}
}

impl TryFrom<[u8; 32]> for X25519PublicKey {
impl TryFrom<[u8; Self::LENGTH]> for X25519PublicKey {
type Error = CryptoCoreError;

fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
fn try_from(bytes: [u8; Self::LENGTH]) -> Result<Self, Self::Error> {
Ok(Self(CompressedRistretto(bytes).decompress().ok_or_else(
|| {
CryptoCoreError::ConversionError(
Expand All @@ -279,7 +272,7 @@ impl TryFrom<&[u8]> for X25519PublicKey {
type Error = CryptoCoreError;

fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes: [u8; 32] = bytes.try_into().map_err(|e| {
let bytes: [u8; Self::LENGTH] = bytes.try_into().map_err(|e| {
Self::Error::ConversionError(format!(
"Error while converting slice of size {} to `X25519PublicKey`: {}",
bytes.len(),
Expand All @@ -292,13 +285,13 @@ impl TryFrom<&[u8]> for X25519PublicKey {

// Needed by serde to derive `Deserialize`. Do not use otherwise since there
// is a copy anyway.
impl From<X25519PublicKey> for [u8; 32] {
impl From<X25519PublicKey> for [u8; X25519_PK_LENGTH] {
fn from(key: X25519PublicKey) -> Self {
key.0.compress().to_bytes()
}
}

impl From<&X25519PublicKey> for [u8; 32] {
impl From<&X25519PublicKey> for [u8; X25519_PK_LENGTH] {
fn from(key: &X25519PublicKey) -> Self {
key.0.compress().to_bytes()
}
Expand Down Expand Up @@ -379,15 +372,18 @@ impl ZeroizeOnDrop for X25519PublicKey {}
#[cfg(test)]
mod test {
use crate::{
asymmetric_crypto::{X25519PrivateKey, X25519PublicKey},
asymmetric_crypto::{
X25519PrivateKey, X25519PublicKey, X25519_PK_LENGTH, X25519_SK_LENGTH,
},
entropy::CsRng,
KeyTrait,
};

#[test]
fn test_private_key_serialization() {
let mut rng = CsRng::new();
let sk = X25519PrivateKey::new(&mut rng);
let bytes: [u8; 32] = (&sk).into();
let bytes: [u8; X25519_SK_LENGTH] = sk.to_bytes();
let recovered = X25519PrivateKey::try_from(bytes).unwrap();
assert_eq!(sk, recovered);
}
Expand All @@ -396,7 +392,7 @@ mod test {
fn test_public_key_serialization() {
let mut rng = CsRng::new();
let pk = X25519PublicKey::new(&mut rng);
let bytes: [u8; 32] = (&pk).into();
let bytes: [u8; X25519_PK_LENGTH] = pk.to_bytes();
let recovered = super::X25519PublicKey::try_from(bytes).unwrap();
assert_eq!(pk, recovered);
}
Expand Down
12 changes: 5 additions & 7 deletions src/entropy.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use generic_array::{ArrayLength, GenericArray};
use rand_core::{CryptoRng, RngCore, SeedableRng};
use rand_hc::Hc128Rng;

Expand All @@ -21,8 +20,8 @@ impl CsRng {
/// Generate a vector of random bytes with the given length.
///
/// - `len` : number of random bytes to generate
pub fn generate_random_bytes<N: ArrayLength<u8>>(&mut self) -> GenericArray<u8, N> {
let mut bytes = GenericArray::<u8, N>::default();
pub fn generate_random_bytes<const LENGTH: usize>(&mut self) -> [u8; LENGTH] {
let mut bytes = [0; LENGTH];
self.rng.fill_bytes(&mut bytes);
bytes
}
Expand Down Expand Up @@ -58,16 +57,15 @@ impl CryptoRng for CsRng {}
mod test {

use crate::entropy::CsRng;
use generic_array::typenum::{Unsigned, U1024};

#[test]
fn test_random_bytes() {
let mut cs_rng = CsRng::default();
type N = U1024;
const N: usize = 1024;
let random_bytes_1 = cs_rng.generate_random_bytes::<N>();
assert_eq!(<N as Unsigned>::to_usize(), random_bytes_1.len());
assert_eq!(N, random_bytes_1.len());
let random_bytes_2 = cs_rng.generate_random_bytes();
assert_eq!(<N as Unsigned>::to_usize(), random_bytes_1.len());
assert_eq!(N, random_bytes_1.len());
assert_ne!(random_bytes_1, random_bytes_2);
}
}
11 changes: 5 additions & 6 deletions src/kdf.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::CryptoCoreError;
use generic_array::{ArrayLength, GenericArray};
use hkdf::Hkdf;
use sha2::Sha256;

Expand All @@ -9,18 +8,18 @@ use sha2::Sha256;
///
/// - `bytes` : input bytes to hash, should be at least 32-bytes long
/// - `info` : some optional additional information to use in the hash
pub fn hkdf_256<KeyLength: ArrayLength<u8>>(
pub fn hkdf_256<const LENGTH: usize>(
bytes: &[u8],
info: &[u8],
) -> Result<GenericArray<u8, KeyLength>, CryptoCoreError> {
) -> Result<[u8; LENGTH], CryptoCoreError> {
if bytes.len() < 32 {
return Err(CryptoCoreError::InvalidSize(
"Input `bytes` size should be at least 32".to_string(),
"Input `bytes` size should be at least 32 bytes".to_string(),
));
}
let h = Hkdf::<Sha256>::new(None, bytes);
let mut out = GenericArray::<u8, KeyLength>::default();
let mut out = [0; LENGTH];
h.expand(info, &mut out)
.map_err(|_| CryptoCoreError::KdfError(KeyLength::to_usize()))?;
.map_err(|_| CryptoCoreError::KdfError(LENGTH))?;
Ok(out)
}
11 changes: 6 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,20 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
pub use crate::error::CryptoCoreError;

pub mod reexport {
pub use generic_array;
// reexport `rand_core` so that the PRNG implement the correct version of the traits
pub use rand_core;
}

/// Trait defining a cryptographic key.
pub trait KeyTrait: PartialEq + Eq + Send + Sync + Sized + Clone + Zeroize + ZeroizeOnDrop {
/// Number of bytes in the serialized key.
type Length: Eq + generic_array::ArrayLength<u8>;
pub trait KeyTrait<const LENGTH: usize>:
PartialEq + Eq + Send + Sync + Sized + Clone + Zeroize + ZeroizeOnDrop
{
/// Key length
const LENGTH: usize = LENGTH;

/// Convert the given key into a vector of bytes.
#[must_use]
fn to_bytes(&self) -> generic_array::GenericArray<u8, Self::Length>;
fn to_bytes(&self) -> [u8; LENGTH];

/// Convert the given bytes into a key. An error is returned in case the
/// conversion fails.
Expand Down
26 changes: 12 additions & 14 deletions src/symmetric_crypto/aes_256_gcm_pure/dem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,31 @@
use crate::{
symmetric_crypto::{
aes_256_gcm_pure::Aes256GcmCrypto, nonce::NonceTrait, Dem, SymmetricCrypto,
aes_256_gcm_pure::{Aes256GcmCrypto, KEY_LENGTH},
nonce::NonceTrait,
Dem, SymmetricCrypto,
},
CryptoCoreError, KeyTrait,
CryptoCoreError,
};
use generic_array::typenum::Unsigned;
use rand_core::{CryptoRng, RngCore};
use std::convert::TryFrom;

impl Dem for Aes256GcmCrypto {
impl Dem<KEY_LENGTH> for Aes256GcmCrypto {
fn encaps<R: RngCore + CryptoRng>(
rng: &mut R,
secret_key: &[u8],
additional_data: Option<&[u8]>,
message: &[u8],
) -> Result<Vec<u8>, CryptoCoreError> {
let key_length = <<Self::Key as KeyTrait>::Length as Unsigned>::to_usize();
if secret_key.len() < key_length {
if secret_key.len() < KEY_LENGTH {
return Err(CryptoCoreError::SizeError {
given: secret_key.len(),
expected: key_length,
expected: KEY_LENGTH,
});
}
// AES GCM includes an authentication method
// there is no need for parsing a MAC key
let key = Self::Key::try_from(&secret_key[..key_length])?;
let key = Self::Key::try_from(&secret_key[..KEY_LENGTH])?;
let nonce = Self::Nonce::new(rng);
let mut c = Self::encrypt(&key, message, &nonce, additional_data)
.map_err(|err| CryptoCoreError::EncryptionError(err.to_string()))?;
Expand All @@ -42,16 +42,15 @@ impl Dem for Aes256GcmCrypto {
additional_data: Option<&[u8]>,
encapsulation: &[u8],
) -> Result<Vec<u8>, CryptoCoreError> {
let key_length = <<Self::Key as KeyTrait>::Length as Unsigned>::to_usize();
if secret_key.len() < key_length {
if secret_key.len() < KEY_LENGTH {
return Err(CryptoCoreError::SizeError {
given: secret_key.len(),
expected: key_length,
expected: KEY_LENGTH,
});
}
// AES GCM includes an authentication method
// there is no need for parsing a MAC key
let key = Self::Key::try_from(&secret_key[..key_length])?;
let key = Self::Key::try_from(&secret_key[..KEY_LENGTH])?;
let nonce = Self::Nonce::try_from(&encapsulation[..Self::Nonce::LENGTH])?;
Self::decrypt(
&key,
Expand All @@ -71,14 +70,13 @@ mod tests {
symmetric_crypto::{aes_256_gcm_pure::Aes256GcmCrypto, Dem},
CryptoCoreError,
};
use generic_array::typenum::U256;

#[test]
fn test_dem() -> Result<(), CryptoCoreError> {
let m = b"my secret message";
let additional_data = Some(b"public tag".as_slice());
let mut rng = CsRng::new();
let secret_key = rng.generate_random_bytes::<U256>();
let secret_key = rng.generate_random_bytes::<256>();
let c = Aes256GcmCrypto::encaps(&mut rng, &secret_key, additional_data, m)?;
let res = Aes256GcmCrypto::decaps(&secret_key, additional_data, &c)?;
if res != m {
Expand Down
Loading

0 comments on commit 092558e

Please sign in to comment.