From 428880ab7b9108e312743817ffdaa87597b00c7c Mon Sep 17 00:00:00 2001 From: dr Date: Fri, 28 Jun 2024 17:46:47 -0700 Subject: [PATCH 1/4] fix: refactor fallible functions --- README.md | 152 +++++++++------ benches/benchmark_sha3.rs | 2 +- src/aes/encryptable.rs | 28 +-- src/ecc/encryptable.rs | 17 +- src/ecc/keypair.rs | 2 +- src/ecc/signable.rs | 8 +- src/kem/encryptable.rs | 16 +- src/lib.rs | 16 +- src/main.rs | 7 +- src/sha3/constants.rs | 49 ++--- src/sha3/encryptable.rs | 16 +- src/sha3/hashable.rs | 4 +- src/sha3/shake_functions.rs | 103 +++------- src/sha3/sponge.rs | 22 +-- tests/integration_tests.rs | 373 +++++++++++++++++++++--------------- 15 files changed, 404 insertions(+), 411 deletions(-) diff --git a/README.md b/README.md index feb9ef2..33b1d28 100644 --- a/README.md +++ b/README.md @@ -8,26 +8,34 @@ [![Crates.io](https://img.shields.io/crates/v/capycrypt?style=flat-square)](https://crates.io/crates/capycrypt) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/drcapybara/capyCRYPT/blob/master/LICENSE.txt) -A complete Rust cryptosystem implementing [NIST FIPS 202](https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf) & [NIST FIPS 197](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf) paired to the ed448 Golidlocks curve. +A complete Rust cryptosystem implementing: -## Security -This library is built with love as an academic excercise in cryptographic algorithm design. Despite how awesome and cool it is, it probably shouldn't be used for anything serious. If you find ways to make it even better, open an issue or PR and we'll gladly engage. +- AES: [NIST FIPS 197](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf) +- SHA3: [NIST FIPS 202](https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf) +- ML-KEM: [NIST FIPS 203](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf) +- E448: [Ed448-Goldilocks Curve](https://eprint.iacr.org/2015/625.pdf) + +These primitives form the basis of a platform supporting a wide variety of cryptographic operations, which are detailed below. +## Security +This library is built with love as an academic excercise in cryptographic algorithm design. Despite how awesome and cool it is, it probably shouldn't be used for anything serious right now. If you find ways to make it even better, open an issue or PR and we'll gladly engage. ## Features -- **AES:** NIST-Compliant Advanced Encryption Standard (AES) implementation for encrypting and decrypting data. +- **AES:** NIST-Compliant **Advanced Encryption Standard** (AES) implementation for encrypting and decrypting data. -- **Edwards Elliptic Curve:** High-performance, side-channel resistant instance of the [Ed448-Goldilocks](https://crates.io/crates/tiny_ed448_goldilocks) curve for asymmetric operations. +- **Edwards Elliptic Curve:** High-performance, side-channel resistant instance of the **Ed448-Goldilocks** curve for asymmetric operations. -- **SHA-3:** NIST-Compliant Secure Hash Algorithm 3 (SHA-3) implementation for generating cryptographic hash values, symmetric keystreams, and PRNGs. +- **SHA-3:** NIST-Compliant **Secure Hash Algorithm 3** (SHA-3) implementation for generating cryptographic hash values, symmetric keystreams, and PRNGs. +- **ML-KEM 768:** NIST Initial Public Draft (IPD)-Compliant **Module Ring-Learning With Errors Key Encapsulation Mechanism** (ML-KEM) for quantum-safe asymmetric key and message exchange. ## Supported Operations - **Message Digest:** Computes hash of a given message, with adjustable digest lengths. - **MACs:** Computes message authentication code of a given message, with adjustable bit security. - **Shared Secret Key:** Symmetric message encryption and decryption. - **Public Key Cryptography:** Asymmetric message encryption under public key, decryption with secret key. -- **Zero-Knowledge:** Prove knowledge of secret information with Schnorr/ECDHIES signatures. +- **Signatures** Prove and verify knowledge of secret information with Schnorr/ECDHIES signatures. +- **Quantum-Safe Message Exchange:** ML-KEM + SHA3 sponge for quantum-safe symmetric messaging and key exchange. ## Installation Add the following line to your `Cargo.toml` file: @@ -36,85 +44,110 @@ cargo add capycrypt ``` ## Quick Start -### Compute Digest: -```rust -use capycrypt::{Hashable, Message}; -// Hash the empty string -let mut data = Message::new(vec![]); -// Obtained from echo -n "" | openssl dgst -sha3-256 -let expected = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; -// Compute a SHA3 digest with 128 bits of security -data.compute_sha3_hash(256); -assert!(hex::encode(data.digest.unwrap().to_vec()) == expected); -``` - -### Symmetric Encrypt/Decrypt: +### Quantum-Secure Encrypt/Decrypt: ```rust use capycrypt::{ - Message, - AESEncryptable, - SpongeEncryptable, - sha3::{aux_functions::byte_utils::get_random_bytes} + kem::{encryptable::KEMEncryptable, keypair::kem_keygen}, + sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, }; -// Get a random 128-bit password -let key = get_random_bytes(16); + // Get 5mb random data let mut msg = Message::new(get_random_bytes(5242880)); -// Encrypt the data -msg.aes_encrypt_cbc(&key); -// Decrypt the data -msg.aes_decrypt_cbc(&key); -// Encrypt the data -msg.sha3_encrypt(&pw, 512); -// Decrypt the data -msg.sha3_decrypt(&pw); -// Verify operation success -assert!(msg.op_result.unwrap()); +// Create a new ML-KEM public/private keypair +let (kem_pub_key, kem_priv_key) = kem_keygen(); +// Encrypt the message +assert!(msg.kem_encrypt(&kem_pub_key, &SecParam::D256).is_ok()); +// Decrypt the message +assert!(msg.kem_decrypt(&kem_priv_key).is_ok()); +// Verify +assert!(msg.op_result.is_ok()); ``` -### Asymmetric Encrypt/Decrypt: +### Elliptic-Curve Encrypt/Decrypt: ```rust use capycrypt::{ - KeyEncryptable, - KeyPair, - Message, - sha3::aux_functions::byte_utils::get_random_bytes + ecc::{encryptable::KeyEncryptable, keypair::KeyPair}, + sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, }; // Get 5mb random data let mut msg = Message::new(get_random_bytes(5242880)); -// Create a new private/public keypair -let key_pair = KeyPair::new(&get_random_bytes(32), "test key".to_string(), 512); +// Create a new elliptic-curve public/private keypair +let key_pair = KeyPair::new( + &get_random_bytes(64), // random password for key + "test key".to_string(), // label + &SecParam::D256, // bit-security for key +) +.unwrap(); // Encrypt the message -msg.key_encrypt(&key_pair.pub_key, 512); +assert!(msg.key_encrypt(&key_pair.pub_key, &SecParam::D256).is_ok()); // Decrypt the message -msg.key_decrypt(&key_pair.priv_key); +assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); // Verify -assert!(msg.op_result.unwrap()); +assert!(msg.op_result.is_ok()); +``` + +### Symmetric Encrypt/Decrypt: +```rust +use capycrypt::{ + aes::encryptable::AesEncryptable, + sha3::{aux_functions::byte_utils::get_random_bytes, + encryptable::SpongeEncryptable}, + Message, SecParam, +}; +// Get a random 128-bit password +let pw = get_random_bytes(16); +// Get 5mb random data +let mut msg = Message::new(get_random_bytes(5242880)); +// Encrypt the data +assert!(msg.aes_encrypt_cbc(&pw).is_ok()); +// Decrypt the data +assert!(msg.aes_decrypt_cbc(&pw).is_ok()); +// Encrypt the data +assert!(msg.sha3_encrypt(&pw, &SecParam::D512).is_ok()); +// Decrypt the data +assert!(msg.sha3_decrypt(&pw).is_ok()); +// Verify operation success +assert!(msg.op_result.is_ok()); ``` ### Schnorr Signatures: ```rust use capycrypt::{ - Signable, - KeyPair, - Message, + ecc::{keypair::KeyPair, signable::Signable}, sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, }; // Get random 5mb let mut msg = Message::new(get_random_bytes(5242880)); -// Get a random password -let pw = get_random_bytes(64); -// Generate a signing keypair -let key_pair = KeyPair::new(&pw, "test key".to_string(), 512); +// Create a new elliptic-curve public/private keypair +let key_pair = KeyPair::new( + &get_random_bytes(64), // random password for key + "test key".to_string(), // label + &SecParam::D256, // bit-security for key +) +.unwrap(); // Sign with 256 bits of security -msg.sign(&key_pair, 512); +assert!(msg.sign(&key_pair, &SecParam::D256).is_ok()); // Verify signature -msg.verify(&key_pair.pub_key); -// Assert correctness -assert!(msg.op_result.unwrap()); +assert!(msg.verify(&key_pair.pub_key).is_ok()); +``` + +### Compute Digest: +```rust +use capycrypt::{sha3::hashable::SpongeHashable, Message, SecParam}; + +// Hash the empty string +let mut data = Message::new(vec![]); +// Obtained from echo -n "" | openssl dgst -sha3-256 +let expected = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; +// Compute a SHA3 digest with 128 bits of security +data.compute_sha3_hash(&SecParam::D256).unwrap(); +assert!(hex::encode(data.digest.unwrap()) == expected); ``` ## Performance @@ -122,10 +155,13 @@ This library uses the criterion crate for benches. Running: ```bash cargo bench ``` -conducts benchmarks in order from lowest security to highest. For example, the lowest security configuration available in this library is the pairing of E222 with cSHAKE256, while the highest security offered is E521 paired with cSHAKE512. +conducts benchmarks over parameter sets in order from lowest security to highest. Symmetric operations compare well to openSSL. On an Intelยฎ Coreโ„ข i7-10710U ร— 12, our adaption of in-place keccak from the [XKCP](https://github.com/XKCP/XKCP) achieves a runtime of approximately 20 ms to digest 5mb of random data, vs approximately 17 ms in openSSL. +## (Plausible) Post-Quantum Security +This library pairs ML-KEM under the 768-parameter set to a SHA3-sponge construction for a quantum-safe public-key cryptosystem. It offers theoretic quantum-security through the use of the KEM and sponge primitives, which are both based on problems conjectured to be hard to solve for a quantum adversary. Our construction is non-standard, has not been evaluated by experts, and is unaudited. Our MLKEM library itself is a work in progress and only supports the NIST-II security parameter of 768. Furthermore, the current FIPS 203 IPD is, (as the name indicates), a draft, and final details about secure implementation may be subject to change. Our design currently exists in this library purely as an academic curiosity. Use it at your own risk, we provide no guarantee of safety, reliability, or efficiency. + ## Acknowledgements The authors wish to sincerely thank Dr. Paulo Barreto for the general design of this library as well as the curve functionality. We also wish to extend gratitude to the curve-dalek authors [here](https://github.com/crate-crypto/Ed448-Goldilocks) and [here](https://docs.rs/curve25519-dalek/4.1.1/curve25519_dalek/) for the excellent reference implementations and exemplary instances of rock-solid cryptography. diff --git a/benches/benchmark_sha3.rs b/benches/benchmark_sha3.rs index 0f2dc9d..529ef21 100644 --- a/benches/benchmark_sha3.rs +++ b/benches/benchmark_sha3.rs @@ -1,4 +1,4 @@ -use capycrypt::sha3::hashable::Hashable; +use capycrypt::sha3::hashable::SpongeHashable; use capycrypt::{Message, SecParam}; use capycrypt::sha3::aux_functions::byte_utils::get_random_bytes; diff --git a/src/aes/encryptable.rs b/src/aes/encryptable.rs index d9899f5..bf51330 100644 --- a/src/aes/encryptable.rs +++ b/src/aes/encryptable.rs @@ -35,7 +35,7 @@ impl AesEncryptable for Message { let iv = get_random_bytes(16); let mut ke_ka = iv.clone(); ke_ka.append(&mut key.to_owned()); - let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256)?; + let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256); let ke = &ke_ka[..key.len()].to_vec(); // Encryption Key let ka = &ke_ka[key.len()..].to_vec(); // Authentication Key @@ -81,7 +81,7 @@ impl AesEncryptable for Message { let iv = self.sym_nonce.clone().unwrap(); let mut ke_ka = iv.clone(); ke_ka.append(&mut key.to_owned()); - let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256)?; + let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256); let ke = &ke_ka[..key.len()].to_vec(); // Encryption Key let ka = &ke_ka[key.len()..].to_vec(); // Authentication Key @@ -107,12 +107,7 @@ impl AesEncryptable for Message { remove_pcks7_padding(&mut self.msg); - let ver = kmac_xof(ka, &self.msg, 512, "AES", &SecParam::D256)?; - self.op_result = match self.digest.as_mut() { - Ok(digest) if ver == *digest => Ok(()), - Ok(_) => Err(OperationError::OperationResultNotSet), - Err(_) => Err(OperationError::SignatureVerificationFailure), - }; + kmac_xof(ka, &self.msg, 512, "AES", &SecParam::D256); Ok(()) } @@ -143,12 +138,12 @@ impl AesEncryptable for Message { let mut ke_ka = iv.clone(); ke_ka.extend_from_slice(&counter_bytes); ke_ka.extend_from_slice(key); - let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256)?; + let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256); let (ke, ka) = ke_ka.split_at(key.len()); self.sym_nonce = Some(iv.clone()); - self.digest = Ok(kmac_xof(ka, &self.msg, 512, "AES", &SecParam::D256)?); + self.digest = kmac_xof(ka, &self.msg, 512, "AES", &SecParam::D256); let key_schedule = AES::new(ke); @@ -197,7 +192,7 @@ impl AesEncryptable for Message { let mut ke_ka = iv.clone(); ke_ka.extend_from_slice(&counter_bytes); ke_ka.extend_from_slice(key); - let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256)?; + let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256); let (ke, ka) = ke_ka.split_at(key.len()); @@ -217,16 +212,7 @@ impl AesEncryptable for Message { xor_blocks(block, &temp); }); - let ver = kmac_xof(ka, &self.msg, 512, "AES", &SecParam::D256)?; - self.op_result = if let Ok(digest) = self.digest.as_ref() { - if digest == &ver { - Ok(()) - } else { - Err(OperationError::AESCTRDecryptionFailure) - } - } else { - Err(OperationError::DigestNotSet) - }; + kmac_xof(ka, &self.msg, 512, "AES", &SecParam::D256); Ok(()) } } diff --git a/src/ecc/encryptable.rs b/src/ecc/encryptable.rs index fe08854..de4544f 100644 --- a/src/ecc/encryptable.rs +++ b/src/ecc/encryptable.rs @@ -37,16 +37,13 @@ impl KeyEncryptable for Message { let w = (*pub_key * k).to_affine(); let Z = (ExtendedPoint::generator() * k).to_affine(); - let ke_ka = kmac_xof(&w.x.to_bytes(), &[], 448 * 2, "PK", d)?; + let ke_ka = kmac_xof(&w.x.to_bytes(), &[], 448 * 2, "PK", d); let (ke, ka) = ke_ka.split_at(ke_ka.len() / 2); let t = kmac_xof(ka, &self.msg, 448, "PKA", d); let msg_len = self.msg.len(); - xor_bytes( - &mut self.msg, - &kmac_xof(ke, &[], (msg_len * 8) as u64, "PKE", d)?, - ); + xor_bytes(&mut self.msg, &kmac_xof(ke, &[], msg_len * 8, "PKE", d)); self.digest = t; self.asym_nonce = Some(Z.to_extended()); @@ -85,19 +82,19 @@ impl KeyEncryptable for Message { .as_ref() .ok_or(OperationError::SecurityParameterNotSet)?; - let s_bytes = kmac_xof(pw, &[], 448, "SK", d)?; + let s_bytes = kmac_xof(pw, &[], 448, "SK", d); let s = bytes_to_scalar(s_bytes).mul_mod(&Scalar::from(4_u64)); let Z = (Z * s).to_affine(); - let ke_ka = kmac_xof(&Z.x.to_bytes(), &[], 448 * 2, "PK", d)?; + let ke_ka = kmac_xof(&Z.x.to_bytes(), &[], 448 * 2, "PK", d); let (ke, ka) = ke_ka.split_at(ke_ka.len() / 2); - let xor_result = kmac_xof(ke, &[], (self.msg.len() * 8) as u64, "PKE", d)?; + let xor_result = kmac_xof(ke, &[], self.msg.len() * 8, "PKE", d); xor_bytes(&mut self.msg, &xor_result); - let t_p = kmac_xof(ka, &self.msg, 448, "PKA", d)?; + let t_p = kmac_xof(ka, &self.msg, 448, "PKA", d); - self.op_result = if self.digest.as_ref() == Ok(&t_p) { + self.op_result = if self.digest == t_p { Ok(()) } else { // revert back to the encrypted message diff --git a/src/ecc/keypair.rs b/src/ecc/keypair.rs index 1b50732..b5c84e8 100644 --- a/src/ecc/keypair.rs +++ b/src/ecc/keypair.rs @@ -41,7 +41,7 @@ impl KeyPair { /// and the nonce ๐‘ˆ: hash (๐‘š, ๐‘ˆ, ๐‘‰) . #[allow(non_snake_case)] pub fn new(pw: &[u8], owner: String, d: &SecParam) -> Result { - let data = kmac_xof(pw, &[], 448, "SK", d)?; + let data = kmac_xof(pw, &[], 448, "SK", d); let s: Scalar = bytes_to_scalar(data).mul_mod(&Scalar::from(4_u64)); let V = ExtendedPoint::generator() * s; Ok(KeyPair { diff --git a/src/ecc/signable.rs b/src/ecc/signable.rs index 781b468..1092b8c 100644 --- a/src/ecc/signable.rs +++ b/src/ecc/signable.rs @@ -42,17 +42,17 @@ impl Signable for Message { /// * Some(key.priv_key) #[allow(non_snake_case)] fn sign(&mut self, key: &KeyPair, d: &SecParam) -> Result<(), OperationError> { - let s_bytes = kmac_xof(&key.priv_key, &[], 448, "SK", d)?; + let s_bytes = kmac_xof(&key.priv_key, &[], 448, "SK", d); let s = bytes_to_scalar(s_bytes).mul_mod(&Scalar::from(4_u64)); let s_bytes = scalar_to_bytes(&s); - let k_bytes = kmac_xof(&s_bytes, &self.msg, 448, "N", d)?; + let k_bytes = kmac_xof(&s_bytes, &self.msg, 448, "N", d); let k = bytes_to_scalar(k_bytes) * Scalar::from(4_u64); let U = ExtendedPoint::generator() * k; let ux_bytes = U.to_affine().x.to_bytes(); - let h = kmac_xof(&ux_bytes, &self.msg, 448, "T", d)?; + let h = kmac_xof(&ux_bytes, &self.msg, 448, "T", d); let h_big = bytes_to_scalar(h.clone()); let z = k - h_big.mul_mod(&s); @@ -84,7 +84,7 @@ impl Signable for Message { let h_scalar = bytes_to_scalar(sig.h.clone()); let U = ExtendedPoint::generator() * sig.z + (*pub_key * h_scalar); - let h_p = kmac_xof(&U.to_affine().x.to_bytes(), &self.msg, 448, "T", d)?; + let h_p = kmac_xof(&U.to_affine().x.to_bytes(), &self.msg, 448, "T", d); self.op_result = if h_p == sig.h { Ok(()) diff --git a/src/kem/encryptable.rs b/src/kem/encryptable.rs index 311c0da..f3e1c2f 100644 --- a/src/kem/encryptable.rs +++ b/src/kem/encryptable.rs @@ -35,12 +35,12 @@ impl KEMEncryptable for Message { let mut ke_ka = z.clone(); ke_ka.extend_from_slice(&secret); - let ke_ka = kmac_xof(&ke_ka, &[], 1024, "S", d)?; + let ke_ka = kmac_xof(&ke_ka, &[], 1024, "S", d); let (ke, ka) = ke_ka.split_at(64); self.digest = kmac_xof(ka, &self.msg, 512, "KEMKA", d); - let m = kmac_xof(ke, &[], (self.msg.len() * 8) as u64, "KEMKE", d)?; + let m = kmac_xof(ke, &[], self.msg.len() * 8, "KEMKE", d); xor_bytes(&mut self.msg, &m); self.sym_nonce = Some(z); @@ -67,19 +67,15 @@ impl KEMEncryptable for Message { .clone(); z_pw.extend_from_slice(&dec); - let ke_ka = kmac_xof(&z_pw, &[], 1024, "S", d)?; + let ke_ka = kmac_xof(&z_pw, &[], 1024, "S", d); let (ke, ka) = ke_ka.split_at(64); - let m = kmac_xof(ke, &[], (self.msg.len() * 8) as u64, "KEMKE", d)?; + let m = kmac_xof(ke, &[], self.msg.len() * 8, "KEMKE", d); xor_bytes(&mut self.msg, &m); - let new_t = kmac_xof(ka, &self.msg, 512, "KEMKA", d)?; + let new_t = kmac_xof(ka, &self.msg, 512, "KEMKA", d); - self.op_result = if self - .digest - .as_ref() - .map_or(false, |digest| digest == &new_t) - { + self.op_result = if self.digest == new_t { Ok(()) } else { xor_bytes(&mut self.msg, &m); diff --git a/src/lib.rs b/src/lib.rs index 820971c..9317cab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,7 +72,7 @@ pub struct Message { /// Nonce used in asymmetric encryption pub asym_nonce: Option, /// Hash value (also known as message digest) - pub digest: Result, OperationError>, + pub digest: Vec, /// Result of the cryptographic trait pub op_result: Result<(), OperationError>, /// Schnorr signatures on the input message @@ -89,7 +89,7 @@ impl Message { d: None, sym_nonce: None, asym_nonce: None, - digest: Ok(vec![]), + digest: vec![], op_result: Ok(()), sig: None, kem_ciphertext: Some(vec![]), @@ -145,10 +145,14 @@ impl SecParam { SecParam::D512 => 136, } } +} - pub fn validate(&self) -> Result<(), OperationError> { - match self { - SecParam::D224 | SecParam::D256 | SecParam::D384 | SecParam::D512 => Ok(()), - } +pub trait BitLength { + fn bit_length(&self) -> u64; +} + +impl BitLength for SecParam { + fn bit_length(&self) -> u64 { + *self as u64 } } diff --git a/src/main.rs b/src/main.rs index 0b82ccb..1e53c24 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use capycrypt::{ecc::keypair::KeyPair, sha3::hashable::Hashable, Message, SecParam}; +use capycrypt::{ecc::keypair::KeyPair, sha3::hashable::SpongeHashable, Message, SecParam}; use structopt::StructOpt; #[derive(Debug, StructOpt)] @@ -50,10 +50,7 @@ fn main() { data.compute_sha3_hash(&sec_param) .expect("An error occurred during hash computation."); - match data.digest { - Ok(digest) => println!("Hash: {}", hex::encode(digest)), - Err(_) => eprintln!("Error: Hash computation failed"), - } + println!("Hash: {}", hex::encode(data.digest)) } Command::NewKeypair { diff --git a/src/sha3/constants.rs b/src/sha3/constants.rs index 6c6f16e..9b51c9d 100644 --- a/src/sha3/constants.rs +++ b/src/sha3/constants.rs @@ -1,4 +1,4 @@ -use crate::{OperationError, SecParam}; +use crate::SecParam; pub const RATE_IN_BYTES: usize = 136; // SHA3-256 r = 1088 / 8 = 136 @@ -35,7 +35,7 @@ pub(crate) enum Capacity { impl Capacity { /// This function effectively maps a given bit length to the appropriate capacity value enum variant, - pub(crate) fn from_bit_length(bit_length: u64) -> Self { + pub(crate) fn from_bit_length(bit_length: usize) -> Self { match bit_length * 2 { x if x <= 448 => Capacity::C448, x if x <= 512 => Capacity::C512, @@ -45,31 +45,16 @@ impl Capacity { } } -/// OutputLength struct for storing the output length. -pub struct OutputLength { - value: u64, -} - -impl OutputLength { - const MAX_VALUE: u64 = u64::MAX; - - pub fn try_from(value: u64) -> Result { - if value < Self::MAX_VALUE { - Ok(OutputLength { value }) - } else { - Err(OperationError::UnsupportedSecurityParameter) - } - } - - pub fn value(&self) -> u64 { - self.value +impl BitLength for Capacity { + fn bit_length(&self) -> usize { + *self as usize } } /// Rate struct for storing the rate value. /// Rate is the number of input bits processed per invocation of the underlying function in sponge construction. pub struct Rate { - value: u64, + value: usize, } impl Rate { @@ -80,35 +65,23 @@ impl Rate { } } - pub fn value(&self) -> u64 { + pub fn value(&self) -> usize { self.value } } pub trait BitLength { - fn bit_length(&self) -> u64; -} - -impl BitLength for Capacity { - fn bit_length(&self) -> u64 { - *self as u64 - } + fn bit_length(&self) -> usize; } impl BitLength for SecParam { - fn bit_length(&self) -> u64 { - *self as u64 + fn bit_length(&self) -> usize { + *self as usize } } impl BitLength for Rate { - fn bit_length(&self) -> u64 { + fn bit_length(&self) -> usize { self.value } } - -impl BitLength for OutputLength { - fn bit_length(&self) -> u64 { - self.value() - } -} diff --git a/src/sha3/encryptable.rs b/src/sha3/encryptable.rs index 1005827..688d0d6 100644 --- a/src/sha3/encryptable.rs +++ b/src/sha3/encryptable.rs @@ -33,12 +33,12 @@ impl SpongeEncryptable for Message { let mut ke_ka = z.clone(); ke_ka.extend_from_slice(pw); - let ke_ka = kmac_xof(&ke_ka, &[], 1024, "S", d)?; + let ke_ka = kmac_xof(&ke_ka, &[], 1024, "S", d); let (ke, ka) = ke_ka.split_at(64); self.digest = kmac_xof(ka, &self.msg, 512, "SKA", d); - let m = kmac_xof(ke, &[], (self.msg.len() * 8) as u64, "SKE", d)?; + let m = kmac_xof(ke, &[], self.msg.len() * 8, "SKE", d); xor_bytes(&mut self.msg, &m); self.sym_nonce = Some(z); @@ -73,20 +73,16 @@ impl SpongeEncryptable for Message { .clone(); z_pw.extend_from_slice(pw); - let ke_ka = kmac_xof(&z_pw, &[], 1024, "S", d)?; + let ke_ka = kmac_xof(&z_pw, &[], 1024, "S", d); let (ke, ka) = ke_ka.split_at(64); - let m = kmac_xof(ke, &[], (self.msg.len() * 8) as u64, "SKE", d)?; + let m = kmac_xof(ke, &[], self.msg.len() * 8, "SKE", d); xor_bytes(&mut self.msg, &m); - let new_t = kmac_xof(ka, &self.msg, 512, "SKA", d)?; + let new_t = kmac_xof(ka, &self.msg, 512, "SKA", d); - self.op_result = if self - .digest - .as_ref() - .map_or(false, |digest| digest == &new_t) - { + self.op_result = if self.digest == new_t { Ok(()) } else { xor_bytes(&mut self.msg, &m); diff --git a/src/sha3/hashable.rs b/src/sha3/hashable.rs index 9454043..5967989 100644 --- a/src/sha3/hashable.rs +++ b/src/sha3/hashable.rs @@ -5,12 +5,12 @@ use super::{ shake_functions::{kmac_xof, shake}, }; -pub trait Hashable { +pub trait SpongeHashable { fn compute_sha3_hash(&mut self, d: &SecParam) -> Result<(), OperationError>; fn compute_tagged_hash(&mut self, pw: &[u8], s: &str, d: &SecParam); } -impl Hashable for Message { +impl SpongeHashable for Message { /// # Message Digest /// Computes SHA3-d hash of input. Does not consume input. /// Replaces `Message.digest` with result of operation. diff --git a/src/sha3/shake_functions.rs b/src/sha3/shake_functions.rs index 1f3437c..82153e7 100644 --- a/src/sha3/shake_functions.rs +++ b/src/sha3/shake_functions.rs @@ -10,10 +10,10 @@ use crate::{ aux_functions::nist_800_185::{byte_pad, encode_string, right_encode}, sponge::{sponge_absorb, sponge_squeeze}, }, - OperationError, SecParam, + SecParam, }; -use super::constants::{BitLength, Capacity, OutputLength, Rate, RATE_IN_BYTES}; +use super::constants::{BitLength, Capacity, Rate, RATE_IN_BYTES}; /// # SHA3-Keccak /// ref NIST FIPS 202. @@ -22,14 +22,14 @@ use super::constants::{BitLength, Capacity, OutputLength, Rate, RATE_IN_BYTES}; /// * `d: usize`: requested output length and security strength /// ## Returns: /// * `return -> Vec`: SHA3-d message digest -pub(crate) fn shake(n: &mut Vec, d: &dyn BitLength) -> Result, OperationError> { +pub(crate) fn shake(n: &mut Vec, d: &impl BitLength) -> Vec { let bytes_to_pad = RATE_IN_BYTES - n.len() % RATE_IN_BYTES; match bytes_to_pad { 1 => n.extend_from_slice(&[0x86]), // delim suffix _ => n.extend_from_slice(&[0x06]), // delim suffix } let c = Capacity::from_bit_length(d.bit_length()); - Ok(sponge_squeeze(&mut sponge_absorb(n, &c), d, Rate::from(&c))) + sponge_squeeze(&mut sponge_absorb(n, &c), d.bit_length(), Rate::from(d)) } /// # Customizable SHAKE @@ -47,15 +47,7 @@ pub(crate) fn shake(n: &mut Vec, d: &dyn BitLength) -> Result, Opera /// length output and there is no possible way to know this value in advance. /// The only constraint on `l` from NIST is that it is a value less than /// the absurdly large 2^{2040}. -pub(crate) fn cshake( - x: &[u8], - l: u64, - n: &str, - s: &str, - d: &SecParam, -) -> Result, OperationError> { - d.validate()?; - +pub(crate) fn cshake(x: &[u8], l: usize, n: &str, s: &str, d: SecParam) -> Vec { let mut encoded_n = encode_string(n.as_bytes()); encoded_n.extend_from_slice(&encode_string(s.as_bytes())); @@ -65,17 +57,11 @@ pub(crate) fn cshake( out.extend_from_slice(x); out.push(0x04); - let length = OutputLength::try_from(l)?; - if n.is_empty() && s.is_empty() { - shake(&mut out, &length)?; + shake(&mut out, &d); } - Ok(sponge_squeeze( - &mut sponge_absorb(&mut out, d), - &length, - Rate::from(d), - )) + sponge_squeeze(&mut sponge_absorb(&mut out, &d), l, Rate::from(&d)) } /// # Keyed Message Authtentication @@ -91,13 +77,7 @@ pub(crate) fn cshake( /// /// ## Returns: /// * `return -> Vec`: kmac_xof of `x` under `k` -pub fn kmac_xof( - k: &[u8], - x: &[u8], - l: u64, - s: &str, - d: &SecParam, -) -> Result, OperationError> { +pub fn kmac_xof(k: &[u8], x: &[u8], l: usize, s: &str, d: &SecParam) -> Vec { let mut encode_k = encode_string(k); let bytepad_w = d.bytepad_value(); let mut bp = byte_pad(&mut encode_k, bytepad_w); @@ -106,13 +86,13 @@ pub fn kmac_xof( bp.extend_from_slice(x); bp.extend_from_slice(&right_encode(0)); // SP 800-185 4.3.1 KMAC with Arbitrary-Length Output - cshake(&bp, l, "KMAC", s, d) + cshake(&bp, l, "KMAC", s, *d) } /// TESTS #[cfg(test)] mod shake_tests { - use crate::{sha3::hashable::Hashable, Message, SecParam}; + use crate::{sha3::hashable::SpongeHashable, Message, SecParam}; #[test] fn test_shake_224() { @@ -121,12 +101,9 @@ mod shake_tests { 0x6b, 0x4e, 0x03, 0x42, 0x36, 0x67, 0xdb, 0xb7, 0x3b, 0x6e, 0x15, 0x45, 0x4f, 0x0e, 0xb1, 0xab, 0xd4, 0x59, 0x7f, 0x9a, 0x1b, 0x07, 0x8e, 0x3f, 0x5b, 0x5a, 0x6b, 0xc7, ]; + assert!(data.compute_sha3_hash(&SecParam::D224).is_ok()); - assert!(data - .digest - .as_ref() - .map(|digest| *digest == expected.to_vec()) - .unwrap_or(false)); + assert!(data.digest == expected.to_vec()); let mut data = Message::new("test".as_bytes().to_vec()); let expected: [u8; 28] = [ @@ -134,11 +111,7 @@ mod shake_tests { 0x55, 0x27, 0x46, 0x87, 0x65, 0x17, 0xa7, 0xf9, 0xb7, 0xce, 0x2d, 0xb0, 0xae, 0x7b, ]; assert!(data.compute_sha3_hash(&SecParam::D224).is_ok()); - assert!(data - .digest - .as_ref() - .map(|digest| *digest == expected.to_vec()) - .unwrap_or(false)); + assert!(data.digest == expected.to_vec()); } #[test] @@ -150,11 +123,7 @@ mod shake_tests { 0x80, 0xf8, 0x43, 0x4a, ]; assert!(data.compute_sha3_hash(&SecParam::D256).is_ok()); - assert!(data - .digest - .as_ref() - .map(|digest| *digest == expected.to_vec()) - .unwrap_or(false)); + assert!(data.digest == expected.to_vec()); let mut data = Message::new("test".as_bytes().to_vec()); let expected: [u8; 32] = [ @@ -163,11 +132,7 @@ mod shake_tests { 0xe2, 0xf5, 0xab, 0x80, ]; assert!(data.compute_sha3_hash(&SecParam::D256).is_ok()); - assert!(data - .digest - .as_ref() - .map(|digest| *digest == expected.to_vec()) - .unwrap_or(false)); + assert!(data.digest == expected.to_vec()); } #[test] @@ -180,11 +145,7 @@ mod shake_tests { 0xd1, 0xe0, 0x58, 0xd5, 0xf0, 0x04, ]; assert!(data.compute_sha3_hash(&SecParam::D384).is_ok()); - assert!(data - .digest - .as_ref() - .map(|digest| *digest == expected.to_vec()) - .unwrap_or(false)); + assert!(data.digest == expected.to_vec()); let mut data = Message::new("test".as_bytes().to_vec()); let expected: [u8; 48] = [ @@ -194,11 +155,7 @@ mod shake_tests { 0x72, 0x60, 0xd5, 0x86, 0x21, 0xbd, ]; assert!(data.compute_sha3_hash(&SecParam::D384).is_ok()); - assert!(data - .digest - .as_ref() - .map(|digest| *digest == expected.to_vec()) - .unwrap_or(false)); + assert!(data.digest == expected.to_vec()); } #[test] @@ -212,11 +169,7 @@ mod shake_tests { 0xc1, 0xae, 0xc9, 0x67, 0x79, 0x14, 0x9c, 0x14, ]; assert!(data.compute_sha3_hash(&SecParam::D512).is_ok()); - assert!(data - .digest - .as_ref() - .map(|digest| *digest == expected.to_vec()) - .unwrap_or(false)); + assert!(data.digest == expected.to_vec()); } #[test] @@ -231,11 +184,7 @@ mod shake_tests { ]; data.compute_tagged_hash(&pw, &s, &SecParam::D256); - assert!(data - .digest - .as_ref() - .map(|digest| *digest == expected.to_vec()) - .unwrap_or(false)); + assert!(data.digest == expected.to_vec()); } #[test] @@ -251,11 +200,7 @@ mod shake_tests { ]; data.compute_tagged_hash(&pw, "", &SecParam::D512); - assert!(data - .digest - .as_ref() - .map(|digest| *digest == expected.to_vec()) - .unwrap_or(false)); + assert!(data.digest == expected.to_vec()); } } @@ -272,7 +217,7 @@ mod cshake_tests { let n = ""; let s = "Email Signature"; - let res = cshake(&data, 256, n, s, &SecParam::D256).unwrap(); + let res = cshake(&data, 256, n, s, SecParam::D256); let expected: [u8; 32] = [ 0xc5, 0x22, 0x1d, 0x50, 0xe4, 0xf8, 0x22, 0xd9, 0x6a, 0x2e, 0x88, 0x81, 0xa9, 0x61, 0x42, 0x0f, 0x29, 0x4b, 0x7b, 0x24, 0xfe, 0x3d, 0x20, 0x94, 0xba, 0xed, 0x2c, 0x65, @@ -286,7 +231,7 @@ mod cshake_tests { let data = NIST_DATA_SPONGE_INIT; let n = ""; let s = "Email Signature"; - let res = cshake(&data, 512, n, s, &SecParam::D512).unwrap(); + let res = cshake(&data, 512, n, s, SecParam::D512); let expected: [u8; 64] = [ 0x07, 0xdc, 0x27, 0xb1, 0x1e, 0x51, 0xfb, 0xac, 0x75, 0xbc, 0x7b, 0x3c, 0x1d, 0x98, 0x3e, 0x8b, 0x4b, 0x85, 0xfb, 0x1d, 0xef, 0xaf, 0x21, 0x89, 0x12, 0xac, 0x86, 0x43, @@ -314,7 +259,7 @@ mod kmac_tests { let s_str = "My Tagged Application"; let key_bytes = key_str; let data = hex::decode("00010203").unwrap(); - let res = kmac_xof(key_bytes.as_ref(), &data, 64, s_str, &SecParam::D512).unwrap(); + let res = kmac_xof(key_bytes.as_ref(), &data, 64, s_str, &SecParam::D512); let expected = "1755133f1534752a"; assert_eq!(hex::encode(res), expected) } @@ -330,7 +275,7 @@ mod kmac_tests { let key_bytes = key_str; let data = NIST_DATA_SPONGE_INIT; - let res = kmac_xof(key_bytes.as_ref(), &data, 512, s_str, &SecParam::D512).unwrap(); + let res = kmac_xof(key_bytes.as_ref(), &data, 512, s_str, &SecParam::D512); let expected: [u8; 64] = [ 0xd5, 0xbe, 0x73, 0x1c, 0x95, 0x4e, 0xd7, 0x73, 0x28, 0x46, 0xbb, 0x59, 0xdb, 0xe3, 0xa8, 0xe3, 0x0f, 0x83, 0xe7, 0x7a, 0x4b, 0xff, 0x44, 0x59, 0xf2, 0xf1, 0xc2, 0xb4, diff --git a/src/sha3/sponge.rs b/src/sha3/sponge.rs index dc38a95..f7d0b41 100644 --- a/src/sha3/sponge.rs +++ b/src/sha3/sponge.rs @@ -8,13 +8,13 @@ use super::constants::{BitLength, Rate}; // * m: message to be absorbed // * capacity: security parameter which determines rate = bit_width - capacity // * return: a state consisting of 25 words of 64 bits each. -pub(crate) fn sponge_absorb(m: &mut Vec, capacity: &S) -> [u64; 25] { +pub(crate) fn sponge_absorb(m: &mut Vec, capacity: &impl BitLength) -> [u64; 25] { let c = capacity.bit_length(); - let r: u64 = (1600 - c) / 8; - if (m.len() % r as usize) != 0 { - pad_ten_one(m, r as usize); + let r = (1600 - c) / 8; + if (m.len() % r) != 0 { + pad_ten_one(m, r); } - bytes_to_state(m, r as usize) + bytes_to_state(m, r) } // Finalizes a state. @@ -23,18 +23,14 @@ pub(crate) fn sponge_absorb(m: &mut Vec, capacity: &S // * bit_length: requested output length in bits // * rate: security parameter // * return: digest of permuted states of length `bit_length`. -pub(crate) fn sponge_squeeze( - s: &mut [u64; 25], - bit_length: &S, - rate: Rate, -) -> Vec { +pub(crate) fn sponge_squeeze(s: &mut [u64; 25], bit_length: usize, rate: Rate) -> Vec { let mut out: Vec = Vec::new(); //FIPS 202 Algorithm 8 Step 8 - let block_size: usize = (rate.value() / 64) as usize; - while out.len() * 8 < bit_length.bit_length() as usize { + let block_size: usize = rate.value() / 64; + while out.len() * 8 < bit_length { out.append(&mut state_to_byte_array(&s[0..block_size])); keccakf_1600(s); //FIPS 202 Algorithm 8 Step 10 } - out.truncate((bit_length.bit_length() / 8) as usize); + out.truncate(bit_length / 8); out } diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 0bdedff..6626e2a 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1,207 +1,274 @@ -#[cfg(test)] -pub mod ops_tests { - use std::time::Instant; - use tempfile::tempdir; +#[test] +fn test_hashable() { + use capycrypt::{sha3::hashable::SpongeHashable, Message, SecParam}; + // Hash the empty string + let mut data = Message::new(vec![]); + // Obtained from echo -n "" | openssl dgst -sha3-256 + let expected = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; + // Compute a SHA3 digest with 128 bits of security + data.compute_sha3_hash(&SecParam::D256).unwrap(); + assert!(hex::encode(data.digest) == expected); +} +#[test] +#[allow(unused_must_use)] +fn test_aes_encryptable() { use capycrypt::{ - ecc::{encryptable::KeyEncryptable, keypair::KeyPair, signable::Signable}, - kem::{encryptable::KEMEncryptable, keypair::kem_keygen}, + aes::encryptable::AesEncryptable, sha3::{aux_functions::byte_utils::get_random_bytes, encryptable::SpongeEncryptable}, Message, SecParam, }; + // Get a random 128-bit password + let pw = get_random_bytes(16); + // Get 5mb random data + let mut msg = Message::new(get_random_bytes(5242880)); + // Encrypt the data + assert!(msg.aes_encrypt_cbc(&pw).is_ok()); + // Decrypt the data + assert!(msg.aes_decrypt_cbc(&pw).is_ok()); + // Encrypt the data + assert!(msg.sha3_encrypt(&pw, &SecParam::D512).is_ok()); + // Decrypt the data + assert!(msg.sha3_decrypt(&pw).is_ok()); + // Verify operation success + assert!(msg.op_result.is_ok()); +} - #[test] - pub fn test_sym_enc_512() { - let pw = get_random_bytes(64); - let mut msg = Message::new(get_random_bytes(5242880)); +#[test] +fn test_key_gen_enc_dec_256() { + use capycrypt::{ + ecc::{encryptable::KeyEncryptable, keypair::KeyPair}, + kem::{encryptable::KEMEncryptable, keypair::kem_keygen}, + sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, + }; - assert!(msg.sha3_encrypt(&pw, &SecParam::D512).is_ok()); - assert!(msg.sha3_decrypt(&pw).is_ok()); + // Get 5mb random data + let mut msg = Message::new(get_random_bytes(5242880)); + // Create a new elliptic-curve public/private keypair + let key_pair = KeyPair::new( + &get_random_bytes(64), + "test key".to_string(), + &SecParam::D256, + ) + .unwrap(); + // Encrypt the message + assert!(msg.key_encrypt(&key_pair.pub_key, &SecParam::D256).is_ok()); + // Decrypt the message + assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); + // Verify + assert!(msg.op_result.is_ok()); + + // Create a new ML-KEM public/private keypair + let (kem_pub_key, kem_priv_key) = kem_keygen(); + // Encrypt the message + assert!(msg.kem_encrypt(&kem_pub_key, &SecParam::D256).is_ok()); + // Decrypt the message + assert!(msg.kem_decrypt(&kem_priv_key).is_ok()); + // Verify + assert!(msg.op_result.is_ok()); +} - assert!(msg.op_result.is_ok()); - } - #[test] - pub fn test_sym_enc_256() { - let pw = get_random_bytes(64); - let mut msg = Message::new(get_random_bytes(5242880)); +#[test] +pub fn test_kem_enc_512() { + use capycrypt::{ + kem::{encryptable::KEMEncryptable, keypair::kem_keygen}, + sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, + }; - assert!(msg.sha3_encrypt(&pw, &SecParam::D256).is_ok()); - assert!(msg.sha3_decrypt(&pw).is_ok()); + let mut msg = Message::new(get_random_bytes(5242880)); - assert!(msg.op_result.is_ok()); - } + let (kem_pub_key, kem_priv_key) = kem_keygen(); - #[test] - pub fn test_kem_enc_256() { - let mut msg = Message::new(get_random_bytes(5242880)); + assert!(msg.kem_encrypt(&kem_pub_key, &SecParam::D512).is_ok()); + assert!(msg.kem_decrypt(&kem_priv_key).is_ok()); + assert!(msg.op_result.is_ok()); +} - let (kem_pub_key, kem_priv_key) = kem_keygen(); +#[test] +fn test_key_gen_enc_dec_512() { + use capycrypt::{ + ecc::{encryptable::KeyEncryptable, keypair::KeyPair}, + sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, + }; - assert!(msg.kem_encrypt(&kem_pub_key, &SecParam::D256).is_ok()); - assert!(msg.kem_decrypt(&kem_priv_key).is_ok()); - assert!(msg.op_result.is_ok()); - } + let mut msg = Message::new(get_random_bytes(5242880)); + let key_pair = KeyPair::new( + &get_random_bytes(32), + "test key".to_string(), + &SecParam::D512, + ) + .unwrap(); - #[test] - pub fn test_kem_enc_512() { - let mut msg = Message::new(get_random_bytes(5242880)); + assert!(msg.key_encrypt(&key_pair.pub_key, &SecParam::D512).is_ok()); + assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); - let (kem_pub_key, kem_priv_key) = kem_keygen(); + assert!(msg.op_result.is_ok()); +} +#[test] +pub fn test_signature_256() { + use capycrypt::{ + ecc::{keypair::KeyPair, signable::Signable}, + sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, + }; + // Get random 5mb + let mut msg = Message::new(get_random_bytes(5242880)); + // Create a new elliptic-curve public/private keypair + let key_pair = KeyPair::new( + &get_random_bytes(64), // random password for key + "test key".to_string(), // label + &SecParam::D256, // bit-security for key + ) + .unwrap(); + // Sign with 256 bits of security + assert!(msg.sign(&key_pair, &SecParam::D256).is_ok()); + // Verify signature + assert!(msg.verify(&key_pair.pub_key).is_ok()); +} - assert!(msg.kem_encrypt(&kem_pub_key, &SecParam::D512).is_ok()); - assert!(msg.kem_decrypt(&kem_priv_key).is_ok()); - assert!(msg.op_result.is_ok()); - } +#[test] +pub fn test_signature_512() { + use capycrypt::{ + ecc::{keypair::KeyPair, signable::Signable}, + sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, + }; - #[test] - fn test_key_gen_enc_dec_256() { - let mut msg = Message::new(get_random_bytes(5242880)); - let key_pair = KeyPair::new( - &get_random_bytes(64), - "test key".to_string(), - &SecParam::D256, - ) - .unwrap(); + let mut msg = Message::new(get_random_bytes(5242880)); + let pw = get_random_bytes(64); + let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512).unwrap(); - assert!(msg.key_encrypt(&key_pair.pub_key, &SecParam::D256).is_ok()); - assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); + assert!(msg.sign(&key_pair, &SecParam::D512).is_ok()); + assert!(msg.verify(&key_pair.pub_key).is_ok()); - assert!(msg.op_result.is_ok()); - } + assert!(msg.op_result.is_ok()); +} - #[test] - fn test_key_gen_enc_dec_512() { - let mut msg = Message::new(get_random_bytes(5242880)); - let key_pair = KeyPair::new( - &get_random_bytes(32), - "test key".to_string(), - &SecParam::D512, - ) - .unwrap(); +// This test shouldnt have a huge variation between key sizes due to the fixed-time +// nature of the lookup table being used for scalar decomposition in the +// variable_base multiplication algorithm. +// ## OBSERVATION: +// key size larger than message has timing variation on larger values of i +#[test] +fn test_sig_timing_side_channel() { + use capycrypt::{ + ecc::{keypair::KeyPair, signable::Signable}, + sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, + }; + use std::time::Instant; - assert!(msg.key_encrypt(&key_pair.pub_key, &SecParam::D512).is_ok()); - assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); + for i in 0..10 { + let mut msg = Message::new(get_random_bytes(5242880)); + let pw = get_random_bytes(1 << i); + let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512).unwrap(); + let now = Instant::now(); + let _ = msg.sign(&key_pair, &SecParam::D512); + println!("{} needed {} microseconds", i, now.elapsed().as_micros()); + let _ = msg.verify(&key_pair.pub_key); assert!(msg.op_result.is_ok()); } - #[test] - pub fn test_signature_256() { - let mut msg = Message::new(get_random_bytes(5242880)); - let pw = get_random_bytes(64); - let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D256).unwrap(); +} - assert!(msg.sign(&key_pair, &SecParam::D256).is_ok()); - assert!(msg.verify(&key_pair.pub_key).is_ok()); +#[test] +fn test_reading_writing_keypair() { + use capycrypt::{ + ecc::keypair::KeyPair, sha3::aux_functions::byte_utils::get_random_bytes, SecParam, + }; - assert!(msg.op_result.is_ok()); - } + use tempfile::tempdir; - #[test] - pub fn test_signature_512() { - let mut msg = Message::new(get_random_bytes(5242880)); - let pw = get_random_bytes(64); - let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512).unwrap(); + let key_pair = KeyPair::new( + &get_random_bytes(32), + "test key".to_string(), + &SecParam::D512, + ) + .expect("Failed to create key pair"); - assert!(msg.sign(&key_pair, &SecParam::D512).is_ok()); - assert!(msg.verify(&key_pair.pub_key).is_ok()); + let temp_dir = tempdir().expect("Failed to create temporary directory"); + let temp_file_path = temp_dir.path().join("read_write_keypair.json"); - assert!(msg.op_result.is_ok()); - } + let _ = key_pair.write_to_file(temp_file_path.to_str().unwrap()); + let read_key_pair = KeyPair::read_from_file(temp_file_path.to_str().unwrap()) + .expect("Failed to read key pair from file"); - // This test shouldnt have a huge variation between key sizes due to the fixed-time - // nature of the lookup table being used for scalar decomposition in the - // variable_base multiplication algorithm. - // ## OBSERVATION: - // key size larger than message has timing variation on larger values of i - #[test] - fn test_sig_timing_side_channel() { - for i in 0..10 { - let mut msg = Message::new(get_random_bytes(5242880)); - let pw = get_random_bytes(1 << i); - let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512).unwrap(); - - let now = Instant::now(); - let _ = msg.sign(&key_pair, &SecParam::D512); - println!("{} needed {} microseconds", i, now.elapsed().as_micros()); - let _ = msg.verify(&key_pair.pub_key); - assert!(msg.op_result.is_ok()); - } - } + assert_eq!(key_pair, read_key_pair); +} - #[test] - fn test_reading_writing_keypair() { - let key_pair = KeyPair::new( - &get_random_bytes(32), - "test key".to_string(), - &SecParam::D512, - ) - .expect("Failed to create key pair"); +#[test] +pub fn test_signature_512_read_keypair_from_file() { + use capycrypt::{ + ecc::{keypair::KeyPair, signable::Signable}, + sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, + }; - let temp_dir = tempdir().expect("Failed to create temporary directory"); - let temp_file_path = temp_dir.path().join("read_write_keypair.json"); + use tempfile::tempdir; - let _ = key_pair.write_to_file(temp_file_path.to_str().unwrap()); - let read_key_pair = KeyPair::read_from_file(temp_file_path.to_str().unwrap()) - .expect("Failed to read key pair from file"); + let mut msg = Message::new(get_random_bytes(5242880)); + let pw = get_random_bytes(64); - assert_eq!(key_pair, read_key_pair); - } + let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512) + .expect("Failed to create key pair"); - #[test] - pub fn test_signature_512_read_keypair_from_file() { - let mut msg = Message::new(get_random_bytes(5242880)); - let pw = get_random_bytes(64); + let temp_dir = tempdir().expect("Failed to create temporary directory"); + let temp_file_path: std::path::PathBuf = temp_dir.path().join("read_write_keypair.json"); - let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512) - .expect("Failed to create key pair"); + let _ = key_pair.write_to_file(temp_file_path.to_str().unwrap()); + let read_key_pair = KeyPair::read_from_file(temp_file_path.to_str().unwrap()) + .expect("Failed to read key pair from file"); - let temp_dir = tempdir().expect("Failed to create temporary directory"); - let temp_file_path: std::path::PathBuf = temp_dir.path().join("read_write_keypair.json"); + assert!(msg.sign(&read_key_pair, &SecParam::D512).is_ok()); + assert!(msg.verify(&read_key_pair.pub_key).is_ok()); + assert!(msg.op_result.is_ok()); +} - let _ = key_pair.write_to_file(temp_file_path.to_str().unwrap()); - let read_key_pair = KeyPair::read_from_file(temp_file_path.to_str().unwrap()) - .expect("Failed to read key pair from file"); +#[test] +pub fn test_signature_512_read_message_from_file() { + use capycrypt::{ + ecc::{keypair::KeyPair, signable::Signable}, + sha3::aux_functions::byte_utils::get_random_bytes, + Message, SecParam, + }; - assert!(msg.sign(&read_key_pair, &SecParam::D512).is_ok()); - assert!(msg.verify(&read_key_pair.pub_key).is_ok()); - assert!(msg.op_result.is_ok()); - } + use tempfile::tempdir; - #[test] - pub fn test_signature_512_read_message_from_file() { - let temp_dir = tempdir().expect("Failed to create temporary directory"); - let temp_file_path: std::path::PathBuf = temp_dir.path().join("temp_message.json"); - Message::new(get_random_bytes(5242880)) - .write_to_file(temp_file_path.to_str().unwrap()) - .unwrap(); + let temp_dir = tempdir().expect("Failed to create temporary directory"); + let temp_file_path: std::path::PathBuf = temp_dir.path().join("temp_message.json"); + Message::new(get_random_bytes(5242880)) + .write_to_file(temp_file_path.to_str().unwrap()) + .unwrap(); - let mut initial_msg = Message::read_from_file(temp_file_path.to_str().unwrap()).unwrap(); + let mut initial_msg = Message::read_from_file(temp_file_path.to_str().unwrap()).unwrap(); - let pw = get_random_bytes(64); - let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512).unwrap(); + let pw = get_random_bytes(64); + let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512).unwrap(); - assert!(initial_msg.sign(&key_pair, &SecParam::D512).is_ok()); + assert!(initial_msg.sign(&key_pair, &SecParam::D512).is_ok()); - initial_msg - .write_to_file(temp_file_path.to_str().unwrap()) - .unwrap(); + initial_msg + .write_to_file(temp_file_path.to_str().unwrap()) + .unwrap(); - let mut signed_msg = Message::read_from_file(temp_file_path.to_str().unwrap()).unwrap(); + let mut signed_msg = Message::read_from_file(temp_file_path.to_str().unwrap()).unwrap(); - assert!(signed_msg.verify(&key_pair.pub_key).is_ok()); + assert!(signed_msg.verify(&key_pair.pub_key).is_ok()); - assert!(signed_msg.op_result.is_ok()); - } + assert!(signed_msg.op_result.is_ok()); } #[cfg(test)] mod decryption_test { - use capycrypt::ecc::encryptable::KeyEncryptable; - use capycrypt::ecc::keypair::KeyPair; - use capycrypt::sha3::aux_functions::byte_utils::get_random_bytes; - use capycrypt::sha3::encryptable::SpongeEncryptable; - use capycrypt::Message; - use capycrypt::SecParam::D512; + use capycrypt::{ + ecc::{encryptable::KeyEncryptable, keypair::KeyPair}, + sha3::{aux_functions::byte_utils::get_random_bytes, encryptable::SpongeEncryptable}, + Message, + SecParam::D512, + }; /// Testing a security parameters whether the failed decryption preserves /// the original encrypted text. If an encrypted text is decrypted with a wrong password, From 6cb34eae84eb9580aeff8222724b938376fcf250 Mon Sep 17 00:00:00 2001 From: dr Date: Fri, 28 Jun 2024 18:51:45 -0700 Subject: [PATCH 2/4] refactor: borrows --- README.md | 25 ++--- benches/benchmark_e448_224.rs | 12 +-- benches/benchmark_e448_512.rs | 12 +-- benches/benchmark_sha3.rs | 2 +- src/aes/encryptable.rs | 16 +-- src/ecc/encryptable.rs | 30 ++---- src/ecc/keypair.rs | 4 +- src/ecc/signable.rs | 27 ++--- src/kem/encryptable.rs | 25 ++--- src/lib.rs | 3 - src/main.rs | 5 +- src/sha3/aux_functions.rs | 4 +- src/sha3/encryptable.rs | 22 ++-- src/sha3/hashable.rs | 13 ++- src/sha3/shake_functions.rs | 34 +++---- src/sha3/sponge.rs | 2 +- tests/aes_tests.rs | 22 ++-- tests/integration_tests.rs | 183 +++++++++++++++------------------- 18 files changed, 180 insertions(+), 261 deletions(-) diff --git a/README.md b/README.md index 33b1d28..8965a7f 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,8 @@ let mut msg = Message::new(get_random_bytes(5242880)); let (kem_pub_key, kem_priv_key) = kem_keygen(); // Encrypt the message assert!(msg.kem_encrypt(&kem_pub_key, &SecParam::D256).is_ok()); -// Decrypt the message +// Decrypt and verify assert!(msg.kem_decrypt(&kem_priv_key).is_ok()); -// Verify -assert!(msg.op_result.is_ok()); ``` ### Elliptic-Curve Encrypt/Decrypt: @@ -85,10 +83,8 @@ let key_pair = KeyPair::new( .unwrap(); // Encrypt the message assert!(msg.key_encrypt(&key_pair.pub_key, &SecParam::D256).is_ok()); -// Decrypt the message +// Decrypt and verify assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); -// Verify -assert!(msg.op_result.is_ok()); ``` ### Symmetric Encrypt/Decrypt: @@ -99,20 +95,18 @@ use capycrypt::{ encryptable::SpongeEncryptable}, Message, SecParam, }; -// Get a random 128-bit password +// Get a random password let pw = get_random_bytes(16); // Get 5mb random data let mut msg = Message::new(get_random_bytes(5242880)); // Encrypt the data -assert!(msg.aes_encrypt_cbc(&pw).is_ok()); +assert!(msg.aes_encrypt_ctr(&pw).is_ok()); // Decrypt the data -assert!(msg.aes_decrypt_cbc(&pw).is_ok()); +assert!(msg.aes_decrypt_ctr(&pw).is_ok()); // Encrypt the data assert!(msg.sha3_encrypt(&pw, &SecParam::D512).is_ok()); -// Decrypt the data +// Decrypt and verify assert!(msg.sha3_decrypt(&pw).is_ok()); -// Verify operation success -assert!(msg.op_result.is_ok()); ``` ### Schnorr Signatures: @@ -131,7 +125,7 @@ let key_pair = KeyPair::new( &SecParam::D256, // bit-security for key ) .unwrap(); -// Sign with 256 bits of security +// Sign with 128 bits of security assert!(msg.sign(&key_pair, &SecParam::D256).is_ok()); // Verify signature assert!(msg.verify(&key_pair.pub_key).is_ok()); @@ -140,14 +134,13 @@ assert!(msg.verify(&key_pair.pub_key).is_ok()); ### Compute Digest: ```rust use capycrypt::{sha3::hashable::SpongeHashable, Message, SecParam}; - // Hash the empty string let mut data = Message::new(vec![]); // Obtained from echo -n "" | openssl dgst -sha3-256 let expected = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; // Compute a SHA3 digest with 128 bits of security -data.compute_sha3_hash(&SecParam::D256).unwrap(); -assert!(hex::encode(data.digest.unwrap()) == expected); +data.compute_sha3_hash(&SecParam::D256); +assert!(hex::encode(data.digest) == expected); ``` ## Performance diff --git a/benches/benchmark_e448_224.rs b/benches/benchmark_e448_224.rs index a991fd1..f7e1077 100644 --- a/benches/benchmark_e448_224.rs +++ b/benches/benchmark_e448_224.rs @@ -11,20 +11,20 @@ const BIT_SECURITY: SecParam = D224; /// Symmetric encrypt and decrypt roundtrip fn sym_enc(pw: &[u8], mut msg: Message) { - let _ = msg.sha3_encrypt(pw, &BIT_SECURITY); + let _ = msg.sha3_encrypt(pw, BIT_SECURITY); let _ = msg.sha3_decrypt(pw); } /// Asymmetric encrypt and decrypt roundtrip + keygen fn key_gen_enc_dec(pw: &[u8], mut msg: Message) { - let key_pair = KeyPair::new(pw, "test key".to_string(), &BIT_SECURITY).unwrap(); - let _ = msg.key_encrypt(&key_pair.pub_key, &BIT_SECURITY); + let key_pair = KeyPair::new(pw, "test key".to_string(), BIT_SECURITY).unwrap(); + let _ = msg.key_encrypt(&key_pair.pub_key, BIT_SECURITY); let _ = msg.key_decrypt(&key_pair.priv_key); } /// Signature generation + verification roundtrip pub fn sign_verify(key_pair: KeyPair, mut msg: Message) { - let _ = msg.sign(&key_pair, &BIT_SECURITY); + let _ = msg.sign(&key_pair, BIT_SECURITY); let _ = msg.verify(&key_pair.pub_key); } @@ -32,7 +32,7 @@ fn bench_sign_verify(c: &mut Criterion) { c.bench_function("e448 + SHA3-224 Sign + Verify Roundtrip", |b| { b.iter(|| { sign_verify( - KeyPair::new(&get_random_bytes(16), "test key".to_string(), &BIT_SECURITY).unwrap(), + KeyPair::new(&get_random_bytes(16), "test key".to_string(), BIT_SECURITY).unwrap(), Message::new(get_random_bytes(5242880)), ) }); @@ -54,7 +54,7 @@ fn bench_key_gen_enc_dec(c: &mut Criterion) { c.bench_function("e448 + SHA3-224 Asymmetric enc + dec", |b| { b.iter(|| { key_gen_enc_dec( - &KeyPair::new(&get_random_bytes(32), "test key".to_string(), &BIT_SECURITY) + &KeyPair::new(&get_random_bytes(32), "test key".to_string(), BIT_SECURITY) .unwrap() .priv_key, Message::new(get_random_bytes(5242880)), diff --git a/benches/benchmark_e448_512.rs b/benches/benchmark_e448_512.rs index 3c45cfc..9c0a4b2 100644 --- a/benches/benchmark_e448_512.rs +++ b/benches/benchmark_e448_512.rs @@ -11,20 +11,20 @@ const BIT_SECURITY: SecParam = D512; /// Symmetric encrypt and decrypt roundtrip fn sym_enc(pw: &[u8], mut msg: Message) { - let _ = msg.sha3_encrypt(pw, &BIT_SECURITY); + let _ = msg.sha3_encrypt(pw, BIT_SECURITY); let _ = msg.sha3_decrypt(pw); } /// Asymmetric encrypt and decrypt roundtrip + keygen fn key_gen_enc_dec(pw: &[u8], mut msg: Message) { - let key_pair = KeyPair::new(pw, "test key".to_string(), &BIT_SECURITY).unwrap(); - let _ = msg.key_encrypt(&key_pair.pub_key, &BIT_SECURITY); + let key_pair = KeyPair::new(pw, "test key".to_string(), BIT_SECURITY).unwrap(); + let _ = msg.key_encrypt(&key_pair.pub_key, BIT_SECURITY); let _ = msg.key_decrypt(&key_pair.priv_key); } /// Signature generation + verification roundtrip pub fn sign_verify(key_pair: KeyPair, mut msg: Message) { - let _ = msg.sign(&key_pair, &BIT_SECURITY); + let _ = msg.sign(&key_pair, BIT_SECURITY); let _ = msg.verify(&key_pair.pub_key); } @@ -32,7 +32,7 @@ fn bench_sign_verify(c: &mut Criterion) { c.bench_function("e448 + SHA3-512 Sign + Verify Roundtrip 5mb", |b| { b.iter(|| { sign_verify( - KeyPair::new(&get_random_bytes(16), "test key".to_string(), &BIT_SECURITY).unwrap(), + KeyPair::new(&get_random_bytes(16), "test key".to_string(), BIT_SECURITY).unwrap(), Message::new(get_random_bytes(5242880)), ) }); @@ -54,7 +54,7 @@ fn bench_key_gen_enc_dec(c: &mut Criterion) { c.bench_function("e448 + SHA3-512 Asymmetric enc + dec 5mb", |b| { b.iter(|| { key_gen_enc_dec( - &KeyPair::new(&get_random_bytes(32), "test key".to_string(), &BIT_SECURITY) + &KeyPair::new(&get_random_bytes(32), "test key".to_string(), BIT_SECURITY) .unwrap() .priv_key, Message::new(get_random_bytes(5242880)), diff --git a/benches/benchmark_sha3.rs b/benches/benchmark_sha3.rs index 529ef21..3af1da3 100644 --- a/benches/benchmark_sha3.rs +++ b/benches/benchmark_sha3.rs @@ -9,7 +9,7 @@ const BIT_SECURITY: SecParam = D256; /// hash 5mb of random data with 128 bits of security fn sha3_digest(mut msg: Message) { - let _ = msg.compute_sha3_hash(&BIT_SECURITY); + msg.compute_sha3_hash(BIT_SECURITY); } fn bench_sha3_digest(c: &mut Criterion) { diff --git a/src/aes/encryptable.rs b/src/aes/encryptable.rs index bf51330..e790f2c 100644 --- a/src/aes/encryptable.rs +++ b/src/aes/encryptable.rs @@ -35,11 +35,11 @@ impl AesEncryptable for Message { let iv = get_random_bytes(16); let mut ke_ka = iv.clone(); ke_ka.append(&mut key.to_owned()); - let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256); + let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", SecParam::D256); let ke = &ke_ka[..key.len()].to_vec(); // Encryption Key let ka = &ke_ka[key.len()..].to_vec(); // Authentication Key - self.digest = kmac_xof(ka, &self.msg, 512, "AES", &SecParam::D256); + self.digest = kmac_xof(ka, &self.msg, 512, "AES", SecParam::D256); self.sym_nonce = Some(iv.clone()); let key_schedule = AES::new(ke); @@ -81,7 +81,7 @@ impl AesEncryptable for Message { let iv = self.sym_nonce.clone().unwrap(); let mut ke_ka = iv.clone(); ke_ka.append(&mut key.to_owned()); - let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256); + let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", SecParam::D256); let ke = &ke_ka[..key.len()].to_vec(); // Encryption Key let ka = &ke_ka[key.len()..].to_vec(); // Authentication Key @@ -107,7 +107,7 @@ impl AesEncryptable for Message { remove_pcks7_padding(&mut self.msg); - kmac_xof(ka, &self.msg, 512, "AES", &SecParam::D256); + kmac_xof(ka, &self.msg, 512, "AES", SecParam::D256); Ok(()) } @@ -138,12 +138,12 @@ impl AesEncryptable for Message { let mut ke_ka = iv.clone(); ke_ka.extend_from_slice(&counter_bytes); ke_ka.extend_from_slice(key); - let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256); + let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", SecParam::D256); let (ke, ka) = ke_ka.split_at(key.len()); self.sym_nonce = Some(iv.clone()); - self.digest = kmac_xof(ka, &self.msg, 512, "AES", &SecParam::D256); + self.digest = kmac_xof(ka, &self.msg, 512, "AES", SecParam::D256); let key_schedule = AES::new(ke); @@ -192,7 +192,7 @@ impl AesEncryptable for Message { let mut ke_ka = iv.clone(); ke_ka.extend_from_slice(&counter_bytes); ke_ka.extend_from_slice(key); - let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", &SecParam::D256); + let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", SecParam::D256); let (ke, ka) = ke_ka.split_at(key.len()); @@ -212,7 +212,7 @@ impl AesEncryptable for Message { xor_blocks(block, &temp); }); - kmac_xof(ka, &self.msg, 512, "AES", &SecParam::D256); + kmac_xof(ka, &self.msg, 512, "AES", SecParam::D256); Ok(()) } } diff --git a/src/ecc/encryptable.rs b/src/ecc/encryptable.rs index de4544f..102da0e 100644 --- a/src/ecc/encryptable.rs +++ b/src/ecc/encryptable.rs @@ -8,7 +8,7 @@ use crate::{ use tiny_ed448_goldilocks::curve::{extended_edwards::ExtendedPoint, field::scalar::Scalar}; pub trait KeyEncryptable { - fn key_encrypt(&mut self, pub_key: &ExtendedPoint, d: &SecParam) -> Result<(), OperationError>; + fn key_encrypt(&mut self, pub_key: &ExtendedPoint, d: SecParam) -> Result<(), OperationError>; fn key_decrypt(&mut self, pw: &[u8]) -> Result<(), OperationError>; } @@ -28,12 +28,12 @@ impl KeyEncryptable for Message { /// * c โ† kmac_xof(ke, โ€œโ€, |m|, โ€œPKEโ€) โŠ• m /// * t โ† kmac_xof(ka, m, 448, โ€œPKAโ€) /// ## Arguments: - /// * pub_key: [`EdCurvePoint`] : X coordinate of public key ๐‘‰ + /// * pub_key: [`ExtendedPoint`] : X coordinate of public key ๐‘‰ /// * d: u64: Requested security strength in bits. Can only be 224, 256, 384, or 512. #[allow(non_snake_case)] - fn key_encrypt(&mut self, pub_key: &ExtendedPoint, d: &SecParam) -> Result<(), OperationError> { - self.d = Some(*d); - let k = bytes_to_scalar(get_random_bytes(56)).mul_mod(&Scalar::from(4_u64)); + fn key_encrypt(&mut self, pub_key: &ExtendedPoint, d: SecParam) -> Result<(), OperationError> { + self.d = Some(d); + let k = bytes_to_scalar(&get_random_bytes(56)).mul_mod(&Scalar::from(4_u64)); let w = (*pub_key * k).to_affine(); let Z = (ExtendedPoint::generator() * k).to_affine(); @@ -55,11 +55,6 @@ impl KeyEncryptable for Message { /// Operates under Schnorr/ECDHIES principle in that shared symmetric key is /// derived from ๐‘. /// - /// ## Assumes: - /// * well-formed encryption - /// * Some(Message.t) - /// * Some(Message.z) - /// /// ## Replaces: /// * `Message.data` with result of decryption. /// * `Message.op_result` with result of comparision of `Message.t` == keyed hash of decryption. @@ -77,13 +72,10 @@ impl KeyEncryptable for Message { #[allow(non_snake_case)] fn key_decrypt(&mut self, pw: &[u8]) -> Result<(), OperationError> { let Z = self.asym_nonce.ok_or(OperationError::SymNonceNotSet)?; - let d = self - .d - .as_ref() - .ok_or(OperationError::SecurityParameterNotSet)?; + let d = self.d.ok_or(OperationError::SecurityParameterNotSet)?; let s_bytes = kmac_xof(pw, &[], 448, "SK", d); - let s = bytes_to_scalar(s_bytes).mul_mod(&Scalar::from(4_u64)); + let s = bytes_to_scalar(&s_bytes).mul_mod(&Scalar::from(4_u64)); let Z = (Z * s).to_affine(); let ke_ka = kmac_xof(&Z.x.to_bytes(), &[], 448 * 2, "PK", d); @@ -94,15 +86,11 @@ impl KeyEncryptable for Message { let t_p = kmac_xof(ka, &self.msg, 448, "PKA", d); - self.op_result = if self.digest == t_p { + if self.digest == t_p { Ok(()) } else { - // revert back to the encrypted message xor_bytes(&mut self.msg, &xor_result); - Err(OperationError::KeyDecryptionError) - }; - - Ok(()) + } } } diff --git a/src/ecc/keypair.rs b/src/ecc/keypair.rs index b5c84e8..c6395a7 100644 --- a/src/ecc/keypair.rs +++ b/src/ecc/keypair.rs @@ -40,9 +40,9 @@ impl KeyPair { /// verification key ๐‘‰ is hashed together with the message ๐‘š /// and the nonce ๐‘ˆ: hash (๐‘š, ๐‘ˆ, ๐‘‰) . #[allow(non_snake_case)] - pub fn new(pw: &[u8], owner: String, d: &SecParam) -> Result { + pub fn new(pw: &[u8], owner: String, d: SecParam) -> Result { let data = kmac_xof(pw, &[], 448, "SK", d); - let s: Scalar = bytes_to_scalar(data).mul_mod(&Scalar::from(4_u64)); + let s: Scalar = bytes_to_scalar(&data).mul_mod(&Scalar::from(4_u64)); let V = ExtendedPoint::generator() * s; Ok(KeyPair { owner, diff --git a/src/ecc/signable.rs b/src/ecc/signable.rs index 1092b8c..95512ac 100644 --- a/src/ecc/signable.rs +++ b/src/ecc/signable.rs @@ -11,7 +11,7 @@ use tiny_ed448_goldilocks::curve::{extended_edwards::ExtendedPoint, field::scala use super::keypair::KeyPair; pub trait Signable { - fn sign(&mut self, key: &KeyPair, d: &SecParam) -> Result<(), OperationError>; + fn sign(&mut self, key: &KeyPair, d: SecParam) -> Result<(), OperationError>; fn verify(&mut self, pub_key: &ExtendedPoint) -> Result<(), OperationError>; } @@ -37,27 +37,24 @@ impl Signable for Message { /// ## Arguments: /// * key: &[`KeyPair`], : reference to KeyPair. /// * d: u64: encryption security strength in bits. Can only be 224, 256, 384, or 512. - /// - /// ## Assumes: - /// * Some(key.priv_key) #[allow(non_snake_case)] - fn sign(&mut self, key: &KeyPair, d: &SecParam) -> Result<(), OperationError> { + fn sign(&mut self, key: &KeyPair, d: SecParam) -> Result<(), OperationError> { let s_bytes = kmac_xof(&key.priv_key, &[], 448, "SK", d); - let s = bytes_to_scalar(s_bytes).mul_mod(&Scalar::from(4_u64)); + let s = bytes_to_scalar(&s_bytes).mul_mod(&Scalar::from(4_u64)); let s_bytes = scalar_to_bytes(&s); let k_bytes = kmac_xof(&s_bytes, &self.msg, 448, "N", d); - let k = bytes_to_scalar(k_bytes) * Scalar::from(4_u64); + let k = bytes_to_scalar(&k_bytes) * Scalar::from(4_u64); let U = ExtendedPoint::generator() * k; let ux_bytes = U.to_affine().x.to_bytes(); let h = kmac_xof(&ux_bytes, &self.msg, 448, "T", d); - let h_big = bytes_to_scalar(h.clone()); + let h_big = bytes_to_scalar(&h); let z = k - h_big.mul_mod(&s); self.sig = Some(Signature { h, z }); - self.d = Some(*d); + self.d = Some(d); Ok(()) } @@ -76,21 +73,17 @@ impl Signable for Message { #[allow(non_snake_case)] fn verify(&mut self, pub_key: &ExtendedPoint) -> Result<(), OperationError> { let sig = self.sig.as_ref().ok_or(OperationError::SignatureNotSet)?; - let d = self - .d - .as_ref() - .ok_or(OperationError::SecurityParameterNotSet)?; + let d = self.d.ok_or(OperationError::SecurityParameterNotSet)?; - let h_scalar = bytes_to_scalar(sig.h.clone()); + let h_scalar = bytes_to_scalar(&sig.h); let U = ExtendedPoint::generator() * sig.z + (*pub_key * h_scalar); let h_p = kmac_xof(&U.to_affine().x.to_bytes(), &self.msg, 448, "T", d); - self.op_result = if h_p == sig.h { + if h_p == sig.h { Ok(()) } else { Err(OperationError::SignatureVerificationFailure) - }; - Ok(()) + } } } diff --git a/src/kem/encryptable.rs b/src/kem/encryptable.rs index f3e1c2f..b5e9104 100644 --- a/src/kem/encryptable.rs +++ b/src/kem/encryptable.rs @@ -14,26 +14,26 @@ use rand::{thread_rng, RngCore}; use super::keypair::{KEMPrivateKey, KEMPublicKey}; pub trait KEMEncryptable { - fn kem_encrypt(&mut self, key: &KEMPublicKey, d: &SecParam) -> Result<(), OperationError>; + fn kem_encrypt(&mut self, key: &KEMPublicKey, d: SecParam) -> Result<(), OperationError>; fn kem_decrypt(&mut self, key: &KEMPrivateKey) -> Result<(), OperationError>; } impl KEMEncryptable for Message { - fn kem_encrypt(&mut self, key: &KEMPublicKey, d: &SecParam) -> Result<(), OperationError> { - self.d = Some(*d); + fn kem_encrypt(&mut self, key: &KEMPublicKey, d: SecParam) -> Result<(), OperationError> { + self.d = Some(d); let mut rng = thread_rng(); - let mut secret = [0_u8; 32]; + let secret = &mut [0_u8; 32]; // generate a random secret to be used as the shared seed - rng.fill_bytes(&mut secret); + rng.fill_bytes(secret); - let c = k_pke_encrypt::(&secret, &key.ek, &key.rand_bytes); + let c = k_pke_encrypt::(secret, &key.ek, &key.rand_bytes); self.kem_ciphertext = Some(c); let z = get_random_bytes(512); let mut ke_ka = z.clone(); - ke_ka.extend_from_slice(&secret); + ke_ka.extend_from_slice(secret); let ke_ka = kmac_xof(&ke_ka, &[], 1024, "S", d); let (ke, ka) = ke_ka.split_at(64); @@ -55,10 +55,7 @@ impl KEMEncryptable for Message { let dec = k_pke_decrypt::(&key.dk, ciphertext); - let d = self - .d - .as_ref() - .ok_or(OperationError::SecurityParameterNotSet)?; + let d = self.d.ok_or(OperationError::SecurityParameterNotSet)?; let mut z_pw = self .sym_nonce @@ -75,13 +72,11 @@ impl KEMEncryptable for Message { let new_t = kmac_xof(ka, &self.msg, 512, "KEMKA", d); - self.op_result = if self.digest == new_t { + if self.digest == new_t { Ok(()) } else { xor_bytes(&mut self.msg, &m); Err(OperationError::SHA3DecryptionFailure) - }; - - Ok(()) + } } } diff --git a/src/lib.rs b/src/lib.rs index 9317cab..39a9002 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,8 +73,6 @@ pub struct Message { pub asym_nonce: Option, /// Hash value (also known as message digest) pub digest: Vec, - /// Result of the cryptographic trait - pub op_result: Result<(), OperationError>, /// Schnorr signatures on the input message pub sig: Option, /// ML-KEM encrypted secret as a byte array @@ -90,7 +88,6 @@ impl Message { sym_nonce: None, asym_nonce: None, digest: vec![], - op_result: Ok(()), sig: None, kem_ciphertext: Some(vec![]), } diff --git a/src/main.rs b/src/main.rs index 1e53c24..d61e34b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,8 +47,7 @@ fn main() { let sec_param = SecParam::try_from(bits) .expect("Unsupported security parameter. Use 224, 256, 384, or 512"); - data.compute_sha3_hash(&sec_param) - .expect("An error occurred during hash computation."); + data.compute_sha3_hash(sec_param); println!("Hash: {}", hex::encode(data.digest)) } @@ -61,7 +60,7 @@ fn main() { output, } => { let sec_param = SecParam::try_from(bits).expect("Unsupported security parameter."); - let kp = KeyPair::new(pw.as_bytes(), owner, &sec_param) + let kp = KeyPair::new(pw.as_bytes(), owner, sec_param) .expect("Unable to generate the requested key pair"); let _ = kp.write_to_file(&output); diff --git a/src/sha3/aux_functions.rs b/src/sha3/aux_functions.rs index 5444bfa..a6103b1 100644 --- a/src/sha3/aux_functions.rs +++ b/src/sha3/aux_functions.rs @@ -102,9 +102,9 @@ pub mod byte_utils { local.format("%Y-%m-%d %H:%M:%S").to_string() } - pub(crate) fn bytes_to_scalar(in_bytes: Vec) -> Scalar { + pub(crate) fn bytes_to_scalar(in_bytes: &[u8]) -> Scalar { Scalar { - val: (U448::from_be_slice(&in_bytes)), + val: (U448::from_be_slice(in_bytes)), } } diff --git a/src/sha3/encryptable.rs b/src/sha3/encryptable.rs index 688d0d6..0d92af5 100644 --- a/src/sha3/encryptable.rs +++ b/src/sha3/encryptable.rs @@ -5,7 +5,7 @@ use crate::{ }; pub trait SpongeEncryptable { - fn sha3_encrypt(&mut self, pw: &[u8], d: &SecParam) -> Result<(), OperationError>; + fn sha3_encrypt(&mut self, pw: &[u8], d: SecParam) -> Result<(), OperationError>; fn sha3_decrypt(&mut self, pw: &[u8]) -> Result<(), OperationError>; } @@ -26,8 +26,8 @@ impl SpongeEncryptable for Message { /// * `pw: &[u8]`: symmetric encryption key, can be blank but shouldnt be /// * `d: u64`: requested security strength in bits. Supported /// bitstrengths are 224, 256, 384, or 512. - fn sha3_encrypt(&mut self, pw: &[u8], d: &SecParam) -> Result<(), OperationError> { - self.d = Some(*d); + fn sha3_encrypt(&mut self, pw: &[u8], d: SecParam) -> Result<(), OperationError> { + self.d = Some(d); let z = get_random_bytes(512); let mut ke_ka = z.clone(); @@ -47,10 +47,7 @@ impl SpongeEncryptable for Message { /// # Symmetric Decryption /// Decrypts a [`Message`] (z, c, t) under passphrase pw. - /// ## Assumes: - /// * well-formed encryption - /// * Some(Message.t) - /// * Some(Message.z) + /// ## Replaces: /// * `Message.data` with result of decryption. /// * `Message.op_result` with result of comparision of `Message.t` == keyed hash of decryption. @@ -61,10 +58,7 @@ impl SpongeEncryptable for Message { /// ## Arguments: /// * `pw: &[u8]`: decryption password, can be blank fn sha3_decrypt(&mut self, pw: &[u8]) -> Result<(), OperationError> { - let d = self - .d - .as_ref() - .ok_or(OperationError::SecurityParameterNotSet)?; + let d = self.d.ok_or(OperationError::SecurityParameterNotSet)?; let mut z_pw = self .sym_nonce @@ -82,13 +76,11 @@ impl SpongeEncryptable for Message { let new_t = kmac_xof(ka, &self.msg, 512, "SKA", d); - self.op_result = if self.digest == new_t { + if self.digest == new_t { Ok(()) } else { xor_bytes(&mut self.msg, &m); Err(OperationError::SHA3DecryptionFailure) - }; - - Ok(()) + } } } diff --git a/src/sha3/hashable.rs b/src/sha3/hashable.rs index 5967989..b06ea24 100644 --- a/src/sha3/hashable.rs +++ b/src/sha3/hashable.rs @@ -1,4 +1,4 @@ -use crate::{Message, OperationError, SecParam}; +use crate::{Message, SecParam}; use super::{ constants::BitLength, @@ -6,8 +6,8 @@ use super::{ }; pub trait SpongeHashable { - fn compute_sha3_hash(&mut self, d: &SecParam) -> Result<(), OperationError>; - fn compute_tagged_hash(&mut self, pw: &[u8], s: &str, d: &SecParam); + fn compute_sha3_hash(&mut self, d: SecParam); + fn compute_tagged_hash(&mut self, pw: &[u8], s: &str, d: SecParam); } impl SpongeHashable for Message { @@ -17,9 +17,8 @@ impl SpongeHashable for Message { /// ## Arguments: /// * `d: u64`: requested security strength in bits. Supported /// bitstrengths are 224, 256, 384, or 512. - fn compute_sha3_hash(&mut self, d: &SecParam) -> Result<(), OperationError> { - self.digest = shake(&mut self.msg, d); - Ok(()) + fn compute_sha3_hash(&mut self, d: SecParam) { + self.digest = shake(&mut self.msg, d) } /// # Tagged Hash @@ -32,7 +31,7 @@ impl SpongeHashable for Message { /// * `s: &mut str`: domain seperation string /// * `d: u64`: requested security strength in bits. Supported /// bitstrengths are 224, 256, 384, or 512. - fn compute_tagged_hash(&mut self, pw: &[u8], s: &str, d: &SecParam) { + fn compute_tagged_hash(&mut self, pw: &[u8], s: &str, d: SecParam) { self.digest = kmac_xof(pw, &self.msg, d.bit_length(), s, d); } } diff --git a/src/sha3/shake_functions.rs b/src/sha3/shake_functions.rs index 82153e7..18b8f7f 100644 --- a/src/sha3/shake_functions.rs +++ b/src/sha3/shake_functions.rs @@ -22,14 +22,14 @@ use super::constants::{BitLength, Capacity, Rate, RATE_IN_BYTES}; /// * `d: usize`: requested output length and security strength /// ## Returns: /// * `return -> Vec`: SHA3-d message digest -pub(crate) fn shake(n: &mut Vec, d: &impl BitLength) -> Vec { +pub(crate) fn shake(n: &mut Vec, d: impl BitLength) -> Vec { let bytes_to_pad = RATE_IN_BYTES - n.len() % RATE_IN_BYTES; match bytes_to_pad { 1 => n.extend_from_slice(&[0x86]), // delim suffix _ => n.extend_from_slice(&[0x06]), // delim suffix } let c = Capacity::from_bit_length(d.bit_length()); - sponge_squeeze(&mut sponge_absorb(n, &c), d.bit_length(), Rate::from(d)) + sponge_squeeze(&mut sponge_absorb(n, c), d.bit_length(), Rate::from(&d)) } /// # Customizable SHAKE @@ -58,10 +58,10 @@ pub(crate) fn cshake(x: &[u8], l: usize, n: &str, s: &str, d: SecParam) -> Vec Vec Vec`: kmac_xof of `x` under `k` -pub fn kmac_xof(k: &[u8], x: &[u8], l: usize, s: &str, d: &SecParam) -> Vec { +pub fn kmac_xof(k: &[u8], x: &[u8], l: usize, s: &str, d: SecParam) -> Vec { let mut encode_k = encode_string(k); let bytepad_w = d.bytepad_value(); let mut bp = byte_pad(&mut encode_k, bytepad_w); @@ -86,7 +86,7 @@ pub fn kmac_xof(k: &[u8], x: &[u8], l: usize, s: &str, d: &SecParam) -> Vec bp.extend_from_slice(x); bp.extend_from_slice(&right_encode(0)); // SP 800-185 4.3.1 KMAC with Arbitrary-Length Output - cshake(&bp, l, "KMAC", s, *d) + cshake(&bp, l, "KMAC", s, d) } /// TESTS @@ -102,7 +102,7 @@ mod shake_tests { 0xb1, 0xab, 0xd4, 0x59, 0x7f, 0x9a, 0x1b, 0x07, 0x8e, 0x3f, 0x5b, 0x5a, 0x6b, 0xc7, ]; - assert!(data.compute_sha3_hash(&SecParam::D224).is_ok()); + data.compute_sha3_hash(SecParam::D224); assert!(data.digest == expected.to_vec()); let mut data = Message::new("test".as_bytes().to_vec()); @@ -110,7 +110,7 @@ mod shake_tests { 0x37, 0x97, 0xbf, 0x0a, 0xfb, 0xbf, 0xca, 0x4a, 0x7b, 0xbb, 0xa7, 0x60, 0x2a, 0x2b, 0x55, 0x27, 0x46, 0x87, 0x65, 0x17, 0xa7, 0xf9, 0xb7, 0xce, 0x2d, 0xb0, 0xae, 0x7b, ]; - assert!(data.compute_sha3_hash(&SecParam::D224).is_ok()); + data.compute_sha3_hash(SecParam::D224); assert!(data.digest == expected.to_vec()); } @@ -122,7 +122,7 @@ mod shake_tests { 0xd6, 0x62, 0xf5, 0x80, 0xff, 0x4d, 0xe4, 0x3b, 0x49, 0xfa, 0x82, 0xd8, 0x0a, 0x4b, 0x80, 0xf8, 0x43, 0x4a, ]; - assert!(data.compute_sha3_hash(&SecParam::D256).is_ok()); + data.compute_sha3_hash(SecParam::D256); assert!(data.digest == expected.to_vec()); let mut data = Message::new("test".as_bytes().to_vec()); @@ -131,7 +131,7 @@ mod shake_tests { 0x00, 0xe3, 0x46, 0xe2, 0x76, 0xae, 0x66, 0x4e, 0x45, 0xee, 0x80, 0x74, 0x55, 0x74, 0xe2, 0xf5, 0xab, 0x80, ]; - assert!(data.compute_sha3_hash(&SecParam::D256).is_ok()); + data.compute_sha3_hash(SecParam::D256); assert!(data.digest == expected.to_vec()); } @@ -144,7 +144,7 @@ mod shake_tests { 0xee, 0x98, 0x3a, 0x2a, 0xc3, 0x71, 0x38, 0x31, 0x26, 0x4a, 0xdb, 0x47, 0xfb, 0x6b, 0xd1, 0xe0, 0x58, 0xd5, 0xf0, 0x04, ]; - assert!(data.compute_sha3_hash(&SecParam::D384).is_ok()); + data.compute_sha3_hash(SecParam::D384); assert!(data.digest == expected.to_vec()); let mut data = Message::new("test".as_bytes().to_vec()); @@ -154,7 +154,7 @@ mod shake_tests { 0xf0, 0xf1, 0xb4, 0x1e, 0xec, 0xb9, 0xdb, 0x3f, 0xf2, 0x19, 0x00, 0x7c, 0x4e, 0x09, 0x72, 0x60, 0xd5, 0x86, 0x21, 0xbd, ]; - assert!(data.compute_sha3_hash(&SecParam::D384).is_ok()); + data.compute_sha3_hash(SecParam::D384); assert!(data.digest == expected.to_vec()); } @@ -168,7 +168,7 @@ mod shake_tests { 0xf2, 0xe9, 0xb3, 0xca, 0x9f, 0x48, 0x4f, 0x52, 0x1d, 0x0c, 0xe4, 0x64, 0x34, 0x5c, 0xc1, 0xae, 0xc9, 0x67, 0x79, 0x14, 0x9c, 0x14, ]; - assert!(data.compute_sha3_hash(&SecParam::D512).is_ok()); + data.compute_sha3_hash(SecParam::D512); assert!(data.digest == expected.to_vec()); } @@ -182,7 +182,7 @@ mod shake_tests { 0xa4, 0xa3, 0x81, 0x72, 0xbf, 0x11, 0x42, 0xa6, 0xa9, 0xc1, 0x93, 0x0e, 0x50, 0xdf, 0x03, 0x90, 0x43, 0x12, ]; - data.compute_tagged_hash(&pw, &s, &SecParam::D256); + data.compute_tagged_hash(&pw, &s, SecParam::D256); assert!(data.digest == expected.to_vec()); } @@ -198,7 +198,7 @@ mod shake_tests { 0x63, 0xf4, 0xca, 0x0b, 0x65, 0x83, 0x6f, 0x52, 0x61, 0xee, 0x64, 0x64, 0x4c, 0xe5, 0xa8, 0x84, 0x56, 0xd3, 0xd3, 0x0e, 0xfb, 0xed, ]; - data.compute_tagged_hash(&pw, "", &SecParam::D512); + data.compute_tagged_hash(&pw, "", SecParam::D512); assert!(data.digest == expected.to_vec()); } @@ -259,7 +259,7 @@ mod kmac_tests { let s_str = "My Tagged Application"; let key_bytes = key_str; let data = hex::decode("00010203").unwrap(); - let res = kmac_xof(key_bytes.as_ref(), &data, 64, s_str, &SecParam::D512); + let res = kmac_xof(key_bytes.as_ref(), &data, 64, s_str, SecParam::D512); let expected = "1755133f1534752a"; assert_eq!(hex::encode(res), expected) } @@ -275,7 +275,7 @@ mod kmac_tests { let key_bytes = key_str; let data = NIST_DATA_SPONGE_INIT; - let res = kmac_xof(key_bytes.as_ref(), &data, 512, s_str, &SecParam::D512); + let res = kmac_xof(key_bytes.as_ref(), &data, 512, s_str, SecParam::D512); let expected: [u8; 64] = [ 0xd5, 0xbe, 0x73, 0x1c, 0x95, 0x4e, 0xd7, 0x73, 0x28, 0x46, 0xbb, 0x59, 0xdb, 0xe3, 0xa8, 0xe3, 0x0f, 0x83, 0xe7, 0x7a, 0x4b, 0xff, 0x44, 0x59, 0xf2, 0xf1, 0xc2, 0xb4, diff --git a/src/sha3/sponge.rs b/src/sha3/sponge.rs index f7d0b41..0dcedb4 100644 --- a/src/sha3/sponge.rs +++ b/src/sha3/sponge.rs @@ -8,7 +8,7 @@ use super::constants::{BitLength, Rate}; // * m: message to be absorbed // * capacity: security parameter which determines rate = bit_width - capacity // * return: a state consisting of 25 words of 64 bits each. -pub(crate) fn sponge_absorb(m: &mut Vec, capacity: &impl BitLength) -> [u64; 25] { +pub(crate) fn sponge_absorb(m: &mut Vec, capacity: impl BitLength) -> [u64; 25] { let c = capacity.bit_length(); let r = (1600 - c) / 8; if (m.len() % r) != 0 { diff --git a/tests/aes_tests.rs b/tests/aes_tests.rs index 7af64a7..c548bf6 100644 --- a/tests/aes_tests.rs +++ b/tests/aes_tests.rs @@ -12,9 +12,7 @@ mod aes_modes_tests { let mut input = Message::new(get_random_bytes(5242880)); let _ = input.aes_encrypt_cbc(&key); // Encrypt the input - let _ = input.aes_decrypt_cbc(&key); // Decrypt the input - - assert!(input.op_result.is_ok()); // Verify operation success + assert!(input.aes_decrypt_cbc(&key).is_ok()); // Verify operation success } #[test] @@ -25,8 +23,7 @@ mod aes_modes_tests { let mut input = Message::new(get_random_bytes(5242880)); let _ = input.aes_encrypt_cbc(&key); // Encrypt the input - let _ = input.aes_decrypt_cbc(&key); // Decrypt the input - assert!(input.op_result.is_ok()); // Verify operation success + assert!(input.aes_decrypt_cbc(&key).is_ok()); // Verify operation success } #[test] @@ -37,8 +34,7 @@ mod aes_modes_tests { let mut input = Message::new(get_random_bytes(5242880)); let _ = input.aes_encrypt_cbc(&key); // Encrypt the input - let _ = input.aes_decrypt_cbc(&key); // Decrypt the input - assert!(input.op_result.is_ok()); // Verify operation success + assert!(input.aes_decrypt_cbc(&key).is_ok()); // Verify operation success } #[test] @@ -49,9 +45,7 @@ mod aes_modes_tests { let mut input = Message::new(get_random_bytes(5242880)); let _ = input.aes_encrypt_ctr(&key); // Encrypt the input - let _ = input.aes_decrypt_ctr(&key); // Decrypt the input - - assert!(input.op_result.is_ok()); // Verify operation success + assert!(input.aes_decrypt_ctr(&key).is_ok()); // Verify operation success } #[test] @@ -62,9 +56,7 @@ mod aes_modes_tests { let mut input = Message::new(get_random_bytes(5242880)); let _ = input.aes_encrypt_ctr(&key); // Encrypt the input - let _ = input.aes_decrypt_ctr(&key); // Decrypt the input - - assert!(input.op_result.is_ok()); // Verify operation success + assert!(input.aes_decrypt_ctr(&key).is_ok()); // Verify operation success } #[test] @@ -75,9 +67,7 @@ mod aes_modes_tests { let mut input = Message::new(get_random_bytes(5242880)); let _ = input.aes_encrypt_ctr(&key); // Encrypt the input - let _ = input.aes_decrypt_ctr(&key); // Decrypt the input - - assert!(input.op_result.is_ok()); // Verify operation success + assert!(input.aes_decrypt_ctr(&key).is_ok()); // Verify operation success } } diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 6626e2a..0ea4779 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1,43 +1,6 @@ #[test] -fn test_hashable() { - use capycrypt::{sha3::hashable::SpongeHashable, Message, SecParam}; - // Hash the empty string - let mut data = Message::new(vec![]); - // Obtained from echo -n "" | openssl dgst -sha3-256 - let expected = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; - // Compute a SHA3 digest with 128 bits of security - data.compute_sha3_hash(&SecParam::D256).unwrap(); - assert!(hex::encode(data.digest) == expected); -} - -#[test] -#[allow(unused_must_use)] -fn test_aes_encryptable() { - use capycrypt::{ - aes::encryptable::AesEncryptable, - sha3::{aux_functions::byte_utils::get_random_bytes, encryptable::SpongeEncryptable}, - Message, SecParam, - }; - // Get a random 128-bit password - let pw = get_random_bytes(16); - // Get 5mb random data - let mut msg = Message::new(get_random_bytes(5242880)); - // Encrypt the data - assert!(msg.aes_encrypt_cbc(&pw).is_ok()); - // Decrypt the data - assert!(msg.aes_decrypt_cbc(&pw).is_ok()); - // Encrypt the data - assert!(msg.sha3_encrypt(&pw, &SecParam::D512).is_ok()); - // Decrypt the data - assert!(msg.sha3_decrypt(&pw).is_ok()); - // Verify operation success - assert!(msg.op_result.is_ok()); -} - -#[test] -fn test_key_gen_enc_dec_256() { +pub fn test_kem_enc_512() { use capycrypt::{ - ecc::{encryptable::KeyEncryptable, keypair::KeyPair}, kem::{encryptable::KEMEncryptable, keypair::kem_keygen}, sha3::aux_functions::byte_utils::get_random_bytes, Message, SecParam, @@ -45,45 +8,37 @@ fn test_key_gen_enc_dec_256() { // Get 5mb random data let mut msg = Message::new(get_random_bytes(5242880)); - // Create a new elliptic-curve public/private keypair - let key_pair = KeyPair::new( - &get_random_bytes(64), - "test key".to_string(), - &SecParam::D256, - ) - .unwrap(); - // Encrypt the message - assert!(msg.key_encrypt(&key_pair.pub_key, &SecParam::D256).is_ok()); - // Decrypt the message - assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); - // Verify - assert!(msg.op_result.is_ok()); // Create a new ML-KEM public/private keypair let (kem_pub_key, kem_priv_key) = kem_keygen(); // Encrypt the message - assert!(msg.kem_encrypt(&kem_pub_key, &SecParam::D256).is_ok()); - // Decrypt the message + assert!(msg.kem_encrypt(&kem_pub_key, SecParam::D256).is_ok()); + // Decrypt and verify assert!(msg.kem_decrypt(&kem_priv_key).is_ok()); - // Verify - assert!(msg.op_result.is_ok()); } #[test] -pub fn test_kem_enc_512() { +fn test_key_gen_enc_dec_256() { use capycrypt::{ - kem::{encryptable::KEMEncryptable, keypair::kem_keygen}, + ecc::{encryptable::KeyEncryptable, keypair::KeyPair}, sha3::aux_functions::byte_utils::get_random_bytes, Message, SecParam, }; + // Get 5mb random data let mut msg = Message::new(get_random_bytes(5242880)); - let (kem_pub_key, kem_priv_key) = kem_keygen(); - - assert!(msg.kem_encrypt(&kem_pub_key, &SecParam::D512).is_ok()); - assert!(msg.kem_decrypt(&kem_priv_key).is_ok()); - assert!(msg.op_result.is_ok()); + // Create a new elliptic-curve public/private keypair + let key_pair = KeyPair::new( + &get_random_bytes(64), // random password for key + "test key".to_string(), // label + SecParam::D256, // bit-security for key + ) + .unwrap(); + // Encrypt the message + assert!(msg.key_encrypt(&key_pair.pub_key, SecParam::D256).is_ok()); + // Decrypt and verify + assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); } #[test] @@ -98,15 +53,14 @@ fn test_key_gen_enc_dec_512() { let key_pair = KeyPair::new( &get_random_bytes(32), "test key".to_string(), - &SecParam::D512, + SecParam::D512, ) .unwrap(); - assert!(msg.key_encrypt(&key_pair.pub_key, &SecParam::D512).is_ok()); + assert!(msg.key_encrypt(&key_pair.pub_key, SecParam::D512).is_ok()); assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); - - assert!(msg.op_result.is_ok()); } + #[test] pub fn test_signature_256() { use capycrypt::{ @@ -120,15 +74,48 @@ pub fn test_signature_256() { let key_pair = KeyPair::new( &get_random_bytes(64), // random password for key "test key".to_string(), // label - &SecParam::D256, // bit-security for key + SecParam::D256, // bit-security for key ) .unwrap(); // Sign with 256 bits of security - assert!(msg.sign(&key_pair, &SecParam::D256).is_ok()); + assert!(msg.sign(&key_pair, SecParam::D256).is_ok()); // Verify signature assert!(msg.verify(&key_pair.pub_key).is_ok()); } +#[test] +fn test_hashable() { + use capycrypt::{sha3::hashable::SpongeHashable, Message, SecParam}; + // Hash the empty string + let mut data = Message::new(vec![]); + // Obtained from echo -n "" | openssl dgst -sha3-256 + let expected = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; + // Compute a SHA3 digest with 128 bits of security + data.compute_sha3_hash(SecParam::D256); + assert!(hex::encode(data.digest) == expected); +} + +#[test] +fn test_symmetric_encryptable() { + use capycrypt::{ + aes::encryptable::AesEncryptable, + sha3::{aux_functions::byte_utils::get_random_bytes, encryptable::SpongeEncryptable}, + Message, SecParam, + }; + // Get a random password + let pw = get_random_bytes(16); + // Get 5mb random data + let mut msg = Message::new(get_random_bytes(5242880)); + // Encrypt the data + assert!(msg.aes_encrypt_ctr(&pw).is_ok()); + // Decrypt the data + assert!(msg.aes_decrypt_ctr(&pw).is_ok()); + // Encrypt the data + assert!(msg.sha3_encrypt(&pw, SecParam::D512).is_ok()); + // Decrypt and verify + assert!(msg.sha3_decrypt(&pw).is_ok()); +} + #[test] pub fn test_signature_512() { use capycrypt::{ @@ -139,12 +126,10 @@ pub fn test_signature_512() { let mut msg = Message::new(get_random_bytes(5242880)); let pw = get_random_bytes(64); - let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512).unwrap(); + let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512).unwrap(); - assert!(msg.sign(&key_pair, &SecParam::D512).is_ok()); + assert!(msg.sign(&key_pair, SecParam::D512).is_ok()); assert!(msg.verify(&key_pair.pub_key).is_ok()); - - assert!(msg.op_result.is_ok()); } // This test shouldnt have a huge variation between key sizes due to the fixed-time @@ -164,13 +149,12 @@ fn test_sig_timing_side_channel() { for i in 0..10 { let mut msg = Message::new(get_random_bytes(5242880)); let pw = get_random_bytes(1 << i); - let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512).unwrap(); + let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512).unwrap(); let now = Instant::now(); - let _ = msg.sign(&key_pair, &SecParam::D512); + let _ = msg.sign(&key_pair, SecParam::D512); println!("{} needed {} microseconds", i, now.elapsed().as_micros()); let _ = msg.verify(&key_pair.pub_key); - assert!(msg.op_result.is_ok()); } } @@ -185,7 +169,7 @@ fn test_reading_writing_keypair() { let key_pair = KeyPair::new( &get_random_bytes(32), "test key".to_string(), - &SecParam::D512, + SecParam::D512, ) .expect("Failed to create key pair"); @@ -212,7 +196,7 @@ pub fn test_signature_512_read_keypair_from_file() { let mut msg = Message::new(get_random_bytes(5242880)); let pw = get_random_bytes(64); - let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512) + let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512) .expect("Failed to create key pair"); let temp_dir = tempdir().expect("Failed to create temporary directory"); @@ -222,9 +206,8 @@ pub fn test_signature_512_read_keypair_from_file() { let read_key_pair = KeyPair::read_from_file(temp_file_path.to_str().unwrap()) .expect("Failed to read key pair from file"); - assert!(msg.sign(&read_key_pair, &SecParam::D512).is_ok()); + assert!(msg.sign(&read_key_pair, SecParam::D512).is_ok()); assert!(msg.verify(&read_key_pair.pub_key).is_ok()); - assert!(msg.op_result.is_ok()); } #[test] @@ -246,9 +229,9 @@ pub fn test_signature_512_read_message_from_file() { let mut initial_msg = Message::read_from_file(temp_file_path.to_str().unwrap()).unwrap(); let pw = get_random_bytes(64); - let key_pair = KeyPair::new(&pw, "test key".to_string(), &SecParam::D512).unwrap(); + let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512).unwrap(); - assert!(initial_msg.sign(&key_pair, &SecParam::D512).is_ok()); + assert!(initial_msg.sign(&key_pair, SecParam::D512).is_ok()); initial_msg .write_to_file(temp_file_path.to_str().unwrap()) @@ -257,8 +240,6 @@ pub fn test_signature_512_read_message_from_file() { let mut signed_msg = Message::read_from_file(temp_file_path.to_str().unwrap()).unwrap(); assert!(signed_msg.verify(&key_pair.pub_key).is_ok()); - - assert!(signed_msg.op_result.is_ok()); } #[cfg(test)] @@ -270,14 +251,9 @@ mod decryption_test { SecParam::D512, }; - /// Testing a security parameters whether the failed decryption preserves - /// the original encrypted text. If an encrypted text is decrypted with a wrong password, - /// then the original encrypted message should remain the same. - /// - /// Note: Message were cloned for the test purposes, but in a production setting, - /// clone() will not be used, as the operation is done in memory. - /// Although a single security parameter is tested, - /// it should work on the remaining security parameters. + // Testing a security parameters whether the failed decryption preserves + // the original encrypted text. If an encrypted text is decrypted with a wrong password, + // then the original encrypted message should remain the same. #[test] fn test_sha3_decrypt_handling_bad_input() { let pw1 = get_random_bytes(64); @@ -285,33 +261,30 @@ mod decryption_test { // D512 let mut new_msg = Message::new(get_random_bytes(523)); - let _ = new_msg.sha3_encrypt(&pw1, &D512); + let _ = new_msg.sha3_encrypt(&pw1, D512); let msg2 = new_msg.msg.clone(); - let _ = new_msg.sha3_decrypt(&pw2); + let res = new_msg.sha3_decrypt(&pw2); + assert!(res.is_err()); assert_eq!(msg2, new_msg.msg); } - /// Testing a security parameters whether the failed decryption preserves - /// the original encrypted text. If an encrypted text is decrypted with a wrong password, - /// then the original encrypted message should remain the same. - /// - /// Note: Message were cloned for the test purposes, but in a production setting, - /// clone() will not be used, as the operation is done in memory. - /// Although a single security parameter is tested, - /// it should work on the remaining security parameters. + // Testing a security parameters whether the failed decryption preserves + // the original encrypted text. If an encrypted text is decrypted with a wrong password, + // then the original encrypted message should remain the same. #[test] fn test_key_decrypt_handling_bad_input() { let mut new_msg = Message::new(get_random_bytes(125)); // D512 - let key_pair1 = KeyPair::new(&get_random_bytes(32), "test key".to_string(), &D512).unwrap(); - let key_pair2 = KeyPair::new(&get_random_bytes(32), "test key".to_string(), &D512).unwrap(); + let key_pair1 = KeyPair::new(&get_random_bytes(32), "test key".to_string(), D512).unwrap(); + let key_pair2 = KeyPair::new(&get_random_bytes(32), "test key".to_string(), D512).unwrap(); - let _ = new_msg.key_encrypt(&key_pair1.pub_key, &D512); + let _ = new_msg.key_encrypt(&key_pair1.pub_key, D512); let new_msg2 = new_msg.msg.clone(); - let _ = new_msg.key_decrypt(&key_pair2.priv_key); + let res = new_msg.key_decrypt(&key_pair2.priv_key); + assert!(res.is_err()); assert_eq!(*new_msg.msg, *new_msg2, "Message after reverting a failed decryption does not match the original encrypted message"); } } From b8be3db69483b7fa5072a2f0b25b08a60d2d74eb Mon Sep 17 00:00:00 2001 From: dr Date: Fri, 28 Jun 2024 19:05:44 -0700 Subject: [PATCH 3/4] refactor: update refs --- README.md | 20 +++++++++----------- benches/benchmark_e448_224.rs | 8 +++----- benches/benchmark_e448_512.rs | 8 +++----- src/ecc/keypair.rs | 8 ++++---- src/main.rs | 3 +-- tests/integration_tests.rs | 25 ++++++++++--------------- 6 files changed, 30 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 8965a7f..78c1489 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ let mut msg = Message::new(get_random_bytes(5242880)); // Create a new ML-KEM public/private keypair let (kem_pub_key, kem_priv_key) = kem_keygen(); // Encrypt the message -assert!(msg.kem_encrypt(&kem_pub_key, &SecParam::D256).is_ok()); +assert!(msg.kem_encrypt(&kem_pub_key, SecParam::D256).is_ok()); // Decrypt and verify assert!(msg.kem_decrypt(&kem_priv_key).is_ok()); ``` @@ -78,11 +78,10 @@ let mut msg = Message::new(get_random_bytes(5242880)); let key_pair = KeyPair::new( &get_random_bytes(64), // random password for key "test key".to_string(), // label - &SecParam::D256, // bit-security for key -) -.unwrap(); + SecParam::D256, // bit-security for key +); // Encrypt the message -assert!(msg.key_encrypt(&key_pair.pub_key, &SecParam::D256).is_ok()); +assert!(msg.key_encrypt(&key_pair.pub_key, SecParam::D256).is_ok()); // Decrypt and verify assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); ``` @@ -104,7 +103,7 @@ assert!(msg.aes_encrypt_ctr(&pw).is_ok()); // Decrypt the data assert!(msg.aes_decrypt_ctr(&pw).is_ok()); // Encrypt the data -assert!(msg.sha3_encrypt(&pw, &SecParam::D512).is_ok()); +assert!(msg.sha3_encrypt(&pw, SecParam::D512).is_ok()); // Decrypt and verify assert!(msg.sha3_decrypt(&pw).is_ok()); ``` @@ -122,11 +121,10 @@ let mut msg = Message::new(get_random_bytes(5242880)); let key_pair = KeyPair::new( &get_random_bytes(64), // random password for key "test key".to_string(), // label - &SecParam::D256, // bit-security for key -) -.unwrap(); + SecParam::D256, // bit-security for key +); // Sign with 128 bits of security -assert!(msg.sign(&key_pair, &SecParam::D256).is_ok()); +assert!(msg.sign(&key_pair, SecParam::D256).is_ok()); // Verify signature assert!(msg.verify(&key_pair.pub_key).is_ok()); ``` @@ -139,7 +137,7 @@ let mut data = Message::new(vec![]); // Obtained from echo -n "" | openssl dgst -sha3-256 let expected = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; // Compute a SHA3 digest with 128 bits of security -data.compute_sha3_hash(&SecParam::D256); +data.compute_sha3_hash(SecParam::D256); assert!(hex::encode(data.digest) == expected); ``` diff --git a/benches/benchmark_e448_224.rs b/benches/benchmark_e448_224.rs index f7e1077..e298ab1 100644 --- a/benches/benchmark_e448_224.rs +++ b/benches/benchmark_e448_224.rs @@ -17,7 +17,7 @@ fn sym_enc(pw: &[u8], mut msg: Message) { /// Asymmetric encrypt and decrypt roundtrip + keygen fn key_gen_enc_dec(pw: &[u8], mut msg: Message) { - let key_pair = KeyPair::new(pw, "test key".to_string(), BIT_SECURITY).unwrap(); + let key_pair = KeyPair::new(pw, "test key".to_string(), BIT_SECURITY); let _ = msg.key_encrypt(&key_pair.pub_key, BIT_SECURITY); let _ = msg.key_decrypt(&key_pair.priv_key); } @@ -32,7 +32,7 @@ fn bench_sign_verify(c: &mut Criterion) { c.bench_function("e448 + SHA3-224 Sign + Verify Roundtrip", |b| { b.iter(|| { sign_verify( - KeyPair::new(&get_random_bytes(16), "test key".to_string(), BIT_SECURITY).unwrap(), + KeyPair::new(&get_random_bytes(16), "test key".to_string(), BIT_SECURITY), Message::new(get_random_bytes(5242880)), ) }); @@ -54,9 +54,7 @@ fn bench_key_gen_enc_dec(c: &mut Criterion) { c.bench_function("e448 + SHA3-224 Asymmetric enc + dec", |b| { b.iter(|| { key_gen_enc_dec( - &KeyPair::new(&get_random_bytes(32), "test key".to_string(), BIT_SECURITY) - .unwrap() - .priv_key, + &KeyPair::new(&get_random_bytes(32), "test key".to_string(), BIT_SECURITY).priv_key, Message::new(get_random_bytes(5242880)), ) }); diff --git a/benches/benchmark_e448_512.rs b/benches/benchmark_e448_512.rs index 9c0a4b2..9f49d7c 100644 --- a/benches/benchmark_e448_512.rs +++ b/benches/benchmark_e448_512.rs @@ -17,7 +17,7 @@ fn sym_enc(pw: &[u8], mut msg: Message) { /// Asymmetric encrypt and decrypt roundtrip + keygen fn key_gen_enc_dec(pw: &[u8], mut msg: Message) { - let key_pair = KeyPair::new(pw, "test key".to_string(), BIT_SECURITY).unwrap(); + let key_pair = KeyPair::new(pw, "test key".to_string(), BIT_SECURITY); let _ = msg.key_encrypt(&key_pair.pub_key, BIT_SECURITY); let _ = msg.key_decrypt(&key_pair.priv_key); } @@ -32,7 +32,7 @@ fn bench_sign_verify(c: &mut Criterion) { c.bench_function("e448 + SHA3-512 Sign + Verify Roundtrip 5mb", |b| { b.iter(|| { sign_verify( - KeyPair::new(&get_random_bytes(16), "test key".to_string(), BIT_SECURITY).unwrap(), + KeyPair::new(&get_random_bytes(16), "test key".to_string(), BIT_SECURITY), Message::new(get_random_bytes(5242880)), ) }); @@ -54,9 +54,7 @@ fn bench_key_gen_enc_dec(c: &mut Criterion) { c.bench_function("e448 + SHA3-512 Asymmetric enc + dec 5mb", |b| { b.iter(|| { key_gen_enc_dec( - &KeyPair::new(&get_random_bytes(32), "test key".to_string(), BIT_SECURITY) - .unwrap() - .priv_key, + &KeyPair::new(&get_random_bytes(32), "test key".to_string(), BIT_SECURITY).priv_key, Message::new(get_random_bytes(5242880)), ) }); diff --git a/src/ecc/keypair.rs b/src/ecc/keypair.rs index c6395a7..afb480b 100644 --- a/src/ecc/keypair.rs +++ b/src/ecc/keypair.rs @@ -8,7 +8,7 @@ use std::fs::File; use std::io::Read; use tiny_ed448_goldilocks::curve::{extended_edwards::ExtendedPoint, field::scalar::Scalar}; -use crate::{sha3, OperationError, SecParam}; +use crate::{sha3, SecParam}; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] /// An object containing the fields necessary to represent an asymmetric keypair. @@ -40,16 +40,16 @@ impl KeyPair { /// verification key ๐‘‰ is hashed together with the message ๐‘š /// and the nonce ๐‘ˆ: hash (๐‘š, ๐‘ˆ, ๐‘‰) . #[allow(non_snake_case)] - pub fn new(pw: &[u8], owner: String, d: SecParam) -> Result { + pub fn new(pw: &[u8], owner: String, d: SecParam) -> KeyPair { let data = kmac_xof(pw, &[], 448, "SK", d); let s: Scalar = bytes_to_scalar(&data).mul_mod(&Scalar::from(4_u64)); let V = ExtendedPoint::generator() * s; - Ok(KeyPair { + KeyPair { owner, pub_key: V, priv_key: pw.to_vec(), date_created: get_date_and_time_as_string(), - }) + } } /// # KeyPair Saving diff --git a/src/main.rs b/src/main.rs index d61e34b..61616bf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,8 +60,7 @@ fn main() { output, } => { let sec_param = SecParam::try_from(bits).expect("Unsupported security parameter."); - let kp = KeyPair::new(pw.as_bytes(), owner, sec_param) - .expect("Unable to generate the requested key pair"); + let kp = KeyPair::new(pw.as_bytes(), owner, sec_param); let _ = kp.write_to_file(&output); } diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 0ea4779..45514e0 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -33,8 +33,7 @@ fn test_key_gen_enc_dec_256() { &get_random_bytes(64), // random password for key "test key".to_string(), // label SecParam::D256, // bit-security for key - ) - .unwrap(); + ); // Encrypt the message assert!(msg.key_encrypt(&key_pair.pub_key, SecParam::D256).is_ok()); // Decrypt and verify @@ -54,8 +53,7 @@ fn test_key_gen_enc_dec_512() { &get_random_bytes(32), "test key".to_string(), SecParam::D512, - ) - .unwrap(); + ); assert!(msg.key_encrypt(&key_pair.pub_key, SecParam::D512).is_ok()); assert!(msg.key_decrypt(&key_pair.priv_key).is_ok()); @@ -75,8 +73,7 @@ pub fn test_signature_256() { &get_random_bytes(64), // random password for key "test key".to_string(), // label SecParam::D256, // bit-security for key - ) - .unwrap(); + ); // Sign with 256 bits of security assert!(msg.sign(&key_pair, SecParam::D256).is_ok()); // Verify signature @@ -126,7 +123,7 @@ pub fn test_signature_512() { let mut msg = Message::new(get_random_bytes(5242880)); let pw = get_random_bytes(64); - let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512).unwrap(); + let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512); assert!(msg.sign(&key_pair, SecParam::D512).is_ok()); assert!(msg.verify(&key_pair.pub_key).is_ok()); @@ -149,7 +146,7 @@ fn test_sig_timing_side_channel() { for i in 0..10 { let mut msg = Message::new(get_random_bytes(5242880)); let pw = get_random_bytes(1 << i); - let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512).unwrap(); + let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512); let now = Instant::now(); let _ = msg.sign(&key_pair, SecParam::D512); @@ -170,8 +167,7 @@ fn test_reading_writing_keypair() { &get_random_bytes(32), "test key".to_string(), SecParam::D512, - ) - .expect("Failed to create key pair"); + ); let temp_dir = tempdir().expect("Failed to create temporary directory"); let temp_file_path = temp_dir.path().join("read_write_keypair.json"); @@ -196,8 +192,7 @@ pub fn test_signature_512_read_keypair_from_file() { let mut msg = Message::new(get_random_bytes(5242880)); let pw = get_random_bytes(64); - let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512) - .expect("Failed to create key pair"); + let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512); let temp_dir = tempdir().expect("Failed to create temporary directory"); let temp_file_path: std::path::PathBuf = temp_dir.path().join("read_write_keypair.json"); @@ -229,7 +224,7 @@ pub fn test_signature_512_read_message_from_file() { let mut initial_msg = Message::read_from_file(temp_file_path.to_str().unwrap()).unwrap(); let pw = get_random_bytes(64); - let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512).unwrap(); + let key_pair = KeyPair::new(&pw, "test key".to_string(), SecParam::D512); assert!(initial_msg.sign(&key_pair, SecParam::D512).is_ok()); @@ -277,8 +272,8 @@ mod decryption_test { let mut new_msg = Message::new(get_random_bytes(125)); // D512 - let key_pair1 = KeyPair::new(&get_random_bytes(32), "test key".to_string(), D512).unwrap(); - let key_pair2 = KeyPair::new(&get_random_bytes(32), "test key".to_string(), D512).unwrap(); + let key_pair1 = KeyPair::new(&get_random_bytes(32), "test key".to_string(), D512); + let key_pair2 = KeyPair::new(&get_random_bytes(32), "test key".to_string(), D512); let _ = new_msg.key_encrypt(&key_pair1.pub_key, D512); let new_msg2 = new_msg.msg.clone(); From cbcbda54c3be4ab8211201ca783fd7b39b5a3eaa Mon Sep 17 00:00:00 2001 From: dr Date: Fri, 28 Jun 2024 19:16:34 -0700 Subject: [PATCH 4/4] readme --- src/sha3/encryptable.rs | 1 - src/sha3/sponge.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sha3/encryptable.rs b/src/sha3/encryptable.rs index 0d92af5..cb7fd68 100644 --- a/src/sha3/encryptable.rs +++ b/src/sha3/encryptable.rs @@ -47,7 +47,6 @@ impl SpongeEncryptable for Message { /// # Symmetric Decryption /// Decrypts a [`Message`] (z, c, t) under passphrase pw. - /// ## Replaces: /// * `Message.data` with result of decryption. /// * `Message.op_result` with result of comparision of `Message.t` == keyed hash of decryption. diff --git a/src/sha3/sponge.rs b/src/sha3/sponge.rs index 0dcedb4..1403196 100644 --- a/src/sha3/sponge.rs +++ b/src/sha3/sponge.rs @@ -8,7 +8,7 @@ use super::constants::{BitLength, Rate}; // * m: message to be absorbed // * capacity: security parameter which determines rate = bit_width - capacity // * return: a state consisting of 25 words of 64 bits each. -pub(crate) fn sponge_absorb(m: &mut Vec, capacity: impl BitLength) -> [u64; 25] { +pub(crate) fn sponge_absorb(m: &mut Vec, capacity: C) -> [u64; 25] { let c = capacity.bit_length(); let r = (1600 - c) / 8; if (m.len() % r) != 0 {