From e7e70c05d448a8ca48fd0d237d112bdbbccd5637 Mon Sep 17 00:00:00 2001 From: Jay Geng Date: Tue, 13 Aug 2024 23:35:58 -0400 Subject: [PATCH 01/18] implement bls12-381 functions with tests bump protocol_version locally add basic g1/g2_add test expose dst add mult-pairing-check update scalar to use U256 representation update env update env pick up xdr change bump sdk version implement bls12-381 --- Cargo.lock | 800 ++++++++++++---------- Cargo.toml | 8 +- soroban-sdk/src/crypto.rs | 384 ++++++++++- soroban-sdk/src/env.rs | 7 + soroban-sdk/src/num.rs | 21 + soroban-sdk/src/tests.rs | 1 + soroban-sdk/src/tests/crypto_bls12_381.rs | 140 ++++ 7 files changed, 1001 insertions(+), 360 deletions(-) create mode 100644 soroban-sdk/src/tests/crypto_bls12_381.rs diff --git a/Cargo.lock b/Cargo.lock index d5cd71e27..e78b62f9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "ahash" version = "0.8.11" @@ -54,32 +39,135 @@ dependencies = [ ] [[package]] -name = "arrayvec" -version = "0.7.6" +name = "ark-bls12-381" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] [[package]] -name = "autocfg" -version = "1.1.0" +name = "ark-ec" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "zeroize", +] [[package]] -name = "backtrace" -version = "0.3.69" +name = "ark-ff" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", ] +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + [[package]] name = "base16ct" version = "0.2.0" @@ -100,9 +188,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -127,15 +215,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -148,9 +230,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes-lit" @@ -161,16 +249,16 @@ dependencies = [ "num-bigint", "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] name = "cc" -version = "1.0.83" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" dependencies = [ - "libc", + "shlex", ] [[package]] @@ -181,34 +269,34 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets 0.48.5", + "windows-targets", ] [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -248,12 +336,12 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" +checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn", + "syn 2.0.77", ] [[package]] @@ -280,14 +368,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] name = "darling" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -295,34 +383,40 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn", + "syn 2.0.77", ] [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn", + "syn 2.0.77", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "zeroize", @@ -330,14 +424,25 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", "serde", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_arbitrary" version = "1.3.2" @@ -346,7 +451,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] @@ -369,15 +474,15 @@ dependencies = [ [[package]] name = "downcast-rs" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "ecdsa" -version = "0.16.7" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "digest", @@ -413,9 +518,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -443,9 +548,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -465,9 +570,9 @@ checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "ff" @@ -481,9 +586,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.5" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "fnv" @@ -504,9 +609,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -515,12 +620,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - [[package]] name = "group" version = "0.13.0" @@ -540,9 +639,18 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", ] @@ -573,9 +681,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -613,12 +721,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -628,6 +736,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.11.0" @@ -639,24 +756,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "k256" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ "cfg-if", "ecdsa", @@ -666,24 +783,24 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" @@ -693,30 +810,21 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "multi-stash" @@ -726,60 +834,55 @@ checksum = "685a9ac4b61f4e728e1d2c6a7844609c16527aeb5e6c865915c08e619c16410f" [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] -[[package]] -name = "object" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "p256" @@ -795,9 +898,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pkcs8" @@ -817,15 +920,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", @@ -833,12 +939,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.15" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.77", ] [[package]] @@ -852,22 +958,22 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.4.1", + "bitflags", "lazy_static", "num-traits", "rand", @@ -897,9 +1003,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -943,20 +1049,11 @@ dependencies = [ "rand_core", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rfc6979" @@ -968,28 +1065,22 @@ dependencies = [ "subtle", ] -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.26" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ - "bitflags 2.4.1", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1010,15 +1101,15 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "sec1" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", @@ -1029,53 +1120,55 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.192" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_with" -version = "3.4.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ - "base64 0.21.5", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.1.0", + "indexmap 2.5.0", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -1083,14 +1176,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.4.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] @@ -1114,11 +1207,17 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", "rand_core", @@ -1133,18 +1232,18 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "soroban-builtin-sdk-macros" version = "22.0.0" -source = "git+https://github.com/stellar/rs-soroban-env?rev=75b782119942a4c8be8003f2901db38b30b6db2d#75b782119942a4c8be8003f2901db38b30b6db2d" +source = "git+https://github.com/stellar/rs-soroban-env?rev=0497816694bef2b103494c8c61b7c8a06a72c7d3#0497816694bef2b103494c8c61b7c8a06a72c7d3" dependencies = [ - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] name = "soroban-env-common" version = "22.0.0" -source = "git+https://github.com/stellar/rs-soroban-env?rev=75b782119942a4c8be8003f2901db38b30b6db2d#75b782119942a4c8be8003f2901db38b30b6db2d" +source = "git+https://github.com/stellar/rs-soroban-env?rev=0497816694bef2b103494c8c61b7c8a06a72c7d3#0497816694bef2b103494c8c61b7c8a06a72c7d3" dependencies = [ "arbitrary", "crate-git-revision", @@ -1162,7 +1261,7 @@ dependencies = [ [[package]] name = "soroban-env-guest" version = "22.0.0" -source = "git+https://github.com/stellar/rs-soroban-env?rev=75b782119942a4c8be8003f2901db38b30b6db2d#75b782119942a4c8be8003f2901db38b30b6db2d" +source = "git+https://github.com/stellar/rs-soroban-env?rev=0497816694bef2b103494c8c61b7c8a06a72c7d3#0497816694bef2b103494c8c61b7c8a06a72c7d3" dependencies = [ "soroban-env-common", "static_assertions", @@ -1171,9 +1270,12 @@ dependencies = [ [[package]] name = "soroban-env-host" version = "22.0.0" -source = "git+https://github.com/stellar/rs-soroban-env?rev=75b782119942a4c8be8003f2901db38b30b6db2d#75b782119942a4c8be8003f2901db38b30b6db2d" +source = "git+https://github.com/stellar/rs-soroban-env?rev=0497816694bef2b103494c8c61b7c8a06a72c7d3#0497816694bef2b103494c8c61b7c8a06a72c7d3" dependencies = [ - "backtrace", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", "curve25519-dalek", "ecdsa", "ed25519-dalek", @@ -1196,22 +1298,22 @@ dependencies = [ "soroban-env-common", "soroban-wasmi", "static_assertions", - "stellar-strkey", + "stellar-strkey 0.0.9", "wasmparser", ] [[package]] name = "soroban-env-macros" version = "22.0.0" -source = "git+https://github.com/stellar/rs-soroban-env?rev=75b782119942a4c8be8003f2901db38b30b6db2d#75b782119942a4c8be8003f2901db38b30b6db2d" +source = "git+https://github.com/stellar/rs-soroban-env?rev=0497816694bef2b103494c8c61b7c8a06a72c7d3#0497816694bef2b103494c8c61b7c8a06a72c7d3" dependencies = [ - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "serde", "serde_json", "stellar-xdr", - "syn", + "syn 2.0.77", ] [[package]] @@ -1247,7 +1349,7 @@ dependencies = [ "soroban-ledger-snapshot", "soroban-sdk-macros", "soroban-spec", - "stellar-strkey", + "stellar-strkey 0.0.8", "stellar-xdr", ] @@ -1257,7 +1359,7 @@ version = "22.0.0-rc.1" dependencies = [ "crate-git-revision", "darling", - "itertools", + "itertools 0.11.0", "proc-macro2", "quote", "rustc_version", @@ -1266,7 +1368,7 @@ dependencies = [ "soroban-spec", "soroban-spec-rust", "stellar-xdr", - "syn", + "syn 2.0.77", ] [[package]] @@ -1291,7 +1393,7 @@ dependencies = [ "sha2", "soroban-spec", "stellar-xdr", - "syn", + "syn 2.0.77", "thiserror", ] @@ -1351,10 +1453,21 @@ dependencies = [ "thiserror", ] +[[package]] +name = "stellar-strkey" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e3aa3ed00e70082cb43febc1c2afa5056b9bb3e348bbb43d0cd0aa88a611144" +dependencies = [ + "crate-git-revision", + "data-encoding", + "thiserror", +] + [[package]] name = "stellar-xdr" version = "22.0.0" -source = "git+https://github.com/stellar/rs-stellar-xdr?rev=39d7dbb0c12bd422ee43a6e2e3277789da4eaac8#39d7dbb0c12bd422ee43a6e2e3277789da4eaac8" +source = "git+https://github.com/stellar/rs-stellar-xdr?rev=b5516843b6379e4e29520bf2ba156484f62edc46#b5516843b6379e4e29520bf2ba156484f62edc46" dependencies = [ "arbitrary", "base64 0.13.1", @@ -1363,7 +1476,7 @@ dependencies = [ "hex", "serde", "serde_with", - "stellar-strkey", + "stellar-strkey 0.0.9", ] [[package]] @@ -1373,27 +1486,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c6a0d765f5807e98a091107bae0a56ea3799f66a5de47b2c84c94a39c09974e" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.39" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -1402,15 +1526,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "once_cell", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1563,32 +1687,33 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] name = "time" -version = "0.3.30" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -1603,10 +1728,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -1624,15 +1750,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" @@ -1651,34 +1777,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1686,22 +1813,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasmi_collections" @@ -1709,7 +1836,7 @@ version = "0.36.0-soroban.22.0.0" source = "git+https://github.com/stellar/wasmi?rev=122a74a7c491929e5ac9de876099154ef7c06d06#122a74a7c491929e5ac9de876099154ef7c06d06" dependencies = [ "ahash", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "string-interner", ] @@ -1730,7 +1857,7 @@ version = "0.116.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.5.0", "semver", ] @@ -1745,20 +1872,11 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -1767,128 +1885,87 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "windows_i686_gnu" -version = "0.52.0" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "zerocopy" @@ -1896,6 +1973,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -1907,11 +1985,25 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] diff --git a/Cargo.toml b/Cargo.toml index 8ac1707fb..0a2683ba2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,17 +26,17 @@ soroban-token-sdk = { version = "22.0.0-rc.1", path = "soroban-token-sdk" } [workspace.dependencies.soroban-env-common] version = "=22.0.0" git = "https://github.com/stellar/rs-soroban-env" -rev = "75b782119942a4c8be8003f2901db38b30b6db2d" +rev = "0497816694bef2b103494c8c61b7c8a06a72c7d3" [workspace.dependencies.soroban-env-guest] version = "=22.0.0" git = "https://github.com/stellar/rs-soroban-env" -rev = "75b782119942a4c8be8003f2901db38b30b6db2d" +rev = "0497816694bef2b103494c8c61b7c8a06a72c7d3" [workspace.dependencies.soroban-env-host] version = "=22.0.0" git = "https://github.com/stellar/rs-soroban-env" -rev = "75b782119942a4c8be8003f2901db38b30b6db2d" +rev = "0497816694bef2b103494c8c61b7c8a06a72c7d3" [workspace.dependencies.stellar-strkey] version = "=0.0.8" @@ -46,7 +46,7 @@ version = "=22.0.0" default-features = false features = ["curr"] git = "https://github.com/stellar/rs-stellar-xdr" -rev = "39d7dbb0c12bd422ee43a6e2e3277789da4eaac8" +rev = "b5516843b6379e4e29520bf2ba156484f62edc46" #[patch."https://github.com/stellar/rs-soroban-env"] #soroban-env-common = { path = "../rs-soroban-env/soroban-env-common" } diff --git a/soroban-sdk/src/crypto.rs b/soroban-sdk/src/crypto.rs index 731f26b8b..8c19794cd 100644 --- a/soroban-sdk/src/crypto.rs +++ b/soroban-sdk/src/crypto.rs @@ -1,9 +1,11 @@ //! Crypto contains functions for cryptographic functions. use crate::{ - env::internal, env::internal::BytesObject, unwrap::UnwrapInfallible, Bytes, BytesN, - ConversionError, Env, IntoVal, TryFromVal, Val, + env::internal::{self, BytesObject, U64Val}, + unwrap::{UnwrapInfallible, UnwrapOptimized}, + Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, TryIntoVal, Val, Vec, U256, }; +use core::{cmp::Ordering, fmt::Debug}; /// A BytesN generated by a cryptographic hash function. /// @@ -251,3 +253,381 @@ impl CryptoHazmat { .unwrap_infallible(); } } + +/// Bls12_381 provides access to curve and field arithmetics on the BLS12-381 +/// curve. +pub struct Bls12_381 { + env: Env, +} + +/// # `G1Affine` is a point in the G1 group (subgroup defined over the base field +/// `Fq`) of the BLS12-381 elliptic curve +/// +/// # Serialization: +/// - The 96 bytes represent the **uncompressed encoding** of a point in G1. The +/// Bytes consist of `be_byte(X) || be_byte(Y)` (`||` is concatenation), +/// where 'X' and 'Y' are the two coordinates, each being a base field element +/// `Fp` +/// - The most significant three bits (bits 0-3) of the first byte are reserved +/// for encoding flags: +/// - compression_flag (bit 0): Must always be set (1), as only uncompressed +/// points are supported. +/// - infinity_flag (bit 1): Set if the point is the point at infinity (zero +/// point), in which case all other bits must be zero. +/// - sort_flag (bit 2): Must always be unset (0). +/// +/// # Example Usage: +/// ```rust +/// use soroban_sdk::{Env, bytesn, crypto::{Bls12_381, G1Affine}}; +/// let env = Env::default(); +/// let bls12_381 = env.bls12_381(); +/// let zero = G1Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)); +/// let one = G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1)); +/// let res = bls12_381.g1_add(&zero, &one); +/// assert_eq!(res, one); +/// ``` +#[derive(Clone)] +#[repr(transparent)] +pub struct G1Affine(BytesN<96>); + +/// # `G2Affine` is a point in the G2 group (subgroup defined over the quadratic +/// extension field `Fq2`) of the BLS12-381 elliptic curve +/// +/// # Serialization: +/// - The 192 bytes represent the **uncompressed encoding** of a point in G2. +/// The bytes consist of `be_bytes(X_c1) || be_bytes(X_c0) || be_bytes(Y_c1) +/// || be_bytes(Y_c0)` (`||` is concatenation), where 'X' and 'Y' are the two +/// coordinates, each being an extension field element `Fp2` and `c0`, `c1` +/// are components of `Fp2` (each being `Fp`). +/// - The most significant three bits (bits 0-3) of the first byte are reserved +/// for encoding flags: +/// - compression_flag (bit 0): Must always be set (1), as only uncompressed +/// points are supported. +/// - infinity_flag (bit 1): Set if the point is the point at infinity (zero +/// point), in which case all other bits must be zero. +/// - sort_flag (bit 2): Must always be unset (0). +#[derive(Clone)] +#[repr(transparent)] +pub struct G2Affine(BytesN<192>); + +/// # `Fp` represents an element of the base field `Fq` of the BLS12-381 elliptic +/// curve +/// +/// # Serialization: +/// - The 48 bytes represent the **big-endian encoding** of an element in the +/// field `Fp`. The value is serialized as a big-endian integer. +#[derive(Clone)] +#[repr(transparent)] +pub struct Fp(BytesN<48>); + +/// # `Fp2` represents an element of the quadratic extension field `Fq2` of the +/// BLS12-381 elliptic curve +/// +/// # Serialization: +/// - The 96 bytes represent the **big-endian encoding** of an element in the +/// field `Fp2`. The bytes consist of `be_bytes(c1) || be_bytes(c0)` (`||` is +/// concatenation), where `c0` and `c1` are the two `Fp` elements (the real +/// and imaginary components). +#[derive(Clone)] +#[repr(transparent)] +pub struct Fp2(BytesN<96>); + +macro_rules! impl_bls_elements_bytes_repr { + ($elem: ident, $size: literal, $name: literal) => { + // #[derive(Clone)] + // #[repr(transparent)] + // pub struct $elem(BytesN<$size>); + impl $elem { + pub fn from_bytes(bytes: BytesN<$size>) -> Self { + Self(bytes) + } + + pub fn to_bytes(&self) -> BytesN<$size> { + self.0.clone() + } + + pub fn as_bytes(&self) -> &BytesN<$size> { + &self.0 + } + + pub fn to_array(&self) -> [u8; $size] { + self.0.to_array() + } + + pub fn as_val(&self) -> &Val { + self.0.as_val() + } + + pub fn to_val(&self) -> Val { + self.0.to_val() + } + + pub fn as_object(&self) -> &BytesObject { + self.0.as_object() + } + + pub fn to_object(&self) -> BytesObject { + self.0.to_object() + } + } + + impl IntoVal for $elem { + fn into_val(&self, e: &Env) -> Val { + self.0.into_val(e) + } + } + + impl TryFromVal for $elem { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + let bytes = >::try_from_val(env, val)?; + Ok($elem(bytes)) + } + } + + impl IntoVal> for $elem { + fn into_val(&self, _e: &Env) -> BytesN<$size> { + self.0.clone() + } + } + + impl From<$elem> for Bytes { + fn from(v: $elem) -> Self { + v.0.into() + } + } + + impl From<$elem> for BytesN<$size> { + fn from(v: $elem) -> Self { + v.0 + } + } + + impl Into<[u8; $size]> for $elem { + fn into(self) -> [u8; $size] { + self.0.into() + } + } + + impl Eq for $elem {} + + impl PartialEq for $elem { + fn eq(&self, other: &Self) -> bool { + self.0.partial_cmp(other.as_bytes()) == Some(Ordering::Equal) + } + } + + impl Debug for $elem { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}({:?})", $name, self.to_array())?; + Ok(()) + } + } + }; +} + +impl_bls_elements_bytes_repr!(G1Affine, 96, "G1Affine"); +impl_bls_elements_bytes_repr!(G2Affine, 192, "G2Affine"); +impl_bls_elements_bytes_repr!(Fp, 48, "Fp"); +impl_bls_elements_bytes_repr!(Fp2, 96, "Fp2"); + +impl Bls12_381 { + pub(crate) fn new(env: &Env) -> Bls12_381 { + Bls12_381 { env: env.clone() } + } + + pub fn env(&self) -> &Env { + &self.env + } + + // g1 + + /// Checks if a point `p` in G1 is in the correct subgroup. + pub fn g1_is_in_subgroup(&self, p: &G1Affine) -> bool { + let env = self.env(); + let res = internal::Env::bls12_381_check_g1_is_in_subgroup(env, p.to_object()) + .unwrap_infallible(); + res.into() + } + + /// Adds two points `p0` and `p1` in G1. + pub fn g1_add(&self, p0: &G1Affine, p1: &G1Affine) -> G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + } + + /// Adds two points `p0` and `p1` in G1, ensuring that the result is in the correct subgroup. + pub fn g1_checked_add(&self, p0: &G1Affine, p1: &G1Affine) -> G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + let res = G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()); + let is_in_correct_subgroup: bool = + internal::Env::bls12_381_check_g1_is_in_subgroup(env, res.to_object()) + .unwrap_optimized() + .into(); + match is_in_correct_subgroup { + true => res, + false => panic!("result G1 point not in the correct subgroup"), + } + } + + /// Multiplies a point `p0` in G1 by a scalar. + pub fn g1_mul(&self, p0: &G1Affine, scalar: &U256) -> G1Affine { + let env = self.env(); + let bin = + internal::Env::bls12_381_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); + G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + } + + /// Performs a multi-scalar multiplication (MSM) operation in G1. + pub fn g1_msm(&self, vp: Vec, vs: Vec) -> G1Affine { + assert!(vp.len() == vs.len() && vp.len() != 0); + let env = self.env(); + let bin = internal::Env::bls12_381_g1_msm(env, vp.into(), vs.into()).unwrap_infallible(); + G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + } + + /// Maps an element in the base field `Fp` to a point in G1. + pub fn map_fp_to_g1(&self, fp: &Fp) -> G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_map_fp_to_g1(env, fp.to_object()).unwrap_infallible(); + G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + } + + /// Hashes a message `msg` to a point in G1, using a domain separation tag `dst`. + pub fn hash_to_g1(&self, msg: &Bytes, dst: &Bytes) -> G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_hash_to_g1(env, msg.into(), dst.to_object()) + .unwrap_infallible(); + G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + } + + // g2 + + /// Checks if a point `p` in G2 is in the correct subgroup. + pub fn g2_is_in_subgroup(&self, p: &G2Affine) -> bool { + let env = self.env(); + let res = internal::Env::bls12_381_check_g2_is_in_subgroup(env, p.to_object()) + .unwrap_infallible(); + res.into() + } + + /// Adds two points `p0` and `p1` in G2. + pub fn g2_add(&self, p0: &G2Affine, p1: &G2Affine) -> G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + } + + /// Adds two points `p0` and `p1` in G2, ensuring that the result is in the correct subgroup. + pub fn g2_checked_add(&self, p0: &G2Affine, p1: &G2Affine) -> G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + let res = G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()); + let is_in_correct_subgroup: bool = + internal::Env::bls12_381_check_g2_is_in_subgroup(env, res.to_object()) + .unwrap_optimized() + .into(); + match is_in_correct_subgroup { + true => res, + false => panic!("result G2 point not in the correct subgroup"), + } + } + + /// Multiplies a point `p0` in G2 by a scalar. + pub fn g2_mul(&self, p0: &G2Affine, scalar: &U256) -> G2Affine { + let env = self.env(); + let bin = + internal::Env::bls12_381_g2_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); + G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + } + + /// Performs a multi-scalar multiplication (MSM) operation in G2. + pub fn g2_msm(&self, vp: Vec, vs: Vec) -> G2Affine { + assert!(vp.len() == vs.len() && vp.len() != 0); + let env = self.env(); + let bin = internal::Env::bls12_381_g2_msm(env, vp.into(), vs.into()).unwrap_infallible(); + G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + } + + /// Maps an element in the base field `Fp2` to a point in G2. + pub fn map_fp2_to_g2(&self, fp2: &Fp2) -> G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_map_fp2_to_g2(env, fp2.to_object()).unwrap_infallible(); + G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + } + + /// Hashes a message `msg` to a point in G2, using a domain separation tag `dst`. + pub fn hash_to_g2(&self, msg: &Bytes, dst: &Bytes) -> G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_hash_to_g2(env, msg.into(), dst.to_object()) + .unwrap_infallible(); + G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + } + + // pairing + + /// Performs a pairing check between vectors of points in G1 and G2. + /// + /// This function computes the pairing for each pair of points in the + /// provided vectors `vp1` (G1 points) and `vp2` (G2 points) and verifies if + /// the overall pairing result is equal to the identity in the target group. + /// + /// # Returns: + /// - `true` if the pairing check holds (i.e., the pairing result is valid + /// and equal to the identity element), otherwise `false`. + /// + /// # Panics: + /// - If the lengths of `vp1` and `vp2` are not equal or if they are empty. + pub fn pairing_check(&self, vp1: Vec, vp2: Vec) -> bool { + assert!(vp1.len() == vp2.len() && vp1.len() != 0); + let env = self.env(); + internal::Env::bls12_381_multi_pairing_check(env, vp1.into(), vp2.into()) + .unwrap_infallible() + .into() + } + + // scalar arithmetic + + /// Adds two scalars in the BLS12-381 scalar field `Fr`. + pub fn fr_add(&self, lhs: &U256, rhs: &U256) -> U256 { + let env = self.env(); + let v = internal::Env::bls12_381_fr_add(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible() + } + + /// Subtracts one scalar from another in the BLS12-381 scalar field `Fr`. + pub fn fr_sub(&self, lhs: &U256, rhs: &U256) -> U256 { + let env = self.env(); + let v = internal::Env::bls12_381_fr_sub(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible() + } + + /// Multiplies two scalars in the BLS12-381 scalar field `Fr`. + pub fn fr_mul(&self, lhs: &U256, rhs: &U256) -> U256 { + let env = self.env(); + let v = internal::Env::bls12_381_fr_mul(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible() + } + + /// Raises a scalar to the power of a given exponent in the BLS12-381 scalar field `Fr`. + pub fn fr_pow(&self, lhs: &U256, rhs: u64) -> U256 { + let env = self.env(); + let rhs = U64Val::try_from_val(env, &rhs).unwrap_optimized(); + let v = internal::Env::bls12_381_fr_pow(env, lhs.into(), rhs).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible() + } + + /// Computes the multiplicative inverse of a scalar in the BLS12-381 scalar field `Fr`. + pub fn fr_inv(&self, lhs: &U256) -> U256 { + let env = self.env(); + let v = internal::Env::bls12_381_fr_inv(env, lhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible() + } +} diff --git a/soroban-sdk/src/env.rs b/soroban-sdk/src/env.rs index bc4ffec17..9c746d0a3 100644 --- a/soroban-sdk/src/env.rs +++ b/soroban-sdk/src/env.rs @@ -113,6 +113,7 @@ where } use crate::auth::InvokerContractAuthEntry; +use crate::crypto::Bls12_381; use crate::unwrap::UnwrapInfallible; use crate::unwrap::UnwrapOptimized; use crate::InvokeError; @@ -313,6 +314,12 @@ impl Env { Crypto::new(self) } + /// Get a [Bls12_381] for accessing the bls12-381 functions. + #[inline(always)] + pub fn bls12_381(&self) -> Bls12_381 { + Bls12_381::new(self) + } + /// # ⚠️ Hazardous Materials /// /// Get a [CryptoHazmat][crate::crypto::CryptoHazmat] for accessing the diff --git a/soroban-sdk/src/num.rs b/soroban-sdk/src/num.rs index 1071943e6..cf321b597 100644 --- a/soroban-sdk/src/num.rs +++ b/soroban-sdk/src/num.rs @@ -54,6 +54,27 @@ macro_rules! impl_num_wrapping_val_type { } } + impl From<$wrapper> for $val { + #[inline(always)] + fn from(v: $wrapper) -> Self { + v.val + } + } + + impl From<&$wrapper> for $val { + #[inline(always)] + fn from(v: &$wrapper) -> Self { + v.val + } + } + + impl From<&$wrapper> for $wrapper { + #[inline(always)] + fn from(v: &$wrapper) -> Self { + v.clone() + } + } + impl TryFromVal for $wrapper { type Error = Infallible; diff --git a/soroban-sdk/src/tests.rs b/soroban-sdk/src/tests.rs index 6cb330d43..268ffb75f 100644 --- a/soroban-sdk/src/tests.rs +++ b/soroban-sdk/src/tests.rs @@ -22,6 +22,7 @@ mod contract_udt_struct; mod contract_udt_struct_tuple; mod contractimport; mod contractimport_with_error; +mod crypto_bls12_381; mod crypto_ed25519; mod crypto_keccak256; mod crypto_secp256k1; diff --git a/soroban-sdk/src/tests/crypto_bls12_381.rs b/soroban-sdk/src/tests/crypto_bls12_381.rs new file mode 100644 index 000000000..5549ed605 --- /dev/null +++ b/soroban-sdk/src/tests/crypto_bls12_381.rs @@ -0,0 +1,140 @@ +use crate::{ + bytes, bytesn, + crypto::{Bls12_381, Fp, Fp2, G1Affine, G2Affine}, + vec, Bytes, Env, Vec, U256, +}; + +#[test] +fn test_bls_g1() { + let env = Env::default(); + let bls12_381 = Bls12_381::new(&env); + const DST_G1: &str = "QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_"; + let zero = G1Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)); + let one = G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1)); + + // subgroup check + assert!(bls12_381.g1_is_in_subgroup(&zero)); + assert!(bls12_381.g1_is_in_subgroup(&one)); + + // add + let res = bls12_381.g1_add(&zero, &one); + assert_eq!(res, one); + + // mul + let res = bls12_381.g1_mul(&one, &U256::from_u32(&env, 0)); + assert_eq!(res, zero); + + // msm + let vp: Vec = vec![&env, one.clone(), one.clone()]; + let vs: Vec = vec![&env, U256::from_u32(&env, 1), U256::from_u32(&env, 0)]; + let res = bls12_381.g1_msm(vp, vs); + assert_eq!(res, one); + + // map to curve (test case from https://datatracker.ietf.org/doc/html/rfc9380) + let dst = Bytes::from_slice(&env, DST_G1.as_bytes()); + let fp = Fp::from_bytes(bytesn!(&env, 0x0d921c33f2bad966478a03ca35d05719bdf92d347557ea166e5bba579eea9b83e9afa5c088573c2281410369fbd32951)); + let expected = G1Affine::from_bytes(bytesn!(&env, 0x125435adce8e1cbd1c803e7123f45392dc6e326d292499c2c45c5865985fd74fe8f042ecdeeec5ecac80680d04317d800e8828948c989126595ee30e4f7c931cbd6f4570735624fd25aef2fa41d3f79cfb4b4ee7b7e55a8ce013af2a5ba20bf2)); + let res = bls12_381.map_fp_to_g1(&fp); + assert_eq!(res, expected); + + // hash msg to curve (test case from https://datatracker.ietf.org/doc/html/rfc9380) + let msg = Bytes::from_slice(&env, "abc".as_bytes()); + let expected = G1Affine::from_bytes(bytesn!(&env, 0x03567bc5ef9c690c2ab2ecdf6a96ef1c139cc0b2f284dca0a9a7943388a49a3aee664ba5379a7655d3c68900be2f69030b9c15f3fe6e5cf4211f346271d7b01c8f3b28be689c8429c85b67af215533311f0b8dfaaa154fa6b88176c229f2885d)); + let res = bls12_381.hash_to_g1(&msg, &dst); + assert_eq!(res, expected); +} + +#[test] +fn test_bls_g2() { + let env = Env::default(); + let bls12_381 = Bls12_381::new(&env); + const DST_G2: &str = "QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_"; + let zero = G2Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)); + let one = G2Affine::from_bytes(bytesn!(&env, 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801)); + + // subgroup check + assert!(bls12_381.g2_is_in_subgroup(&zero)); + assert!(bls12_381.g2_is_in_subgroup(&one)); + + // add + let res = bls12_381.g2_add(&zero, &one); + assert_eq!(res, one); + + // mul + let res = bls12_381.g2_mul(&one, &U256::from_u32(&env, 0)); + assert_eq!(res, zero); + + // msm + let vp: Vec = vec![&env, one.clone(), one.clone()]; + let vs: Vec = vec![&env, U256::from_u32(&env, 1), U256::from_u32(&env, 0)]; + let res = bls12_381.g2_msm(vp, vs); + assert_eq!(res, one); + + // map to curve (test case from https://datatracker.ietf.org/doc/html/rfc9380) + let dst = Bytes::from_slice(&env, DST_G2.as_bytes()); + let fp2 = Fp2::from_bytes(bytesn!(&env, 0x01c8067bf4c0ba709aa8b9abc3d1cef589a4758e09ef53732d670fd8739a7274e111ba2fcaa71b3d33df2a3a0c8529dd15f7c0aa8f6b296ab5ff9c2c7581ade64f4ee6f1bf18f55179ff44a2cf355fa53dd2a2158c5ecb17d7c52f63e7195771)); + let expected = G2Affine::from_bytes(bytesn!(&env, 0x05d8a724db78e570e34100c0bc4a5fa84ad5839359b40398151f37cff5a51de945c563463c9efbdda569850ee5a53e7712b2e525281b5f4d2276954e84ac4f42cf4e13b6ac4228624e17760faf94ce5706d53f0ca1952f1c5ef75239aeed55ad04bbe48bfd5814648d0b9e30f0717b34015d45a861425fabc1ee06fdfce36384ae2c808185e693ae97dcde118f34de4102eacdc556d0bdb5d18d22f23dcb086dd106cad713777c7e6407943edbe0b3d1efe391eedf11e977fac55f9b94f2489c)); + let res = bls12_381.map_fp2_to_g2(&fp2); + assert_eq!(res, expected); + + // hash msg to curve (test case from https://datatracker.ietf.org/doc/html/rfc9380) + let msg = Bytes::from_slice(&env, "abc".as_bytes()); + let expected = G2Affine::from_bytes(bytesn!(&env, 0x139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd802c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e600aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd161787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48)); + let res = bls12_381.hash_to_g2(&msg, &dst); + assert_eq!(res, expected); +} + +#[test] +fn test_pairing() { + let env = Env::default(); + let bls12_381 = Bls12_381::new(&env); + // test case from one of the ethereum tests "verify_valid_case_195246ee3bd3b6ec.json" + const DST_ETHEREUM: &str = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + let dst = Bytes::from_slice(&env, DST_ETHEREUM.as_bytes()); + let neg_g1 = G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb114d1d6855d545a8aa7d76c8cf2e21f267816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca)); + let pk = G1Affine::from_bytes(bytesn!(&env, 0x153d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f14e22fd412a826a329fb40cbdc01b5e4e2f931ed84d8e45932ec62a039f9d61a9dbf2c6eedc5db6fa585b6e0bdde100c)); + let msg = bytes!( + &env, + 0xabababababababababababababababababababababababababababababababab + ); + let msg = bls12_381.hash_to_g2(&msg, &dst); + let sig = G2Affine::from_bytes(bytesn!(&env, 0x0e82747ddeefe4fd64cf9cedb9b04ae3e8a43420cd255e3c7cd06a8d88b7c7f8638543719981c5d16fa3527c468c25f0026704a6951bde891360c7e8d12ddee0559004ccdbe6046b55bae1b257ee97f7cdb955773d7cf29adf3ccbb9975e4eb915e60d5b66a43e074b801a07df931a17505048f7f96dc80f857b638e505868dc008cc9c26ed5b8495e9c181b67dc4c2317d9d447337a9cc6d2956b9c6dd7c23c0bfb73855e902061bcb9cb9d40e43c38140091e638ffcffc7261366018900047)); + + let vp1 = vec![&env, pk, neg_g1]; + let vp2 = vec![&env, msg, sig]; + assert!(bls12_381.pairing_check(vp1, vp2)) +} + +#[test] +fn test_fr_arithmetic() { + let env = Env::default(); + let bls12_381 = Bls12_381::new(&env); + let modulus = U256::from_be_bytes( + &env, + &bytes!( + &env, + 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 + ), + ); + assert_eq!( + bls12_381.fr_add(&U256::from_u32(&env, 2), &U256::from_u32(&env, 3)), + U256::from_u32(&env, 5) + ); + assert_eq!( + bls12_381.fr_sub(&U256::from_u32(&env, 2), &U256::from_u32(&env, 3)), + modulus.sub(&U256::from_u32(&env, 1)) + ); + assert_eq!( + bls12_381.fr_mul(&U256::from_u32(&env, 2), &U256::from_u32(&env, 3)), + U256::from_u32(&env, 6) + ); + assert_eq!( + bls12_381.fr_pow(&U256::from_u32(&env, 5), 2), + U256::from_u32(&env, 25) + ); + let inverse_13 = bls12_381.fr_inv(&U256::from_u32(&env, 13)); + assert_eq!( + bls12_381.fr_mul(&inverse_13, &U256::from_u32(&env, 13)), + U256::from_u32(&env, 1) + ); +} From 253c2c9cf109f7298a060eaf61e1e2cee002b9d3 Mon Sep 17 00:00:00 2001 From: Jay Geng Date: Thu, 19 Sep 2024 19:45:14 -0400 Subject: [PATCH 02/18] fix some deps --- Cargo.lock | 42 +++++++---------------------------- Cargo.toml | 2 +- soroban-sdk-macros/Cargo.toml | 2 +- 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e78b62f9e..9cfe735fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,7 +62,7 @@ dependencies = [ "ark-std", "derivative", "hashbrown 0.13.2", - "itertools 0.10.5", + "itertools", "num-traits", "zeroize", ] @@ -79,7 +79,7 @@ dependencies = [ "ark-std", "derivative", "digest", - "itertools 0.10.5", + "itertools", "num-bigint", "num-traits", "paste", @@ -174,12 +174,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base32" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" - [[package]] name = "base64" version = "0.13.1" @@ -745,15 +739,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.11" @@ -1234,7 +1219,7 @@ name = "soroban-builtin-sdk-macros" version = "22.0.0" source = "git+https://github.com/stellar/rs-soroban-env?rev=0497816694bef2b103494c8c61b7c8a06a72c7d3#0497816694bef2b103494c8c61b7c8a06a72c7d3" dependencies = [ - "itertools 0.10.5", + "itertools", "proc-macro2", "quote", "syn 2.0.77", @@ -1298,7 +1283,7 @@ dependencies = [ "soroban-env-common", "soroban-wasmi", "static_assertions", - "stellar-strkey 0.0.9", + "stellar-strkey", "wasmparser", ] @@ -1307,7 +1292,7 @@ name = "soroban-env-macros" version = "22.0.0" source = "git+https://github.com/stellar/rs-soroban-env?rev=0497816694bef2b103494c8c61b7c8a06a72c7d3#0497816694bef2b103494c8c61b7c8a06a72c7d3" dependencies = [ - "itertools 0.10.5", + "itertools", "proc-macro2", "quote", "serde", @@ -1349,7 +1334,7 @@ dependencies = [ "soroban-ledger-snapshot", "soroban-sdk-macros", "soroban-spec", - "stellar-strkey 0.0.8", + "stellar-strkey", "stellar-xdr", ] @@ -1359,7 +1344,7 @@ version = "22.0.0-rc.1" dependencies = [ "crate-git-revision", "darling", - "itertools 0.11.0", + "itertools", "proc-macro2", "quote", "rustc_version", @@ -1442,17 +1427,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stellar-strkey" -version = "0.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12d2bf45e114117ea91d820a846fd1afbe3ba7d717988fee094ce8227a3bf8bd" -dependencies = [ - "base32", - "crate-git-revision", - "thiserror", -] - [[package]] name = "stellar-strkey" version = "0.0.9" @@ -1476,7 +1450,7 @@ dependencies = [ "hex", "serde", "serde_with", - "stellar-strkey 0.0.9", + "stellar-strkey", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0a2683ba2..ce88c468e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ git = "https://github.com/stellar/rs-soroban-env" rev = "0497816694bef2b103494c8c61b7c8a06a72c7d3" [workspace.dependencies.stellar-strkey] -version = "=0.0.8" +version = "=0.0.9" [workspace.dependencies.stellar-xdr] version = "=22.0.0" diff --git a/soroban-sdk-macros/Cargo.toml b/soroban-sdk-macros/Cargo.toml index 927ce56c5..24fa1e82e 100644 --- a/soroban-sdk-macros/Cargo.toml +++ b/soroban-sdk-macros/Cargo.toml @@ -26,7 +26,7 @@ stellar-xdr = { workspace = true, features = ["curr", "std"] } syn = {version="2.0",features=["full"]} quote = "1.0" proc-macro2 = "1.0" -itertools = "0.11.0" +itertools = "0.10.5" darling = "0.20.0" sha2 = "0.10.7" From 616e9ed6418c2249e8137c90a429e9e02619432f Mon Sep 17 00:00:00 2001 From: Jay Geng Date: Thu, 19 Sep 2024 20:10:37 -0400 Subject: [PATCH 03/18] address comments --- soroban-sdk/src/crypto.rs | 53 +++++++++++++---------- soroban-sdk/src/tests/crypto_bls12_381.rs | 8 ++++ 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/soroban-sdk/src/crypto.rs b/soroban-sdk/src/crypto.rs index 8c19794cd..2ee3f97be 100644 --- a/soroban-sdk/src/crypto.rs +++ b/soroban-sdk/src/crypto.rs @@ -3,7 +3,7 @@ use crate::{ env::internal::{self, BytesObject, U64Val}, unwrap::{UnwrapInfallible, UnwrapOptimized}, - Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, TryIntoVal, Val, Vec, U256, + Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256, }; use core::{cmp::Ordering, fmt::Debug}; @@ -456,22 +456,26 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + G1Affine::from_bytes(bin.into_val(env)) } - /// Adds two points `p0` and `p1` in G1, ensuring that the result is in the correct subgroup. - pub fn g1_checked_add(&self, p0: &G1Affine, p1: &G1Affine) -> G1Affine { + /// Adds two points `p0` and `p1` in G1, ensuring that the result is in the + /// correct subgroup. Note the subgroup check is computationally expensive, + /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. + pn`, + /// it may make sense to only call g1_checked_add on the final addition, + /// while using `g1_add` (non-checked version) on the intermediate ones. + pub fn g1_checked_add(&self, p0: &G1Affine, p1: &G1Affine) -> Option { let env = self.env(); let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - let res = G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()); + let res = G1Affine::from_bytes(bin.into_val(env)); let is_in_correct_subgroup: bool = internal::Env::bls12_381_check_g1_is_in_subgroup(env, res.to_object()) .unwrap_optimized() .into(); match is_in_correct_subgroup { - true => res, - false => panic!("result G1 point not in the correct subgroup"), + true => Some(res), + false => None, } } @@ -480,22 +484,21 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + G1Affine::from_bytes(bin.into_val(env)) } /// Performs a multi-scalar multiplication (MSM) operation in G1. pub fn g1_msm(&self, vp: Vec, vs: Vec) -> G1Affine { - assert!(vp.len() == vs.len() && vp.len() != 0); let env = self.env(); let bin = internal::Env::bls12_381_g1_msm(env, vp.into(), vs.into()).unwrap_infallible(); - G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + G1Affine::from_bytes(bin.into_val(env)) } /// Maps an element in the base field `Fp` to a point in G1. pub fn map_fp_to_g1(&self, fp: &Fp) -> G1Affine { let env = self.env(); let bin = internal::Env::bls12_381_map_fp_to_g1(env, fp.to_object()).unwrap_infallible(); - G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + G1Affine::from_bytes(bin.into_val(env)) } /// Hashes a message `msg` to a point in G1, using a domain separation tag `dst`. @@ -503,7 +506,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_hash_to_g1(env, msg.into(), dst.to_object()) .unwrap_infallible(); - G1Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + G1Affine::from_bytes(bin.into_val(env)) } // g2 @@ -521,22 +524,26 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + G2Affine::from_bytes(bin.into_val(env)) } - /// Adds two points `p0` and `p1` in G2, ensuring that the result is in the correct subgroup. - pub fn g2_checked_add(&self, p0: &G2Affine, p1: &G2Affine) -> G2Affine { + /// Adds two points `p0` and `p1` in G2, ensuring that the result is in the + /// correct subgroup. Note the subgroup check is computationally expensive, + /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. +pn`, + /// it may make sense to only call g2_checked_add on the final addition, + /// while using `g2_add` (non-checked version) on the intermediate ones. + pub fn g2_checked_add(&self, p0: &G2Affine, p1: &G2Affine) -> Option { let env = self.env(); let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - let res = G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()); + let res = G2Affine::from_bytes(bin.into_val(env)); let is_in_correct_subgroup: bool = internal::Env::bls12_381_check_g2_is_in_subgroup(env, res.to_object()) .unwrap_optimized() .into(); match is_in_correct_subgroup { - true => res, - false => panic!("result G2 point not in the correct subgroup"), + true => Some(res), + false => None, } } @@ -545,22 +552,21 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g2_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + G2Affine::from_bytes(bin.into_val(env)) } /// Performs a multi-scalar multiplication (MSM) operation in G2. pub fn g2_msm(&self, vp: Vec, vs: Vec) -> G2Affine { - assert!(vp.len() == vs.len() && vp.len() != 0); let env = self.env(); let bin = internal::Env::bls12_381_g2_msm(env, vp.into(), vs.into()).unwrap_infallible(); - G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + G2Affine::from_bytes(bin.into_val(env)) } /// Maps an element in the base field `Fp2` to a point in G2. pub fn map_fp2_to_g2(&self, fp2: &Fp2) -> G2Affine { let env = self.env(); let bin = internal::Env::bls12_381_map_fp2_to_g2(env, fp2.to_object()).unwrap_infallible(); - G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + G2Affine::from_bytes(bin.into_val(env)) } /// Hashes a message `msg` to a point in G2, using a domain separation tag `dst`. @@ -568,7 +574,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_hash_to_g2(env, msg.into(), dst.to_object()) .unwrap_infallible(); - G2Affine::from_bytes(bin.try_into_val(env).unwrap_optimized()) + G2Affine::from_bytes(bin.into_val(env)) } // pairing @@ -586,7 +592,6 @@ impl Bls12_381 { /// # Panics: /// - If the lengths of `vp1` and `vp2` are not equal or if they are empty. pub fn pairing_check(&self, vp1: Vec, vp2: Vec) -> bool { - assert!(vp1.len() == vp2.len() && vp1.len() != 0); let env = self.env(); internal::Env::bls12_381_multi_pairing_check(env, vp1.into(), vp2.into()) .unwrap_infallible() diff --git a/soroban-sdk/src/tests/crypto_bls12_381.rs b/soroban-sdk/src/tests/crypto_bls12_381.rs index 5549ed605..c8e084b9a 100644 --- a/soroban-sdk/src/tests/crypto_bls12_381.rs +++ b/soroban-sdk/src/tests/crypto_bls12_381.rs @@ -20,6 +20,10 @@ fn test_bls_g1() { let res = bls12_381.g1_add(&zero, &one); assert_eq!(res, one); + // checked_add + let res = bls12_381.g1_checked_add(&zero, &one); + assert!(res.is_some_and(|v| v == one)); + // mul let res = bls12_381.g1_mul(&one, &U256::from_u32(&env, 0)); assert_eq!(res, zero); @@ -60,6 +64,10 @@ fn test_bls_g2() { let res = bls12_381.g2_add(&zero, &one); assert_eq!(res, one); + // checked_add + let res = bls12_381.g2_checked_add(&zero, &one); + assert!(res.is_some_and(|v| v == one)); + // mul let res = bls12_381.g2_mul(&one, &U256::from_u32(&env, 0)); assert_eq!(res, zero); From bbcce966aa140430a2f743c6cf2b26defbccb88d Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Fri, 20 Sep 2024 15:03:06 -0700 Subject: [PATCH 04/18] Allow duplicates for arkworks deps --- deny.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deny.toml b/deny.toml index b18f9481b..7efb64b46 100644 --- a/deny.toml +++ b/deny.toml @@ -244,6 +244,8 @@ deny = [ # Certain crates/versions that will be skipped when doing duplicate detection. skip = [ #{ name = "ansi_term", version = "=0.11.0" }, + { name = "hashbrown", version = "=0.14.5" }, + { name = "syn", version = "=2.0.77" }, ] # Similarly to `skip` allows you to skip certain crates during duplicate # detection. Unlike skip, it also includes the entire tree of transitive From 6add893377717ad4c009e3c4d63eecf449a72e06 Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Fri, 20 Sep 2024 15:41:05 -0700 Subject: [PATCH 05/18] Address some comments --- soroban-sdk/src/bytes.rs | 92 ++++++++++++++++++++++++++++++++ soroban-sdk/src/crypto.rs | 109 ++++---------------------------------- soroban-sdk/src/env.rs | 7 --- 3 files changed, 102 insertions(+), 106 deletions(-) diff --git a/soroban-sdk/src/bytes.rs b/soroban-sdk/src/bytes.rs index 1605341bd..4c510a355 100644 --- a/soroban-sdk/src/bytes.rs +++ b/soroban-sdk/src/bytes.rs @@ -102,6 +102,98 @@ macro_rules! bytesn { }; } +#[macro_export] +macro_rules! impl_bytesn_repr { + ($elem: ident, $size: literal) => { + impl $elem { + pub fn from_bytes(bytes: BytesN<$size>) -> Self { + Self(bytes) + } + + pub fn to_bytes(&self) -> BytesN<$size> { + self.0.clone() + } + + pub fn as_bytes(&self) -> &BytesN<$size> { + &self.0 + } + + pub fn to_array(&self) -> [u8; $size] { + self.0.to_array() + } + + pub fn as_val(&self) -> &Val { + self.0.as_val() + } + + pub fn to_val(&self) -> Val { + self.0.to_val() + } + + pub fn as_object(&self) -> &BytesObject { + self.0.as_object() + } + + pub fn to_object(&self) -> BytesObject { + self.0.to_object() + } + } + + impl IntoVal for $elem { + fn into_val(&self, e: &Env) -> Val { + self.0.into_val(e) + } + } + + impl TryFromVal for $elem { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + let bytes = >::try_from_val(env, val)?; + Ok($elem(bytes)) + } + } + + impl IntoVal> for $elem { + fn into_val(&self, _e: &Env) -> BytesN<$size> { + self.0.clone() + } + } + + impl From<$elem> for Bytes { + fn from(v: $elem) -> Self { + v.0.into() + } + } + + impl From<$elem> for BytesN<$size> { + fn from(v: $elem) -> Self { + v.0 + } + } + + impl Into<[u8; $size]> for $elem { + fn into(self) -> [u8; $size] { + self.0.into() + } + } + + impl Eq for $elem {} + + impl PartialEq for $elem { + fn eq(&self, other: &Self) -> bool { + self.0.partial_cmp(other.as_bytes()) == Some(Ordering::Equal) + } + } + + impl Debug for $elem { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}({:?})", stringify!($elem), self.to_array()) + } + } + }; +} + /// Bytes is a contiguous growable array type containing `u8`s. /// /// The array is stored in the Host and available to the Guest through the diff --git a/soroban-sdk/src/crypto.rs b/soroban-sdk/src/crypto.rs index 2ee3f97be..d94774996 100644 --- a/soroban-sdk/src/crypto.rs +++ b/soroban-sdk/src/crypto.rs @@ -2,6 +2,7 @@ use crate::{ env::internal::{self, BytesObject, U64Val}, + impl_bytesn_repr, unwrap::{UnwrapInfallible, UnwrapOptimized}, Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256, }; @@ -176,6 +177,11 @@ impl Crypto { let env = self.env(); CryptoHazmat::new(env).secp256r1_verify(public_key, &message_digest.0, signature) } + + /// Get a [Bls12_381] for accessing the bls12-381 functions. + pub fn bls12_381(&self) -> Bls12_381 { + Bls12_381::new(self.env()) + } } /// # ⚠️ Hazardous Materials @@ -332,105 +338,10 @@ pub struct Fp(BytesN<48>); #[repr(transparent)] pub struct Fp2(BytesN<96>); -macro_rules! impl_bls_elements_bytes_repr { - ($elem: ident, $size: literal, $name: literal) => { - // #[derive(Clone)] - // #[repr(transparent)] - // pub struct $elem(BytesN<$size>); - impl $elem { - pub fn from_bytes(bytes: BytesN<$size>) -> Self { - Self(bytes) - } - - pub fn to_bytes(&self) -> BytesN<$size> { - self.0.clone() - } - - pub fn as_bytes(&self) -> &BytesN<$size> { - &self.0 - } - - pub fn to_array(&self) -> [u8; $size] { - self.0.to_array() - } - - pub fn as_val(&self) -> &Val { - self.0.as_val() - } - - pub fn to_val(&self) -> Val { - self.0.to_val() - } - - pub fn as_object(&self) -> &BytesObject { - self.0.as_object() - } - - pub fn to_object(&self) -> BytesObject { - self.0.to_object() - } - } - - impl IntoVal for $elem { - fn into_val(&self, e: &Env) -> Val { - self.0.into_val(e) - } - } - - impl TryFromVal for $elem { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - let bytes = >::try_from_val(env, val)?; - Ok($elem(bytes)) - } - } - - impl IntoVal> for $elem { - fn into_val(&self, _e: &Env) -> BytesN<$size> { - self.0.clone() - } - } - - impl From<$elem> for Bytes { - fn from(v: $elem) -> Self { - v.0.into() - } - } - - impl From<$elem> for BytesN<$size> { - fn from(v: $elem) -> Self { - v.0 - } - } - - impl Into<[u8; $size]> for $elem { - fn into(self) -> [u8; $size] { - self.0.into() - } - } - - impl Eq for $elem {} - - impl PartialEq for $elem { - fn eq(&self, other: &Self) -> bool { - self.0.partial_cmp(other.as_bytes()) == Some(Ordering::Equal) - } - } - - impl Debug for $elem { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}({:?})", $name, self.to_array())?; - Ok(()) - } - } - }; -} - -impl_bls_elements_bytes_repr!(G1Affine, 96, "G1Affine"); -impl_bls_elements_bytes_repr!(G2Affine, 192, "G2Affine"); -impl_bls_elements_bytes_repr!(Fp, 48, "Fp"); -impl_bls_elements_bytes_repr!(Fp2, 96, "Fp2"); +impl_bytesn_repr!(G1Affine, 96); +impl_bytesn_repr!(G2Affine, 192); +impl_bytesn_repr!(Fp, 48); +impl_bytesn_repr!(Fp2, 96); impl Bls12_381 { pub(crate) fn new(env: &Env) -> Bls12_381 { diff --git a/soroban-sdk/src/env.rs b/soroban-sdk/src/env.rs index 9c746d0a3..bc4ffec17 100644 --- a/soroban-sdk/src/env.rs +++ b/soroban-sdk/src/env.rs @@ -113,7 +113,6 @@ where } use crate::auth::InvokerContractAuthEntry; -use crate::crypto::Bls12_381; use crate::unwrap::UnwrapInfallible; use crate::unwrap::UnwrapOptimized; use crate::InvokeError; @@ -314,12 +313,6 @@ impl Env { Crypto::new(self) } - /// Get a [Bls12_381] for accessing the bls12-381 functions. - #[inline(always)] - pub fn bls12_381(&self) -> Bls12_381 { - Bls12_381::new(self) - } - /// # ⚠️ Hazardous Materials /// /// Get a [CryptoHazmat][crate::crypto::CryptoHazmat] for accessing the From 34437add345af8ba188805cd049660dd230ffd47 Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Fri, 20 Sep 2024 16:19:30 -0700 Subject: [PATCH 06/18] Fix doc comment --- soroban-sdk/src/crypto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soroban-sdk/src/crypto.rs b/soroban-sdk/src/crypto.rs index d94774996..7cfce7648 100644 --- a/soroban-sdk/src/crypto.rs +++ b/soroban-sdk/src/crypto.rs @@ -286,7 +286,7 @@ pub struct Bls12_381 { /// ```rust /// use soroban_sdk::{Env, bytesn, crypto::{Bls12_381, G1Affine}}; /// let env = Env::default(); -/// let bls12_381 = env.bls12_381(); +/// let bls12_381 = env.crypto().bls12_381(); /// let zero = G1Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)); /// let one = G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1)); /// let res = bls12_381.g1_add(&zero, &one); From 4a55224f57bffa02069ea6cb9700bccf8d9d7fa8 Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Fri, 20 Sep 2024 16:40:32 -0700 Subject: [PATCH 07/18] Create separate bls12-381 module --- soroban-sdk/src/crypto.rs | 301 +--------------------- soroban-sdk/src/crypto/bls12_381.rs | 294 +++++++++++++++++++++ soroban-sdk/src/tests/crypto_bls12_381.rs | 2 +- 3 files changed, 301 insertions(+), 296 deletions(-) create mode 100644 soroban-sdk/src/crypto/bls12_381.rs diff --git a/soroban-sdk/src/crypto.rs b/soroban-sdk/src/crypto.rs index 7cfce7648..c725ebcf0 100644 --- a/soroban-sdk/src/crypto.rs +++ b/soroban-sdk/src/crypto.rs @@ -1,13 +1,12 @@ //! Crypto contains functions for cryptographic functions. use crate::{ - env::internal::{self, BytesObject, U64Val}, - impl_bytesn_repr, - unwrap::{UnwrapInfallible, UnwrapOptimized}, - Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256, + env::internal::{self, BytesObject}, + unwrap::UnwrapInfallible, + Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, }; -use core::{cmp::Ordering, fmt::Debug}; +pub mod bls12_381; /// A BytesN generated by a cryptographic hash function. /// /// The `Hash` type contains a `BytesN` and can only be constructed in @@ -179,8 +178,8 @@ impl Crypto { } /// Get a [Bls12_381] for accessing the bls12-381 functions. - pub fn bls12_381(&self) -> Bls12_381 { - Bls12_381::new(self.env()) + pub fn bls12_381(&self) -> bls12_381::Bls12_381 { + bls12_381::Bls12_381::new(self.env()) } } @@ -259,291 +258,3 @@ impl CryptoHazmat { .unwrap_infallible(); } } - -/// Bls12_381 provides access to curve and field arithmetics on the BLS12-381 -/// curve. -pub struct Bls12_381 { - env: Env, -} - -/// # `G1Affine` is a point in the G1 group (subgroup defined over the base field -/// `Fq`) of the BLS12-381 elliptic curve -/// -/// # Serialization: -/// - The 96 bytes represent the **uncompressed encoding** of a point in G1. The -/// Bytes consist of `be_byte(X) || be_byte(Y)` (`||` is concatenation), -/// where 'X' and 'Y' are the two coordinates, each being a base field element -/// `Fp` -/// - The most significant three bits (bits 0-3) of the first byte are reserved -/// for encoding flags: -/// - compression_flag (bit 0): Must always be set (1), as only uncompressed -/// points are supported. -/// - infinity_flag (bit 1): Set if the point is the point at infinity (zero -/// point), in which case all other bits must be zero. -/// - sort_flag (bit 2): Must always be unset (0). -/// -/// # Example Usage: -/// ```rust -/// use soroban_sdk::{Env, bytesn, crypto::{Bls12_381, G1Affine}}; -/// let env = Env::default(); -/// let bls12_381 = env.crypto().bls12_381(); -/// let zero = G1Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)); -/// let one = G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1)); -/// let res = bls12_381.g1_add(&zero, &one); -/// assert_eq!(res, one); -/// ``` -#[derive(Clone)] -#[repr(transparent)] -pub struct G1Affine(BytesN<96>); - -/// # `G2Affine` is a point in the G2 group (subgroup defined over the quadratic -/// extension field `Fq2`) of the BLS12-381 elliptic curve -/// -/// # Serialization: -/// - The 192 bytes represent the **uncompressed encoding** of a point in G2. -/// The bytes consist of `be_bytes(X_c1) || be_bytes(X_c0) || be_bytes(Y_c1) -/// || be_bytes(Y_c0)` (`||` is concatenation), where 'X' and 'Y' are the two -/// coordinates, each being an extension field element `Fp2` and `c0`, `c1` -/// are components of `Fp2` (each being `Fp`). -/// - The most significant three bits (bits 0-3) of the first byte are reserved -/// for encoding flags: -/// - compression_flag (bit 0): Must always be set (1), as only uncompressed -/// points are supported. -/// - infinity_flag (bit 1): Set if the point is the point at infinity (zero -/// point), in which case all other bits must be zero. -/// - sort_flag (bit 2): Must always be unset (0). -#[derive(Clone)] -#[repr(transparent)] -pub struct G2Affine(BytesN<192>); - -/// # `Fp` represents an element of the base field `Fq` of the BLS12-381 elliptic -/// curve -/// -/// # Serialization: -/// - The 48 bytes represent the **big-endian encoding** of an element in the -/// field `Fp`. The value is serialized as a big-endian integer. -#[derive(Clone)] -#[repr(transparent)] -pub struct Fp(BytesN<48>); - -/// # `Fp2` represents an element of the quadratic extension field `Fq2` of the -/// BLS12-381 elliptic curve -/// -/// # Serialization: -/// - The 96 bytes represent the **big-endian encoding** of an element in the -/// field `Fp2`. The bytes consist of `be_bytes(c1) || be_bytes(c0)` (`||` is -/// concatenation), where `c0` and `c1` are the two `Fp` elements (the real -/// and imaginary components). -#[derive(Clone)] -#[repr(transparent)] -pub struct Fp2(BytesN<96>); - -impl_bytesn_repr!(G1Affine, 96); -impl_bytesn_repr!(G2Affine, 192); -impl_bytesn_repr!(Fp, 48); -impl_bytesn_repr!(Fp2, 96); - -impl Bls12_381 { - pub(crate) fn new(env: &Env) -> Bls12_381 { - Bls12_381 { env: env.clone() } - } - - pub fn env(&self) -> &Env { - &self.env - } - - // g1 - - /// Checks if a point `p` in G1 is in the correct subgroup. - pub fn g1_is_in_subgroup(&self, p: &G1Affine) -> bool { - let env = self.env(); - let res = internal::Env::bls12_381_check_g1_is_in_subgroup(env, p.to_object()) - .unwrap_infallible(); - res.into() - } - - /// Adds two points `p0` and `p1` in G1. - pub fn g1_add(&self, p0: &G1Affine, p1: &G1Affine) -> G1Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) - .unwrap_infallible(); - G1Affine::from_bytes(bin.into_val(env)) - } - - /// Adds two points `p0` and `p1` in G1, ensuring that the result is in the - /// correct subgroup. Note the subgroup check is computationally expensive, - /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. + pn`, - /// it may make sense to only call g1_checked_add on the final addition, - /// while using `g1_add` (non-checked version) on the intermediate ones. - pub fn g1_checked_add(&self, p0: &G1Affine, p1: &G1Affine) -> Option { - let env = self.env(); - let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) - .unwrap_infallible(); - let res = G1Affine::from_bytes(bin.into_val(env)); - let is_in_correct_subgroup: bool = - internal::Env::bls12_381_check_g1_is_in_subgroup(env, res.to_object()) - .unwrap_optimized() - .into(); - match is_in_correct_subgroup { - true => Some(res), - false => None, - } - } - - /// Multiplies a point `p0` in G1 by a scalar. - pub fn g1_mul(&self, p0: &G1Affine, scalar: &U256) -> G1Affine { - let env = self.env(); - let bin = - internal::Env::bls12_381_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - G1Affine::from_bytes(bin.into_val(env)) - } - - /// Performs a multi-scalar multiplication (MSM) operation in G1. - pub fn g1_msm(&self, vp: Vec, vs: Vec) -> G1Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_g1_msm(env, vp.into(), vs.into()).unwrap_infallible(); - G1Affine::from_bytes(bin.into_val(env)) - } - - /// Maps an element in the base field `Fp` to a point in G1. - pub fn map_fp_to_g1(&self, fp: &Fp) -> G1Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_map_fp_to_g1(env, fp.to_object()).unwrap_infallible(); - G1Affine::from_bytes(bin.into_val(env)) - } - - /// Hashes a message `msg` to a point in G1, using a domain separation tag `dst`. - pub fn hash_to_g1(&self, msg: &Bytes, dst: &Bytes) -> G1Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_hash_to_g1(env, msg.into(), dst.to_object()) - .unwrap_infallible(); - G1Affine::from_bytes(bin.into_val(env)) - } - - // g2 - - /// Checks if a point `p` in G2 is in the correct subgroup. - pub fn g2_is_in_subgroup(&self, p: &G2Affine) -> bool { - let env = self.env(); - let res = internal::Env::bls12_381_check_g2_is_in_subgroup(env, p.to_object()) - .unwrap_infallible(); - res.into() - } - - /// Adds two points `p0` and `p1` in G2. - pub fn g2_add(&self, p0: &G2Affine, p1: &G2Affine) -> G2Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) - .unwrap_infallible(); - G2Affine::from_bytes(bin.into_val(env)) - } - - /// Adds two points `p0` and `p1` in G2, ensuring that the result is in the - /// correct subgroup. Note the subgroup check is computationally expensive, - /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. +pn`, - /// it may make sense to only call g2_checked_add on the final addition, - /// while using `g2_add` (non-checked version) on the intermediate ones. - pub fn g2_checked_add(&self, p0: &G2Affine, p1: &G2Affine) -> Option { - let env = self.env(); - let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) - .unwrap_infallible(); - let res = G2Affine::from_bytes(bin.into_val(env)); - let is_in_correct_subgroup: bool = - internal::Env::bls12_381_check_g2_is_in_subgroup(env, res.to_object()) - .unwrap_optimized() - .into(); - match is_in_correct_subgroup { - true => Some(res), - false => None, - } - } - - /// Multiplies a point `p0` in G2 by a scalar. - pub fn g2_mul(&self, p0: &G2Affine, scalar: &U256) -> G2Affine { - let env = self.env(); - let bin = - internal::Env::bls12_381_g2_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - G2Affine::from_bytes(bin.into_val(env)) - } - - /// Performs a multi-scalar multiplication (MSM) operation in G2. - pub fn g2_msm(&self, vp: Vec, vs: Vec) -> G2Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_g2_msm(env, vp.into(), vs.into()).unwrap_infallible(); - G2Affine::from_bytes(bin.into_val(env)) - } - - /// Maps an element in the base field `Fp2` to a point in G2. - pub fn map_fp2_to_g2(&self, fp2: &Fp2) -> G2Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_map_fp2_to_g2(env, fp2.to_object()).unwrap_infallible(); - G2Affine::from_bytes(bin.into_val(env)) - } - - /// Hashes a message `msg` to a point in G2, using a domain separation tag `dst`. - pub fn hash_to_g2(&self, msg: &Bytes, dst: &Bytes) -> G2Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_hash_to_g2(env, msg.into(), dst.to_object()) - .unwrap_infallible(); - G2Affine::from_bytes(bin.into_val(env)) - } - - // pairing - - /// Performs a pairing check between vectors of points in G1 and G2. - /// - /// This function computes the pairing for each pair of points in the - /// provided vectors `vp1` (G1 points) and `vp2` (G2 points) and verifies if - /// the overall pairing result is equal to the identity in the target group. - /// - /// # Returns: - /// - `true` if the pairing check holds (i.e., the pairing result is valid - /// and equal to the identity element), otherwise `false`. - /// - /// # Panics: - /// - If the lengths of `vp1` and `vp2` are not equal or if they are empty. - pub fn pairing_check(&self, vp1: Vec, vp2: Vec) -> bool { - let env = self.env(); - internal::Env::bls12_381_multi_pairing_check(env, vp1.into(), vp2.into()) - .unwrap_infallible() - .into() - } - - // scalar arithmetic - - /// Adds two scalars in the BLS12-381 scalar field `Fr`. - pub fn fr_add(&self, lhs: &U256, rhs: &U256) -> U256 { - let env = self.env(); - let v = internal::Env::bls12_381_fr_add(env, lhs.into(), rhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible() - } - - /// Subtracts one scalar from another in the BLS12-381 scalar field `Fr`. - pub fn fr_sub(&self, lhs: &U256, rhs: &U256) -> U256 { - let env = self.env(); - let v = internal::Env::bls12_381_fr_sub(env, lhs.into(), rhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible() - } - - /// Multiplies two scalars in the BLS12-381 scalar field `Fr`. - pub fn fr_mul(&self, lhs: &U256, rhs: &U256) -> U256 { - let env = self.env(); - let v = internal::Env::bls12_381_fr_mul(env, lhs.into(), rhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible() - } - - /// Raises a scalar to the power of a given exponent in the BLS12-381 scalar field `Fr`. - pub fn fr_pow(&self, lhs: &U256, rhs: u64) -> U256 { - let env = self.env(); - let rhs = U64Val::try_from_val(env, &rhs).unwrap_optimized(); - let v = internal::Env::bls12_381_fr_pow(env, lhs.into(), rhs).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible() - } - - /// Computes the multiplicative inverse of a scalar in the BLS12-381 scalar field `Fr`. - pub fn fr_inv(&self, lhs: &U256) -> U256 { - let env = self.env(); - let v = internal::Env::bls12_381_fr_inv(env, lhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible() - } -} diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs new file mode 100644 index 000000000..8669ea836 --- /dev/null +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -0,0 +1,294 @@ +use crate::{ + env::internal::{self, BytesObject, U64Val}, + impl_bytesn_repr, + unwrap::{UnwrapInfallible, UnwrapOptimized}, + Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256, +}; +use core::{cmp::Ordering, fmt::Debug}; +/// Bls12_381 provides access to curve and field arithmetics on the BLS12-381 +/// curve. +pub struct Bls12_381 { + env: Env, +} + +/// # `G1Affine` is a point in the G1 group (subgroup defined over the base field +/// `Fq`) of the BLS12-381 elliptic curve +/// +/// # Serialization: +/// - The 96 bytes represent the **uncompressed encoding** of a point in G1. The +/// Bytes consist of `be_byte(X) || be_byte(Y)` (`||` is concatenation), +/// where 'X' and 'Y' are the two coordinates, each being a base field element +/// `Fp` +/// - The most significant three bits (bits 0-3) of the first byte are reserved +/// for encoding flags: +/// - compression_flag (bit 0): Must always be set (1), as only uncompressed +/// points are supported. +/// - infinity_flag (bit 1): Set if the point is the point at infinity (zero +/// point), in which case all other bits must be zero. +/// - sort_flag (bit 2): Must always be unset (0). +/// +/// # Example Usage: +/// ```rust +/// use soroban_sdk::{Env, bytesn, crypto::bls12_381::{Bls12_381, G1Affine}}; +/// let env = Env::default(); +/// let bls12_381 = env.crypto().bls12_381(); +/// let zero = G1Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)); +/// let one = G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1)); +/// let res = bls12_381.g1_add(&zero, &one); +/// assert_eq!(res, one); +/// ``` +#[derive(Clone)] +#[repr(transparent)] +pub struct G1Affine(BytesN<96>); + +/// # `G2Affine` is a point in the G2 group (subgroup defined over the quadratic +/// extension field `Fq2`) of the BLS12-381 elliptic curve +/// +/// # Serialization: +/// - The 192 bytes represent the **uncompressed encoding** of a point in G2. +/// The bytes consist of `be_bytes(X_c1) || be_bytes(X_c0) || be_bytes(Y_c1) +/// || be_bytes(Y_c0)` (`||` is concatenation), where 'X' and 'Y' are the two +/// coordinates, each being an extension field element `Fp2` and `c0`, `c1` +/// are components of `Fp2` (each being `Fp`). +/// - The most significant three bits (bits 0-3) of the first byte are reserved +/// for encoding flags: +/// - compression_flag (bit 0): Must always be set (1), as only uncompressed +/// points are supported. +/// - infinity_flag (bit 1): Set if the point is the point at infinity (zero +/// point), in which case all other bits must be zero. +/// - sort_flag (bit 2): Must always be unset (0). +#[derive(Clone)] +#[repr(transparent)] +pub struct G2Affine(BytesN<192>); + +/// # `Fp` represents an element of the base field `Fq` of the BLS12-381 elliptic +/// curve +/// +/// # Serialization: +/// - The 48 bytes represent the **big-endian encoding** of an element in the +/// field `Fp`. The value is serialized as a big-endian integer. +#[derive(Clone)] +#[repr(transparent)] +pub struct Fp(BytesN<48>); + +/// # `Fp2` represents an element of the quadratic extension field `Fq2` of the +/// BLS12-381 elliptic curve +/// +/// # Serialization: +/// - The 96 bytes represent the **big-endian encoding** of an element in the +/// field `Fp2`. The bytes consist of `be_bytes(c1) || be_bytes(c0)` (`||` is +/// concatenation), where `c0` and `c1` are the two `Fp` elements (the real +/// and imaginary components). +#[derive(Clone)] +#[repr(transparent)] +pub struct Fp2(BytesN<96>); + +impl_bytesn_repr!(G1Affine, 96); +impl_bytesn_repr!(G2Affine, 192); +impl_bytesn_repr!(Fp, 48); +impl_bytesn_repr!(Fp2, 96); + +impl Bls12_381 { + pub(crate) fn new(env: &Env) -> Bls12_381 { + Bls12_381 { env: env.clone() } + } + + pub fn env(&self) -> &Env { + &self.env + } + + // g1 + + /// Checks if a point `p` in G1 is in the correct subgroup. + pub fn g1_is_in_subgroup(&self, p: &G1Affine) -> bool { + let env = self.env(); + let res = internal::Env::bls12_381_check_g1_is_in_subgroup(env, p.to_object()) + .unwrap_infallible(); + res.into() + } + + /// Adds two points `p0` and `p1` in G1. + pub fn g1_add(&self, p0: &G1Affine, p1: &G1Affine) -> G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + G1Affine::from_bytes(bin.into_val(env)) + } + + /// Adds two points `p0` and `p1` in G1, ensuring that the result is in the + /// correct subgroup. Note the subgroup check is computationally expensive, + /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. + pn`, + /// it may make sense to only call g1_checked_add on the final addition, + /// while using `g1_add` (non-checked version) on the intermediate ones. + pub fn g1_checked_add(&self, p0: &G1Affine, p1: &G1Affine) -> Option { + let env = self.env(); + let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + let res = G1Affine::from_bytes(bin.into_val(env)); + let is_in_correct_subgroup: bool = + internal::Env::bls12_381_check_g1_is_in_subgroup(env, res.to_object()) + .unwrap_optimized() + .into(); + match is_in_correct_subgroup { + true => Some(res), + false => None, + } + } + + /// Multiplies a point `p0` in G1 by a scalar. + pub fn g1_mul(&self, p0: &G1Affine, scalar: &U256) -> G1Affine { + let env = self.env(); + let bin = + internal::Env::bls12_381_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); + G1Affine::from_bytes(bin.into_val(env)) + } + + /// Performs a multi-scalar multiplication (MSM) operation in G1. + pub fn g1_msm(&self, vp: Vec, vs: Vec) -> G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g1_msm(env, vp.into(), vs.into()).unwrap_infallible(); + G1Affine::from_bytes(bin.into_val(env)) + } + + /// Maps an element in the base field `Fp` to a point in G1. + pub fn map_fp_to_g1(&self, fp: &Fp) -> G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_map_fp_to_g1(env, fp.to_object()).unwrap_infallible(); + G1Affine::from_bytes(bin.into_val(env)) + } + + /// Hashes a message `msg` to a point in G1, using a domain separation tag `dst`. + pub fn hash_to_g1(&self, msg: &Bytes, dst: &Bytes) -> G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_hash_to_g1(env, msg.into(), dst.to_object()) + .unwrap_infallible(); + G1Affine::from_bytes(bin.into_val(env)) + } + + // g2 + + /// Checks if a point `p` in G2 is in the correct subgroup. + pub fn g2_is_in_subgroup(&self, p: &G2Affine) -> bool { + let env = self.env(); + let res = internal::Env::bls12_381_check_g2_is_in_subgroup(env, p.to_object()) + .unwrap_infallible(); + res.into() + } + + /// Adds two points `p0` and `p1` in G2. + pub fn g2_add(&self, p0: &G2Affine, p1: &G2Affine) -> G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + G2Affine::from_bytes(bin.into_val(env)) + } + + /// Adds two points `p0` and `p1` in G2, ensuring that the result is in the + /// correct subgroup. Note the subgroup check is computationally expensive, + /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. +pn`, + /// it may make sense to only call g2_checked_add on the final addition, + /// while using `g2_add` (non-checked version) on the intermediate ones. + pub fn g2_checked_add(&self, p0: &G2Affine, p1: &G2Affine) -> Option { + let env = self.env(); + let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + let res = G2Affine::from_bytes(bin.into_val(env)); + let is_in_correct_subgroup: bool = + internal::Env::bls12_381_check_g2_is_in_subgroup(env, res.to_object()) + .unwrap_optimized() + .into(); + match is_in_correct_subgroup { + true => Some(res), + false => None, + } + } + + /// Multiplies a point `p0` in G2 by a scalar. + pub fn g2_mul(&self, p0: &G2Affine, scalar: &U256) -> G2Affine { + let env = self.env(); + let bin = + internal::Env::bls12_381_g2_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); + G2Affine::from_bytes(bin.into_val(env)) + } + + /// Performs a multi-scalar multiplication (MSM) operation in G2. + pub fn g2_msm(&self, vp: Vec, vs: Vec) -> G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g2_msm(env, vp.into(), vs.into()).unwrap_infallible(); + G2Affine::from_bytes(bin.into_val(env)) + } + + /// Maps an element in the base field `Fp2` to a point in G2. + pub fn map_fp2_to_g2(&self, fp2: &Fp2) -> G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_map_fp2_to_g2(env, fp2.to_object()).unwrap_infallible(); + G2Affine::from_bytes(bin.into_val(env)) + } + + /// Hashes a message `msg` to a point in G2, using a domain separation tag `dst`. + pub fn hash_to_g2(&self, msg: &Bytes, dst: &Bytes) -> G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_hash_to_g2(env, msg.into(), dst.to_object()) + .unwrap_infallible(); + G2Affine::from_bytes(bin.into_val(env)) + } + + // pairing + + /// Performs a pairing check between vectors of points in G1 and G2. + /// + /// This function computes the pairing for each pair of points in the + /// provided vectors `vp1` (G1 points) and `vp2` (G2 points) and verifies if + /// the overall pairing result is equal to the identity in the target group. + /// + /// # Returns: + /// - `true` if the pairing check holds (i.e., the pairing result is valid + /// and equal to the identity element), otherwise `false`. + /// + /// # Panics: + /// - If the lengths of `vp1` and `vp2` are not equal or if they are empty. + pub fn pairing_check(&self, vp1: Vec, vp2: Vec) -> bool { + let env = self.env(); + internal::Env::bls12_381_multi_pairing_check(env, vp1.into(), vp2.into()) + .unwrap_infallible() + .into() + } + + // scalar arithmetic + + /// Adds two scalars in the BLS12-381 scalar field `Fr`. + pub fn fr_add(&self, lhs: &U256, rhs: &U256) -> U256 { + let env = self.env(); + let v = internal::Env::bls12_381_fr_add(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible() + } + + /// Subtracts one scalar from another in the BLS12-381 scalar field `Fr`. + pub fn fr_sub(&self, lhs: &U256, rhs: &U256) -> U256 { + let env = self.env(); + let v = internal::Env::bls12_381_fr_sub(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible() + } + + /// Multiplies two scalars in the BLS12-381 scalar field `Fr`. + pub fn fr_mul(&self, lhs: &U256, rhs: &U256) -> U256 { + let env = self.env(); + let v = internal::Env::bls12_381_fr_mul(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible() + } + + /// Raises a scalar to the power of a given exponent in the BLS12-381 scalar field `Fr`. + pub fn fr_pow(&self, lhs: &U256, rhs: u64) -> U256 { + let env = self.env(); + let rhs = U64Val::try_from_val(env, &rhs).unwrap_optimized(); + let v = internal::Env::bls12_381_fr_pow(env, lhs.into(), rhs).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible() + } + + /// Computes the multiplicative inverse of a scalar in the BLS12-381 scalar field `Fr`. + pub fn fr_inv(&self, lhs: &U256) -> U256 { + let env = self.env(); + let v = internal::Env::bls12_381_fr_inv(env, lhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible() + } +} diff --git a/soroban-sdk/src/tests/crypto_bls12_381.rs b/soroban-sdk/src/tests/crypto_bls12_381.rs index c8e084b9a..04d03ac47 100644 --- a/soroban-sdk/src/tests/crypto_bls12_381.rs +++ b/soroban-sdk/src/tests/crypto_bls12_381.rs @@ -1,6 +1,6 @@ use crate::{ bytes, bytesn, - crypto::{Bls12_381, Fp, Fp2, G1Affine, G2Affine}, + crypto::bls12_381::{Bls12_381, Fp, Fp2, G1Affine, G2Affine}, vec, Bytes, Env, Vec, U256, }; From 149ee19edce263cd4cd6d9a384c637237bdad0d7 Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Mon, 23 Sep 2024 09:41:10 -0700 Subject: [PATCH 08/18] Update soroban-sdk/src/crypto/bls12_381.rs Co-authored-by: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> --- soroban-sdk/src/crypto/bls12_381.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs index 8669ea836..1fe9b969a 100644 --- a/soroban-sdk/src/crypto/bls12_381.rs +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -11,7 +11,7 @@ pub struct Bls12_381 { env: Env, } -/// # `G1Affine` is a point in the G1 group (subgroup defined over the base field +/// `G1Affine` is a point in the G1 group (subgroup defined over the base field /// `Fq`) of the BLS12-381 elliptic curve /// /// # Serialization: From 86cbca159fbc233f5f1e7ce7a68030cf5d460e6f Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Mon, 23 Sep 2024 10:35:00 -0700 Subject: [PATCH 09/18] Use unchecked_new --- soroban-sdk/src/crypto/bls12_381.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs index 1fe9b969a..4b62dd0c3 100644 --- a/soroban-sdk/src/crypto/bls12_381.rs +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -112,7 +112,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - G1Affine::from_bytes(bin.into_val(env)) + unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } } /// Adds two points `p0` and `p1` in G1, ensuring that the result is in the @@ -124,7 +124,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - let res = G1Affine::from_bytes(bin.into_val(env)); + let res = unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) }; let is_in_correct_subgroup: bool = internal::Env::bls12_381_check_g1_is_in_subgroup(env, res.to_object()) .unwrap_optimized() @@ -140,21 +140,21 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - G1Affine::from_bytes(bin.into_val(env)) + unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } } /// Performs a multi-scalar multiplication (MSM) operation in G1. pub fn g1_msm(&self, vp: Vec, vs: Vec) -> G1Affine { let env = self.env(); let bin = internal::Env::bls12_381_g1_msm(env, vp.into(), vs.into()).unwrap_infallible(); - G1Affine::from_bytes(bin.into_val(env)) + unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } } /// Maps an element in the base field `Fp` to a point in G1. pub fn map_fp_to_g1(&self, fp: &Fp) -> G1Affine { let env = self.env(); let bin = internal::Env::bls12_381_map_fp_to_g1(env, fp.to_object()).unwrap_infallible(); - G1Affine::from_bytes(bin.into_val(env)) + unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } } /// Hashes a message `msg` to a point in G1, using a domain separation tag `dst`. @@ -162,7 +162,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_hash_to_g1(env, msg.into(), dst.to_object()) .unwrap_infallible(); - G1Affine::from_bytes(bin.into_val(env)) + unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } } // g2 @@ -180,7 +180,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - G2Affine::from_bytes(bin.into_val(env)) + unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } } /// Adds two points `p0` and `p1` in G2, ensuring that the result is in the @@ -192,7 +192,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - let res = G2Affine::from_bytes(bin.into_val(env)); + let res = unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) }; let is_in_correct_subgroup: bool = internal::Env::bls12_381_check_g2_is_in_subgroup(env, res.to_object()) .unwrap_optimized() @@ -208,21 +208,21 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g2_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - G2Affine::from_bytes(bin.into_val(env)) + unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } } /// Performs a multi-scalar multiplication (MSM) operation in G2. pub fn g2_msm(&self, vp: Vec, vs: Vec) -> G2Affine { let env = self.env(); let bin = internal::Env::bls12_381_g2_msm(env, vp.into(), vs.into()).unwrap_infallible(); - G2Affine::from_bytes(bin.into_val(env)) + unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } } /// Maps an element in the base field `Fp2` to a point in G2. pub fn map_fp2_to_g2(&self, fp2: &Fp2) -> G2Affine { let env = self.env(); let bin = internal::Env::bls12_381_map_fp2_to_g2(env, fp2.to_object()).unwrap_infallible(); - G2Affine::from_bytes(bin.into_val(env)) + unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } } /// Hashes a message `msg` to a point in G2, using a domain separation tag `dst`. @@ -230,7 +230,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_hash_to_g2(env, msg.into(), dst.to_object()) .unwrap_infallible(); - G2Affine::from_bytes(bin.into_val(env)) + unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } } // pairing From 8a6a5b5d24071ee96177a222d7a1c419e7f19474 Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Mon, 23 Sep 2024 10:44:56 -0700 Subject: [PATCH 10/18] Add a from_array method --- soroban-sdk/src/bytes.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/soroban-sdk/src/bytes.rs b/soroban-sdk/src/bytes.rs index 4c510a355..706a87590 100644 --- a/soroban-sdk/src/bytes.rs +++ b/soroban-sdk/src/bytes.rs @@ -122,6 +122,10 @@ macro_rules! impl_bytesn_repr { self.0.to_array() } + pub fn from_array(&self, env: &Env, array: &[u8; $size]) -> Self { + Self(>::from_array(env, array)) + } + pub fn as_val(&self) -> &Val { self.0.as_val() } From 6d5604adfc38b0baa6d2eb7b5607d1a697e12b74 Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Mon, 23 Sep 2024 16:58:42 -0700 Subject: [PATCH 11/18] cleanup --- soroban-sdk/src/crypto/bls12_381.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs index 4b62dd0c3..a1ed32902 100644 --- a/soroban-sdk/src/crypto/bls12_381.rs +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -112,7 +112,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } + unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } } /// Adds two points `p0` and `p1` in G1, ensuring that the result is in the @@ -124,7 +124,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - let res = unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) }; + let res = unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }; let is_in_correct_subgroup: bool = internal::Env::bls12_381_check_g1_is_in_subgroup(env, res.to_object()) .unwrap_optimized() @@ -140,21 +140,21 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } + unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } } /// Performs a multi-scalar multiplication (MSM) operation in G1. pub fn g1_msm(&self, vp: Vec, vs: Vec) -> G1Affine { let env = self.env(); let bin = internal::Env::bls12_381_g1_msm(env, vp.into(), vs.into()).unwrap_infallible(); - unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } + unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } } /// Maps an element in the base field `Fp` to a point in G1. pub fn map_fp_to_g1(&self, fp: &Fp) -> G1Affine { let env = self.env(); let bin = internal::Env::bls12_381_map_fp_to_g1(env, fp.to_object()).unwrap_infallible(); - unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } + unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } } /// Hashes a message `msg` to a point in G1, using a domain separation tag `dst`. @@ -162,7 +162,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_hash_to_g1(env, msg.into(), dst.to_object()) .unwrap_infallible(); - unsafe { G1Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } + unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } } // g2 @@ -180,7 +180,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } + unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } } /// Adds two points `p0` and `p1` in G2, ensuring that the result is in the @@ -192,7 +192,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) .unwrap_infallible(); - let res = unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) }; + let res = unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }; let is_in_correct_subgroup: bool = internal::Env::bls12_381_check_g2_is_in_subgroup(env, res.to_object()) .unwrap_optimized() @@ -208,21 +208,21 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_g2_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } + unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } } /// Performs a multi-scalar multiplication (MSM) operation in G2. pub fn g2_msm(&self, vp: Vec, vs: Vec) -> G2Affine { let env = self.env(); let bin = internal::Env::bls12_381_g2_msm(env, vp.into(), vs.into()).unwrap_infallible(); - unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } + unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } } /// Maps an element in the base field `Fp2` to a point in G2. pub fn map_fp2_to_g2(&self, fp2: &Fp2) -> G2Affine { let env = self.env(); let bin = internal::Env::bls12_381_map_fp2_to_g2(env, fp2.to_object()).unwrap_infallible(); - unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } + unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } } /// Hashes a message `msg` to a point in G2, using a domain separation tag `dst`. @@ -230,7 +230,7 @@ impl Bls12_381 { let env = self.env(); let bin = internal::Env::bls12_381_hash_to_g2(env, msg.into(), dst.to_object()) .unwrap_infallible(); - unsafe { G2Affine::from_bytes(>::unchecked_new(env.clone(), bin)) } + unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } } // pairing From 177581c240266a607fa5c03dd648a7aedf7f6e4c Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Mon, 23 Sep 2024 17:27:58 -0700 Subject: [PATCH 12/18] Add methods to affine types --- soroban-sdk/src/crypto/bls12_381.rs | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs index a1ed32902..e19b53bcf 100644 --- a/soroban-sdk/src/crypto/bls12_381.rs +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -88,6 +88,58 @@ impl_bytesn_repr!(G2Affine, 192); impl_bytesn_repr!(Fp, 48); impl_bytesn_repr!(Fp2, 96); +impl G1Affine { + pub fn env(&self) -> &Env { + self.0.env() + } + + pub fn is_in_subgroup(&self) -> bool { + self.env().crypto().bls12_381().g1_is_in_subgroup(self) + } + + pub fn checked_add(&self, rhs: &Self) -> Option { + self.env().crypto().bls12_381().g1_checked_add(self, rhs) + } + + pub fn mul(&self, scalar: &U256) -> Self { + self.env().crypto().bls12_381().g1_mul(self, &scalar) + } +} + +impl core::ops::Add for G1Affine { + type Output = G1Affine; + + fn add(self, rhs: Self) -> Self::Output { + self.env().crypto().bls12_381().g1_add(&self, &rhs) + } +} + +impl G2Affine { + pub fn env(&self) -> &Env { + self.0.env() + } + + pub fn is_in_subgroup(&self) -> bool { + self.env().crypto().bls12_381().g2_is_in_subgroup(self) + } + + pub fn checked_add(&self, rhs: &Self) -> Option { + self.env().crypto().bls12_381().g2_checked_add(self, rhs) + } + + pub fn mul(&self, scalar: &U256) -> Self { + self.env().crypto().bls12_381().g2_mul(self, &scalar) + } +} + +impl core::ops::Add for G2Affine { + type Output = G2Affine; + + fn add(self, rhs: Self) -> Self::Output { + self.env().crypto().bls12_381().g2_add(&self, &rhs) + } +} + impl Bls12_381 { pub(crate) fn new(env: &Env) -> Bls12_381 { Bls12_381 { env: env.clone() } From 7dde397279c3d4a5a22d3379bebefddd9aad450a Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Mon, 23 Sep 2024 18:25:31 -0700 Subject: [PATCH 13/18] Update soroban-sdk/src/crypto/bls12_381.rs Co-authored-by: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> --- soroban-sdk/src/crypto/bls12_381.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs index e19b53bcf..509c7cc77 100644 --- a/soroban-sdk/src/crypto/bls12_381.rs +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -41,7 +41,7 @@ pub struct Bls12_381 { #[repr(transparent)] pub struct G1Affine(BytesN<96>); -/// # `G2Affine` is a point in the G2 group (subgroup defined over the quadratic +/// `G2Affine` is a point in the G2 group (subgroup defined over the quadratic /// extension field `Fq2`) of the BLS12-381 elliptic curve /// /// # Serialization: From d52a0095f2bc5385de1d5fda15f162cdbf2a3370 Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Mon, 23 Sep 2024 18:25:37 -0700 Subject: [PATCH 14/18] Update soroban-sdk/src/crypto/bls12_381.rs Co-authored-by: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> --- soroban-sdk/src/crypto/bls12_381.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs index 509c7cc77..da19e80ec 100644 --- a/soroban-sdk/src/crypto/bls12_381.rs +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -61,7 +61,7 @@ pub struct G1Affine(BytesN<96>); #[repr(transparent)] pub struct G2Affine(BytesN<192>); -/// # `Fp` represents an element of the base field `Fq` of the BLS12-381 elliptic +/// `Fp` represents an element of the base field `Fq` of the BLS12-381 elliptic /// curve /// /// # Serialization: From 718574aa76da0829a6b7a92df80b3744cfb2d7fe Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Mon, 23 Sep 2024 18:25:48 -0700 Subject: [PATCH 15/18] Update soroban-sdk/src/crypto/bls12_381.rs Co-authored-by: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> --- soroban-sdk/src/crypto/bls12_381.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs index da19e80ec..09760042d 100644 --- a/soroban-sdk/src/crypto/bls12_381.rs +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -5,6 +5,7 @@ use crate::{ Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256, }; use core::{cmp::Ordering, fmt::Debug}; + /// Bls12_381 provides access to curve and field arithmetics on the BLS12-381 /// curve. pub struct Bls12_381 { From 3ba3803546f9ce110a839d723dc1097501a7625a Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Mon, 23 Sep 2024 18:25:53 -0700 Subject: [PATCH 16/18] Update soroban-sdk/src/crypto/bls12_381.rs Co-authored-by: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> --- soroban-sdk/src/crypto/bls12_381.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs index 09760042d..3a98eaf5a 100644 --- a/soroban-sdk/src/crypto/bls12_381.rs +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -72,7 +72,7 @@ pub struct G2Affine(BytesN<192>); #[repr(transparent)] pub struct Fp(BytesN<48>); -/// # `Fp2` represents an element of the quadratic extension field `Fq2` of the +/// `Fp2` represents an element of the quadratic extension field `Fq2` of the /// BLS12-381 elliptic curve /// /// # Serialization: From cb1f27f2d547b575d76fe2df7fefdfd377c081ca Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Mon, 23 Sep 2024 19:57:50 -0700 Subject: [PATCH 17/18] Use ops::Mul --- soroban-sdk/src/crypto/bls12_381.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs index 3a98eaf5a..45db161f1 100644 --- a/soroban-sdk/src/crypto/bls12_381.rs +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -101,10 +101,6 @@ impl G1Affine { pub fn checked_add(&self, rhs: &Self) -> Option { self.env().crypto().bls12_381().g1_checked_add(self, rhs) } - - pub fn mul(&self, scalar: &U256) -> Self { - self.env().crypto().bls12_381().g1_mul(self, &scalar) - } } impl core::ops::Add for G1Affine { @@ -115,6 +111,14 @@ impl core::ops::Add for G1Affine { } } +impl core::ops::Mul for G1Affine { + type Output = G1Affine; + + fn mul(self, rhs: U256) -> Self::Output { + self.env().crypto().bls12_381().g1_mul(&self, &rhs) + } +} + impl G2Affine { pub fn env(&self) -> &Env { self.0.env() @@ -127,10 +131,6 @@ impl G2Affine { pub fn checked_add(&self, rhs: &Self) -> Option { self.env().crypto().bls12_381().g2_checked_add(self, rhs) } - - pub fn mul(&self, scalar: &U256) -> Self { - self.env().crypto().bls12_381().g2_mul(self, &scalar) - } } impl core::ops::Add for G2Affine { @@ -141,6 +141,14 @@ impl core::ops::Add for G2Affine { } } +impl core::ops::Mul for G2Affine { + type Output = G2Affine; + + fn mul(self, rhs: U256) -> Self::Output { + self.env().crypto().bls12_381().g2_mul(&self, &rhs) + } +} + impl Bls12_381 { pub(crate) fn new(env: &Env) -> Bls12_381 { Bls12_381 { env: env.clone() } From 401388f4f625fe8615727e18dfad6062ee044da8 Mon Sep 17 00:00:00 2001 From: Siddharth Suresh Date: Wed, 25 Sep 2024 16:06:25 -0700 Subject: [PATCH 18/18] Add Fp methods on type --- soroban-sdk/src/crypto/bls12_381.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/soroban-sdk/src/crypto/bls12_381.rs b/soroban-sdk/src/crypto/bls12_381.rs index 45db161f1..cbfe9d41c 100644 --- a/soroban-sdk/src/crypto/bls12_381.rs +++ b/soroban-sdk/src/crypto/bls12_381.rs @@ -149,6 +149,26 @@ impl core::ops::Mul for G2Affine { } } +impl Fp { + pub fn env(&self) -> &Env { + self.0.env() + } + + pub fn map_to_g1(&self) -> G1Affine { + self.env().crypto().bls12_381().map_fp_to_g1(self) + } +} + +impl Fp2 { + pub fn env(&self) -> &Env { + self.0.env() + } + + pub fn map_to_g2(&self) -> G2Affine { + self.env().crypto().bls12_381().map_fp2_to_g2(self) + } +} + impl Bls12_381 { pub(crate) fn new(env: &Env) -> Bls12_381 { Bls12_381 { env: env.clone() }