diff --git a/Cargo.lock b/Cargo.lock index 667c4c298aa..f3b1d09628f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7621,7 +7621,6 @@ dependencies = [ "hex", "ic-crypto-internal-bls12-381-type", "ic-crypto-test-utils-reproducible-rng", - "ic-sha3 1.0.0", "rand 0.8.5", "rand_chacha 0.3.1", ] diff --git a/rs/crypto/internal/crypto_lib/bls12_381/type/src/lib.rs b/rs/crypto/internal/crypto_lib/bls12_381/type/src/lib.rs index 57fe1df6d3c..b4a9fb47aba 100644 --- a/rs/crypto/internal/crypto_lib/bls12_381/type/src/lib.rs +++ b/rs/crypto/internal/crypto_lib/bls12_381/type/src/lib.rs @@ -31,7 +31,7 @@ pub type NodeIndex = u32; #[cfg(test)] mod tests; -use ic_bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve}; +use ic_bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField}; use itertools::multiunzip; use pairing::group::{ff::Field, Group}; use paste::paste; @@ -234,6 +234,18 @@ impl Scalar { Self::new(ic_bls12_381::Scalar::one()) } + /// Hash to scalar + /// + /// Uses the same mechanism as RFC 9380's hash_to_field except + /// targeting the scalar group. + pub fn hash(domain_sep: &[u8], input: &[u8]) -> Self { + let mut s = [ic_bls12_381::Scalar::zero()]; + ::hash_to_field::>( + input, domain_sep, &mut s, + ); + Self::new(s[0]) + } + /// Return true iff this value is zero pub fn is_zero(&self) -> bool { bool::from(self.value.is_zero()) diff --git a/rs/crypto/internal/crypto_lib/bls12_381/type/tests/tests.rs b/rs/crypto/internal/crypto_lib/bls12_381/type/tests/tests.rs index 4cc6aceafb8..7648996cfaa 100644 --- a/rs/crypto/internal/crypto_lib/bls12_381/type/tests/tests.rs +++ b/rs/crypto/internal/crypto_lib/bls12_381/type/tests/tests.rs @@ -1332,6 +1332,39 @@ fn test_verify_bls_signature_batch_with_same_pk() { } } +#[test] +fn test_hash_to_scalar_matches_known_values() { + // I was not able to locate any official test vectors for BLS12-381 hash_to_scalar + // so these were just generated using ic_bls12_381 itself. + + let dst = b"QUUX-V01-CS02-with-BLS12381SCALAR_XMD:SHA-256_SSWU_RO_"; + + scalar_test_encoding( + Scalar::hash(&dst[..], b""), + "3b3fdf74b194c0a0f683d67a312a4e72d663d74b8478dc7b56be41e0ce11caa1", + ); + + scalar_test_encoding( + Scalar::hash(&dst[..], b"abc"), + "47e7a8839695a3df27f202cf71e295a8554b47cef75c1e316b1865317720e188", + ); + + scalar_test_encoding( + Scalar::hash(&dst[..], b"abcdef0123456789"), + "3dff572f262e702f2ee8fb79b70e3225f5ee543a389eea2e58eec7b2bfd6afeb", + ); + + scalar_test_encoding( + Scalar::hash(&dst[..], format!("q128_{}", "q".repeat(128)).as_bytes()), + "2874c0e7814fcf42a5f63258417d4be8ea0465ff7352691493d0eca2dd5a9729", + ); + + scalar_test_encoding( + Scalar::hash(&dst[..], format!("a512_{}", "a".repeat(512)).as_bytes()), + "3cf6864b1a81fba0798c370f6daf9c23a838f9dbb96ea3a3a1145899ddf259b4", + ); +} + #[test] fn test_hash_to_g1_matches_draft() { /* diff --git a/rs/crypto/internal/crypto_lib/bls12_381/vetkd/BUILD.bazel b/rs/crypto/internal/crypto_lib/bls12_381/vetkd/BUILD.bazel index 039aea2f17d..7ec5c5b6967 100644 --- a/rs/crypto/internal/crypto_lib/bls12_381/vetkd/BUILD.bazel +++ b/rs/crypto/internal/crypto_lib/bls12_381/vetkd/BUILD.bazel @@ -5,7 +5,6 @@ package(default_visibility = ["//rs/crypto:__subpackages__"]) DEPENDENCIES = [ # Keep sorted. - "//packages/ic-sha3", "//rs/crypto/internal/crypto_lib/bls12_381/type", "@crate_index//:rand", ] diff --git a/rs/crypto/internal/crypto_lib/bls12_381/vetkd/Cargo.toml b/rs/crypto/internal/crypto_lib/bls12_381/vetkd/Cargo.toml index 091fe601ccb..539f80ff069 100644 --- a/rs/crypto/internal/crypto_lib/bls12_381/vetkd/Cargo.toml +++ b/rs/crypto/internal/crypto_lib/bls12_381/vetkd/Cargo.toml @@ -8,7 +8,6 @@ documentation.workspace = true [dependencies] ic-crypto-internal-bls12-381-type = { path = "../type" } -ic-sha3 = { path = "../../../../../../packages/ic-sha3" } rand = { workspace = true } [dev-dependencies] diff --git a/rs/crypto/internal/crypto_lib/bls12_381/vetkd/src/lib.rs b/rs/crypto/internal/crypto_lib/bls12_381/vetkd/src/lib.rs index e7c6bafd5b8..c57013b6f7d 100644 --- a/rs/crypto/internal/crypto_lib/bls12_381/vetkd/src/lib.rs +++ b/rs/crypto/internal/crypto_lib/bls12_381/vetkd/src/lib.rs @@ -10,8 +10,6 @@ use ic_crypto_internal_bls12_381_type::{G2Prepared, Gt, LagrangeCoefficients}; use rand::{CryptoRng, RngCore}; -mod ro; - /// The index of a node pub type NodeIndex = u32; @@ -21,18 +19,26 @@ pub struct DerivationPath { delta: Scalar, } +const DERIVATION_PATH_DOMAIN_SEP: &[u8; 44] = b"ic-crypto-vetkd-bls12-381-g2-derivation-path"; + impl DerivationPath { /// Create a new derivation path pub fn new>(canister_id: &[u8], extra_paths: &[U]) -> Self { - let mut ro = ro::RandomOracle::new("ic-crypto-vetkd-bls12-381-derivation-path"); + let mut combined_inputs = vec![]; - ro.update_bin(canister_id); + // Each input is prefixed with an 8 byte length field + let len = canister_id.len() as u64; + combined_inputs.extend_from_slice(&len.to_be_bytes()); + combined_inputs.extend_from_slice(canister_id); - for path in extra_paths { - ro.update_bin(path.as_ref()); + for input in extra_paths { + let len = input.as_ref().len() as u64; + combined_inputs.extend_from_slice(&len.to_be_bytes()); // 8 bytes length + combined_inputs.extend_from_slice(input.as_ref()); } - let delta = ro.finalize_to_scalar(); + let delta = Scalar::hash(DERIVATION_PATH_DOMAIN_SEP, &combined_inputs); + Self { delta } } diff --git a/rs/crypto/internal/crypto_lib/bls12_381/vetkd/src/ro.rs b/rs/crypto/internal/crypto_lib/bls12_381/vetkd/src/ro.rs deleted file mode 100644 index 96fb4677c4e..00000000000 --- a/rs/crypto/internal/crypto_lib/bls12_381/vetkd/src/ro.rs +++ /dev/null @@ -1,43 +0,0 @@ -use ic_crypto_internal_bls12_381_type::Scalar; -use ic_sha3::Shake256; - -#[derive(Clone)] -pub(crate) struct RandomOracle { - shake: Shake256, -} - -impl RandomOracle { - pub(crate) fn new(domain_separator: &str) -> Self { - let mut ro = Self { - shake: Shake256::default(), - }; - - ro.update_str(domain_separator); - - ro - } - - pub(crate) fn update_str(&mut self, s: &str) { - self.update_bin(s.as_bytes()); - } - - pub(crate) fn update_bin(&mut self, v: &[u8]) { - let v_len = v.len() as u64; - self.shake.update(v_len.to_be_bytes()); - self.shake.update(v); - } - - fn finalize(mut self, output: &mut [u8]) { - let o_len = output.len() as u64; - self.shake.update(o_len.to_be_bytes()); - - let mut xof = self.shake.finalize_xof(); - xof.read(output); - } - - pub(crate) fn finalize_to_scalar(self) -> Scalar { - let mut output = [0u8; 2 * Scalar::BYTES]; - self.finalize(&mut output); - Scalar::from_bytes_wide(&output) - } -} diff --git a/rs/crypto/internal/crypto_lib/bls12_381/vetkd/tests/tests.rs b/rs/crypto/internal/crypto_lib/bls12_381/vetkd/tests/tests.rs index 016f96bb3cd..ddd197d8980 100644 --- a/rs/crypto/internal/crypto_lib/bls12_381/vetkd/tests/tests.rs +++ b/rs/crypto/internal/crypto_lib/bls12_381/vetkd/tests/tests.rs @@ -110,15 +110,6 @@ fn random_derivation_path(rng: &mut R) -> DerivationPath DerivationPath::new(&canister_id, &extra_paths) } -fn shake256(bytes: &[u8]) -> [u8; 32] { - let mut output = [0u8; 32]; - let mut shake = ic_sha3::Shake256::new(); - shake.update(bytes); - let mut xof_reader = shake.finalize_xof(); - xof_reader.read(&mut output); - output -} - #[test] fn encrypted_key_share_creation_is_stable() { let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(1); @@ -136,27 +127,27 @@ fn encrypted_key_share_creation_is_stable() { let derivation_path = random_derivation_path(&mut rng); let did = rng.gen::<[u8; 28]>(); - const EXPECTED_EKS_HASH: [&str; NODES] = [ - "cb3075ecd2c5cd946dcfaf8486031cf7bbca656092aada97644307c598af5073", - "fbfaa432bd0fc9c60b456742368034d35d5fefceae1cdd027c27147ecc7f012c", - "7d6bd8ef201443fe5b570b62d244fc8192819f53783a1ae81e3fe747a793decd", - "12f894d3ddce41e5fa0cb1cd05e77d50ed214248cba809a9fe6fccf5515f5c13", - "d187e7bf4defab92ce9c82c692a9b3c3de65994cd4bf422438cbc515a8a48501", - "9aa47ad2dcf06a6a308152d935698684799714c772dfaf2b6654e6642a11937b", - "d96c4f897ba7e7ac657d363171b324adbad2faf13ef395bd0efa28a60273583d", - "fc3b2d0eae4c7d96212058d815d48701267a673c20197a08f28762301043405d", - "85ba21972c3a7717922d6bc734217d5dae12be7df42ffb93604e0ae7228ac9ed", - "3f7b6c16d35118519c92d31e074633f00fe30b6e4b522cda47d81088dc4011bb", - "658383824de7771db64a87b884ffbefe92567baeb851229785d9f3717c91bdda", - "e7a69b641278a5a8084938d1c03de2850a6639a882713a190fe0417f678e118e", - "d59283b0a48181d93c6e1a22e5ff9130df68a01bcadf96a25d37a2a092cb1a1a", + const EXPECTED_EKS_VALUE: [&str; NODES] = [ + "a9940d0137c71275b4d11bf9a80bcf484a93e777a20734b95dd57e835ac484661f4056bbd4fa3ed218f50d967617c2b781516e7bd2baace117b77803686953aaebba83589a10a15b7a139da6dc3f1093561ccce5ded1ad7bfed4e35a198a0a0e14936d6a37ebba930bfae338185ac104c4ef67f899c0cc25467f80f09a886574dbc0642a6ed1a2516d4f7c90c9128610ae6d24d5bea60cdc939f5ebe2a98ce274cbb57003db162bac370a255eeab6ba1ff639d19fe97d61045a671162b15fe60", +"b9d2a21b758fc961c8a98dc7aa5a5597bcbc365134d3da90527a6b60a30831803afd52fc5e0163c5fd43154c0d2177f49317ddf48515edd84ccf2ecd8724f808b24ca44f10a684cdc4eb56f23c2f2a5152c44cbb59a0c70155aecda3f95710770582abdf6febb54b078a90b96af6fb1b27073dd10cd5366e1e6ce378d882b7251f361d4979388d0a8efe288811adb3b5a24f833bdb6fa7dda962970410ab4364c2a837781176187fa62ff51841f81a8f6bbea3e7b171ebb93d4ce11bd9be7b4d", +"811d9cd064cd7c6ab4a448c68b8b5fc8a5f08cd17c78d46469e810e8df3d1f8d3f1431ccf627e2198b72d850eb99b2e2b2dfe2c43ddf86e5403ba474a3a0ba596ddabecfe303eddfd70444057baaae733f92eca70509425f87633ce9d78a28040b559446e22f73d637b04c6eca6ecff71fb3d1a662d86ef22fa6c3ef8157c582e4afdc7a0047d4535c6e01e9c65eae7890de3f7362e9d027f847484e5e3a2734c57f02030c44425012f17277c825d8093bef8862bd69753c7ac0d80b45c4257c", +"aca469bb1dd96297c86044e6032c15fbf2a2c380764085be21d50cff4b9f52f5e32e8c7fd718d64b435334b4aa9f8016a4dbcedc7da27a8b23d4b254850a26e75cb7e744585f0bcf5fb4b7ffb7befa0a983cbff9de8d22be23f6674a32fd058a03f31140af7af5934a23ef4494fe1bd2ff3947dae35f4bc653388878fdea0a451d7bdd1ecaabec217faa1efcf24dd5a68aaae8ce07882503721cbbb0a6afed9bdfe611b6e6f70cf1f36300d296d97c284bdc1c06f2fad6c3b9b3f2bed39f6f6d", +"abc9b461b441ce17b4d581f5a82f0f21dfb0091c9c097e2f4ce7962adf7c14d14d86c9765dc2e296c66a02187699fbe396767f7fdbe594a787368bb59ef5d43b70bd0c7a39e07b27107cdc7fb06de7da15a2a33cd10593b65764c98a7591726a0f603451396769fdaf5bd3b69ff0b7f515b4fd1dd0629b3762bc3916b8c2e01d2bfd5ddebc9f638191cc919da5a5d619864bc64eaa58a9af0a48487c12040619f1d45e5c42959b7cc89e036caeb207e9e33def185af6b4f11c06ba9d7505b800", +"92ef0d8f00e18f23879783c51c72b9706c7ad0df2a2ba44d651c5c3d903431ca49732637a579eb8c423e2b79faf9fb0b95fb96958149013e2932286ccf93bcbb94386df13e0519927b231a39f9a40b82bcd7fea94490e574493fa38a7a809a2211f4f2296639157bfe932518a5b4d8ccee3ac4997dce11aab4ff31633f715c1b1c3a6cc3a9ee14b879d0c890721d0e3f833c9383b01a183c11076f08c6e70fa1d4e14189878614ba5c49631f013f2b680ec56d582bf1ca5ac17a96bee0c80925", +"8efef76050abe03984f8b22b1cd6075a89e361c8f70bd2b493185d710ff284cca2d32c41d05735f5d9f39a4ea9b5e2cb8b4b207ec0d535c835768f95a0a1e13018b185b77f6e506fe85c2014989113b2c59935f2e323db5913bdddff8b56aa5a000a6f4e4c409a9ead3945979e3914e903b75bf754587ffbcead720960dfbcb6407d193acc91734cf61ef47d8b8684c59575f5590e3a5cc065f065f9adf4e30cbf6fe3f2469eeacb0c8baae349f86f1c0d0ac6dafb600c7a8feb05cbd8490fb5", +"80ac9ea725ec6101b18e316e7f8ff9cdbf7619549b5b9cea767203deb4b0e0496c1c84e828e74268d2368937e7f9a34195b3697321df62a084bcc2cc2bf079ce2638625bbf243d906130a700908ce481dbbe1d32b014e89baef97cc10aa6f914092a904efd5d904a1ed3687361a186126858f14bc84cdd00cc0c4671313874f1ebedf1bddc3bb3d0484e23dfc754a6768b55ea732ff9c02a374c8e1fef793c01b37c464099a2863cb4c15469c4d867083db6924fb4cceda762d10a01777cdc97", +"92b3a643f608fd4ccbb7644cbb1b38ac39a6cb4461846c6cf79c3610a411fd4e8709b960260966586f67e2e0d6cf6c5b85b45c442c3f78bda0666389631a8a8c8b1c642eaa4c0214781c6ada600fd1a7663b43b844a6f7a96741315674090b7f10534d4789de9fc1829b7a97f30dedd86b8f801ac01c1f8a8e1fb247cec9f726dabe43a6f246e7248b8a6675370c47318a3c4788b4eb5092b283f7f81f6a5903c35f024159b8fc5bd2a01a4dc118b1855bcbd409abe6d54bc3daaf795694a580", +"807e2fa6fe3e4bec12953acc2b57bf4cd49614cfbccb393bbaa4a04d614f1b85a7bbae48ed5c147e05786a7a29494c2092cfd5bd41d088213fa676abd137ad6e4511ff65811c7622068d995c1d38e36f5a90284c7a5769510c1e71fb46bace121742873aa75b1956f331d13e7541fdd862d617965ed541376598a541bf2bc47e370f728e86c909b943b1db0cf6e38dba8b4ef50a2cb42410b5ccd9c2788a49df08585284c4dadeb7ff93befe0beb46ca998041ece1dd36832e5e44783f0e6005", +"b90e01a902b1af0a9039d32b1325c030424791d2a7c72dbb68cf17c962b80e2897b29bccf1bda9587f62d019098938b1b68aaf0628576dd28569de2bbc705ac51ae9e69552e912894b47d87d3af588466ad30316de574dd7663129ee342c949f101501911075cb27af2255635e9ea68401ccda1edf127ec3472d1018b0e1a012d352849ef40b835ab5357785798bbd15a90db5211cc61dd44b1660a6a2d68deb708d772b8b32fa29e9c5890ffd812709913c0488c159fe44bb8582677d171950", +"b653a21c480fccfb9b69419240cdb530e18f23b8a2bc5296073e8bea44f49104172158f2e2deec0cc1f6ed44d667bab5ab0cabfb9bd23b775fc903c2d2ddb3874c522c54e3465ed7ebbb8cec4f3e0bbca5537c8e4792a4bd0ce0e81196c49e14046ea5482f08f760d3be6b524a86f81771934cc91e1f6ed5aafc38f236ae74eba2d3d21458c0d19907b762a8fa2b860dac60873dda48bca15a4363b1271354e6623438ca5075e19a6f967c4912d8ce193e3f1f9de3f20c26a4d3bc2f7041b319", +"8489576ac848031c6e90ad9e0477fc72e766ccf00894db8ae9536415d817a4478726e4e1247ffa8656209a23ca261fa088312490c4d7b4f029f9b944196e4e3f1eb52c6a89e1ba9fc87f42c09ed3ae1490d10cdbda013863c775f00f3d070de413af98b3b688a397ab4124bc316876a4c015059607040c9faed27191db1e875e072c923fb4575f771cdb70f4ef0fbd7390b77f611ca8840b31d5d353a0039b011fc798ba380c99ed00ab4a3fedba0ded56dd630655431784d1a02767f44bfa85", ]; - for (node_idx, expected_eks_hash) in EXPECTED_EKS_HASH.iter().enumerate() { + for (node_idx, expected_eks) in EXPECTED_EKS_VALUE.iter().enumerate() { let node_sk = poly.evaluate_at(&Scalar::from_node_index(node_idx as u32)); let eks = EncryptedKeyShare::create(&mut rng, &master_pk, &node_sk, &tpk, &derivation_path, &did); - assert_eq!(hex::encode(shake256(&eks.serialize())), *expected_eks_hash,); + assert_eq!(*expected_eks, hex::encode(eks.serialize())); } } diff --git a/rs/crypto/internal/crypto_service_provider/src/vault/local_csp_vault/vetkd/tests.rs b/rs/crypto/internal/crypto_service_provider/src/vault/local_csp_vault/vetkd/tests.rs index 68108017335..af79065b791 100644 --- a/rs/crypto/internal/crypto_service_provider/src/vault/local_csp_vault/vetkd/tests.rs +++ b/rs/crypto/internal/crypto_service_provider/src/vault/local_csp_vault/vetkd/tests.rs @@ -36,9 +36,9 @@ fn should_correctly_create_encrypted_vetkd_key_share_for_smoke_test_vector() { f3e68e13f62604d027660883213c90ea72810bcecee58b883fb62118e538243\ 03718e6876ea400d083beb0439d3934122a4c4b2e58e3f145305b9a0c0a00e3\ 2dd808574dec2605dbc7f122fe593ca0c07ca92720d0f17b7d53c9c68dbb93d\ - 489078859e5e5fe2b6612ac9536fe7f8b463cac948e6db97908b7f5a67b33b3\ - e60a1c160889ef49448519a84be1aba0611829a7cca180cbbdf94f7b2cda2db\ - 6b14c65", + 489078859e5e5fe2b6612ac9536fe7f8b463cafcc003efe88f1cddd26499322\ + 9229edb5ec96ea3fd2d083b815776b6cc7e03586d864374ba54d44c09201db8\ + d33dd44", ) .expect("invalid test vector") ))