Skip to content

Commit

Permalink
polish docs
Browse files Browse the repository at this point in the history
  • Loading branch information
supinie committed May 28, 2024
1 parent 49f4cbe commit 9b57bba
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 57 deletions.
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,39 @@ enc_rust currently supports ML-KEM as a sole mechanism, but will provide:

---

### How to use

Currently, enc_rust is not released as a crate, but plans to launch soon. In its current state, it can be used with `cargo add --git https://github.com/supinie/enc_rust`.

#### Example

```rust
use enc_rust::kem::*;

fn alice(pk: PublicKey) -> (Ciphertext, [u8; 32]) {
let (ciphertext, shared_secret) = pk.encapsulate(None, None).unwrap();

(ciphertext, shared_secret)
}

fn bob(sk: PrivateKey, ciphertext: &[u8]) -> [u8; 32] {
let shared_secret = sk.decapsulate(ciphertext).unwrap();

shared_secret
}


fn main() {
let (pk, sk) = generate_key_pair(None, 3).unwrap();

let (ciphertext, alice_secret) = alice(pk);

let bob_secret = bob(sk, ciphertext.as_bytes());

assert_eq!(alice_secret, bob_secret);
}
```

### Disclaimer

This library and binary wrapper is offered as-is, and without a guarantee. Please exercise caution when using this library in a production application, and we accept no liability for any security issues related to the use of this code.
Expand Down
129 changes: 77 additions & 52 deletions src/kem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ use sha3::{
use subtle::{ConditionallySelectable, ConstantTimeEq};
use tinyvec::ArrayVec;

/// PrivateKey struct that can only be generated via the [`generate_key_pair`] function
/// 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. 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 {
sk: IndcpaPrivateKey,
Expand All @@ -22,12 +29,21 @@ pub struct PrivateKey {
z: [u8; SYMBYTES],
}

/// PublicKey struct that can only be generated via the [`generate_key_pair`] or from the
/// corresponding [`PrivateKey`] struct using the [`get_public_key`](PrivateKey::get_public_key)
/// method and is used to [`encapsulate`](PublicKey::encapsulate) a shared secret.
///
/// Can be packed into a `u8` byte array using the [`pack`](PublicKey::pack) and
/// [`unpack`](PublicKey::unpack) methods. The array used to pack must be of the correct length
/// for the given secrity level, see [`pack`](PublicKey::pack) for more.
#[derive(Debug, Eq, PartialEq)]
pub struct PublicKey {
pk: IndcpaPublicKey,
h_pk: [u8; SYMBYTES],
}

/// 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()
len: usize,
Expand All @@ -39,7 +55,6 @@ impl Ciphertext {
/// # Example
/// ```
/// # use enc_rust::kem::*;
///
/// # let (pk, sk) = generate_key_pair(None, 3).unwrap();
/// let (ciphertext_obj, shared_secret) = pk.encapsulate(None, None)?;
/// let ciphertext = ciphertext_obj.as_bytes();
Expand Down Expand Up @@ -102,31 +117,40 @@ fn new_key_from_seed(
Ok((PublicKey { pk, h_pk }, PrivateKey { sk, pk, h_pk, z }))
}

/// Acceptable RNG to be used in encapsulation and key generation must have the
/// [`RngCore`](https://docs.rs/rand_core/latest/rand_core/trait.RngCore.html) and
/// [`CryptoRng`](https://docs.rs/rand_core/latest/rand_core/trait.CryptoRng.html) traits.
pub trait AcceptableRng: RngCore + CryptoRng {}

/// Generates a new keypair for a given security level.
///
/// # Inputs
/// - `rng`: (Optional) RNG to be used when generating the keypair. Must satisfy the `RngCore` and
/// `CryptoRng` traits. If RNG is not present, then `ChaCha20` will be used.
/// - `rng`: (Optional) RNG to be used when generating the keypair. Must satisfy the
/// [`RngCore`](https://docs.rs/rand_core/latest/rand_core/trait.RngCore.html) and
/// [`CryptoRng`](https://docs.rs/rand_core/latest/rand_core/trait.CryptoRng.html) traits.
/// If RNG is not present, then
/// [`ChaCha20`](https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha20Rng.html)
/// will be used.
/// - `k`: The k value corresponding to the security value to be used:
/// - 2: 512
/// - 3: 768
/// - 4: 1024
///
/// | Security Level | K |
/// |----------------|---|
/// | 512 | 2 |
/// | 768 | 3 |
/// | 1024 | 4 |
///
/// # Outputs
/// - `PublicKey` object
/// - `PrivateKey` object
/// - [`PublicKey`] object
/// - [`PrivateKey`] object
///
/// # Errors
/// Will return a `KeyGenerationError` if:
/// Will return a [`KeyGenerationError`] if:
/// - Given invalid K value
/// - RNG fails
///
/// # Example
/// ```
/// # use enc_rust::kem::*;
///
/// let (pk, sk) = generate_key_pair(None, 3)?;
///
/// # Ok::<(), enc_rust::errors::KeyGenerationError>(())
Expand Down Expand Up @@ -164,8 +188,7 @@ impl PrivateKey {
///
/// # Example
/// ```
/// use enc_rust::kem::*;
///
/// # use enc_rust::kem::*;
/// let (_, sk) = generate_key_pair(None, 3)?;
/// let pk = sk.get_public_key();
///
Expand All @@ -182,20 +205,22 @@ impl PrivateKey {
/// Packs private key into a given buffer
///
/// # Inputs
/// - `bytes`: Buffer for the private key to be packed into
/// For corresponding security levels, `bytes` should be of length:
/// - 512: 1632
/// - 768: 2400
/// - 1024: 3168
/// - `bytes`: Buffer for the private key to be packed into. For corresponding
/// security levels, `bytes` should be of length:
///
/// | Security Level | Length |
/// |----------------|--------|
/// | 512 | 1632 |
/// | 768 | 2400 |
/// | 1024 | 3168 |
///
/// # Errors
/// Will return a `PackingError` if the buffer is of the wrong length
/// Will return a [`PackingError`] if the buffer is of the wrong length
///
/// # Example
/// ```
/// use enc_rust::kem::*;
/// # let (pk, sk) = generate_key_pair(None, 3).unwrap();
///
/// # use enc_rust::kem::*;
/// let (_, sk) = generate_key_pair(None, 3).unwrap();
/// let mut sk_bytes = [0u8; 2400];
/// sk.pack(&mut sk_bytes)?;
///
Expand Down Expand Up @@ -223,25 +248,23 @@ impl PrivateKey {
Ok(())
}

/// Unpacks a buffer of bytes into a private key
/// Unpacks a buffer of bytes into a [`PrivateKey`]
///
/// # Inputs
/// - `bytes`: Buffer for the private key to be extracted from
///
/// # Outputs
/// - `PrivateKey` object
/// - [`PrivateKey`] object
///
/// # Errors
/// Will return a `PackingError` if the buffer is of the wrong length
/// Will return a [`PackingError`] if the buffer is of the wrong length
///
/// # Example
/// ```
/// use enc_rust::kem::*;
/// # use enc_rust::kem::*;
/// # let (pk, new_sk) = generate_key_pair(None, 3).unwrap();
///
/// # let mut sk_bytes = [0u8; 2400];
/// # new_sk.pack(&mut sk_bytes)?;
///
/// let sk = PrivateKey::unpack(&sk_bytes)?;
///
/// # Ok::<(), enc_rust::errors::PackingError>(())
Expand Down Expand Up @@ -270,19 +293,18 @@ impl PrivateKey {
/// Decapsulates a ciphertext (given as a byte slice) into the shared secret
///
/// # Inputs
/// - `ciphertext`: Byte slice containing the ciphertext to be decasulated
/// - `ciphertext`: Byte slice containing the ciphertext to be decapsulated
///
/// # Outputs
/// - `[u8; 32]`: The shared secret, a 32 byte array
///
/// # Errors
/// Will return an `EncryptionDecryptionError` if:
/// Will return an [`EncryptionDecryptionError`] if:
/// - Given invalid ciphertext length
///
/// # Example
/// ```
/// use enc_rust::kem::*;
///
/// # use enc_rust::kem::*;
/// # let (pk, sk) = generate_key_pair(None, 3).unwrap();
/// # let (ciphertext_obj, secret) = pk.encapsulate(None, None).unwrap();
/// # let ciphertext = ciphertext_obj.as_bytes();
Expand Down Expand Up @@ -330,23 +352,25 @@ impl PublicKey {
self.pk.sec_level()
}

/// Packs public key into a given buffer
/// Packs [`PublicKey`] into a given buffer
///
/// # Inputs
/// - `bytes`: Buffer for the public key to be packed into
/// For corresponding security levels, `bytes` should be of length:
/// - 512: 800
/// - 768: 1184
/// - 1024: 1568
/// - `bytes`: Buffer for the public key to be packed into. For corresponding
/// security levels, `bytes` should be of length:
///
/// | Security Level | Length |
/// |----------------|--------|
/// | 512 | 800 |
/// | 768 | 1184 |
/// | 1024 | 1568 |
///
/// # Errors
/// Will return a `PackingError` if the buffer is of the wrong length
/// Will return a [`PackingError`] if the buffer is of the wrong length
///
/// # Example
/// ```
/// use enc_rust::kem::*;
/// # use enc_rust::kem::*;
/// # let (pk, sk) = generate_key_pair(None, 3).unwrap();
///
/// let mut pk_bytes = [0u8; 1184];
/// pk.pack(&mut pk_bytes)?;
///
Expand All @@ -366,25 +390,23 @@ impl PublicKey {
Ok(())
}

/// Unpacks a buffer of bytes into a public key
/// Unpacks a buffer of bytes into a [`PublicKey`]
///
/// # Inputs
/// - `bytes`: Buffer for the public key to be extracted from
///
/// # Outputs
/// - `PublicKey` object
/// - [`PublicKey`] object
///
/// # Errors
/// Will return a `PackingError` if the buffer is of the wrong length
/// Will return a [`PackingError`] if the buffer is of the wrong length
///
/// # Example
/// ```
/// use enc_rust::kem::*;
/// # use enc_rust::kem::*;
/// # let (new_pk, sk) = generate_key_pair(None, 3).unwrap();
///
/// # let mut pk_bytes = [0u8; 1184];
/// # new_pk.pack(&mut pk_bytes)?;
///
/// let pk = PublicKey::unpack(&pk_bytes)?;
///
/// # Ok::<(), enc_rust::errors::PackingError>(())
Expand All @@ -400,22 +422,25 @@ impl PublicKey {
///
/// # Inputs
/// - `seed`: (Optional) a 64 byte slice used as a seed for randomness
/// - `rng`: (Optional) RNG to be used when generating the keypair. Must satisfy the `RngCore` and
/// `CryptoRng` traits. If RNG is not present, then `ChaCha20` will be used.
/// - `rng`: (Optional) RNG to be used during encapsulation. Must satisfy the
/// [`RngCore`](https://docs.rs/rand_core/latest/rand_core/trait.RngCore.html) and
/// [`CryptoRng`](https://docs.rs/rand_core/latest/rand_core/trait.CryptoRng.html) traits.
/// If RNG is not present, then
/// [`ChaCha20`](https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha20Rng.html)
/// will be used.
///
/// # Outputs
/// - `Ciphertext` object
/// - [`Ciphertext`] object
/// - `[u8; 32]`: The shared secret, a 32 byte array
///
/// # Errors
/// Will return an `EncryptionDecryptionError` if:
/// Will return an [`EncryptionDecryptionError`] if:
/// - Given invalid seed length
/// - RNG fails
///
/// # Example
/// ```
/// use enc_rust::kem::*;
///
/// # use enc_rust::kem::*;
/// # let (pk, sk) = generate_key_pair(None, 3).unwrap();
/// let (ciphertext_obj, shared_secret) = pk.encapsulate(None, None)?;
///
Expand Down
Loading

0 comments on commit 9b57bba

Please sign in to comment.