diff --git a/Cargo.lock b/Cargo.lock index 003abcae1..1b1541f60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -810,6 +810,12 @@ dependencies = [ "tower-service", ] +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + [[package]] name = "backoff" version = "0.4.0" @@ -1019,9 +1025,15 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec", + "bit-vec 0.8.0", ] +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bit-vec" version = "0.8.0" @@ -1832,6 +1844,7 @@ version = "0.4.8" dependencies = [ "bcs", "fastcrypto 0.1.8", + "fastcrypto-lattice", "hex", "itertools 0.14.0", "rand 0.8.5", @@ -2658,6 +2671,26 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "fastcrypto-lattice" +version = "0.1.0" +dependencies = [ + "bit-vec 0.6.3", + "fastcrypto 0.1.9", + "hex", + "itertools 0.12.1", + "num", + "num-complex", + "once_cell", + "rand 0.8.5", + "rand_distr", + "rug", + "serde", + "serde_json", + "serde_with", + "sha3 0.10.8", +] + [[package]] name = "fastcrypto-tbls" version = "0.1.0" @@ -3096,6 +3129,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "gmp-mpfr-sys" +version = "1.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a636fb6a653382a379ee1e5593dacdc628667994167024c143214cafd40c1a86" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "governor" version = "0.6.3" @@ -6502,7 +6545,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set", - "bit-vec", + "bit-vec 0.8.0", "bitflags 2.6.0", "lazy_static", "num-traits", @@ -6830,6 +6873,16 @@ dependencies = [ "getrandom 0.3.3", ] +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -7171,6 +7224,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rug" +version = "1.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad2e973fe3c3214251a840a621812a4f40468da814b1a3d6947d433c2af11f" +dependencies = [ + "az", + "gmp-mpfr-sys", + "libc", + "libm", +] + [[package]] name = "rust_decimal" version = "1.37.1" @@ -7411,6 +7476,18 @@ dependencies = [ "serde_json", ] +[[package]] +name = "schemars" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "schemars_derive" version = "0.8.21" @@ -7713,9 +7790,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42" +checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" dependencies = [ "base64 0.22.1", "chrono", @@ -7723,6 +7800,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.7.0", "schemars 0.9.0", + "schemars 1.0.4", "serde", "serde_derive", "serde_json", @@ -7732,9 +7810,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81679d9ed988d5e9a5e6531dc3f2c28efbd639cbd1dfb628df08edea6004da77" +checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" dependencies = [ "darling 0.20.10", "proc-macro2", @@ -11409,7 +11487,7 @@ checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ "windows-result", "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-targets 0.53.3", ] [[package]] @@ -11466,6 +11544,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -11499,10 +11586,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", diff --git a/crates/crypto/Cargo.toml b/crates/crypto/Cargo.toml index 587a42090..eb51f1f82 100644 --- a/crates/crypto/Cargo.toml +++ b/crates/crypto/Cargo.toml @@ -14,5 +14,6 @@ bcs.workspace = true itertools.workspace = true serde_with.workspace = true sui_types.workspace = true +fastcrypto-lattice = { path = "../../../fastcrypto-lattice" } typenum = "1.18.0" \ No newline at end of file diff --git a/crates/crypto/src/lib.rs b/crates/crypto/src/lib.rs index 3d8aa9040..d457d0fba 100644 --- a/crates/crypto/src/lib.rs +++ b/crates/crypto/src/lib.rs @@ -7,6 +7,8 @@ use fastcrypto::error::FastCryptoError::{GeneralError, InvalidInput}; use fastcrypto::error::FastCryptoResult; use fastcrypto::groups::Scalar; use fastcrypto::hash::{HashFunction, Sha3_256}; +use fastcrypto_lattice::falcon_util::falcon; +use fastcrypto_lattice::ibe::{sample_polynomial, IBE}; use itertools::Itertools; use rand::thread_rng; use serde::{Deserialize, Serialize}; @@ -75,15 +77,20 @@ pub enum IBEEncryptions { encrypted_shares: Vec, encrypted_randomness: ibe::EncryptedRandomness, }, + Falcon512 { + encrypted_shares: Vec>, + }, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum IBEPublicKeys { BonehFranklinBLS12381(Vec), + Falcon512(Vec>), } pub enum IBEUserSecretKeys { BonehFranklinBLS12381(HashMap), + Falcon512(HashMap>), } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -163,13 +170,38 @@ pub fn seal_encrypt( encrypted_randomness, } } + IBEPublicKeys::Falcon512(pks) => { + if pks.len() != number_of_shares as usize { + return Err(InvalidInput); + } + let n = 512; + + let encrypted_shares = pks + .iter() + .zip(shares) + .map(|(pk, share)| { + let k = sample_polynomial(n, &mut rng, 0..=1); + let r = sample_polynomial(n, &mut rng, -1..=1); + let e1 = sample_polynomial(n, &mut rng, -1..=1); + let e2 = sample_polynomial(n, &mut rng, -1..=1); + + fastcrypto_lattice::ibe::FalconIBE::encrypt_deterministic( + (k, r, e1, e2), + pk, + &fastcrypto_lattice::ibe::Plaintext::<32>(share), + &full_id, + ) + }) + .collect_vec(); + IBEEncryptions::Falcon512 { encrypted_shares } + } }; // Derive the key used by the DEM let dem_key = derive_key( KeyPurpose::DEM, &base_key, - encrypted_shares.ciphertexts(), + &encrypted_shares.ciphertexts(), threshold, &key_servers, ); @@ -264,6 +296,31 @@ pub fn seal_decrypt( }) .collect_vec() } + ( + IBEEncryptions::Falcon512 { encrypted_shares }, + IBEUserSecretKeys::Falcon512(user_secret_keys), + ) => { + // Check that the encrypted object is valid, + // e.g., that there is an encrypted share of the key per service + if encrypted_shares.len() != services.len() { + return Err(InvalidInput); + } + + services + .iter() + .enumerate() + .map(|(i, (object_id, index))| { + let user_secret_key = user_secret_keys + .get(object_id) + .expect("This shouldn't happen: It's checked above that this secret key is available"); + (index, fastcrypto_lattice::ibe::FalconIBE::decrypt( + user_secret_key, + &encrypted_shares[i], + )) + }).map(|(index, share)| (*index, share.0)) + .collect_vec() + } + _ => panic!("This shouldn't happen: It's not checked above that this secret"), }; // Create the base key from the shares @@ -283,7 +340,7 @@ pub fn seal_decrypt( let dem_key = derive_key( KeyPurpose::DEM, &base_key, - encrypted_shares.ciphertexts(), + &encrypted_shares.ciphertexts(), *threshold, &services.iter().map(|(id, _)| *id).collect_vec(), ); @@ -378,19 +435,22 @@ impl IBEEncryptions { base_key: &[u8; KEY_SIZE], threshold: u8, ) -> FastCryptoResult> { - match self { - IBEEncryptions::BonehFranklinBLS12381 { - encrypted_randomness, - encrypted_shares, - nonce, - } => { + match (self, public_keys) { + ( + IBEEncryptions::BonehFranklinBLS12381 { + encrypted_randomness, + encrypted_shares, + nonce, + }, + IBEPublicKeys::BonehFranklinBLS12381(public_keys), + ) => { // Decrypt encrypted nonce, let randomness = ibe::decrypt_and_verify_nonce( encrypted_randomness, &derive_key( KeyPurpose::EncryptedRandomness, base_key, - self.ciphertexts(), + &self.ciphertexts(), threshold, &services.iter().map(|(id, _)| *id).collect_vec(), ), @@ -398,32 +458,33 @@ impl IBEEncryptions { )?; // Decrypt all shares - match public_keys { - IBEPublicKeys::BonehFranklinBLS12381(public_keys) => { - if public_keys.len() != encrypted_shares.len() { - return Err(InvalidInput); - } - public_keys - .iter() - .zip(encrypted_shares) - .zip(services) - .map(|((pk, ciphertext), service)| { - decrypt_deterministic(&randomness, ciphertext, pk, full_id, service) - .map(|plaintext| (service.1, plaintext)) - }) - .collect::>() - } + if public_keys.len() != encrypted_shares.len() { + return Err(InvalidInput); } + public_keys + .iter() + .zip(encrypted_shares) + .zip(services) + .map(|((pk, ciphertext), service)| { + decrypt_deterministic(&randomness, ciphertext, pk, full_id, service) + .map(|plaintext| (service.1, plaintext)) + }) + .collect::>() } + _ => unimplemented!(), } } /// Returns a binary representation of all encrypted shares. - fn ciphertexts(&self) -> &[impl AsRef<[u8]>] { + fn ciphertexts(&self) -> Vec> { match self { IBEEncryptions::BonehFranklinBLS12381 { encrypted_shares, .. - } => encrypted_shares, + } => encrypted_shares.iter().map(|c| c.to_vec()).collect_vec(), + IBEEncryptions::Falcon512 { encrypted_shares } => encrypted_shares + .iter() + .map(|c| bcs::to_bytes(c).unwrap().to_vec()) + .collect_vec(), } } } @@ -616,6 +677,57 @@ mod tests { ); } + #[test] + fn test_plain_round_trip_pq() { + let package_id = ObjectID::random(); + let id = vec![1, 2, 3, 4]; + let full_id = create_full_id(&package_id, &id); + + let keypairs = (0..3) + .map(|_| fastcrypto_lattice::ibe::FalconIBE::keygen(&mut thread_rng())) + .collect_vec(); + + let services = keypairs.iter().map(|_| ObjectID::random()).collect_vec(); + + let threshold = 1; + let public_keys = + IBEPublicKeys::Falcon512(keypairs.iter().map(|(pk, _)| pk.clone()).collect_vec()); + + let (encrypted, key) = seal_encrypt( + package_id, + id, + services.clone(), + &public_keys, + threshold, + EncryptionInput::Aes256Gcm { + data: b"Hello, World!".to_vec(), + aad: None, + }, + ) + .unwrap(); + + let user_secret_keys = services + .into_iter() + .zip(keypairs) + .map(|(s, kp)| { + ( + s, + fastcrypto_lattice::ibe::FalconIBE::extract(&kp.1, &full_id), + ) + }) + .collect(); + + assert_eq!( + b"Hello, World!".to_vec(), + seal_decrypt( + &encrypted, + &IBEUserSecretKeys::Falcon512(user_secret_keys), + None, + ) + .unwrap() + ); + } + #[test] fn typescript_test_vector() { let package_id = [0u8; 32]; @@ -782,7 +894,7 @@ mod tests { let dem_key = derive_key( KeyPurpose::DEM, &base_key, - encrypted_shares.ciphertexts(), + &encrypted_shares.ciphertexts(), threshold, &service_ids, );