From 96d4b775a49fe9f90009a0e1559c9ed4d90c0195 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 4 Apr 2025 13:31:04 -0700 Subject: [PATCH 01/57] change guest openvm to develop (#1366) --- examples/keccak/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/keccak/Cargo.toml b/examples/keccak/Cargo.toml index 74f15e6234..3c5cd8a26e 100644 --- a/examples/keccak/Cargo.toml +++ b/examples/keccak/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" members = [] [dependencies] -openvm = { git = "https://github.com/openvm-org/openvm.git", features = [ +openvm = { git = "https://github.com/openvm-org/openvm.git", branch = "develop", features = [ "std", ] } openvm-keccak256 = { git = "https://github.com/openvm-org/openvm.git" } From 803f740c7a5347d615bd334cff7a705f9ac5a0e0 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Sat, 22 Feb 2025 01:02:49 +0100 Subject: [PATCH 02/57] poseidon-air: simplify horizen_round_consts impl (#1362) --- crates/circuits/poseidon2-air/src/babybear.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/crates/circuits/poseidon2-air/src/babybear.rs b/crates/circuits/poseidon2-air/src/babybear.rs index e12b60bfb4..6989f992c7 100644 --- a/crates/circuits/poseidon2-air/src/babybear.rs +++ b/crates/circuits/poseidon2-air/src/babybear.rs @@ -18,7 +18,7 @@ pub(crate) fn horizen_to_p3_babybear(horizen_babybear: HorizenBabyBear) -> BabyB } pub(crate) fn horizen_round_consts() -> Poseidon2Constants { - let p3_rc16: Vec> = RC16 + let p3_rc16: Vec> = RC16 .iter() .map(|round| { round @@ -29,18 +29,10 @@ pub(crate) fn horizen_round_consts() -> Poseidon2Constants { .collect(); let p_end = BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS + BABY_BEAR_POSEIDON2_PARTIAL_ROUNDS; - let beginning_full_round_constants: [[BabyBear; POSEIDON2_WIDTH]; - BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS] = from_fn(|i| p3_rc16[i].clone().try_into().unwrap()); - let partial_round_constants: [BabyBear; BABY_BEAR_POSEIDON2_PARTIAL_ROUNDS] = - from_fn(|i| p3_rc16[i + BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS][0]); - let ending_full_round_constants: [[BabyBear; POSEIDON2_WIDTH]; - BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS] = - from_fn(|i| p3_rc16[i + p_end].clone().try_into().unwrap()); - Poseidon2Constants { - beginning_full_round_constants, - partial_round_constants, - ending_full_round_constants, + beginning_full_round_constants: from_fn(|i| p3_rc16[i].clone().try_into().unwrap()), + partial_round_constants: from_fn(|i| p3_rc16[i + BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS][0]), + ending_full_round_constants: from_fn(|i| p3_rc16[i + p_end].clone().try_into().unwrap()), } } From 716468f61e062a4b8705d0f0a5d27bfaa0ebfba5 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Thu, 23 Jan 2025 15:23:09 -0500 Subject: [PATCH 03/57] Added Twisted Edwards chip --- Cargo.lock | 108 +++++- Cargo.toml | 7 +- extensions/ecc/circuit/Cargo.toml | 1 + .../ecc/circuit/src/edwards_chip/README.md | 1 + .../ecc/circuit/src/edwards_chip/add.rs | 41 +++ .../ecc/circuit/src/edwards_chip/mod.rs | 77 +++++ .../ecc/circuit/src/edwards_chip/tests.rs | 189 +++++++++++ extensions/ecc/circuit/src/lib.rs | 3 + .../ecc/circuit/src/weierstrass_extension.rs | 294 ++++++++++------ extensions/ecc/guest/Cargo.toml | 1 + extensions/ecc/guest/src/edwards.rs | 282 ++++++++++++++++ extensions/ecc/guest/src/lib.rs | 20 +- extensions/ecc/sw-macros/src/lib.rs | 10 +- extensions/ecc/te-setup/Cargo.toml | 17 + extensions/ecc/te-setup/src/lib.rs | 314 ++++++++++++++++++ extensions/ecc/tests/Cargo.toml | 1 + .../ecc/tests/programs/examples/edwards_ec.rs | 126 +++++++ extensions/ecc/tests/src/lib.rs | 40 ++- extensions/ecc/transpiler/src/lib.rs | 78 ++++- .../pairing/circuit/src/pairing_extension.rs | 14 +- 20 files changed, 1513 insertions(+), 111 deletions(-) create mode 100644 extensions/ecc/circuit/src/edwards_chip/README.md create mode 100644 extensions/ecc/circuit/src/edwards_chip/add.rs create mode 100644 extensions/ecc/circuit/src/edwards_chip/mod.rs create mode 100644 extensions/ecc/circuit/src/edwards_chip/tests.rs create mode 100644 extensions/ecc/guest/src/edwards.rs create mode 100644 extensions/ecc/te-setup/Cargo.toml create mode 100644 extensions/ecc/te-setup/src/lib.rs create mode 100644 extensions/ecc/tests/programs/examples/edwards_ec.rs diff --git a/Cargo.lock b/Cargo.lock index 58eb08e660..96a814b4c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,6 +159,7 @@ dependencies = [ "foldhash", "hashbrown 0.15.2", "indexmap 2.7.1", + "indexmap 2.7.1", "itoa", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-asm", @@ -175,8 +176,10 @@ dependencies = [ [[package]] name = "alloy-rlp" version = "0.3.11" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" +checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -186,8 +189,10 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" version = "0.3.11" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" +checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" dependencies = [ "proc-macro2", "quote", @@ -340,11 +345,14 @@ dependencies = [ [[package]] name = "anstyle-wincon" version = "3.0.7" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", "once_cell", + "once_cell", "windows-sys 0.59.0", ] @@ -635,8 +643,10 @@ dependencies = [ [[package]] name = "auto_impl" version = "1.2.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" +checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" dependencies = [ "proc-macro2", "quote", @@ -850,8 +860,10 @@ dependencies = [ [[package]] name = "aws-smithy-async" version = "1.2.4" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa59d1327d8b5053c54bf2eaae63bf629ba9e904434d0835a28ed3c0ed0a614e" +checksum = "fa59d1327d8b5053c54bf2eaae63bf629ba9e904434d0835a28ed3c0ed0a614e" dependencies = [ "futures-util", "pin-project-lite", @@ -870,6 +882,7 @@ dependencies = [ "crc32c", "crc32fast", "crc64fast-nvme", + "crc64fast-nvme", "hex", "http 0.2.12", "http-body 0.4.6", @@ -894,6 +907,7 @@ dependencies = [ [[package]] name = "aws-smithy-http" version = "0.60.12" +version = "0.60.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7809c27ad8da6a6a68c454e651d4962479e81472aa19ae99e59f9aba1f9713cc" dependencies = [ @@ -935,8 +949,10 @@ dependencies = [ [[package]] name = "aws-smithy-json" version = "0.61.2" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "623a51127f24c30776c8b374295f2df78d92517386f77ba30773f15a30ce1422" +checksum = "623a51127f24c30776c8b374295f2df78d92517386f77ba30773f15a30ce1422" dependencies = [ "aws-smithy-types", ] @@ -1178,8 +1194,10 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.8.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bitvec" @@ -1474,6 +1492,7 @@ dependencies = [ "camino", "cargo-platform", "semver 1.0.25", + "semver 1.0.25", "serde", "serde_json", "thiserror 1.0.69", @@ -1698,7 +1717,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ - "libc", + "crc-catalog", ] [[package]] @@ -1743,6 +1762,15 @@ dependencies = [ "crc", ] +[[package]] +name = "crc64fast-nvme" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4955638f00a809894c947f85a024020a20815b65a5eea633798ea7924edab2b3" +dependencies = [ + "crc", +] + [[package]] name = "criterion" version = "0.5.1" @@ -2827,8 +2855,10 @@ dependencies = [ [[package]] name = "getset" version = "0.1.4" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eded738faa0e88d3abc9d1a13cb11adc2073c400969eeb8793cf7132589959fc" +checksum = "eded738faa0e88d3abc9d1a13cb11adc2073c400969eeb8793cf7132589959fc" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2916,6 +2946,7 @@ dependencies = [ "futures-util", "http 0.2.12", "indexmap 2.7.1", + "indexmap 2.7.1", "slab", "tokio", "tokio-util", @@ -3554,8 +3585,10 @@ dependencies = [ [[package]] name = "indexmap" version = "2.7.1" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -3645,8 +3678,10 @@ dependencies = [ [[package]] name = "js-sys" version = "0.3.77" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -3864,8 +3899,10 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] name = "log" version = "0.4.25" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "lru" @@ -3962,6 +3999,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62a6a1f7141f1d9bc7a886b87536bbfc97752e08b369e1e0453a9acfab5f5da4" dependencies = [ + "indexmap 2.7.1", "indexmap 2.7.1", "itoa", "lockfree-object-pool", @@ -3984,6 +4022,7 @@ dependencies = [ "crossbeam-utils", "hashbrown 0.14.5", "indexmap 2.7.1", + "indexmap 2.7.1", "metrics", "num_cpus", "ordered-float", @@ -4089,6 +4128,21 @@ dependencies = [ "serde", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "smallvec", +] + [[package]] name = "num-complex" version = "0.4.6" @@ -4634,6 +4688,7 @@ dependencies = [ "hex-literal 0.4.1", "lazy_static", "num-bigint 0.4.6", + "num-bigint-dig", "num-integer", "num-traits", "once_cell", @@ -4702,6 +4757,17 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "openvm-ecc-te-setup" +version = "0.2.0-alpha" +dependencies = [ + "num-bigint 0.4.6", + "openvm-macros-common", + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "openvm-ecc-transpiler" version = "1.2.1-rc.0" @@ -5445,8 +5511,10 @@ dependencies = [ [[package]] name = "outref" version = "0.5.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] name = "overload" @@ -6024,6 +6092,7 @@ checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", "thiserror 2.0.11", + "thiserror 2.0.11", "ucd-trie", ] @@ -6233,8 +6302,10 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "prettyplease" version = "0.2.29" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" +checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" dependencies = [ "proc-macro2", "syn 2.0.98", @@ -6288,8 +6359,10 @@ dependencies = [ [[package]] name = "proc-macro2" version = "1.0.93" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -6928,6 +7001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.25", + "semver 1.0.25", ] [[package]] @@ -7151,8 +7225,10 @@ dependencies = [ [[package]] name = "semver" version = "1.0.25" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" dependencies = [ "serde", ] @@ -7210,6 +7286,7 @@ version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" dependencies = [ + "indexmap 2.7.1", "indexmap 2.7.1", "itoa", "memchr", @@ -7259,6 +7336,7 @@ dependencies = [ "hex", "indexmap 1.9.3", "indexmap 2.7.1", + "indexmap 2.7.1", "serde", "serde_derive", "serde_json", @@ -7809,8 +7887,10 @@ dependencies = [ [[package]] name = "test-log" version = "0.2.17" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f46083d221181166e5b6f6b1e5f1d499f3a76888826e6cb1d057554157cd0f" +checksum = "e7f46083d221181166e5b6f6b1e5f1d499f3a76888826e6cb1d057554157cd0f" dependencies = [ "env_logger", "test-log-macros", @@ -7820,8 +7900,10 @@ dependencies = [ [[package]] name = "test-log-macros" version = "0.2.17" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" +checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" dependencies = [ "proc-macro2", "quote", @@ -7840,10 +7922,13 @@ dependencies = [ [[package]] name = "thiserror" version = "2.0.11" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ "thiserror-impl 2.0.11", + "thiserror-impl 2.0.11", ] [[package]] @@ -7860,8 +7945,10 @@ dependencies = [ [[package]] name = "thiserror-impl" version = "2.0.11" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", @@ -8114,6 +8201,7 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ + "indexmap 2.7.1", "indexmap 2.7.1", "serde", "serde_spanned", @@ -8356,8 +8444,10 @@ checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6" [[package]] name = "valuable" version = "0.1.1" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -8442,20 +8532,25 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" version = "0.2.100" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.100" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", @@ -8481,8 +8576,10 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" version = "0.2.100" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -8491,8 +8588,10 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" version = "0.2.100" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -8504,17 +8603,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" version = "0.2.100" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" version = "0.3.77" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 24156f7ac9..afb0a76cd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,8 @@ members = [ "extensions/ecc/circuit", "extensions/ecc/transpiler", "extensions/ecc/guest", - "extensions/ecc/sw-macros", + "extensions/ecc/sw-setup", + "extensions/ecc/te-setup", "extensions/ecc/tests", "extensions/pairing/circuit", "extensions/pairing/guest", @@ -161,7 +162,8 @@ openvm-algebra-complex-macros = { path = "extensions/algebra/complex-macros", de openvm-ecc-circuit = { path = "extensions/ecc/circuit", default-features = false } openvm-ecc-transpiler = { path = "extensions/ecc/transpiler", default-features = false } openvm-ecc-guest = { path = "extensions/ecc/guest", default-features = false } -openvm-ecc-sw-macros = { path = "extensions/ecc/sw-macros", default-features = false } +openvm-ecc-sw-setup = { path = "extensions/ecc/sw-setup", default-features = false } +openvm-ecc-te-setup = { path = "extensions/ecc/te-setup", default-features = false } openvm-pairing-circuit = { path = "extensions/pairing/circuit", default-features = false } openvm-pairing-transpiler = { path = "extensions/pairing/transpiler", default-features = false } openvm-pairing-guest = { path = "extensions/pairing/guest", default-features = false } @@ -241,6 +243,7 @@ k256 = { version = "0.13.4", default-features = false } elliptic-curve = { version = "0.13.8", default-features = false } ecdsa-core = { version = "0.16.9", package = "ecdsa", default-features = false } num-bigint = { version = "0.4.6", default-features = false } +num-bigint-dig = { version = "0.8.4", default-features = false } num-integer = { version = "0.1.46", default-features = false } num-traits = { version = "0.2.19", default-features = false } ff = { version = "0.13.1", default-features = false } diff --git a/extensions/ecc/circuit/Cargo.toml b/extensions/ecc/circuit/Cargo.toml index adfce69f36..eb076c8045 100644 --- a/extensions/ecc/circuit/Cargo.toml +++ b/extensions/ecc/circuit/Cargo.toml @@ -21,6 +21,7 @@ openvm-rv32-adapters = { workspace = true } openvm-ecc-transpiler = { workspace = true } num-bigint = { workspace = true } +num-bigint-dig = { workspace = true } num-traits = { workspace = true } strum = { workspace = true } derive_more = { workspace = true } diff --git a/extensions/ecc/circuit/src/edwards_chip/README.md b/extensions/ecc/circuit/src/edwards_chip/README.md new file mode 100644 index 0000000000..009fa95887 --- /dev/null +++ b/extensions/ecc/circuit/src/edwards_chip/README.md @@ -0,0 +1 @@ +Twisted Edwards (te) curve operations \ No newline at end of file diff --git a/extensions/ecc/circuit/src/edwards_chip/add.rs b/extensions/ecc/circuit/src/edwards_chip/add.rs new file mode 100644 index 0000000000..532163a063 --- /dev/null +++ b/extensions/ecc/circuit/src/edwards_chip/add.rs @@ -0,0 +1,41 @@ +use std::{cell::RefCell, rc::Rc}; + +use num_bigint::BigUint; +use num_traits::One; +use openvm_circuit_primitives::var_range::VariableRangeCheckerBus; +use openvm_mod_circuit_builder::{ExprBuilder, ExprBuilderConfig, FieldExpr}; + +pub fn ec_add_expr( + config: ExprBuilderConfig, // The coordinate field. + range_bus: VariableRangeCheckerBus, + a_biguint: BigUint, + d_biguint: BigUint, +) -> FieldExpr { + config.check_valid(); + let builder = ExprBuilder::new(config, range_bus.range_max_bits); + let builder = Rc::new(RefCell::new(builder)); + + let x1 = ExprBuilder::new_input(builder.clone()); + let y1 = ExprBuilder::new_input(builder.clone()); + let x2 = ExprBuilder::new_input(builder.clone()); + let y2 = ExprBuilder::new_input(builder.clone()); + let a = ExprBuilder::new_const(builder.clone(), a_biguint.clone()); + let d = ExprBuilder::new_const(builder.clone(), d_biguint.clone()); + let one = ExprBuilder::new_const(builder.clone(), BigUint::one()); + + let x1y2 = x1.clone() * y2.clone(); + let x2y1 = x2.clone() * y1.clone(); + let y1y2 = y1 * y2; + let x1x2 = x1 * x2; + let dx1x2y1y2 = d * x1x2.clone() * y1y2.clone(); + + let mut x3 = (x1y2 + x2y1) / (one.clone() + dx1x2y1y2.clone()); + let mut y3 = (y1y2 - a * x1x2) / (one - dx1x2y1y2); + + x3.save_output(); + y3.save_output(); + + let builder = builder.borrow().clone(); + + FieldExpr::new_with_setup_values(builder, range_bus, true, vec![a_biguint, d_biguint]) +} diff --git a/extensions/ecc/circuit/src/edwards_chip/mod.rs b/extensions/ecc/circuit/src/edwards_chip/mod.rs new file mode 100644 index 0000000000..f7c3286dab --- /dev/null +++ b/extensions/ecc/circuit/src/edwards_chip/mod.rs @@ -0,0 +1,77 @@ +mod add; +pub use add::*; + +#[cfg(test)] +mod tests; + +use std::sync::{Arc, Mutex}; + +use openvm_circuit::{arch::VmChipWrapper, system::memory::OfflineMemory}; +use openvm_circuit_derive::InstructionExecutor; +use openvm_circuit_primitives::var_range::SharedVariableRangeCheckerChip; +use openvm_circuit_primitives_derive::{BytesStateful, Chip, ChipUsageGetter}; +use openvm_ecc_transpiler::Rv32EdwardsOpcode; +use openvm_mod_circuit_builder::{ExprBuilderConfig, FieldExpressionCoreChip}; +use openvm_rv32_adapters::Rv32VecHeapAdapterChip; +use openvm_stark_backend::p3_field::PrimeField32; + +/// BLOCK_SIZE: how many cells do we read at a time, must be a power of 2. +/// BLOCKS: how many blocks do we need to represent one input or output +/// For example, for bls12_381, BLOCK_SIZE = 16, each element has 3 blocks and with two elements per input AffinePoint, BLOCKS = 6. +/// For secp256k1, BLOCK_SIZE = 32, BLOCKS = 2. +#[derive(Chip, ChipUsageGetter, InstructionExecutor, BytesStateful)] +pub struct TeEcAddChip( + VmChipWrapper< + F, + Rv32VecHeapAdapterChip, + FieldExpressionCoreChip, + >, +); + +// converts from num_bigint::BigUint to num_bigint_dig::BigInt in order to use num_bigint_dig::algorithms::jacobi +fn num_bigint_to_num_bigint_dig(x: &num_bigint::BigUint) -> num_bigint_dig::BigInt { + num_bigint_dig::BigInt::from_bytes_le(num_bigint_dig::Sign::Plus, &x.to_bytes_le()) +} + +impl + TeEcAddChip +{ + pub fn new( + adapter: Rv32VecHeapAdapterChip, + config: ExprBuilderConfig, + offset: usize, + a: num_bigint::BigUint, + d: num_bigint::BigUint, + range_checker: SharedVariableRangeCheckerChip, + offline_memory: Arc>>, + ) -> Self { + // Ensure that the addition operation is complete + assert!( + num_bigint_dig::algorithms::jacobi( + &num_bigint_to_num_bigint_dig(&a), + &num_bigint_to_num_bigint_dig(&config.modulus) + ) == 1 + ); + assert!( + num_bigint_dig::algorithms::jacobi( + &num_bigint_to_num_bigint_dig(&d), + &num_bigint_to_num_bigint_dig(&config.modulus) + ) == -1 + ); + + let expr = ec_add_expr(config, range_checker.bus(), a, d); + let core = FieldExpressionCoreChip::new( + expr, + offset, + vec![ + Rv32EdwardsOpcode::EC_ADD as usize, + Rv32EdwardsOpcode::SETUP_EC_ADD as usize, + ], + vec![], + range_checker, + "TeEcAdd", + true, + ); + Self(VmChipWrapper::new(adapter, core, offline_memory)) + } +} diff --git a/extensions/ecc/circuit/src/edwards_chip/tests.rs b/extensions/ecc/circuit/src/edwards_chip/tests.rs new file mode 100644 index 0000000000..c492b38c1d --- /dev/null +++ b/extensions/ecc/circuit/src/edwards_chip/tests.rs @@ -0,0 +1,189 @@ +use std::str::FromStr; + +use num_bigint::BigUint; +use num_traits::FromPrimitive; +use openvm_circuit::arch::{testing::VmChipTestBuilder, BITWISE_OP_LOOKUP_BUS}; +use openvm_circuit_primitives::{ + bigint::utils::big_uint_to_limbs, + bitwise_op_lookup::{BitwiseOperationLookupBus, SharedBitwiseOperationLookupChip}, +}; +use openvm_ecc_transpiler::Rv32EdwardsOpcode; +use openvm_instructions::{riscv::RV32_CELL_BITS, LocalOpcode}; +use openvm_mod_circuit_builder::{test_utils::biguint_to_limbs, ExprBuilderConfig, FieldExpr}; +use openvm_rv32_adapters::{rv32_write_heap_default, Rv32VecHeapAdapterChip}; +use openvm_stark_backend::p3_field::FieldAlgebra; +use openvm_stark_sdk::p3_baby_bear::BabyBear; + +use super::TeEcAddChip; + +const NUM_LIMBS: usize = 32; +const LIMB_BITS: usize = 8; +const BLOCK_SIZE: usize = 32; +type F = BabyBear; + +lazy_static::lazy_static! { + pub static ref SampleEcPoints: Vec<(BigUint, BigUint)> = { + // Base point of edwards25519 + let x1 = BigUint::from_str( + "15112221349535400772501151409588531511454012693041857206046113283949847762202", + ) + .unwrap(); + let y1 = BigUint::from_str( + "46316835694926478169428394003475163141307993866256225615783033603165251855960", + ) + .unwrap(); + + // random point on edwards25519 + let x2 = BigUint::from_u32(2).unwrap(); + let y2 = BigUint::from_str( + "11879831548380997166425477238087913000047176376829905612296558668626594440753", + ) + .unwrap(); + + // This is the sum of (x1, y1) and (x2, y2). + let x3 = BigUint::from_str( + "44969869612046584870714054830543834361257841801051546235130567688769346152934", + ) + .unwrap(); + let y3 = BigUint::from_str( + "50796027728050908782231253190819121962159170739537197094456293084373503699602", + ) + .unwrap(); + + // This is 2 * (x1, y1) + let x4 = BigUint::from_str( + "39226743113244985161159605482495583316761443760287217110659799046557361995496", + ) + .unwrap(); + let y4 = BigUint::from_str( + "12570354238812836652656274015246690354874018829607973815551555426027032771563", + ) + .unwrap(); + + vec![(x1, y1), (x2, y2), (x3, y3), (x4, y4)] + }; + + pub static ref Edwards25519_Prime: BigUint = BigUint::from_str( + "57896044618658097711785492504343953926634992332820282019728792003956564819949", + ) + .unwrap(); + + pub static ref Edwards25519_A: BigUint = BigUint::from_str( + "57896044618658097711785492504343953926634992332820282019728792003956564819948", + ) + .unwrap(); + + pub static ref Edwards25519_D: BigUint = BigUint::from_str( + "37095705934669439343138083508754565189542113879843219016388785533085940283555", + ) + .unwrap(); + + pub static ref Edwards25519_A_LIMBS: [BabyBear; NUM_LIMBS] = + big_uint_to_limbs(&Edwards25519_A, LIMB_BITS) + .into_iter() + .map(BabyBear::from_canonical_usize) + .collect::>() + .try_into() + .unwrap(); + pub static ref Edwards25519_D_LIMBS: [BabyBear; NUM_LIMBS] = + big_uint_to_limbs(&Edwards25519_D, LIMB_BITS) + .into_iter() + .map(BabyBear::from_canonical_usize) + .collect::>() + .try_into() + .unwrap(); +} + +fn prime_limbs(expr: &FieldExpr) -> Vec { + expr.prime_limbs + .iter() + .map(|n| BabyBear::from_canonical_usize(*n)) + .collect::>() +} + +#[test] +fn test_add() { + let mut tester: VmChipTestBuilder = VmChipTestBuilder::default(); + let config = ExprBuilderConfig { + modulus: Edwards25519_Prime.clone(), + num_limbs: NUM_LIMBS, + limb_bits: LIMB_BITS, + }; + let bitwise_bus = BitwiseOperationLookupBus::new(BITWISE_OP_LOOKUP_BUS); + let bitwise_chip = SharedBitwiseOperationLookupChip::::new(bitwise_bus); + let adapter = Rv32VecHeapAdapterChip::::new( + tester.execution_bus(), + tester.program_bus(), + tester.memory_bridge(), + tester.address_bits(), + bitwise_chip.clone(), + ); + let mut chip = TeEcAddChip::new( + adapter, + config, + Rv32EdwardsOpcode::CLASS_OFFSET, + Edwards25519_A.clone(), + Edwards25519_D.clone(), + tester.range_checker(), + tester.offline_memory_mutex_arc(), + ); + //assert_eq!(chip.0.core.expr().builder.num_variables, 12); + assert_eq!(chip.0.core.air.expr.builder.num_variables, 12); + + let (p1_x, p1_y) = SampleEcPoints[0].clone(); + let (p2_x, p2_y) = SampleEcPoints[1].clone(); + + let p1_x_limbs = + biguint_to_limbs::(p1_x.clone(), LIMB_BITS).map(BabyBear::from_canonical_u32); + let p1_y_limbs = + biguint_to_limbs::(p1_y.clone(), LIMB_BITS).map(BabyBear::from_canonical_u32); + let p2_x_limbs = + biguint_to_limbs::(p2_x.clone(), LIMB_BITS).map(BabyBear::from_canonical_u32); + let p2_y_limbs = + biguint_to_limbs::(p2_y.clone(), LIMB_BITS).map(BabyBear::from_canonical_u32); + + let r = chip + .0 + .core + //.expr() + .air + .expr + .execute(vec![p1_x, p1_y, p2_x, p2_y], vec![true]); + assert_eq!(r.len(), 12); + + let outputs = chip + .0 + .core + .air + .output_indices() + .iter() + .map(|i| &r[*i]) + .collect::>(); + assert_eq!(outputs[0], &SampleEcPoints[2].0); + assert_eq!(outputs[1], &SampleEcPoints[2].1); + + //let prime_limbs: [BabyBear; NUM_LIMBS] = prime_limbs(chip.0.core.expr()).try_into().unwrap(); + let prime_limbs: [BabyBear; NUM_LIMBS] = prime_limbs(&chip.0.core.air.expr).try_into().unwrap(); + let mut one_limbs = [BabyBear::ONE; NUM_LIMBS]; + one_limbs[0] = BabyBear::ONE; + let setup_instruction = rv32_write_heap_default( + &mut tester, + vec![prime_limbs, *Edwards25519_A_LIMBS], + vec![*Edwards25519_D_LIMBS], + chip.0.core.air.offset + Rv32EdwardsOpcode::SETUP_EC_ADD as usize, + ); + tester.execute(&mut chip, &setup_instruction); + + let instruction = rv32_write_heap_default( + &mut tester, + vec![p1_x_limbs, p1_y_limbs], + vec![p2_x_limbs, p2_y_limbs], + chip.0.core.air.offset + Rv32EdwardsOpcode::EC_ADD as usize, + ); + + tester.execute(&mut chip, &instruction); + + let tester = tester.build().load(chip).load(bitwise_chip).finalize(); + + tester.simple_test().expect("Verification failed"); +} diff --git a/extensions/ecc/circuit/src/lib.rs b/extensions/ecc/circuit/src/lib.rs index c1ec864636..378d4ec800 100644 --- a/extensions/ecc/circuit/src/lib.rs +++ b/extensions/ecc/circuit/src/lib.rs @@ -4,5 +4,8 @@ pub use weierstrass_chip::*; mod weierstrass_extension; pub use weierstrass_extension::*; +mod edwards_chip; +pub use edwards_chip::*; + mod config; pub use config::*; diff --git a/extensions/ecc/circuit/src/weierstrass_extension.rs b/extensions/ecc/circuit/src/weierstrass_extension.rs index afe2def687..1081f21e98 100644 --- a/extensions/ecc/circuit/src/weierstrass_extension.rs +++ b/extensions/ecc/circuit/src/weierstrass_extension.rs @@ -13,7 +13,7 @@ use openvm_circuit_primitives::bitwise_op_lookup::{ BitwiseOperationLookupBus, SharedBitwiseOperationLookupChip, }; use openvm_circuit_primitives_derive::{Chip, ChipUsageGetter}; -use openvm_ecc_transpiler::{EccPhantom, Rv32WeierstrassOpcode}; +use openvm_ecc_transpiler::{EccPhantom, Rv32EdwardsOpcode, Rv32WeierstrassOpcode}; use openvm_instructions::{LocalOpcode, PhantomDiscriminant, VmOpcode}; use openvm_mod_circuit_builder::ExprBuilderConfig; use openvm_rv32_adapters::Rv32VecHeapAdapterChip; @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; use strum::EnumCount; -use super::{EcAddNeChip, EcDoubleChip}; +use super::{EcAddNeChip, EcDoubleChip, TeEcAddChip}; #[serde_as] #[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] @@ -35,6 +35,19 @@ pub struct CurveConfig { /// The scalar field modulus of the curve. #[serde_as(as = "DisplayFromStr")] pub scalar: BigUint, + // curve-specific coefficients + pub coeffs: CurveCoeffs, +} + +#[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] +pub enum CurveCoeffs { + SwCurve(SwCurveConfig), + TeCurve(TeCurveConfig), +} + +#[serde_as] +#[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] +pub struct SwCurveConfig { /// The coefficient a of y^2 = x^3 + ax + b. #[serde_as(as = "DisplayFromStr")] pub a: BigUint, @@ -43,20 +56,35 @@ pub struct CurveConfig { pub b: BigUint, } +#[serde_as] +#[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] +pub struct TeCurveConfig { + /// The coefficient a of ax^2 + y^2 = 1 + dx^2y^2 + #[serde_as(as = "DisplayFromStr")] + pub a: BigUint, + /// The coefficient d of ax^2 + y^2 = 1 + dx^2y^2 + #[serde_as(as = "DisplayFromStr")] + pub d: BigUint, +} + pub static SECP256K1_CONFIG: Lazy = Lazy::new(|| CurveConfig { struct_name: SECP256K1_ECC_STRUCT_NAME.to_string(), modulus: SECP256K1_MODULUS.clone(), scalar: SECP256K1_ORDER.clone(), - a: BigUint::zero(), - b: BigUint::from_u8(7u8).unwrap(), + coeffs: CurveCoeffs::SwCurve(SwCurveConfig { + a: BigUint::zero(), + b: BigUint::from_u8(7u8).unwrap(), + }), }); pub static P256_CONFIG: Lazy = Lazy::new(|| CurveConfig { struct_name: P256_ECC_STRUCT_NAME.to_string(), modulus: P256_MODULUS.clone(), scalar: P256_ORDER.clone(), - a: BigUint::from_bytes_le(&P256_A), - b: BigUint::from_bytes_le(&P256_B), + coeffs: CurveCoeffs::SwCurve(SwCurveConfig { + a: BigUint::from_bytes_le(&P256_A), + b: BigUint::from_bytes_le(&P256_B), + }), }); #[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] @@ -80,11 +108,15 @@ impl WeierstrassExtension { #[derive(Chip, ChipUsageGetter, InstructionExecutor, AnyEnum)] pub enum WeierstrassExtensionExecutor { // 32 limbs prime - EcAddNeRv32_32(EcAddNeChip), - EcDoubleRv32_32(EcDoubleChip), + SwEcAddNeRv32_32(EcAddNeChip), + SwEcDoubleRv32_32(EcDoubleChip), // 48 limbs prime - EcAddNeRv32_48(EcAddNeChip), - EcDoubleRv32_48(EcDoubleChip), + SwEcAddNeRv32_48(EcAddNeChip), + SwEcDoubleRv32_48(EcDoubleChip), + // 32 limbs prime + TeEcAddRv32_32(TeEcAddChip), + // 48 limbs prime + TeEcAddRv32_48(TeEcAddChip), } #[derive(ChipUsageGetter, Chip, AnyEnum, From)] @@ -121,14 +153,21 @@ impl VmExtension for WeierstrassExtension { let offline_memory = builder.system_base().offline_memory(); let range_checker = builder.system_base().range_checker_chip.clone(); let pointer_bits = builder.system_config().memory_config.pointer_max_bits; - let ec_add_ne_opcodes = (Rv32WeierstrassOpcode::EC_ADD_NE as usize) + + let sw_add_ne_opcodes = (Rv32WeierstrassOpcode::EC_ADD_NE as usize) ..=(Rv32WeierstrassOpcode::SETUP_EC_ADD_NE as usize); - let ec_double_opcodes = (Rv32WeierstrassOpcode::EC_DOUBLE as usize) + let sw_double_opcodes = (Rv32WeierstrassOpcode::EC_DOUBLE as usize) ..=(Rv32WeierstrassOpcode::SETUP_EC_DOUBLE as usize); + let te_add_opcodes = + (Rv32EdwardsOpcode::EC_ADD as usize)..=(Rv32EdwardsOpcode::SETUP_EC_ADD as usize); + for (i, curve) in self.supported_curves.iter().enumerate() { - let start_offset = + let sw_start_offset = Rv32WeierstrassOpcode::CLASS_OFFSET + i * Rv32WeierstrassOpcode::COUNT; + // right now this is the same as sw_start_offset + let te_start_offset = Rv32EdwardsOpcode::CLASS_OFFSET + i * Rv32EdwardsOpcode::COUNT; + let bytes = curve.modulus.bits().div_ceil(8); let config32 = ExprBuilderConfig { modulus: curve.modulus.clone(), @@ -141,85 +180,141 @@ impl VmExtension for WeierstrassExtension { limb_bits: 8, }; if bytes <= 32 { - let add_ne_chip = EcAddNeChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - config32.clone(), - start_offset, - range_checker.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - WeierstrassExtensionExecutor::EcAddNeRv32_32(add_ne_chip), - ec_add_ne_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + start_offset)), - )?; - let double_chip = EcDoubleChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - range_checker.clone(), - config32.clone(), - start_offset, - curve.a.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - WeierstrassExtensionExecutor::EcDoubleRv32_32(double_chip), - ec_double_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + start_offset)), - )?; + match curve.coeffs.clone() { + CurveCoeffs::SwCurve(SwCurveConfig { a, b: _ }) => { + let sw_add_ne_chip = EcAddNeChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + config32.clone(), + sw_start_offset, + range_checker.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + WeierstrassExtensionExecutor::SwEcAddNeRv32_32(sw_add_ne_chip), + sw_add_ne_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), + )?; + let sw_double_chip = EcDoubleChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + range_checker.clone(), + config32.clone(), + sw_start_offset, + a.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + WeierstrassExtensionExecutor::SwEcDoubleRv32_32(sw_double_chip), + sw_double_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + sw_class_offset)), + )?; + } + + CurveCoeffs::TeCurve(TeCurveConfig { a, d }) => { + let te_add_chip = TeEcAddChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + config32.clone(), + te_start_offset, + a.clone(), + d.clone(), + range_checker.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + WeierstrassExtensionExecutor::TeEcAddRv32_32(te_add_chip), + te_add_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + te_start_offset)), + )?; + } + } } else if bytes <= 48 { - let add_ne_chip = EcAddNeChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - config48.clone(), - start_offset, - range_checker.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - WeierstrassExtensionExecutor::EcAddNeRv32_48(add_ne_chip), - ec_add_ne_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + start_offset)), - )?; - let double_chip = EcDoubleChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - range_checker.clone(), - config48.clone(), - start_offset, - curve.a.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - WeierstrassExtensionExecutor::EcDoubleRv32_48(double_chip), - ec_double_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + start_offset)), - )?; + match curve.coeffs.clone() { + CurveCoeffs::SwCurve(SwCurveConfig { a, b: _ }) => { + let sw_add_ne_chip = EcAddNeChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + config48.clone(), + sw_start_offset, + range_checker.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + WeierstrassExtensionExecutor::SwEcAddNeRv32_48(sw_add_ne_chip), + sw_add_ne_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), + )?; + let sw_double_chip = EcDoubleChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + range_checker.clone(), + config48.clone(), + sw_start_offset, + a.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + WeierstrassExtensionExecutor::SwEcDoubleRv32_48(sw_double_chip), + sw_double_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + sw_class_offset)), + )?; + } + + CurveCoeffs::TeCurve(TeCurveConfig { a, d }) => { + let te_add_chip = TeEcAddChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + config48.clone(), + te_start_offset, + a.clone(), + d.clone(), + range_checker.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + WeierstrassExtensionExecutor::TeEcAddRv32_48(te_add_chip), + te_add_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + te_start_offset)), + )?; + } + } } else { panic!("Modulus too large"); } @@ -257,7 +352,7 @@ pub(crate) mod phantom { use openvm_rv32im_circuit::adapters::unsafe_read_rv32_register; use openvm_stark_backend::p3_field::PrimeField32; - use super::CurveConfig; + use super::{CurveCoeffs, CurveConfig, SwCurveConfig, TeCurveConfig}; // Hint for a decompression // if possible is true, then `sqrt` is the decompressed y-coordinate @@ -338,13 +433,24 @@ pub(crate) mod phantom { } impl DecompressHintSubEx { - /// Given `x` in the coordinate field of the curve, and the recovery id, + fn decompress_point(&self, x: BigUint, is_y_odd: bool, curve_idx: usize) -> BigUint { + match self.supported_curves[curve_idx].coeffs.clone() { + CurveCoeffs::SwCurve(SwCurveConfig { a, b }) => { + self.decompress_sw_point(x, is_y_odd, curve_idx) + } + CurveCoeffs::TeCurve(TeCurveConfig { a: _, d: _ }) => { + unimplemented!("should not call decompress_point for Twisted Edwards curves"); + } + } + } + + /// Given `x` in the coordinate field of a Weierstrass curve, and the recovery id, /// return the unique `y` such that `(x, y)` is a point on the curve and /// `y` has the same parity as the recovery id. /// /// If no such `y` exists, return the square root of `(x^3 + ax + b) * non_qr` /// where `non_qr` is a quadratic nonresidue of the field. - fn decompress_point( + fn decompress_sw_point( &self, x: BigUint, is_y_odd: bool, diff --git a/extensions/ecc/guest/Cargo.toml b/extensions/ecc/guest/Cargo.toml index e5251eb366..5870b10c92 100644 --- a/extensions/ecc/guest/Cargo.toml +++ b/extensions/ecc/guest/Cargo.toml @@ -17,6 +17,7 @@ openvm-custom-insn = { workspace = true } openvm-rv32im-guest = { workspace = true } openvm-algebra-guest = { workspace = true } openvm-ecc-sw-macros = { workspace = true } +openvm-ecc-te-macros = { workspace = true } once_cell = { workspace = true, features = ["race", "alloc"] } # Used for `halo2curves` feature diff --git a/extensions/ecc/guest/src/edwards.rs b/extensions/ecc/guest/src/edwards.rs new file mode 100644 index 0000000000..dc51e2c115 --- /dev/null +++ b/extensions/ecc/guest/src/edwards.rs @@ -0,0 +1,282 @@ +use core::ops::Mul; + +use openvm_algebra_guest::{Field, IntMod}; + +pub trait TwistedEdwardsPoint: Sized { + /// The `a` coefficient in the twisted Edwards curve equation `ax^2 + y^2 = 1 + d x^2 y^2`. + const CURVE_A: Self::Coordinate; + /// The `d` coefficient in the twisted Edwards curve equation `ax^2 + y^2 = 1 + d x^2 y^2`. + const CURVE_D: Self::Coordinate; + const IDENTITY: Self; + + type Coordinate: IntMod + Field; + const ZERO: Self::Coordinate = ::ZERO; + const ONE: Self::Coordinate = ::ONE; + + /// The concatenated `x, y` coordinates of the affine point, where + /// coordinates are in little endian. + /// + /// **Warning**: The memory layout of `Self` is expected to pack + /// `x` and `y` contigously with no unallocated space in between. + fn as_le_bytes(&self) -> &[u8]; + + /// Raw constructor without asserting point is on the curve. + fn from_xy_unchecked(x: Self::Coordinate, y: Self::Coordinate) -> Self; + fn into_coords(self) -> (Self::Coordinate, Self::Coordinate); + fn x(&self) -> &Self::Coordinate; + fn y(&self) -> &Self::Coordinate; + fn x_mut(&mut self) -> &mut Self::Coordinate; + fn y_mut(&mut self) -> &mut Self::Coordinate; + + fn add_impl(&self, p2: &Self) -> Self; + + fn from_xy(x: Self::Coordinate, y: Self::Coordinate) -> Option + where + for<'a> &'a Self::Coordinate: Mul<&'a Self::Coordinate, Output = Self::Coordinate>, + { + if x == Self::ZERO && y == Self::ONE { + Some(Self::IDENTITY) + } else { + Self::from_xy_nonidentity(x, y) + } + } + + fn from_xy_nonidentity(x: Self::Coordinate, y: Self::Coordinate) -> Option + where + for<'a> &'a Self::Coordinate: Mul<&'a Self::Coordinate, Output = Self::Coordinate>, + { + let lhs = Self::CURVE_A * &x * &x + &y * &y; + let rhs = Self::CURVE_D * &x * &x * &y * &y + &Self::ONE; + if lhs != rhs { + return None; + } + Some(Self::from_xy_unchecked(x, y)) + } +} + +/// Macro to generate a newtype wrapper for [AffinePoint](crate::AffinePoint) +/// that implements elliptic curve operations by using the underlying field operations according to the +/// [formulas](https://en.wikipedia.org/wiki/Twisted_Edwards_curve) for twisted Edwards curves. +/// +/// The following imports are required: +/// ```rust +/// use core::ops::AddAssign; +/// +/// use openvm_algebra_guest::{DivUnsafe, Field}; +/// use openvm_ecc_guest::{AffinePoint, Group, edwards::TwistedEdwardsPoint}; +/// ``` +#[macro_export] +macro_rules! impl_te_affine { + ($struct_name:ident, $field:ty, $a:expr, $d:expr) => { + /// A newtype wrapper for [AffinePoint] that implements elliptic curve operations + /// by using the underlying field operations according to the [formulas](https://en.wikipedia.org/wiki/Twisted_Edwards_curve) for twisted Edwards curves. + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)] + #[repr(transparent)] + pub struct $struct_name(AffinePoint<$field>); + + impl TwistedEdwardsPoint for $struct_name { + const CURVE_A: $field = $a; + const CURVE_D: $field = $d; + const IDENTITY: Self = Self(AffinePoint::new(<$field>::ZERO, <$field>::ONE)); + + type Coordinate = $field; + + /// SAFETY: assumes that [$field] has internal representation in little-endian. + fn as_le_bytes(&self) -> &[u8] { + unsafe { + &*core::ptr::slice_from_raw_parts( + self as *const Self as *const u8, + core::mem::size_of::(), + ) + } + } + fn from_xy_unchecked(x: Self::Coordinate, y: Self::Coordinate) -> Self { + Self(AffinePoint::new(x, y)) + } + fn into_coords(self) -> (Self::Coordinate, Self::Coordinate) { + (self.0.x, self.0.y) + } + fn x(&self) -> &Self::Coordinate { + &self.0.x + } + fn y(&self) -> &Self::Coordinate { + &self.0.y + } + fn x_mut(&mut self) -> &mut Self::Coordinate { + &mut self.0.x + } + fn y_mut(&mut self) -> &mut Self::Coordinate { + &mut self.0.y + } + + fn add_impl(&self, p2: &Self) -> Self { + use ::openvm_algebra_guest::DivUnsafe; + // For twisted Edwards curves: + // x3 = (x1*y2 + y1*x2)/(1 + d*x1*x2*y1*y2) + // y3 = (y1*y2 - a*x1*x2)/(1 - d*x1*x2*y1*y2) + let x1y2 = self.x() * p2.y(); + let y1x2 = self.y() * p2.x(); + let x1x2 = self.x() * p2.x(); + let y1y2 = self.y() * p2.y(); + let dx1x2y1y2 = Self::CURVE_D * x1x2 * y1y2; + + let x3 = (x1y2 + y1x2).div_unsafe(&(Self::Coordinate::ONE + dx1x2y1y2)); + let y3 = (y1y2 - Self::CURVE_A * x1x2).div_unsafe(&(Self::Coordinate::ONE - dx1x2y1y2)); + + Self(AffinePoint::new(x3, y3)) + } + + impl core::ops::Neg for $struct_name { + type Output = Self; + + fn neg(mut self) -> Self::Output { + self.0.x.neg_assign(); + self + } + } + + impl core::ops::Neg for &$struct_name { + type Output = $struct_name; + + fn neg(self) -> Self::Output { + self.clone().neg() + } + } + + impl From<$struct_name> for AffinePoint<$field> { + fn from(value: $struct_name) -> Self { + value.0 + } + } + + impl From> for $struct_name { + fn from(value: AffinePoint<$field>) -> Self { + Self(value) + } + } + } + } +} + +/// Implements `Group` on `$struct_name` assuming that `$struct_name` implements `TwistedEdwardsPoint`. +/// Assumes that `Neg` is implemented for `&$struct_name`. +#[macro_export] +macro_rules! impl_te_group_ops { + ($struct_name:ident, $field:ty) => { + impl Group for $struct_name { + type SelfRef<'a> = &'a Self; + + const IDENTITY: Self = ::IDENTITY; + + fn double(&self) -> Self { + if self.is_identity() { + self.clone() + } else { + self.add_impl(self) + } + } + + fn double_assign(&mut self) { + if !self.is_identity() { + *self = self.add_impl(self) + } + } + } + + impl core::ops::Add<&$struct_name> for $struct_name { + type Output = Self; + + fn add(mut self, p2: &$struct_name) -> Self::Output { + use core::ops::AddAssign; + self.add_assign(p2); + self + } + } + + impl core::ops::Add for $struct_name { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + self.add(&rhs) + } + } + + impl core::ops::Add<&$struct_name> for &$struct_name { + type Output = $struct_name; + + fn add(self, p2: &$struct_name) -> Self::Output { + if self.is_identity() { + p2.clone() + } else if p2.is_identity() { + self.clone() + } else if self.x() + p2.x() == <$field as openvm_algebra_guest::Field>::ZERO + && self.y() == p2.y() + { + <$struct_name as TwistedEdwardsPoint>::IDENTITY + } else { + self.add_impl(p2) + } + } + } + + impl core::ops::AddAssign<&$struct_name> for $struct_name { + fn add_assign(&mut self, p2: &$struct_name) { + if self.is_identity() { + *self = p2.clone(); + } else if p2.is_identity() { + // do nothing + } else if self.x() + p2.x() == <$field as openvm_algebra_guest::Field>::ZERO + && self.y() == p2.y() + { + *self = <$struct_name as TwistedEdwardsPoint>::IDENTITY; + } else { + *self = self.add_impl(p2); + } + } + } + + impl core::ops::AddAssign for $struct_name { + fn add_assign(&mut self, rhs: Self) { + self.add_assign(&rhs); + } + } + + impl core::ops::Sub<&$struct_name> for $struct_name { + type Output = Self; + + fn sub(self, rhs: &$struct_name) -> Self::Output { + core::ops::Sub::sub(&self, rhs) + } + } + + impl core::ops::Sub for $struct_name { + type Output = $struct_name; + + fn sub(self, rhs: Self) -> Self::Output { + self.sub(&rhs) + } + } + + impl core::ops::Sub<&$struct_name> for &$struct_name { + type Output = $struct_name; + + fn sub(self, p2: &$struct_name) -> Self::Output { + use core::ops::Add; + self.add(&-p2) + } + } + + impl core::ops::SubAssign<&$struct_name> for $struct_name { + fn sub_assign(&mut self, p2: &$struct_name) { + use core::ops::AddAssign; + self.add_assign(-p2); + } + } + + impl core::ops::SubAssign for $struct_name { + fn sub_assign(&mut self, rhs: Self) { + self.sub_assign(&rhs); + } + } + }; +} diff --git a/extensions/ecc/guest/src/lib.rs b/extensions/ecc/guest/src/lib.rs index 1d7f15a0d9..7f70d63ab0 100644 --- a/extensions/ecc/guest/src/lib.rs +++ b/extensions/ecc/guest/src/lib.rs @@ -6,6 +6,7 @@ extern crate alloc; pub use once_cell; pub use openvm_algebra_guest as algebra; pub use openvm_ecc_sw_macros as sw_macros; +pub use openvm_ecc_te_macros as te_macros; use strum_macros::FromRepr; mod affine_point; @@ -17,11 +18,13 @@ pub use msm::*; /// Optimized ECDSA implementation with the same functional interface as the `ecdsa` crate pub mod ecdsa; +/// Edwards curve traits +pub mod edwards; /// Weierstrass curve traits pub mod weierstrass; /// This is custom-1 defined in RISC-V spec document -pub const OPCODE: u8 = 0x2b; +pub const SW_OPCODE: u8 = 0x2b; pub const SW_FUNCT3: u8 = 0b001; /// Short Weierstrass curves are configurable. @@ -39,3 +42,18 @@ pub enum SwBaseFunct7 { impl SwBaseFunct7 { pub const SHORT_WEIERSTRASS_MAX_KINDS: u8 = 8; } + +/// This is custom-1 defined in RISC-V spec document +pub const TE_OPCODE: u8 = 0x2b; +pub const TE_FUNCT3: u8 = 0b100; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)] +#[repr(u8)] +pub enum TeBaseFunct7 { + TeAdd = 0, + TeSetup, +} + +impl TeBaseFunct7 { + pub const TWISTED_EDWARDS_MAX_KINDS: u8 = 8; +} diff --git a/extensions/ecc/sw-macros/src/lib.rs b/extensions/ecc/sw-macros/src/lib.rs index a7be2e23b1..08f034ee8d 100644 --- a/extensions/ecc/sw-macros/src/lib.rs +++ b/extensions/ecc/sw-macros/src/lib.rs @@ -435,7 +435,7 @@ pub fn sw_init(input: TokenStream) -> TokenStream { #[no_mangle] extern "C" fn #add_ne_extern_func(rd: usize, rs1: usize, rs2: usize) { openvm::platform::custom_insn_r!( - opcode = OPCODE, + opcode = SW_OPCODE, funct3 = SW_FUNCT3 as usize, funct7 = SwBaseFunct7::SwAddNe as usize + #ec_idx * (SwBaseFunct7::SHORT_WEIERSTRASS_MAX_KINDS as usize), @@ -448,7 +448,7 @@ pub fn sw_init(input: TokenStream) -> TokenStream { #[no_mangle] extern "C" fn #double_extern_func(rd: usize, rs1: usize) { openvm::platform::custom_insn_r!( - opcode = OPCODE, + opcode = SW_OPCODE, funct3 = SW_FUNCT3 as usize, funct7 = SwBaseFunct7::SwDouble as usize + #ec_idx * (SwBaseFunct7::SHORT_WEIERSTRASS_MAX_KINDS as usize), @@ -475,7 +475,7 @@ pub fn sw_init(input: TokenStream) -> TokenStream { let p2 = [one.as_ref(), one.as_ref()].concat(); let mut uninit: core::mem::MaybeUninit<[#item; 2]> = core::mem::MaybeUninit::uninit(); openvm::platform::custom_insn_r!( - opcode = ::openvm_ecc_guest::OPCODE, + opcode = ::openvm_ecc_guest::SW_OPCODE, funct3 = ::openvm_ecc_guest::SW_FUNCT3 as usize, funct7 = ::openvm_ecc_guest::SwBaseFunct7::SwSetup as usize + #ec_idx @@ -485,7 +485,7 @@ pub fn sw_init(input: TokenStream) -> TokenStream { rs2 = In p2.as_ptr() ); openvm::platform::custom_insn_r!( - opcode = ::openvm_ecc_guest::OPCODE, + opcode = ::openvm_ecc_guest::SW_OPCODE, funct3 = ::openvm_ecc_guest::SW_FUNCT3 as usize, funct7 = ::openvm_ecc_guest::SwBaseFunct7::SwSetup as usize + #ec_idx @@ -503,7 +503,7 @@ pub fn sw_init(input: TokenStream) -> TokenStream { #[allow(non_snake_case)] #[cfg(target_os = "zkvm")] mod openvm_intrinsics_ffi_2 { - use ::openvm_ecc_guest::{OPCODE, SW_FUNCT3, SwBaseFunct7}; + use ::openvm_ecc_guest::{SW_OPCODE, SW_FUNCT3, SwBaseFunct7}; #(#externs)* } diff --git a/extensions/ecc/te-setup/Cargo.toml b/extensions/ecc/te-setup/Cargo.toml new file mode 100644 index 0000000000..ff8afb15e0 --- /dev/null +++ b/extensions/ecc/te-setup/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "openvm-ecc-te-setup" +version.workspace = true +authors.workspace = true +edition.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +syn = { version = "2.0", features = ["full"] } +quote = "1.0" +openvm-macros-common = { workspace = true, default-features = false } +num-bigint.workspace = true +proc-macro2 = "1.0.38" + +[lib] +proc-macro = true diff --git a/extensions/ecc/te-setup/src/lib.rs b/extensions/ecc/te-setup/src/lib.rs new file mode 100644 index 0000000000..f166abe553 --- /dev/null +++ b/extensions/ecc/te-setup/src/lib.rs @@ -0,0 +1,314 @@ +#![feature(proc_macro_diagnostic)] + +extern crate proc_macro; + +use openvm_macros_common::MacroArgs; +use proc_macro::TokenStream; +use quote::format_ident; +use syn::{ + parse::{Parse, ParseStream}, + parse_macro_input, Expr, ExprPath, Path, Token, +}; + +/// This macro generates the code to setup a Twisted Edwards elliptic curve for a given modular type. Also it places the curve parameters into a special static variable to be later extracted from the ELF and used by the VM. +/// Usage: +/// ``` +/// te_declare! { +/// [TODO] +/// } +/// ``` +/// +/// For this macro to work, you must import the `elliptic_curve` crate and the `openvm_ecc_guest` crate.. +#[proc_macro] +pub fn te_declare(input: TokenStream) -> TokenStream { + let MacroArgs { items } = parse_macro_input!(input as MacroArgs); + + let mut output = Vec::new(); + + let span = proc_macro::Span::call_site(); + + for item in items.into_iter() { + let struct_name = item.name.to_string(); + let struct_name = syn::Ident::new(&struct_name, span.into()); + let struct_path: syn::Path = syn::parse_quote!(#struct_name); + let mut intmod_type: Option = None; + let mut const_a: Option = None; + let mut const_d: Option = None; + for param in item.params { + match param.name.to_string().as_str() { + "mod_type" => { + if let syn::Expr::Path(ExprPath { path, .. }) = param.value { + intmod_type = Some(path) + } else { + return syn::Error::new_spanned(param.value, "Expected a type") + .to_compile_error() + .into(); + } + } + "a" => { + const_a = Some(param.value); + } + "d" => { + const_d = Some(param.value); + } + _ => { + panic!("Unknown parameter {}", param.name); + } + } + } + + let intmod_type = intmod_type.expect("mod_type parameter is required"); + let const_a = const_a.expect("constant a coefficient is required"); + let const_d = const_d.expect("constant d coefficient is required"); + + macro_rules! create_extern_func { + ($name:ident) => { + let $name = syn::Ident::new( + &format!( + "{}_{}", + stringify!($name), + struct_path + .segments + .iter() + .map(|x| x.ident.to_string()) + .collect::>() + .join("_") + ), + span.into(), + ); + }; + } + create_extern_func!(te_add_extern_func); + + let group_ops_mod_name = format_ident!("{}_ops", struct_name.to_string().to_lowercase()); + + let result = TokenStream::from(quote::quote_spanned! { span.into() => + extern "C" { + fn #te_add_extern_func(rd: usize, rs1: usize, rs2: usize); + } + + #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] + #[repr(C)] + pub struct #struct_name { + x: #intmod_type, + y: #intmod_type, + } + + impl #struct_name { + const fn identity() -> Self { + Self { + x: <#intmod_type as openvm_algebra_guest::IntMod>::ZERO, + y: <#intmod_type as openvm_algebra_guest::IntMod>::ONE, + } + } + // Below are wrapper functions for the intrinsic instructions. + // Should not be called directly. + #[inline(always)] + fn add_chip(p1: &#struct_name, p2: &#struct_name) -> #struct_name { + #[cfg(not(target_os = "zkvm"))] + { + let x1y2 = p1.x() * p2.y(); + let y1x2 = p1.y() * p2.x(); + let x1x2 = p1.x() * p2.x(); + let y1y2 = p1.y() * p2.y(); + let dx1x2y1y2 = Self::CURVE_D * x1x2 * y1y2; + + let x3 = (x1y2 + y1x2).div_unsafe(&(Self::Coordinate::ONE + dx1x2y1y2)); + let y3 = (y1y2 - Self::CURVE_A * x1x2).div_unsafe(&(Self::Coordinate::ONE - dx1x2y1y2)); + + #struct_name { x: x3, y: y3 } + } + #[cfg(target_os = "zkvm")] + { + let mut uninit: core::mem::MaybeUninit<#struct_name> = core::mem::MaybeUninit::uninit(); + unsafe { + #te_add_extern_func( + uninit.as_mut_ptr() as usize, + p1 as *const #struct_name as usize, + p2 as *const #struct_name as usize + ) + }; + unsafe { uninit.assume_init() } + } + } + } + + impl ::openvm_ecc_guest::edwards::TwistedEdwardsPoint for #struct_name { + const CURVE_A: Self::Coordinate = #const_a; + const CURVE_D: Self::Coordinate = #const_d; + + const IDENTITY: Self = Self::identity(); + type Coordinate = #intmod_type; + + /// SAFETY: assumes that #intmod_type has a memory representation + /// such that with repr(C), two coordinates are packed contiguously. + fn as_le_bytes(&self) -> &[u8] { + unsafe { &*core::ptr::slice_from_raw_parts(self as *const Self as *const u8, <#intmod_type as openvm_algebra_guest::IntMod>::NUM_LIMBS * 2) } + } + + fn from_xy_unchecked(x: Self::Coordinate, y: Self::Coordinate) -> Self { + Self { x, y } + } + + fn x(&self) -> &Self::Coordinate { + &self.x + } + + fn y(&self) -> &Self::Coordinate { + &self.y + } + + fn x_mut(&mut self) -> &mut Self::Coordinate { + &mut self.x + } + + fn y_mut(&mut self) -> &mut Self::Coordinate { + &mut self.y + } + + fn into_coords(self) -> (Self::Coordinate, Self::Coordinate) { + (self.x, self.y) + } + + fn add_impl(&self, p2: &Self) -> Self { + Self::add_chip(self, p2) + } + } + + impl core::ops::Neg for #struct_name { + type Output = Self; + + fn neg(self) -> Self::Output { + #struct_name { + x: core::ops::Neg::neg(&self.x), + y: self.y, + } + } + } + + impl core::ops::Neg for &#struct_name { + type Output = #struct_name; + + fn neg(self) -> #struct_name { + #struct_name { + x: core::ops::Neg::neg(&self.x), + y: self.y.clone(), + } + } + } + + mod #group_ops_mod_name { + use ::openvm_ecc_guest::{edwards::TwistedEdwardsPoint, impl_te_group_ops}; + use super::*; + + impl_te_group_ops!(#struct_name, #intmod_type); + } + }); + output.push(result); + } + + TokenStream::from_iter(output) +} + +struct TeDefine { + items: Vec, +} + +impl Parse for TeDefine { + fn parse(input: ParseStream) -> syn::Result { + let items = input.parse_terminated(::parse, Token![,])?; + Ok(Self { + items: items + .into_iter() + .map(|e| { + if let Expr::Path(p) = e { + p.path + } else { + panic!("expected path"); + } + }) + .collect(), + }) + } +} + +#[proc_macro] +pub fn te_init(input: TokenStream) -> TokenStream { + let TeDefine { items } = parse_macro_input!(input as TeDefine); + + let mut externs = Vec::new(); + let mut setups = Vec::new(); + let mut setup_all_curves = Vec::new(); + + let span = proc_macro::Span::call_site(); + + for (ec_idx, item) in items.into_iter().enumerate() { + let str_path = item + .segments + .iter() + .map(|x| x.ident.to_string()) + .collect::>() + .join("_"); + let add_extern_func = + syn::Ident::new(&format!("te_add_extern_func_{}", str_path), span.into()); + externs.push(quote::quote_spanned! { span.into() => + #[no_mangle] + extern "C" fn #add_extern_func(rd: usize, rs1: usize, rs2: usize) { + openvm::platform::custom_insn_r!( + opcode = TE_OPCODE, + funct3 = TE_FUNCT3 as usize, + funct7 = TeBaseFunct7::TeAdd as usize + #ec_idx + * (TeBaseFunct7::TWISTED_EDWARDS_MAX_KINDS as usize), + rd = In rd, + rs1 = In rs1, + rs2 = In rs2 + ); + } + }); + + let setup_function = syn::Ident::new(&format!("setup_te_{}", str_path), span.into()); + setups.push(quote::quote_spanned! { span.into() => + + #[allow(non_snake_case)] + pub fn #setup_function() { + #[cfg(target_os = "zkvm")] + { + let modulus_bytes = <<#item as openvm_ecc_guest::edwards::TwistedEdwardsPoint>::Coordinate as openvm_algebra_guest::IntMod>::MODULUS; + let mut zero = [0u8; <<#item as openvm_ecc_guest::edwards::TwistedEdwardsPoint>::Coordinate as openvm_algebra_guest::IntMod>::NUM_LIMBS]; + let curve_a_bytes = openvm_algebra_guest::IntMod::as_le_bytes(&<#item as openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_A); + let curve_d_bytes = openvm_algebra_guest::IntMod::as_le_bytes(&<#item as openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_D); + let p1 = [modulus_bytes.as_ref(), curve_a_bytes.as_ref()].concat(); + let p2 = [curve_d_bytes.as_ref(), zero.as_ref()].concat(); + let mut uninit: core::mem::MaybeUninit<[#item; 2]> = core::mem::MaybeUninit::uninit(); + openvm::platform::custom_insn_r!( + opcode = ::openvm_ecc_guest::TE_OPCODE, + funct3 = ::openvm_ecc_guest::TE_FUNCT3 as usize, + funct7 = ::openvm_ecc_guest::TeBaseFunct7::TeSetup as usize + + #ec_idx + * (::openvm_ecc_guest::TeBaseFunct7::TWISTED_EDWARDS_MAX_KINDS as usize), + rd = In uninit.as_mut_ptr(), + rs1 = In p1.as_ptr(), + rs2 = In p2.as_ptr(), + ); + } + } + }); + + setup_all_curves.push(quote::quote_spanned! { span.into() => + #setup_function(); + }); + } + + TokenStream::from(quote::quote_spanned! { span.into() => + #[cfg(target_os = "zkvm")] + mod openvm_intrinsics_ffi_2 { + use ::openvm_ecc_guest::{TE_OPCODE, TE_FUNCT3, TeBaseFunct7}; + + #(#externs)* + } + #(#setups)* + pub fn setup_all_curves() { + #(#setup_all_curves)* + } + }) +} diff --git a/extensions/ecc/tests/Cargo.toml b/extensions/ecc/tests/Cargo.toml index 14afb36453..bcdaf6f539 100644 --- a/extensions/ecc/tests/Cargo.toml +++ b/extensions/ecc/tests/Cargo.toml @@ -20,6 +20,7 @@ openvm-keccak256-transpiler.workspace = true openvm-toolchain-tests = { path = "../../../crates/toolchain/tests" } openvm-sdk.workspace = true eyre.workspace = true +num-bigint.workspace = true hex-literal.workspace = true num-bigint.workspace = true halo2curves-axiom = { workspace = true } diff --git a/extensions/ecc/tests/programs/examples/edwards_ec.rs b/extensions/ecc/tests/programs/examples/edwards_ec.rs new file mode 100644 index 0000000000..51768e9cc5 --- /dev/null +++ b/extensions/ecc/tests/programs/examples/edwards_ec.rs @@ -0,0 +1,126 @@ +#![cfg_attr(not(feature = "std"), no_main)] +#![cfg_attr(not(feature = "std"), no_std)] + +use core::str::FromStr; + +use num_bigint::BigUint; +use openvm_algebra_guest::{ + moduli_setup::{moduli_declare, moduli_init}, + Field, IntMod, +}; +use openvm_ecc_guest::{ + edwards::TwistedEdwardsPoint, + te_setup::{te_declare, te_init}, + Group, +}; + +moduli_declare! { + Edwards25519Coord { modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" }, +} + +moduli_init! { + "57896044618658097711785492504343953926634992332820282019728792003956564819949", +} + +impl Field for Edwards25519Coord { + const ZERO: Self = ::ZERO; + const ONE: Self = ::ONE; + + type SelfRef<'a> = &'a Self; + + fn double_assign(&mut self) { + IntMod::double_assign(self); + } + + fn square_assign(&mut self) { + IntMod::square_assign(self); + } +} + +// a = 57896044618658097711785492504343953926634992332820282019728792003956564819948 +// d = 37095705934669439343138083508754565189542113879843219016388785533085940283555 +// encoded in little endian, 32 limbs of 8 bits each +const CURVE_A: Edwards25519Coord = Edwards25519Coord::from_const_bytes([ + 236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, +]); +const CURVE_D: Edwards25519Coord = Edwards25519Coord::from_const_bytes([ + 163, 120, 89, 19, 202, 77, 235, 117, 171, 216, 65, 65, 77, 10, 112, 0, 152, 232, 121, 119, 121, + 64, 199, 140, 115, 254, 111, 43, 238, 108, 3, 82, +]); + +te_declare! { + Edwards25519Point { + mod_type = Edwards25519Coord, + a = CURVE_A, + d = CURVE_D + } +} + +te_init! { + Edwards25519Point, +} + +openvm::entry!(main); + +fn string_to_coord(s: &str) -> Edwards25519Coord { + Edwards25519Coord::from_le_bytes(&BigUint::from_str(s).unwrap().to_bytes_le()) +} + +pub fn main() { + setup_all_moduli(); + setup_all_curves(); + + // Base point of edwards25519 + let x1 = string_to_coord( + "15112221349535400772501151409588531511454012693041857206046113283949847762202", + ); + let y1 = string_to_coord( + "46316835694926478169428394003475163141307993866256225615783033603165251855960", + ); + + // random point on edwards25519 + let x2 = Edwards25519Coord::from_u32(2); + let y2 = string_to_coord( + "11879831548380997166425477238087913000047176376829905612296558668626594440753", + ); + + // This is the sum of (x1, y1) and (x2, y2). + let x3 = string_to_coord( + "44969869612046584870714054830543834361257841801051546235130567688769346152934", + ); + let y3 = string_to_coord( + "50796027728050908782231253190819121962159170739537197094456293084373503699602", + ); + + // This is 2 * (x1, y1) + let x4 = string_to_coord( + "39226743113244985161159605482495583316761443760287217110659799046557361995496", + ); + let y4 = string_to_coord( + "12570354238812836652656274015246690354874018829607973815551555426027032771563", + ); + + let mut p1 = Edwards25519Point::from_xy(x1.clone(), y1.clone()).unwrap(); + let mut p2 = Edwards25519Point::from_xy(x2, y2).unwrap(); + + // Generic add can handle equal or unequal points. + let p3 = &p1 + &p2; + if p3.x() != &x3 || p3.y() != &y3 { + panic!(); + } + let p4 = &p2 + &p2; + if p4.x() != &x4 || p4.y() != &y4 { + panic!(); + } + + // Add assign and double assign + p1 += &p2; + if p1.x() != &x3 || p1.y() != &y3 { + panic!(); + } + p2.double_assign(); + if p2.x() != &x4 || p2.y() != &y4 { + panic!(); + } +} diff --git a/extensions/ecc/tests/src/lib.rs b/extensions/ecc/tests/src/lib.rs index 523973f098..fea5dce974 100644 --- a/extensions/ecc/tests/src/lib.rs +++ b/extensions/ecc/tests/src/lib.rs @@ -12,7 +12,8 @@ mod tests { utils::{air_test, air_test_with_min_segments}, }; use openvm_ecc_circuit::{ - CurveConfig, Rv32WeierstrassConfig, WeierstrassExtension, P256_CONFIG, SECP256K1_CONFIG, + CurveConfig, CurveCoeffs, CurveConfig, Rv32WeierstrassConfig, TeCurveConfig, WeierstrassExtension, + P256_CONFIG, SECP256K1_CONFIG, }; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_keccak256_transpiler::Keccak256TranspilerExtension; @@ -196,6 +197,43 @@ mod tests { Ok(()) } + #[test] + fn test_edwards_ec() -> Result<()> { + let elf = build_example_program_at_path_with_features::<&str>( + get_programs_dir!(), + "edwards_ec", + [], + )?; + let openvm_exe = VmExe::from_elf( + elf, + Transpiler::::default() + .with_extension(Rv32ITranspilerExtension) + .with_extension(Rv32MTranspilerExtension) + .with_extension(Rv32IoTranspilerExtension) + .with_extension(EccTranspilerExtension) + .with_extension(ModularTranspilerExtension), + )?; + let config = + Rv32WeierstrassConfig::new(vec![CurveConfig { + modulus: BigUint::from_str( + "57896044618658097711785492504343953926634992332820282019728792003956564819949", + ).unwrap(), + scalar: BigUint::from_str( + "7237005577332262213973186563042994240857116359379907606001950938285454250989", + ).unwrap(), + coeffs: CurveCoeffs::TeCurve(TeCurveConfig { + a: BigUint::from_str( + "57896044618658097711785492504343953926634992332820282019728792003956564819948", + ).unwrap(), + d: BigUint::from_str( + "37095705934669439343138083508754565189542113879843219016388785533085940283555", + ).unwrap(), + }), + }]); + air_test(config, openvm_exe); + Ok(()) + } + #[test] #[should_panic] fn test_invalid_setup() { diff --git a/extensions/ecc/transpiler/src/lib.rs b/extensions/ecc/transpiler/src/lib.rs index 4dae6b2151..9b4a997008 100644 --- a/extensions/ecc/transpiler/src/lib.rs +++ b/extensions/ecc/transpiler/src/lib.rs @@ -1,4 +1,4 @@ -use openvm_ecc_guest::{SwBaseFunct7, OPCODE, SW_FUNCT3}; +use openvm_ecc_guest::{SwBaseFunct7, TeBaseFunct7, SW_FUNCT3, SW_OPCODE, TE_FUNCT3, TE_OPCODE}; use openvm_instructions::{ instruction::Instruction, riscv::RV32_REGISTER_NUM_LIMBS, LocalOpcode, PhantomDiscriminant, VmOpcode, @@ -22,6 +22,17 @@ pub enum Rv32WeierstrassOpcode { SETUP_EC_DOUBLE, } +#[derive( + Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EnumCount, EnumIter, FromRepr, LocalOpcode, +)] +#[opcode_offset = 0x600] // same as for weierstrass +#[allow(non_camel_case_types)] +#[repr(usize)] +pub enum Rv32EdwardsOpcode { + EC_ADD, + SETUP_EC_ADD, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, FromRepr)] #[repr(u16)] pub enum EccPhantom { @@ -34,6 +45,69 @@ pub struct EccTranspilerExtension; impl TranspilerExtension for EccTranspilerExtension { fn process_custom(&self, instruction_stream: &[u32]) -> Option> { + self.process_weierstrass_instruction(instruction_stream) + .or(self.process_edwards_instruction(instruction_stream)) + } +} + +impl EccTranspilerExtension { + fn process_edwards_instruction( + &self, + instruction_stream: &[u32], + ) -> Option> { + if instruction_stream.is_empty() { + return None; + } + let instruction_u32 = instruction_stream[0]; + let opcode = (instruction_u32 & 0x7f) as u8; + let funct3 = ((instruction_u32 >> 12) & 0b111) as u8; + + if opcode != TE_OPCODE { + return None; + } + if funct3 != TE_FUNCT3 { + return None; + } + + let instruction = { + // twisted edwards ec + assert!(Rv32EdwardsOpcode::COUNT <= TeBaseFunct7::TWISTED_EDWARDS_MAX_KINDS as usize); + let dec_insn = RType::new(instruction_u32); + let base_funct7 = (dec_insn.funct7 as u8) % TeBaseFunct7::TWISTED_EDWARDS_MAX_KINDS; + let curve_idx = + ((dec_insn.funct7 as u8) / TeBaseFunct7::TWISTED_EDWARDS_MAX_KINDS) as usize; + let curve_idx_shift = curve_idx * Rv32EdwardsOpcode::COUNT; + + if base_funct7 == TeBaseFunct7::TeSetup as u8 { + let local_opcode = Rv32EdwardsOpcode::SETUP_EC_ADD; + Some(Instruction::new( + VmOpcode::from_usize(local_opcode.global_opcode().as_usize() + curve_idx_shift), + F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rd), + F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs1), + F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs2), + F::ONE, // d_as = 1 + F::TWO, // e_as = 2 + F::ZERO, + F::ZERO, + )) + } else { + let global_opcode = match TeBaseFunct7::from_repr(base_funct7) { + Some(TeBaseFunct7::TeAdd) => { + Rv32EdwardsOpcode::EC_ADD as usize + Rv32EdwardsOpcode::CLASS_OFFSET + } + _ => unimplemented!(), + }; + let global_opcode = global_opcode + curve_idx_shift; + Some(from_r_type(global_opcode, 2, &dec_insn)) + } + }; + instruction.map(TranspilerOutput::one_to_one) + } + + fn process_weierstrass_instruction( + &self, + instruction_stream: &[u32], + ) -> Option> { if instruction_stream.is_empty() { return None; } @@ -41,7 +115,7 @@ impl TranspilerExtension for EccTranspilerExtension { let opcode = (instruction_u32 & 0x7f) as u8; let funct3 = ((instruction_u32 >> 12) & 0b111) as u8; - if opcode != OPCODE { + if opcode != SW_OPCODE { return None; } if funct3 != SW_FUNCT3 { diff --git a/extensions/pairing/circuit/src/pairing_extension.rs b/extensions/pairing/circuit/src/pairing_extension.rs index c75687f404..539773c454 100644 --- a/extensions/pairing/circuit/src/pairing_extension.rs +++ b/extensions/pairing/circuit/src/pairing_extension.rs @@ -8,7 +8,7 @@ use openvm_circuit::{ use openvm_circuit_derive::{AnyEnum, InstructionExecutor}; use openvm_circuit_primitives::bitwise_op_lookup::SharedBitwiseOperationLookupChip; use openvm_circuit_primitives_derive::{Chip, ChipUsageGetter}; -use openvm_ecc_circuit::CurveConfig; +use openvm_ecc_circuit::{CurveCoeffs, CurveConfig, SwCurveConfig}; use openvm_instructions::PhantomDiscriminant; use openvm_pairing_guest::{ bls12_381::{ @@ -38,15 +38,19 @@ impl PairingCurve { BN254_ECC_STRUCT_NAME.to_string(), BN254_MODULUS.clone(), BN254_ORDER.clone(), - BigUint::zero(), - BigUint::from_u8(3).unwrap(), + CurveCoeffs::SwCurve(SwCurveConfig { + a: BigUint::zero(), + b: BigUint::from_u8(3).unwrap(), + }), ), PairingCurve::Bls12_381 => CurveConfig::new( BLS12_381_ECC_STRUCT_NAME.to_string(), BLS12_381_MODULUS.clone(), BLS12_381_ORDER.clone(), - BigUint::zero(), - BigUint::from_u8(4).unwrap(), + CurveCoeffs::SwCurve(SwCurveConfig { + a: BigUint::zero(), + b: BigUint::from_u8(4).unwrap(), + }), ), } } From 6d8e6d5d035e296e71aa1902a7ef4f95260afecd Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Wed, 22 Jan 2025 18:14:30 -0500 Subject: [PATCH 04/57] renamed WeierstrassExtension to EccExtension (etc) --- benchmarks/prove/src/bin/ecrecover.rs | 7 +- crates/sdk/src/config/global.rs | 10 +- extensions/ecc/circuit/src/config.rs | 8 +- ...erstrass_extension.rs => ecc_extension.rs} | 320 ++---------------- extensions/ecc/circuit/src/lib.rs | 4 +- extensions/ecc/tests/src/lib.rs | 33 +- extensions/pairing/circuit/src/config.rs | 6 +- guest-libs/pairing/tests/lib.rs | 8 +- 8 files changed, 63 insertions(+), 333 deletions(-) rename extensions/ecc/circuit/src/{weierstrass_extension.rs => ecc_extension.rs} (50%) diff --git a/benchmarks/prove/src/bin/ecrecover.rs b/benchmarks/prove/src/bin/ecrecover.rs index 23fe2c82af..13382caeb8 100644 --- a/benchmarks/prove/src/bin/ecrecover.rs +++ b/benchmarks/prove/src/bin/ecrecover.rs @@ -12,8 +12,7 @@ use openvm_circuit::{ derive::VmConfig, }; use openvm_ecc_circuit::{ - CurveConfig, WeierstrassExtension, WeierstrassExtensionExecutor, WeierstrassExtensionPeriphery, - SECP256K1_CONFIG, + CurveConfig, EccExtension, EccExtensionExecutor, EccExtensionPeriphery, SECP256K1_CONFIG, }; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_keccak256_circuit::{Keccak256, Keccak256Executor, Keccak256Periphery}; @@ -63,7 +62,7 @@ pub struct Rv32ImEcRecoverConfig { #[extension] pub keccak: Keccak256, #[extension] - pub weierstrass: WeierstrassExtension, + pub weierstrass: EccExtension, } impl InitFileGenerator for Rv32ImEcRecoverConfig { @@ -89,7 +88,7 @@ impl Rv32ImEcRecoverConfig { io: Default::default(), modular: ModularExtension::new(primes), keccak: Default::default(), - weierstrass: WeierstrassExtension::new(curves), + weierstrass: EccExtension::new(curves), } } } diff --git a/crates/sdk/src/config/global.rs b/crates/sdk/src/config/global.rs index faf8182246..fb15631905 100644 --- a/crates/sdk/src/config/global.rs +++ b/crates/sdk/src/config/global.rs @@ -15,9 +15,7 @@ use openvm_circuit::{ circuit_derive::{Chip, ChipUsageGetter}, derive::{AnyEnum, InstructionExecutor}, }; -use openvm_ecc_circuit::{ - WeierstrassExtension, WeierstrassExtensionExecutor, WeierstrassExtensionPeriphery, -}; +use openvm_ecc_circuit::{EccExtension, EccExtensionExecutor, EccExtensionPeriphery}; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_keccak256_circuit::{Keccak256, Keccak256Executor, Keccak256Periphery}; use openvm_keccak256_transpiler::Keccak256TranspilerExtension; @@ -62,7 +60,7 @@ pub struct SdkVmConfig { pub modular: Option, pub fp2: Option, pub pairing: Option, - pub ecc: Option, + pub ecc: Option, } #[derive(ChipUsageGetter, Chip, InstructionExecutor, From, AnyEnum)] @@ -90,7 +88,7 @@ pub enum SdkVmConfigExecutor { #[any_enum] Pairing(PairingExtensionExecutor), #[any_enum] - Ecc(WeierstrassExtensionExecutor), + Ecc(EccExtensionExecutor), #[any_enum] CastF(CastFExtensionExecutor), } @@ -120,7 +118,7 @@ pub enum SdkVmConfigPeriphery { #[any_enum] Pairing(PairingExtensionPeriphery), #[any_enum] - Ecc(WeierstrassExtensionPeriphery), + Ecc(EccExtensionPeriphery), #[any_enum] CastF(CastFExtensionPeriphery), } diff --git a/extensions/ecc/circuit/src/config.rs b/extensions/ecc/circuit/src/config.rs index a959938be9..67d9f74609 100644 --- a/extensions/ecc/circuit/src/config.rs +++ b/extensions/ecc/circuit/src/config.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use super::*; #[derive(Clone, Debug, VmConfig, Serialize, Deserialize)] -pub struct Rv32WeierstrassConfig { +pub struct Rv32EccConfig { #[system] pub system: SystemConfig, #[extension] @@ -20,10 +20,10 @@ pub struct Rv32WeierstrassConfig { #[extension] pub modular: ModularExtension, #[extension] - pub weierstrass: WeierstrassExtension, + pub ecc: EccExtension, } -impl Rv32WeierstrassConfig { +impl Rv32EccConfig { pub fn new(curves: Vec) -> Self { let primes: Vec<_> = curves .iter() @@ -35,7 +35,7 @@ impl Rv32WeierstrassConfig { mul: Default::default(), io: Default::default(), modular: ModularExtension::new(primes), - weierstrass: WeierstrassExtension::new(curves), + ecc: EccExtension::new(curves), } } } diff --git a/extensions/ecc/circuit/src/weierstrass_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs similarity index 50% rename from extensions/ecc/circuit/src/weierstrass_extension.rs rename to extensions/ecc/circuit/src/ecc_extension.rs index 1081f21e98..2122962e7d 100644 --- a/extensions/ecc/circuit/src/weierstrass_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -1,9 +1,8 @@ use derive_more::derive::From; -use hex_literal::hex; -use lazy_static::lazy_static; use num_bigint::BigUint; use num_traits::{FromPrimitive, Zero}; use once_cell::sync::Lazy; +use openvm_algebra_guest::IntMod; use openvm_circuit::{ arch::{SystemPort, VmExtension, VmInventory, VmInventoryBuilder, VmInventoryError}, system::phantom::PhantomChip, @@ -12,7 +11,11 @@ use openvm_circuit_derive::{AnyEnum, InstructionExecutor}; use openvm_circuit_primitives::bitwise_op_lookup::{ BitwiseOperationLookupBus, SharedBitwiseOperationLookupChip, }; -use openvm_circuit_primitives_derive::{Chip, ChipUsageGetter}; +use openvm_circuit_primitives_derive::{BytesStateful, Chip, ChipUsageGetter}; +use openvm_ecc_guest::{ + k256::{SECP256K1_MODULUS, SECP256K1_ORDER}, + p256::{CURVE_A as P256_A, CURVE_B as P256_B, P256_MODULUS, P256_ORDER}, +}; use openvm_ecc_transpiler::{EccPhantom, Rv32EdwardsOpcode, Rv32WeierstrassOpcode}; use openvm_instructions::{LocalOpcode, PhantomDiscriminant, VmOpcode}; use openvm_mod_circuit_builder::ExprBuilderConfig; @@ -68,7 +71,6 @@ pub struct TeCurveConfig { } pub static SECP256K1_CONFIG: Lazy = Lazy::new(|| CurveConfig { - struct_name: SECP256K1_ECC_STRUCT_NAME.to_string(), modulus: SECP256K1_MODULUS.clone(), scalar: SECP256K1_ORDER.clone(), coeffs: CurveCoeffs::SwCurve(SwCurveConfig { @@ -78,35 +80,21 @@ pub static SECP256K1_CONFIG: Lazy = Lazy::new(|| CurveConfig { }); pub static P256_CONFIG: Lazy = Lazy::new(|| CurveConfig { - struct_name: P256_ECC_STRUCT_NAME.to_string(), modulus: P256_MODULUS.clone(), scalar: P256_ORDER.clone(), coeffs: CurveCoeffs::SwCurve(SwCurveConfig { - a: BigUint::from_bytes_le(&P256_A), - b: BigUint::from_bytes_le(&P256_B), + a: BigUint::from_bytes_le(P256_A.as_le_bytes()), + b: BigUint::from_bytes_le(P256_B.as_le_bytes()), }), }); #[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] -pub struct WeierstrassExtension { +pub struct EccExtension { pub supported_curves: Vec, } -impl WeierstrassExtension { - pub fn generate_sw_init(&self) -> String { - let supported_curves = self - .supported_curves - .iter() - .map(|curve_config| curve_config.struct_name.to_string()) - .collect::>() - .join(", "); - - format!("openvm_ecc_guest::sw_macros::sw_init! {{ {supported_curves} }}") - } -} - -#[derive(Chip, ChipUsageGetter, InstructionExecutor, AnyEnum)] -pub enum WeierstrassExtensionExecutor { +#[derive(Chip, ChipUsageGetter, InstructionExecutor, AnyEnum, BytesStateful)] +pub enum EccExtensionExecutor { // 32 limbs prime SwEcAddNeRv32_32(EcAddNeChip), SwEcDoubleRv32_32(EcDoubleChip), @@ -119,15 +107,15 @@ pub enum WeierstrassExtensionExecutor { TeEcAddRv32_48(TeEcAddChip), } -#[derive(ChipUsageGetter, Chip, AnyEnum, From)] -pub enum WeierstrassExtensionPeriphery { +#[derive(ChipUsageGetter, Chip, AnyEnum, From, BytesStateful)] +pub enum EccExtensionPeriphery { BitwiseOperationLookup(SharedBitwiseOperationLookupChip<8>), Phantom(PhantomChip), } -impl VmExtension for WeierstrassExtension { - type Executor = WeierstrassExtensionExecutor; - type Periphery = WeierstrassExtensionPeriphery; +impl VmExtension for EccExtension { + type Executor = EccExtensionExecutor; + type Periphery = EccExtensionPeriphery; fn build( &self, @@ -165,7 +153,7 @@ impl VmExtension for WeierstrassExtension { for (i, curve) in self.supported_curves.iter().enumerate() { let sw_start_offset = Rv32WeierstrassOpcode::CLASS_OFFSET + i * Rv32WeierstrassOpcode::COUNT; - // right now this is the same as sw_start_offset + // right now this is the same as sw_class_offset let te_start_offset = Rv32EdwardsOpcode::CLASS_OFFSET + i * Rv32EdwardsOpcode::COUNT; let bytes = curve.modulus.bits().div_ceil(8); @@ -196,7 +184,7 @@ impl VmExtension for WeierstrassExtension { offline_memory.clone(), ); inventory.add_executor( - WeierstrassExtensionExecutor::SwEcAddNeRv32_32(sw_add_ne_chip), + EccExtensionExecutor::SwEcAddNeRv32_32(sw_add_ne_chip), sw_add_ne_opcodes .clone() .map(|x| VmOpcode::from_usize(x + sw_start_offset)), @@ -216,10 +204,10 @@ impl VmExtension for WeierstrassExtension { offline_memory.clone(), ); inventory.add_executor( - WeierstrassExtensionExecutor::SwEcDoubleRv32_32(sw_double_chip), + EccExtensionExecutor::SwEcDoubleRv32_32(sw_double_chip), sw_double_opcodes .clone() - .map(|x| VmOpcode::from_usize(x + sw_class_offset)), + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), )?; } @@ -240,8 +228,8 @@ impl VmExtension for WeierstrassExtension { offline_memory.clone(), ); inventory.add_executor( - WeierstrassExtensionExecutor::TeEcAddRv32_32(te_add_chip), - te_add_opcodes + EccExtensionExecutor::TeEcAddRv32_32(te_add_chip), + sw_add_ne_opcodes .clone() .map(|x| VmOpcode::from_usize(x + te_start_offset)), )?; @@ -264,7 +252,7 @@ impl VmExtension for WeierstrassExtension { offline_memory.clone(), ); inventory.add_executor( - WeierstrassExtensionExecutor::SwEcAddNeRv32_48(sw_add_ne_chip), + EccExtensionExecutor::SwEcAddNeRv32_48(sw_add_ne_chip), sw_add_ne_opcodes .clone() .map(|x| VmOpcode::from_usize(x + sw_start_offset)), @@ -284,10 +272,10 @@ impl VmExtension for WeierstrassExtension { offline_memory.clone(), ); inventory.add_executor( - WeierstrassExtensionExecutor::SwEcDoubleRv32_48(sw_double_chip), + EccExtensionExecutor::SwEcDoubleRv32_48(sw_double_chip), sw_double_opcodes .clone() - .map(|x| VmOpcode::from_usize(x + sw_class_offset)), + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), )?; } @@ -308,7 +296,7 @@ impl VmExtension for WeierstrassExtension { offline_memory.clone(), ); inventory.add_executor( - WeierstrassExtensionExecutor::TeEcAddRv32_48(te_add_chip), + EccExtensionExecutor::TeEcAddRv32_48(te_add_chip), te_add_opcodes .clone() .map(|x| VmOpcode::from_usize(x + te_start_offset)), @@ -319,263 +307,7 @@ impl VmExtension for WeierstrassExtension { panic!("Modulus too large"); } } - let non_qr_hint_sub_ex = phantom::NonQrHintSubEx::new(self.supported_curves.clone()); - builder.add_phantom_sub_executor( - non_qr_hint_sub_ex.clone(), - PhantomDiscriminant(EccPhantom::HintNonQr as u16), - )?; - builder.add_phantom_sub_executor( - phantom::DecompressHintSubEx::new(non_qr_hint_sub_ex), - PhantomDiscriminant(EccPhantom::HintDecompress as u16), - )?; Ok(inventory) } } - -pub(crate) mod phantom { - use std::{ - iter::{once, repeat}, - ops::Deref, - }; - - use eyre::bail; - use num_bigint::BigUint; - use num_integer::Integer; - use num_traits::One; - use openvm_algebra_circuit::{find_non_qr, mod_sqrt}; - use openvm_circuit::{ - arch::{PhantomSubExecutor, Streams}, - system::memory::MemoryController, - }; - use openvm_instructions::{riscv::RV32_MEMORY_AS, PhantomDiscriminant}; - use openvm_rv32im_circuit::adapters::unsafe_read_rv32_register; - use openvm_stark_backend::p3_field::PrimeField32; - - use super::{CurveCoeffs, CurveConfig, SwCurveConfig, TeCurveConfig}; - - // Hint for a decompression - // if possible is true, then `sqrt` is the decompressed y-coordinate - // if possible is false, then `sqrt` is such that - // `sqrt^2 = rhs * non_qr` where `rhs` is the rhs of the curve equation - pub struct DecompressionHint { - pub possible: bool, - pub sqrt: T, - } - - #[derive(derive_new::new)] - pub struct DecompressHintSubEx(NonQrHintSubEx); - - impl Deref for DecompressHintSubEx { - type Target = NonQrHintSubEx; - - fn deref(&self) -> &NonQrHintSubEx { - &self.0 - } - } - - impl PhantomSubExecutor for DecompressHintSubEx { - fn phantom_execute( - &mut self, - memory: &MemoryController, - streams: &mut Streams, - _: PhantomDiscriminant, - a: F, - b: F, - c_upper: u16, - ) -> eyre::Result<()> { - let c_idx = c_upper as usize; - if c_idx >= self.supported_curves.len() { - bail!( - "Curve index {c_idx} out of range: {} supported curves", - self.supported_curves.len() - ); - } - let curve = &self.supported_curves[c_idx]; - let rs1 = unsafe_read_rv32_register(memory, a); - let num_limbs: usize = if curve.modulus.bits().div_ceil(8) <= 32 { - 32 - } else if curve.modulus.bits().div_ceil(8) <= 48 { - 48 - } else { - bail!("Modulus too large") - }; - let mut x_limbs: Vec = Vec::with_capacity(num_limbs); - for i in 0..num_limbs { - let limb = memory.unsafe_read_cell( - F::from_canonical_u32(RV32_MEMORY_AS), - F::from_canonical_u32(rs1 + i as u32), - ); - x_limbs.push(limb.as_canonical_u32() as u8); - } - let x = BigUint::from_bytes_le(&x_limbs); - let rs2 = unsafe_read_rv32_register(memory, b); - let rec_id = memory.unsafe_read_cell( - F::from_canonical_u32(RV32_MEMORY_AS), - F::from_canonical_u32(rs2), - ); - let hint = self.decompress_point(x, rec_id.as_canonical_u32() & 1 == 1, c_idx); - let hint_bytes = once(F::from_bool(hint.possible)) - .chain(repeat(F::ZERO)) - .take(4) - .chain( - hint.sqrt - .to_bytes_le() - .into_iter() - .map(F::from_canonical_u8) - .chain(repeat(F::ZERO)) - .take(num_limbs), - ) - .collect(); - streams.hint_stream = hint_bytes; - Ok(()) - } - } - - impl DecompressHintSubEx { - fn decompress_point(&self, x: BigUint, is_y_odd: bool, curve_idx: usize) -> BigUint { - match self.supported_curves[curve_idx].coeffs.clone() { - CurveCoeffs::SwCurve(SwCurveConfig { a, b }) => { - self.decompress_sw_point(x, is_y_odd, curve_idx) - } - CurveCoeffs::TeCurve(TeCurveConfig { a: _, d: _ }) => { - unimplemented!("should not call decompress_point for Twisted Edwards curves"); - } - } - } - - /// Given `x` in the coordinate field of a Weierstrass curve, and the recovery id, - /// return the unique `y` such that `(x, y)` is a point on the curve and - /// `y` has the same parity as the recovery id. - /// - /// If no such `y` exists, return the square root of `(x^3 + ax + b) * non_qr` - /// where `non_qr` is a quadratic nonresidue of the field. - fn decompress_sw_point( - &self, - x: BigUint, - is_y_odd: bool, - curve_idx: usize, - ) -> DecompressionHint { - let curve = &self.supported_curves[curve_idx]; - let alpha = ((&x * &x * &x) + (&x * &curve.a) + &curve.b) % &curve.modulus; - match mod_sqrt(&alpha, &curve.modulus, &self.non_qrs[curve_idx]) { - Some(beta) => { - if is_y_odd == beta.is_odd() { - DecompressionHint { - possible: true, - sqrt: beta, - } - } else { - DecompressionHint { - possible: true, - sqrt: &curve.modulus - &beta, - } - } - } - None => { - debug_assert_eq!( - self.non_qrs[curve_idx] - .modpow(&((&curve.modulus - BigUint::one()) >> 1), &curve.modulus), - &curve.modulus - BigUint::one() - ); - let sqrt = mod_sqrt( - &(&alpha * &self.non_qrs[curve_idx]), - &curve.modulus, - &self.non_qrs[curve_idx], - ) - .unwrap(); - DecompressionHint { - possible: false, - sqrt, - } - } - } - } - } - - #[derive(Clone)] - pub struct NonQrHintSubEx { - pub supported_curves: Vec, - pub non_qrs: Vec, - } - - impl NonQrHintSubEx { - pub fn new(supported_curves: Vec) -> Self { - let non_qrs = supported_curves - .iter() - .map(|curve| find_non_qr(&curve.modulus)) - .collect(); - Self { - supported_curves, - non_qrs, - } - } - } - - impl PhantomSubExecutor for NonQrHintSubEx { - fn phantom_execute( - &mut self, - _: &MemoryController, - streams: &mut Streams, - _: PhantomDiscriminant, - _: F, - _: F, - c_upper: u16, - ) -> eyre::Result<()> { - let c_idx = c_upper as usize; - if c_idx >= self.supported_curves.len() { - bail!( - "Curve index {c_idx} out of range: {} supported curves", - self.supported_curves.len() - ); - } - let curve = &self.supported_curves[c_idx]; - - let num_limbs: usize = if curve.modulus.bits().div_ceil(8) <= 32 { - 32 - } else if curve.modulus.bits().div_ceil(8) <= 48 { - 48 - } else { - bail!("Modulus too large") - }; - - let hint_bytes = self.non_qrs[c_idx] - .to_bytes_le() - .into_iter() - .map(F::from_canonical_u8) - .chain(repeat(F::ZERO)) - .take(num_limbs) - .collect(); - streams.hint_stream = hint_bytes; - Ok(()) - } - } -} - -// Convenience constants for constructors -lazy_static! { - // The constants are taken from: https://en.bitcoin.it/wiki/Secp256k1 - pub static ref SECP256K1_MODULUS: BigUint = BigUint::from_bytes_be(&hex!( - "FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F" - )); - pub static ref SECP256K1_ORDER: BigUint = BigUint::from_bytes_be(&hex!( - "FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141" - )); -} - -lazy_static! { - // The constants are taken from: https://neuromancer.sk/std/secg/secp256r1 - pub static ref P256_MODULUS: BigUint = BigUint::from_bytes_be(&hex!( - "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff" - )); - pub static ref P256_ORDER: BigUint = BigUint::from_bytes_be(&hex!( - "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" - )); -} -// little-endian -const P256_A: [u8; 32] = hex!("fcffffffffffffffffffffff00000000000000000000000001000000ffffffff"); -// little-endian -const P256_B: [u8; 32] = hex!("4b60d2273e3cce3bf6b053ccb0061d65bc86987655bdebb3e7933aaad835c65a"); - -pub const SECP256K1_ECC_STRUCT_NAME: &str = "Secp256k1Point"; -pub const P256_ECC_STRUCT_NAME: &str = "P256Point"; diff --git a/extensions/ecc/circuit/src/lib.rs b/extensions/ecc/circuit/src/lib.rs index 378d4ec800..050bf57a3b 100644 --- a/extensions/ecc/circuit/src/lib.rs +++ b/extensions/ecc/circuit/src/lib.rs @@ -1,8 +1,8 @@ mod weierstrass_chip; pub use weierstrass_chip::*; -mod weierstrass_extension; -pub use weierstrass_extension::*; +mod ecc_extension; +pub use ecc_extension::*; mod edwards_chip; pub use edwards_chip::*; diff --git a/extensions/ecc/tests/src/lib.rs b/extensions/ecc/tests/src/lib.rs index fea5dce974..a4d981b719 100644 --- a/extensions/ecc/tests/src/lib.rs +++ b/extensions/ecc/tests/src/lib.rs @@ -12,8 +12,8 @@ mod tests { utils::{air_test, air_test_with_min_segments}, }; use openvm_ecc_circuit::{ - CurveConfig, CurveCoeffs, CurveConfig, Rv32WeierstrassConfig, TeCurveConfig, WeierstrassExtension, - P256_CONFIG, SECP256K1_CONFIG, + CurveCoeffs, CurveConfig, EccExtension, Rv32EccConfig, TeCurveConfig, P256_CONFIG, + SECP256K1_CONFIG, }; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_keccak256_transpiler::Keccak256TranspilerExtension; @@ -31,7 +31,7 @@ mod tests { #[test] fn test_ec() -> Result<()> { - let config = Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone()]); let elf = build_example_program_at_path_with_features( get_programs_dir!(), "ec", @@ -53,7 +53,7 @@ mod tests { #[test] fn test_ec_nonzero_a() -> Result<()> { - let config = Rv32WeierstrassConfig::new(vec![P256_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![P256_CONFIG.clone()]); let elf = build_example_program_at_path_with_features( get_programs_dir!(), "ec_nonzero_a", @@ -75,8 +75,7 @@ mod tests { #[test] fn test_ec_two_curves() -> Result<()> { - let config = - Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone(), P256_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone(), P256_CONFIG.clone()]); let elf = build_example_program_at_path_with_features( get_programs_dir!(), "ec_two_curves", @@ -101,7 +100,7 @@ mod tests { use halo2curves_axiom::{group::Curve, secp256k1::Secp256k1Affine}; let config = - Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone(), + Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone(), CurveConfig { struct_name: "CurvePoint5mod8".to_string(), modulus: BigUint::from_str("115792089237316195423570985008687907853269984665640564039457584007913129639501") @@ -109,8 +108,10 @@ mod tests { // unused, set to 10e9 + 7 scalar: BigUint::from_str("1000000007") .unwrap(), - a: BigUint::ZERO, - b: BigUint::from_str("3").unwrap(), + coeffs: CurveCoeffs::SwCurve(SwCurveConfig { + a: BigUint::ZERO, + b: BigUint::from_str("3").unwrap(), + }), }, CurveConfig { struct_name: "CurvePoint1mod4".to_string(), @@ -118,10 +119,12 @@ mod tests { .unwrap(), scalar: BigUint::from_radix_be(&hex!("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d"), 256) .unwrap(), - a: BigUint::from_radix_be(&hex!("fffffffffffffffffffffffffffffffefffffffffffffffffffffffe"), 256) - .unwrap(), - b: BigUint::from_radix_be(&hex!("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"), 256) - .unwrap(), + coeffs: CurveCoeffs::SwCurve(SwCurveConfig { + a: BigUint::from_radix_be(&hex!("fffffffffffffffffffffffffffffffefffffffffffffffffffffffe"), 256) + .unwrap(), + b: BigUint::from_radix_be(&hex!("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"), 256) + .unwrap(), + }), }, ]); @@ -174,7 +177,7 @@ mod tests { SECP256K1_CONFIG.scalar.clone(), ])) .keccak(Default::default()) - .ecc(WeierstrassExtension::new(vec![SECP256K1_CONFIG.clone()])) + .ecc(EccExtension::new(vec![SECP256K1_CONFIG.clone()])) .build(); let elf = build_example_program_at_path_with_features( @@ -214,7 +217,7 @@ mod tests { .with_extension(ModularTranspilerExtension), )?; let config = - Rv32WeierstrassConfig::new(vec![CurveConfig { + Rv32EccConfig::new(vec![CurveConfig { modulus: BigUint::from_str( "57896044618658097711785492504343953926634992332820282019728792003956564819949", ).unwrap(), diff --git a/extensions/pairing/circuit/src/config.rs b/extensions/pairing/circuit/src/config.rs index d63bac664e..2310622d39 100644 --- a/extensions/pairing/circuit/src/config.rs +++ b/extensions/pairing/circuit/src/config.rs @@ -23,7 +23,7 @@ pub struct Rv32PairingConfig { #[extension] pub fp2: Fp2Extension, #[extension] - pub weierstrass: WeierstrassExtension, + pub weierstrass: EccExtension, #[extension] pub pairing: PairingExtension, } @@ -48,9 +48,7 @@ impl Rv32PairingConfig { .zip(modulus_primes) .collect(), ), - weierstrass: WeierstrassExtension::new( - curves.iter().map(|c| c.curve_config()).collect(), - ), + weierstrass: EccExtension::new(curves.iter().map(|c| c.curve_config()).collect()), pairing: PairingExtension::new(curves), } } diff --git a/guest-libs/pairing/tests/lib.rs b/guest-libs/pairing/tests/lib.rs index e7c189b550..9aee0f2fec 100644 --- a/guest-libs/pairing/tests/lib.rs +++ b/guest-libs/pairing/tests/lib.rs @@ -15,7 +15,7 @@ mod bn254 { arch::SystemConfig, utils::{air_test, air_test_impl, air_test_with_min_segments}, }; - use openvm_ecc_circuit::{Rv32WeierstrassConfig, WeierstrassExtension}; + use openvm_ecc_circuit::{EccExtension, Rv32WeierstrassConfig}; use openvm_ecc_guest::{ algebra::{field::FieldExtension, IntMod}, AffinePoint, @@ -54,7 +54,7 @@ mod bn254 { io: Default::default(), modular: ModularExtension::new(primes.to_vec()), fp2: Fp2Extension::new(primes_with_names), - weierstrass: WeierstrassExtension::new(vec![]), + weierstrass: EccExtension::new(vec![]), pairing: PairingExtension::new(vec![PairingCurve::Bn254]), } } @@ -462,7 +462,7 @@ mod bls12_381 { arch::{instructions::exe::VmExe, SystemConfig}, utils::{air_test, air_test_impl, air_test_with_min_segments}, }; - use openvm_ecc_circuit::{CurveConfig, Rv32WeierstrassConfig, WeierstrassExtension}; + use openvm_ecc_circuit::EccExtension; use openvm_ecc_guest::{ algebra::{field::FieldExtension, IntMod}, AffinePoint, @@ -503,7 +503,7 @@ mod bls12_381 { io: Default::default(), modular: ModularExtension::new(primes.to_vec()), fp2: Fp2Extension::new(primes_with_names), - weierstrass: WeierstrassExtension::new(vec![]), + weierstrass: EccExtension::new(vec![]), pairing: PairingExtension::new(vec![PairingCurve::Bls12_381]), } } From a5d42ae3851b97959a340eabc4802fdf883777df Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Thu, 23 Jan 2025 15:24:28 -0500 Subject: [PATCH 05/57] fix linter errors and address PR comments - rename remaining structs - switch from num-bigint-dig to num-bigint --- Cargo.lock | 16 --- examples/algebra/openvm/app.vmexe | Bin 0 -> 149050 bytes examples/ecc/openvm.toml | 3 +- examples/ecc/openvm/app.vmexe | Bin 0 -> 139865 bytes examples/i256/openvm/app.vmexe | Bin 0 -> 259692 bytes extensions/ecc/circuit/Cargo.toml | 1 - extensions/ecc/circuit/src/ecc_extension.rs | 27 ++--- .../ecc/circuit/src/edwards_chip/mod.rs | 31 ++---- .../ecc/circuit/src/edwards_chip/tests.rs | 4 +- .../ecc/circuit/src/edwards_chip/utils.rs | 101 ++++++++++++++++++ .../circuit/src/weierstrass_chip/add_ne.rs | 2 +- .../circuit/src/weierstrass_chip/double.rs | 2 +- .../ecc/circuit/src/weierstrass_chip/mod.rs | 16 +-- .../ecc/circuit/src/weierstrass_chip/tests.rs | 8 +- extensions/ecc/te-setup/src/lib.rs | 8 +- 15 files changed, 147 insertions(+), 72 deletions(-) create mode 100644 examples/algebra/openvm/app.vmexe create mode 100644 examples/ecc/openvm/app.vmexe create mode 100644 examples/i256/openvm/app.vmexe create mode 100644 extensions/ecc/circuit/src/edwards_chip/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 96a814b4c2..fcf9528769 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4128,21 +4128,6 @@ dependencies = [ "serde", ] -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "smallvec", -] - [[package]] name = "num-complex" version = "0.4.6" @@ -4688,7 +4673,6 @@ dependencies = [ "hex-literal 0.4.1", "lazy_static", "num-bigint 0.4.6", - "num-bigint-dig", "num-integer", "num-traits", "once_cell", diff --git a/examples/algebra/openvm/app.vmexe b/examples/algebra/openvm/app.vmexe new file mode 100644 index 0000000000000000000000000000000000000000..801ce826381b8b3c474e2058138396c1c1e89506 GIT binary patch literal 149050 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 literal 0 HcmV?d00001 diff --git a/examples/ecc/openvm.toml b/examples/ecc/openvm.toml index 1dc6cf25f2..d887d74a5f 100644 --- a/examples/ecc/openvm.toml +++ b/examples/ecc/openvm.toml @@ -8,5 +8,4 @@ supported_moduli = ["11579208923731619542357098500868790785326998466564056403945 struct_name = "Secp256k1Point" modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" -a = "0" -b = "7" \ No newline at end of file +coeffs = { SwCurve = { a = "0", b = "7" } } diff --git a/examples/ecc/openvm/app.vmexe b/examples/ecc/openvm/app.vmexe new file mode 100644 index 0000000000000000000000000000000000000000..9d1635d7e8dd8033a14c7368b95da84a07ff68d6 GIT binary patch literal 139865 zcmeF)1%Q>+y8rQE$f3KtySux)ySs*N1Pl-r0~-?&3j+}q5iw~|2~m+5y1NIM_NKipK; zzEhJg<}UuZkMGX@`IKdd>0_mO&g~p1^~JR3)=Kimv?&{t-cBpEv3|O~)oHx>F5>ob zNAz9W*fv*->sx!?K;L^yroh5n=}!Q3?Mo9xuUCKj-rw3rKXn;saq}s(Yulqlfe8Z> z&|j^zBUWyy$_lf>M1ev4Nf@ZR5fGR;`frWvE4O{lM_wybETxi<-N_V~B%0=_{yGUs z0u%FhLPm`3N_D>0is##*MA0))-uA|wsYcceRHt(F_T_!oWhuY2Ir!FcCowc5?UQe> zGP9SN*_BMue`~(JUG=r76jOV%Ja2S6U-`{`z8JTk|8qQd2Hr?FTjt{q)Mb8>Hu_oe z{jC-m0*gk^yDaxI9}<$&nb2C?vc%M>)U8unE4S3@17bdnE742$R3|DQe>A2(h4mEb z*}C}*`bzz^_Sd#jOcbpk`q>Lmw3|<>?|IPQDzm?Dmg-7#@z=K;^UW6%OXt=1tms+u zJuQkzIU_1YCH|<5Z=9PWs7}$fW~I?1MYr@_l?zN4-9O(Sv-3u!3gO%;IP^I%j30>)gAfv+s?de7-+o z-khIB^Oo2hwp8_sp-&s#Et_55=u+SL(aa?;e=-Lap>1Kk14Qqa_Docx`&gD*<#bB) zXUit|=-}^wK=x9MP}{c#%Ip0>W$Adnbe)dB?Hj406^*V{4E56Az8D(E z*V@-!d7WVW(f5F|(JTAUHooUZt#rS&Ufn4>4@!M!B6#ggm%}c$W6+L5lqf=jmveCVKv$W^OW@s~4f9;T+TKC#YZN;`Otv+B`R8)}w zUW=ll%Gk9xJsTC3G%PBr&YGyGJS(H3`V5JRYSKF@Dvk20Q+rtw6*a^aTeNZ*-e>V{?b&}*oVd=6>g=A}tvUZ&XZ@d;_y6W|uDRRUkL`0% z<+|tIby`0=1F_||Mnz>&e~Yj8aEoPql-f9|_rA|tJH?6Zr8A^D8z;8Ub3MO$&(kxm zxoa-&dw`uq8`IY3wy}OnZCopJ+ucblH;#>?x$4@To7$<|yJxqPS6_c~v~k=yXm8zl z*c{w)E3-MdbB*o3*nPMApn1=aimGBUlp1gOoT#YD*3SAVRV<6AKGsid?b_-swj0aJ z{H1Cq>OX~Zt2Vl}@%{C2%iOlwJN2`^cCGk|9n7<*`Knyk?wqaO=52W!%jRhH{!%Mb zA6tu3caF-doyOl471c)9#>RB>)<$(keeGIfx$(6=+XuThwgy|T;@enme4CT{SxoC| zsru?#sqM4XS!(5)huhv_D!#^7osFq$V{>!!?mTVnx3dp!49!n{|Lu8bKWuOOrJAGW zr8-^PJhe}j_ZLI^>-Mqxtv$L{on0pu{2MctJbG@cD7Znz0oCb{a?5T7%smr7BaMXkDUtS{rL`ZEh!ZW4i6#xNaMN z<64=Uy8CR`b~Y{5817nht+5ox=Ayh_TAQ`EI!jgWy|z8Ea?4w4W4PMxe&VRNxqcE7#fMLY93+KTVRjiREu)a3U}s#i>#kELp(a=kPk z#aEg7i+z`M=c@0uD))|IF?Fvkmaa8dy5=IpLh>$Q0(w!Y)5-rCrhO0`F7ub5)vD7LOGzS`QjR;IY>tJGp?T>E*# z=AgW|v284irT*4lWw$yfI!|hUyXUGR-5IgdUc+32DK(PRh`jVb*Y-KNO9%_3#_r$x$c8_cx+JEhV=Akj9Kuqe6rTM$_Ql0kOr8%j;>NGc{TBohu z>NU2?mD(KbNHpQ_ql`60GsE_8L_XeXrHooSgYq6MCr*_`?YR?o$du08*@vKhq>{@Yj zZD(C`ifc_a2kndEXw6n;<0@5LQN7(KZ>qDXwpMO=i=+8#47(R@OtrCcYp+!8EpOLq zXMJr?)Mi)A{m}S2?_y>CVknN<8jEG~R3AHwcD_}ndgaw$*J3f0x^-$}?d)1Hv^QFh z=BIgT|I^cV9rxV0dG%2nwN-qLqw6W$6J0A+EcLZIH*OGpL@^UEwo*}hyH>qhr)#mk zcI~g9#n2oT)6UZz`fF}7pZIpYkg<)`X}-25x1D0Bt@c^hwvWo&wf4u(hn3qL&Js5) zW}nnw^){yFWMxWiT$_vbRBTEQPRI!w*PN}WO@+wn*YdfELi1Om@rSev1V_M$&S-Fj?`xVC6M)yE5?OynM zkFw8+&g{2+HrunKIVhIiYi*8hos}t7xtq5+xn*{(Ik{)Z+N#XvZZX~QRHt&S(_*Qw zSUgK@kJMJzc9yNJr8XDkZA_bkx6a)QUHjWlch4=J&DBk9o^F|Yt+Cy_U8|qX&*rQ; zw>)}t)kqZzq-$$nsU{j1n}FKb;1*A*zjF0)Um90=>!-1;UUfQrmRD-+-7>e_=AklO zd*kV#irZf?HCK)0j%V%MF|FSED31CnwRRfQ$}F|^im9?YrFqdE?tS{}ZX^;_qDhE7Sbc{&vo~J}mCWdg9Nz@4fVH?B%Uu z#Gmt<@6C43^&uYHzS(o24_dXimzCSI9$Q{tU@f-#>Pv_l!|JTR)oVPvR-ML)i`rPM z*iyyRd$gSan}<^C@BK`)&ogUdee}%g`Bz@!S-Db+W%bId+}V5{owrl2aqaU;*EUC8+xwzhu9!9tf8|zYbF>(WdpqY#_r%Va?z?@_SGk=7w_M{X zuO9&H+G5y!R=MJ6ooZ|S)yK_SJGb1ecfUxhjm=Z#Q&^wc+8nH(zf}EHu2lPC^RjZq zu=A-@6kpWF)@tpP*BspORi~G=^_N;7)v2$gHaFEPhSk{`gE<2>C;f1$dex~+dDW{- z*D6z9v8|uVY^|1R9Njn7sju>SDX&y>ajA_;(o)UO*gn~uEw#O}K9+`YPTan3dv{DLciUT;V%xP+_uAil?zG-w zdgtek{a5GYFQ)cducI+Px1Hs=5tV5l^nB>rK1+42dX-x{mDw|+)au-8wb3iCcDL&1 zt-n>?=4bQO_`24*G!LV4?WfE{5we5>imFZmS+RnDFt&QrfpT$$1 z)-9Tsjqh&_>J!`CEw1gMQpHewx6bxJm!XtK3pu>z9^VuhDl$m9^s8P&>Ws`=rf7d3zsHz1n(NTbol&#?l!2 z4ye@nS-VF3!dPXo)hWJWXrJ5|>Z6z2&&IJi+89bzruP2U>F$liP?@e>+8attw(co z&xvMJlli-4x?eU|t=rCyy-z5f+9;+{#kBUi)_y4O#`LyPOzo}O+4HaSqK6!m)fYU?vv*1-M`z-ZzYD!&E{aK#dD zH`V!2d&TwES^jpPbIr%*q(sy-*yn=Rp1JeyOdlEtc|n*}m8r zviBW(FH*f|9vVmO&axl3V)xhP;;uv2HntmI=U3%=hBQ~r!8>28v$@zAR6p-aZS0wF z%v_d{it*R`EvTdUPs-cl>SRqDp{wpE>#xz{SQy>!=M zW9z)?zSx@7R@c@?vFxQXtG70aqyCDmcB;4YsB6``&xHCZ@5WJk_nat>ofW03SD9XR z&ZjWmI?jz(dg5D|ugA@Q?4i8I4~}`R6+>luwlyc4x9+Rr1Tn5slD+ZB=jWl`3Xzaco?r*3agkRQF7&Ub-i0 zBkr}8xvAYpz29kU^;elvy|;DdOzT=Ny{EcsQ&zo1dTc&Gk>rFM5=Abs3vr@hM z%|-LjdKKe#QpHhQ+hgUuFV*{-gRR&0LV0~2c<1ltW7~6$>F$^Ham#gW<(9f-IycH| z48_v5rB?pO7Y1#fb+A;8^cr#?q|uxkJPbE@gSf$)^$mXbxWO;WZ$#B85E?RQ<&CI5 zqxOen8WQ>Ee+Z%Soclv^dCON2Lvg1tu}E%ED2~#1(Rts5)o)h#&@5&f@7 zl~+HNg`SE?ZYl^%}>{= zSKeD@hc40?r@#fi#IS~nCqsH^&PH+0Uf@62i5a6rB>%!WGOAC_$f!JxBBQ$O3Xf_N z8qQvXb7;b&lD3NEzc~`g55ST9z($|2aQ?+v1aDFid{9L2FKj8(gW!!56i$73RB-n2 zs4@k@`ELw(;*y$t4o(Y|RMrT)h9uE9H&cMTd(>(~D4T654`G$)OtwP}rtqq%Dh zT1zX|q&?BzXpgjJ@7V5G7kKl~IErcGsgJwA3yHIccuR=8jPbm4U&%byFrRhA*vk02 zcS<$)l~<$s=tD~%g!&-UIrGLp8uKO+#@^`+dE@JRX;1ZVD`o=rB8+GA?2V|TM{oT3 zzX77>BlJd8nq4>e*N!*%SDZJZx)kE<*}YMGy%Jow`L85>C5(H4H}J@)q~VOGROP+H zqSENB4>=LiXc^~Ob5W|g64%&!_D<)(yT{ohIGYjtkQ~8TjNrfZ;5nl;BRESDoTUiP zQUw3)oqzbO|J8e_bL2i7-e*DksdITZ&brQuojqOa9O*piTxlHltn2*g9O^u3O@HOA zYYfG+vApNd`~KuThu-%m-8Y?eoym3F%ay#>t>L|H9p`N;_xnHM^IjLqd)-myq4VX9 zuXD8|lC?#$wn)Ahd(Qd%NZtn`Ik)_a+hF?N&N;6b=G#NPFX_zcr8BKPu=gyL>HRsb z&q1}(b5P)T$RK?dsIQ*o^d};MRetnXNFzNPHBUt3QGVUAkWR|?J`oZ9`4@B|qDq3$ zkcoQMRj&60rHZ@oT2!#g74MI6j)e@edX?#V*U5NMe2QO~89W z5ML(K^B$L7UozPG==+D{;>E1DzX7_rhYR&6IQOHRneCjLO%Xi^`+-JAIkcmp^^4@xIsU zZ0dbe&#C%)_e=Nc?1_-XHpkxQeP1Zu`KYb{aa5)l?%bB0_s!qRHLrE&efQRlv55D> zxbBN$hDG?!sOEc}wd@axm|TG8LFX-;aSw(>4AJM+;gE6r}C0tUNJO12jC(dDB58Kj$DBufX6d|T z4~;03J~SdYC^RDazp1A(?Y-8WAT%QS9w@&y<_ue0Zyenpok8{M91ze}^U*rAM$sJ4 za&C03I=!q;*ZV_4CaS&etJa}CcH0gK2xzK$eW%hGHE%@aQGO2lpgq+02(=I9vs3Z( z()v{v3bj?c!yzG^lo#!d)*JmLoc+-{)z8YbmnzemtxWZroBCLp^0ps3CyKo;AfW5@ zkdRV(UsoT!G>3%=0>-Fb`>{V}JjGW$#ZWspueKJmcR)Z|wbNc(J4>V2K%M&Pd#1|u zQeN~~t$ZZ$lxn{fdpC2^KK!vBXCJK0-3KdEj43hmwld}Y?L%ZpNGd(&>Z6z1>t1Ls z2SY*zX&!sXYaY55omaabR_4yb$`sG$VP&z+BRnJ|m)fhHo)OJs4bM*)^IpV0s4kK^ z&CRau+^CHxuR66+9JSY(RheGOD^Un-AnyemAT8t)SCaT;5By-z5w zxu53jDt}VXcTD~`=Sq3qhr^r`uJ^**aq?{}N%Z*8rg_Ck9+g}Lq~O~CgMwO6^@-tDhC>#zOO zI@M=2{cSBu^|CsxL2DO#epP0D)K+8Yb1T8IkcrAOvFP^$T`P{;*2*-l;wYx*JxO(L zY;W8G{0=~E^m606@pT^*TWN4;L{hcY+_oMK$)q&wNJuSxE`>7ouA>oc8ij^*TEf04 zo@kw``F+Ej^HGy^&(vq#k&sS0AG%M9t+}e5Vraga=Tg?7HX3iu-iYYu#~pXck&r=u zjC(AijeaK)ye}g9yy$w!zK}*5Uon*GeNJaV@s%pCc`o8!DbA3=kdCJepcd!Nx95*+rucWWOtruI1?fGEI>qQ6vv%!~@}jvZrsBl5CnZ?7>ebH1>>M+`^0Q;=G^Z&svD8-U zS3iwo_f%u3O!e-1H4lrec@AOj!NgWPf9FKwE6$KmerM_D9NE3n9&1e9AI&e6*fy^E z+e>RyJIzC%@tVt0^6Ia-HsV@+D{}wUN9)lXt-t1>zM?Z-A|Rk>P5P?-D4#u=uf<;+ z^BJ&=Hr9U;dt~jcOlfbPW6N8;ohv;rnx{VNG*6AKHb)~kf2_g!ZRK|>TD$hZ%Dm~a z8@_w27;5j`qrbDqx_25Ul$ctd=4kU!nZ{DR%9Z+io#pp@I>TC*+UxA=R$Bd!2#?F;@Y{jzsYH^e*mipewn%#KrweFSjioccbciw%rwyIChcYmEX%~P~b zt+U~z+v!uQ{ z``$UITrbUA=Tm3XormAJjPL8^`#Y{SvCU2QR?nx!v3sq&=At=>e(%^j!k5>&RbP`- z-}m$#PI-;5KAOAs+dhxAIqxN=Avj+r}wf;)=N)Yqjq49e|Wx5}>CguIT7wK74 z8(Uv?=6ROy!D?@*uI;7YC)>5wWoP16_td=~Hm7jL)tWT6apTx}Lu2agtSfJGP-@R* zP2#!z-8PD^=e9HBxzCN};*F=adT#8@sE@xh=x-^}PdOM-N8is>u0D#dc`C2+ zikJBvB;VV#Ud=^w(s*j)j$wPPHmVcdW1ShDm&L44dBr?>nV(sBZq>);uDNJzjjI?o zAH`9fy&CO}i2f|rnbq%z^d7CanxF2O%|rF}Sw18thUV^`U5zJdr_VkcL#e;>sB*2x z#&z38KPNnYil=*Szqd*d8Z}wZkNRm%YNxqQ;aYRle6){B(^IFlYfqG_&m5lfMltVy z(c|&CtWrg9y`E9kS-Hye8K(VL zxvtgUTdz9JRdr!JbGs7welMoabIncb)I62inr+USlN(R$F!S^U$@{6n)NO?z_f0$zE=`&UaycW>|EH-&ygQrZQO_bf`?nb5VUXue0ZT&%n4V zoC)d{RE)}^`=_{?-(mJHnE2Wc&0#n5)&1Nsf2&s;)mh(L z#j$>h<&Cd>54!9-H=2{;#`SZQJ+Jnh>;9}f5Yo%?>aY3hKcfj_y}GxmTf^G)bKco7 z-~X6_=I;L7r+F>pOe)?{{*8e8U8hWaHKzJ&e!6$6(>Qu*{`&U=`p<)+&&q+2Qd+OC z*7v>Gt`$Rb()*8MXby^R=Tmb~e9d2T(YUr=#ZbBW=zb`c#nl}2pP{L*$~1=6S=yVv zLl`TVadigtyv*lZb&lzy_iXE{{)%t=qxq^%V{5KjXV8I=O0n&c*6-b?^d}>N6+?Y@ z?GI_Slr<>d>O@4A=!I!<|29qFPRG0(G46B@@%{h(vlGAP@p~SB2I9{^{27Qp1Mz1d z{tU#Qf%r2Je+J^u!2gvq@OOT${VRR`N?Yye?Y6gemioINan<>2f49p1&2j(DvF_IX z#K(z$|BOEa@n<0Z48)&-_%jfH2I9{^{27Qp1Mz1d{tU#Qf%r4<-**P0{~KNUMT7pu zhi;HvyQy8PjZ5X;S8VmMmAn0Ie7EfHTq};oi>q&3^)}bI`rm1tjd3Tb=5Qzdt?%86 zWAS23ZO>w>|10HpGge&V+TPsF@!VK;R^yt(KV4_@`KQvmF@MeNzbVeG=3;w!t9G|j ze>Y>@YP`ESmK*E;$~pJ9f40uMkt)98cs~oR{8nT5o1a@|{oOLVwz|KXdgrSC{>pAA zuD^c%%Dk~+Yh!EsyQy~^aC6DZrnC@?XJzrtiQ#ua-~+MYm4hIhQBiF z>o2b2=@nOY_4BUL&D*t`>e})e!M(oKJgi=+ziXSZ z8`H{emAWz2-{PyEziYR>)m!Qv%PseJtuib3rruaKAL|oaYVEwKzxK9XOKlGR#&*lp z&h2Bd)y7}B)my4I;2#W!BHV zwlbye_*NcQEVupbUR&JTN&SuO_EWvP7RzfcZaZCDov!`Wt6VROXX|mxbZzBss&euH8QFzSx|Us*R;?d$-)`m5RpnmU;WSdAE=CvwG!? z;>I?vTW;6>+FN|9yVW>0wzZ2ZRa?b1*4FZ|rPfZV&Ce~fYq!6Z*_f7B>c&tXx6Zv* zJGZUn{q^y-bLZmk+QzXu%e$#tr)#%P*H(YKslPt4#k97T+W0n>x1XE0eX>2VyxLfq zwYNHp?=81{T=f=HsoT!V6~n!@m~NS_E$^o8wZ(DUS}d#cm$w-1+|*8ai)C%BT&dOR z+FmM)t)JSsecWs7Z*4498>{oq&)df0Ss%+=J2&+gOZBmpyM1;2cV0HH*!tRh-8tx5 zRA<-fZ`Vqdx7e1dEVh@ojW@P8uQ+ZWySA}y9B)5=d2cN1tJE9MU1Mz5Zh!B!jc?^{ ze2eGS`72YsTkc+4UrTLYEN`jJ!}{J%s=jKczQ*DyjcqK|S$ti)FDv(^{@SQa?X1qO zt#4fAZd+^jucWbU%3mpW+q&0UfHxmoSzP6+vzNbks*9~Wu73XdsLWsa?Tle##i#K* z@ISc&{?2b~W&X-F_t?t+C)X7}cKi;wJK*n(-fo#2N7u3SbIWz@&3of`^KSdt#)+%k z8}Cl?w=)-So7l$lw)5t1cTN8K-EQC5=4R#I*xr0>?cyr;7sFqf#rUVw|H-lc>9xhj zkKcj#9r(Y$1M%-+f4;~6)PCGaTPc}v}L_uA@jm0BNfYW-Ahbt-eOt<9}c zZy#^o?H^a2+fLWswwAZlZEt0kx^>=Iv9*b-j~m17?_PWRyLoRrZ{BVD-*o-IWuESy z{nK;y7vEo*JEy;LeK%wMm2u;0``YXS1Y?!|6A2tocQ#A&kp>z-P2pm=T`OJo&T%tz5V}A{+}50PGa6k-@mi| zzuU*=Y3bjM6W{Od?ts7hVP)P_BU{D%+=f1n|H_e)_L=4>#xj> z;qTh|SZZy&c`N@XQh#IlEBh;B$JRf#^0;DKA4{#R@`;jLECS*nyWJNY)M-JpfF62fYArwXt6h$!w>E3`%%v_(6# zM+bC7Cv-*^bVWCGM-TKwFZ4zq^hH1P#{dk(APmM348<@E#|VtXD2zrh#$YVQVLT>a zA|_!nreG?jVLE1DChoy3%*Gtti~Ddt9>848!-JTQhwv~S!2&#r$M86wz(PEUr|>kM z!LxV{&tnl@z>9bZFXI)wip6*hOYl0D;tjlsx9~RJ!7{vy_wYVGz;b+u75E4%@i9KZ zr&xv0uo|CZ4Zgrye2K5{HNL^O_zvr^9viR`o3I&M@IAKT2mFYiunpU>13U3EcHtNN zir=sszhe(V5Q@Fnhy6H!gE)l4ID(@%hT}MalQ@ObID@k|hx53Ai@1c#xPq$)!!=yT z4TK{Ck%&S-f&}~@&p#3(5fUQ_k|G&`kQ^zH5~+|HX^CS*nyWJNY)M-JpfF62fYArwXt6h$!< zM+uZfDU?PTltnp|M+Hw> zE3`%%v_(6#M+bC7Cv-*^bVWCGM-TKwFZ4zq^hH1P#{dk(APmM348<@E#|VtXD2zrh z#$YVQVLT>aA|_!nreG?jVLE1DChoy3%*Gtti~Ddt9>848!-JTQhwv~S!2&#r$M86w zz(PEUr|>kM!LxV{&tnl@z>9bZFXI)wip6*hOYl0D;tjlsx9~RJ!7{vy_wYVGz;b+u z75E4%@i9KZr&xv0uo|CZ4Zgrye2K5{HNL^O_zvr^9viR`o3I&M@IAKT2mFYiunpU> z13U3EcHtNNir=sszhe(V5Q@Fnhy6H!gE)l4ID(@%hT}MalQ@ObID@k|hx53Ai@1c# zxPq$)!!=yT4TK{Ck%&S-5YImXkr0WH7)g*6$q5h1|%4yvT?AD1d?}gu*C-q9}&qD1nkFh0-X4vM7i0sDO&7gvzLbs;GwQ zsDYZOh1#ftx~PZxXn=-jgvMxsrf7!dXn~e!h1O_;wrGd;=zxysgwE)KuIPsD=z*T- zh2H3czUYVk7=VEoguxhsp%{kY7=e)(h0zGc7>va@jK>5_#3W3{6imf5OvenBgW z*_eZSaUbr-1DK0>co6gP5FW-OSb#_I7#_zHScoU_6rRR2coxs$c`U*Uco8q*WxRq{ zu^6vm30}uiyn#3I7T(4?ScZ4;9^S_XSdI^|0v}-|KE@~b6szzVR^xN5!53JIFYy(= z#y9vD-(elrV*@r~6EW_9&hw8zBt#-4 zMiL}NG6W$xQXnN#AvMw@+p*HHEF6yB^8lWK>p)s1EDVm`< zTA(Fbp*7l|E!v?yI-nyup)jb+gop767T{4l zhR5*)7UD@fg{Schp2c%`9*gh-Uc^gy8L!|~EXHeCg4eMWZ{SV5g}3nzmf>BzhxhRT zmg7ULz(-h#kMRjU#VUM;)%YB1@CDZ5OMHc|@eRJkcUXt@*no}Lgw5E3@39p>;79y~ zZP<<-*omL93%}r3{D$559eWUhQ0&D%?8gBd#33BU5gf%a9LEWq#3`J{8JxvAoW})R z#3fwD6j0T_ru7>pqpieVUz5g3V47>!_z!B~vLcuc@VOu}SL!BkAcbj-j^ z+=E$|jXAg%_u+m#fVr552QeQH;bA<21$Y#X;c+~Hg?JKA;b}aBXYm}K$0EFd7x5Ba z#w&Ogi}4zk;B_p;8+a3M;cdKwWq23w;eC97<@gXQ@DWzxV|;>7u?nAIH9p50e1Wz2 z5?|qKe1mWC9oAtzHee$*VKcVidu+uI_z^#08@6KycH(F3!Y}w0zhO6i#~y?r6nn7` z`*8pVaR`TT1V?cU$8iEDaSEq#24`^&=WziSaS4}k1y>Pu0A|28r12Q5LG9wGJA{(+J2XZ18aw8A&A|LXj01BcI z3Zn>$q8N&!1WKY5N}~+Qq8!Sj0xF^sDx(Ujq8h5B25O=fYNHP7q8{p_0UDwa8lwrC zq8XZ_1zMsNTB8lxq8-|!13ID;I-?7^q8qxS2YR9xdZQ2eq96KW00v?Z24e_@Vi<;F z1V&;MMk5$wFc#x59uqJTlQ0=mFcs4<9WyW!_h1%gV-D`ceYhVFU@qq2LCnWPco>gh z0UpI;cpOh)A)drjcpA^(Sv-g5u?R2VMZAQU@d{qWV!VbWcpXde2HwP5cpL9v8Q#Tv zcpo2NIX=V+e1w(w7@y!%tioqljnAzl-{4z(hjmzw4cLfH*o-as9$WDP ze#B4MhV9sao%k8M@C$y$Z`h6Bu?Hat#a`^gejLC-9KvB7!BHH;ah$+OoWg0G!C9Qc zd0fCnT*75s!BvFe8m{98!V!T;L?Iv*&p!f@5Q&f&NstuD5QOANfs{yv)JTK0NQd;u zfQ-n5%*cYQ$cF65ft<*N+{lBx$cOwWfPyH5!YG2GD2C!Ffs!bN(kO$nD2MW>fQqPu z%BX^>sD|pOftsj=+NguNsE7J!fQD#<#%O}3Xolu!ftF~6)@XyaXovRbfR5;d&gg=! z=!Wj-fu87v-spqA=!gCofPol3~(fsq)6(Fn#EjKw&N#{^8oBuvH>OvN-z z#|+HGJ(z{rn1g$9AMVEkn2ULM5cBa69>ybBfJgBd9>)_{h$rzBp2jnH7SG{%EW!(T z5ij9oyn_G@Z zu^0QW9|v#{hj182a1_UI94BxRr*Il)a2Drq9v5&Cmv9+Za1~*=hU>V2a6}*yQ3y!Q z^N&CzL?R?c5+p@31R*(6ASF^EHPRq0(jh%EAR{s%GqNBnvLQQiASZGmH}W7a@*zJ8 zpdbpNFp8ikilI14pd?D6G|HeX%Aq_epdu=vGOC~|s-Ze+peAaeHtL`*>Y+XwpdlKe zF`A$$nxQ#bpe0(NHQJyp+MzuM(r|}G)#dCNbi|_(o#7lS?ui#ZI#%oxD*Rd3D;7z=RxA6{^ z;a$9k_wfOi<3p^#M_7rE@d-Y~Dtw03_#A8S1=iwAe1)&^4Zg*9Scmo4fQ{IM&DetP zu@yhyNBo3s*p408iJ!3xzu;H=hTZrbdk}(9?8QFp#{nF~AsogL9K|sl#|fOoDV)X` zoW(hu#|2!(C0xc8TtyhJ;W}<091(~_6av!l{38$vkqC*A1WAz$K}e1iNQqQPjWkG$ zbV!d3$cRkHj4a5CY{-rr$cbFYjXcPUe8`UiD2PHRj3OwCVknLhD2Y-ijWQ^Uawv}q zsEA6aj4G&#YN(DHsEJyrjXJ1{dZ>>EXoyB=j3#J`W@wHUXo*&6jW%eDc4&_d=!j0} zj4tSkZs?94=!stFjXvm$e&~+@7>Gd_j3F3`VHl1P7>Q9BjbMzySd7DXOu$4;!emUr zR7}Hk%)m_CgISo3Ik*@1;eI@TxtNCsF&_`%VLXBbcodJ}aXf*AcoI+HX*`2x@f@DV zBD{bX@e*FfD|i))@fw!kbu7gjcoT2oZM=hJco*;CeSCoB_z)}b5mw@3e1cE03ZG#$ zKF1n-fwlM&U*T(fgKzO2)?qz1U?VnRGq&J+Y{d`w5kFxYwqpl&;%Dr_FZdO|VK;uq z9)utid$AAuaR3K#2#0Y5M{x|taRMiC3a4=fXK@baaRC=`372sNR}qG5xQ-hLM+71f zg@Cj?{|H1vBtl{&K~f|`5RxMWQX&;nBMs6b9nvEMG9nW)BMY)38?qw@av~RUBM$k7>c6=N}?1>qYTQT9Ll2tDxwl9qYA2`8mglPYN8fuqYmn#9_ph3 z8ln*zqY0X#8JeR7TA~$NqYc`k9onM0U$4(`Q$xE~K-F6QAu z%*R7`7>{599>rsL98X{&p2Sml8qeTaJcsA82ruA8yo8tW3SPxxyoM!s9ZT^B-o#sY z8}DEl-o<-(A0J>jKEw)qgq8RhpWsuh!e>~G&#?wyU@gAHSNIy=;9Go$by$xL*oaNo zj4k*cTk!*a#823U?bv~x_!+zK3x36K*p1(@2O$W>UhKnu9Kb;w!eJc2Q5?f@oWMz( z!fBkrS)9XpT);(K!ev~+RfORhuHy#65rIfVAs`*kKLU{uiI5mckQB)fgycwplt_it zNQ1OUhxEvRjL3w{$bziMhV00JoXCaT$b-Ddhx{mjf+&Q-D1xFWhT4JD1)*n zhw`X^il~IjsDi4fhU%z+ny7`^sDrwwhx%xMhG>MwXo99_hURF2mS~06XoI$BhxX`z zj_8EW=z^~3hVJNrp6G?%=!3rKhyECVff$6r7=ob~hT#~2kr;*12*wzU#W;+|1Wd#v zOvV&U#WYOE49vtmn1$JxgL`ow?#Ba|i+Oku^YIWK#v@pONAVaQ#}inHC-D@X#xr;p z&*6D2!V7p2FX3gpf>*H^uVD#Z$5On3H}MwU#yePsckv$H#|K!B53vFtVI@AsC-@Yr z@EKO)bF9G^Sc@<56~4wd_!i$`9oAz5HewStV++2=R{Ve;@e{UTJ9c0ve#S2Rf?x3) zcH?*KK?p*z7yGau2XGLFa2Q8$6vuEJCvXy{a2jWD7Uyst7jO}ma2Z!{6=ArB>$rh% zL?9AT2uRQKk3b|uA|yrYy&_ zp*|X*AsV4EnxH9~p*dQhC0e01+Mq4kp*=dFBRZiox}Yn%p*wn@Cwieb`k*iRp+5#- zAO>MDhF~a$VK_!$Bt~I0f-weTF%IJ~0TVF^lQ9KTF%8o(12b_CW??qw;9lH^`|$wg zVjdpEd_07Q@dy^+Q9Opn@dOs)Nj!z8@eH2Db9f$$@B&`MOL!Tt;8iTfYgmHUu@rCM zO}vG-@eY>ZUA%|)@d1|OL#)6@Sc#AE2|mRte1_Hd9Bc3e*5XTig|G1qzQuP~hxOQi zjo5_E*n;n|6+hrd{Df`Tjvd&EpRo(S;8*;H-S{1Q5Q0$b#XjuE0UX339L5nG#W5Vm z37o_!oW>cP#W|eE1zf}>T*eh#MHsH(I&L5w5r{+-0y6OYBM=FZ2#JvdNs$aeNRAXp ziBw39G)RkdNRJH2h)l?gEXay%$c`MyiCoByJjjcD$d3Xjh(aigA}EStD2@^+iBc$y zGAN63D31!Lh)Sr8DyWKTsE!(_iCU6PCTNOgXpR zXpau)h)(E?F6fGG=#C!fiC*Z9KIn^n=#K#yh(Q>PAsC8b7>*GbiBTAhV2r_7jKg?L zz(h>KWK6+SOv7}{z)akOS(uGExEJ@~emsD=n1=^39}nSSJc0#y6p!I?Jb{IH5>Mf2 zJcDQP9G=G_ynq++5?;nDcomEB8kXR7EX5mm6K~;dyn|(U7w_SHe1PTn5G(KzR^nrP zf={supJ6pV#~OTrwfGWW;cI+@Z}A=0VLdirBQ{|(w%~hg#Si!qKVciTV+VHPXY9f+ z_!YllH-5(+gdh}qu@C!k00(ghhj9c)aSX?C0w-|_r*Q^naSrEk0T*!zmvIGG5r%8H zjvEL^1R@cIfQ&r<2t-08LSiIAQY1qVk|PCDA{A024bmbV(jx;hA`>zr3$h{`vLgp_ zA{TNa5Aq@(@}mF>q7VwB2#TT@ilYQdq7+J_49cP$%A*1*q7o{j3aX+Ss-p&Kq84hS z4(g&F>Z1V~q7fRS37VoAnxh3;q7_=B4cej|+M@$Hq7yo!3%a5kx}yhrq8ECj5Bj1X z`eOhFVh{#n2!>)9hGPUqViZOr7-KLN<1ii*FcFh58B;J7(=Z(~FcbG+7G`4(?!|q$ z9}i$I=HWri$3u7+k6-~F#bbCJPhcUQ#8Y@0&)``+hv%^fFW^PIgqQIOUd3X(h9!6% zOYsKY#9Me9?_e3;#d~-kA7D8?#0q?bmG~H+;8U!^XIPETu?AmYExyE8_!{5fTYQIg zSdR_Zh)vjxE%+W=@dJLuPuPa-*nyq+8N2Wce#LLtjo+~cAqd4@?8AN>z(E|sVI09x z9K&&(z)76KX`I1XoWprsz(ribWn95kgy9;l;|9VJfk;FlAQR6&0+A4jkQhmj6v+^T zf~u&7>ZpO5sD;|7gSx1P`e=ZLXoSXSf~IJO=4gSIXoc2j zgSKdg_UM3)=!DMbg0AR>?&yJ@=!M?sgTCm8{uqFP7=*zXf}t3O;TVCD7=_UY#u$vn zIE=>xOvEHi#uQA&G)%_~%)~vIh1r;cdvPD`#{-y)d3X@>@em%yBUpe(@faS*6Ih5R z@f4oMGk6xy;dv~=3wRMP;bpvnSFsqcVF_NxQoMmT@fP03J6MKy@gCmC2Uv~|u>v1q zB|gR{_!O(~8CK(Sticypi!bpNzQ#BB7T;kV)?))UViPuF3%xd z#xDGVU-27u<9F;q2tu(J`>-Dea1e)Z7)Njv$8a1ca1y6*8fS18=Wreua1obq8CP%> zVYr6txPfp)AQDjs;D1*k0RoW_iI5mckQB)fgycwplt_itNQ1OUhxEvRjL3w{$bziM zhV00JoXCaT$b-Ddhx{mjf+&Q-D1xFWhT4JD1)*nhw`X^il~IjsDi4fhU%z+ zny7`^sDrwwhx%xMhG>MwXo99_hURF2mS~06XoI$BhxX`zj_8EW=z^~3hVJNrp6G?% z=!3rKhyECVff$6r7=ob~hT#~2kr;*12*wzU#W;+|1Wd#vOvV&U#WYOE49vtmn1$Jx zgL`ow?#Ba|i+Oku^YIWK#v@pONAVaQ#}inHC-D@X#xr;p&*6D2!V7p2FX3gpf>*H^ zuVD#Z$5On3H}MwU#yePsckv$H#|K!B53vFtVI@AsC-@Yr@EKO)bF9G^Sc@<56~4wd z_!i$`9oAz5HewStV++2=R{Ve;@e{UTJ9c0ve#S2Rf?x3)cH?*KK?p*z7yGau2XGLF za2Q8$6vuEJCvXy{a2jWD7Uyst7jO}ma2Z!{6=ArB>$rh%L?9AT2*|?ok3b|uA|yr< zBtYy&_p*|X*AsV4EnxH9~p*dQh zC0e01+Mq4kp*=dFBRZiox}Yn%p*wn@Cwieb`k*iRp+5#-AO>MDhF~a$VK_!$Bt~I0 zf-weTF%IJ~0TVF^lQ9KTF%8o(12b_CW??qw;9lH^`|$wgVjdpEd_07Q@dy^+Q9Opn z@dOs)Nj!z8@eH2Db9f$$@B&`MOL!Tt;8iTfYgmHUu@rCMO}vG-@eY>ZUA%|)@d1|O zL#)6@Sc#AE2|mRte1_Hd9Bc3e*5XTig|G1qzQuP~hxOQijo5_E*n;n|6+hrd{Df`T zjvd&EpRo(S;8*;H-S{1Q5Q0$b#XjuE0UX339L5nG#W5Vm37o_!oW>cP#W|eE1zf}> zT*eh#MHsH(I&L5w5r{+-06PCTNOgXpRXpau)h)(E?F6fGG=#C!f ziC*Z9KIn^n=#K#yh(Q>PAsC8b7>*GbiBTAhV2r_7jKg?Lz(h>KWK6+SOv7}{z)akO zS(uGExEJ@~emsD=n1=^39}nSSJc0#y6p!I?Jb{IH5>Mf2JcDQP9G=G_ynq++5?;nD zcomEB8kXR7EX5mm6K~;dyn|(U7w_SHe1PTn5G(KzR^nrPf={supJ6pV#~OTrwfGWW z;cI+@Z}A=0VLdirBQ{|(w%~hg#Si!qKVciTV+VHPXY9f+_!YllH-5(+gdh}qu@C!k z00(ghhj9c)aSX?C0w-|_r*Q^naSrEk0T*!zmvIGG5r%8HjvEL^1R@cIfNVVf2t-08 zLSiIAQY1qVk|PCDA{A024bmbV(jx;hA`>zr3$h{`vLgp_A{TNa5Aq@(@}mF>q7VwB z2#TT@ilYQdq7+J_49cP$%A*1*q7o{j3aX+Ss-p&Kq84hS4(g&F>Z1V~q7fRS37VoA znxh3;q7_=B4cej|+M@$Hq7yo!3%a5kx}yhrq8ECj5Bj1X`eOhFVh{#n2!>)9hGPUq zViZOr7-KLN<1ii*FcFh58B;J7(=Z(~FcbG+7G`4(?!|q$9}i$I=HWri$3u7+k6-~F z#bbCJPhcUQ#8Y@0&)``+hv%^fFW^PIgqQIOUd3X(h9!6%OYsKY#9Me9?_e3;#d~-k zA7D8?#0q?bmG~H+;8U!^XIPETu?AmYExyE8_!{5fTYQIgSdR_Zh)vjxE%+W=@dJLu zPuPa-*nyq+8N2Wce#LLtjo+~cAqd4@?8AN>z(E|sVI09x9K&&(z)76KX`I1XoWprs zz(ribWn95kgy9;l;|9VJfk;FlAUn@L0+A4jkQhmj6v+^T zf~u&7>ZpO5sD;|7gSx1P`e=ZLXoSXSf~IJO=4gSIXoc2jgSKdg_UM3)=!DMbg0AR> z?&yJ@=!M?sgTCm8{uqFP7=*zXf}t3O;TVCD7=_UY#u$vnIE=>xOvEHi#uQA&G)%_~ z%)~vIh1r;cdvPD`#{-y)d3X@>@em%yBUpe(@faS*6Ih5R@f4oMGk6xy;dv~=3wRMP z;bpvnSFsqcVF_NxQoMmT@fP03J6MKy@gCmC2Uv~|u>v1qB|gR{_!O(~8CK(Sticyp zi!bpNzQ#BB7T;kV)?))UViPuF3%xd#xDGVU-27u<9F;q2tu(J z`>-Dea1e)Z7)Njv$8a1ca1y6*8fS18=Wreua1obq8CP%>VYr6txPfp)AQDjs$iefE zKqN#WBt{Y>MKS~-IZ_}cQXw_cAT81%Ju)C8G9fdvAS<#VJ8~c=av?YJATRPEKMJ5A z3ZXEHpeTx=I7*--N})8$pe)LvJSw0fDxor}pem}NI%=RMYN0mjpf2j6J{q7Q8lf?o zpedT6Ia;74TA?-Cpe@>=JvyKxI-xVVpewqeJ9?ledZ9P^pfCENKL%hR24OIUU?_%R zI7VP3MqxC9F$QBX4&yNa6EO*sF$GgG4bw3LGyflV_XFkSv^IRaBngS6l9VJ#5=kYL zBuR**l9VJ#5@8xiNs=UyB*~B@Ng^3ZB1w`&k|aZtB#9&=)x6(t?(01FJ8yM3&pFS# z)-!8;&iwXo|GW0J_kG{LnaMini+;Er{c#5d;7$z0T^NMBF&Ot?2=2vD+=pSf9}i$S z9>fSdgpqg{qwoku<57&kW5~kecmiYbB*x(>jK|ZMfM+lf&teju!(=>`F6>vBz;s{j2k*JKLPz6V$Dvm)l9E<8W4mEH*PC!kZh*~%awNVFk zaWd-R6r76FP#+C&IvU~(G{Tu^jI+=LXQL_3K{K3-^Kd?z;{sfW7Pts4aWPt;w}ur-588}Fa-BvDDJ~B+>Zw^91mgy9>PdGj8S+5qwy%l z;4x(3aXf*scoO6A6vpFeOu#dkh-Wbg&tWp2#}vGP7cmttVH#dWHeSJWyowok4KwjN zX5kIIiP?AybMQ9i;vLMxyO@vnumJC4AwIw&e29;*7$0K^KEYCaie>l=%keo@;0xs7 zOMHcu_!_J54OZh@tig9!i|?@xKVUt6#0LC?pRp0YU=x1DX8eX+{EjX716#2T+mVL? zhjIO54-~?lD2%;O1bd?>_QAf`55=%QisJwrh!QvmC2=rHp)|_i5R}ECD2KyP9u;sn zD&h!K!jY(qqfiA$qbiO;H5`lTI1V*%JWfDOoQPUD3AIrNb#XH4;S`*T(@-A`a5@^| z3^c--XpFPa1ZSfu&OtMri}P?kn&Sdoh!(gAEpahgp*7mz612soXot(t9vyHwI^qg+ z!jZXZ0|Rg; z2I4LZ!rd5*doTp|VkqvzFx-y^FdPqJ1RlajJd9Cz1f%gN#^5nz;c+~Hv3L^W@D#@5 zX-vQ~n22XF3D03Np2rltfEO_pFJT&9MmAo-bi9fgcnvf0I%eSwyouR(3v=)`=Hea9 z!@HP|_pku(V2|mG6e2QiG49oF3R^SWd;7fdkmG~N~@C{buTdcu% zSc~tm4nJT$e#8d+grBhyzhD!7#b*45T>OqL_yb$94cn220_C~>u?GraPZY*pD1yCF z6#HOb?1y65AH{J14nzqYgpxQIrBE7Wa0trcP?W=AD31y_92Ic{D&a^}#!;w(qfr&d zpc;-vbsUEpI36dUCQd{xoP^q_gSt2w^>7MK#c8OI1~?rJaRwUUOf<$>Xo9oR6z8BB z&c%5+AI)(AE<_7lgqFA%t_xBDL%zAe1_%t94qhza_}X-!b*INRrm(0@h#TiJFLa`Scf059zS9Oe!|b# zh+nV?zhX0fLoR;D7W{#&*oN)MLxBoh|JVbCuqO&*FBHMvD2jcsFZM$*?2qC&00*K3 z4nj#Bj8Z6#GB^ZfaVW~+FqB6H9FB@O0+nziD&r_r!O^ISV^9spqB@R44IGaXP!lJj z7EVHK)InXGjCwc)r{Xl!M+2OWhByO_a3&h#EHuH{Xo_>t4CmrJoR8+X02iVKE<#IO zj83xjYs2IC$K!MzxY`!Edm;{goEgBXE_FcJ@A z6du87Jc==R3|V*_Phc#b#5g>K@pu{&@C+v6Sxmxnn2hH!1ux)5OvOu>hL@3zS1=u~ zVg_ErOuUX+cmr=@Hr~Psbug|H_IV=olJ-YANFurKyQG3<}xH~$D%rpLk%2{6HpT;q83g=KZb5I{iaxjvebEoM zqd)Gz0NjazxC?`DHwNP#48gq^iu*7O_u~N!$AcJwhcFTkV-z02XgrEBcnn#198X{@ zp2Rpjh4FYA6YvZs;#o|>bC`_hF$FK+MNGv@n1+{;jaM)ouVMyX!%V!6S$G3)Vm98w z9K4OWcn9ZHKPp}l9Vi`Wea(s>z_yRfj5?^5@zQ!ti zgVp#JYw#V`;(M&a4_J>Mu>n8fXKchT*o0rP8NVSHzhevjz*cO-cI2TzMXrDBfkN05 zg|QckU~d$~KG+xgp&0f@aU6gHQ33~{Bo0O?ltvjGg0eUi1>0oPtwv8tS6~PDewWfkrqJjd2#5 z;A}L-IcSD+aURY`b6kK6(E=BtB`!uQv_>0Tg0{F6?Qj{|qXRBSM_hqUxDuUl6}sSR zbj3C3hHKFs*P#cl#|`L-8*vkEMh1Ez6Str@Zbcv5hQ8>B+tD9)U;ysKK-`5vxEq6U z4~F1g48?sIhWqgVhT}nuz(W{`hcOC|U^E`Z7(9k7JdP(Y7EfXvp2B!MjR|-L6Y(r2 z;WoH!&M;VGiELT)cyMco*~W9v0wz zEW`&`gb(o%7UN?q!6#UXPq7T2VL3j>3VeYae2K5H5?^B#zQJmIi#7NTYw*o@zhi{G&Ye_$)NVLS4`gSS9I?14hq6NRxCiePUP#Xi^<`=J>2 zM{yj015pA8p(GAQDU?PT9D=eq6yie8i4#!^C!sd#pe{~EJ)DA5aT@BQ0ZvCloPkC-6OC~en&50S#W`q(b8#NdM{`_& z3(*1>p(QRxE3`%%T!OZ^6zy;s+M@$5M@L+NPPh`CaTU7YYIMal=!R?29oL};uE!1N zi5qbfZbk-rArrTtH*Q5A+=jmBhuhH~cVGbS#6aAILAV=(aSw*zUJS*37>4`t0EXj1 zjKD(}iH9)?k6<(&#TYz>EIf`UFcwc@9G=2>JdFu>1{3itCgC|u#`Bnh7w{sc;w4PO z%gDwnn2uL51FvBwUdJrFfj2Q5Z($DJ#$3FEd3YD|@g5f7eJsQWScDJp5fs4r}o}*5L=N$B)>6pYSs_;umbfuh@*= zkc;231%F^GwqZN+z=!Sv1+fPTVNVpsUMPaSQ55@NU+jls*dN7l01iY69E6fM7^P4e zWpD_};!u>sVJMFZI2;vm1S;W3RK`)Lf}>Ft$DkUHMRgp98aN&&pe9a4Eu4hfsDrvV z8TD`qPQ_`cj|Mm$4RHn<;Y>8fS!jZ@(G=&P8P3IdI3LY%0WL%fT!fam7_HD6ZEy+N z;!?E3WoVBMxEvjE1v=qMbjDTaf~(OL*Pt7&MR#0>9=IMipeJs`O}H5u=!Hz&g5J0l zeQ+E4q91NYf82oqxDx|$7Y5;O48}bef_pI(_hA_B#{(FS2QdN2m4|_6vO@~jstKYO5h-r#K91c>E z&a4ovyI`qKxxB)$JBW}XY$UrY-;uiGAt>}Z>&=>u1JNn}e48WZj zh`TTdcVjT_!4TYwp|}sja6cZva6E_+cnBl$Fh=1KjK-rFgU67C$MFQl;z^9dQy7n@ zF#*qDBA&%0Jcr469#ilFUc^+qglTvg*?0xh@hWEEHO$28n1wg+CT8O;%)#53i+3;& z?_xgQ!vegIh4=uA@F70JVtkAx_ykMwDVE_gEXU_qfiIAQFYy&t;%ltJH&~5tu?F8^ zExyM({DAfN5gYIme#S=pf=&1poADcR@jJHQ4{XIYY)2mWWm|!Q*aL;ICkkUP6v5so zihZyz_Cqo3kK#B02ciTHLP;EqQYeiwI0R*JD9Yh5lt%>|j*2(}m2e~~<0w?Y(Wr`J zPz}eTI*vmP9FG%F6DOh;PC{+eL0z1TdN>8A;xyDp1DuYAI0KDvCK}@`G{MO<0^E))#!?A&<)q3 zJFY_yT#p;j6F1@}+>8wLLMCoOZ`_JLxD9>L54WQ~?!W-tiGjEagK#$n;~osby%>u7 zFbwzO0Sw237=ec{5)We(9>HiliZOT$S$G^zU@V@*I6Q^%cp4M%3?|}POu}=RjOQ^0 zFW^N?#Y>ommywNEFdeUA242HVypCCT18-tB-ohNbjk$OS^YAX_<2@|E`&ft%um~UG zBP_#7Kfr74nuiVz~QKfBTxxPqB4#`6&#JKI0n^lEUM!;)WGpL0X11`@dU==NsPl&7>}nh0ncC}p2Z|Qhsk&zQ}6;_#8kY5X?Pjgcm>n( zDrVp{%*5-Mg*WgfX5%f)!P}UNcQ6m{Vm{u(0=$of_yCLWAwI%le2gXd1WWNLmftP52d?@f&jSJGS5t zY{fQgM;`biTY-Yu1BI|B3S%!6!QLo}eXuX~Low`+;y3^Yq67{?NgRw)D2*~W1Z8n3 z%Hc4SM+F>?iZ}w5a3m_@C{)4GsET7y4acH7jzbL`j}uT6C!!WkLT%JRU7U=1I0dKT zG}K1}oQ{S#1C4Md8sjW9!P#hvbI=Uu;yj#>=C}YCq6IEOOI(arXpJ_w1Z{CC+Tk*^ zM+aPvj<^Dya3wn9Ds;is=!$F54cDSOu0s!8j~mbvH{vGTj12TbCT>A*+=@Q94SmrM zx1&GqzyREdfw&8Ua5o0y9t^>~7>fHa4EN&!499~Qfrl^>4`UP_!Du{+F?bAFcpOh) zES|(TJcaRi8WZpgCgNF4!gH96=P?B@;6+TuOPGe2k&Ra{9j{^rUc*ehj#+pEZ(=sy z!W_Jfxp)Wj@Gj=#JuJZcScng>2p{4jEXK!Jf={p%pJEw4!*YC%75D-<_!3`XCBDWg ze1p~a7HjYw*5Z4t!w*=GAF%;H;b&~bFW7`%u^GQ17r$c*{=imj!*=9>Kd=`lh&@mU zd!jJ*LJ{nZqSy!fVm}na{wR(Ea3D(HAe6+xD237}gF{djhoT$~LwQud;i!lsPzgt( zGLAwO9F3|t2GwvZs^d7+!0|W%HE|+p;Uv^X9n{6isE1QgrZ@-9a4ycn`Dl&{a3NaYBDBQCXoc2jgG-hj&hKofwF_FbH>J zFz&$++>4>O55sUj9>8!sh!J=QBk?ds;Sr3+qZot7kcG$b1jgb?jKfnHkEbyK&tM{+ z#Uwn3$#@=9@B&`MRJ?>~cp2Gv1=H~=X5cl<#Os)aH}EEA<1Ng=+n9@YFc0ryKHkFu zypM(W0E_S;KEh&rj3xL4OYtd|;WI49=U9O+kb^Jr6;|SFtim@~jc>6A-(fAj$2$Cg z_4pAR@DqN`F6>vBz;s{j2k*JKLPz6V$Dvm)l9E<8W z4mEH*PC!kZh*~%awNVFkaWd-R6r76FP#+C&IvU~(G{Tu^jI+=LXQL_3K{K3-^Kd?z z;{sfW7Pts4aWPt;w}ur-588}Fa-BvDDJ~B+>Zw^ z91mgy9>PdGj8S+5qwy%l;4x(3aXf*scoO6A6vpFeOu#dkh-Wbg&tWp2#}vGP7cmtt zVH#dWHeSJ-Cv$z{EzH5&n2UEX5AR|=-opaCkA?UEi|`>n!eV@kCHMqO@hO(!Gc3pF zSb;B)gD>$FR^n@{!Z%orZ?Oj7VJ*JLI{bk3_z@fM6Mn`<{DMvR6`S!Ja`8L1;16uY zHf%>8_=j%=3Stiw!k#FMy-);uqbT;lzSs}Nus@39033)CI0z+iFiN2`%HR-`#i1yN z!%!X-a5yUB2vow6sEngf1xKSQjzKjXi|RNIHE=vmKuw&8S~v-{Q3rK#GV0+JoQl&> z9}RFi8sZEz!kK7{v(N-*qbbfoGn|X_a6X#j0$hj|xCkwAFs)`1ovVn?!z$Lj|VUu4`Ku!!bm)fQFsKS@hHaNF=XL!Jb|%z z665d`#^Y&Bz%!VLXE6!SVKSb_6uf{JF%>Ui8eT>=Ucq#{iWztfGx0iR;SIcr*?0?c z@HXb+9n8bKn2-0c0PkZVKENV;h>x%sA7cqV!BTvRW%vxs@i|uD3*_KSe1(kq7?KYk`8;1BI|B z3S%!6!QLo}eXuX~Low`+;y3^Yq67{?NgRw)D2*~W1Z8n3%Hc4SM+F>?iZ}w5a3m_@ zC{)4GsET7y4acH7jzbL`j}uT6C!!WkLT%JRU7U=1I0dKTG}K1}oQ{S#1C4Md8sjW9 z!P#hvbI=Uu;yj#>=C}YCq6IEOOI(arXpJ_w1Z{CC+Tk*^M+aPvj<^Dya3wn9Ds;is z=!$F54cDSOu0s!8j~mbvH{vGTj12TbCT>A*+=@Q94SmrMx1&GqzyREdfw&8Ua5o0y z9t^>~7>fHa4EN&!499~Qfrl^>4`UP_!Du{+F?bAFcpOh)ES|(TJcaRi8WZpgCgNF4 z!gH96=P?B@;6+TuOPGe2k&Ra{9j{^rUc*ehj#+pEZ(=sy!W_Jfxp)Wj@Gj=#JuJZc zScng>2p{4jEXK!Jf={p%pJEw4!*YC%75D-<_!3`XCBDWge1p~a7HjYw*5Z4t!w*=G zAF%;H;b&~bFW7`%u^GQ17r$c*{=imj!*=9>fAC(QAof5Z?1{qI3q`Ouieew^i~Udx z`=dAxz=0@%gHRF&qZCS`3=TnA9Ex%{4CPS)hod5nKqVZB$~X#Da5Spo7*xZtsE*@M z1IOb8)WnIXg_BSlbx;>4qaIGdsW=Vw(Ez8TAOd+4{k$W^uz7wk2^2`cVZy!!XVs@!MF!Qa4&}9J`BVCcmTuk zAV%OJjKsqjg-0+Nk75iSLlz##6BvspF%C~*Jf6k`JcEgN7L)KCCgXWb!3%g1Q}Gg} z;bmmw6->vgn1R72B{KdEh^GDNqo5pb+*%VeEw>*c(N$5B9}=D2Dw}90%Y)l)ynKiGxuJ zrBMclpeznWIUI)asDQ&!5l5gBjznb~g(^52RdEce;aF71aj1dgaRO@MMAX7bsEs

!3U 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 literal 0 HcmV?d00001 diff --git a/examples/i256/openvm/app.vmexe b/examples/i256/openvm/app.vmexe new file mode 100644 index 0000000000000000000000000000000000000000..e45a699ef3ebae8e2f5d367a93ed1386d6e8b48f GIT binary patch literal 259692 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 { // 32 limbs prime - SwEcAddNeRv32_32(EcAddNeChip), - SwEcDoubleRv32_32(EcDoubleChip), + SwEcAddNeRv32_32(SwAddNeChip), + SwEcDoubleRv32_32(SwDoubleChip), // 48 limbs prime - SwEcAddNeRv32_48(EcAddNeChip), - SwEcDoubleRv32_48(EcDoubleChip), + SwEcAddNeRv32_48(SwAddNeChip), + SwEcDoubleRv32_48(SwDoubleChip), // 32 limbs prime - TeEcAddRv32_32(TeEcAddChip), + TeEcAddRv32_32(TeAddChip), // 48 limbs prime - TeEcAddRv32_48(TeEcAddChip), + TeEcAddRv32_48(TeAddChip), } #[derive(ChipUsageGetter, Chip, AnyEnum, From, BytesStateful)] @@ -170,7 +171,7 @@ impl VmExtension for EccExtension { if bytes <= 32 { match curve.coeffs.clone() { CurveCoeffs::SwCurve(SwCurveConfig { a, b: _ }) => { - let sw_add_ne_chip = EcAddNeChip::new( + let sw_add_ne_chip = SwAddNeChip::new( Rv32VecHeapAdapterChip::::new( execution_bus, program_bus, @@ -189,7 +190,7 @@ impl VmExtension for EccExtension { .clone() .map(|x| VmOpcode::from_usize(x + sw_start_offset)), )?; - let sw_double_chip = EcDoubleChip::new( + let sw_double_chip = SwDoubleChip::new( Rv32VecHeapAdapterChip::::new( execution_bus, program_bus, @@ -212,7 +213,7 @@ impl VmExtension for EccExtension { } CurveCoeffs::TeCurve(TeCurveConfig { a, d }) => { - let te_add_chip = TeEcAddChip::new( + let te_add_chip = TeAddChip::new( Rv32VecHeapAdapterChip::::new( execution_bus, program_bus, @@ -238,7 +239,7 @@ impl VmExtension for EccExtension { } else if bytes <= 48 { match curve.coeffs.clone() { CurveCoeffs::SwCurve(SwCurveConfig { a, b: _ }) => { - let sw_add_ne_chip = EcAddNeChip::new( + let sw_add_ne_chip = SwAddNeChip::new( Rv32VecHeapAdapterChip::::new( execution_bus, program_bus, @@ -257,7 +258,7 @@ impl VmExtension for EccExtension { .clone() .map(|x| VmOpcode::from_usize(x + sw_start_offset)), )?; - let sw_double_chip = EcDoubleChip::new( + let sw_double_chip = SwDoubleChip::new( Rv32VecHeapAdapterChip::::new( execution_bus, program_bus, @@ -280,7 +281,7 @@ impl VmExtension for EccExtension { } CurveCoeffs::TeCurve(TeCurveConfig { a, d }) => { - let te_add_chip = TeEcAddChip::new( + let te_add_chip = TeAddChip::new( Rv32VecHeapAdapterChip::::new( execution_bus, program_bus, diff --git a/extensions/ecc/circuit/src/edwards_chip/mod.rs b/extensions/ecc/circuit/src/edwards_chip/mod.rs index f7c3286dab..9e7430e0f8 100644 --- a/extensions/ecc/circuit/src/edwards_chip/mod.rs +++ b/extensions/ecc/circuit/src/edwards_chip/mod.rs @@ -1,11 +1,14 @@ mod add; pub use add::*; +mod utils; + #[cfg(test)] mod tests; use std::sync::{Arc, Mutex}; +use num_bigint::BigUint; use openvm_circuit::{arch::VmChipWrapper, system::memory::OfflineMemory}; use openvm_circuit_derive::InstructionExecutor; use openvm_circuit_primitives::var_range::SharedVariableRangeCheckerChip; @@ -14,13 +17,14 @@ use openvm_ecc_transpiler::Rv32EdwardsOpcode; use openvm_mod_circuit_builder::{ExprBuilderConfig, FieldExpressionCoreChip}; use openvm_rv32_adapters::Rv32VecHeapAdapterChip; use openvm_stark_backend::p3_field::PrimeField32; +use utils::jacobi; /// BLOCK_SIZE: how many cells do we read at a time, must be a power of 2. /// BLOCKS: how many blocks do we need to represent one input or output /// For example, for bls12_381, BLOCK_SIZE = 16, each element has 3 blocks and with two elements per input AffinePoint, BLOCKS = 6. /// For secp256k1, BLOCK_SIZE = 32, BLOCKS = 2. #[derive(Chip, ChipUsageGetter, InstructionExecutor, BytesStateful)] -pub struct TeEcAddChip( +pub struct TeAddChip( VmChipWrapper< F, Rv32VecHeapAdapterChip, @@ -28,36 +32,21 @@ pub struct TeEcAddChip, ); -// converts from num_bigint::BigUint to num_bigint_dig::BigInt in order to use num_bigint_dig::algorithms::jacobi -fn num_bigint_to_num_bigint_dig(x: &num_bigint::BigUint) -> num_bigint_dig::BigInt { - num_bigint_dig::BigInt::from_bytes_le(num_bigint_dig::Sign::Plus, &x.to_bytes_le()) -} - impl - TeEcAddChip + TeAddChip { pub fn new( adapter: Rv32VecHeapAdapterChip, config: ExprBuilderConfig, offset: usize, - a: num_bigint::BigUint, - d: num_bigint::BigUint, + a: BigUint, + d: BigUint, range_checker: SharedVariableRangeCheckerChip, offline_memory: Arc>>, ) -> Self { // Ensure that the addition operation is complete - assert!( - num_bigint_dig::algorithms::jacobi( - &num_bigint_to_num_bigint_dig(&a), - &num_bigint_to_num_bigint_dig(&config.modulus) - ) == 1 - ); - assert!( - num_bigint_dig::algorithms::jacobi( - &num_bigint_to_num_bigint_dig(&d), - &num_bigint_to_num_bigint_dig(&config.modulus) - ) == -1 - ); + assert!(jacobi(&a.clone().into(), &config.modulus.clone().into()) == 1); + assert!(jacobi(&d.clone().into(), &config.modulus.clone().into()) == -1); let expr = ec_add_expr(config, range_checker.bus(), a, d); let core = FieldExpressionCoreChip::new( diff --git a/extensions/ecc/circuit/src/edwards_chip/tests.rs b/extensions/ecc/circuit/src/edwards_chip/tests.rs index c492b38c1d..a13438013b 100644 --- a/extensions/ecc/circuit/src/edwards_chip/tests.rs +++ b/extensions/ecc/circuit/src/edwards_chip/tests.rs @@ -14,7 +14,7 @@ use openvm_rv32_adapters::{rv32_write_heap_default, Rv32VecHeapAdapterChip}; use openvm_stark_backend::p3_field::FieldAlgebra; use openvm_stark_sdk::p3_baby_bear::BabyBear; -use super::TeEcAddChip; +use super::TeAddChip; const NUM_LIMBS: usize = 32; const LIMB_BITS: usize = 8; @@ -118,7 +118,7 @@ fn test_add() { tester.address_bits(), bitwise_chip.clone(), ); - let mut chip = TeEcAddChip::new( + let mut chip = TeAddChip::new( adapter, config, Rv32EdwardsOpcode::CLASS_OFFSET, diff --git a/extensions/ecc/circuit/src/edwards_chip/utils.rs b/extensions/ecc/circuit/src/edwards_chip/utils.rs new file mode 100644 index 0000000000..ce7711519f --- /dev/null +++ b/extensions/ecc/circuit/src/edwards_chip/utils.rs @@ -0,0 +1,101 @@ +use num_bigint::BigInt; +use num_integer::Integer; +use num_traits::{sign::Signed, One, Zero}; + +/// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0. +/// The y argument must be an odd integer. +pub fn jacobi(x: &BigInt, y: &BigInt) -> isize { + if !y.is_odd() { + panic!( + "invalid arguments, y must be an odd integer,but got {:?}", + y + ); + } + + let mut a = x.clone(); + let mut b = y.clone(); + let mut j = 1; + + if b.is_negative() { + if a.is_negative() { + j = -1; + } + b = -b; + } + + loop { + if b.is_one() { + return j; + } + if a.is_zero() { + return 0; + } + + a = a.mod_floor(&b); + if a.is_zero() { + return 0; + } + + // a > 0 + + // handle factors of 2 in a + let s = a.trailing_zeros().unwrap(); + if s & 1 != 0 { + //let bmod8 = b.get_limb(0) & 7; + let bmod8 = mod_2_to_the_k(&b, 3); + if bmod8 == BigInt::from(3) || bmod8 == BigInt::from(5) { + j = -j; + } + } + + let c = &a >> s; // a = 2^s*c + + // swap numerator and denominator + if mod_2_to_the_k(&b, 2) == BigInt::from(3) && mod_2_to_the_k(&c, 2) == BigInt::from(3) { + j = -j + } + + a = b; + b = c; + } +} + +fn mod_2_to_the_k(x: &BigInt, k: u32) -> BigInt { + x & BigInt::from(2u32.pow(k) - 1) +} +#[cfg(test)] +mod tests { + use num_traits::FromPrimitive; + + use super::*; + + #[test] + fn test_jacobi() { + let cases = [ + [0, 1, 1], + [0, -1, 1], + [1, 1, 1], + [1, -1, 1], + [0, 5, 0], + [1, 5, 1], + [2, 5, -1], + [-2, 5, -1], + [2, -5, -1], + [-2, -5, 1], + [3, 5, -1], + [5, 5, 0], + [-5, 5, 0], + [6, 5, 1], + [6, -5, 1], + [-6, 5, 1], + [-6, -5, -1], + ]; + + for case in cases.iter() { + let x = BigInt::from_i64(case[0]).unwrap(); + let y = BigInt::from_i64(case[1]).unwrap(); + + assert_eq!(case[2] as isize, jacobi(&x, &y), "jacobi({}, {})", x, y); + } + } +} diff --git a/extensions/ecc/circuit/src/weierstrass_chip/add_ne.rs b/extensions/ecc/circuit/src/weierstrass_chip/add_ne.rs index 24bcc52ef3..c290b8b431 100644 --- a/extensions/ecc/circuit/src/weierstrass_chip/add_ne.rs +++ b/extensions/ecc/circuit/src/weierstrass_chip/add_ne.rs @@ -5,7 +5,7 @@ use openvm_mod_circuit_builder::{ExprBuilder, ExprBuilderConfig, FieldExpr}; // Assumes that (x1, y1), (x2, y2) both lie on the curve and are not the identity point. // Further assumes that x1, x2 are not equal in the coordinate field. -pub fn ec_add_ne_expr( +pub fn sw_add_ne_expr( config: ExprBuilderConfig, // The coordinate field. range_bus: VariableRangeCheckerBus, ) -> FieldExpr { diff --git a/extensions/ecc/circuit/src/weierstrass_chip/double.rs b/extensions/ecc/circuit/src/weierstrass_chip/double.rs index 0ae55f2df7..246bf3f017 100644 --- a/extensions/ecc/circuit/src/weierstrass_chip/double.rs +++ b/extensions/ecc/circuit/src/weierstrass_chip/double.rs @@ -5,7 +5,7 @@ use num_traits::One; use openvm_circuit_primitives::var_range::VariableRangeCheckerBus; use openvm_mod_circuit_builder::{ExprBuilder, ExprBuilderConfig, FieldExpr, FieldVariable}; -pub fn ec_double_ne_expr( +pub fn sw_double_ne_expr( config: ExprBuilderConfig, // The coordinate field. range_bus: VariableRangeCheckerBus, a_biguint: BigUint, diff --git a/extensions/ecc/circuit/src/weierstrass_chip/mod.rs b/extensions/ecc/circuit/src/weierstrass_chip/mod.rs index 0bcee1facf..e1e3ea084c 100644 --- a/extensions/ecc/circuit/src/weierstrass_chip/mod.rs +++ b/extensions/ecc/circuit/src/weierstrass_chip/mod.rs @@ -26,8 +26,8 @@ use openvm_stark_backend::p3_field::PrimeField32; /// For example, for bls12_381, BLOCK_SIZE = 16, each element has 3 blocks and with two elements per /// input AffinePoint, BLOCKS = 6. For secp256k1, BLOCK_SIZE = 32, BLOCKS = 2. #[derive(Chip, ChipUsageGetter, InstructionExecutor)] -pub struct EcAddNeChip( - pub VmChipWrapper< +pub struct SwAddNeChip( + pub VmChipWrapper< F, Rv32VecHeapAdapterChip, FieldExpressionCoreChip, @@ -35,7 +35,7 @@ pub struct EcAddNeChip - EcAddNeChip + SwAddNeChip { pub fn new( adapter: Rv32VecHeapAdapterChip, @@ -44,7 +44,7 @@ impl range_checker: SharedVariableRangeCheckerChip, offline_memory: Arc>>, ) -> Self { - let expr = ec_add_ne_expr(config, range_checker.bus()); + let expr = sw_add_ne_expr(config, range_checker.bus()); let core = FieldExpressionCoreChip::new( expr, offset, @@ -62,8 +62,8 @@ impl } #[derive(Chip, ChipUsageGetter, InstructionExecutor)] -pub struct EcDoubleChip( - pub VmChipWrapper< +pub struct SwDoubleChip( + pub VmChipWrapper< F, Rv32VecHeapAdapterChip, FieldExpressionCoreChip, @@ -71,7 +71,7 @@ pub struct EcDoubleChip - EcDoubleChip + SwDoubleChip { pub fn new( adapter: Rv32VecHeapAdapterChip, @@ -81,7 +81,7 @@ impl a: BigUint, offline_memory: Arc>>, ) -> Self { - let expr = ec_double_ne_expr(config, range_checker.bus(), a); + let expr = sw_double_ne_expr(config, range_checker.bus(), a); let core = FieldExpressionCoreChip::new( expr, offset, diff --git a/extensions/ecc/circuit/src/weierstrass_chip/tests.rs b/extensions/ecc/circuit/src/weierstrass_chip/tests.rs index 213918ec2e..a859070bc7 100644 --- a/extensions/ecc/circuit/src/weierstrass_chip/tests.rs +++ b/extensions/ecc/circuit/src/weierstrass_chip/tests.rs @@ -14,7 +14,7 @@ use openvm_rv32_adapters::{rv32_write_heap_default, Rv32VecHeapAdapterChip}; use openvm_stark_backend::p3_field::FieldAlgebra; use openvm_stark_sdk::p3_baby_bear::BabyBear; -use super::{EcAddNeChip, EcDoubleChip}; +use super::{SwAddNeChip, SwDoubleChip}; const NUM_LIMBS: usize = 32; const LIMB_BITS: usize = 8; @@ -94,7 +94,7 @@ fn test_add_ne() { tester.address_bits(), bitwise_chip.clone(), ); - let mut chip = EcAddNeChip::new( + let mut chip = SwAddNeChip::new( adapter, config, Rv32WeierstrassOpcode::CLASS_OFFSET, @@ -173,7 +173,7 @@ fn test_double() { let p1_y_limbs = biguint_to_limbs::(p1_y.clone(), LIMB_BITS).map(BabyBear::from_canonical_u32); - let mut chip = EcDoubleChip::new( + let mut chip = SwDoubleChip::new( adapter, tester.memory_controller().borrow().range_checker.clone(), config, @@ -251,7 +251,7 @@ fn test_p256_double() { let p1_y_limbs = biguint_to_limbs::(p1_y.clone(), LIMB_BITS).map(BabyBear::from_canonical_u32); - let mut chip = EcDoubleChip::new( + let mut chip = SwDoubleChip::new( adapter, tester.memory_controller().borrow().range_checker.clone(), config, diff --git a/extensions/ecc/te-setup/src/lib.rs b/extensions/ecc/te-setup/src/lib.rs index f166abe553..4c0fcdc783 100644 --- a/extensions/ecc/te-setup/src/lib.rs +++ b/extensions/ecc/te-setup/src/lib.rs @@ -107,14 +107,16 @@ pub fn te_declare(input: TokenStream) -> TokenStream { fn add_chip(p1: &#struct_name, p2: &#struct_name) -> #struct_name { #[cfg(not(target_os = "zkvm"))] { + use openvm_algebra_guest::DivUnsafe; + let x1y2 = p1.x() * p2.y(); let y1x2 = p1.y() * p2.x(); let x1x2 = p1.x() * p2.x(); let y1y2 = p1.y() * p2.y(); - let dx1x2y1y2 = Self::CURVE_D * x1x2 * y1y2; + let dx1x2y1y2 = Self::CURVE_D * &x1x2 * &y1y2; - let x3 = (x1y2 + y1x2).div_unsafe(&(Self::Coordinate::ONE + dx1x2y1y2)); - let y3 = (y1y2 - Self::CURVE_A * x1x2).div_unsafe(&(Self::Coordinate::ONE - dx1x2y1y2)); + let x3 = (x1y2 + y1x2).div_unsafe(&<#intmod_type as openvm_algebra_guest::IntMod>::ONE + &dx1x2y1y2); + let y3 = (y1y2 - Self::CURVE_A * x1x2).div_unsafe(&<#intmod_type as openvm_algebra_guest::IntMod>::ONE - &dx1x2y1y2); #struct_name { x: x3, y: y3 } } From 59253b093de7ada4cf3d6a97ec16d761cde08081 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 24 Jan 2025 11:50:07 -0500 Subject: [PATCH 06/57] cleanup TwistedEdwardsPoint trait --- extensions/ecc/guest/src/edwards.rs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/extensions/ecc/guest/src/edwards.rs b/extensions/ecc/guest/src/edwards.rs index dc51e2c115..30ede8cc80 100644 --- a/extensions/ecc/guest/src/edwards.rs +++ b/extensions/ecc/guest/src/edwards.rs @@ -1,6 +1,6 @@ use core::ops::Mul; -use openvm_algebra_guest::{Field, IntMod}; +use openvm_algebra_guest::Field; pub trait TwistedEdwardsPoint: Sized { /// The `a` coefficient in the twisted Edwards curve equation `ax^2 + y^2 = 1 + d x^2 y^2`. @@ -9,9 +9,7 @@ pub trait TwistedEdwardsPoint: Sized { const CURVE_D: Self::Coordinate; const IDENTITY: Self; - type Coordinate: IntMod + Field; - const ZERO: Self::Coordinate = ::ZERO; - const ONE: Self::Coordinate = ::ONE; + type Coordinate: Field; /// The concatenated `x, y` coordinates of the affine point, where /// coordinates are in little endian. @@ -31,22 +29,11 @@ pub trait TwistedEdwardsPoint: Sized { fn add_impl(&self, p2: &Self) -> Self; fn from_xy(x: Self::Coordinate, y: Self::Coordinate) -> Option - where - for<'a> &'a Self::Coordinate: Mul<&'a Self::Coordinate, Output = Self::Coordinate>, - { - if x == Self::ZERO && y == Self::ONE { - Some(Self::IDENTITY) - } else { - Self::from_xy_nonidentity(x, y) - } - } - - fn from_xy_nonidentity(x: Self::Coordinate, y: Self::Coordinate) -> Option where for<'a> &'a Self::Coordinate: Mul<&'a Self::Coordinate, Output = Self::Coordinate>, { let lhs = Self::CURVE_A * &x * &x + &y * &y; - let rhs = Self::CURVE_D * &x * &x * &y * &y + &Self::ONE; + let rhs = Self::CURVE_D * &x * &x * &y * &y + &Self::Coordinate::ONE; if lhs != rhs { return None; } From 01316c1f386e05e28fa876b1d8195f4dbb1cc9c4 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 24 Jan 2025 13:17:17 -0500 Subject: [PATCH 07/57] fix name collisions --- extensions/ecc/sw-macros/src/lib.rs | 2 +- extensions/ecc/te-setup/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/ecc/sw-macros/src/lib.rs b/extensions/ecc/sw-macros/src/lib.rs index 08f034ee8d..33e13a67d3 100644 --- a/extensions/ecc/sw-macros/src/lib.rs +++ b/extensions/ecc/sw-macros/src/lib.rs @@ -502,7 +502,7 @@ pub fn sw_init(input: TokenStream) -> TokenStream { TokenStream::from(quote::quote_spanned! { span.into() => #[allow(non_snake_case)] #[cfg(target_os = "zkvm")] - mod openvm_intrinsics_ffi_2 { + mod openvm_intrinsics_ffi_2_sw { use ::openvm_ecc_guest::{SW_OPCODE, SW_FUNCT3, SwBaseFunct7}; #(#externs)* diff --git a/extensions/ecc/te-setup/src/lib.rs b/extensions/ecc/te-setup/src/lib.rs index 4c0fcdc783..dfe5236e54 100644 --- a/extensions/ecc/te-setup/src/lib.rs +++ b/extensions/ecc/te-setup/src/lib.rs @@ -303,13 +303,13 @@ pub fn te_init(input: TokenStream) -> TokenStream { TokenStream::from(quote::quote_spanned! { span.into() => #[cfg(target_os = "zkvm")] - mod openvm_intrinsics_ffi_2 { + mod openvm_intrinsics_ffi_2_te { use ::openvm_ecc_guest::{TE_OPCODE, TE_FUNCT3, TeBaseFunct7}; #(#externs)* } #(#setups)* - pub fn setup_all_curves() { + pub fn setup_all_te_curves() { #(#setup_all_curves)* } }) From b5ca86005cb9c09b84b49bfe6b4e35de99304632 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 24 Jan 2025 13:18:11 -0500 Subject: [PATCH 08/57] change serde serialization for CurveConfig.coeffs to tagged --- extensions/ecc/circuit/src/ecc_extension.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index fa9fc22125..bcf598158e 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -44,6 +44,7 @@ pub struct CurveConfig { } #[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] +#[serde(tag = "type")] pub enum CurveCoeffs { SwCurve(SwCurveConfig), TeCurve(TeCurveConfig), From 75d9c027923ee3ed46a7c8487aeb8e0fcdb8242f Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 24 Jan 2025 13:21:37 -0500 Subject: [PATCH 09/57] fix typo bug --- extensions/ecc/circuit/src/ecc_extension.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index bcf598158e..058b628edd 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -231,7 +231,7 @@ impl VmExtension for EccExtension { ); inventory.add_executor( EccExtensionExecutor::TeEcAddRv32_32(te_add_chip), - sw_add_ne_opcodes + te_add_opcodes .clone() .map(|x| VmOpcode::from_usize(x + te_start_offset)), )?; From d3832d14fcb3725a94e8e365f65d0960b21fdb6a Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 24 Jan 2025 13:24:29 -0500 Subject: [PATCH 10/57] update setup_all_curves to setup_all_sw_curves or setup_all_te_curves --- extensions/ecc/te-setup/src/lib.rs | 6 +++--- extensions/ecc/tests/programs/examples/edwards_ec.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/ecc/te-setup/src/lib.rs b/extensions/ecc/te-setup/src/lib.rs index dfe5236e54..aaf7f7d489 100644 --- a/extensions/ecc/te-setup/src/lib.rs +++ b/extensions/ecc/te-setup/src/lib.rs @@ -240,7 +240,7 @@ pub fn te_init(input: TokenStream) -> TokenStream { let mut externs = Vec::new(); let mut setups = Vec::new(); - let mut setup_all_curves = Vec::new(); + let mut setup_all_te_curves = Vec::new(); let span = proc_macro::Span::call_site(); @@ -296,7 +296,7 @@ pub fn te_init(input: TokenStream) -> TokenStream { } }); - setup_all_curves.push(quote::quote_spanned! { span.into() => + setup_all_te_curves.push(quote::quote_spanned! { span.into() => #setup_function(); }); } @@ -310,7 +310,7 @@ pub fn te_init(input: TokenStream) -> TokenStream { } #(#setups)* pub fn setup_all_te_curves() { - #(#setup_all_curves)* + #(#setup_all_te_curves)* } }) } diff --git a/extensions/ecc/tests/programs/examples/edwards_ec.rs b/extensions/ecc/tests/programs/examples/edwards_ec.rs index 51768e9cc5..03aa0e4e79 100644 --- a/extensions/ecc/tests/programs/examples/edwards_ec.rs +++ b/extensions/ecc/tests/programs/examples/edwards_ec.rs @@ -69,7 +69,7 @@ fn string_to_coord(s: &str) -> Edwards25519Coord { pub fn main() { setup_all_moduli(); - setup_all_curves(); + setup_all_te_curves(); // Base point of edwards25519 let x1 = string_to_coord( From a9f1c30d7d64172116eb3a57272f993813b4b2a1 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 24 Jan 2025 14:05:34 -0500 Subject: [PATCH 11/57] Updated the OpenVM book and example code for twisted Edwards curves --- book/src/custom-extensions/ecc.md | 46 +++++++++++++++----- examples/ecc/Cargo.toml | 1 + examples/ecc/openvm.toml | 15 ++++++- examples/ecc/src/main.rs | 72 +++++++++++++++++++++++++++++-- 4 files changed, 120 insertions(+), 14 deletions(-) diff --git a/book/src/custom-extensions/ecc.md b/book/src/custom-extensions/ecc.md index 819b1c0845..1f5599f6de 100644 --- a/book/src/custom-extensions/ecc.md +++ b/book/src/custom-extensions/ecc.md @@ -17,12 +17,20 @@ The secp256k1 and secp256r1 curves are supported out of the box, and developers - `WeierstrassPoint` trait: It represents an affine point on a Weierstrass elliptic curve and it extends `Group`. - - `Coordinate` type is the type of the coordinates of the point, and it implements `IntMod`. - - `x()`, `y()` are used to get the affine coordinates + - `Coordinate` type is the type of the coordinates of the point, and it implements `Field`. + - `x()`, `y()` are used to get the affine coordinates. - `from_xy` is a constructor for the point, which checks if the point is either identity or on the affine curve. - The point supports elliptic curve operations through intrinsic functions `add_ne_nonidentity` and `double_nonidentity`. - `decompress`: Sometimes an elliptic curve point is compressed and represented by its `x` coordinate and the odd/even parity of the `y` coordinate. `decompress` is used to decompress the point back to `(x, y)`. +- `TwistedEdwardsPoint` trait: + It represents an affine point on a twisted Edwards elliptic curve and it extends `Group`. + + - `Coordinate` type is the type of the coordinates of the point, and it implements `Field`. + - `x()`, `y()` are used to get the affine coordinates. + - `from_xy` is a constructor for the point, which checks if the point is on the affine curve. + - The point supports elliptic curve addition through the `add_impl` method. + - `msm`: for multi-scalar multiplication. - `ecdsa`: for doing ECDSA signature verification and public key recovery from signature. @@ -31,17 +39,20 @@ The secp256k1 and secp256r1 curves are supported out of the box, and developers For elliptic curve cryptography, the `openvm-ecc-guest` crate provides macros similar to those in [`openvm-algebra-guest`](./algebra.md): -1. **Declare**: Use `sw_declare!` to define elliptic curves over the previously declared moduli. For example: +1. **Declare**: Use `sw_declare!` or `te_declare!` to define weierstrass or twisted edwards elliptic curves, respectively,over the previously declared moduli. For example: ```rust sw_declare! { Bls12_381G1Affine { mod_type = Bls12_381Fp, b = BLS12_381_B }, P256Affine { mod_type = P256Coord, a = P256_A, b = P256_B }, } +te_declare! { + Edwards25519 { mod_type = Edwards25519Coord, a = CURVE_A, d = CURVE_D }, +} ``` +This creates `Bls12_381G1Affine` and `P256Affine` structs which implement the `Group` and `WeierstrassPoint` traits, and the `Edwards25519` struct which implements the `Group` and `TwistedEdwardsPoint` traits. The underlying memory layout of the structs uses the memory layout of the `Bls12_381Fp`, `P256Coord`, and `Edwards25519Coord` structs, respectively. -Each declared curve must specify the `mod_type` (implementing `IntMod`) and a constant `b` for the Weierstrass curve equation \\(y^2 = x^3 + ax + b\\). `a` is optional and defaults to 0 for short Weierstrass curves. -This creates `Bls12_381G1Affine` and `P256Affine` structs which implement the `Group` and `WeierstrassPoint` traits. The underlying memory layout of the structs uses the memory layout of the `Bls12_381Fp` and `P256Coord` structs, respectively. +Each declared curve must specify the `mod_type` (implementing `Field`) and a constant `b` for the Weierstrass curve equation \\(y^2 = x^3 + ax + b\\) or `a` and `d` for the twisted Edwards curve equation \\(ax^2 + y^2 = 1 + dx^2y^2\\). For short Weierstrass curves, `a` is optional and defaults to 0. 2. **Init**: Called once, the `init!` macro produces a call to `sw_init!` that enumerates these curves and allows the compiler to produce optimized instructions: @@ -51,17 +62,21 @@ init!(); sw_init! { Bls12_381G1Affine, P256Affine, } +te_init! { + Edwards25519, +} */ ``` **Summary**: -- `sw_declare!`: Declares elliptic curve structures. +- `sw_declare!`: Declares short Weierstrass elliptic curve structures. +- `te_declare!`: Declares twisted Edwards elliptic curve structures. - `init!`: Initializes them once, linking them to the underlying moduli. -To use elliptic curve operations on a struct defined with `sw_declare!`, it is expected that the struct for the curve's coordinate field was defined using `moduli_declare!`. In particular, the coordinate field needs to be initialized and set up as described in the [algebra extension](./algebra.md) chapter. +To use elliptic curve operations on a struct defined with `sw_declare!` or `te_declare!`, it is expected that the struct for the curve's coordinate field was defined using `moduli_declare!`. In particular, the coordinate field needs to be initialized and set up as described in the [algebra extension](./algebra.md) chapter. -For the basic operations provided by the `WeierstrassPoint` trait, the scalar field is not needed. For the ECDSA functions in the `ecdsa` module, the scalar field must also be declared, initialized, and set up. +For the basic operations provided by the `WeierstrassPoint` or `TwistedEdwardsPoint` traits, the scalar field is not needed. For the ECDSA functions in the `ecdsa` module, the scalar field must also be declared, initialized, and set up. ## ECDSA @@ -106,12 +121,23 @@ supported_moduli = ["11579208923731619542357098500868790785326998466564056403945 struct_name = "Secp256k1Point" modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" + +[app_vm_config.ecc.supported_curves.coeffs] +type = "SwCurve" a = "0" b = "7" + +[[app_vm_config.ecc.supported_curves]] +modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" +scalar = "7237005577332262213973186563042994240857116359379907606001950938285454250989" + +[app_vm_config.ecc.supported_curves.coeffs] +type = "TeCurve" +a = "57896044618658097711785492504343953926634992332820282019728792003956564819948" +d = "37095705934669439343138083508754565189542113879843219016388785533085940283555" ``` The `supported_moduli` parameter is a list of moduli that the guest program will use. As mentioned in the [algebra extension](./algebra.md) chapter, the order of moduli in `[app_vm_config.modular]` must match the order in the `moduli_init!` macro. -The `ecc.supported_curves` parameter is a list of supported curves that the guest program will use. They must be provided in decimal format in the `.toml` file. For multiple curves create multiple `[[app_vm_config.ecc.supported_curves]]` sections. The order of curves in `[[app_vm_config.ecc.supported_curves]]` must match the order in the `sw_init!` macro. -Also, the `struct_name` field must be the name of the elliptic curve struct created by `sw_declare!`. +The `ecc.supported_curves` parameter is a list of supported curves that the guest program will use. They must be provided in decimal format in the `.toml` file. For multiple curves create multiple `[[app_vm_config.ecc.supported_curves]]` sections. The `type` field must be `SwCurve` for short Weierstrass curves and `TeCurve` for twisted Edwards curves. The order of curves in `[[app_vm_config.ecc.supported_curves]]` must match the order in the `sw_init!` macro. Also, the `struct_name` field must be the name of the elliptic curve struct created by `sw_declare!` or `te_declare!`. In this example, the `Secp256k1Point` struct is created in `openvm_ecc_guest::k256`. diff --git a/examples/ecc/Cargo.toml b/examples/ecc/Cargo.toml index 3e0dcdbcfc..d040e24a99 100644 --- a/examples/ecc/Cargo.toml +++ b/examples/ecc/Cargo.toml @@ -14,6 +14,7 @@ openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git" } openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git" } openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", package = "k256" } hex-literal = { version = "0.4.1", default-features = false } +serde = { version = "1.0", default-features = false, features = [ "derive" ] } [features] default = [] diff --git a/examples/ecc/openvm.toml b/examples/ecc/openvm.toml index d887d74a5f..df7cd4524a 100644 --- a/examples/ecc/openvm.toml +++ b/examples/ecc/openvm.toml @@ -8,4 +8,17 @@ supported_moduli = ["11579208923731619542357098500868790785326998466564056403945 struct_name = "Secp256k1Point" modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" -coeffs = { SwCurve = { a = "0", b = "7" } } + +[app_vm_config.ecc.supported_curves.coeffs] +type = "SwCurve" +a = "0" +b = "7" + +[[app_vm_config.ecc.supported_curves]] +modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" +scalar = "7237005577332262213973186563042994240857116359379907606001950938285454250989" + +[app_vm_config.ecc.supported_curves.coeffs] +type = "TeCurve" +a = "57896044618658097711785492504343953926634992332820282019728792003956564819948" +d = "37095705934669439343138083508754565189542113879843219016388785533085940283555" diff --git a/examples/ecc/src/main.rs b/examples/ecc/src/main.rs index 0d706d5363..fed901c814 100644 --- a/examples/ecc/src/main.rs +++ b/examples/ecc/src/main.rs @@ -1,16 +1,65 @@ // ANCHOR: imports use hex_literal::hex; -use openvm_algebra_guest::IntMod; -use openvm_ecc_guest::weierstrass::WeierstrassPoint; +use openvm_algebra_guest::{Field, IntMod}; +use openvm_ecc_guest::{ + edwards::TwistedEdwardsPoint, + weierstrass::WeierstrassPoint + Group, +}; use openvm_k256::{Secp256k1Coord, Secp256k1Point}; // ANCHOR_END: imports +openvm_algebra_guest::moduli_setup::moduli_declare! { + // The Secp256k1 modulus and scalar field modulus are already declared in the k256 module + Edwards25519Coord { modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" }, +} // ANCHOR: init openvm::init!(); /* The init! macro will expand to the following openvm_algebra_guest::moduli_macros::moduli_init! { "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F", - "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141" + "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141", + "57896044618658097711785492504343953926634992332820282019728792003956564819949", +} + +// have to implement Field for Edwards25519Coord because moduli_declare! only implements IntMod +impl Field for Edwards25519Coord { + const ZERO: Self = ::ZERO; + const ONE: Self = ::ONE; + + type SelfRef<'a> = &'a Self; + + fn double_assign(&mut self) { + IntMod::double_assign(self); + } + + fn square_assign(&mut self) { + IntMod::square_assign(self); + } +} + +// a = 57896044618658097711785492504343953926634992332820282019728792003956564819948 +// d = 37095705934669439343138083508754565189542113879843219016388785533085940283555 +// encoded in little endian, 32 limbs of 8 bits each +const CURVE_A: Edwards25519Coord = Edwards25519Coord::from_const_bytes([ + 236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, +]); +const CURVE_D: Edwards25519Coord = Edwards25519Coord::from_const_bytes([ + 163, 120, 89, 19, 202, 77, 235, 117, 171, 216, 65, 65, 77, 10, 112, 0, 152, 232, 121, 119, 121, + 64, 199, 140, 115, 254, 111, 43, 238, 108, 3, 82, +]); + +openvm_ecc_guest::te_setup::te_declare! { + Edwards25519Point { + mod_type = Edwards25519Coord, + a = CURVE_A, + d = CURVE_D + } +} + +openvm_ecc_guest::te_setup::te_init! { + Edwards25519Point, } openvm_ecc_guest::sw_macros::sw_init! { @@ -35,5 +84,22 @@ pub fn main() { #[allow(clippy::op_ref)] let _p3 = &p1 + &p2; + + let x1 = Edwards25519Coord::from_le_bytes(&hex!( + "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + )); + let y1 = Edwards25519Coord::from_le_bytes(&hex!( + "6666666666666666666666666666666666666666666666666666666666666658" + )); + let p1 = Edwards25519Point::from_xy(x1, y1).unwrap(); + + let x2 = Edwards25519Coord::from_u32(2); + let y2 = Edwards25519Coord::from_le_bytes(&hex!( + "1A43BF127BDDC4D71FF910403C11DDB5BA2BCDD2815393924657EF111E712631" + )); + let p2 = Edwards25519Point::from_xy(x2, y2).unwrap(); + + #[allow(clippy::op_ref)] + let _p3 = &p1 + &p2; } // ANCHOR_END: main From 27f3d4c8da64ac0fdad4f4cb40247d0c32fa1556 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 24 Jan 2025 14:06:55 -0500 Subject: [PATCH 12/57] delete vmexe (accidentally commited) --- examples/ecc/openvm/app.vmexe | Bin 139865 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/ecc/openvm/app.vmexe diff --git a/examples/ecc/openvm/app.vmexe b/examples/ecc/openvm/app.vmexe deleted file mode 100644 index 9d1635d7e8dd8033a14c7368b95da84a07ff68d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 139865 zcmeF)1%Q>+y8rQE$f3KtySux)ySs*N1Pl-r0~-?&3j+}q5iw~|2~m+5y1NIM_NKipK; zzEhJg<}UuZkMGX@`IKdd>0_mO&g~p1^~JR3)=Kimv?&{t-cBpEv3|O~)oHx>F5>ob zNAz9W*fv*->sx!?K;L^yroh5n=}!Q3?Mo9xuUCKj-rw3rKXn;saq}s(Yulqlfe8Z> z&|j^zBUWyy$_lf>M1ev4Nf@ZR5fGR;`frWvE4O{lM_wybETxi<-N_V~B%0=_{yGUs z0u%FhLPm`3N_D>0is##*MA0))-uA|wsYcceRHt(F_T_!oWhuY2Ir!FcCowc5?UQe> zGP9SN*_BMue`~(JUG=r76jOV%Ja2S6U-`{`z8JTk|8qQd2Hr?FTjt{q)Mb8>Hu_oe z{jC-m0*gk^yDaxI9}<$&nb2C?vc%M>)U8unE4S3@17bdnE742$R3|DQe>A2(h4mEb z*}C}*`bzz^_Sd#jOcbpk`q>Lmw3|<>?|IPQDzm?Dmg-7#@z=K;^UW6%OXt=1tms+u zJuQkzIU_1YCH|<5Z=9PWs7}$fW~I?1MYr@_l?zN4-9O(Sv-3u!3gO%;IP^I%j30>)gAfv+s?de7-+o z-khIB^Oo2hwp8_sp-&s#Et_55=u+SL(aa?;e=-Lap>1Kk14Qqa_Docx`&gD*<#bB) zXUit|=-}^wK=x9MP}{c#%Ip0>W$Adnbe)dB?Hj406^*V{4E56Az8D(E z*V@-!d7WVW(f5F|(JTAUHooUZt#rS&Ufn4>4@!M!B6#ggm%}c$W6+L5lqf=jmveCVKv$W^OW@s~4f9;T+TKC#YZN;`Otv+B`R8)}w zUW=ll%Gk9xJsTC3G%PBr&YGyGJS(H3`V5JRYSKF@Dvk20Q+rtw6*a^aTeNZ*-e>V{?b&}*oVd=6>g=A}tvUZ&XZ@d;_y6W|uDRRUkL`0% z<+|tIby`0=1F_||Mnz>&e~Yj8aEoPql-f9|_rA|tJH?6Zr8A^D8z;8Ub3MO$&(kxm zxoa-&dw`uq8`IY3wy}OnZCopJ+ucblH;#>?x$4@To7$<|yJxqPS6_c~v~k=yXm8zl z*c{w)E3-MdbB*o3*nPMApn1=aimGBUlp1gOoT#YD*3SAVRV<6AKGsid?b_-swj0aJ z{H1Cq>OX~Zt2Vl}@%{C2%iOlwJN2`^cCGk|9n7<*`Knyk?wqaO=52W!%jRhH{!%Mb zA6tu3caF-doyOl471c)9#>RB>)<$(keeGIfx$(6=+XuThwgy|T;@enme4CT{SxoC| zsru?#sqM4XS!(5)huhv_D!#^7osFq$V{>!!?mTVnx3dp!49!n{|Lu8bKWuOOrJAGW zr8-^PJhe}j_ZLI^>-Mqxtv$L{on0pu{2MctJbG@cD7Znz0oCb{a?5T7%smr7BaMXkDUtS{rL`ZEh!ZW4i6#xNaMN z<64=Uy8CR`b~Y{5817nht+5ox=Ayh_TAQ`EI!jgWy|z8Ea?4w4W4PMxe&VRNxqcE7#fMLY93+KTVRjiREu)a3U}s#i>#kELp(a=kPk z#aEg7i+z`M=c@0uD))|IF?Fvkmaa8dy5=IpLh>$Q0(w!Y)5-rCrhO0`F7ub5)vD7LOGzS`QjR;IY>tJGp?T>E*# z=AgW|v284irT*4lWw$yfI!|hUyXUGR-5IgdUc+32DK(PRh`jVb*Y-KNO9%_3#_r$x$c8_cx+JEhV=Akj9Kuqe6rTM$_Ql0kOr8%j;>NGc{TBohu z>NU2?mD(KbNHpQ_ql`60GsE_8L_XeXrHooSgYq6MCr*_`?YR?o$du08*@vKhq>{@Yj zZD(C`ifc_a2kndEXw6n;<0@5LQN7(KZ>qDXwpMO=i=+8#47(R@OtrCcYp+!8EpOLq zXMJr?)Mi)A{m}S2?_y>CVknN<8jEG~R3AHwcD_}ndgaw$*J3f0x^-$}?d)1Hv^QFh z=BIgT|I^cV9rxV0dG%2nwN-qLqw6W$6J0A+EcLZIH*OGpL@^UEwo*}hyH>qhr)#mk zcI~g9#n2oT)6UZz`fF}7pZIpYkg<)`X}-25x1D0Bt@c^hwvWo&wf4u(hn3qL&Js5) zW}nnw^){yFWMxWiT$_vbRBTEQPRI!w*PN}WO@+wn*YdfELi1Om@rSev1V_M$&S-Fj?`xVC6M)yE5?OynM zkFw8+&g{2+HrunKIVhIiYi*8hos}t7xtq5+xn*{(Ik{)Z+N#XvZZX~QRHt&S(_*Qw zSUgK@kJMJzc9yNJr8XDkZA_bkx6a)QUHjWlch4=J&DBk9o^F|Yt+Cy_U8|qX&*rQ; zw>)}t)kqZzq-$$nsU{j1n}FKb;1*A*zjF0)Um90=>!-1;UUfQrmRD-+-7>e_=AklO zd*kV#irZf?HCK)0j%V%MF|FSED31CnwRRfQ$}F|^im9?YrFqdE?tS{}ZX^;_qDhE7Sbc{&vo~J}mCWdg9Nz@4fVH?B%Uu z#Gmt<@6C43^&uYHzS(o24_dXimzCSI9$Q{tU@f-#>Pv_l!|JTR)oVPvR-ML)i`rPM z*iyyRd$gSan}<^C@BK`)&ogUdee}%g`Bz@!S-Db+W%bId+}V5{owrl2aqaU;*EUC8+xwzhu9!9tf8|zYbF>(WdpqY#_r%Va?z?@_SGk=7w_M{X zuO9&H+G5y!R=MJ6ooZ|S)yK_SJGb1ecfUxhjm=Z#Q&^wc+8nH(zf}EHu2lPC^RjZq zu=A-@6kpWF)@tpP*BspORi~G=^_N;7)v2$gHaFEPhSk{`gE<2>C;f1$dex~+dDW{- z*D6z9v8|uVY^|1R9Njn7sju>SDX&y>ajA_;(o)UO*gn~uEw#O}K9+`YPTan3dv{DLciUT;V%xP+_uAil?zG-w zdgtek{a5GYFQ)cducI+Px1Hs=5tV5l^nB>rK1+42dX-x{mDw|+)au-8wb3iCcDL&1 zt-n>?=4bQO_`24*G!LV4?WfE{5we5>imFZmS+RnDFt&QrfpT$$1 z)-9Tsjqh&_>J!`CEw1gMQpHewx6bxJm!XtK3pu>z9^VuhDl$m9^s8P&>Ws`=rf7d3zsHz1n(NTbol&#?l!2 z4ye@nS-VF3!dPXo)hWJWXrJ5|>Z6z2&&IJi+89bzruP2U>F$liP?@e>+8attw(co z&xvMJlli-4x?eU|t=rCyy-z5f+9;+{#kBUi)_y4O#`LyPOzo}O+4HaSqK6!m)fYU?vv*1-M`z-ZzYD!&E{aK#dD zH`V!2d&TwES^jpPbIr%*q(sy-*yn=Rp1JeyOdlEtc|n*}m8r zviBW(FH*f|9vVmO&axl3V)xhP;;uv2HntmI=U3%=hBQ~r!8>28v$@zAR6p-aZS0wF z%v_d{it*R`EvTdUPs-cl>SRqDp{wpE>#xz{SQy>!=M zW9z)?zSx@7R@c@?vFxQXtG70aqyCDmcB;4YsB6``&xHCZ@5WJk_nat>ofW03SD9XR z&ZjWmI?jz(dg5D|ugA@Q?4i8I4~}`R6+>luwlyc4x9+Rr1Tn5slD+ZB=jWl`3Xzaco?r*3agkRQF7&Ub-i0 zBkr}8xvAYpz29kU^;elvy|;DdOzT=Ny{EcsQ&zo1dTc&Gk>rFM5=Abs3vr@hM z%|-LjdKKe#QpHhQ+hgUuFV*{-gRR&0LV0~2c<1ltW7~6$>F$^Ham#gW<(9f-IycH| z48_v5rB?pO7Y1#fb+A;8^cr#?q|uxkJPbE@gSf$)^$mXbxWO;WZ$#B85E?RQ<&CI5 zqxOen8WQ>Ee+Z%Soclv^dCON2Lvg1tu}E%ED2~#1(Rts5)o)h#&@5&f@7 zl~+HNg`SE?ZYl^%}>{= zSKeD@hc40?r@#fi#IS~nCqsH^&PH+0Uf@62i5a6rB>%!WGOAC_$f!JxBBQ$O3Xf_N z8qQvXb7;b&lD3NEzc~`g55ST9z($|2aQ?+v1aDFid{9L2FKj8(gW!!56i$73RB-n2 zs4@k@`ELw(;*y$t4o(Y|RMrT)h9uE9H&cMTd(>(~D4T654`G$)OtwP}rtqq%Dh zT1zX|q&?BzXpgjJ@7V5G7kKl~IErcGsgJwA3yHIccuR=8jPbm4U&%byFrRhA*vk02 zcS<$)l~<$s=tD~%g!&-UIrGLp8uKO+#@^`+dE@JRX;1ZVD`o=rB8+GA?2V|TM{oT3 zzX77>BlJd8nq4>e*N!*%SDZJZx)kE<*}YMGy%Jow`L85>C5(H4H}J@)q~VOGROP+H zqSENB4>=LiXc^~Ob5W|g64%&!_D<)(yT{ohIGYjtkQ~8TjNrfZ;5nl;BRESDoTUiP zQUw3)oqzbO|J8e_bL2i7-e*DksdITZ&brQuojqOa9O*piTxlHltn2*g9O^u3O@HOA zYYfG+vApNd`~KuThu-%m-8Y?eoym3F%ay#>t>L|H9p`N;_xnHM^IjLqd)-myq4VX9 zuXD8|lC?#$wn)Ahd(Qd%NZtn`Ik)_a+hF?N&N;6b=G#NPFX_zcr8BKPu=gyL>HRsb z&q1}(b5P)T$RK?dsIQ*o^d};MRetnXNFzNPHBUt3QGVUAkWR|?J`oZ9`4@B|qDq3$ zkcoQMRj&60rHZ@oT2!#g74MI6j)e@edX?#V*U5NMe2QO~89W z5ML(K^B$L7UozPG==+D{;>E1DzX7_rhYR&6IQOHRneCjLO%Xi^`+-JAIkcmp^^4@xIsU zZ0dbe&#C%)_e=Nc?1_-XHpkxQeP1Zu`KYb{aa5)l?%bB0_s!qRHLrE&efQRlv55D> zxbBN$hDG?!sOEc}wd@axm|TG8LFX-;aSw(>4AJM+;gE6r}C0tUNJO12jC(dDB58Kj$DBufX6d|T z4~;03J~SdYC^RDazp1A(?Y-8WAT%QS9w@&y<_ue0Zyenpok8{M91ze}^U*rAM$sJ4 za&C03I=!q;*ZV_4CaS&etJa}CcH0gK2xzK$eW%hGHE%@aQGO2lpgq+02(=I9vs3Z( z()v{v3bj?c!yzG^lo#!d)*JmLoc+-{)z8YbmnzemtxWZroBCLp^0ps3CyKo;AfW5@ zkdRV(UsoT!G>3%=0>-Fb`>{V}JjGW$#ZWspueKJmcR)Z|wbNc(J4>V2K%M&Pd#1|u zQeN~~t$ZZ$lxn{fdpC2^KK!vBXCJK0-3KdEj43hmwld}Y?L%ZpNGd(&>Z6z1>t1Ls z2SY*zX&!sXYaY55omaabR_4yb$`sG$VP&z+BRnJ|m)fhHo)OJs4bM*)^IpV0s4kK^ z&CRau+^CHxuR66+9JSY(RheGOD^Un-AnyemAT8t)SCaT;5By-z5w zxu53jDt}VXcTD~`=Sq3qhr^r`uJ^**aq?{}N%Z*8rg_Ck9+g}Lq~O~CgMwO6^@-tDhC>#zOO zI@M=2{cSBu^|CsxL2DO#epP0D)K+8Yb1T8IkcrAOvFP^$T`P{;*2*-l;wYx*JxO(L zY;W8G{0=~E^m606@pT^*TWN4;L{hcY+_oMK$)q&wNJuSxE`>7ouA>oc8ij^*TEf04 zo@kw``F+Ej^HGy^&(vq#k&sS0AG%M9t+}e5Vraga=Tg?7HX3iu-iYYu#~pXck&r=u zjC(AijeaK)ye}g9yy$w!zK}*5Uon*GeNJaV@s%pCc`o8!DbA3=kdCJepcd!Nx95*+rucWWOtruI1?fGEI>qQ6vv%!~@}jvZrsBl5CnZ?7>ebH1>>M+`^0Q;=G^Z&svD8-U zS3iwo_f%u3O!e-1H4lrec@AOj!NgWPf9FKwE6$KmerM_D9NE3n9&1e9AI&e6*fy^E z+e>RyJIzC%@tVt0^6Ia-HsV@+D{}wUN9)lXt-t1>zM?Z-A|Rk>P5P?-D4#u=uf<;+ z^BJ&=Hr9U;dt~jcOlfbPW6N8;ohv;rnx{VNG*6AKHb)~kf2_g!ZRK|>TD$hZ%Dm~a z8@_w27;5j`qrbDqx_25Ul$ctd=4kU!nZ{DR%9Z+io#pp@I>TC*+UxA=R$Bd!2#?F;@Y{jzsYH^e*mipewn%#KrweFSjioccbciw%rwyIChcYmEX%~P~b zt+U~z+v!uQ{ z``$UITrbUA=Tm3XormAJjPL8^`#Y{SvCU2QR?nx!v3sq&=At=>e(%^j!k5>&RbP`- z-}m$#PI-;5KAOAs+dhxAIqxN=Avj+r}wf;)=N)Yqjq49e|Wx5}>CguIT7wK74 z8(Uv?=6ROy!D?@*uI;7YC)>5wWoP16_td=~Hm7jL)tWT6apTx}Lu2agtSfJGP-@R* zP2#!z-8PD^=e9HBxzCN};*F=adT#8@sE@xh=x-^}PdOM-N8is>u0D#dc`C2+ zikJBvB;VV#Ud=^w(s*j)j$wPPHmVcdW1ShDm&L44dBr?>nV(sBZq>);uDNJzjjI?o zAH`9fy&CO}i2f|rnbq%z^d7CanxF2O%|rF}Sw18thUV^`U5zJdr_VkcL#e;>sB*2x z#&z38KPNnYil=*Szqd*d8Z}wZkNRm%YNxqQ;aYRle6){B(^IFlYfqG_&m5lfMltVy z(c|&CtWrg9y`E9kS-Hye8K(VL zxvtgUTdz9JRdr!JbGs7welMoabIncb)I62inr+USlN(R$F!S^U$@{6n)NO?z_f0$zE=`&UaycW>|EH-&ygQrZQO_bf`?nb5VUXue0ZT&%n4V zoC)d{RE)}^`=_{?-(mJHnE2Wc&0#n5)&1Nsf2&s;)mh(L z#j$>h<&Cd>54!9-H=2{;#`SZQJ+Jnh>;9}f5Yo%?>aY3hKcfj_y}GxmTf^G)bKco7 z-~X6_=I;L7r+F>pOe)?{{*8e8U8hWaHKzJ&e!6$6(>Qu*{`&U=`p<)+&&q+2Qd+OC z*7v>Gt`$Rb()*8MXby^R=Tmb~e9d2T(YUr=#ZbBW=zb`c#nl}2pP{L*$~1=6S=yVv zLl`TVadigtyv*lZb&lzy_iXE{{)%t=qxq^%V{5KjXV8I=O0n&c*6-b?^d}>N6+?Y@ z?GI_Slr<>d>O@4A=!I!<|29qFPRG0(G46B@@%{h(vlGAP@p~SB2I9{^{27Qp1Mz1d z{tU#Qf%r2Je+J^u!2gvq@OOT${VRR`N?Yye?Y6gemioINan<>2f49p1&2j(DvF_IX z#K(z$|BOEa@n<0Z48)&-_%jfH2I9{^{27Qp1Mz1d{tU#Qf%r4<-**P0{~KNUMT7pu zhi;HvyQy8PjZ5X;S8VmMmAn0Ie7EfHTq};oi>q&3^)}bI`rm1tjd3Tb=5Qzdt?%86 zWAS23ZO>w>|10HpGge&V+TPsF@!VK;R^yt(KV4_@`KQvmF@MeNzbVeG=3;w!t9G|j ze>Y>@YP`ESmK*E;$~pJ9f40uMkt)98cs~oR{8nT5o1a@|{oOLVwz|KXdgrSC{>pAA zuD^c%%Dk~+Yh!EsyQy~^aC6DZrnC@?XJzrtiQ#ua-~+MYm4hIhQBiF z>o2b2=@nOY_4BUL&D*t`>e})e!M(oKJgi=+ziXSZ z8`H{emAWz2-{PyEziYR>)m!Qv%PseJtuib3rruaKAL|oaYVEwKzxK9XOKlGR#&*lp z&h2Bd)y7}B)my4I;2#W!BHV zwlbye_*NcQEVupbUR&JTN&SuO_EWvP7RzfcZaZCDov!`Wt6VROXX|mxbZzBss&euH8QFzSx|Us*R;?d$-)`m5RpnmU;WSdAE=CvwG!? z;>I?vTW;6>+FN|9yVW>0wzZ2ZRa?b1*4FZ|rPfZV&Ce~fYq!6Z*_f7B>c&tXx6Zv* zJGZUn{q^y-bLZmk+QzXu%e$#tr)#%P*H(YKslPt4#k97T+W0n>x1XE0eX>2VyxLfq zwYNHp?=81{T=f=HsoT!V6~n!@m~NS_E$^o8wZ(DUS}d#cm$w-1+|*8ai)C%BT&dOR z+FmM)t)JSsecWs7Z*4498>{oq&)df0Ss%+=J2&+gOZBmpyM1;2cV0HH*!tRh-8tx5 zRA<-fZ`Vqdx7e1dEVh@ojW@P8uQ+ZWySA}y9B)5=d2cN1tJE9MU1Mz5Zh!B!jc?^{ ze2eGS`72YsTkc+4UrTLYEN`jJ!}{J%s=jKczQ*DyjcqK|S$ti)FDv(^{@SQa?X1qO zt#4fAZd+^jucWbU%3mpW+q&0UfHxmoSzP6+vzNbks*9~Wu73XdsLWsa?Tle##i#K* z@ISc&{?2b~W&X-F_t?t+C)X7}cKi;wJK*n(-fo#2N7u3SbIWz@&3of`^KSdt#)+%k z8}Cl?w=)-So7l$lw)5t1cTN8K-EQC5=4R#I*xr0>?cyr;7sFqf#rUVw|H-lc>9xhj zkKcj#9r(Y$1M%-+f4;~6)PCGaTPc}v}L_uA@jm0BNfYW-Ahbt-eOt<9}c zZy#^o?H^a2+fLWswwAZlZEt0kx^>=Iv9*b-j~m17?_PWRyLoRrZ{BVD-*o-IWuESy z{nK;y7vEo*JEy;LeK%wMm2u;0``YXS1Y?!|6A2tocQ#A&kp>z-P2pm=T`OJo&T%tz5V}A{+}50PGa6k-@mi| zzuU*=Y3bjM6W{Od?ts7hVP)P_BU{D%+=f1n|H_e)_L=4>#xj> z;qTh|SZZy&c`N@XQh#IlEBh;B$JRf#^0;DKA4{#R@`;jLECS*nyWJNY)M-JpfF62fYArwXt6h$!w>E3`%%v_(6# zM+bC7Cv-*^bVWCGM-TKwFZ4zq^hH1P#{dk(APmM348<@E#|VtXD2zrh#$YVQVLT>a zA|_!nreG?jVLE1DChoy3%*Gtti~Ddt9>848!-JTQhwv~S!2&#r$M86wz(PEUr|>kM z!LxV{&tnl@z>9bZFXI)wip6*hOYl0D;tjlsx9~RJ!7{vy_wYVGz;b+u75E4%@i9KZ zr&xv0uo|CZ4Zgrye2K5{HNL^O_zvr^9viR`o3I&M@IAKT2mFYiunpU>13U3EcHtNN zir=sszhe(V5Q@Fnhy6H!gE)l4ID(@%hT}MalQ@ObID@k|hx53Ai@1c#xPq$)!!=yT z4TK{Ck%&S-f&}~@&p#3(5fUQ_k|G&`kQ^zH5~+|HX^CS*nyWJNY)M-JpfF62fYArwXt6h$!< zM+uZfDU?PTltnp|M+Hw> zE3`%%v_(6#M+bC7Cv-*^bVWCGM-TKwFZ4zq^hH1P#{dk(APmM348<@E#|VtXD2zrh z#$YVQVLT>aA|_!nreG?jVLE1DChoy3%*Gtti~Ddt9>848!-JTQhwv~S!2&#r$M86w zz(PEUr|>kM!LxV{&tnl@z>9bZFXI)wip6*hOYl0D;tjlsx9~RJ!7{vy_wYVGz;b+u z75E4%@i9KZr&xv0uo|CZ4Zgrye2K5{HNL^O_zvr^9viR`o3I&M@IAKT2mFYiunpU> z13U3EcHtNNir=sszhe(V5Q@Fnhy6H!gE)l4ID(@%hT}MalQ@ObID@k|hx53Ai@1c# zxPq$)!!=yT4TK{Ck%&S-5YImXkr0WH7)g*6$q5h1|%4yvT?AD1d?}gu*C-q9}&qD1nkFh0-X4vM7i0sDO&7gvzLbs;GwQ zsDYZOh1#ftx~PZxXn=-jgvMxsrf7!dXn~e!h1O_;wrGd;=zxysgwE)KuIPsD=z*T- zh2H3czUYVk7=VEoguxhsp%{kY7=e)(h0zGc7>va@jK>5_#3W3{6imf5OvenBgW z*_eZSaUbr-1DK0>co6gP5FW-OSb#_I7#_zHScoU_6rRR2coxs$c`U*Uco8q*WxRq{ zu^6vm30}uiyn#3I7T(4?ScZ4;9^S_XSdI^|0v}-|KE@~b6szzVR^xN5!53JIFYy(= z#y9vD-(elrV*@r~6EW_9&hw8zBt#-4 zMiL}NG6W$xQXnN#AvMw@+p*HHEF6yB^8lWK>p)s1EDVm`< zTA(Fbp*7l|E!v?yI-nyup)jb+gop767T{4l zhR5*)7UD@fg{Schp2c%`9*gh-Uc^gy8L!|~EXHeCg4eMWZ{SV5g}3nzmf>BzhxhRT zmg7ULz(-h#kMRjU#VUM;)%YB1@CDZ5OMHc|@eRJkcUXt@*no}Lgw5E3@39p>;79y~ zZP<<-*omL93%}r3{D$559eWUhQ0&D%?8gBd#33BU5gf%a9LEWq#3`J{8JxvAoW})R z#3fwD6j0T_ru7>pqpieVUz5g3V47>!_z!B~vLcuc@VOu}SL!BkAcbj-j^ z+=E$|jXAg%_u+m#fVr552QeQH;bA<21$Y#X;c+~Hg?JKA;b}aBXYm}K$0EFd7x5Ba z#w&Ogi}4zk;B_p;8+a3M;cdKwWq23w;eC97<@gXQ@DWzxV|;>7u?nAIH9p50e1Wz2 z5?|qKe1mWC9oAtzHee$*VKcVidu+uI_z^#08@6KycH(F3!Y}w0zhO6i#~y?r6nn7` z`*8pVaR`TT1V?cU$8iEDaSEq#24`^&=WziSaS4}k1y>Pu0A|28r12Q5LG9wGJA{(+J2XZ18aw8A&A|LXj01BcI z3Zn>$q8N&!1WKY5N}~+Qq8!Sj0xF^sDx(Ujq8h5B25O=fYNHP7q8{p_0UDwa8lwrC zq8XZ_1zMsNTB8lxq8-|!13ID;I-?7^q8qxS2YR9xdZQ2eq96KW00v?Z24e_@Vi<;F z1V&;MMk5$wFc#x59uqJTlQ0=mFcs4<9WyW!_h1%gV-D`ceYhVFU@qq2LCnWPco>gh z0UpI;cpOh)A)drjcpA^(Sv-g5u?R2VMZAQU@d{qWV!VbWcpXde2HwP5cpL9v8Q#Tv zcpo2NIX=V+e1w(w7@y!%tioqljnAzl-{4z(hjmzw4cLfH*o-as9$WDP ze#B4MhV9sao%k8M@C$y$Z`h6Bu?Hat#a`^gejLC-9KvB7!BHH;ah$+OoWg0G!C9Qc zd0fCnT*75s!BvFe8m{98!V!T;L?Iv*&p!f@5Q&f&NstuD5QOANfs{yv)JTK0NQd;u zfQ-n5%*cYQ$cF65ft<*N+{lBx$cOwWfPyH5!YG2GD2C!Ffs!bN(kO$nD2MW>fQqPu z%BX^>sD|pOftsj=+NguNsE7J!fQD#<#%O}3Xolu!ftF~6)@XyaXovRbfR5;d&gg=! z=!Wj-fu87v-spqA=!gCofPol3~(fsq)6(Fn#EjKw&N#{^8oBuvH>OvN-z z#|+HGJ(z{rn1g$9AMVEkn2ULM5cBa69>ybBfJgBd9>)_{h$rzBp2jnH7SG{%EW!(T z5ij9oyn_G@Z zu^0QW9|v#{hj182a1_UI94BxRr*Il)a2Drq9v5&Cmv9+Za1~*=hU>V2a6}*yQ3y!Q z^N&CzL?R?c5+p@31R*(6ASF^EHPRq0(jh%EAR{s%GqNBnvLQQiASZGmH}W7a@*zJ8 zpdbpNFp8ikilI14pd?D6G|HeX%Aq_epdu=vGOC~|s-Ze+peAaeHtL`*>Y+XwpdlKe zF`A$$nxQ#bpe0(NHQJyp+MzuM(r|}G)#dCNbi|_(o#7lS?ui#ZI#%oxD*Rd3D;7z=RxA6{^ z;a$9k_wfOi<3p^#M_7rE@d-Y~Dtw03_#A8S1=iwAe1)&^4Zg*9Scmo4fQ{IM&DetP zu@yhyNBo3s*p408iJ!3xzu;H=hTZrbdk}(9?8QFp#{nF~AsogL9K|sl#|fOoDV)X` zoW(hu#|2!(C0xc8TtyhJ;W}<091(~_6av!l{38$vkqC*A1WAz$K}e1iNQqQPjWkG$ zbV!d3$cRkHj4a5CY{-rr$cbFYjXcPUe8`UiD2PHRj3OwCVknLhD2Y-ijWQ^Uawv}q zsEA6aj4G&#YN(DHsEJyrjXJ1{dZ>>EXoyB=j3#J`W@wHUXo*&6jW%eDc4&_d=!j0} zj4tSkZs?94=!stFjXvm$e&~+@7>Gd_j3F3`VHl1P7>Q9BjbMzySd7DXOu$4;!emUr zR7}Hk%)m_CgISo3Ik*@1;eI@TxtNCsF&_`%VLXBbcodJ}aXf*AcoI+HX*`2x@f@DV zBD{bX@e*FfD|i))@fw!kbu7gjcoT2oZM=hJco*;CeSCoB_z)}b5mw@3e1cE03ZG#$ zKF1n-fwlM&U*T(fgKzO2)?qz1U?VnRGq&J+Y{d`w5kFxYwqpl&;%Dr_FZdO|VK;uq z9)utid$AAuaR3K#2#0Y5M{x|taRMiC3a4=fXK@baaRC=`372sNR}qG5xQ-hLM+71f zg@Cj?{|H1vBtl{&K~f|`5RxMWQX&;nBMs6b9nvEMG9nW)BMY)38?qw@av~RUBM$k7>c6=N}?1>qYTQT9Ll2tDxwl9qYA2`8mglPYN8fuqYmn#9_ph3 z8ln*zqY0X#8JeR7TA~$NqYc`k9onM0U$4(`Q$xE~K-F6QAu z%*R7`7>{599>rsL98X{&p2Sml8qeTaJcsA82ruA8yo8tW3SPxxyoM!s9ZT^B-o#sY z8}DEl-o<-(A0J>jKEw)qgq8RhpWsuh!e>~G&#?wyU@gAHSNIy=;9Go$by$xL*oaNo zj4k*cTk!*a#823U?bv~x_!+zK3x36K*p1(@2O$W>UhKnu9Kb;w!eJc2Q5?f@oWMz( z!fBkrS)9XpT);(K!ev~+RfORhuHy#65rIfVAs`*kKLU{uiI5mckQB)fgycwplt_it zNQ1OUhxEvRjL3w{$bziMhV00JoXCaT$b-Ddhx{mjf+&Q-D1xFWhT4JD1)*n zhw`X^il~IjsDi4fhU%z+ny7`^sDrwwhx%xMhG>MwXo99_hURF2mS~06XoI$BhxX`z zj_8EW=z^~3hVJNrp6G?%=!3rKhyECVff$6r7=ob~hT#~2kr;*12*wzU#W;+|1Wd#v zOvV&U#WYOE49vtmn1$JxgL`ow?#Ba|i+Oku^YIWK#v@pONAVaQ#}inHC-D@X#xr;p z&*6D2!V7p2FX3gpf>*H^uVD#Z$5On3H}MwU#yePsckv$H#|K!B53vFtVI@AsC-@Yr z@EKO)bF9G^Sc@<56~4wd_!i$`9oAz5HewStV++2=R{Ve;@e{UTJ9c0ve#S2Rf?x3) zcH?*KK?p*z7yGau2XGLFa2Q8$6vuEJCvXy{a2jWD7Uyst7jO}ma2Z!{6=ArB>$rh% zL?9AT2uRQKk3b|uA|yrYy&_ zp*|X*AsV4EnxH9~p*dQhC0e01+Mq4kp*=dFBRZiox}Yn%p*wn@Cwieb`k*iRp+5#- zAO>MDhF~a$VK_!$Bt~I0f-weTF%IJ~0TVF^lQ9KTF%8o(12b_CW??qw;9lH^`|$wg zVjdpEd_07Q@dy^+Q9Opn@dOs)Nj!z8@eH2Db9f$$@B&`MOL!Tt;8iTfYgmHUu@rCM zO}vG-@eY>ZUA%|)@d1|OL#)6@Sc#AE2|mRte1_Hd9Bc3e*5XTig|G1qzQuP~hxOQi zjo5_E*n;n|6+hrd{Df`Tjvd&EpRo(S;8*;H-S{1Q5Q0$b#XjuE0UX339L5nG#W5Vm z37o_!oW>cP#W|eE1zf}>T*eh#MHsH(I&L5w5r{+-0y6OYBM=FZ2#JvdNs$aeNRAXp ziBw39G)RkdNRJH2h)l?gEXay%$c`MyiCoByJjjcD$d3Xjh(aigA}EStD2@^+iBc$y zGAN63D31!Lh)Sr8DyWKTsE!(_iCU6PCTNOgXpR zXpau)h)(E?F6fGG=#C!fiC*Z9KIn^n=#K#yh(Q>PAsC8b7>*GbiBTAhV2r_7jKg?L zz(h>KWK6+SOv7}{z)akOS(uGExEJ@~emsD=n1=^39}nSSJc0#y6p!I?Jb{IH5>Mf2 zJcDQP9G=G_ynq++5?;nDcomEB8kXR7EX5mm6K~;dyn|(U7w_SHe1PTn5G(KzR^nrP zf={supJ6pV#~OTrwfGWW;cI+@Z}A=0VLdirBQ{|(w%~hg#Si!qKVciTV+VHPXY9f+ z_!YllH-5(+gdh}qu@C!k00(ghhj9c)aSX?C0w-|_r*Q^naSrEk0T*!zmvIGG5r%8H zjvEL^1R@cIfQ&r<2t-08LSiIAQY1qVk|PCDA{A024bmbV(jx;hA`>zr3$h{`vLgp_ zA{TNa5Aq@(@}mF>q7VwB2#TT@ilYQdq7+J_49cP$%A*1*q7o{j3aX+Ss-p&Kq84hS z4(g&F>Z1V~q7fRS37VoAnxh3;q7_=B4cej|+M@$Hq7yo!3%a5kx}yhrq8ECj5Bj1X z`eOhFVh{#n2!>)9hGPUqViZOr7-KLN<1ii*FcFh58B;J7(=Z(~FcbG+7G`4(?!|q$ z9}i$I=HWri$3u7+k6-~F#bbCJPhcUQ#8Y@0&)``+hv%^fFW^PIgqQIOUd3X(h9!6% zOYsKY#9Me9?_e3;#d~-kA7D8?#0q?bmG~H+;8U!^XIPETu?AmYExyE8_!{5fTYQIg zSdR_Zh)vjxE%+W=@dJLuPuPa-*nyq+8N2Wce#LLtjo+~cAqd4@?8AN>z(E|sVI09x z9K&&(z)76KX`I1XoWprsz(ribWn95kgy9;l;|9VJfk;FlAQR6&0+A4jkQhmj6v+^T zf~u&7>ZpO5sD;|7gSx1P`e=ZLXoSXSf~IJO=4gSIXoc2j zgSKdg_UM3)=!DMbg0AR>?&yJ@=!M?sgTCm8{uqFP7=*zXf}t3O;TVCD7=_UY#u$vn zIE=>xOvEHi#uQA&G)%_~%)~vIh1r;cdvPD`#{-y)d3X@>@em%yBUpe(@faS*6Ih5R z@f4oMGk6xy;dv~=3wRMP;bpvnSFsqcVF_NxQoMmT@fP03J6MKy@gCmC2Uv~|u>v1q zB|gR{_!O(~8CK(Sticypi!bpNzQ#BB7T;kV)?))UViPuF3%xd z#xDGVU-27u<9F;q2tu(J`>-Dea1e)Z7)Njv$8a1ca1y6*8fS18=Wreua1obq8CP%> zVYr6txPfp)AQDjs;D1*k0RoW_iI5mckQB)fgycwplt_itNQ1OUhxEvRjL3w{$bziM zhV00JoXCaT$b-Ddhx{mjf+&Q-D1xFWhT4JD1)*nhw`X^il~IjsDi4fhU%z+ zny7`^sDrwwhx%xMhG>MwXo99_hURF2mS~06XoI$BhxX`zj_8EW=z^~3hVJNrp6G?% z=!3rKhyECVff$6r7=ob~hT#~2kr;*12*wzU#W;+|1Wd#vOvV&U#WYOE49vtmn1$Jx zgL`ow?#Ba|i+Oku^YIWK#v@pONAVaQ#}inHC-D@X#xr;p&*6D2!V7p2FX3gpf>*H^ zuVD#Z$5On3H}MwU#yePsckv$H#|K!B53vFtVI@AsC-@Yr@EKO)bF9G^Sc@<56~4wd z_!i$`9oAz5HewStV++2=R{Ve;@e{UTJ9c0ve#S2Rf?x3)cH?*KK?p*z7yGau2XGLF za2Q8$6vuEJCvXy{a2jWD7Uyst7jO}ma2Z!{6=ArB>$rh%L?9AT2*|?ok3b|uA|yr< zBtYy&_p*|X*AsV4EnxH9~p*dQh zC0e01+Mq4kp*=dFBRZiox}Yn%p*wn@Cwieb`k*iRp+5#-AO>MDhF~a$VK_!$Bt~I0 zf-weTF%IJ~0TVF^lQ9KTF%8o(12b_CW??qw;9lH^`|$wgVjdpEd_07Q@dy^+Q9Opn z@dOs)Nj!z8@eH2Db9f$$@B&`MOL!Tt;8iTfYgmHUu@rCMO}vG-@eY>ZUA%|)@d1|O zL#)6@Sc#AE2|mRte1_Hd9Bc3e*5XTig|G1qzQuP~hxOQijo5_E*n;n|6+hrd{Df`T zjvd&EpRo(S;8*;H-S{1Q5Q0$b#XjuE0UX339L5nG#W5Vm37o_!oW>cP#W|eE1zf}> zT*eh#MHsH(I&L5w5r{+-06PCTNOgXpRXpau)h)(E?F6fGG=#C!f ziC*Z9KIn^n=#K#yh(Q>PAsC8b7>*GbiBTAhV2r_7jKg?Lz(h>KWK6+SOv7}{z)akO zS(uGExEJ@~emsD=n1=^39}nSSJc0#y6p!I?Jb{IH5>Mf2JcDQP9G=G_ynq++5?;nD zcomEB8kXR7EX5mm6K~;dyn|(U7w_SHe1PTn5G(KzR^nrPf={supJ6pV#~OTrwfGWW z;cI+@Z}A=0VLdirBQ{|(w%~hg#Si!qKVciTV+VHPXY9f+_!YllH-5(+gdh}qu@C!k z00(ghhj9c)aSX?C0w-|_r*Q^naSrEk0T*!zmvIGG5r%8HjvEL^1R@cIfNVVf2t-08 zLSiIAQY1qVk|PCDA{A024bmbV(jx;hA`>zr3$h{`vLgp_A{TNa5Aq@(@}mF>q7VwB z2#TT@ilYQdq7+J_49cP$%A*1*q7o{j3aX+Ss-p&Kq84hS4(g&F>Z1V~q7fRS37VoA znxh3;q7_=B4cej|+M@$Hq7yo!3%a5kx}yhrq8ECj5Bj1X`eOhFVh{#n2!>)9hGPUq zViZOr7-KLN<1ii*FcFh58B;J7(=Z(~FcbG+7G`4(?!|q$9}i$I=HWri$3u7+k6-~F z#bbCJPhcUQ#8Y@0&)``+hv%^fFW^PIgqQIOUd3X(h9!6%OYsKY#9Me9?_e3;#d~-k zA7D8?#0q?bmG~H+;8U!^XIPETu?AmYExyE8_!{5fTYQIgSdR_Zh)vjxE%+W=@dJLu zPuPa-*nyq+8N2Wce#LLtjo+~cAqd4@?8AN>z(E|sVI09x9K&&(z)76KX`I1XoWprs zz(ribWn95kgy9;l;|9VJfk;FlAUn@L0+A4jkQhmj6v+^T zf~u&7>ZpO5sD;|7gSx1P`e=ZLXoSXSf~IJO=4gSIXoc2jgSKdg_UM3)=!DMbg0AR> z?&yJ@=!M?sgTCm8{uqFP7=*zXf}t3O;TVCD7=_UY#u$vnIE=>xOvEHi#uQA&G)%_~ z%)~vIh1r;cdvPD`#{-y)d3X@>@em%yBUpe(@faS*6Ih5R@f4oMGk6xy;dv~=3wRMP z;bpvnSFsqcVF_NxQoMmT@fP03J6MKy@gCmC2Uv~|u>v1qB|gR{_!O(~8CK(Sticyp zi!bpNzQ#BB7T;kV)?))UViPuF3%xd#xDGVU-27u<9F;q2tu(J z`>-Dea1e)Z7)Njv$8a1ca1y6*8fS18=Wreua1obq8CP%>VYr6txPfp)AQDjs$iefE zKqN#WBt{Y>MKS~-IZ_}cQXw_cAT81%Ju)C8G9fdvAS<#VJ8~c=av?YJATRPEKMJ5A z3ZXEHpeTx=I7*--N})8$pe)LvJSw0fDxor}pem}NI%=RMYN0mjpf2j6J{q7Q8lf?o zpedT6Ia;74TA?-Cpe@>=JvyKxI-xVVpewqeJ9?ledZ9P^pfCENKL%hR24OIUU?_%R zI7VP3MqxC9F$QBX4&yNa6EO*sF$GgG4bw3LGyflV_XFkSv^IRaBngS6l9VJ#5=kYL zBuR**l9VJ#5@8xiNs=UyB*~B@Ng^3ZB1w`&k|aZtB#9&=)x6(t?(01FJ8yM3&pFS# z)-!8;&iwXo|GW0J_kG{LnaMini+;Er{c#5d;7$z0T^NMBF&Ot?2=2vD+=pSf9}i$S z9>fSdgpqg{qwoku<57&kW5~kecmiYbB*x(>jK|ZMfM+lf&teju!(=>`F6>vBz;s{j2k*JKLPz6V$Dvm)l9E<8W4mEH*PC!kZh*~%awNVFk zaWd-R6r76FP#+C&IvU~(G{Tu^jI+=LXQL_3K{K3-^Kd?z;{sfW7Pts4aWPt;w}ur-588}Fa-BvDDJ~B+>Zw^91mgy9>PdGj8S+5qwy%l z;4x(3aXf*scoO6A6vpFeOu#dkh-Wbg&tWp2#}vGP7cmttVH#dWHeSJWyowok4KwjN zX5kIIiP?AybMQ9i;vLMxyO@vnumJC4AwIw&e29;*7$0K^KEYCaie>l=%keo@;0xs7 zOMHcu_!_J54OZh@tig9!i|?@xKVUt6#0LC?pRp0YU=x1DX8eX+{EjX716#2T+mVL? zhjIO54-~?lD2%;O1bd?>_QAf`55=%QisJwrh!QvmC2=rHp)|_i5R}ECD2KyP9u;sn zD&h!K!jY(qqfiA$qbiO;H5`lTI1V*%JWfDOoQPUD3AIrNb#XH4;S`*T(@-A`a5@^| z3^c--XpFPa1ZSfu&OtMri}P?kn&Sdoh!(gAEpahgp*7mz612soXot(t9vyHwI^qg+ z!jZXZ0|Rg; z2I4LZ!rd5*doTp|VkqvzFx-y^FdPqJ1RlajJd9Cz1f%gN#^5nz;c+~Hv3L^W@D#@5 zX-vQ~n22XF3D03Np2rltfEO_pFJT&9MmAo-bi9fgcnvf0I%eSwyouR(3v=)`=Hea9 z!@HP|_pku(V2|mG6e2QiG49oF3R^SWd;7fdkmG~N~@C{buTdcu% zSc~tm4nJT$e#8d+grBhyzhD!7#b*45T>OqL_yb$94cn220_C~>u?GraPZY*pD1yCF z6#HOb?1y65AH{J14nzqYgpxQIrBE7Wa0trcP?W=AD31y_92Ic{D&a^}#!;w(qfr&d zpc;-vbsUEpI36dUCQd{xoP^q_gSt2w^>7MK#c8OI1~?rJaRwUUOf<$>Xo9oR6z8BB z&c%5+AI)(AE<_7lgqFA%t_xBDL%zAe1_%t94qhza_}X-!b*INRrm(0@h#TiJFLa`Scf059zS9Oe!|b# zh+nV?zhX0fLoR;D7W{#&*oN)MLxBoh|JVbCuqO&*FBHMvD2jcsFZM$*?2qC&00*K3 z4nj#Bj8Z6#GB^ZfaVW~+FqB6H9FB@O0+nziD&r_r!O^ISV^9spqB@R44IGaXP!lJj z7EVHK)InXGjCwc)r{Xl!M+2OWhByO_a3&h#EHuH{Xo_>t4CmrJoR8+X02iVKE<#IO zj83xjYs2IC$K!MzxY`!Edm;{goEgBXE_FcJ@A z6du87Jc==R3|V*_Phc#b#5g>K@pu{&@C+v6Sxmxnn2hH!1ux)5OvOu>hL@3zS1=u~ zVg_ErOuUX+cmr=@Hr~Psbug|H_IV=olJ-YANFurKyQG3<}xH~$D%rpLk%2{6HpT;q83g=KZb5I{iaxjvebEoM zqd)Gz0NjazxC?`DHwNP#48gq^iu*7O_u~N!$AcJwhcFTkV-z02XgrEBcnn#198X{@ zp2Rpjh4FYA6YvZs;#o|>bC`_hF$FK+MNGv@n1+{;jaM)ouVMyX!%V!6S$G3)Vm98w z9K4OWcn9ZHKPp}l9Vi`Wea(s>z_yRfj5?^5@zQ!ti zgVp#JYw#V`;(M&a4_J>Mu>n8fXKchT*o0rP8NVSHzhevjz*cO-cI2TzMXrDBfkN05 zg|QckU~d$~KG+xgp&0f@aU6gHQ33~{Bo0O?ltvjGg0eUi1>0oPtwv8tS6~PDewWfkrqJjd2#5 z;A}L-IcSD+aURY`b6kK6(E=BtB`!uQv_>0Tg0{F6?Qj{|qXRBSM_hqUxDuUl6}sSR zbj3C3hHKFs*P#cl#|`L-8*vkEMh1Ez6Str@Zbcv5hQ8>B+tD9)U;ysKK-`5vxEq6U z4~F1g48?sIhWqgVhT}nuz(W{`hcOC|U^E`Z7(9k7JdP(Y7EfXvp2B!MjR|-L6Y(r2 z;WoH!&M;VGiELT)cyMco*~W9v0wz zEW`&`gb(o%7UN?q!6#UXPq7T2VL3j>3VeYae2K5H5?^B#zQJmIi#7NTYw*o@zhi{G&Ye_$)NVLS4`gSS9I?14hq6NRxCiePUP#Xi^<`=J>2 zM{yj015pA8p(GAQDU?PT9D=eq6yie8i4#!^C!sd#pe{~EJ)DA5aT@BQ0ZvCloPkC-6OC~en&50S#W`q(b8#NdM{`_& z3(*1>p(QRxE3`%%T!OZ^6zy;s+M@$5M@L+NPPh`CaTU7YYIMal=!R?29oL};uE!1N zi5qbfZbk-rArrTtH*Q5A+=jmBhuhH~cVGbS#6aAILAV=(aSw*zUJS*37>4`t0EXj1 zjKD(}iH9)?k6<(&#TYz>EIf`UFcwc@9G=2>JdFu>1{3itCgC|u#`Bnh7w{sc;w4PO z%gDwnn2uL51FvBwUdJrFfj2Q5Z($DJ#$3FEd3YD|@g5f7eJsQWScDJp5fs4r}o}*5L=N$B)>6pYSs_;umbfuh@*= zkc;231%F^GwqZN+z=!Sv1+fPTVNVpsUMPaSQ55@NU+jls*dN7l01iY69E6fM7^P4e zWpD_};!u>sVJMFZI2;vm1S;W3RK`)Lf}>Ft$DkUHMRgp98aN&&pe9a4Eu4hfsDrvV z8TD`qPQ_`cj|Mm$4RHn<;Y>8fS!jZ@(G=&P8P3IdI3LY%0WL%fT!fam7_HD6ZEy+N z;!?E3WoVBMxEvjE1v=qMbjDTaf~(OL*Pt7&MR#0>9=IMipeJs`O}H5u=!Hz&g5J0l zeQ+E4q91NYf82oqxDx|$7Y5;O48}bef_pI(_hA_B#{(FS2QdN2m4|_6vO@~jstKYO5h-r#K91c>E z&a4ovyI`qKxxB)$JBW}XY$UrY-;uiGAt>}Z>&=>u1JNn}e48WZj zh`TTdcVjT_!4TYwp|}sja6cZva6E_+cnBl$Fh=1KjK-rFgU67C$MFQl;z^9dQy7n@ zF#*qDBA&%0Jcr469#ilFUc^+qglTvg*?0xh@hWEEHO$28n1wg+CT8O;%)#53i+3;& z?_xgQ!vegIh4=uA@F70JVtkAx_ykMwDVE_gEXU_qfiIAQFYy&t;%ltJH&~5tu?F8^ zExyM({DAfN5gYIme#S=pf=&1poADcR@jJHQ4{XIYY)2mWWm|!Q*aL;ICkkUP6v5so zihZyz_Cqo3kK#B02ciTHLP;EqQYeiwI0R*JD9Yh5lt%>|j*2(}m2e~~<0w?Y(Wr`J zPz}eTI*vmP9FG%F6DOh;PC{+eL0z1TdN>8A;xyDp1DuYAI0KDvCK}@`G{MO<0^E))#!?A&<)q3 zJFY_yT#p;j6F1@}+>8wLLMCoOZ`_JLxD9>L54WQ~?!W-tiGjEagK#$n;~osby%>u7 zFbwzO0Sw237=ec{5)We(9>HiliZOT$S$G^zU@V@*I6Q^%cp4M%3?|}POu}=RjOQ^0 zFW^N?#Y>ommywNEFdeUA242HVypCCT18-tB-ohNbjk$OS^YAX_<2@|E`&ft%um~UG zBP_#7Kfr74nuiVz~QKfBTxxPqB4#`6&#JKI0n^lEUM!;)WGpL0X11`@dU==NsPl&7>}nh0ncC}p2Z|Qhsk&zQ}6;_#8kY5X?Pjgcm>n( zDrVp{%*5-Mg*WgfX5%f)!P}UNcQ6m{Vm{u(0=$of_yCLWAwI%le2gXd1WWNLmftP52d?@f&jSJGS5t zY{fQgM;`biTY-Yu1BI|B3S%!6!QLo}eXuX~Low`+;y3^Yq67{?NgRw)D2*~W1Z8n3 z%Hc4SM+F>?iZ}w5a3m_@C{)4GsET7y4acH7jzbL`j}uT6C!!WkLT%JRU7U=1I0dKT zG}K1}oQ{S#1C4Md8sjW9!P#hvbI=Uu;yj#>=C}YCq6IEOOI(arXpJ_w1Z{CC+Tk*^ zM+aPvj<^Dya3wn9Ds;is=!$F54cDSOu0s!8j~mbvH{vGTj12TbCT>A*+=@Q94SmrM zx1&GqzyREdfw&8Ua5o0y9t^>~7>fHa4EN&!499~Qfrl^>4`UP_!Du{+F?bAFcpOh) zES|(TJcaRi8WZpgCgNF4!gH96=P?B@;6+TuOPGe2k&Ra{9j{^rUc*ehj#+pEZ(=sy z!W_Jfxp)Wj@Gj=#JuJZcScng>2p{4jEXK!Jf={p%pJEw4!*YC%75D-<_!3`XCBDWg ze1p~a7HjYw*5Z4t!w*=GAF%;H;b&~bFW7`%u^GQ17r$c*{=imj!*=9>Kd=`lh&@mU zd!jJ*LJ{nZqSy!fVm}na{wR(Ea3D(HAe6+xD237}gF{djhoT$~LwQud;i!lsPzgt( zGLAwO9F3|t2GwvZs^d7+!0|W%HE|+p;Uv^X9n{6isE1QgrZ@-9a4ycn`Dl&{a3NaYBDBQCXoc2jgG-hj&hKofwF_FbH>J zFz&$++>4>O55sUj9>8!sh!J=QBk?ds;Sr3+qZot7kcG$b1jgb?jKfnHkEbyK&tM{+ z#Uwn3$#@=9@B&`MRJ?>~cp2Gv1=H~=X5cl<#Os)aH}EEA<1Ng=+n9@YFc0ryKHkFu zypM(W0E_S;KEh&rj3xL4OYtd|;WI49=U9O+kb^Jr6;|SFtim@~jc>6A-(fAj$2$Cg z_4pAR@DqN`F6>vBz;s{j2k*JKLPz6V$Dvm)l9E<8W z4mEH*PC!kZh*~%awNVFkaWd-R6r76FP#+C&IvU~(G{Tu^jI+=LXQL_3K{K3-^Kd?z z;{sfW7Pts4aWPt;w}ur-588}Fa-BvDDJ~B+>Zw^ z91mgy9>PdGj8S+5qwy%l;4x(3aXf*scoO6A6vpFeOu#dkh-Wbg&tWp2#}vGP7cmtt zVH#dWHeSJ-Cv$z{EzH5&n2UEX5AR|=-opaCkA?UEi|`>n!eV@kCHMqO@hO(!Gc3pF zSb;B)gD>$FR^n@{!Z%orZ?Oj7VJ*JLI{bk3_z@fM6Mn`<{DMvR6`S!Ja`8L1;16uY zHf%>8_=j%=3Stiw!k#FMy-);uqbT;lzSs}Nus@39033)CI0z+iFiN2`%HR-`#i1yN z!%!X-a5yUB2vow6sEngf1xKSQjzKjXi|RNIHE=vmKuw&8S~v-{Q3rK#GV0+JoQl&> z9}RFi8sZEz!kK7{v(N-*qbbfoGn|X_a6X#j0$hj|xCkwAFs)`1ovVn?!z$Lj|VUu4`Ku!!bm)fQFsKS@hHaNF=XL!Jb|%z z665d`#^Y&Bz%!VLXE6!SVKSb_6uf{JF%>Ui8eT>=Ucq#{iWztfGx0iR;SIcr*?0?c z@HXb+9n8bKn2-0c0PkZVKENV;h>x%sA7cqV!BTvRW%vxs@i|uD3*_KSe1(kq7?KYk`8;1BI|B z3S%!6!QLo}eXuX~Low`+;y3^Yq67{?NgRw)D2*~W1Z8n3%Hc4SM+F>?iZ}w5a3m_@ zC{)4GsET7y4acH7jzbL`j}uT6C!!WkLT%JRU7U=1I0dKTG}K1}oQ{S#1C4Md8sjW9 z!P#hvbI=Uu;yj#>=C}YCq6IEOOI(arXpJ_w1Z{CC+Tk*^M+aPvj<^Dya3wn9Ds;is z=!$F54cDSOu0s!8j~mbvH{vGTj12TbCT>A*+=@Q94SmrMx1&GqzyREdfw&8Ua5o0y z9t^>~7>fHa4EN&!499~Qfrl^>4`UP_!Du{+F?bAFcpOh)ES|(TJcaRi8WZpgCgNF4 z!gH96=P?B@;6+TuOPGe2k&Ra{9j{^rUc*ehj#+pEZ(=sy!W_Jfxp)Wj@Gj=#JuJZc zScng>2p{4jEXK!Jf={p%pJEw4!*YC%75D-<_!3`XCBDWge1p~a7HjYw*5Z4t!w*=G zAF%;H;b&~bFW7`%u^GQ17r$c*{=imj!*=9>fAC(QAof5Z?1{qI3q`Ouieew^i~Udx z`=dAxz=0@%gHRF&qZCS`3=TnA9Ex%{4CPS)hod5nKqVZB$~X#Da5Spo7*xZtsE*@M z1IOb8)WnIXg_BSlbx;>4qaIGdsW=Vw(Ez8TAOd+4{k$W^uz7wk2^2`cVZy!!XVs@!MF!Qa4&}9J`BVCcmTuk zAV%OJjKsqjg-0+Nk75iSLlz##6BvspF%C~*Jf6k`JcEgN7L)KCCgXWb!3%g1Q}Gg} z;bmmw6->vgn1R72B{KdEh^GDNqo5pb+*%VeEw>*c(N$5B9}=D2Dw}90%Y)l)ynKiGxuJ zrBMclpeznWIUI)asDQ&!5l5gBjznb~g(^52RdEce;aF71aj1dgaRO@MMAX7bsEs

!3U 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 From d6660180730d538cacfa5f5bbd2e81f26462b31a Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 24 Jan 2025 17:55:05 -0500 Subject: [PATCH 13/57] Add Ed25519 curve to the guest library --- examples/ecc/src/main.rs | 2 + extensions/ecc/guest/Cargo.toml | 1 + extensions/ecc/guest/src/ed25519.rs | 80 ++++++++++++++ extensions/ecc/guest/src/lib.rs | 3 + extensions/ecc/tests/programs/Cargo.toml | 5 + .../ecc/tests/programs/examples/edwards_ec.rs | 102 +++++------------- extensions/ecc/tests/src/lib.rs | 2 +- 7 files changed, 116 insertions(+), 79 deletions(-) create mode 100644 extensions/ecc/guest/src/ed25519.rs diff --git a/examples/ecc/src/main.rs b/examples/ecc/src/main.rs index fed901c814..499c7ecee2 100644 --- a/examples/ecc/src/main.rs +++ b/examples/ecc/src/main.rs @@ -50,6 +50,8 @@ const CURVE_D: Edwards25519Coord = Edwards25519Coord::from_const_bytes([ 64, 199, 140, 115, 254, 111, 43, 238, 108, 3, 82, ]); +// Note that we are defining the Edwards25519 curve for illustrative purposes only. +// In practice, we would use the ed25519 module which defines the Edwards25519 curve for us. openvm_ecc_guest::te_setup::te_declare! { Edwards25519Point { mod_type = Edwards25519Coord, diff --git a/extensions/ecc/guest/Cargo.toml b/extensions/ecc/guest/Cargo.toml index 5870b10c92..f997b7213c 100644 --- a/extensions/ecc/guest/Cargo.toml +++ b/extensions/ecc/guest/Cargo.toml @@ -26,6 +26,7 @@ group = "0.13.0" [features] default = [] +ed25519 = [] halo2curves = ["dep:halo2curves-axiom", "openvm-algebra-guest/halo2curves"] std = ["alloc"] alloc = [] diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs new file mode 100644 index 0000000000..0ddaee024c --- /dev/null +++ b/extensions/ecc/guest/src/ed25519.rs @@ -0,0 +1,80 @@ +use hex_literal::hex; +#[cfg(not(target_os = "zkvm"))] +use lazy_static::lazy_static; +#[cfg(not(target_os = "zkvm"))] +use num_bigint::BigUint; +use openvm_algebra_guest::{Field, IntMod}; + +use super::group::{CyclicGroup, Group}; + +#[cfg(not(target_os = "zkvm"))] +lazy_static! { + pub static ref Ed25519_MODULUS: BigUint = BigUint::from_bytes_be(&hex!( + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED" + )); + pub static ref Ed25519_ORDER: BigUint = BigUint::from_bytes_be(&hex!( + "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED" + )); + pub static ref Ed25519_A: BigUint = BigUint::from_bytes_be(&hex!( + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC" + )); + pub static ref Ed25519_D: BigUint = BigUint::from_bytes_be(&hex!( + "52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3" + )); +} + +openvm_algebra_moduli_setup::moduli_declare! { + Ed25519Coord { modulus = "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED" }, + Ed25519Scalar { modulus = "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED" }, +} + +pub const ED25519_NUM_LIMBS: usize = 32; +pub const ED25519_LIMB_BITS: usize = 8; +pub const ED25519_BLOCK_SIZE: usize = 32; +// from_const_bytes is little endian +pub const CURVE_A: Ed25519Coord = Ed25519Coord::from_const_bytes(hex!( + "ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F" +)); +pub const CURVE_D: Ed25519Coord = Ed25519Coord::from_const_bytes(hex!( + "A3785913CA4DEB75ABD841414D0A700098E879777940C78C73FE6F2BEE6C0352" +)); + +openvm_ecc_te_setup::te_declare! { + Ed25519Point { mod_type = Ed25519Coord, a = CURVE_A, d = CURVE_D }, +} + +impl Field for Ed25519Coord { + const ZERO: Self = ::ZERO; + const ONE: Self = ::ONE; + + type SelfRef<'a> = &'a Self; + + fn double_assign(&mut self) { + IntMod::double_assign(self); + } + + fn square_assign(&mut self) { + IntMod::square_assign(self); + } +} + +impl CyclicGroup for Ed25519Point { + // from_const_bytes is little endian + const GENERATOR: Self = Ed25519Point { + x: Ed25519Coord::from_const_bytes(hex!( + "1AD5258F602D56C9B2A7259560C72C695CDCD6FD31E2A4C0FE536ECDD3366921" + )), + y: Ed25519Coord::from_const_bytes(hex!( + "5866666666666666666666666666666666666666666666666666666666666666" + )), + }; + // TODO: fix + const NEG_GENERATOR: Self = Ed25519Point { + x: Ed25519Coord::from_const_bytes(hex!( + "1AD5258F602D56C9B2A7259560C72C695CDCD6FD31E2A4C0FE536ECDD3366921" + )), + y: Ed25519Coord::from_const_bytes(hex!( + "5866666666666666666666666666666666666666666666666666666666666666" + )), + }; +} diff --git a/extensions/ecc/guest/src/lib.rs b/extensions/ecc/guest/src/lib.rs index 7f70d63ab0..c829b890b6 100644 --- a/extensions/ecc/guest/src/lib.rs +++ b/extensions/ecc/guest/src/lib.rs @@ -23,6 +23,9 @@ pub mod edwards; /// Weierstrass curve traits pub mod weierstrass; +#[cfg(feature = "ed25519")] +pub mod ed25519; + /// This is custom-1 defined in RISC-V spec document pub const SW_OPCODE: u8 = 0x2b; pub const SW_FUNCT3: u8 = 0b001; diff --git a/extensions/ecc/tests/programs/Cargo.toml b/extensions/ecc/tests/programs/Cargo.toml index 8f53bf5ae1..6572da4328 100644 --- a/extensions/ecc/tests/programs/Cargo.toml +++ b/extensions/ecc/tests/programs/Cargo.toml @@ -38,6 +38,7 @@ default = [] std = ["serde/std", "openvm/std"] k256 = ["dep:openvm-k256"] p256 = ["dep:openvm-p256"] +ed25519 = ["openvm-ecc-guest/ed25519"] [profile.release] panic = "abort" @@ -64,6 +65,10 @@ required-features = ["k256"] name = "ecdsa" required-features = ["k256"] +[[example]] +name = "edwards_ec" +required-features = ["ed25519"] + [[example]] name = "invalid_setup" required-features = ["k256", "p256"] diff --git a/extensions/ecc/tests/programs/examples/edwards_ec.rs b/extensions/ecc/tests/programs/examples/edwards_ec.rs index 03aa0e4e79..438b21fb00 100644 --- a/extensions/ecc/tests/programs/examples/edwards_ec.rs +++ b/extensions/ecc/tests/programs/examples/edwards_ec.rs @@ -1,108 +1,54 @@ #![cfg_attr(not(feature = "std"), no_main)] #![cfg_attr(not(feature = "std"), no_std)] -use core::str::FromStr; - -use num_bigint::BigUint; -use openvm_algebra_guest::{ - moduli_setup::{moduli_declare, moduli_init}, - Field, IntMod, -}; +use hex_literal::hex; +use openvm_algebra_guest::{moduli_setup::moduli_init, IntMod}; use openvm_ecc_guest::{ + ed25519::{Ed25519Coord, Ed25519Point}, edwards::TwistedEdwardsPoint, - te_setup::{te_declare, te_init}, - Group, + te_setup::te_init, + CyclicGroup, Group, }; -moduli_declare! { - Edwards25519Coord { modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" }, -} - moduli_init! { "57896044618658097711785492504343953926634992332820282019728792003956564819949", } -impl Field for Edwards25519Coord { - const ZERO: Self = ::ZERO; - const ONE: Self = ::ONE; - - type SelfRef<'a> = &'a Self; - - fn double_assign(&mut self) { - IntMod::double_assign(self); - } - - fn square_assign(&mut self) { - IntMod::square_assign(self); - } -} - -// a = 57896044618658097711785492504343953926634992332820282019728792003956564819948 -// d = 37095705934669439343138083508754565189542113879843219016388785533085940283555 -// encoded in little endian, 32 limbs of 8 bits each -const CURVE_A: Edwards25519Coord = Edwards25519Coord::from_const_bytes([ - 236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, -]); -const CURVE_D: Edwards25519Coord = Edwards25519Coord::from_const_bytes([ - 163, 120, 89, 19, 202, 77, 235, 117, 171, 216, 65, 65, 77, 10, 112, 0, 152, 232, 121, 119, 121, - 64, 199, 140, 115, 254, 111, 43, 238, 108, 3, 82, -]); - -te_declare! { - Edwards25519Point { - mod_type = Edwards25519Coord, - a = CURVE_A, - d = CURVE_D - } -} - te_init! { - Edwards25519Point, + Ed25519Point, } openvm::entry!(main); -fn string_to_coord(s: &str) -> Edwards25519Coord { - Edwards25519Coord::from_le_bytes(&BigUint::from_str(s).unwrap().to_bytes_le()) -} - pub fn main() { setup_all_moduli(); setup_all_te_curves(); // Base point of edwards25519 - let x1 = string_to_coord( - "15112221349535400772501151409588531511454012693041857206046113283949847762202", - ); - let y1 = string_to_coord( - "46316835694926478169428394003475163141307993866256225615783033603165251855960", - ); + let mut p1 = Ed25519Point::GENERATOR; // random point on edwards25519 - let x2 = Edwards25519Coord::from_u32(2); - let y2 = string_to_coord( - "11879831548380997166425477238087913000047176376829905612296558668626594440753", - ); + let x2 = Ed25519Coord::from_u32(2); + let y2 = Ed25519Coord::from_be_bytes(&hex!( + "1A43BF127BDDC4D71FF910403C11DDB5BA2BCDD2815393924657EF111E712631" + )); + let mut p2 = Ed25519Point::from_xy(x2, y2).unwrap(); // This is the sum of (x1, y1) and (x2, y2). - let x3 = string_to_coord( - "44969869612046584870714054830543834361257841801051546235130567688769346152934", - ); - let y3 = string_to_coord( - "50796027728050908782231253190819121962159170739537197094456293084373503699602", - ); + let x3 = Ed25519Coord::from_be_bytes(&hex!( + "636C0B519B2C5B1E0D3BFD213F45AFD5DAEE3CECC9B68CF88615101BC78329E6" + )); + let y3 = Ed25519Coord::from_be_bytes(&hex!( + "704D8868CB335A7B609D04B9CD619511675691A78861F1DFF7A5EBC389C7EA92" + )); // This is 2 * (x1, y1) - let x4 = string_to_coord( - "39226743113244985161159605482495583316761443760287217110659799046557361995496", - ); - let y4 = string_to_coord( - "12570354238812836652656274015246690354874018829607973815551555426027032771563", - ); - - let mut p1 = Edwards25519Point::from_xy(x1.clone(), y1.clone()).unwrap(); - let mut p2 = Edwards25519Point::from_xy(x2, y2).unwrap(); + let x4 = Ed25519Coord::from_be_bytes(&hex!( + "56B98CC045559AD2BBC45CAB58D842ECEE264DB9395F6014B772501B62BB7EE8" + )); + let y4 = Ed25519Coord::from_be_bytes(&hex!( + "1BCA918096D89C83A15105DF343DC9F7510494407750226DAC0A7620ACE77BEB" + )); // Generic add can handle equal or unequal points. let p3 = &p1 + &p2; diff --git a/extensions/ecc/tests/src/lib.rs b/extensions/ecc/tests/src/lib.rs index a4d981b719..1931a86f3b 100644 --- a/extensions/ecc/tests/src/lib.rs +++ b/extensions/ecc/tests/src/lib.rs @@ -205,7 +205,7 @@ mod tests { let elf = build_example_program_at_path_with_features::<&str>( get_programs_dir!(), "edwards_ec", - [], + ["ed25519"], )?; let openvm_exe = VmExe::from_elf( elf, From 1a9aa831b65ee76ef7e3517e40815bfefd0a3219 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 24 Jan 2025 19:46:21 -0500 Subject: [PATCH 14/57] bugs --- extensions/ecc/te-setup/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/ecc/te-setup/src/lib.rs b/extensions/ecc/te-setup/src/lib.rs index aaf7f7d489..614f56370e 100644 --- a/extensions/ecc/te-setup/src/lib.rs +++ b/extensions/ecc/te-setup/src/lib.rs @@ -109,14 +109,14 @@ pub fn te_declare(input: TokenStream) -> TokenStream { { use openvm_algebra_guest::DivUnsafe; - let x1y2 = p1.x() * p2.y(); - let y1x2 = p1.y() * p2.x(); - let x1x2 = p1.x() * p2.x(); - let y1y2 = p1.y() * p2.y(); - let dx1x2y1y2 = Self::CURVE_D * &x1x2 * &y1y2; + let x1y2 = p1.x.clone() * p2.y.clone(); + let y1x2 = p1.y.clone() * p2.x.clone(); + let x1x2 = p1.x.clone() * p2.x.clone(); + let y1y2 = p1.y.clone() * p2.y.clone(); + let dx1x2y1y2 = ::CURVE_D * &x1x2 * &y1y2; let x3 = (x1y2 + y1x2).div_unsafe(&<#intmod_type as openvm_algebra_guest::IntMod>::ONE + &dx1x2y1y2); - let y3 = (y1y2 - Self::CURVE_A * x1x2).div_unsafe(&<#intmod_type as openvm_algebra_guest::IntMod>::ONE - &dx1x2y1y2); + let y3 = (y1y2 - ::CURVE_A * x1x2).div_unsafe(&<#intmod_type as openvm_algebra_guest::IntMod>::ONE - &dx1x2y1y2); #struct_name { x: x3, y: y3 } } From 084daf9f87c05f83fbcddbf87b221e3e0e3966ef Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 27 Jan 2025 18:13:30 -0500 Subject: [PATCH 15/57] Move IntrinsicCurve trait definition to lib.rs (since it's common to weierstrass and edwards curves) --- extensions/ecc/guest/src/ecdsa.rs | 4 ++-- extensions/ecc/guest/src/ed25519.rs | 1 + extensions/ecc/guest/src/lib.rs | 12 ++++++++++++ extensions/ecc/guest/src/weierstrass.rs | 14 +------------- guest-libs/k256/src/internal.rs | 4 ++-- guest-libs/p256/src/internal.rs | 4 ++-- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/extensions/ecc/guest/src/ecdsa.rs b/extensions/ecc/guest/src/ecdsa.rs index b9cac8e4e7..47cc5ab415 100644 --- a/extensions/ecc/guest/src/ecdsa.rs +++ b/extensions/ecc/guest/src/ecdsa.rs @@ -20,8 +20,8 @@ use elliptic_curve::{ use openvm_algebra_guest::{DivUnsafe, IntMod, Reduce}; use crate::{ - weierstrass::{FromCompressed, IntrinsicCurve, WeierstrassPoint}, - CyclicGroup, Group, + weierstrass::{FromCompressed, WeierstrassPoint}, + CyclicGroup, Group, IntrinsicCurve, }; type Coordinate = <::Point as WeierstrassPoint>::Coordinate; diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs index 0ddaee024c..a13a9d44fb 100644 --- a/extensions/ecc/guest/src/ed25519.rs +++ b/extensions/ecc/guest/src/ed25519.rs @@ -6,6 +6,7 @@ use num_bigint::BigUint; use openvm_algebra_guest::{Field, IntMod}; use super::group::{CyclicGroup, Group}; +use crate::IntrinsicCurve; #[cfg(not(target_os = "zkvm"))] lazy_static! { diff --git a/extensions/ecc/guest/src/lib.rs b/extensions/ecc/guest/src/lib.rs index c829b890b6..81587c24f0 100644 --- a/extensions/ecc/guest/src/lib.rs +++ b/extensions/ecc/guest/src/lib.rs @@ -60,3 +60,15 @@ pub enum TeBaseFunct7 { impl TeBaseFunct7 { pub const TWISTED_EDWARDS_MAX_KINDS: u8 = 8; } + +/// A trait for elliptic curves that bridges the openvm types and external types with CurveArithmetic etc. +/// Implement this for external curves with corresponding openvm point and scalar types. +pub trait IntrinsicCurve { + type Scalar: Clone; + type Point: Clone; + + /// Multi-scalar multiplication. + /// The implementation may be specialized to use properties of the curve + /// (e.g., if the curve order is prime). + fn msm(coeffs: &[Self::Scalar], bases: &[Self::Point]) -> Self::Point; +} diff --git a/extensions/ecc/guest/src/weierstrass.rs b/extensions/ecc/guest/src/weierstrass.rs index b74d6aaf6d..3d06d3ed98 100644 --- a/extensions/ecc/guest/src/weierstrass.rs +++ b/extensions/ecc/guest/src/weierstrass.rs @@ -4,6 +4,7 @@ use core::ops::Mul; use openvm_algebra_guest::{Field, IntMod}; use super::group::Group; +use crate::IntrinsicCurve; /// Short Weierstrass curve affine point. pub trait WeierstrassPoint: Clone + Sized { @@ -124,19 +125,6 @@ pub trait FromCompressed { Self: core::marker::Sized; } -/// A trait for elliptic curves that bridges the openvm types and external types with -/// CurveArithmetic etc. Implement this for external curves with corresponding openvm point and -/// scalar types. -pub trait IntrinsicCurve { - type Scalar: Clone; - type Point: Clone; - - /// Multi-scalar multiplication. - /// The implementation may be specialized to use properties of the curve - /// (e.g., if the curve order is prime). - fn msm(coeffs: &[Self::Scalar], bases: &[Self::Point]) -> Self::Point; -} - // MSM using preprocessed table (windowed method) // Reference: modified from https://github.com/arkworks-rs/algebra/blob/master/ec/src/scalar_mul/mod.rs // diff --git a/guest-libs/k256/src/internal.rs b/guest-libs/k256/src/internal.rs index b8f8857dc9..868bce2cd5 100644 --- a/guest-libs/k256/src/internal.rs +++ b/guest-libs/k256/src/internal.rs @@ -4,8 +4,8 @@ use hex_literal::hex; use openvm_algebra_guest::IntMod; use openvm_algebra_moduli_macros::moduli_declare; use openvm_ecc_guest::{ - weierstrass::{CachedMulTable, IntrinsicCurve, WeierstrassPoint}, - CyclicGroup, Group, + weierstrass::{CachedMulTable, WeierstrassPoint}, + CyclicGroup, Group, IntrinsicCurve, }; use openvm_ecc_sw_macros::sw_declare; diff --git a/guest-libs/p256/src/internal.rs b/guest-libs/p256/src/internal.rs index b98c401c8c..7db8f868c6 100644 --- a/guest-libs/p256/src/internal.rs +++ b/guest-libs/p256/src/internal.rs @@ -4,8 +4,8 @@ use hex_literal::hex; use openvm_algebra_guest::IntMod; use openvm_algebra_moduli_macros::moduli_declare; use openvm_ecc_guest::{ - weierstrass::{CachedMulTable, IntrinsicCurve, WeierstrassPoint}, - CyclicGroup, Group, + weierstrass::{CachedMulTable, WeierstrassPoint}, + CyclicGroup, Group, IntrinsicCurve, }; use openvm_ecc_sw_macros::sw_declare; From 4933d50e62fc8c675faf3b82f514869bb874460c Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 27 Jan 2025 18:14:02 -0500 Subject: [PATCH 16/57] Implement IntrinsicCurve trivially for ed25519 --- extensions/ecc/guest/src/ed25519.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs index a13a9d44fb..868d3ed3e3 100644 --- a/extensions/ecc/guest/src/ed25519.rs +++ b/extensions/ecc/guest/src/ed25519.rs @@ -79,3 +79,13 @@ impl CyclicGroup for Ed25519Point { )), }; } + +impl IntrinsicCurve for Ed25519Point { + type Scalar = Ed25519Scalar; + type Point = Ed25519Point; + + fn msm(coeffs: &[Self::Scalar], bases: &[Self::Point]) -> Self::Point { + // TODO: idk if this can be optimized + openvm_ecc_guest::msm(coeffs, bases) + } +} From 380f7d131b851ee365af55b0d37b51438a3492e1 Mon Sep 17 00:00:00 2001 From: Avaneesh-axiom Date: Tue, 28 Jan 2025 11:38:15 -0500 Subject: [PATCH 17/57] Update book/src/custom-extensions/ecc.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/custom-extensions/ecc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/custom-extensions/ecc.md b/book/src/custom-extensions/ecc.md index 1f5599f6de..c9a1d56ef3 100644 --- a/book/src/custom-extensions/ecc.md +++ b/book/src/custom-extensions/ecc.md @@ -39,7 +39,7 @@ The secp256k1 and secp256r1 curves are supported out of the box, and developers For elliptic curve cryptography, the `openvm-ecc-guest` crate provides macros similar to those in [`openvm-algebra-guest`](./algebra.md): -1. **Declare**: Use `sw_declare!` or `te_declare!` to define weierstrass or twisted edwards elliptic curves, respectively,over the previously declared moduli. For example: +1. **Declare**: Use `sw_declare!` or `te_declare!` to define short Weierstrass or twisted Edwards elliptic curves, respectively, over the previously declared moduli. For example: ```rust sw_declare! { From a48b6023c66e39d837e434073f821b1eb66c0054 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Tue, 28 Jan 2025 11:39:31 -0500 Subject: [PATCH 18/57] Remove num-bigint-dig dependancy --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index afb0a76cd8..e1e90656da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -243,7 +243,6 @@ k256 = { version = "0.13.4", default-features = false } elliptic-curve = { version = "0.13.8", default-features = false } ecdsa-core = { version = "0.16.9", package = "ecdsa", default-features = false } num-bigint = { version = "0.4.6", default-features = false } -num-bigint-dig = { version = "0.8.4", default-features = false } num-integer = { version = "0.1.46", default-features = false } num-traits = { version = "0.2.19", default-features = false } ff = { version = "0.13.1", default-features = false } From b0a24f34ed26ce66bcf09c3e661e60f9b3ece7d7 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Tue, 28 Jan 2025 18:38:05 -0500 Subject: [PATCH 19/57] Add decompression hints for ed25519 and rewrite curve config A bug involving opcode collisions between short Weierstrass and twisted Edwards curves was found. To fix this, CurveConfig was rewritten and separate opcodes were given to the two types of curves. --- Cargo.lock | 1 + examples/ecc/openvm.toml | 12 +- examples/ecc/src/main.rs | 6 +- extensions/ecc/circuit/src/config.rs | 14 +- extensions/ecc/circuit/src/ecc_extension.rs | 323 +++++++++--------- extensions/ecc/guest/src/ecdsa.rs | 5 +- extensions/ecc/guest/src/ed25519.rs | 8 +- extensions/ecc/guest/src/lib.rs | 27 +- extensions/ecc/te-setup/src/lib.rs | 56 ++- extensions/ecc/tests/Cargo.toml | 1 + extensions/ecc/tests/programs/Cargo.toml | 3 +- .../ecc/tests/programs/examples/decompress.rs | 23 +- extensions/ecc/tests/src/lib.rs | 44 ++- extensions/ecc/transpiler/src/lib.rs | 35 +- extensions/pairing/circuit/src/config.rs | 5 +- .../pairing/circuit/src/pairing_extension.rs | 12 +- guest-libs/pairing/tests/lib.rs | 4 +- 17 files changed, 347 insertions(+), 232 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcf9528769..c2a331e086 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4720,6 +4720,7 @@ dependencies = [ "hex-literal 0.4.1", "num-bigint 0.4.6", "openvm-algebra-circuit", + "openvm-algebra-guest", "openvm-algebra-transpiler", "openvm-circuit", "openvm-ecc-circuit", diff --git a/examples/ecc/openvm.toml b/examples/ecc/openvm.toml index df7cd4524a..e23efc9d5f 100644 --- a/examples/ecc/openvm.toml +++ b/examples/ecc/openvm.toml @@ -2,23 +2,21 @@ [app_vm_config.rv32m] [app_vm_config.io] [app_vm_config.modular] -supported_moduli = ["115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337"] +supported_moduli = ["115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337", "57896044618658097711785492504343953926634992332820282019728792003956564819949"] -[[app_vm_config.ecc.supported_curves]] +[[app_vm_config.ecc.supported_sw_curves]] struct_name = "Secp256k1Point" modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" -[app_vm_config.ecc.supported_curves.coeffs] -type = "SwCurve" +[app_vm_config.ecc.supported_sw_curves.coeffs] a = "0" b = "7" -[[app_vm_config.ecc.supported_curves]] +[[app_vm_config.ecc.supported_te_curves]] modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" scalar = "7237005577332262213973186563042994240857116359379907606001950938285454250989" -[app_vm_config.ecc.supported_curves.coeffs] -type = "TeCurve" +[app_vm_config.ecc.supported_te_curves.coeffs] a = "57896044618658097711785492504343953926634992332820282019728792003956564819948" d = "37095705934669439343138083508754565189542113879843219016388785533085940283555" diff --git a/examples/ecc/src/main.rs b/examples/ecc/src/main.rs index 499c7ecee2..81440faa17 100644 --- a/examples/ecc/src/main.rs +++ b/examples/ecc/src/main.rs @@ -87,16 +87,16 @@ pub fn main() { #[allow(clippy::op_ref)] let _p3 = &p1 + &p2; - let x1 = Edwards25519Coord::from_le_bytes(&hex!( + let x1 = Edwards25519Coord::from_be_bytes(&hex!( "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" )); - let y1 = Edwards25519Coord::from_le_bytes(&hex!( + let y1 = Edwards25519Coord::from_be_bytes(&hex!( "6666666666666666666666666666666666666666666666666666666666666658" )); let p1 = Edwards25519Point::from_xy(x1, y1).unwrap(); let x2 = Edwards25519Coord::from_u32(2); - let y2 = Edwards25519Coord::from_le_bytes(&hex!( + let y2 = Edwards25519Coord::from_be_bytes(&hex!( "1A43BF127BDDC4D71FF910403C11DDB5BA2BCDD2815393924657EF111E712631" )); let p2 = Edwards25519Point::from_xy(x2, y2).unwrap(); diff --git a/extensions/ecc/circuit/src/config.rs b/extensions/ecc/circuit/src/config.rs index 67d9f74609..1477ea9e70 100644 --- a/extensions/ecc/circuit/src/config.rs +++ b/extensions/ecc/circuit/src/config.rs @@ -24,18 +24,26 @@ pub struct Rv32EccConfig { } impl Rv32EccConfig { - pub fn new(curves: Vec) -> Self { - let primes: Vec<_> = curves + pub fn new( + sw_curves: Vec>, + te_curves: Vec>, + ) -> Self { + let sw_primes: Vec<_> = sw_curves .iter() .flat_map(|c| [c.modulus.clone(), c.scalar.clone()]) .collect(); + let te_primes: Vec<_> = te_curves + .iter() + .flat_map(|c| [c.modulus.clone(), c.scalar.clone()]) + .collect(); + let primes = sw_primes.into_iter().chain(te_primes).collect(); Self { system: SystemConfig::default().with_continuations(), base: Default::default(), mul: Default::default(), io: Default::default(), modular: ModularExtension::new(primes), - ecc: EccExtension::new(curves), + ecc: EccExtension::new(sw_curves, te_curves), } } } diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index 058b628edd..fa380990b2 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -13,6 +13,7 @@ use openvm_circuit_primitives::bitwise_op_lookup::{ }; use openvm_circuit_primitives_derive::{BytesStateful, Chip, ChipUsageGetter}; use openvm_ecc_guest::{ + ed25519::{CURVE_A as ED25519_A, CURVE_D as ED25519_D, ED25519_MODULUS, ED25519_ORDER}, k256::{SECP256K1_MODULUS, SECP256K1_ORDER}, p256::{CURVE_A as P256_A, CURVE_B as P256_B, P256_MODULUS, P256_ORDER}, }; @@ -29,7 +30,7 @@ use super::{SwAddNeChip, SwDoubleChip, TeAddChip}; #[serde_as] #[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] -pub struct CurveConfig { +pub struct CurveConfig { /// The name of the curve struct as defined by moduli_declare. pub struct_name: String, /// The coordinate modulus of the curve. @@ -39,20 +40,12 @@ pub struct CurveConfig { #[serde_as(as = "DisplayFromStr")] pub scalar: BigUint, // curve-specific coefficients - #[serde_as(as = "_")] - pub coeffs: CurveCoeffs, -} - -#[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] -#[serde(tag = "type")] -pub enum CurveCoeffs { - SwCurve(SwCurveConfig), - TeCurve(TeCurveConfig), + pub coeffs: T, } #[serde_as] #[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] -pub struct SwCurveConfig { +pub struct SwCurveCoeffs { /// The coefficient a of y^2 = x^3 + ax + b. #[serde_as(as = "DisplayFromStr")] pub a: BigUint, @@ -63,7 +56,7 @@ pub struct SwCurveConfig { #[serde_as] #[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] -pub struct TeCurveConfig { +pub struct TeCurveCoeffs { /// The coefficient a of ax^2 + y^2 = 1 + dx^2y^2 #[serde_as(as = "DisplayFromStr")] pub a: BigUint, @@ -72,27 +65,37 @@ pub struct TeCurveConfig { pub d: BigUint, } -pub static SECP256K1_CONFIG: Lazy = Lazy::new(|| CurveConfig { +pub static SECP256K1_CONFIG: Lazy> = Lazy::new(|| CurveConfig { modulus: SECP256K1_MODULUS.clone(), scalar: SECP256K1_ORDER.clone(), - coeffs: CurveCoeffs::SwCurve(SwCurveConfig { + coeffs: SwCurveCoeffs { a: BigUint::zero(), b: BigUint::from_u8(7u8).unwrap(), - }), + }, }); -pub static P256_CONFIG: Lazy = Lazy::new(|| CurveConfig { +pub static P256_CONFIG: Lazy> = Lazy::new(|| CurveConfig { modulus: P256_MODULUS.clone(), scalar: P256_ORDER.clone(), - coeffs: CurveCoeffs::SwCurve(SwCurveConfig { + coeffs: SwCurveCoeffs { a: BigUint::from_bytes_le(P256_A.as_le_bytes()), b: BigUint::from_bytes_le(P256_B.as_le_bytes()), - }), + }, +}); + +pub static ED25519_CONFIG: Lazy> = Lazy::new(|| CurveConfig { + modulus: ED25519_MODULUS.clone(), + scalar: ED25519_ORDER.clone(), + coeffs: TeCurveCoeffs { + a: BigUint::from_bytes_le(ED25519_A.as_le_bytes()), + d: BigUint::from_bytes_le(ED25519_D.as_le_bytes()), + }, }); #[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] pub struct EccExtension { - pub supported_curves: Vec, + pub supported_sw_curves: Vec>, + pub supported_te_curves: Vec>, } #[derive(Chip, ChipUsageGetter, InstructionExecutor, AnyEnum, BytesStateful)] @@ -152,12 +155,108 @@ impl VmExtension for EccExtension { let te_add_opcodes = (Rv32EdwardsOpcode::EC_ADD as usize)..=(Rv32EdwardsOpcode::SETUP_EC_ADD as usize); - for (i, curve) in self.supported_curves.iter().enumerate() { + for (sw_idx, curve) in self.supported_sw_curves.iter().enumerate() { + let bytes = curve.modulus.bits().div_ceil(8); + let config32 = ExprBuilderConfig { + modulus: curve.modulus.clone(), + num_limbs: 32, + limb_bits: 8, + }; + let config48 = ExprBuilderConfig { + modulus: curve.modulus.clone(), + num_limbs: 48, + limb_bits: 8, + }; + // TODO: Better support for different limb sizes. Currently only 32 or 48 limbs are + // supported. let sw_start_offset = - Rv32WeierstrassOpcode::CLASS_OFFSET + i * Rv32WeierstrassOpcode::COUNT; - // right now this is the same as sw_class_offset - let te_start_offset = Rv32EdwardsOpcode::CLASS_OFFSET + i * Rv32EdwardsOpcode::COUNT; + Rv32WeierstrassOpcode::CLASS_OFFSET + sw_idx * Rv32WeierstrassOpcode::COUNT; + if bytes <= 32 { + let sw_add_ne_chip = SwAddNeChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + config32.clone(), + sw_start_offset, + range_checker.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + EccExtensionExecutor::SwEcAddNeRv32_32(sw_add_ne_chip), + sw_add_ne_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), + )?; + let sw_double_chip = SwDoubleChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + range_checker.clone(), + config32.clone(), + sw_start_offset, + curve.coeffs.a.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + EccExtensionExecutor::SwEcDoubleRv32_32(sw_double_chip), + sw_double_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), + )?; + } else if bytes <= 48 { + let sw_add_ne_chip = SwAddNeChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + config48.clone(), + sw_start_offset, + range_checker.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + EccExtensionExecutor::SwEcAddNeRv32_48(sw_add_ne_chip), + sw_add_ne_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), + )?; + let sw_double_chip = SwDoubleChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + range_checker.clone(), + config48.clone(), + sw_start_offset, + curve.coeffs.a.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + EccExtensionExecutor::SwEcDoubleRv32_48(sw_double_chip), + sw_double_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), + )?; + } else { + panic!("Modulus too large"); + } + } + for (te_idx, curve) in self.supported_te_curves.iter().enumerate() { let bytes = curve.modulus.bits().div_ceil(8); let config32 = ExprBuilderConfig { modulus: curve.modulus.clone(), @@ -169,142 +268,52 @@ impl VmExtension for EccExtension { num_limbs: 48, limb_bits: 8, }; + let te_start_offset = + Rv32EdwardsOpcode::CLASS_OFFSET + te_idx * Rv32EdwardsOpcode::COUNT; if bytes <= 32 { - match curve.coeffs.clone() { - CurveCoeffs::SwCurve(SwCurveConfig { a, b: _ }) => { - let sw_add_ne_chip = SwAddNeChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - config32.clone(), - sw_start_offset, - range_checker.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - EccExtensionExecutor::SwEcAddNeRv32_32(sw_add_ne_chip), - sw_add_ne_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + sw_start_offset)), - )?; - let sw_double_chip = SwDoubleChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - range_checker.clone(), - config32.clone(), - sw_start_offset, - a.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - EccExtensionExecutor::SwEcDoubleRv32_32(sw_double_chip), - sw_double_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + sw_start_offset)), - )?; - } - - CurveCoeffs::TeCurve(TeCurveConfig { a, d }) => { - let te_add_chip = TeAddChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - config32.clone(), - te_start_offset, - a.clone(), - d.clone(), - range_checker.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - EccExtensionExecutor::TeEcAddRv32_32(te_add_chip), - te_add_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + te_start_offset)), - )?; - } - } + let te_add_chip = TeAddChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + config32.clone(), + te_start_offset, + curve.coeffs.a.clone(), + curve.coeffs.d.clone(), + range_checker.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + EccExtensionExecutor::TeEcAddRv32_32(te_add_chip), + te_add_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + te_start_offset)), + )?; } else if bytes <= 48 { - match curve.coeffs.clone() { - CurveCoeffs::SwCurve(SwCurveConfig { a, b: _ }) => { - let sw_add_ne_chip = SwAddNeChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - config48.clone(), - sw_start_offset, - range_checker.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - EccExtensionExecutor::SwEcAddNeRv32_48(sw_add_ne_chip), - sw_add_ne_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + sw_start_offset)), - )?; - let sw_double_chip = SwDoubleChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - range_checker.clone(), - config48.clone(), - sw_start_offset, - a.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - EccExtensionExecutor::SwEcDoubleRv32_48(sw_double_chip), - sw_double_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + sw_start_offset)), - )?; - } - - CurveCoeffs::TeCurve(TeCurveConfig { a, d }) => { - let te_add_chip = TeAddChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - config48.clone(), - te_start_offset, - a.clone(), - d.clone(), - range_checker.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - EccExtensionExecutor::TeEcAddRv32_48(te_add_chip), - te_add_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + te_start_offset)), - )?; - } - } + let te_add_chip = TeAddChip::new( + Rv32VecHeapAdapterChip::::new( + execution_bus, + program_bus, + memory_bridge, + pointer_bits, + bitwise_lu_chip.clone(), + ), + config48.clone(), + te_start_offset, + curve.coeffs.a.clone(), + curve.coeffs.d.clone(), + range_checker.clone(), + offline_memory.clone(), + ); + inventory.add_executor( + EccExtensionExecutor::TeEcAddRv32_48(te_add_chip), + te_add_opcodes + .clone() + .map(|x| VmOpcode::from_usize(x + te_start_offset)), + )?; } else { panic!("Modulus too large"); } diff --git a/extensions/ecc/guest/src/ecdsa.rs b/extensions/ecc/guest/src/ecdsa.rs index 47cc5ab415..91e9dc776c 100644 --- a/extensions/ecc/guest/src/ecdsa.rs +++ b/extensions/ecc/guest/src/ecdsa.rs @@ -19,10 +19,7 @@ use elliptic_curve::{ }; use openvm_algebra_guest::{DivUnsafe, IntMod, Reduce}; -use crate::{ - weierstrass::{FromCompressed, WeierstrassPoint}, - CyclicGroup, Group, IntrinsicCurve, -}; +use crate::{weierstrass::WeierstrassPoint, CyclicGroup, FromCompressed, Group, IntrinsicCurve}; type Coordinate = <::Point as WeierstrassPoint>::Coordinate; type Scalar = ::Scalar; diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs index 868d3ed3e3..a49ca6dcef 100644 --- a/extensions/ecc/guest/src/ed25519.rs +++ b/extensions/ecc/guest/src/ed25519.rs @@ -10,16 +10,16 @@ use crate::IntrinsicCurve; #[cfg(not(target_os = "zkvm"))] lazy_static! { - pub static ref Ed25519_MODULUS: BigUint = BigUint::from_bytes_be(&hex!( + pub static ref ED25519_MODULUS: BigUint = BigUint::from_bytes_be(&hex!( "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED" )); - pub static ref Ed25519_ORDER: BigUint = BigUint::from_bytes_be(&hex!( + pub static ref ED25519_ORDER: BigUint = BigUint::from_bytes_be(&hex!( "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED" )); - pub static ref Ed25519_A: BigUint = BigUint::from_bytes_be(&hex!( + pub static ref ED25519_A: BigUint = BigUint::from_bytes_be(&hex!( "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC" )); - pub static ref Ed25519_D: BigUint = BigUint::from_bytes_be(&hex!( + pub static ref ED25519_D: BigUint = BigUint::from_bytes_be(&hex!( "52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3" )); } diff --git a/extensions/ecc/guest/src/lib.rs b/extensions/ecc/guest/src/lib.rs index 81587c24f0..8778ba5c3d 100644 --- a/extensions/ecc/guest/src/lib.rs +++ b/extensions/ecc/guest/src/lib.rs @@ -38,7 +38,7 @@ pub enum SwBaseFunct7 { SwAddNe = 0, SwDouble, SwSetup, - HintDecompress, + SwHintDecompress, HintNonQr, } @@ -55,6 +55,7 @@ pub const TE_FUNCT3: u8 = 0b100; pub enum TeBaseFunct7 { TeAdd = 0, TeSetup, + TeHintDecompress, } impl TeBaseFunct7 { @@ -72,3 +73,27 @@ pub trait IntrinsicCurve { /// (e.g., if the curve order is prime). fn msm(coeffs: &[Self::Scalar], bases: &[Self::Point]) -> Self::Point; } + +pub trait FromCompressed { + /// Given `x`-coordinate, + /// + /// ## Panics + /// If the input is not a valid compressed point. + /// The zkVM panics instead of returning an [Option] because this function + /// can only guarantee correct behavior when decompression is possible, + /// but the function cannot compute the boolean equal to true if and only + /// if decompression is possible. + // This is because we rely on a hint for the correct decompressed value + // and then constrain its correctness. A malicious prover could hint + // incorrectly, so there is no way to use a hint to prove that the input + // **cannot** be decompressed. + fn decompress(x: Coordinate, rec_id: &u8) -> Self; + + /// If it exists, hints the unique `y` coordinate that is less than `Coordinate::MODULUS` + /// such that `(x, y)` is a point on the curve and `y` has parity equal to `rec_id`. + /// If such `y` does not exist, undefined behavior. + /// + /// This is only a hint, and the returned `y` does not guarantee any of the above properties. + /// They must be checked separately. Normal users should use `decompress` directly. + fn hint_decompress(x: &Coordinate, rec_id: &u8) -> Coordinate; +} diff --git a/extensions/ecc/te-setup/src/lib.rs b/extensions/ecc/te-setup/src/lib.rs index 614f56370e..e183086307 100644 --- a/extensions/ecc/te-setup/src/lib.rs +++ b/extensions/ecc/te-setup/src/lib.rs @@ -79,12 +79,14 @@ pub fn te_declare(input: TokenStream) -> TokenStream { }; } create_extern_func!(te_add_extern_func); + create_extern_func!(te_hint_decompress_extern_func); let group_ops_mod_name = format_ident!("{}_ops", struct_name.to_string().to_lowercase()); let result = TokenStream::from(quote::quote_spanned! { span.into() => extern "C" { fn #te_add_extern_func(rd: usize, rs1: usize, rs2: usize); + fn #te_hint_decompress_extern_func(rs1: usize, rs2: usize); } #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] @@ -200,11 +202,44 @@ pub fn te_declare(input: TokenStream) -> TokenStream { } mod #group_ops_mod_name { - use ::openvm_ecc_guest::{edwards::TwistedEdwardsPoint, impl_te_group_ops}; + use ::openvm_ecc_guest::{edwards::TwistedEdwardsPoint, FromCompressed, impl_te_group_ops}; use super::*; impl_te_group_ops!(#struct_name, #intmod_type); - } + + impl FromCompressed<#intmod_type> for #struct_name { + fn decompress(y: #intmod_type, rec_id: &u8) -> Self { + let x = <#struct_name as FromCompressed<#intmod_type>>::hint_decompress(&y, rec_id); + // Must assert unique so we can check the parity + x.assert_unique(); + assert_eq!(x.as_le_bytes()[0] & 1, *rec_id & 1); + <#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::from_xy(x, y).expect("decompressed point not on curve") + } + + fn hint_decompress(y: &#intmod_type, rec_id: &u8) -> #intmod_type { + #[cfg(not(target_os = "zkvm"))] + { + unimplemented!() + } + #[cfg(target_os = "zkvm")] + { + use openvm::platform as openvm_platform; // needed for hint_store_u32! + + let x = core::mem::MaybeUninit::<#intmod_type>::uninit(); + unsafe { + #te_hint_decompress_extern_func(y as *const _ as usize, rec_id as *const u8 as usize); + let mut ptr = x.as_ptr() as *const u8; + // NOTE[jpw]: this loop could be unrolled using seq_macro and hint_store_u32(ptr, $imm) + for _ in (0..<#intmod_type as openvm_algebra_guest::IntMod>::NUM_LIMBS).step_by(4) { + openvm_rv32im_guest::hint_store_u32!(ptr, 0); + ptr = ptr.add(4); + } + x.assume_init() + } + } + } + } + } }); output.push(result); } @@ -253,6 +288,10 @@ pub fn te_init(input: TokenStream) -> TokenStream { .join("_"); let add_extern_func = syn::Ident::new(&format!("te_add_extern_func_{}", str_path), span.into()); + let te_hint_decompress_extern_func = syn::Ident::new( + &format!("te_hint_decompress_extern_func_{}", str_path), + span.into(), + ); externs.push(quote::quote_spanned! { span.into() => #[no_mangle] extern "C" fn #add_extern_func(rd: usize, rs1: usize, rs2: usize) { @@ -266,6 +305,19 @@ pub fn te_init(input: TokenStream) -> TokenStream { rs2 = In rs2 ); } + + #[no_mangle] + extern "C" fn #te_hint_decompress_extern_func(rs1: usize, rs2: usize) { + openvm::platform::custom_insn_r!( + opcode = TE_OPCODE, + funct3 = TE_FUNCT3 as usize, + funct7 = TeBaseFunct7::TeHintDecompress as usize + #ec_idx + * (TeBaseFunct7::TWISTED_EDWARDS_MAX_KINDS as usize), + rd = Const "x0", + rs1 = In rs1, + rs2 = In rs2 + ); + } }); let setup_function = syn::Ident::new(&format!("setup_te_{}", str_path), span.into()); diff --git a/extensions/ecc/tests/Cargo.toml b/extensions/ecc/tests/Cargo.toml index bcdaf6f539..cea89631d1 100644 --- a/extensions/ecc/tests/Cargo.toml +++ b/extensions/ecc/tests/Cargo.toml @@ -12,6 +12,7 @@ openvm-stark-sdk.workspace = true openvm-circuit = { workspace = true, features = ["test-utils"] } openvm-transpiler.workspace = true openvm-algebra-circuit.workspace = true +openvm-algebra-guest.workspace = true openvm-algebra-transpiler.workspace = true openvm-ecc-transpiler.workspace = true openvm-ecc-circuit.workspace = true diff --git a/extensions/ecc/tests/programs/Cargo.toml b/extensions/ecc/tests/programs/Cargo.toml index 6572da4328..c7b7ad025d 100644 --- a/extensions/ecc/tests/programs/Cargo.toml +++ b/extensions/ecc/tests/programs/Cargo.toml @@ -11,6 +11,7 @@ openvm-custom-insn = { path = "../../../../crates/toolchain/custom_insn", defaul openvm-ecc-guest = { path = "../../guest", default-features = false } openvm-ecc-sw-macros = { path = "../../../../extensions/ecc/sw-macros", default-features = false } +openvm-ecc-te-macros = { path = "../../../../extensions/ecc/te-macros", default-features = false } openvm-algebra-guest = { path = "../../../algebra/guest", default-features = false } openvm-algebra-moduli-macros = { path = "../../../algebra/moduli-macros", default-features = false } openvm-rv32im-guest = { path = "../../../../extensions/rv32im/guest", default-features = false } @@ -59,7 +60,7 @@ required-features = ["k256", "p256"] [[example]] name = "decompress" -required-features = ["k256"] +required-features = ["k256", "ed25519"] [[example]] name = "ecdsa" diff --git a/extensions/ecc/tests/programs/examples/decompress.rs b/extensions/ecc/tests/programs/examples/decompress.rs index d00976c046..9bf5922a57 100644 --- a/extensions/ecc/tests/programs/examples/decompress.rs +++ b/extensions/ecc/tests/programs/examples/decompress.rs @@ -7,9 +7,12 @@ extern crate alloc; use hex_literal::hex; use openvm::io::read_vec; use openvm_ecc_guest::{ - algebra::IntMod, - weierstrass::{FromCompressed, WeierstrassPoint}, - Group, + algebra::{Field, IntMod}, + ed25519::{Ed25519Coord, Ed25519Point}, + edwards::TwistedEdwardsPoint, + k256::{Secp256k1Coord, Secp256k1Point}, + weierstrass::WeierstrassPoint, + FromCompressed, Group, }; use openvm_k256::{Secp256k1Coord, Secp256k1Point}; @@ -48,6 +51,8 @@ openvm::init!("openvm_init_decompress_k256.rs"); // test decompression under an honest host pub fn main() { let bytes = read_vec(); + + // secp256k1 let x = Secp256k1Coord::from_le_bytes(&bytes[..32]); let y = Secp256k1Coord::from_le_bytes(&bytes[32..64]); let rec_id = y.as_le_bytes()[0] & 1; @@ -71,6 +76,18 @@ pub fn main() { test_possible_decompression::(&x, &y, rec_id); // x = 1 is not on the x-coordinate of any point on the CurvePoint1mod4 curve test_impossible_decompression::(&Fp1mod4::from_u8(1), rec_id); + + // ed25519 + let x = Ed25519Coord::from_le_bytes(&bytes[64..96]); + let y = Ed25519Coord::from_le_bytes(&bytes[96..128]); + let rec_id = x.as_le_bytes()[0] & 1; + + let p = Ed25519Point::decompress(y.clone(), &rec_id); + assert_eq!(p.x(), &x); + assert_eq!(p.y(), &y); + + let p = Ed25519Point::decompress(&Ed25519Coord::from_u8(2), &rec_id); + assert!(p.is_none()); } fn test_possible_decompression>( diff --git a/extensions/ecc/tests/src/lib.rs b/extensions/ecc/tests/src/lib.rs index 1931a86f3b..266c87713a 100644 --- a/extensions/ecc/tests/src/lib.rs +++ b/extensions/ecc/tests/src/lib.rs @@ -12,9 +12,9 @@ mod tests { utils::{air_test, air_test_with_min_segments}, }; use openvm_ecc_circuit::{ - CurveCoeffs, CurveConfig, EccExtension, Rv32EccConfig, TeCurveConfig, P256_CONFIG, - SECP256K1_CONFIG, + CurveConfig, EccExtension, Rv32EccConfig, ED25519_CONFIG, P256_CONFIG, SECP256K1_CONFIG, }; + use openvm_ecc_guest::CyclicGroup; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_keccak256_transpiler::Keccak256TranspilerExtension; use openvm_rv32im_transpiler::{ @@ -97,7 +97,10 @@ mod tests { #[test] fn test_decompress() -> Result<()> { + use ed25519::Ed25519Point; + use edwards::TwistedEdwardsPoint; use halo2curves_axiom::{group::Curve, secp256k1::Secp256k1Affine}; + use openvm_algebra_guest::IntMod; let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone(), @@ -126,8 +129,7 @@ mod tests { .unwrap(), }), }, - ]); - + ], vec![ED25519_CONFIG.clone()]); let elf = build_example_program_at_path_with_features( get_programs_dir!(), "decompress", @@ -156,11 +158,23 @@ mod tests { let r_y: [u8; 32] = hex!("347E00859981D5446447075AA07543CDE6DF224CFB23F7B5886337BD00000000"); - let coords = [p.x.to_bytes(), p.y.to_bytes(), q_x, q_y, r_x, r_y] + let coords1 = [p1.x.to_bytes(), p1.y.to_bytes(), q_x, q_y, r_x, r_y] .concat() .into_iter() .map(FieldAlgebra::from_canonical_u8) .collect(); + + let p2 = Ed25519Point::GENERATOR.clone(); + let p2 = &p2 + &p2 + &p2; + println!("ed25519 decompressed: {:?}", &p2); + + let coords2: Vec<_> = [p2.x().as_le_bytes(), p2.y().as_le_bytes()] + .concat() + .into_iter() + .map(FieldAlgebra::from_canonical_u8) + .collect(); + + let coords = [coords1, coords2].concat(); air_test_with_min_segments(config, openvm_exe, vec![coords], 1); Ok(()) } @@ -177,7 +191,7 @@ mod tests { SECP256K1_CONFIG.scalar.clone(), ])) .keccak(Default::default()) - .ecc(EccExtension::new(vec![SECP256K1_CONFIG.clone()])) + .ecc(EccExtension::new(vec![SECP256K1_CONFIG.clone()], vec![])) .build(); let elf = build_example_program_at_path_with_features( @@ -216,23 +230,7 @@ mod tests { .with_extension(EccTranspilerExtension) .with_extension(ModularTranspilerExtension), )?; - let config = - Rv32EccConfig::new(vec![CurveConfig { - modulus: BigUint::from_str( - "57896044618658097711785492504343953926634992332820282019728792003956564819949", - ).unwrap(), - scalar: BigUint::from_str( - "7237005577332262213973186563042994240857116359379907606001950938285454250989", - ).unwrap(), - coeffs: CurveCoeffs::TeCurve(TeCurveConfig { - a: BigUint::from_str( - "57896044618658097711785492504343953926634992332820282019728792003956564819948", - ).unwrap(), - d: BigUint::from_str( - "37095705934669439343138083508754565189542113879843219016388785533085940283555", - ).unwrap(), - }), - }]); + let config = Rv32EccConfig::new(vec![], vec![ED25519_CONFIG.clone()]); air_test(config, openvm_exe); Ok(()) } diff --git a/extensions/ecc/transpiler/src/lib.rs b/extensions/ecc/transpiler/src/lib.rs index 9b4a997008..f7186e908a 100644 --- a/extensions/ecc/transpiler/src/lib.rs +++ b/extensions/ecc/transpiler/src/lib.rs @@ -25,7 +25,7 @@ pub enum Rv32WeierstrassOpcode { #[derive( Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EnumCount, EnumIter, FromRepr, LocalOpcode, )] -#[opcode_offset = 0x600] // same as for weierstrass +#[opcode_offset = 0x680] #[allow(non_camel_case_types)] #[repr(usize)] pub enum Rv32EdwardsOpcode { @@ -36,7 +36,8 @@ pub enum Rv32EdwardsOpcode { #[derive(Copy, Clone, Debug, PartialEq, Eq, FromRepr)] #[repr(u16)] pub enum EccPhantom { - HintDecompress = 0x40, + SwHintDecompress = 0x40, + TeHintDecompress = 0x41, HintNonQr = 0x41, } @@ -78,6 +79,15 @@ impl EccTranspilerExtension { ((dec_insn.funct7 as u8) / TeBaseFunct7::TWISTED_EDWARDS_MAX_KINDS) as usize; let curve_idx_shift = curve_idx * Rv32EdwardsOpcode::COUNT; + if let Some(TeBaseFunct7::TeHintDecompress) = TeBaseFunct7::from_repr(base_funct7) { + assert_eq!(dec_insn.rd, 0); + return Some(TranspilerOutput::one_to_one(Instruction::phantom( + PhantomDiscriminant(EccPhantom::TeHintDecompress as u16), + F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs1), + F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs2), + curve_idx as u16, + ))); + } if base_funct7 == TeBaseFunct7::TeSetup as u8 { let local_opcode = Rv32EdwardsOpcode::SETUP_EC_ADD; Some(Instruction::new( @@ -92,12 +102,10 @@ impl EccTranspilerExtension { )) } else { let global_opcode = match TeBaseFunct7::from_repr(base_funct7) { - Some(TeBaseFunct7::TeAdd) => { - Rv32EdwardsOpcode::EC_ADD as usize + Rv32EdwardsOpcode::CLASS_OFFSET - } + Some(TeBaseFunct7::TeAdd) => Rv32EdwardsOpcode::EC_ADD.global_opcode(), _ => unimplemented!(), }; - let global_opcode = global_opcode + curve_idx_shift; + let global_opcode = global_opcode.as_usize() + curve_idx_shift; Some(from_r_type(global_opcode, 2, &dec_insn)) } }; @@ -132,10 +140,11 @@ impl EccTranspilerExtension { let curve_idx = ((dec_insn.funct7 as u8) / SwBaseFunct7::SHORT_WEIERSTRASS_MAX_KINDS) as usize; let curve_idx_shift = curve_idx * Rv32WeierstrassOpcode::COUNT; - if let Some(SwBaseFunct7::HintDecompress) = SwBaseFunct7::from_repr(base_funct7) { + + if let Some(SwBaseFunct7::SwHintDecompress) = SwBaseFunct7::from_repr(base_funct7) { assert_eq!(dec_insn.rd, 0); return Some(TranspilerOutput::one_to_one(Instruction::phantom( - PhantomDiscriminant(EccPhantom::HintDecompress as u16), + PhantomDiscriminant(EccPhantom::SwHintDecompress as u16), F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs1), F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs2), curve_idx as u16, @@ -169,18 +178,14 @@ impl EccTranspilerExtension { )) } else { let global_opcode = match SwBaseFunct7::from_repr(base_funct7) { - Some(SwBaseFunct7::SwAddNe) => { - Rv32WeierstrassOpcode::EC_ADD_NE as usize - + Rv32WeierstrassOpcode::CLASS_OFFSET - } + Some(SwBaseFunct7::SwAddNe) => Rv32WeierstrassOpcode::EC_ADD_NE.global_opcode(), Some(SwBaseFunct7::SwDouble) => { assert!(dec_insn.rs2 == 0); - Rv32WeierstrassOpcode::EC_DOUBLE as usize - + Rv32WeierstrassOpcode::CLASS_OFFSET + Rv32WeierstrassOpcode::EC_DOUBLE.global_opcode() } _ => unimplemented!(), }; - let global_opcode = global_opcode + curve_idx_shift; + let global_opcode = global_opcode.as_usize() + curve_idx_shift; Some(from_r_type(global_opcode, 2, &dec_insn, true)) } }; diff --git a/extensions/pairing/circuit/src/config.rs b/extensions/pairing/circuit/src/config.rs index 2310622d39..46e17dfc0f 100644 --- a/extensions/pairing/circuit/src/config.rs +++ b/extensions/pairing/circuit/src/config.rs @@ -48,7 +48,10 @@ impl Rv32PairingConfig { .zip(modulus_primes) .collect(), ), - weierstrass: EccExtension::new(curves.iter().map(|c| c.curve_config()).collect()), + weierstrass: EccExtension::new( + curves.iter().map(|c| c.curve_config()).collect(), + vec![], + ), pairing: PairingExtension::new(curves), } } diff --git a/extensions/pairing/circuit/src/pairing_extension.rs b/extensions/pairing/circuit/src/pairing_extension.rs index 539773c454..e0aa030eb6 100644 --- a/extensions/pairing/circuit/src/pairing_extension.rs +++ b/extensions/pairing/circuit/src/pairing_extension.rs @@ -8,7 +8,7 @@ use openvm_circuit::{ use openvm_circuit_derive::{AnyEnum, InstructionExecutor}; use openvm_circuit_primitives::bitwise_op_lookup::SharedBitwiseOperationLookupChip; use openvm_circuit_primitives_derive::{Chip, ChipUsageGetter}; -use openvm_ecc_circuit::{CurveCoeffs, CurveConfig, SwCurveConfig}; +use openvm_ecc_circuit::{CurveConfig, SwCurveCoeffs}; use openvm_instructions::PhantomDiscriminant; use openvm_pairing_guest::{ bls12_381::{ @@ -32,25 +32,25 @@ pub enum PairingCurve { } impl PairingCurve { - pub fn curve_config(&self) -> CurveConfig { + pub fn curve_config(&self) -> CurveConfig { match self { PairingCurve::Bn254 => CurveConfig::new( BN254_ECC_STRUCT_NAME.to_string(), BN254_MODULUS.clone(), BN254_ORDER.clone(), - CurveCoeffs::SwCurve(SwCurveConfig { + SwCurveCoeffs { a: BigUint::zero(), b: BigUint::from_u8(3).unwrap(), - }), + }, ), PairingCurve::Bls12_381 => CurveConfig::new( BLS12_381_ECC_STRUCT_NAME.to_string(), BLS12_381_MODULUS.clone(), BLS12_381_ORDER.clone(), - CurveCoeffs::SwCurve(SwCurveConfig { + SwCurveCoeffs { a: BigUint::zero(), b: BigUint::from_u8(4).unwrap(), - }), + }, ), } } diff --git a/guest-libs/pairing/tests/lib.rs b/guest-libs/pairing/tests/lib.rs index 9aee0f2fec..f32e4cb4c4 100644 --- a/guest-libs/pairing/tests/lib.rs +++ b/guest-libs/pairing/tests/lib.rs @@ -54,7 +54,7 @@ mod bn254 { io: Default::default(), modular: ModularExtension::new(primes.to_vec()), fp2: Fp2Extension::new(primes_with_names), - weierstrass: EccExtension::new(vec![]), + weierstrass: EccExtension::new(vec![], vec![]), pairing: PairingExtension::new(vec![PairingCurve::Bn254]), } } @@ -503,7 +503,7 @@ mod bls12_381 { io: Default::default(), modular: ModularExtension::new(primes.to_vec()), fp2: Fp2Extension::new(primes_with_names), - weierstrass: EccExtension::new(vec![]), + weierstrass: EccExtension::new(vec![], vec![]), pairing: PairingExtension::new(vec![PairingCurve::Bls12_381]), } } From fcc8bb84eaf29ae65788740272b50ecbe49b8670 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Tue, 28 Jan 2025 19:42:54 -0500 Subject: [PATCH 20/57] Add negative of ed25519 generator --- extensions/ecc/guest/src/ed25519.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs index a49ca6dcef..25326d0599 100644 --- a/extensions/ecc/guest/src/ed25519.rs +++ b/extensions/ecc/guest/src/ed25519.rs @@ -69,11 +69,11 @@ impl CyclicGroup for Ed25519Point { "5866666666666666666666666666666666666666666666666666666666666666" )), }; - // TODO: fix const NEG_GENERATOR: Self = Ed25519Point { - x: Ed25519Coord::from_const_bytes(hex!( - "1AD5258F602D56C9B2A7259560C72C695CDCD6FD31E2A4C0FE536ECDD3366921" - )), + x: Ed25519Coord::from_const_bytes([ + 211, 42, 218, 112, 159, 210, 169, 54, 77, 88, 218, 106, 159, 56, 211, 150, 163, 35, 41, + 2, 206, 29, 91, 63, 1, 172, 145, 50, 44, 201, 150, 94, + ]), y: Ed25519Coord::from_const_bytes(hex!( "5866666666666666666666666666666666666666666666666666666666666666" )), From 2a91eb94a91e0fa52ad4d35a629e07e9aa319bac Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Wed, 29 Jan 2025 13:13:19 -0500 Subject: [PATCH 21/57] Update ecc extension section in the book to match CurveConfig rewrite --- book/src/custom-extensions/ecc.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/book/src/custom-extensions/ecc.md b/book/src/custom-extensions/ecc.md index c9a1d56ef3..ca8600bd15 100644 --- a/book/src/custom-extensions/ecc.md +++ b/book/src/custom-extensions/ecc.md @@ -115,24 +115,22 @@ For the guest program to build successfully, all used moduli and curves must be ```toml [app_vm_config.modular] -supported_moduli = ["115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337"] +supported_moduli = ["115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337", "57896044618658097711785492504343953926634992332820282019728792003956564819949"] -[[app_vm_config.ecc.supported_curves]] +[[app_vm_config.ecc.supported_sw_curves]] struct_name = "Secp256k1Point" modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" -[app_vm_config.ecc.supported_curves.coeffs] -type = "SwCurve" +[app_vm_config.ecc.supported_sw_curves.coeffs] a = "0" b = "7" -[[app_vm_config.ecc.supported_curves]] +[[app_vm_config.ecc.supported_te_curves]] modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" scalar = "7237005577332262213973186563042994240857116359379907606001950938285454250989" -[app_vm_config.ecc.supported_curves.coeffs] -type = "TeCurve" +[app_vm_config.ecc.supported_te_curves.coeffs] a = "57896044618658097711785492504343953926634992332820282019728792003956564819948" d = "37095705934669439343138083508754565189542113879843219016388785533085940283555" ``` From 64f6bcd5dbbe3d3eb5d1123f2b53df3e9a4e59f0 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Wed, 29 Jan 2025 14:24:46 -0500 Subject: [PATCH 22/57] fix issues introduced after rebase --- Cargo.lock | 96 +++++-------------- Cargo.toml | 8 +- extensions/ecc/guest/src/ed25519.rs | 4 +- .../ecc/{te-setup => te-macros}/Cargo.toml | 2 +- .../ecc/{te-setup => te-macros}/src/lib.rs | 10 +- .../ecc/tests/programs/examples/decompress.rs | 2 +- .../ecc/tests/programs/examples/edwards_ec.rs | 4 +- extensions/ecc/transpiler/src/lib.rs | 2 +- 8 files changed, 38 insertions(+), 90 deletions(-) rename extensions/ecc/{te-setup => te-macros}/Cargo.toml (92%) rename extensions/ecc/{te-setup => te-macros}/src/lib.rs (96%) diff --git a/Cargo.lock b/Cargo.lock index c2a331e086..4f2c813d2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,7 +159,6 @@ dependencies = [ "foldhash", "hashbrown 0.15.2", "indexmap 2.7.1", - "indexmap 2.7.1", "itoa", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-asm", @@ -176,10 +175,8 @@ dependencies = [ [[package]] name = "alloy-rlp" version = "0.3.11" -version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" -checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -189,10 +186,8 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" version = "0.3.11" -version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" -checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" dependencies = [ "proc-macro2", "quote", @@ -345,14 +340,11 @@ dependencies = [ [[package]] name = "anstyle-wincon" version = "3.0.7" -version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", "once_cell", - "once_cell", "windows-sys 0.59.0", ] @@ -643,10 +635,8 @@ dependencies = [ [[package]] name = "auto_impl" version = "1.2.1" -version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" -checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" dependencies = [ "proc-macro2", "quote", @@ -860,10 +850,8 @@ dependencies = [ [[package]] name = "aws-smithy-async" version = "1.2.4" -version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa59d1327d8b5053c54bf2eaae63bf629ba9e904434d0835a28ed3c0ed0a614e" -checksum = "fa59d1327d8b5053c54bf2eaae63bf629ba9e904434d0835a28ed3c0ed0a614e" dependencies = [ "futures-util", "pin-project-lite", @@ -882,7 +870,6 @@ dependencies = [ "crc32c", "crc32fast", "crc64fast-nvme", - "crc64fast-nvme", "hex", "http 0.2.12", "http-body 0.4.6", @@ -907,7 +894,6 @@ dependencies = [ [[package]] name = "aws-smithy-http" version = "0.60.12" -version = "0.60.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7809c27ad8da6a6a68c454e651d4962479e81472aa19ae99e59f9aba1f9713cc" dependencies = [ @@ -949,10 +935,8 @@ dependencies = [ [[package]] name = "aws-smithy-json" version = "0.61.2" -version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "623a51127f24c30776c8b374295f2df78d92517386f77ba30773f15a30ce1422" -checksum = "623a51127f24c30776c8b374295f2df78d92517386f77ba30773f15a30ce1422" dependencies = [ "aws-smithy-types", ] @@ -1194,10 +1178,8 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.8.0" -version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bitvec" @@ -1492,7 +1474,6 @@ dependencies = [ "camino", "cargo-platform", "semver 1.0.25", - "semver 1.0.25", "serde", "serde_json", "thiserror 1.0.69", @@ -2008,6 +1989,28 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "derive-new" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "derive-new" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "derive_more" version = "0.99.19" @@ -2855,10 +2858,8 @@ dependencies = [ [[package]] name = "getset" version = "0.1.4" -version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eded738faa0e88d3abc9d1a13cb11adc2073c400969eeb8793cf7132589959fc" -checksum = "eded738faa0e88d3abc9d1a13cb11adc2073c400969eeb8793cf7132589959fc" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2946,7 +2947,6 @@ dependencies = [ "futures-util", "http 0.2.12", "indexmap 2.7.1", - "indexmap 2.7.1", "slab", "tokio", "tokio-util", @@ -3585,10 +3585,8 @@ dependencies = [ [[package]] name = "indexmap" version = "2.7.1" -version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -3678,10 +3676,8 @@ dependencies = [ [[package]] name = "js-sys" version = "0.3.77" -version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -3899,10 +3895,8 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] name = "log" version = "0.4.25" -version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "lru" @@ -3999,7 +3993,6 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62a6a1f7141f1d9bc7a886b87536bbfc97752e08b369e1e0453a9acfab5f5da4" dependencies = [ - "indexmap 2.7.1", "indexmap 2.7.1", "itoa", "lockfree-object-pool", @@ -4022,7 +4015,6 @@ dependencies = [ "crossbeam-utils", "hashbrown 0.14.5", "indexmap 2.7.1", - "indexmap 2.7.1", "metrics", "num_cpus", "ordered-float", @@ -4743,8 +4735,8 @@ dependencies = [ ] [[package]] -name = "openvm-ecc-te-setup" -version = "0.2.0-alpha" +name = "openvm-ecc-te-macros" +version = "1.0.0-rc.0" dependencies = [ "num-bigint 0.4.6", "openvm-macros-common", @@ -5496,10 +5488,8 @@ dependencies = [ [[package]] name = "outref" version = "0.5.2" -version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" -checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] name = "overload" @@ -6077,7 +6067,6 @@ checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", "thiserror 2.0.11", - "thiserror 2.0.11", "ucd-trie", ] @@ -6287,10 +6276,8 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "prettyplease" version = "0.2.29" -version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" -checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" dependencies = [ "proc-macro2", "syn 2.0.98", @@ -6344,10 +6331,8 @@ dependencies = [ [[package]] name = "proc-macro2" version = "1.0.93" -version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -6986,7 +6971,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.25", - "semver 1.0.25", ] [[package]] @@ -7210,10 +7194,8 @@ dependencies = [ [[package]] name = "semver" version = "1.0.25" -version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" dependencies = [ "serde", ] @@ -7271,7 +7253,6 @@ version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" dependencies = [ - "indexmap 2.7.1", "indexmap 2.7.1", "itoa", "memchr", @@ -7321,7 +7302,6 @@ dependencies = [ "hex", "indexmap 1.9.3", "indexmap 2.7.1", - "indexmap 2.7.1", "serde", "serde_derive", "serde_json", @@ -7872,10 +7852,8 @@ dependencies = [ [[package]] name = "test-log" version = "0.2.17" -version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f46083d221181166e5b6f6b1e5f1d499f3a76888826e6cb1d057554157cd0f" -checksum = "e7f46083d221181166e5b6f6b1e5f1d499f3a76888826e6cb1d057554157cd0f" dependencies = [ "env_logger", "test-log-macros", @@ -7885,10 +7863,8 @@ dependencies = [ [[package]] name = "test-log-macros" version = "0.2.17" -version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" -checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" dependencies = [ "proc-macro2", "quote", @@ -7907,13 +7883,10 @@ dependencies = [ [[package]] name = "thiserror" version = "2.0.11" -version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ "thiserror-impl 2.0.11", - "thiserror-impl 2.0.11", ] [[package]] @@ -7930,10 +7903,8 @@ dependencies = [ [[package]] name = "thiserror-impl" version = "2.0.11" -version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", @@ -8186,7 +8157,6 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.7.1", "indexmap 2.7.1", "serde", "serde_spanned", @@ -8429,10 +8399,8 @@ checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6" [[package]] name = "valuable" version = "0.1.1" -version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -8517,25 +8485,20 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" version = "0.2.100" -version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", - "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.100" -version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", @@ -8561,10 +8524,8 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" version = "0.2.100" -version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -8573,10 +8534,8 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" version = "0.2.100" -version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -8588,24 +8547,17 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" version = "0.2.100" -version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] [[package]] name = "web-sys" version = "0.3.77" -version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index e1e90656da..38062f6da0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,8 +57,8 @@ members = [ "extensions/ecc/circuit", "extensions/ecc/transpiler", "extensions/ecc/guest", - "extensions/ecc/sw-setup", - "extensions/ecc/te-setup", + "extensions/ecc/sw-macros", + "extensions/ecc/te-macros", "extensions/ecc/tests", "extensions/pairing/circuit", "extensions/pairing/guest", @@ -162,8 +162,8 @@ openvm-algebra-complex-macros = { path = "extensions/algebra/complex-macros", de openvm-ecc-circuit = { path = "extensions/ecc/circuit", default-features = false } openvm-ecc-transpiler = { path = "extensions/ecc/transpiler", default-features = false } openvm-ecc-guest = { path = "extensions/ecc/guest", default-features = false } -openvm-ecc-sw-setup = { path = "extensions/ecc/sw-setup", default-features = false } -openvm-ecc-te-setup = { path = "extensions/ecc/te-setup", default-features = false } +openvm-ecc-sw-macros = { path = "extensions/ecc/sw-macros", default-features = false } +openvm-ecc-te-macros = { path = "extensions/ecc/te-macros", default-features = false } openvm-pairing-circuit = { path = "extensions/pairing/circuit", default-features = false } openvm-pairing-transpiler = { path = "extensions/pairing/transpiler", default-features = false } openvm-pairing-guest = { path = "extensions/pairing/guest", default-features = false } diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs index 25326d0599..3a6b788d39 100644 --- a/extensions/ecc/guest/src/ed25519.rs +++ b/extensions/ecc/guest/src/ed25519.rs @@ -24,7 +24,7 @@ lazy_static! { )); } -openvm_algebra_moduli_setup::moduli_declare! { +openvm_algebra_moduli_macros::moduli_declare! { Ed25519Coord { modulus = "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED" }, Ed25519Scalar { modulus = "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED" }, } @@ -40,7 +40,7 @@ pub const CURVE_D: Ed25519Coord = Ed25519Coord::from_const_bytes(hex!( "A3785913CA4DEB75ABD841414D0A700098E879777940C78C73FE6F2BEE6C0352" )); -openvm_ecc_te_setup::te_declare! { +openvm_ecc_te_macros::te_declare! { Ed25519Point { mod_type = Ed25519Coord, a = CURVE_A, d = CURVE_D }, } diff --git a/extensions/ecc/te-setup/Cargo.toml b/extensions/ecc/te-macros/Cargo.toml similarity index 92% rename from extensions/ecc/te-setup/Cargo.toml rename to extensions/ecc/te-macros/Cargo.toml index ff8afb15e0..3784d74dc3 100644 --- a/extensions/ecc/te-setup/Cargo.toml +++ b/extensions/ecc/te-macros/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "openvm-ecc-te-setup" +name = "openvm-ecc-te-macros" version.workspace = true authors.workspace = true edition.workspace = true diff --git a/extensions/ecc/te-setup/src/lib.rs b/extensions/ecc/te-macros/src/lib.rs similarity index 96% rename from extensions/ecc/te-setup/src/lib.rs rename to extensions/ecc/te-macros/src/lib.rs index e183086307..ac4b49ddbb 100644 --- a/extensions/ecc/te-setup/src/lib.rs +++ b/extensions/ecc/te-macros/src/lib.rs @@ -223,17 +223,13 @@ pub fn te_declare(input: TokenStream) -> TokenStream { } #[cfg(target_os = "zkvm")] { - use openvm::platform as openvm_platform; // needed for hint_store_u32! + use openvm::platform as openvm_platform; // needed for hint_buffer_u32! let x = core::mem::MaybeUninit::<#intmod_type>::uninit(); unsafe { #te_hint_decompress_extern_func(y as *const _ as usize, rec_id as *const u8 as usize); - let mut ptr = x.as_ptr() as *const u8; - // NOTE[jpw]: this loop could be unrolled using seq_macro and hint_store_u32(ptr, $imm) - for _ in (0..<#intmod_type as openvm_algebra_guest::IntMod>::NUM_LIMBS).step_by(4) { - openvm_rv32im_guest::hint_store_u32!(ptr, 0); - ptr = ptr.add(4); - } + let ptr = x.as_ptr() as *const u8; + openvm_rv32im_guest::hint_buffer_u32!(ptr, <#intmod_type as openvm_algebra_guest::IntMod>::NUM_LIMBS / 4); x.assume_init() } } diff --git a/extensions/ecc/tests/programs/examples/decompress.rs b/extensions/ecc/tests/programs/examples/decompress.rs index 9bf5922a57..268db22669 100644 --- a/extensions/ecc/tests/programs/examples/decompress.rs +++ b/extensions/ecc/tests/programs/examples/decompress.rs @@ -46,7 +46,7 @@ openvm_ecc_sw_macros::sw_declare! { }, } -openvm::init!("openvm_init_decompress_k256.rs"); +openvm::init!("openvm_init_decompress_k256_ed25519.rs"); // test decompression under an honest host pub fn main() { diff --git a/extensions/ecc/tests/programs/examples/edwards_ec.rs b/extensions/ecc/tests/programs/examples/edwards_ec.rs index 438b21fb00..ba74b41a19 100644 --- a/extensions/ecc/tests/programs/examples/edwards_ec.rs +++ b/extensions/ecc/tests/programs/examples/edwards_ec.rs @@ -2,11 +2,11 @@ #![cfg_attr(not(feature = "std"), no_std)] use hex_literal::hex; -use openvm_algebra_guest::{moduli_setup::moduli_init, IntMod}; +use openvm_algebra_guest::{moduli_macros::moduli_init, IntMod}; use openvm_ecc_guest::{ ed25519::{Ed25519Coord, Ed25519Point}, edwards::TwistedEdwardsPoint, - te_setup::te_init, + te_macros::te_init, CyclicGroup, Group, }; diff --git a/extensions/ecc/transpiler/src/lib.rs b/extensions/ecc/transpiler/src/lib.rs index f7186e908a..db30392534 100644 --- a/extensions/ecc/transpiler/src/lib.rs +++ b/extensions/ecc/transpiler/src/lib.rs @@ -106,7 +106,7 @@ impl EccTranspilerExtension { _ => unimplemented!(), }; let global_opcode = global_opcode.as_usize() + curve_idx_shift; - Some(from_r_type(global_opcode, 2, &dec_insn)) + Some(from_r_type(global_opcode, 2, &dec_insn, true)) } }; instruction.map(TranspilerOutput::one_to_one) From df3aca0451cc985fc27f18f29a14dbf35ba8744e Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Wed, 29 Jan 2025 14:25:12 -0500 Subject: [PATCH 23/57] update README for ecc macros --- extensions/ecc/te-macros/README.md | 121 +++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 extensions/ecc/te-macros/README.md diff --git a/extensions/ecc/te-macros/README.md b/extensions/ecc/te-macros/README.md new file mode 100644 index 0000000000..402b46ad06 --- /dev/null +++ b/extensions/ecc/te-macros/README.md @@ -0,0 +1,121 @@ +# `openvm-ecc-te-macros` + +Procedural macros for use in guest program to generate short twisted Edwards elliptic curve struct with custom intrinsics for compile-time modulus. + +The workflow of this macro is very similar to the [`openvm-algebra-moduli-macros`](../moduli-macros/README.md) crate. We recommend reading it first. + +## Example + +```rust +// ... + +moduli_declare! { + Ed25519Coord { modulus = "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED" }, + Ed25519Scalar { modulus = "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED" }, +} + +// Note that from_const_bytes is little endian +pub const CURVE_A: Ed25519Coord = Ed25519Coord::from_const_bytes(hex!( + "ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F" +)); +pub const CURVE_D: Ed25519Coord = Ed25519Coord::from_const_bytes(hex!( + "A3785913CA4DEB75ABD841414D0A700098E879777940C78C73FE6F2BEE6C0352" +)); + +sw_declare! { + Ed25519Point { mod_type = Ed25519Coord, a = CURVE_A, d = CURVE_D }, +} + +openvm_algebra_guest::moduli_macros::moduli_init! { + "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", + "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", +} + +openvm_ecc_guest::te_macros::te_init! { + Ed25519Point, +} + +pub fn main() { + setup_all_moduli(); + setup_all_te_curves(); + // ... +} +``` + +## Full story + +Again, the principle is the same as in the [`openvm-algebra-moduli-macros`](../moduli-macros/README.md) crate. Here we emphasize the core differences. + +The crate provides two macros: `te_declare!` and `te_init!`. The signatures are: + +- `te_declare!` receives comma-separated list of moduli classes descriptions. Each description looks like `TeStruct { mod_type = ModulusName, a = a_expr, d = d_expr }`. Here `ModulusName` is the name of any struct that implements `trait IntMod` -- in particular, the ones created by `moduli_declare!` do. Parameters `a` and `d` correspond to the coefficients of the equation defining the curve. They **must be compile-time constants**. Both the parameters `a` and `d` are required. + +- `te_init!` receives comma-separated list of struct names. The struct name must exactly match the name in `te_declare!` -- type defs are not allowed (see point 5 below). + +What happens under the hood: + +1. `te_declare!` macro creates a struct with two field `x` and `y` of type `mod_type`. This struct denotes a point on the corresponding elliptic curve. In the example it would be + +```rust +struct Ed25519Point { + x: Ed25519Coord, + y: Ed25519Coord, +} +``` + +Similar to `moduli_declare!`, this macro also creates extern functions for arithmetic operations -- but in this case they are named after the te type, not after any hexadecimal (since the macro has no way to obtain it from the name of the modulus type anyway): + +```rust +extern "C" { + fn te_add_extern_func_Ed25519Point(rd: usize, rs1: usize, rs2: usize); + fn hint_decompress_extern_func_Ed25519Point(rs1: usize, rs2: usize); +} +``` + +2. Again, `te_init!` macro implements these extern functions and defines the setup functions for the te struct. + +```rust +#[cfg(target_os = "zkvm")] +mod openvm_intrinsics_ffi_2 { + use :openvm_ecc_guest::{OPCODE, TE_FUNCT3, TeBaseFunct7}; + + #[no_mangle] + extern "C" fn te_add_extern_func_Ed25519Point(rd: usize, rs1: usize, rs2: usize) { + // ... + } + // other externs +} +#[allow(non_snake_case)] +pub fn setup_te_Ed25519Point() { + #[cfg(target_os = "zkvm")] + { + // ... + } +} +pub fn setup_all_te_curves() { + setup_te_Ed25519Point(); + // other setups +} +``` + +3. Again, the `setup` function for every used curve must be called before any other instructions for that curve. If all curves are used, one can call `setup_all_te_curves()` to setup all of them. + +4. The order of the items in `te_init!` **must match** the order of the moduli in the chip configuration -- more specifically, in the modular extension parameters (the order of `CurveConfig`s in `TwistedEdwardsExtension::supported_curves`, which is usually defined with the whole `app_vm_config` in the `openvm.toml` file). + +5. Note that, due to the nature of function names, the name of the struct used in `te_init!` must be the same as in `te_declare!`. To illustrate, the following code will **fail** to compile: + +```rust +// ... + +te_declare! { + Ed25519Point { mod_type = Ed25519Coord, a = CURVE_A, d = CURVE_D }, +} + +pub type Te = Ed25519Point; + +te_init! { + Te, +} +``` + +The reason is that, for example, the function `sw_add_extern_func_Secp256k1Point` remains unimplemented, but we implement `sw_add_extern_func_Sw`. From 028e5c4c69cb409a7308b77ec0f5596efa8e267f Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Wed, 29 Jan 2025 14:43:44 -0500 Subject: [PATCH 24/57] rename ecc opcodes --- extensions/ecc/circuit/src/ecc_extension.rs | 10 ++++---- .../ecc/circuit/src/edwards_chip/mod.rs | 4 ++-- .../ecc/circuit/src/edwards_chip/tests.rs | 4 ++-- .../ecc/circuit/src/weierstrass_chip/mod.rs | 8 +++---- .../ecc/circuit/src/weierstrass_chip/tests.rs | 12 +++++----- extensions/ecc/transpiler/src/lib.rs | 24 +++++++++---------- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index fa380990b2..816a35a514 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -147,13 +147,13 @@ impl VmExtension for EccExtension { let range_checker = builder.system_base().range_checker_chip.clone(); let pointer_bits = builder.system_config().memory_config.pointer_max_bits; - let sw_add_ne_opcodes = (Rv32WeierstrassOpcode::EC_ADD_NE as usize) - ..=(Rv32WeierstrassOpcode::SETUP_EC_ADD_NE as usize); - let sw_double_opcodes = (Rv32WeierstrassOpcode::EC_DOUBLE as usize) - ..=(Rv32WeierstrassOpcode::SETUP_EC_DOUBLE as usize); + let sw_add_ne_opcodes = (Rv32WeierstrassOpcode::SW_ADD_NE as usize) + ..=(Rv32WeierstrassOpcode::SETUP_SW_ADD_NE as usize); + let sw_double_opcodes = (Rv32WeierstrassOpcode::SW_DOUBLE as usize) + ..=(Rv32WeierstrassOpcode::SETUP_SW_DOUBLE as usize); let te_add_opcodes = - (Rv32EdwardsOpcode::EC_ADD as usize)..=(Rv32EdwardsOpcode::SETUP_EC_ADD as usize); + (Rv32EdwardsOpcode::TE_ADD as usize)..=(Rv32EdwardsOpcode::SETUP_TE_ADD as usize); for (sw_idx, curve) in self.supported_sw_curves.iter().enumerate() { let bytes = curve.modulus.bits().div_ceil(8); diff --git a/extensions/ecc/circuit/src/edwards_chip/mod.rs b/extensions/ecc/circuit/src/edwards_chip/mod.rs index 9e7430e0f8..b7472195f5 100644 --- a/extensions/ecc/circuit/src/edwards_chip/mod.rs +++ b/extensions/ecc/circuit/src/edwards_chip/mod.rs @@ -53,8 +53,8 @@ impl expr, offset, vec![ - Rv32EdwardsOpcode::EC_ADD as usize, - Rv32EdwardsOpcode::SETUP_EC_ADD as usize, + Rv32EdwardsOpcode::TE_ADD as usize, + Rv32EdwardsOpcode::SETUP_TE_ADD as usize, ], vec![], range_checker, diff --git a/extensions/ecc/circuit/src/edwards_chip/tests.rs b/extensions/ecc/circuit/src/edwards_chip/tests.rs index a13438013b..95806d101c 100644 --- a/extensions/ecc/circuit/src/edwards_chip/tests.rs +++ b/extensions/ecc/circuit/src/edwards_chip/tests.rs @@ -170,7 +170,7 @@ fn test_add() { &mut tester, vec![prime_limbs, *Edwards25519_A_LIMBS], vec![*Edwards25519_D_LIMBS], - chip.0.core.air.offset + Rv32EdwardsOpcode::SETUP_EC_ADD as usize, + chip.0.core.air.offset + Rv32EdwardsOpcode::SETUP_TE_ADD as usize, ); tester.execute(&mut chip, &setup_instruction); @@ -178,7 +178,7 @@ fn test_add() { &mut tester, vec![p1_x_limbs, p1_y_limbs], vec![p2_x_limbs, p2_y_limbs], - chip.0.core.air.offset + Rv32EdwardsOpcode::EC_ADD as usize, + chip.0.core.air.offset + Rv32EdwardsOpcode::TE_ADD as usize, ); tester.execute(&mut chip, &instruction); diff --git a/extensions/ecc/circuit/src/weierstrass_chip/mod.rs b/extensions/ecc/circuit/src/weierstrass_chip/mod.rs index e1e3ea084c..dc162f23e4 100644 --- a/extensions/ecc/circuit/src/weierstrass_chip/mod.rs +++ b/extensions/ecc/circuit/src/weierstrass_chip/mod.rs @@ -49,8 +49,8 @@ impl expr, offset, vec![ - Rv32WeierstrassOpcode::EC_ADD_NE as usize, - Rv32WeierstrassOpcode::SETUP_EC_ADD_NE as usize, + Rv32WeierstrassOpcode::SW_ADD_NE as usize, + Rv32WeierstrassOpcode::SETUP_SW_ADD_NE as usize, ], vec![], range_checker, @@ -86,8 +86,8 @@ impl expr, offset, vec![ - Rv32WeierstrassOpcode::EC_DOUBLE as usize, - Rv32WeierstrassOpcode::SETUP_EC_DOUBLE as usize, + Rv32WeierstrassOpcode::SW_DOUBLE as usize, + Rv32WeierstrassOpcode::SETUP_SW_DOUBLE as usize, ], vec![], range_checker, diff --git a/extensions/ecc/circuit/src/weierstrass_chip/tests.rs b/extensions/ecc/circuit/src/weierstrass_chip/tests.rs index a859070bc7..5a4780671b 100644 --- a/extensions/ecc/circuit/src/weierstrass_chip/tests.rs +++ b/extensions/ecc/circuit/src/weierstrass_chip/tests.rs @@ -131,7 +131,7 @@ fn test_add_ne() { &mut tester, vec![prime_limbs, one_limbs], // inputs[0] = prime, others doesn't matter vec![one_limbs, one_limbs], - chip.0.core.air.offset + Rv32WeierstrassOpcode::SETUP_EC_ADD_NE as usize, + chip.0.core.air.offset + Rv32WeierstrassOpcode::SETUP_SW_ADD_NE as usize, ); tester.execute(&mut chip, &setup_instruction); @@ -139,7 +139,7 @@ fn test_add_ne() { &mut tester, vec![p1_x_limbs, p1_y_limbs], vec![p2_x_limbs, p2_y_limbs], - chip.0.core.air.offset + Rv32WeierstrassOpcode::EC_ADD_NE as usize, + chip.0.core.air.offset + Rv32WeierstrassOpcode::SW_ADD_NE as usize, ); tester.execute(&mut chip, &instruction); @@ -195,7 +195,7 @@ fn test_double() { vec![prime_limbs, a_limbs], /* inputs[0] = prime, inputs[1] = a coeff of weierstrass * equation */ vec![], - chip.0.core.air.offset + Rv32WeierstrassOpcode::SETUP_EC_DOUBLE as usize, + chip.0.core.air.offset + Rv32WeierstrassOpcode::SETUP_SW_DOUBLE as usize, ); tester.execute(&mut chip, &setup_instruction); @@ -203,7 +203,7 @@ fn test_double() { &mut tester, vec![p1_x_limbs, p1_y_limbs], vec![], - chip.0.core.air.offset + Rv32WeierstrassOpcode::EC_DOUBLE as usize, + chip.0.core.air.offset + Rv32WeierstrassOpcode::SW_DOUBLE as usize, ); tester.execute(&mut chip, &instruction); @@ -284,7 +284,7 @@ fn test_p256_double() { vec![prime_limbs, a_limbs], /* inputs[0] = prime, inputs[1] = a coeff of weierstrass * equation */ vec![], - chip.0.core.air.offset + Rv32WeierstrassOpcode::SETUP_EC_DOUBLE as usize, + chip.0.core.air.offset + Rv32WeierstrassOpcode::SETUP_SW_DOUBLE as usize, ); tester.execute(&mut chip, &setup_instruction); @@ -292,7 +292,7 @@ fn test_p256_double() { &mut tester, vec![p1_x_limbs, p1_y_limbs], vec![], - chip.0.core.air.offset + Rv32WeierstrassOpcode::EC_DOUBLE as usize, + chip.0.core.air.offset + Rv32WeierstrassOpcode::SW_DOUBLE as usize, ); tester.execute(&mut chip, &instruction); diff --git a/extensions/ecc/transpiler/src/lib.rs b/extensions/ecc/transpiler/src/lib.rs index db30392534..be69b4ecea 100644 --- a/extensions/ecc/transpiler/src/lib.rs +++ b/extensions/ecc/transpiler/src/lib.rs @@ -16,10 +16,10 @@ use strum::{EnumCount, EnumIter, FromRepr}; #[allow(non_camel_case_types)] #[repr(usize)] pub enum Rv32WeierstrassOpcode { - EC_ADD_NE, - SETUP_EC_ADD_NE, - EC_DOUBLE, - SETUP_EC_DOUBLE, + SW_ADD_NE, + SETUP_SW_ADD_NE, + SW_DOUBLE, + SETUP_SW_DOUBLE, } #[derive( @@ -29,8 +29,8 @@ pub enum Rv32WeierstrassOpcode { #[allow(non_camel_case_types)] #[repr(usize)] pub enum Rv32EdwardsOpcode { - EC_ADD, - SETUP_EC_ADD, + TE_ADD, + SETUP_TE_ADD, } #[derive(Copy, Clone, Debug, PartialEq, Eq, FromRepr)] @@ -89,7 +89,7 @@ impl EccTranspilerExtension { ))); } if base_funct7 == TeBaseFunct7::TeSetup as u8 { - let local_opcode = Rv32EdwardsOpcode::SETUP_EC_ADD; + let local_opcode = Rv32EdwardsOpcode::SETUP_TE_ADD; Some(Instruction::new( VmOpcode::from_usize(local_opcode.global_opcode().as_usize() + curve_idx_shift), F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rd), @@ -102,7 +102,7 @@ impl EccTranspilerExtension { )) } else { let global_opcode = match TeBaseFunct7::from_repr(base_funct7) { - Some(TeBaseFunct7::TeAdd) => Rv32EdwardsOpcode::EC_ADD.global_opcode(), + Some(TeBaseFunct7::TeAdd) => Rv32EdwardsOpcode::TE_ADD.global_opcode(), _ => unimplemented!(), }; let global_opcode = global_opcode.as_usize() + curve_idx_shift; @@ -163,8 +163,8 @@ impl EccTranspilerExtension { } if base_funct7 == SwBaseFunct7::SwSetup as u8 { let local_opcode = match dec_insn.rs2 { - 0 => Rv32WeierstrassOpcode::SETUP_EC_DOUBLE, - _ => Rv32WeierstrassOpcode::SETUP_EC_ADD_NE, + 0 => Rv32WeierstrassOpcode::SETUP_SW_DOUBLE, + _ => Rv32WeierstrassOpcode::SETUP_SW_ADD_NE, }; Some(Instruction::new( VmOpcode::from_usize(local_opcode.global_opcode().as_usize() + curve_idx_shift), @@ -178,10 +178,10 @@ impl EccTranspilerExtension { )) } else { let global_opcode = match SwBaseFunct7::from_repr(base_funct7) { - Some(SwBaseFunct7::SwAddNe) => Rv32WeierstrassOpcode::EC_ADD_NE.global_opcode(), + Some(SwBaseFunct7::SwAddNe) => Rv32WeierstrassOpcode::SW_ADD_NE.global_opcode(), Some(SwBaseFunct7::SwDouble) => { assert!(dec_insn.rs2 == 0); - Rv32WeierstrassOpcode::EC_DOUBLE.global_opcode() + Rv32WeierstrassOpcode::SW_DOUBLE.global_opcode() } _ => unimplemented!(), }; From 13274f3a4a70ac0d7031cdd6e36e67e204b1b951 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Wed, 29 Jan 2025 14:51:01 -0500 Subject: [PATCH 25/57] Update contributer docs for ecc extension --- docs/specs/ISA.md | 22 +++++++++++++--------- docs/specs/RISCV.md | 6 ++++-- docs/specs/transpiler.md | 4 +++- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/docs/specs/ISA.md b/docs/specs/ISA.md index e362be3dad..214759521f 100644 --- a/docs/specs/ISA.md +++ b/docs/specs/ISA.md @@ -677,11 +677,13 @@ r32_fp2(a) -> Fp2 { ### Elliptic Curve Extension -The elliptic curve extension supports arithmetic over elliptic curves `C` in Weierstrass form given by -equation `C: y^2 = x^3 + C::A * x + C::B` where `C::A` and `C::B` are constants in the coordinate field. We note that -the definitions of the -curve arithmetic operations do not depend on `C::B`. The VM configuration will specify a list of supported curves. For -each Weierstrass curve `C` there will be associated configuration parameters `C::COORD_SIZE` and `C::BLOCK_SIZE` ( +The elliptic curve extension supports arithmetic over elliptic curves `C` in the following forms: +- in short Weierstrass form given by equation `C: y^2 = x^3 + C::A * x + C::B` where `C::A` and `C::B` are constants in the coordinate field +- in twisted Edwards form given by equation `C: C::A * x^2 + y^2 = 1 + C::D * x^2 * y^2` where `C::A` and `C::D` are constants in the coordinate field + +We note that +the definitions of the curve arithmetic operations for short Weierstrass curves do not depend on `C::B`. The VM configuration will specify a list of supported curves. For +each curve `C` (of either form) there will be associated configuration parameters `C::COORD_SIZE` and `C::BLOCK_SIZE` ( defined below). The extension operates on address spaces `1` and `2`, meaning all memory cells are constrained to be bytes. @@ -702,10 +704,12 @@ r32_ec_point(a) -> EcPoint { | Name | Operands | Description | | -------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| EC_ADD_NE\ | `a,b,c,1,2` | Set `r32_ec_point(a) = r32_ec_point(b) + r32_ec_point(c)` (curve addition). Assumes that `r32_ec_point(b), r32_ec_point(c)` both lie on the curve and are not the identity point. Further assumes that `r32_ec_point(b).x, r32_ec_point(c).x` are not equal in the coordinate field. | -| SETUP_EC_ADD_NE\ | `a,b,c,1,2` | `assert(r32_ec_point(b).x == C::MODULUS)` in the chip for EC ADD. For the sake of implementation convenience it also writes something (can be anything) into `[r32{0}(a): 2*C::COORD_SIZE]_2`. It is required for proper functionality that `assert(r32_ec_point(b).x != r32_ec_point(c).x)` | -| EC_DOUBLE\ | `a,b,_,1,2` | Set `r32_ec_point(a) = 2 * r32_ec_point(b)`. This doubles the input point. Assumes that `r32_ec_point(b)` lies on the curve and is not the identity point. | -| SETUP_EC_DOUBLE\ | `a,b,_,1,2` | `assert(r32_ec_point(b).x == C::MODULUS)` in the chip for EC DOUBLE. For the sake of implementation convenience it also writes something (can be anything) into `[r32{0}(a): 2*C::COORD_SIZE]_2`. It is required for proper functionality that `assert(r32_ec_point(b).y != 0 mod C::MODULUS)` | +| SW_ADD_NE\ | `a,b,c,1,2` | Set `r32_ec_point(a) = r32_ec_point(b) + r32_ec_point(c)` (curve addition). Assumes that `r32_ec_point(b), r32_ec_point(c)` both lie on the curve and are not the identity point. Further assumes that `r32_ec_point(b).x, r32_ec_point(c).x` are not equal in the coordinate field. | +| SETUP_SW_ADD_NE\ | `a,b,c,1,2` | `assert(r32_ec_point(b).x == C::MODULUS && r32_ec_point(b).y == C::A)` in the chip for SW ADD. For the sake of implementation convenience it also writes something (can be anything) into `[r32{0}(a): 2*C::COORD_SIZE]_2`. It is required for proper functionality that `assert(r32_ec_point(b).x != r32_ec_point(c).x)` | +| SW_DOUBLE\ | `a,b,_,1,2` | Set `r32_ec_point(a) = 2 * r32_ec_point(b)`. This doubles the input point. Assumes that `r32_ec_point(b)` lies on the curve and is not the identity point. | +| SETUP_SW_DOUBLE\ | `a,b,_,1,2` | `assert(r32_ec_point(b).x == C::MODULUS)` in the chip for SW DOUBLE. For the sake of implementation convenience it also writes something (can be anything) into `[r32{0}(a): 2*C::COORD_SIZE]_2`. It is required for proper functionality that `assert(r32_ec_point(b).y != 0 mod C::MODULUS)` | +| TE_ADD\ | `a,b,c,1,2` | Set `r32_ec_point(a) = r32_ec_point(b) + r32_ec_point(c)` (curve addition). Assumes that `r32_ec_point(b), r32_ec_point(c)` both lie on the curve. | +| SETUP_TE_ADD\ | `a,b,c,1,2` | `assert(r32_ec_point(b).x == C::MODULUS && r32_ec_point(b).y == C::A && r32_ec_point(c).x == C::D)` in the chip for TE ADD. For the sake of implementation convenience it also writes something (can be anything) into `[r32{0}(a): 2*C::COORD_SIZE]_2`. | ### Pairing Extension diff --git a/docs/specs/RISCV.md b/docs/specs/RISCV.md index 32d0cc63fa..622ed7b0ea 100644 --- a/docs/specs/RISCV.md +++ b/docs/specs/RISCV.md @@ -176,13 +176,15 @@ Complex extension field arithmetic over `Fp2` depends on `Fp` where `-1` is not ## Elliptic Curve Extension -The elliptic curve extension supports arithmetic over short Weierstrass curves, which requires specification of the elliptic curve `C`. The extension must be configured to support a fixed ordered list of supported curves. We use `config.curve_idx(C)` to denote the index of `C` in this list. In the list below, `idx` denotes `config.curve_idx(C)`. +The elliptic curve extension supports arithmetic over short Weierstrass curves and twisted Edwards curves, which requires specification of the elliptic curve `C`. The extension must be configured to support a fixed ordered list of supported curves. There is one list for each type of curves (short Weierstrass and twisted Edwards). We use `config.curve_idx(C)` to denote the index of `C` in the appropriate list. In the list below, `idx` denotes `config.curve_idx(C)`. | RISC-V Inst | FMT | opcode[6:0] | funct3 | funct7 | RISC-V description and notes | | --------------- | --- | ----------- | ------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | sw_add_ne\ | R | 0101011 | 001 | `idx*8` | `EcPoint([rd:2*C::COORD_SIZE]_2) = EcPoint([rs1:2*C::COORD_SIZE]_2) + EcPoint([rs2:2*C::COORD_SIZE]_2)`. Assumes that input affine points are not identity and do not have same x-coordinate. | | sw_double\ | R | 0101011 | 001 | `idx*8+1` | `EcPoint([rd:2*C::COORD_SIZE]_2) = 2 * EcPoint([rs1:2*C::COORD_SIZE]_2)`. Assumes that input affine point is not identity. `rs2` is unused and must be set to `x0`. | -| setup\ | R | 0101011 | 001 | `idx*8+2` | `assert([rs1: C::COORD_SIZE]_2 == C::MODULUS)` in the chip defined by the register index of `rs2`. For the sake of implementation convenience it also writes an unconstrained value into `[rd: 2*C::COORD_SIZE]_2`. If `ind(rs2) != 0`, then this instruction is setup for `sw_add_ne`. Otherwise it is setup for `sw_double`. When `ind(rs2) != 0` (add_ne), it is required for proper functionality that `[rs2: C::COORD_SIZE]_2 != [rs1: C::COORD_SIZE]_2`; otherwise (double), it is required that `[rs1 + C::COORD_SIZE: C::COORD_SIZE]_2 != C::Fp::ZERO` | +| sw_setup\ | R | 0101011 | 001 | `idx*8+2` | `assert([rs1: 2*C::COORD_SIZE]_2 == [C::MODULUS, CURVE_A])` in the chip defined by the register index of `rs2`. For the sake of implementation convenience it also writes an unconstrained value into `[rd: 2*C::COORD_SIZE]_2`. If `ind(rs2) != 0`, then this instruction is setup for `sw_add_ne`. Otherwise it is setup for `sw_double`. When `ind(rs2) != 0` (add_ne), it is required for proper functionality that `[rs2: C::COORD_SIZE]_2 != [rs1: C::COORD_SIZE]_2`; otherwise (double), it is required that `[rs1 + C::COORD_SIZE: C::COORD_SIZE]_2 != C::Fp::ZERO` | +| te_add\ | R | 0101011 | 100 | `idx*8` | `EcPoint([rd:2*C::COORD_SIZE]_2) = EcPoint([rs1:2*C::COORD_SIZE]_2) + EcPoint([rs2:2*C::COORD_SIZE]_2)`. | +| te_setup\ | R | 0101011 | 100 | `idx*8+2` | `assert([rs1: 2*C::COORD_SIZE]_2 == [C::MODULUS, C::CURVE_A] && [rs2: C::COORD_SIZE]_2 == C::CURVE_D])`. For the sake of implementation convenience it also writes an unconstrained value into `[rd: 2*C::COORD_SIZE]_2`. | Since `funct7` is 7-bits, up to 16 curves can be supported simultaneously. We use `idx*8` to leave some room for future expansion. diff --git a/docs/specs/transpiler.md b/docs/specs/transpiler.md index fded65b6d8..b2e585a1e8 100644 --- a/docs/specs/transpiler.md +++ b/docs/specs/transpiler.md @@ -205,7 +205,9 @@ Each VM extension's behavior is specified below. | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | sw_add_ne\ | EC_ADD_NE_RV32\ `ind(rd), ind(rs1), ind(rs2), 1, 2` | | sw_double\ | EC_DOUBLE_RV32\ `ind(rd), ind(rs1), 0, 1, 2` | -| setup\ | SETUP_EC_ADD_NE_RV32\ `ind(rd), ind(rs1), ind(rs2), 1, 2` if `ind(rs2) != 0`, SETUP_EC_DOUBLE_RV32\ `ind(rd), ind(rs1), ind(rs2), 1, 2` if `ind(rs2) = 0` | +| sw_setup\ | SETUP_EC_ADD_NE_RV32\ `ind(rd), ind(rs1), ind(rs2), 1, 2` if `ind(rs2) != 0`, SETUP_EC_DOUBLE_RV32\ `ind(rd), ind(rs1), ind(rs2), 1, 2` if `ind(rs2) = 0` | +| te_add\ | TE_ADD_RV32\ `ind(rd), ind(rs1), ind(rs2), 1, 2` | +| te_setup\ | SETUP_TE_ADD_RV32\ `ind(rd), ind(rs1), ind(rs2), 1, 2` | ### Pairing Extension From 5ab2ec4d46fcd5e00dcd6a724b3212d4ad45701b Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Wed, 29 Jan 2025 14:59:50 -0500 Subject: [PATCH 26/57] fix small bugs --- Cargo.lock | 80 ++++--------------- .../ecc/circuit/src/edwards_chip/tests.rs | 2 +- guest-libs/pairing/tests/lib.rs | 10 ++- 3 files changed, 21 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f2c813d2b..f473c15611 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1342,9 +1342,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byte-slice-cast" @@ -1638,32 +1638,6 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "const_format" -version = "0.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" -dependencies = [ - "const_format_proc_macros", -] - -[[package]] -name = "const_format_proc_macros" -version = "0.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "constant_time_eq" version = "0.3.1" @@ -1694,9 +1668,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.17" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "crc-catalog", ] @@ -3290,9 +3264,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.10.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -4054,7 +4028,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.52.0", ] @@ -4712,7 +4686,6 @@ dependencies = [ "hex-literal 0.4.1", "num-bigint 0.4.6", "openvm-algebra-circuit", - "openvm-algebra-guest", "openvm-algebra-transpiler", "openvm-circuit", "openvm-ecc-circuit", @@ -5109,6 +5082,7 @@ version = "1.2.1-rc.0" dependencies = [ "critical-section", "embedded-alloc", + "getrandom", "libm", "openvm-custom-insn", "openvm-rv32im-guest", @@ -5908,10 +5882,8 @@ dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", - "const_format", "impl-trait-for-tuples", "parity-scale-codec-derive", - "rustversion", "serde", ] @@ -6414,7 +6386,7 @@ dependencies = [ "libc", "once_cell", "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "web-sys", "winapi", ] @@ -6507,16 +6479,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.1", + "getrandom", ] [[package]] @@ -6777,7 +6740,7 @@ checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom", "libc", "untrusted", "windows-sys 0.52.0", @@ -7049,9 +7012,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.19" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -7799,7 +7762,7 @@ checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if", "fastrand", - "getrandom 0.3.1", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", @@ -8467,21 +8430,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasi" -version = "0.13.3+wasi-0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - [[package]] name = "wasm-bindgen" version = "0.2.100" diff --git a/extensions/ecc/circuit/src/edwards_chip/tests.rs b/extensions/ecc/circuit/src/edwards_chip/tests.rs index 95806d101c..2d3c432d9b 100644 --- a/extensions/ecc/circuit/src/edwards_chip/tests.rs +++ b/extensions/ecc/circuit/src/edwards_chip/tests.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use num_bigint::BigUint; use num_traits::FromPrimitive; -use openvm_circuit::arch::{testing::VmChipTestBuilder, BITWISE_OP_LOOKUP_BUS}; +use openvm_circuit::arch::testing::{VmChipTestBuilder, BITWISE_OP_LOOKUP_BUS}; use openvm_circuit_primitives::{ bigint::utils::big_uint_to_limbs, bitwise_op_lookup::{BitwiseOperationLookupBus, SharedBitwiseOperationLookupChip}, diff --git a/guest-libs/pairing/tests/lib.rs b/guest-libs/pairing/tests/lib.rs index f32e4cb4c4..19cd7cfb15 100644 --- a/guest-libs/pairing/tests/lib.rs +++ b/guest-libs/pairing/tests/lib.rs @@ -462,7 +462,7 @@ mod bls12_381 { arch::{instructions::exe::VmExe, SystemConfig}, utils::{air_test, air_test_impl, air_test_with_min_segments}, }; - use openvm_ecc_circuit::EccExtension; + use openvm_ecc_circuit::{CurveConfig, EccExtension, Rv32EccConfig, SwCurveCoeffs}; use openvm_ecc_guest::{ algebra::{field::FieldExtension, IntMod}, AffinePoint, @@ -514,10 +514,12 @@ mod bls12_381 { struct_name: BLS12_381_ECC_STRUCT_NAME.to_string(), modulus: BLS12_381_MODULUS.clone(), scalar: BLS12_381_ORDER.clone(), - a: BigUint::ZERO, - b: BigUint::from_u8(4).unwrap(), + coeffs: SwCurveCoeffs { + a: BigUint::ZERO, + b: BigUint::from_u8(4).unwrap(), + }, }; - let config = Rv32WeierstrassConfig::new(vec![curve]); + let config = Rv32EccConfig::new(vec![curve], vec![]); let elf = build_example_program_at_path_with_features( get_programs_dir!("tests/programs"), "bls_ec", From bd2f9573f747e550fa3b1f70e2af4d486b4a1eb5 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Wed, 29 Jan 2025 15:32:51 -0500 Subject: [PATCH 27/57] fix messed up rebase --- benchmarks/prove/src/bin/ecrecover.rs | 31 +++++++++++++++++---- extensions/ecc/circuit/src/ecc_extension.rs | 22 +++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/benchmarks/prove/src/bin/ecrecover.rs b/benchmarks/prove/src/bin/ecrecover.rs index 13382caeb8..268e68ff27 100644 --- a/benchmarks/prove/src/bin/ecrecover.rs +++ b/benchmarks/prove/src/bin/ecrecover.rs @@ -12,7 +12,8 @@ use openvm_circuit::{ derive::VmConfig, }; use openvm_ecc_circuit::{ - CurveConfig, EccExtension, EccExtensionExecutor, EccExtensionPeriphery, SECP256K1_CONFIG, + CurveConfig, EccExtension, EccExtensionExecutor, EccExtensionPeriphery, SwCurveCoeffs, + TeCurveCoeffs, SECP256K1_CONFIG, }; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_keccak256_circuit::{Keccak256, Keccak256Executor, Keccak256Periphery}; @@ -62,7 +63,17 @@ pub struct Rv32ImEcRecoverConfig { #[extension] pub keccak: Keccak256, #[extension] - pub weierstrass: EccExtension, + pub ecc: EccExtension, +} + +impl InitFileGenerator for Rv32ImEcRecoverConfig { + fn generate_init_file_contnts(&self) -> Option { + Some(format!( + "// This file is automatically generated by cargo openvm. Do not rename or edit.\n{}\n{}\n", + self.modular.generate_moduli_init(), + self.ecc.generate_ecc_init() + )) + } } impl InitFileGenerator for Rv32ImEcRecoverConfig { @@ -76,11 +87,19 @@ impl InitFileGenerator for Rv32ImEcRecoverConfig { } impl Rv32ImEcRecoverConfig { - pub fn for_curves(curves: Vec) -> Self { - let primes: Vec = curves + pub fn for_curves( + sw_curves: Vec>, + te_curves: Vec>, + ) -> Self { + let sw_primes: Vec = sw_curves + .iter() + .flat_map(|c| [c.modulus.clone(), c.scalar.clone()]) + .collect(); + let te_primes: Vec = te_curves .iter() .flat_map(|c| [c.modulus.clone(), c.scalar.clone()]) .collect(); + let primes = [sw_primes, te_primes].concat(); Self { system: SystemConfig::default().with_continuations(), base: Default::default(), @@ -88,7 +107,7 @@ impl Rv32ImEcRecoverConfig { io: Default::default(), modular: ModularExtension::new(primes), keccak: Default::default(), - weierstrass: EccExtension::new(curves), + ecc: EccExtension::new(sw_curves, te_curves), } } } @@ -96,7 +115,7 @@ impl Rv32ImEcRecoverConfig { fn main() -> Result<()> { let args = BenchmarkCli::parse(); - let config = Rv32ImEcRecoverConfig::for_curves(vec![SECP256K1_CONFIG.clone()]); + let config = Rv32ImEcRecoverConfig::for_curves(vec![SECP256K1_CONFIG.clone()], vec![]); let elf = args.build_bench_program("ecrecover", &config, None)?; let exe = VmExe::from_elf( diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index 816a35a514..13df0108d9 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -98,6 +98,28 @@ pub struct EccExtension { pub supported_te_curves: Vec>, } +impl EccExtension { + pub fn generate_ecc_init(&self) -> String { + let supported_sw_curves = self + .supported_sw_curves + .iter() + .map(|curve_config| curve_config.struct_name.to_string()) + .collect::>() + .join(", "); + + let supported_te_curves = self + .supported_te_curves + .iter() + .map(|curve_config| curve_config.struct_name.to_string()) + .collect::>() + .join(", "); + + format!( + "openvm_ecc_guest::sw_macros::sw_init! {{ {supported_sw_curves} }}\nopenvm_ecc_guest::te_macros::te_init! {{ {supported_te_curves} }}" + ) + } +} + #[derive(Chip, ChipUsageGetter, InstructionExecutor, AnyEnum, BytesStateful)] pub enum EccExtensionExecutor { // 32 limbs prime From 88421813bc6cccb0b707b7f5b3325eca57c72dfe Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Wed, 29 Jan 2025 15:35:34 -0500 Subject: [PATCH 28/57] update Cargo.lock --- Cargo.lock | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f473c15611..7caa83beef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4672,6 +4672,8 @@ dependencies = [ "openvm-algebra-guest", "openvm-custom-insn", "openvm-ecc-sw-macros", + "openvm-ecc-te-macros", + "openvm-platform", "openvm-rv32im-guest", "serde", "strum_macros", @@ -4682,10 +4684,9 @@ name = "openvm-ecc-integration-tests" version = "1.2.1-rc.0" dependencies = [ "eyre", - "halo2curves-axiom", - "hex-literal 0.4.1", "num-bigint 0.4.6", "openvm-algebra-circuit", + "openvm-algebra-guest", "openvm-algebra-transpiler", "openvm-circuit", "openvm-ecc-circuit", @@ -4707,6 +4708,16 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "openvm-ecc-te-macros" +version = "1.0.0-rc.0" +dependencies = [ + "num-bigint 0.4.6", + "openvm-macros-common", + "quote", + "syn 2.0.96", +] + [[package]] name = "openvm-ecc-te-macros" version = "1.0.0-rc.0" @@ -4715,7 +4726,7 @@ dependencies = [ "openvm-macros-common", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] From 7e371ef5438fce02c3f4c3297dc5043fa6c12f76 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Wed, 29 Jan 2025 17:36:58 -0500 Subject: [PATCH 29/57] fix linter errors --- examples/ecc/Cargo.toml | 1 + examples/ecc/openvm/app.vmexe | Bin 0 -> 170049 bytes examples/ecc/src/main.rs | 6 +++--- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 examples/ecc/openvm/app.vmexe diff --git a/examples/ecc/Cargo.toml b/examples/ecc/Cargo.toml index d040e24a99..c25809a41b 100644 --- a/examples/ecc/Cargo.toml +++ b/examples/ecc/Cargo.toml @@ -15,6 +15,7 @@ openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git" } openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", package = "k256" } hex-literal = { version = "0.4.1", default-features = false } serde = { version = "1.0", default-features = false, features = [ "derive" ] } +num-bigint = { version = "0.4.6", default-features = false } [features] default = [] diff --git a/examples/ecc/openvm/app.vmexe b/examples/ecc/openvm/app.vmexe new file mode 100644 index 0000000000000000000000000000000000000000..910f3a4efdacc1f3066cdc99814eb57775f548a1 GIT binary patch literal 170049 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

{N@6(4v`93|po0w;ZdgXH}KC6+d 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 Date: Thu, 30 Jan 2025 16:04:16 -0500 Subject: [PATCH 30/57] Add CachedMulTable for preprocessed msm for twisted edwards curves --- extensions/ecc/guest/src/ed25519.rs | 23 +++++- extensions/ecc/guest/src/edwards.rs | 120 +++++++++++++++++++++++++++- 2 files changed, 140 insertions(+), 3 deletions(-) diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs index 3a6b788d39..e05a619f00 100644 --- a/extensions/ecc/guest/src/ed25519.rs +++ b/extensions/ecc/guest/src/ed25519.rs @@ -1,3 +1,5 @@ +use core::ops::Add; + use hex_literal::hex; #[cfg(not(target_os = "zkvm"))] use lazy_static::lazy_static; @@ -6,7 +8,7 @@ use num_bigint::BigUint; use openvm_algebra_guest::{Field, IntMod}; use super::group::{CyclicGroup, Group}; -use crate::IntrinsicCurve; +use crate::{edwards::CachedMulTable, IntrinsicCurve}; #[cfg(not(target_os = "zkvm"))] lazy_static! { @@ -80,6 +82,7 @@ impl CyclicGroup for Ed25519Point { }; } +/* impl IntrinsicCurve for Ed25519Point { type Scalar = Ed25519Scalar; type Point = Ed25519Point; @@ -89,3 +92,21 @@ impl IntrinsicCurve for Ed25519Point { openvm_ecc_guest::msm(coeffs, bases) } } +*/ + +impl IntrinsicCurve for Ed25519Point { + type Scalar = Ed25519Scalar; + type Point = Ed25519Point; + + fn msm(coeffs: &[Self::Scalar], bases: &[Self::Point]) -> Self::Point + where + for<'a> &'a Self::Point: Add<&'a Self::Point, Output = Self::Point>, + { + if coeffs.len() < 25 { + let table = CachedMulTable::::new(bases, 4); + table.windowed_mul(coeffs) + } else { + crate::msm(coeffs, bases) + } + } +} diff --git a/extensions/ecc/guest/src/edwards.rs b/extensions/ecc/guest/src/edwards.rs index 30ede8cc80..88ffc9c084 100644 --- a/extensions/ecc/guest/src/edwards.rs +++ b/extensions/ecc/guest/src/edwards.rs @@ -1,6 +1,9 @@ -use core::ops::Mul; +use alloc::vec::Vec; +use core::ops::{AddAssign, Mul}; -use openvm_algebra_guest::Field; +use openvm_algebra_guest::{Field, IntMod}; + +use crate::{Group, IntrinsicCurve}; pub trait TwistedEdwardsPoint: Sized { /// The `a` coefficient in the twisted Edwards curve equation `ax^2 + y^2 = 1 + d x^2 y^2`. @@ -267,3 +270,116 @@ macro_rules! impl_te_group_ops { } }; } + +// This is the same as the Weierstrass version, but for Edwards curves we use +// TwistedEdwardsPoint::add_impl instead of WeierstrassPoint::add_ne_nonidentity, etc. +// Unlike the Weierstrass version, we do not require the bases to have prime order, since our addition +// formulas are complete. + +// MSM using preprocessed table (windowed method) +// Reference: modified from https://github.com/arkworks-rs/algebra/blob/master/ec/src/scalar_mul/mod.rs + +/// Cached precomputations of scalar multiples of several base points. +/// - `window_bits` is the window size used for the precomputation +/// - `max_scalar_bits` is the maximum size of the scalars that will be multiplied +/// - `table` is the precomputed table +pub struct CachedMulTable<'a, C: IntrinsicCurve> { + /// Window bits. Must be > 0. + /// For alignment, we currently require this to divide 8 (bits in a byte). + pub window_bits: usize, + pub bases: &'a [C::Point], + /// `table[i][j] = (j + 2) * bases[i]` for `j + 2 < 2 ** window_bits` + table: Vec>, + /// Needed to return reference to the identity point. + identity: C::Point, +} + +impl<'a, C: IntrinsicCurve> CachedMulTable<'a, C> +where + C::Point: TwistedEdwardsPoint + Group, + C::Scalar: IntMod, +{ + pub fn new(bases: &'a [C::Point], window_bits: usize) -> Self { + assert!(window_bits > 0); + let window_size = 1 << window_bits; + let table = bases + .iter() + .map(|base| { + if base.is_identity() { + vec![::IDENTITY; window_size - 2] + } else { + let mut multiples = Vec::with_capacity(window_size - 2); + for _ in 0..window_size - 2 { + let multiple = multiples + .last() + .map(|last| TwistedEdwardsPoint::add_impl(last, base)) + .unwrap_or_else(|| base.double()); + multiples.push(multiple); + } + multiples + } + }) + .collect(); + + Self { + window_bits, + bases, + table, + identity: ::IDENTITY, + } + } + + fn get_multiple(&self, base_idx: usize, scalar: usize) -> &C::Point { + if scalar == 0 { + &self.identity + } else if scalar == 1 { + unsafe { self.bases.get_unchecked(base_idx) } + } else { + unsafe { self.table.get_unchecked(base_idx).get_unchecked(scalar - 2) } + } + } + + /// Computes `sum scalars[i] * bases[i]`. + /// + /// For implementation simplicity, currently only implemented when + /// `window_bits` divides 8 (number of bits in a byte). + pub fn windowed_mul(&self, scalars: &[C::Scalar]) -> C::Point { + assert_eq!(8 % self.window_bits, 0); + assert_eq!(scalars.len(), self.bases.len()); + let windows_per_byte = 8 / self.window_bits; + + let num_windows = C::Scalar::NUM_LIMBS * windows_per_byte; + let mask = (1u8 << self.window_bits) - 1; + + // The current byte index (little endian) at the current step of the + // windowed method, across all scalars. + let mut limb_idx = C::Scalar::NUM_LIMBS; + // The current bit (little endian) within the current byte of the windowed + // method. The window will look at bits `bit_idx..bit_idx + window_bits`. + // bit_idx will always be in range [0, 8) + let mut bit_idx = 0; + + let mut res = ::IDENTITY; + for outer in 0..num_windows { + if bit_idx == 0 { + limb_idx -= 1; + bit_idx = 8 - self.window_bits; + } else { + bit_idx -= self.window_bits; + } + + if outer != 0 { + for _ in 0..self.window_bits { + res.double_assign(); + } + } + for (base_idx, scalar) in scalars.iter().enumerate() { + let scalar = (scalar.as_le_bytes()[limb_idx] >> bit_idx) & mask; + let summand = self.get_multiple(base_idx, scalar as usize); + // handles identity + res.add_assign(summand); + } + } + res + } +} From 1590c055d19477581d3885eaaf52b56865bab4d6 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 28 Mar 2025 17:59:33 -0400 Subject: [PATCH 31/57] Add hint fallback for twisted Edwards curves --- Cargo.lock | 984 ++++++++++++++++-------- extensions/ecc/guest/src/lib.rs | 32 +- extensions/ecc/guest/src/weierstrass.rs | 13 - extensions/ecc/te-macros/src/lib.rs | 112 ++- 4 files changed, 768 insertions(+), 373 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7caa83beef..3d63a06025 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,7 +58,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -158,7 +158,7 @@ dependencies = [ "derive_more 2.0.1", "foldhash", "hashbrown 0.15.2", - "indexmap 2.7.1", + "indexmap 2.8.0", "itoa", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-asm", @@ -189,6 +189,20 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10ae8e9a91d328ae954c22542415303919aabe976fe7a92eb06db1b68fd59f2" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error2", "proc-macro2", "quote", "syn 2.0.98", @@ -350,7 +364,7 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.96" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" @@ -604,13 +618,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.86" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -640,7 +654,7 @@ checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -651,9 +665,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.5.18" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90aff65e86db5fe300752551c1b015ef72b708ac54bded8ef43d0d53cb7cb0b1" +checksum = "8c39646d1a6b51240a1a23bb57ea4eebede7e16fbc237fdc876980233dcecb4f" dependencies = [ "aws-credential-types", "aws-runtime", @@ -661,7 +675,7 @@ dependencies = [ "aws-sdk-ssooidc", "aws-sdk-sts", "aws-smithy-async", - "aws-smithy-http 0.61.1", + "aws-smithy-http", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -670,7 +684,7 @@ dependencies = [ "bytes", "fastrand", "hex", - "http 0.2.12", + "http 1.3.1", "ring", "time", "tokio", @@ -681,9 +695,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e8f6b615cb5fc60a98132268508ad104310f0cfb25a1c22eee76efdf9154da" +checksum = "4471bef4c22a06d2c7a1b6492493d3fdf24a805323109d6874f9c94d5906ac14" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -691,17 +705,40 @@ dependencies = [ "zeroize", ] +[[package]] +name = "aws-lc-rs" +version = "1.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dabb68eb3a7aa08b46fddfd59a3d55c978243557a90ab804769f7e20e67d2b01" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77926887776171ced7d662120a75998e444d3750c951abfe07f90da130514b1f" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "aws-runtime" -version = "1.5.5" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dd04d39cc12844c0994f2c9c5a6f5184c22e9188ec1ff723de41910a21dcad" +checksum = "0aff45ffe35196e593ea3b9dd65b320e51e2dda95aff4390bc459e461d09c6ad" dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http 0.60.12", + "aws-smithy-http", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -719,9 +756,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.78.0" +version = "1.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038614b6cf7dd68d9a7b5b39563d04337eb3678d1d4173e356e927b0356158a" +checksum = "3a36b09e8273d89c4f35ea122b83b30e48f906f3b644460d72a7d3656d1be93d" dependencies = [ "aws-credential-types", "aws-runtime", @@ -729,7 +766,7 @@ dependencies = [ "aws-smithy-async", "aws-smithy-checksums", "aws-smithy-eventstream", - "aws-smithy-http 0.61.1", + "aws-smithy-http", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -741,6 +778,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", + "http 1.3.1", "http-body 0.4.6", "lru", "once_cell", @@ -753,20 +791,21 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.61.0" +version = "1.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e65ff295979977039a25f5a0bf067a64bc5e6aa38f3cef4037cf42516265553c" +checksum = "02d4bdb0e5f80f0689e61c77ab678b2b9304af329616af38aef5b6b967b8e736" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http 0.61.1", + "aws-smithy-http", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", + "fastrand", "http 0.2.12", "once_cell", "regex-lite", @@ -775,20 +814,21 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.62.0" +version = "1.65.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91430a60f754f235688387b75ee798ef00cfd09709a582be2b7525ebb5306d4f" +checksum = "acbbb3ce8da257aedbccdcb1aadafbbb6a5fe9adf445db0e1ea897bdc7e22d08" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http 0.61.1", + "aws-smithy-http", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", + "fastrand", "http 0.2.12", "once_cell", "regex-lite", @@ -797,14 +837,14 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.62.0" +version = "1.65.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9276e139d39fff5a0b0c984fc2d30f970f9a202da67234f948fda02e5bea1dbe" +checksum = "96a78a8f50a1630db757b60f679c8226a8a70ee2ab5f5e6e51dc67f6c61c7cfd" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http 0.61.1", + "aws-smithy-http", "aws-smithy-json", "aws-smithy-query", "aws-smithy-runtime", @@ -812,6 +852,7 @@ dependencies = [ "aws-smithy-types", "aws-smithy-xml", "aws-types", + "fastrand", "http 0.2.12", "once_cell", "regex-lite", @@ -820,13 +861,13 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.9" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bfe75fad52793ce6dec0dc3d4b1f388f038b5eb866c8d4d7f3a8e21b5ea5051" +checksum = "69d03c3c05ff80d54ff860fe38c726f6f494c639ae975203a101335f223386db" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", - "aws-smithy-http 0.60.12", + "aws-smithy-http", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", @@ -835,7 +876,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.2.0", + "http 1.3.1", "once_cell", "p256 0.11.1", "percent-encoding", @@ -849,9 +890,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa59d1327d8b5053c54bf2eaae63bf629ba9e904434d0835a28ed3c0ed0a614e" +checksum = "1e190749ea56f8c42bf15dd76c65e14f8f765233e6df9b0506d9d934ebef867c" dependencies = [ "futures-util", "pin-project-lite", @@ -860,11 +901,11 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.63.0" +version = "0.63.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2dc8d842d872529355c72632de49ef8c5a2949a4472f10e802f28cf925770c" +checksum = "b65d21e1ba6f2cdec92044f904356a19f5ad86961acf015741106cdfafd747c0" dependencies = [ - "aws-smithy-http 0.60.12", + "aws-smithy-http", "aws-smithy-types", "bytes", "crc32c", @@ -882,9 +923,9 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.7" +version = "0.60.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "461e5e02f9864cba17cff30f007c2e37ade94d01e87cdb5204e44a84e6d38c17" +checksum = "7c45d3dddac16c5c59d553ece225a88870cf81b7b813c9cc17b78cf4685eac7a" dependencies = [ "aws-smithy-types", "bytes", @@ -893,16 +934,18 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.60.12" +version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7809c27ad8da6a6a68c454e651d4962479e81472aa19ae99e59f9aba1f9713cc" +checksum = "c5949124d11e538ca21142d1fba61ab0a2a2c1bc3ed323cdb3e4b878bfb83166" dependencies = [ + "aws-smithy-eventstream", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", "bytes-utils", "futures-core", "http 0.2.12", + "http 1.3.1", "http-body 0.4.6", "once_cell", "percent-encoding", @@ -912,35 +955,52 @@ dependencies = [ ] [[package]] -name = "aws-smithy-http" -version = "0.61.1" +name = "aws-smithy-http-client" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f276f21c7921fe902826618d1423ae5bf74cf8c1b8472aee8434f3dfd31824" +checksum = "8aff1159006441d02e57204bf57a1b890ba68bedb6904ffd2873c1c4c11c546b" dependencies = [ - "aws-smithy-eventstream", + "aws-smithy-async", "aws-smithy-runtime-api", "aws-smithy-types", - "bytes", - "bytes-utils", - "futures-core", + "h2 0.4.8", "http 0.2.12", + "http 1.3.1", "http-body 0.4.6", - "once_cell", - "percent-encoding", + "hyper 0.14.32", + "hyper 1.6.0", + "hyper-rustls 0.24.2", + "hyper-rustls 0.27.5", + "hyper-util", "pin-project-lite", - "pin-utils", + "rustls 0.21.12", + "rustls 0.23.25", + "rustls-native-certs 0.8.1", + "rustls-pki-types", + "tokio", + "tower", "tracing", ] [[package]] name = "aws-smithy-json" -version = "0.61.2" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "623a51127f24c30776c8b374295f2df78d92517386f77ba30773f15a30ce1422" +checksum = "92144e45819cae7dc62af23eac5a038a58aa544432d2102609654376a900bd07" dependencies = [ "aws-smithy-types", ] +[[package]] +name = "aws-smithy-observability" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445d065e76bc1ef54963db400319f1dd3ebb3e0a74af20f7f7630625b0cc7cc0" +dependencies = [ + "aws-smithy-runtime-api", + "once_cell", +] + [[package]] name = "aws-smithy-query" version = "0.60.7" @@ -953,42 +1013,40 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.8" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d526a12d9ed61fadefda24abe2e682892ba288c2018bcb38b1b4c111d13f6d92" +checksum = "0152749e17ce4d1b47c7747bdfec09dac1ccafdcbc741ebf9daa2a373356730f" dependencies = [ "aws-smithy-async", - "aws-smithy-http 0.60.12", + "aws-smithy-http", + "aws-smithy-http-client", + "aws-smithy-observability", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", "fastrand", - "h2", "http 0.2.12", + "http 1.3.1", "http-body 0.4.6", "http-body 1.0.1", - "httparse", - "hyper", - "hyper-rustls", "once_cell", "pin-project-lite", "pin-utils", - "rustls", "tokio", "tracing", ] [[package]] name = "aws-smithy-runtime-api" -version = "1.7.3" +version = "1.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92165296a47a812b267b4f41032ff8069ab7ff783696d217f0994a0d7ab585cd" +checksum = "3da37cf5d57011cb1753456518ec76e31691f1f474b73934a284eb2a1c76510f" dependencies = [ "aws-smithy-async", "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.2.0", + "http 1.3.1", "pin-project-lite", "tokio", "tracing", @@ -997,16 +1055,16 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.13" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7b8a53819e42f10d0821f56da995e1470b199686a1809168db6ca485665f042" +checksum = "836155caafba616c0ff9b07944324785de2ab016141c3550bd1c07882f8cee8f" dependencies = [ "base64-simd", "bytes", "bytes-utils", "futures-core", "http 0.2.12", - "http 1.2.0", + "http 1.3.1", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", @@ -1032,9 +1090,9 @@ dependencies = [ [[package]] name = "aws-types" -version = "1.3.5" +version = "1.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbd0a668309ec1f66c0f6bda4840dd6d4796ae26d699ebc266d7cc95c6d040f" +checksum = "3873f8deed8927ce8d04487630dc9ff73193bab64742a61d050e57a68dec4125" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -1102,9 +1160,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.6.0" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" [[package]] name = "bincode" @@ -1115,6 +1173,29 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.100", + "which", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -1147,9 +1228,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitcode" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c1406a27371b2f76232a2259df6ab607b91b5a0a7476a7729ff590df5a969a" +checksum = "cf300f4aa6e66f3bdff11f1236a88c622fe47ea814524792240b4d554d9858ee" dependencies = [ "arrayvec", "bitcode_derive", @@ -1166,7 +1247,7 @@ checksum = "42b6b4cb608b8282dc3b53d0f4c9ab404655d562674c682db7e6c0458cc83c23" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1215,9 +1296,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1230237285e3e10cde447185e8975408ae24deaa67205ce684805c25bc0c7937" +checksum = "b17679a8d69b6d7fd9cd9801a536cec9fa5e5970b69f9d4747f70b39b031f5e7" dependencies = [ "arrayref", "arrayvec", @@ -1278,9 +1359,9 @@ dependencies = [ [[package]] name = "bon" -version = "3.3.2" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7acc34ff59877422326db7d6f2d845a582b16396b6b08194942bf34c6528ab" +checksum = "65268237be94042665b92034f979c42d431d2fd998b49809543afe3e66abad1c" dependencies = [ "bon-macros", "rustversion", @@ -1288,9 +1369,9 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.3.2" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4159dd617a7fbc9be6a692fe69dc2954f8e6bb6bb5e4d7578467441390d77fd0" +checksum = "803c95b2ecf650eb10b5f87dda6b9f6a1b758cee53245e2b7b825c9b3803a443" dependencies = [ "darling", "ident_case", @@ -1342,21 +1423,21 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byte-slice-cast" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytemuck" -version = "1.21.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" [[package]] name = "byteorder" @@ -1366,7 +1447,7 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" dependencies = [ @@ -1473,7 +1554,7 @@ checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_json", "thiserror 1.0.69", @@ -1487,15 +1568,24 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.14" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "jobserver", "libc", "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -1510,9 +1600,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1560,9 +1650,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.30" +version = "4.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" +checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff" dependencies = [ "clap_builder", "clap_derive", @@ -1570,9 +1660,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.30" +version = "4.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c" +checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489" dependencies = [ "anstream", "anstyle", @@ -1582,14 +1672,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.28" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1598,6 +1688,15 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + [[package]] name = "colorchoice" version = "1.0.3" @@ -1638,6 +1737,26 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "constant_time_eq" version = "0.3.1" @@ -1660,6 +1779,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1668,11 +1797,11 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ - "crc-catalog", + "libc", ] [[package]] @@ -1717,15 +1846,6 @@ dependencies = [ "crc", ] -[[package]] -name = "crc64fast-nvme" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4955638f00a809894c947f85a024020a20815b65a5eea633798ea7924edab2b3" -dependencies = [ - "crc", -] - [[package]] name = "criterion" version = "0.5.1" @@ -1866,9 +1986,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", @@ -1876,27 +1996,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1922,9 +2042,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" dependencies = [ "powerfmt", "serde", @@ -1949,7 +2069,7 @@ checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1960,49 +2080,45 @@ checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] -name = "derive-new" -version = "0.7.0" +name = "derive_more" +version = "0.99.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" dependencies = [ + "convert_case", "proc-macro2", "quote", - "syn 2.0.98", + "rustc_version 0.4.1", + "syn 2.0.100", ] [[package]] -name = "derive-new" -version = "0.7.0" +name = "derive_more" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", + "derive_more-impl 1.0.0", ] [[package]] name = "derive_more" -version = "0.99.19" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.1", - "syn 2.0.98", + "derive_more-impl 2.0.1", ] [[package]] -name = "derive_more" +name = "derive_more-impl" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "derive_more-impl 1.0.0", ] @@ -2018,7 +2134,7 @@ dependencies = [ [[package]] name = "derive_more-impl" -version = "1.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ @@ -2142,7 +2258,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -2173,9 +2289,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feeef44e73baff3a26d371801df019877a9866a8c493d315ab00177843314f35" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" [[package]] name = "ecdsa" @@ -2206,9 +2322,9 @@ dependencies = [ [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "elf" @@ -2306,7 +2422,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -2317,7 +2433,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -2331,9 +2447,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697" dependencies = [ "anstream", "anstyle", @@ -2638,7 +2754,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" @@ -2819,9 +2935,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", "libc", @@ -2831,14 +2947,14 @@ dependencies = [ [[package]] name = "getset" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded738faa0e88d3abc9d1a13cb11adc2073c400969eeb8793cf7132589959fc" +checksum = "f3586f256131df87204eb733da72e3d3eb4f343c639f4b7be279ac7c48baeafe" dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -2862,9 +2978,9 @@ dependencies = [ [[package]] name = "glam" -version = "0.30.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17fcdf9683c406c2fc4d124afd29c0d595e22210d633cbdb8695ba9935ab1dc6" +checksum = "bf3aa70d918d2b234126ff4f850f628f172542bf0603ded26b8ee36e5e22d5f9" [[package]] name = "glob" @@ -2920,7 +3036,26 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.7.1", + "indexmap 2.8.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap 2.8.0", "slab", "tokio", "tokio-util", @@ -2929,9 +3064,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" dependencies = [ "cfg-if", "crunchy", @@ -3154,9 +3289,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" [[package]] name = "hex" @@ -3219,9 +3354,9 @@ dependencies = [ [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -3246,27 +3381,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.2.0", + "http 1.3.1", ] [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", - "http 1.2.0", + "futures-core", + "http 1.3.1", "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -3284,7 +3419,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "httparse", @@ -3298,6 +3433,26 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.8", + "http 1.3.1", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -3306,24 +3461,62 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper", + "hyper 0.14.32", "log", - "rustls", - "rustls-native-certs", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http 1.3.1", + "hyper 1.6.0", + "hyper-util", + "rustls 0.23.25", + "rustls-native-certs 0.8.1", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.2", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.6.0", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -3378,9 +3571,9 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" @@ -3402,9 +3595,9 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" [[package]] name = "icu_properties" @@ -3423,9 +3616,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" [[package]] name = "icu_provider" @@ -3452,7 +3645,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -3558,9 +3751,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -3590,11 +3783,11 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "is-terminal" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.4.0", + "hermit-abi 0.5.0", "libc", "windows-sys 0.59.0", ] @@ -3623,6 +3816,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -3634,9 +3836,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" @@ -3776,11 +3978,17 @@ dependencies = [ "spin", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" -version = "0.2.169" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libgit2-sys" @@ -3794,6 +4002,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets", +] + [[package]] name = "libm" version = "0.2.11" @@ -3802,9 +4020,9 @@ checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libmimalloc-sys" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44" +checksum = "07d0e07885d6a754b9c7993f2625187ad694ee985d60f23355ff0e7077261502" dependencies = [ "cc", "libc", @@ -3822,9 +4040,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.21" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "libc", @@ -3844,9 +4062,15 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" + [[package]] name = "litemap" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" @@ -3868,9 +4092,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] name = "log" -version = "0.4.25" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru" @@ -3967,7 +4191,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62a6a1f7141f1d9bc7a886b87536bbfc97752e08b369e1e0453a9acfab5f5da4" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.8.0", "itoa", "lockfree-object-pool", "metrics", @@ -3988,7 +4212,7 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "hashbrown 0.14.5", - "indexmap 2.7.1", + "indexmap 2.8.0", "metrics", "num_cpus", "ordered-float", @@ -3999,9 +4223,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633" +checksum = "99585191385958383e13f6b822e6b6d8d9cf928e7d286ceb092da92b43c87bc1" dependencies = [ "libmimalloc-sys", ] @@ -4014,9 +4238,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" dependencies = [ "adler2", ] @@ -4028,7 +4252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -4047,6 +4271,16 @@ dependencies = [ "smallvec", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -4256,7 +4490,7 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" dependencies = [ @@ -4266,7 +4500,7 @@ dependencies = [ [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" @@ -4351,7 +4585,7 @@ version = "1.2.1-rc.0" dependencies = [ "openvm-macros-common", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -4377,7 +4611,7 @@ dependencies = [ "num-prime", "openvm-macros-common", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -4578,7 +4812,7 @@ version = "1.2.1-rc.0" dependencies = [ "itertools 0.14.0", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -4603,7 +4837,7 @@ version = "1.2.1-rc.0" dependencies = [ "itertools 0.14.0", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -4626,7 +4860,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -4673,7 +4907,6 @@ dependencies = [ "openvm-custom-insn", "openvm-ecc-sw-macros", "openvm-ecc-te-macros", - "openvm-platform", "openvm-rv32im-guest", "serde", "strum_macros", @@ -4684,6 +4917,7 @@ name = "openvm-ecc-integration-tests" version = "1.2.1-rc.0" dependencies = [ "eyre", + "hex-literal", "num-bigint 0.4.6", "openvm-algebra-circuit", "openvm-algebra-guest", @@ -4705,28 +4939,18 @@ version = "1.2.1-rc.0" dependencies = [ "openvm-macros-common", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] name = "openvm-ecc-te-macros" -version = "1.0.0-rc.0" -dependencies = [ - "num-bigint 0.4.6", - "openvm-macros-common", - "quote", - "syn 2.0.96", -] - -[[package]] -name = "openvm-ecc-te-macros" -version = "1.0.0-rc.0" +version = "1.0.0-rc.2" dependencies = [ "num-bigint 0.4.6", "openvm-macros-common", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.100", ] [[package]] @@ -4863,7 +5087,7 @@ dependencies = [ name = "openvm-macros-common" version = "1.2.1-rc.0" dependencies = [ - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -4943,7 +5167,7 @@ name = "openvm-native-compiler-derive" version = "1.2.1-rc.0" dependencies = [ "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -5093,7 +5317,7 @@ version = "1.2.1-rc.0" dependencies = [ "critical-section", "embedded-alloc", - "getrandom", + "getrandom 0.2.15", "libm", "openvm-custom-insn", "openvm-rv32im-guest", @@ -5893,8 +6117,10 @@ dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", + "const_format", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] @@ -6044,12 +6270,12 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.15" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" dependencies = [ "memchr", - "thiserror 2.0.11", + "thiserror 2.0.12", "ucd-trie", ] @@ -6139,9 +6365,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plotters" @@ -6173,9 +6399,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "poseidon-primitives" @@ -6243,11 +6469,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy", + "zerocopy 0.8.24", ] [[package]] @@ -6258,12 +6484,12 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "prettyplease" -version = "0.2.29" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" +checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" dependencies = [ "proc-macro2", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -6282,9 +6508,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ "toml_edit 0.22.24", ] @@ -6308,14 +6534,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] @@ -6397,7 +6623,7 @@ dependencies = [ "libc", "once_cell", "raw-cpuid", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "web-sys", "winapi", ] @@ -6419,13 +6645,19 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" @@ -6490,7 +6722,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -6504,9 +6736,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.4.0" +version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529468c1335c1c03919960dfefdb1b3648858c20d7ec2d0663e728e4a717efbc" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ "bitflags 2.8.0", ] @@ -6745,13 +6977,13 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.13" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "untrusted", "windows-sys 0.52.0", @@ -6944,7 +7176,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.25", + "semver 1.0.26", ] [[package]] @@ -6952,6 +7184,19 @@ name = "rustix" version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.8.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" dependencies = [ "bitflags 2.8.0", "errno", @@ -6968,10 +7213,24 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.103.1", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -6981,7 +7240,19 @@ dependencies = [ "openssl-probe", "rustls-pemfile", "schannel", - "security-framework", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.2.0", ] [[package]] @@ -6993,6 +7264,12 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -7003,11 +7280,23 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.103.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "rusty-fork" @@ -7023,9 +7312,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -7167,9 +7456,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] @@ -7185,9 +7474,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -7212,22 +7501,22 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] name = "serde_json" -version = "1.0.139" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.8.0", "itoa", "memchr", "ryu", @@ -7275,7 +7564,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.1", + "indexmap 2.8.0", "serde", "serde_derive", "serde_json", @@ -7607,7 +7896,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -7688,9 +7977,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.98" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -7767,15 +8056,14 @@ checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "tempfile" -version = "3.17.1" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", - "getrandom", + "getrandom 0.3.2", "once_cell", - "rustix", + "rustix 1.0.3", "windows-sys 0.59.0", ] @@ -7808,7 +8096,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -7819,7 +8107,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", "test-case-core", ] @@ -7842,7 +8130,7 @@ checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -7856,11 +8144,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -7871,18 +8159,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -7926,9 +8214,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -7943,15 +8231,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -8061,15 +8349,25 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls 0.23.25", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" dependencies = [ "bytes", "futures-core", @@ -8131,7 +8429,7 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.8.0", "serde", "serde_spanned", "toml_datetime", @@ -8164,7 +8462,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -8282,7 +8580,7 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" @@ -8366,9 +8664,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.13.2" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" [[package]] name = "valuable" @@ -8441,6 +8739,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -8463,7 +8770,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", "wasm-bindgen-shared", ] @@ -8498,7 +8805,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -8588,6 +8895,12 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + [[package]] name = "windows-sys" version = "0.52.0" @@ -8757,9 +9070,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags 2.8.0", ] @@ -8823,7 +9136,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", "synstructure", ] @@ -8833,8 +9146,16 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive 0.8.24", ] [[package]] @@ -8845,27 +9166,38 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", "synstructure", ] @@ -8886,7 +9218,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] diff --git a/extensions/ecc/guest/src/lib.rs b/extensions/ecc/guest/src/lib.rs index 8778ba5c3d..33d06409e0 100644 --- a/extensions/ecc/guest/src/lib.rs +++ b/extensions/ecc/guest/src/lib.rs @@ -62,8 +62,9 @@ impl TeBaseFunct7 { pub const TWISTED_EDWARDS_MAX_KINDS: u8 = 8; } -/// A trait for elliptic curves that bridges the openvm types and external types with CurveArithmetic etc. -/// Implement this for external curves with corresponding openvm point and scalar types. +/// A trait for elliptic curves that bridges the openvm types and external types with +/// CurveArithmetic etc. Implement this for external curves with corresponding openvm point and +/// scalar types. pub trait IntrinsicCurve { type Scalar: Clone; type Point: Clone; @@ -77,23 +78,12 @@ pub trait IntrinsicCurve { pub trait FromCompressed { /// Given `x`-coordinate, /// - /// ## Panics - /// If the input is not a valid compressed point. - /// The zkVM panics instead of returning an [Option] because this function - /// can only guarantee correct behavior when decompression is possible, - /// but the function cannot compute the boolean equal to true if and only - /// if decompression is possible. - // This is because we rely on a hint for the correct decompressed value - // and then constrain its correctness. A malicious prover could hint - // incorrectly, so there is no way to use a hint to prove that the input - // **cannot** be decompressed. - fn decompress(x: Coordinate, rec_id: &u8) -> Self; - - /// If it exists, hints the unique `y` coordinate that is less than `Coordinate::MODULUS` - /// such that `(x, y)` is a point on the curve and `y` has parity equal to `rec_id`. - /// If such `y` does not exist, undefined behavior. - /// - /// This is only a hint, and the returned `y` does not guarantee any of the above properties. - /// They must be checked separately. Normal users should use `decompress` directly. - fn hint_decompress(x: &Coordinate, rec_id: &u8) -> Coordinate; + /// Decompresses a point from its x-coordinate and a recovery identifier which indicates + /// the parity of the y-coordinate. Given the x-coordinate, this function attempts to find the + /// corresponding y-coordinate that satisfies the elliptic curve equation. If successful, it + /// returns the point as an instance of Self. If the point cannot be decompressed, it returns + /// None. + fn decompress(x: Coordinate, rec_id: &u8) -> Option + where + Self: core::marker::Sized; } diff --git a/extensions/ecc/guest/src/weierstrass.rs b/extensions/ecc/guest/src/weierstrass.rs index 3d06d3ed98..74289f8b31 100644 --- a/extensions/ecc/guest/src/weierstrass.rs +++ b/extensions/ecc/guest/src/weierstrass.rs @@ -112,19 +112,6 @@ pub trait WeierstrassPoint: Clone + Sized { } } -pub trait FromCompressed { - /// Given `x`-coordinate, - /// - /// Decompresses a point from its x-coordinate and a recovery identifier which indicates - /// the parity of the y-coordinate. Given the x-coordinate, this function attempts to find the - /// corresponding y-coordinate that satisfies the elliptic curve equation. If successful, it - /// returns the point as an instance of Self. If the point cannot be decompressed, it returns - /// None. - fn decompress(x: Coordinate, rec_id: &u8) -> Option - where - Self: core::marker::Sized; -} - // MSM using preprocessed table (windowed method) // Reference: modified from https://github.com/arkworks-rs/algebra/blob/master/ec/src/scalar_mul/mod.rs // diff --git a/extensions/ecc/te-macros/src/lib.rs b/extensions/ecc/te-macros/src/lib.rs index ac4b49ddbb..2a58cd767e 100644 --- a/extensions/ecc/te-macros/src/lib.rs +++ b/extensions/ecc/te-macros/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(proc_macro_diagnostic)] - extern crate proc_macro; use openvm_macros_common::MacroArgs; @@ -80,6 +78,7 @@ pub fn te_declare(input: TokenStream) -> TokenStream { } create_extern_func!(te_add_extern_func); create_extern_func!(te_hint_decompress_extern_func); + create_extern_func!(hint_non_qr_extern_func); let group_ops_mod_name = format_ident!("{}_ops", struct_name.to_string().to_lowercase()); @@ -87,6 +86,7 @@ pub fn te_declare(input: TokenStream) -> TokenStream { extern "C" { fn #te_add_extern_func(rd: usize, rs1: usize, rs2: usize); fn #te_hint_decompress_extern_func(rs1: usize, rs2: usize); + fn #hint_non_qr_extern_func(); } #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] @@ -202,21 +202,28 @@ pub fn te_declare(input: TokenStream) -> TokenStream { } mod #group_ops_mod_name { - use ::openvm_ecc_guest::{edwards::TwistedEdwardsPoint, FromCompressed, impl_te_group_ops}; + use ::openvm_ecc_guest::{edwards::TwistedEdwardsPoint, FromCompressed, DecompressionHint, impl_te_group_ops}; use super::*; impl_te_group_ops!(#struct_name, #intmod_type); impl FromCompressed<#intmod_type> for #struct_name { - fn decompress(y: #intmod_type, rec_id: &u8) -> Self { - let x = <#struct_name as FromCompressed<#intmod_type>>::hint_decompress(&y, rec_id); - // Must assert unique so we can check the parity - x.assert_unique(); - assert_eq!(x.as_le_bytes()[0] & 1, *rec_id & 1); - <#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::from_xy(x, y).expect("decompressed point not on curve") + fn decompress(y: #intmod_type, rec_id: &u8) -> Option { + match Self::honest_host_decompress(&y, rec_id) { + // successfully decompressed + Some(Some(ret)) => Some(ret), + // successfully proved that the point cannot be decompressed + Some(None) => None, + None => { + // host is dishonest, enter infinite loop + loop { + openvm::io::println("ERROR: Decompression hint is invalid. Entering infinite loop."); + } + } + } } - fn hint_decompress(y: &#intmod_type, rec_id: &u8) -> #intmod_type { + fn hint_decompress(y: &#intmod_type, rec_id: &u8) -> Option> { #[cfg(not(target_os = "zkvm"))] { unimplemented!() @@ -225,15 +232,94 @@ pub fn te_declare(input: TokenStream) -> TokenStream { { use openvm::platform as openvm_platform; // needed for hint_buffer_u32! - let x = core::mem::MaybeUninit::<#intmod_type>::uninit(); + let possible = core::mem::MaybeUninit::::uninit(); + let sqrt = core::mem::MaybeUninit::<#intmod_type>::uninit(); unsafe { #te_hint_decompress_extern_func(y as *const _ as usize, rec_id as *const u8 as usize); - let ptr = x.as_ptr() as *const u8; + let possible_ptr = possible.as_ptr() as *const u32; + openvm_rv32im_guest::hint_store_u32!(possible_ptr); + openvm_rv32im_guest::hint_buffer_u32!(sqrt.as_ptr() as *const u8, <#intmod_type as openvm_algebra_guest::IntMod>::NUM_LIMBS / 4); + let possible = possible.assume_init(); + if possible == 0 || possible == 1 { + Some(DecompressionHint { possible: possible == 1, sqrt: sqrt.assume_init() }) + } else { + None + } + } + } + } + } + + impl #struct_name { + // Returns None if the hint is incorrect (i.e. the host is dishonest) + // Returns Some(None) if the hint proves that the point cannot be decompressed + fn honest_host_decompress(y: &#intmod_type, rec_id: &u8) -> Option> { + let hint = <#struct_name as FromCompressed<#intmod_type>>::hint_decompress(y, rec_id)?; + + if hint.possible { + // ensure x < modulus + hint.sqrt.assert_reduced(); + + if hint.sqrt.as_le_bytes()[0] & 1 != *rec_id & 1 { + None + } else { + let ret = <#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::from_xy(hint.sqrt, y.clone())?; + Some(Some(ret)) + } + } else { + // ensure sqrt < modulus + hint.sqrt.assert_reduced(); + + let lhs = (&hint.sqrt * &hint.sqrt) * (&<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_D * y * y - &<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_A * &hint.sqrt * &hint.sqrt - &<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_A); + let rhs = y * y - &<#intmod_type as openvm_algebra_guest::IntMod>::ONE; + if lhs == rhs * Self::get_non_qr() { + Some(None) + } else { + None + } + } + } + + // Generate a non quadratic residue in the coordinate field by using a hint + fn init_non_qr() -> alloc::boxed::Box<::Coordinate> { + #[cfg(not(target_os = "zkvm"))] + { + unimplemented!(); + } + #[cfg(target_os = "zkvm")] + { + use openvm::platform as openvm_platform; // needed for hint_buffer_u32 + let mut non_qr_uninit = core::mem::MaybeUninit::<#intmod_type>::uninit(); + let mut non_qr; + unsafe { + #hint_non_qr_extern_func(); + let ptr = non_qr_uninit.as_ptr() as *const u8; openvm_rv32im_guest::hint_buffer_u32!(ptr, <#intmod_type as openvm_algebra_guest::IntMod>::NUM_LIMBS / 4); - x.assume_init() + non_qr = non_qr_uninit.assume_init(); + } + // ensure non_qr < modulus + non_qr.assert_reduced(); + + // construct exp = (p-1)/2 as an integer by first constraining exp = (p-1)/2 (mod p) and then exp < p + let exp = -<#intmod_type as openvm_algebra_guest::IntMod>::ONE.div_unsafe(#intmod_type::from_const_u8(2)); + exp.assert_reduced(); + + if non_qr.exp_bytes(true, &exp.to_be_bytes()) != -<#intmod_type as openvm_algebra_guest::IntMod>::ONE + { + // non_qr is not a non quadratic residue, so host is dishonest + loop { + openvm::io::println("ERROR: Non quadratic residue hint is invalid. Entering infinite loop."); + } } + + alloc::boxed::Box::new(non_qr) } } + + pub fn get_non_qr() -> &'static #intmod_type { + static non_qr: ::openvm_ecc_guest::once_cell::race::OnceBox<#intmod_type> = ::openvm_ecc_guest::once_cell::race::OnceBox::new(); + &non_qr.get_or_init(Self::init_non_qr) + } } } }); From 171bf4025915fb1ccccadc859946c416bbaa0f5e Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 28 Mar 2025 18:03:10 -0400 Subject: [PATCH 32/57] fix rebase issues --- extensions/ecc/circuit/src/ecc_extension.rs | 4 +-- .../ecc/circuit/src/edwards_chip/mod.rs | 4 +-- .../ecc/tests/programs/examples/decompress.rs | 4 +-- extensions/ecc/tests/src/lib.rs | 36 ++++++------------- extensions/ecc/transpiler/src/lib.rs | 2 +- 5 files changed, 18 insertions(+), 32 deletions(-) diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index 13df0108d9..4df8555a2e 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -11,7 +11,7 @@ use openvm_circuit_derive::{AnyEnum, InstructionExecutor}; use openvm_circuit_primitives::bitwise_op_lookup::{ BitwiseOperationLookupBus, SharedBitwiseOperationLookupChip, }; -use openvm_circuit_primitives_derive::{BytesStateful, Chip, ChipUsageGetter}; +use openvm_circuit_primitives_derive::{Chip, ChipUsageGetter}; use openvm_ecc_guest::{ ed25519::{CURVE_A as ED25519_A, CURVE_D as ED25519_D, ED25519_MODULUS, ED25519_ORDER}, k256::{SECP256K1_MODULUS, SECP256K1_ORDER}, @@ -134,7 +134,7 @@ pub enum EccExtensionExecutor { TeEcAddRv32_48(TeAddChip), } -#[derive(ChipUsageGetter, Chip, AnyEnum, From, BytesStateful)] +#[derive(ChipUsageGetter, Chip, AnyEnum, From)] pub enum EccExtensionPeriphery { BitwiseOperationLookup(SharedBitwiseOperationLookupChip<8>), Phantom(PhantomChip), diff --git a/extensions/ecc/circuit/src/edwards_chip/mod.rs b/extensions/ecc/circuit/src/edwards_chip/mod.rs index b7472195f5..cc28d5354c 100644 --- a/extensions/ecc/circuit/src/edwards_chip/mod.rs +++ b/extensions/ecc/circuit/src/edwards_chip/mod.rs @@ -12,7 +12,7 @@ use num_bigint::BigUint; use openvm_circuit::{arch::VmChipWrapper, system::memory::OfflineMemory}; use openvm_circuit_derive::InstructionExecutor; use openvm_circuit_primitives::var_range::SharedVariableRangeCheckerChip; -use openvm_circuit_primitives_derive::{BytesStateful, Chip, ChipUsageGetter}; +use openvm_circuit_primitives_derive::{Chip, ChipUsageGetter}; use openvm_ecc_transpiler::Rv32EdwardsOpcode; use openvm_mod_circuit_builder::{ExprBuilderConfig, FieldExpressionCoreChip}; use openvm_rv32_adapters::Rv32VecHeapAdapterChip; @@ -23,7 +23,7 @@ use utils::jacobi; /// BLOCKS: how many blocks do we need to represent one input or output /// For example, for bls12_381, BLOCK_SIZE = 16, each element has 3 blocks and with two elements per input AffinePoint, BLOCKS = 6. /// For secp256k1, BLOCK_SIZE = 32, BLOCKS = 2. -#[derive(Chip, ChipUsageGetter, InstructionExecutor, BytesStateful)] +#[derive(Chip, ChipUsageGetter, InstructionExecutor)] pub struct TeAddChip( VmChipWrapper< F, diff --git a/extensions/ecc/tests/programs/examples/decompress.rs b/extensions/ecc/tests/programs/examples/decompress.rs index 268db22669..2b4b13ee40 100644 --- a/extensions/ecc/tests/programs/examples/decompress.rs +++ b/extensions/ecc/tests/programs/examples/decompress.rs @@ -78,8 +78,8 @@ pub fn main() { test_impossible_decompression::(&Fp1mod4::from_u8(1), rec_id); // ed25519 - let x = Ed25519Coord::from_le_bytes(&bytes[64..96]); - let y = Ed25519Coord::from_le_bytes(&bytes[96..128]); + let x = Ed25519Coord::from_le_bytes(&bytes[192..224]); + let y = Ed25519Coord::from_le_bytes(&bytes[224..256]); let rec_id = x.as_le_bytes()[0] & 1; let p = Ed25519Point::decompress(y.clone(), &rec_id); diff --git a/extensions/ecc/tests/src/lib.rs b/extensions/ecc/tests/src/lib.rs index 266c87713a..cac1044392 100644 --- a/extensions/ecc/tests/src/lib.rs +++ b/extensions/ecc/tests/src/lib.rs @@ -12,9 +12,10 @@ mod tests { utils::{air_test, air_test_with_min_segments}, }; use openvm_ecc_circuit::{ - CurveConfig, EccExtension, Rv32EccConfig, ED25519_CONFIG, P256_CONFIG, SECP256K1_CONFIG, + CurveConfig, EccExtension, Rv32EccConfig, SwCurveCoeffs, ED25519_CONFIG, P256_CONFIG, + SECP256K1_CONFIG, }; - use openvm_ecc_guest::CyclicGroup; + use openvm_ecc_guest::{ed25519::Ed25519Point, edwards::TwistedEdwardsPoint, CyclicGroup}; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_keccak256_transpiler::Keccak256TranspilerExtension; use openvm_rv32im_transpiler::{ @@ -111,10 +112,10 @@ mod tests { // unused, set to 10e9 + 7 scalar: BigUint::from_str("1000000007") .unwrap(), - coeffs: CurveCoeffs::SwCurve(SwCurveConfig { + coeffs: SwCurveCoeffs { a: BigUint::ZERO, b: BigUint::from_str("3").unwrap(), - }), + }, }, CurveConfig { struct_name: "CurvePoint1mod4".to_string(), @@ -122,33 +123,18 @@ mod tests { .unwrap(), scalar: BigUint::from_radix_be(&hex!("ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d"), 256) .unwrap(), - coeffs: CurveCoeffs::SwCurve(SwCurveConfig { + coeffs: SwCurveCoeffs { a: BigUint::from_radix_be(&hex!("fffffffffffffffffffffffffffffffefffffffffffffffffffffffe"), 256) .unwrap(), b: BigUint::from_radix_be(&hex!("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"), 256) .unwrap(), - }), + }, }, ], vec![ED25519_CONFIG.clone()]); - let elf = build_example_program_at_path_with_features( - get_programs_dir!(), - "decompress", - ["k256"], - &config, - )?; - let openvm_exe = VmExe::from_elf( - elf, - Transpiler::::default() - .with_extension(Rv32ITranspilerExtension) - .with_extension(Rv32MTranspilerExtension) - .with_extension(Rv32IoTranspilerExtension) - .with_extension(EccTranspilerExtension) - .with_extension(ModularTranspilerExtension), - )?; - let p = Secp256k1Affine::generator(); - let p = (p + p + p).to_affine(); - println!("decompressed: {:?}", p); + let p1 = Secp256k1Affine::generator(); + let p1 = (p1 + p1 + p1).to_affine(); + println!("secp256k1 decompressed: {:?}", p1); let q_x: [u8; 32] = hex!("0100000000000000000000000000000000000000000000000000000000000000"); let q_y: [u8; 32] = @@ -256,7 +242,7 @@ mod tests { ) .unwrap(); let config = - Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone(), P256_CONFIG.clone()]); + Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone(), P256_CONFIG.clone()], vec![]); air_test(config, openvm_exe); } } diff --git a/extensions/ecc/transpiler/src/lib.rs b/extensions/ecc/transpiler/src/lib.rs index be69b4ecea..30b11c8e34 100644 --- a/extensions/ecc/transpiler/src/lib.rs +++ b/extensions/ecc/transpiler/src/lib.rs @@ -38,7 +38,7 @@ pub enum Rv32EdwardsOpcode { pub enum EccPhantom { SwHintDecompress = 0x40, TeHintDecompress = 0x41, - HintNonQr = 0x41, + HintNonQr = 0x42, } #[derive(Default)] From 62031bf55962730b44093a41a20b5069c4959378 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 31 Mar 2025 12:39:15 -0400 Subject: [PATCH 33/57] Fixed decompression tests for twisted edwards curves --- extensions/ecc/guest/src/lib.rs | 3 +- extensions/ecc/te-macros/src/lib.rs | 22 +++++++- .../ecc/tests/programs/examples/decompress.rs | 53 +++++++++++++------ extensions/ecc/tests/src/lib.rs | 35 ++++++------ extensions/ecc/transpiler/src/lib.rs | 20 +++++-- 5 files changed, 92 insertions(+), 41 deletions(-) diff --git a/extensions/ecc/guest/src/lib.rs b/extensions/ecc/guest/src/lib.rs index 33d06409e0..4bad260ed7 100644 --- a/extensions/ecc/guest/src/lib.rs +++ b/extensions/ecc/guest/src/lib.rs @@ -39,7 +39,7 @@ pub enum SwBaseFunct7 { SwDouble, SwSetup, SwHintDecompress, - HintNonQr, + SwHintNonQr, } impl SwBaseFunct7 { @@ -56,6 +56,7 @@ pub enum TeBaseFunct7 { TeAdd = 0, TeSetup, TeHintDecompress, + TeHintNonQr, } impl TeBaseFunct7 { diff --git a/extensions/ecc/te-macros/src/lib.rs b/extensions/ecc/te-macros/src/lib.rs index 2a58cd767e..11e1f6adc9 100644 --- a/extensions/ecc/te-macros/src/lib.rs +++ b/extensions/ecc/te-macros/src/lib.rs @@ -202,7 +202,7 @@ pub fn te_declare(input: TokenStream) -> TokenStream { } mod #group_ops_mod_name { - use ::openvm_ecc_guest::{edwards::TwistedEdwardsPoint, FromCompressed, DecompressionHint, impl_te_group_ops}; + use ::openvm_ecc_guest::{edwards::TwistedEdwardsPoint, FromCompressed, DecompressionHint, impl_te_group_ops, algebra::{IntMod, DivUnsafe, DivAssignUnsafe, ExpBytes}}; use super::*; impl_te_group_ops!(#struct_name, #intmod_type); @@ -270,7 +270,7 @@ pub fn te_declare(input: TokenStream) -> TokenStream { // ensure sqrt < modulus hint.sqrt.assert_reduced(); - let lhs = (&hint.sqrt * &hint.sqrt) * (&<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_D * y * y - &<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_A * &hint.sqrt * &hint.sqrt - &<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_A); + let lhs = (&hint.sqrt * &hint.sqrt) * (&<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_D * y * y - &<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_A); let rhs = y * y - &<#intmod_type as openvm_algebra_guest::IntMod>::ONE; if lhs == rhs * Self::get_non_qr() { Some(None) @@ -288,6 +288,7 @@ pub fn te_declare(input: TokenStream) -> TokenStream { } #[cfg(target_os = "zkvm")] { + use openvm_algebra_guest::DivUnsafe; use openvm::platform as openvm_platform; // needed for hint_buffer_u32 let mut non_qr_uninit = core::mem::MaybeUninit::<#intmod_type>::uninit(); let mut non_qr; @@ -374,6 +375,10 @@ pub fn te_init(input: TokenStream) -> TokenStream { &format!("te_hint_decompress_extern_func_{}", str_path), span.into(), ); + let hint_non_qr_extern_func = syn::Ident::new( + &format!("hint_non_qr_extern_func_{}", str_path), + span.into(), + ); externs.push(quote::quote_spanned! { span.into() => #[no_mangle] extern "C" fn #add_extern_func(rd: usize, rs1: usize, rs2: usize) { @@ -400,6 +405,19 @@ pub fn te_init(input: TokenStream) -> TokenStream { rs2 = In rs2 ); } + + #[no_mangle] + extern "C" fn #hint_non_qr_extern_func() { + openvm::platform::custom_insn_r!( + opcode = TE_OPCODE, + funct3 = TE_FUNCT3 as usize, + funct7 = TeBaseFunct7::TeHintNonQr as usize + #ec_idx + * (TeBaseFunct7::TWISTED_EDWARDS_MAX_KINDS as usize), + rd = Const "x0", + rs1 = Const "x0", + rs2 = Const "x0" + ); + } }); let setup_function = syn::Ident::new(&format!("setup_te_{}", str_path), span.into()); diff --git a/extensions/ecc/tests/programs/examples/decompress.rs b/extensions/ecc/tests/programs/examples/decompress.rs index 2b4b13ee40..498be5c66f 100644 --- a/extensions/ecc/tests/programs/examples/decompress.rs +++ b/extensions/ecc/tests/programs/examples/decompress.rs @@ -7,7 +7,7 @@ extern crate alloc; use hex_literal::hex; use openvm::io::read_vec; use openvm_ecc_guest::{ - algebra::{Field, IntMod}, + algebra::{DivUnsafe, Field, IntMod}, ed25519::{Ed25519Coord, Ed25519Point}, edwards::TwistedEdwardsPoint, k256::{Secp256k1Coord, Secp256k1Point}, @@ -57,40 +57,36 @@ pub fn main() { let y = Secp256k1Coord::from_le_bytes(&bytes[32..64]); let rec_id = y.as_le_bytes()[0] & 1; - test_possible_decompression::(&x, &y, rec_id); + test_possible_sw_decompression::(&x, &y, rec_id); // x = 5 is not on the x-coordinate of any point on the Secp256k1 curve - test_impossible_decompression::(&Secp256k1Coord::from_u8(5), rec_id); + test_impossible_sw_decompression::(&Secp256k1Coord::from_u8(5), rec_id); let x = Fp5mod8::from_le_bytes(&bytes[64..96]); let y = Fp5mod8::from_le_bytes(&bytes[96..128]); let rec_id = y.as_le_bytes()[0] & 1; - test_possible_decompression::(&x, &y, rec_id); + test_possible_sw_decompression::(&x, &y, rec_id); // x = 3 is not on the x-coordinate of any point on the CurvePoint5mod8 curve - test_impossible_decompression::(&Fp5mod8::from_u8(3), rec_id); + test_impossible_sw_decompression::(&Fp5mod8::from_u8(3), rec_id); let x = Fp1mod4::from_le_bytes(&bytes[128..160]); let y = Fp1mod4::from_le_bytes(&bytes[160..192]); let rec_id = y.as_le_bytes()[0] & 1; - test_possible_decompression::(&x, &y, rec_id); + test_possible_sw_decompression::(&x, &y, rec_id); // x = 1 is not on the x-coordinate of any point on the CurvePoint1mod4 curve - test_impossible_decompression::(&Fp1mod4::from_u8(1), rec_id); + test_impossible_sw_decompression::(&Fp1mod4::from_u8(1), rec_id); // ed25519 let x = Ed25519Coord::from_le_bytes(&bytes[192..224]); let y = Ed25519Coord::from_le_bytes(&bytes[224..256]); let rec_id = x.as_le_bytes()[0] & 1; - - let p = Ed25519Point::decompress(y.clone(), &rec_id); - assert_eq!(p.x(), &x); - assert_eq!(p.y(), &y); - - let p = Ed25519Point::decompress(&Ed25519Coord::from_u8(2), &rec_id); - assert!(p.is_none()); + test_possible_te_decompression::(&x, &y, rec_id); + // y = 2 is not on the y-coordinate of any point on the Ed25519 curve + test_impossible_te_decompression::(&Ed25519Coord::from_u8(2), rec_id); } -fn test_possible_decompression>( +fn test_possible_sw_decompression>( x: &P::Coordinate, y: &P::Coordinate, rec_id: u8, @@ -100,7 +96,32 @@ fn test_possible_decompression>( +fn test_possible_te_decompression>( + x: &P::Coordinate, + y: &P::Coordinate, + rec_id: u8, +) { + let hint = P::hint_decompress(y, &rec_id).expect("hint should be well-formed"); + if hint.possible { + assert_eq!(x, &hint.sqrt); + } else { + panic!("decompression should be possible"); + } + + let p = P::decompress(y.clone(), &rec_id).unwrap(); + assert_eq!(p.x(), x); + assert_eq!(p.y(), y); +} + +fn test_impossible_sw_decompression>( + x: &P::Coordinate, + rec_id: u8, +) { + let p = P::decompress(x.clone(), &rec_id); + assert!(p.is_none()); +} + +fn test_impossible_te_decompression>( x: &P::Coordinate, rec_id: u8, ) { diff --git a/extensions/ecc/tests/src/lib.rs b/extensions/ecc/tests/src/lib.rs index cac1044392..a30f52ddbb 100644 --- a/extensions/ecc/tests/src/lib.rs +++ b/extensions/ecc/tests/src/lib.rs @@ -15,7 +15,6 @@ mod tests { CurveConfig, EccExtension, Rv32EccConfig, SwCurveCoeffs, ED25519_CONFIG, P256_CONFIG, SECP256K1_CONFIG, }; - use openvm_ecc_guest::{ed25519::Ed25519Point, edwards::TwistedEdwardsPoint, CyclicGroup}; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_keccak256_transpiler::Keccak256TranspilerExtension; use openvm_rv32im_transpiler::{ @@ -100,7 +99,7 @@ mod tests { fn test_decompress() -> Result<()> { use ed25519::Ed25519Point; use edwards::TwistedEdwardsPoint; - use halo2curves_axiom::{group::Curve, secp256k1::Secp256k1Affine}; + use halo2curves_axiom::{ed25519::Ed25519Affine, group::Curve, secp256k1::Secp256k1Affine}; use openvm_algebra_guest::IntMod; let config = @@ -143,24 +142,24 @@ mod tests { hex!("211D5C11D68032342211C256D3C1034AB99013327FBFB46BBD0C0EB700000000"); let r_y: [u8; 32] = hex!("347E00859981D5446447075AA07543CDE6DF224CFB23F7B5886337BD00000000"); + let s = Ed25519Affine::generator(); + let s = (s + s + s).to_affine(); - let coords1 = [p1.x.to_bytes(), p1.y.to_bytes(), q_x, q_y, r_x, r_y] - .concat() - .into_iter() - .map(FieldAlgebra::from_canonical_u8) - .collect(); + let coords = [ + p.x.to_bytes(), + p.y.to_bytes(), + q_x, + q_y, + r_x, + r_y, + s.x.to_bytes(), + s.y.to_bytes(), + ] + .concat() + .into_iter() + .map(FieldAlgebra::from_canonical_u8) + .collect(); - let p2 = Ed25519Point::GENERATOR.clone(); - let p2 = &p2 + &p2 + &p2; - println!("ed25519 decompressed: {:?}", &p2); - - let coords2: Vec<_> = [p2.x().as_le_bytes(), p2.y().as_le_bytes()] - .concat() - .into_iter() - .map(FieldAlgebra::from_canonical_u8) - .collect(); - - let coords = [coords1, coords2].concat(); air_test_with_min_segments(config, openvm_exe, vec![coords], 1); Ok(()) } diff --git a/extensions/ecc/transpiler/src/lib.rs b/extensions/ecc/transpiler/src/lib.rs index 30b11c8e34..1b304ec022 100644 --- a/extensions/ecc/transpiler/src/lib.rs +++ b/extensions/ecc/transpiler/src/lib.rs @@ -37,8 +37,9 @@ pub enum Rv32EdwardsOpcode { #[repr(u16)] pub enum EccPhantom { SwHintDecompress = 0x40, - TeHintDecompress = 0x41, - HintNonQr = 0x42, + SwHintNonQr = 0x41, + TeHintDecompress = 0x42, + TeHintNonQr = 0x43, } #[derive(Default)] @@ -88,6 +89,17 @@ impl EccTranspilerExtension { curve_idx as u16, ))); } + if let Some(TeBaseFunct7::TeHintNonQr) = TeBaseFunct7::from_repr(base_funct7) { + assert_eq!(dec_insn.rd, 0); + assert_eq!(dec_insn.rs1, 0); + assert_eq!(dec_insn.rs2, 0); + return Some(TranspilerOutput::one_to_one(Instruction::phantom( + PhantomDiscriminant(EccPhantom::TeHintNonQr as u16), + F::ZERO, + F::ZERO, + curve_idx as u16, + ))); + } if base_funct7 == TeBaseFunct7::TeSetup as u8 { let local_opcode = Rv32EdwardsOpcode::SETUP_TE_ADD; Some(Instruction::new( @@ -150,12 +162,12 @@ impl EccTranspilerExtension { curve_idx as u16, ))); } - if let Some(SwBaseFunct7::HintNonQr) = SwBaseFunct7::from_repr(base_funct7) { + if let Some(SwBaseFunct7::SwHintNonQr) = SwBaseFunct7::from_repr(base_funct7) { assert_eq!(dec_insn.rd, 0); assert_eq!(dec_insn.rs1, 0); assert_eq!(dec_insn.rs2, 0); return Some(TranspilerOutput::one_to_one(Instruction::phantom( - PhantomDiscriminant(EccPhantom::HintNonQr as u16), + PhantomDiscriminant(EccPhantom::SwHintNonQr as u16), F::ZERO, F::ZERO, curve_idx as u16, From 4d6223155f8552e1e6f9d90fc00a2fc3f77ca021 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 31 Mar 2025 14:36:01 -0400 Subject: [PATCH 34/57] Fix codespell error on te (twisted edwards) abbreviation --- .codespellignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.codespellignore b/.codespellignore index c91d0f7707..4b1c229c68 100644 --- a/.codespellignore +++ b/.codespellignore @@ -2,4 +2,5 @@ InOut inout LoadE SelectE -ser \ No newline at end of file +ser +te \ No newline at end of file From 6a6b32e5e81320bee580e1cde8b43bea03f05cea Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 31 Mar 2025 15:03:46 -0400 Subject: [PATCH 35/57] Fix lint errors and typos --- Cargo.lock | 5 +---- benchmarks/prove/src/bin/kitchen_sink.rs | 17 ++++++++++------- benchmarks/prove/src/bin/pairing.rs | 9 +++++---- extensions/ecc/circuit/src/edwards_chip/mod.rs | 2 +- .../ecc/circuit/src/weierstrass_chip/mod.rs | 4 ++-- extensions/ecc/te-macros/Cargo.toml | 2 -- extensions/ecc/tests/Cargo.toml | 1 - extensions/ecc/tests/programs/examples/ec.rs | 3 +-- .../ecc/tests/programs/examples/ec_nonzero_a.rs | 3 +-- .../tests/programs/examples/ec_two_curves.rs | 3 +-- .../ecc/tests/programs/examples/edwards_ec.rs | 3 ++- 11 files changed, 24 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d63a06025..db9ad395a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4920,7 +4920,6 @@ dependencies = [ "hex-literal", "num-bigint 0.4.6", "openvm-algebra-circuit", - "openvm-algebra-guest", "openvm-algebra-transpiler", "openvm-circuit", "openvm-ecc-circuit", @@ -4944,11 +4943,9 @@ dependencies = [ [[package]] name = "openvm-ecc-te-macros" -version = "1.0.0-rc.2" +version = "1.0.0" dependencies = [ - "num-bigint 0.4.6", "openvm-macros-common", - "proc-macro2", "quote", "syn 2.0.100", ] diff --git a/benchmarks/prove/src/bin/kitchen_sink.rs b/benchmarks/prove/src/bin/kitchen_sink.rs index 3102c9e3fe..4292186c5f 100644 --- a/benchmarks/prove/src/bin/kitchen_sink.rs +++ b/benchmarks/prove/src/bin/kitchen_sink.rs @@ -6,7 +6,7 @@ use num_bigint::BigUint; use openvm_algebra_circuit::{Fp2Extension, ModularExtension}; use openvm_benchmarks_prove::util::BenchmarkCli; use openvm_circuit::arch::{instructions::exe::VmExe, SystemConfig}; -use openvm_ecc_circuit::{WeierstrassExtension, P256_CONFIG, SECP256K1_CONFIG}; +use openvm_ecc_circuit::{EccExtension, P256_CONFIG, SECP256K1_CONFIG}; use openvm_native_recursion::halo2::utils::{CacheHalo2ParamsReader, DEFAULT_PARAMS_DIR}; use openvm_pairing_circuit::{PairingCurve, PairingExtension}; use openvm_pairing_guest::{ @@ -57,12 +57,15 @@ fn main() -> Result<()> { bls_config.modulus.clone(), ), ])) - .ecc(WeierstrassExtension::new(vec![ - SECP256K1_CONFIG.clone(), - P256_CONFIG.clone(), - bn_config.clone(), - bls_config.clone(), - ])) + .ecc(EccExtension::new( + vec![ + SECP256K1_CONFIG.clone(), + P256_CONFIG.clone(), + bn_config.clone(), + bls_config.clone(), + ], + vec![], + )) .pairing(PairingExtension::new(vec![ PairingCurve::Bn254, PairingCurve::Bls12_381, diff --git a/benchmarks/prove/src/bin/pairing.rs b/benchmarks/prove/src/bin/pairing.rs index 1db6d1b491..80cc68809c 100644 --- a/benchmarks/prove/src/bin/pairing.rs +++ b/benchmarks/prove/src/bin/pairing.rs @@ -3,7 +3,7 @@ use eyre::Result; use openvm_algebra_circuit::{Fp2Extension, ModularExtension}; use openvm_benchmarks_prove::util::BenchmarkCli; use openvm_circuit::arch::SystemConfig; -use openvm_ecc_circuit::WeierstrassExtension; +use openvm_ecc_circuit::EccExtension; use openvm_pairing_circuit::{PairingCurve, PairingExtension}; use openvm_pairing_guest::bn254::{BN254_COMPLEX_STRUCT_NAME, BN254_MODULUS, BN254_ORDER}; use openvm_sdk::{config::SdkVmConfig, Sdk, StdIn}; @@ -26,9 +26,10 @@ fn main() -> Result<()> { BN254_COMPLEX_STRUCT_NAME.to_string(), BN254_MODULUS.clone(), )])) - .ecc(WeierstrassExtension::new(vec![ - PairingCurve::Bn254.curve_config() - ])) + .ecc(EccExtension::new( + vec![PairingCurve::Bn254.curve_config()], + vec![], + )) .pairing(PairingExtension::new(vec![PairingCurve::Bn254])) .build(); let elf = args.build_bench_program("pairing", &vm_config, None)?; diff --git a/extensions/ecc/circuit/src/edwards_chip/mod.rs b/extensions/ecc/circuit/src/edwards_chip/mod.rs index cc28d5354c..03c5e1253e 100644 --- a/extensions/ecc/circuit/src/edwards_chip/mod.rs +++ b/extensions/ecc/circuit/src/edwards_chip/mod.rs @@ -25,7 +25,7 @@ use utils::jacobi; /// For secp256k1, BLOCK_SIZE = 32, BLOCKS = 2. #[derive(Chip, ChipUsageGetter, InstructionExecutor)] pub struct TeAddChip( - VmChipWrapper< + pub VmChipWrapper< F, Rv32VecHeapAdapterChip, FieldExpressionCoreChip, diff --git a/extensions/ecc/circuit/src/weierstrass_chip/mod.rs b/extensions/ecc/circuit/src/weierstrass_chip/mod.rs index dc162f23e4..4fef9c4838 100644 --- a/extensions/ecc/circuit/src/weierstrass_chip/mod.rs +++ b/extensions/ecc/circuit/src/weierstrass_chip/mod.rs @@ -27,7 +27,7 @@ use openvm_stark_backend::p3_field::PrimeField32; /// input AffinePoint, BLOCKS = 6. For secp256k1, BLOCK_SIZE = 32, BLOCKS = 2. #[derive(Chip, ChipUsageGetter, InstructionExecutor)] pub struct SwAddNeChip( - pub VmChipWrapper< + pub VmChipWrapper< F, Rv32VecHeapAdapterChip, FieldExpressionCoreChip, @@ -63,7 +63,7 @@ impl #[derive(Chip, ChipUsageGetter, InstructionExecutor)] pub struct SwDoubleChip( - pub VmChipWrapper< + pub VmChipWrapper< F, Rv32VecHeapAdapterChip, FieldExpressionCoreChip, diff --git a/extensions/ecc/te-macros/Cargo.toml b/extensions/ecc/te-macros/Cargo.toml index 3784d74dc3..de3544ff87 100644 --- a/extensions/ecc/te-macros/Cargo.toml +++ b/extensions/ecc/te-macros/Cargo.toml @@ -10,8 +10,6 @@ repository.workspace = true syn = { version = "2.0", features = ["full"] } quote = "1.0" openvm-macros-common = { workspace = true, default-features = false } -num-bigint.workspace = true -proc-macro2 = "1.0.38" [lib] proc-macro = true diff --git a/extensions/ecc/tests/Cargo.toml b/extensions/ecc/tests/Cargo.toml index cea89631d1..bcdaf6f539 100644 --- a/extensions/ecc/tests/Cargo.toml +++ b/extensions/ecc/tests/Cargo.toml @@ -12,7 +12,6 @@ openvm-stark-sdk.workspace = true openvm-circuit = { workspace = true, features = ["test-utils"] } openvm-transpiler.workspace = true openvm-algebra-circuit.workspace = true -openvm-algebra-guest.workspace = true openvm-algebra-transpiler.workspace = true openvm-ecc-transpiler.workspace = true openvm-ecc-circuit.workspace = true diff --git a/extensions/ecc/tests/programs/examples/ec.rs b/extensions/ecc/tests/programs/examples/ec.rs index 52b3568548..3e21719772 100644 --- a/extensions/ecc/tests/programs/examples/ec.rs +++ b/extensions/ecc/tests/programs/examples/ec.rs @@ -2,8 +2,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use hex_literal::hex; -use openvm_algebra_guest::IntMod; -use openvm_ecc_guest::{msm, weierstrass::WeierstrassPoint, Group}; +use openvm_ecc_guest::{algebra::IntMod, msm, weierstrass::WeierstrassPoint, Group}; use openvm_k256::{Secp256k1Coord, Secp256k1Point, Secp256k1Scalar}; openvm::init!("openvm_init_ec_k256.rs"); diff --git a/extensions/ecc/tests/programs/examples/ec_nonzero_a.rs b/extensions/ecc/tests/programs/examples/ec_nonzero_a.rs index ea0a0387cd..82900a0226 100644 --- a/extensions/ecc/tests/programs/examples/ec_nonzero_a.rs +++ b/extensions/ecc/tests/programs/examples/ec_nonzero_a.rs @@ -2,8 +2,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use hex_literal::hex; -use openvm_algebra_guest::IntMod; -use openvm_ecc_guest::{weierstrass::WeierstrassPoint, CyclicGroup, Group}; +use openvm_ecc_guest::{algebra::IntMod, weierstrass::WeierstrassPoint, CyclicGroup, Group}; use openvm_p256::{P256Coord, P256Point}; openvm::entry!(main); diff --git a/extensions/ecc/tests/programs/examples/ec_two_curves.rs b/extensions/ecc/tests/programs/examples/ec_two_curves.rs index 3daa6a9c30..78e3ff4f25 100644 --- a/extensions/ecc/tests/programs/examples/ec_two_curves.rs +++ b/extensions/ecc/tests/programs/examples/ec_two_curves.rs @@ -2,8 +2,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use hex_literal::hex; -use openvm_algebra_guest::IntMod; -use openvm_ecc_guest::{msm, weierstrass::WeierstrassPoint, Group}; +use openvm_ecc_guest::{algebra::IntMod, msm, weierstrass::WeierstrassPoint, Group}; use openvm_k256::{Secp256k1Coord, Secp256k1Point, Secp256k1Scalar}; use openvm_p256::{P256Coord, P256Point}; diff --git a/extensions/ecc/tests/programs/examples/edwards_ec.rs b/extensions/ecc/tests/programs/examples/edwards_ec.rs index ba74b41a19..06ff06c523 100644 --- a/extensions/ecc/tests/programs/examples/edwards_ec.rs +++ b/extensions/ecc/tests/programs/examples/edwards_ec.rs @@ -2,8 +2,9 @@ #![cfg_attr(not(feature = "std"), no_std)] use hex_literal::hex; -use openvm_algebra_guest::{moduli_macros::moduli_init, IntMod}; +use openvm_algebra_guest::moduli_macros::moduli_init; use openvm_ecc_guest::{ + algebra::IntMod, ed25519::{Ed25519Coord, Ed25519Point}, edwards::TwistedEdwardsPoint, te_macros::te_init, From 0d6908370c4121520cb81353661a44a39c339314 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 31 Mar 2025 17:15:26 -0400 Subject: [PATCH 36/57] Update docs --- docs/specs/ISA.md | 5 +++-- docs/specs/RISCV.md | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/specs/ISA.md b/docs/specs/ISA.md index 214759521f..5a2403850d 100644 --- a/docs/specs/ISA.md +++ b/docs/specs/ISA.md @@ -683,8 +683,7 @@ The elliptic curve extension supports arithmetic over elliptic curves `C` in the We note that the definitions of the curve arithmetic operations for short Weierstrass curves do not depend on `C::B`. The VM configuration will specify a list of supported curves. For -each curve `C` (of either form) there will be associated configuration parameters `C::COORD_SIZE` and `C::BLOCK_SIZE` ( -defined below). The extension operates on address spaces `1` and `2`, meaning all memory cells are constrained to be +each curve `C` (of either form) there will be associated configuration parameters `C::COORD_SIZE` and `C::BLOCK_SIZE` (defined below). The extension operates on address spaces `1` and `2`, meaning all memory cells are constrained to be bytes. An affine curve point `EcPoint(x, y)` is a pair of `x,y` where each element is an array of `C::COORD_SIZE` elements each @@ -702,6 +701,8 @@ r32_ec_point(a) -> EcPoint { } ``` +The instructions that have prefix `SW_` perform short Weierstrass curve operations, and those with prefix `TE_` perform twisted Edwards curve operations. + | Name | Operands | Description | | -------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SW_ADD_NE\ | `a,b,c,1,2` | Set `r32_ec_point(a) = r32_ec_point(b) + r32_ec_point(c)` (curve addition). Assumes that `r32_ec_point(b), r32_ec_point(c)` both lie on the curve and are not the identity point. Further assumes that `r32_ec_point(b).x, r32_ec_point(c).x` are not equal in the coordinate field. | diff --git a/docs/specs/RISCV.md b/docs/specs/RISCV.md index 622ed7b0ea..4693bf0b39 100644 --- a/docs/specs/RISCV.md +++ b/docs/specs/RISCV.md @@ -176,7 +176,7 @@ Complex extension field arithmetic over `Fp2` depends on `Fp` where `-1` is not ## Elliptic Curve Extension -The elliptic curve extension supports arithmetic over short Weierstrass curves and twisted Edwards curves, which requires specification of the elliptic curve `C`. The extension must be configured to support a fixed ordered list of supported curves. There is one list for each type of curves (short Weierstrass and twisted Edwards). We use `config.curve_idx(C)` to denote the index of `C` in the appropriate list. In the list below, `idx` denotes `config.curve_idx(C)`. +The elliptic curve extension supports arithmetic over short Weierstrass curves and twisted Edwards curves, which requires specification of the elliptic curve `C`. The extension must be configured to support two fixed ordered lists of supported curves: one list of short Weierstrass curves and one list of twisted Edwards curves. Instructions prefixed with `sw_` are for short Weierstrass curves and instructions prefixed with `te_` are for twisted Edwards curves. We use `config.curve_idx(C)` to denote the index of `C` in the appropriate list. In the list below, `idx` denotes `config.curve_idx(C)`. | RISC-V Inst | FMT | opcode[6:0] | funct3 | funct7 | RISC-V description and notes | | --------------- | --- | ----------- | ------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -184,7 +184,8 @@ The elliptic curve extension supports arithmetic over short Weierstrass curves a | sw_double\ | R | 0101011 | 001 | `idx*8+1` | `EcPoint([rd:2*C::COORD_SIZE]_2) = 2 * EcPoint([rs1:2*C::COORD_SIZE]_2)`. Assumes that input affine point is not identity. `rs2` is unused and must be set to `x0`. | | sw_setup\ | R | 0101011 | 001 | `idx*8+2` | `assert([rs1: 2*C::COORD_SIZE]_2 == [C::MODULUS, CURVE_A])` in the chip defined by the register index of `rs2`. For the sake of implementation convenience it also writes an unconstrained value into `[rd: 2*C::COORD_SIZE]_2`. If `ind(rs2) != 0`, then this instruction is setup for `sw_add_ne`. Otherwise it is setup for `sw_double`. When `ind(rs2) != 0` (add_ne), it is required for proper functionality that `[rs2: C::COORD_SIZE]_2 != [rs1: C::COORD_SIZE]_2`; otherwise (double), it is required that `[rs1 + C::COORD_SIZE: C::COORD_SIZE]_2 != C::Fp::ZERO` | | te_add\ | R | 0101011 | 100 | `idx*8` | `EcPoint([rd:2*C::COORD_SIZE]_2) = EcPoint([rs1:2*C::COORD_SIZE]_2) + EcPoint([rs2:2*C::COORD_SIZE]_2)`. | -| te_setup\ | R | 0101011 | 100 | `idx*8+2` | `assert([rs1: 2*C::COORD_SIZE]_2 == [C::MODULUS, C::CURVE_A] && [rs2: C::COORD_SIZE]_2 == C::CURVE_D])`. For the sake of implementation convenience it also writes an unconstrained value into `[rd: 2*C::COORD_SIZE]_2`. | +| te_setup\ | R | 0101011 | 100 | `idx*8+1` | `assert([rs1: 2*C::COORD_SIZE]_2 == [C::MODULUS, C::CURVE_A] && [rs2: C::COORD_SIZE]_2 == C::CURVE_D])`. For the sake of implementation convenience it also writes an unconstrained value into `[rd: 2*C::COORD_SIZE]_2`. | + Since `funct7` is 7-bits, up to 16 curves can be supported simultaneously. We use `idx*8` to leave some room for future expansion. From 64e41c9ca825aa8e13d85f7627d34ac2dfda299a Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Sun, 15 Jun 2025 22:18:07 -0400 Subject: [PATCH 37/57] Remove code related to ecc phantom instructions --- extensions/ecc/circuit/src/ecc_extension.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index 4df8555a2e..885df162cc 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -3,9 +3,8 @@ use num_bigint::BigUint; use num_traits::{FromPrimitive, Zero}; use once_cell::sync::Lazy; use openvm_algebra_guest::IntMod; -use openvm_circuit::{ - arch::{SystemPort, VmExtension, VmInventory, VmInventoryBuilder, VmInventoryError}, - system::phantom::PhantomChip, +use openvm_circuit::arch::{ + SystemPort, VmExtension, VmInventory, VmInventoryBuilder, VmInventoryError, }; use openvm_circuit_derive::{AnyEnum, InstructionExecutor}; use openvm_circuit_primitives::bitwise_op_lookup::{ @@ -17,8 +16,8 @@ use openvm_ecc_guest::{ k256::{SECP256K1_MODULUS, SECP256K1_ORDER}, p256::{CURVE_A as P256_A, CURVE_B as P256_B, P256_MODULUS, P256_ORDER}, }; -use openvm_ecc_transpiler::{EccPhantom, Rv32EdwardsOpcode, Rv32WeierstrassOpcode}; -use openvm_instructions::{LocalOpcode, PhantomDiscriminant, VmOpcode}; +use openvm_ecc_transpiler::{Rv32EdwardsOpcode, Rv32WeierstrassOpcode}; +use openvm_instructions::{LocalOpcode, VmOpcode}; use openvm_mod_circuit_builder::ExprBuilderConfig; use openvm_rv32_adapters::Rv32VecHeapAdapterChip; use openvm_stark_backend::p3_field::PrimeField32; @@ -137,7 +136,6 @@ pub enum EccExtensionExecutor { #[derive(ChipUsageGetter, Chip, AnyEnum, From)] pub enum EccExtensionPeriphery { BitwiseOperationLookup(SharedBitwiseOperationLookupChip<8>), - Phantom(PhantomChip), } impl VmExtension for EccExtension { From 3d6c5f78e0404bbf5ec7692c05783db23489e855 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Sun, 15 Jun 2025 22:18:45 -0400 Subject: [PATCH 38/57] Add struct_name fields to curve configs --- extensions/ecc/circuit/src/ecc_extension.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index 885df162cc..2d4a20dc0c 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -65,6 +65,7 @@ pub struct TeCurveCoeffs { } pub static SECP256K1_CONFIG: Lazy> = Lazy::new(|| CurveConfig { + struct_name: "Secp256k1".to_string(), modulus: SECP256K1_MODULUS.clone(), scalar: SECP256K1_ORDER.clone(), coeffs: SwCurveCoeffs { @@ -74,6 +75,7 @@ pub static SECP256K1_CONFIG: Lazy> = Lazy::new(|| Cur }); pub static P256_CONFIG: Lazy> = Lazy::new(|| CurveConfig { + struct_name: "P256".to_string(), modulus: P256_MODULUS.clone(), scalar: P256_ORDER.clone(), coeffs: SwCurveCoeffs { @@ -83,6 +85,7 @@ pub static P256_CONFIG: Lazy> = Lazy::new(|| CurveCon }); pub static ED25519_CONFIG: Lazy> = Lazy::new(|| CurveConfig { + struct_name: "Ed25519".to_string(), modulus: ED25519_MODULUS.clone(), scalar: ED25519_ORDER.clone(), coeffs: TeCurveCoeffs { From 68909ce6b2298ba3b6627a10fce33dc647888ab8 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 14:44:54 -0400 Subject: [PATCH 39/57] Fix rebase issues --- Cargo.lock | 2113 +++++++++++------ benchmarks/prove/src/bin/ecrecover.rs | 12 +- crates/sdk/src/config/global.rs | 2 +- .../toolchain/tests/tests/transpiler_tests.rs | 12 +- extensions/ecc/circuit/Cargo.toml | 1 + extensions/ecc/circuit/src/config.rs | 4 +- extensions/ecc/circuit/src/ecc_extension.rs | 44 +- extensions/ecc/guest/Cargo.toml | 6 + extensions/ecc/guest/src/ed25519.rs | 17 +- extensions/ecc/sw-macros/src/lib.rs | 4 +- extensions/ecc/te-macros/src/lib.rs | 130 +- extensions/ecc/tests/Cargo.toml | 2 +- .../ecc/tests/programs/examples/decompress.rs | 8 - .../ecc/tests/programs/examples/edwards_ec.rs | 3 - ...=> openvm_init_decompress_k256_ed25519.rs} | 3 +- .../ecc/tests/programs/openvm_init_ec_k256.rs | 1 + .../programs/openvm_init_ec_nonzero_a_p256.rs | 1 + .../openvm_init_ec_two_curves_k256_p256.rs | 1 + .../tests/programs/openvm_init_ecdsa_k256.rs | 1 + .../openvm_init_edwards_ec_ed25519.rs | 4 + extensions/ecc/tests/src/lib.rs | 36 +- extensions/pairing/circuit/src/config.rs | 9 +- guest-libs/k256/src/point.rs | 7 +- guest-libs/k256/tests/lib.rs | 21 +- guest-libs/p256/src/point.rs | 7 +- guest-libs/p256/tests/lib.rs | 21 +- 26 files changed, 1540 insertions(+), 930 deletions(-) rename extensions/ecc/tests/programs/{openvm_init_decompress_k256.rs => openvm_init_decompress_k256_ed25519.rs} (73%) create mode 100644 extensions/ecc/tests/programs/openvm_init_edwards_ec_ed25519.rs diff --git a/Cargo.lock b/Cargo.lock index db9ad395a5..2b073562b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,9 +34,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aes" @@ -51,14 +51,14 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -76,28 +76,61 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "alloy-eip2124" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" +dependencies = [ + "alloy-primitives 1.2.0", + "alloy-rlp", + "crc", + "serde", + "thiserror 2.0.12", +] + [[package]] name = "alloy-eip2930" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +checksum = "7b82752a889170df67bbb36d42ca63c531eb16274f0d7299ae2a680facba17bd" dependencies = [ - "alloy-primitives 0.8.25", + "alloy-primitives 1.2.0", "alloy-rlp", "serde", ] [[package]] name = "alloy-eip7702" -version = "0.4.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c986539255fb839d1533c128e190e557e52ff652c9ef62939e233a81dd93f7e" +checksum = "9d4769c6ffddca380b0070d71c8b7f30bed375543fe76bb2f74ec0acf4b7cd16" dependencies = [ - "alloy-primitives 0.8.25", + "alloy-primitives 1.2.0", "alloy-rlp", - "derive_more 1.0.0", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde", + "thiserror 2.0.12", +] + +[[package]] +name = "alloy-eips" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3056872f6da48046913e76edb5ddced272861f6032f09461aea1a2497be5ae5d" +dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives 1.2.0", + "alloy-rlp", + "alloy-serde", + "auto_impl", + "c-kzg", + "derive_more 2.0.1", + "either", + "serde", + "sha2 0.10.9", ] [[package]] @@ -121,10 +154,10 @@ dependencies = [ "bytes", "cfg-if", "const-hex", - "derive_more 0.99.19", + "derive_more 0.99.20", "hex-literal 0.4.1", "itoa", - "ruint 1.12.3", + "ruint 1.15.0", "tiny-keccak", ] @@ -138,10 +171,10 @@ dependencies = [ "bytes", "cfg-if", "const-hex", - "derive_more 0.99.19", + "derive_more 0.99.20", "hex-literal 0.4.1", "itoa", - "ruint 1.12.3", + "ruint 1.15.0", "tiny-keccak", ] @@ -157,15 +190,42 @@ dependencies = [ "const-hex", "derive_more 2.0.1", "foldhash", - "hashbrown 0.15.2", - "indexmap 2.8.0", + "hashbrown 0.15.4", + "indexmap 2.9.0", "itoa", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-asm", "paste", "proptest", "rand 0.8.5", - "ruint 1.12.3", + "ruint 1.15.0", + "rustc-hash 2.1.1", + "serde", + "sha3", + "tiny-keccak", +] + +[[package]] +name = "alloy-primitives" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a326d47106039f38b811057215a92139f46eef7983a4b77b10930a0ea5685b1e" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more 2.0.1", + "foldhash", + "hashbrown 0.15.4", + "indexmap 2.9.0", + "itoa", + "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak-asm", + "paste", + "proptest", + "rand 0.9.1", + "ruint 1.15.0", "rustc-hash 2.1.1", "serde", "sha3", @@ -174,9 +234,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" +checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -185,27 +245,24 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" +checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] -name = "alloy-sol-macro" -version = "0.8.25" +name = "alloy-serde" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10ae8e9a91d328ae954c22542415303919aabe976fe7a92eb06db1b68fd59f2" +checksum = "730e8f2edf2fc224cabd1c25d090e1655fa6137b2e409f92e5eec735903f1507" dependencies = [ - "alloy-sol-macro-expander", - "alloy-sol-macro-input", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.98", + "alloy-primitives 1.2.0", + "serde", + "serde_json", ] [[package]] @@ -219,7 +276,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -232,11 +289,11 @@ dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.7.1", + "indexmap 2.9.0", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", "syn-solidity", "tiny-keccak", ] @@ -255,7 +312,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.98", + "syn 2.0.103", "syn-solidity", ] @@ -266,7 +323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c" dependencies = [ "serde", - "winnow 0.7.3", + "winnow 0.7.11", ] [[package]] @@ -314,9 +371,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -329,44 +386,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "approx" @@ -393,6 +450,18 @@ dependencies = [ "yansi 0.5.1", ] +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + [[package]] name = "ark-bn254" version = "0.3.0" @@ -415,6 +484,18 @@ dependencies = [ "ark-std 0.4.0", ] +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-r1cs-std", + "ark-std 0.5.0", +] + [[package]] name = "ark-ec" version = "0.3.0" @@ -436,7 +517,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ "ark-ff 0.4.2", - "ark-poly", + "ark-poly 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", "derivative", @@ -446,6 +527,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.4", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "zeroize", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -484,6 +586,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-traits", + "paste", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -504,6 +626,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.103", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -529,6 +661,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "ark-poly" version = "0.4.2" @@ -542,6 +687,50 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.4", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-relations", + "ark-std 0.5.0", + "educe", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff 0.5.0", + "ark-std 0.5.0", + "tracing", + "tracing-subscriber 0.2.25", +] + [[package]] name = "ark-serialize" version = "0.3.0" @@ -558,12 +747,25 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ - "ark-serialize-derive", + "ark-serialize-derive 0.4.2", "ark-std 0.4.0", "digest 0.10.7", "num-bigint 0.4.6", ] +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint 0.4.6", +] + [[package]] name = "ark-serialize-derive" version = "0.4.2" @@ -575,6 +777,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -595,6 +808,16 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -624,7 +847,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -636,6 +859,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "aurora-engine-modexp" version = "1.2.0" @@ -648,13 +877,13 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -665,9 +894,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c39646d1a6b51240a1a23bb57ea4eebede7e16fbc237fdc876980233dcecb4f" +checksum = "455e9fb7743c6f6267eb2830ccc08686fbb3d13c9a689369562fd4d4ef9ea462" dependencies = [ "aws-credential-types", "aws-runtime", @@ -695,9 +924,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4471bef4c22a06d2c7a1b6492493d3fdf24a805323109d6874f9c94d5906ac14" +checksum = "687bc16bc431a8533fe0097c7f0182874767f920989d7260950172ae8e3c4465" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -707,9 +936,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.12.6" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dabb68eb3a7aa08b46fddfd59a3d55c978243557a90ab804769f7e20e67d2b01" +checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" dependencies = [ "aws-lc-sys", "zeroize", @@ -717,9 +946,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.27.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77926887776171ced7d662120a75998e444d3750c951abfe07f90da130514b1f" +checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" dependencies = [ "bindgen", "cc", @@ -730,9 +959,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.6" +version = "1.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aff45ffe35196e593ea3b9dd65b320e51e2dda95aff4390bc459e461d09c6ad" +checksum = "4f6c68419d8ba16d9a7463671593c54f81ba58cab466e9b759418da606dcc2e2" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -747,7 +976,6 @@ dependencies = [ "fastrand", "http 0.2.12", "http-body 0.4.6", - "once_cell", "percent-encoding", "pin-project-lite", "tracing", @@ -756,9 +984,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.80.0" +version = "1.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a36b09e8273d89c4f35ea122b83b30e48f906f3b644460d72a7d3656d1be93d" +checksum = "f68db68f26c6337fb89c15916d5ac59c1b4224eb0111492a4f7b85c1058f9ca8" dependencies = [ "aws-credential-types", "aws-runtime", @@ -781,19 +1009,18 @@ dependencies = [ "http 1.3.1", "http-body 0.4.6", "lru", - "once_cell", "percent-encoding", "regex-lite", - "sha2", + "sha2 0.10.9", "tracing", "url", ] [[package]] name = "aws-sdk-sso" -version = "1.64.0" +version = "1.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d4bdb0e5f80f0689e61c77ab678b2b9304af329616af38aef5b6b967b8e736" +checksum = "b2ac1674cba7872061a29baaf02209fefe499ff034dfd91bd4cc59e4d7741489" dependencies = [ "aws-credential-types", "aws-runtime", @@ -807,16 +1034,15 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", - "once_cell", "regex-lite", "tracing", ] [[package]] name = "aws-sdk-ssooidc" -version = "1.65.0" +version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbbb3ce8da257aedbccdcb1aadafbbb6a5fe9adf445db0e1ea897bdc7e22d08" +checksum = "3a6a22f077f5fd3e3c0270d4e1a110346cddf6769e9433eb9e6daceb4ca3b149" dependencies = [ "aws-credential-types", "aws-runtime", @@ -830,16 +1056,15 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", - "once_cell", "regex-lite", "tracing", ] [[package]] name = "aws-sdk-sts" -version = "1.65.0" +version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a78a8f50a1630db757b60f679c8226a8a70ee2ab5f5e6e51dc67f6c61c7cfd" +checksum = "19d440e1d368759bd10df0dbdddbfff6473d7cd73e9d9ef2363dc9995ac2d711" dependencies = [ "aws-credential-types", "aws-runtime", @@ -854,16 +1079,15 @@ dependencies = [ "aws-types", "fastrand", "http 0.2.12", - "once_cell", "regex-lite", "tracing", ] [[package]] name = "aws-sigv4" -version = "1.3.0" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d03c3c05ff80d54ff860fe38c726f6f494c639ae975203a101335f223386db" +checksum = "ddfb9021f581b71870a17eac25b52335b82211cdc092e02b6876b2bcefa61666" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", @@ -877,11 +1101,10 @@ dependencies = [ "hmac", "http 0.2.12", "http 1.3.1", - "once_cell", "p256 0.11.1", "percent-encoding", "ring", - "sha2", + "sha2 0.10.9", "subtle", "time", "tracing", @@ -901,31 +1124,29 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.63.1" +version = "0.63.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65d21e1ba6f2cdec92044f904356a19f5ad86961acf015741106cdfafd747c0" +checksum = "d2f77a921dbd2c78ebe70726799787c1d110a2245dd65e39b20923dfdfb2deee" dependencies = [ "aws-smithy-http", "aws-smithy-types", "bytes", - "crc32c", - "crc32fast", - "crc64fast-nvme", + "crc-fast", "hex", "http 0.2.12", "http-body 0.4.6", "md-5", "pin-project-lite", "sha1", - "sha2", + "sha2 0.10.9", "tracing", ] [[package]] name = "aws-smithy-eventstream" -version = "0.60.8" +version = "0.60.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c45d3dddac16c5c59d553ece225a88870cf81b7b813c9cc17b78cf4685eac7a" +checksum = "338a3642c399c0a5d157648426110e199ca7fd1c689cc395676b81aa563700c4" dependencies = [ "aws-smithy-types", "bytes", @@ -934,9 +1155,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.62.0" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5949124d11e538ca21142d1fba61ab0a2a2c1bc3ed323cdb3e4b878bfb83166" +checksum = "99335bec6cdc50a346fda1437f9fefe33abf8c99060739a546a16457f2862ca9" dependencies = [ "aws-smithy-eventstream", "aws-smithy-runtime-api", @@ -947,7 +1168,6 @@ dependencies = [ "http 0.2.12", "http 1.3.1", "http-body 0.4.6", - "once_cell", "percent-encoding", "pin-project-lite", "pin-utils", @@ -956,25 +1176,26 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.0.1" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aff1159006441d02e57204bf57a1b890ba68bedb6904ffd2873c1c4c11c546b" +checksum = "7f491388e741b7ca73b24130ff464c1478acc34d5b331b7dd0a2ee4643595a15" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", "aws-smithy-types", - "h2 0.4.8", + "h2 0.3.26", + "h2 0.4.10", "http 0.2.12", "http 1.3.1", "http-body 0.4.6", "hyper 0.14.32", "hyper 1.6.0", "hyper-rustls 0.24.2", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.7", "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.25", + "rustls 0.23.27", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", @@ -984,21 +1205,20 @@ dependencies = [ [[package]] name = "aws-smithy-json" -version = "0.61.3" +version = "0.61.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92144e45819cae7dc62af23eac5a038a58aa544432d2102609654376a900bd07" +checksum = "a16e040799d29c17412943bdbf488fd75db04112d0c0d4b9290bacf5ae0014b9" dependencies = [ "aws-smithy-types", ] [[package]] name = "aws-smithy-observability" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445d065e76bc1ef54963db400319f1dd3ebb3e0a74af20f7f7630625b0cc7cc0" +checksum = "9364d5989ac4dd918e5cc4c4bdcc61c9be17dcd2586ea7f69e348fc7c6cab393" dependencies = [ "aws-smithy-runtime-api", - "once_cell", ] [[package]] @@ -1013,9 +1233,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.8.1" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0152749e17ce4d1b47c7747bdfec09dac1ccafdcbc741ebf9daa2a373356730f" +checksum = "14302f06d1d5b7d333fd819943075b13d27c7700b414f574c3c35859bfb55d5e" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -1029,7 +1249,6 @@ dependencies = [ "http 1.3.1", "http-body 0.4.6", "http-body 1.0.1", - "once_cell", "pin-project-lite", "pin-utils", "tokio", @@ -1038,9 +1257,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.7.4" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da37cf5d57011cb1753456518ec76e31691f1f474b73934a284eb2a1c76510f" +checksum = "bd8531b6d8882fd8f48f82a9754e682e29dd44cff27154af51fa3eb730f59efb" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -1055,9 +1274,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.3.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836155caafba616c0ff9b07944324785de2ab016141c3550bd1c07882f8cee8f" +checksum = "d498595448e43de7f4296b7b7a18a8a02c61ec9349128c80a368f7c3b4ab11a8" dependencies = [ "base64-simd", "bytes", @@ -1081,18 +1300,18 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.9" +version = "0.60.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" +checksum = "3db87b96cb1b16c024980f133968d52882ca0daaee3a086c6decc500f6c99728" dependencies = [ "xmlparser", ] [[package]] name = "aws-types" -version = "1.3.6" +version = "1.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3873f8deed8927ce8d04487630dc9ff73193bab64742a61d050e57a68dec4125" +checksum = "8a322fec39e4df22777ed3ad8ea868ac2f94cd15e1a55f6ee8d8d6305057689a" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -1104,9 +1323,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -1160,9 +1379,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.7.3" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bincode" @@ -1179,7 +1398,7 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.12.1", @@ -1192,7 +1411,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.100", + "syn 2.0.103", "which", ] @@ -1247,7 +1466,23 @@ checksum = "42b6b4cb608b8282dc3b53d0f4c9ab404655d562674c682db7e6c0458cc83c23" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", +] + +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", ] [[package]] @@ -1258,9 +1493,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bitvec" @@ -1296,16 +1531,24 @@ dependencies = [ [[package]] name = "blake3" -version = "1.7.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17679a8d69b6d7fd9cd9801a536cec9fa5e5970b69f9d4747f70b39b031f5e7" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq 0.3.1", - "memmap2", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", ] [[package]] @@ -1332,9 +1575,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c79a94619fade3c0b887670333513a67ac28a6a7e653eb260bf0d4103db38d" +checksum = "4fd49896f12ac9b6dcd7a5998466b9b58263a695a3dd1ecc1aaca2e12a90b080" dependencies = [ "cc", "glob", @@ -1348,7 +1591,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34e20109dce74b02019885a01edc8ca485380a297ed8d6eb9e63e657774074b" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "js-sys", "primitive-types", "rustc-hex", @@ -1359,9 +1602,9 @@ dependencies = [ [[package]] name = "bon" -version = "3.5.1" +version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65268237be94042665b92034f979c42d431d2fd998b49809543afe3e66abad1c" +checksum = "f61138465baf186c63e8d9b6b613b508cd832cba4ce93cf37ce5f096f91ac1a6" dependencies = [ "bon-macros", "rustversion", @@ -1369,9 +1612,9 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.5.1" +version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "803c95b2ecf650eb10b5f87dda6b9f6a1b758cee53245e2b7b825c9b3803a443" +checksum = "40d1dad34aa19bf02295382f08d9bc40651585bd497266831d40ee6296fb49ca" dependencies = [ "darling", "ident_case", @@ -1379,7 +1622,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -1402,7 +1645,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -1423,9 +1666,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "byte-slice-cast" @@ -1435,9 +1678,9 @@ checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" [[package]] name = "byteorder" @@ -1449,7 +1692,7 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" dependencies = [ "serde", ] @@ -1486,9 +1729,9 @@ dependencies = [ [[package]] name = "c-kzg" -version = "1.0.3" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +checksum = "7318cfa722931cb5fe0838b98d3ce5621e75f6a6408abc21721d80de9223f2e4" dependencies = [ "blst", "cc", @@ -1501,9 +1744,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" dependencies = [ "serde", ] @@ -1531,8 +1774,8 @@ dependencies = [ "target-lexicon 0.12.16", "tempfile", "tokio", - "toml 0.8.20", - "toml_edit 0.22.24", + "toml 0.8.23", + "toml_edit 0.22.27", "tracing", "vergen", ] @@ -1568,9 +1811,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.17" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "jobserver", "libc", @@ -1588,9 +1831,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -1600,15 +1843,15 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -1648,11 +1891,22 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" -version = "4.5.34" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -1660,9 +1914,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.34" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -1672,21 +1926,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "cmake" @@ -1699,9 +1953,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "concurrent-queue" @@ -1720,9 +1974,9 @@ checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" [[package]] name = "const-hex" -version = "1.14.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c" +checksum = "83e22e0ed40b96a48d3db274f72fd365bd78f67af39b6bbd47e8a15e1c6207ff" dependencies = [ "cfg-if", "cpufeatures", @@ -1757,6 +2011,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "constant_time_eq" version = "0.3.1" @@ -1781,9 +2041,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -1806,9 +2066,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -1820,12 +2080,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] -name = "crc32c" -version = "0.6.8" +name = "crc-fast" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" +checksum = "6bf62af4cc77d8fe1c22dde4e721d87f2f54056139d8c412e1366b740305f56f" dependencies = [ - "rustc_version 0.4.1", + "crc", + "digest 0.10.7", + "libc", + "rand 0.9.1", + "regex", ] [[package]] @@ -1837,15 +2101,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crc64fast-nvme" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4955638f00a809894c947f85a024020a20815b65a5eea633798ea7924edab2b3" -dependencies = [ - "crc", -] - [[package]] name = "criterion" version = "0.5.1" @@ -2005,7 +2260,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -2016,7 +2271,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -2031,9 +2286,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "pem-rfc7468", @@ -2042,9 +2297,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", "serde", @@ -2069,7 +2324,7 @@ checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -2080,45 +2335,38 @@ checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] -name = "derive_more" -version = "0.99.19" +name = "derive-where" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +checksum = "e73f2692d4bd3cac41dca28934a39894200c9fabf49586d77d0e5954af1d7902" dependencies = [ - "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.1", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "derive_more" -version = "1.0.0" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ - "derive_more-impl 1.0.0", + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.103", ] [[package]] name = "derive_more" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" -dependencies = [ - "derive_more-impl 2.0.1", -] - -[[package]] -name = "derive_more-impl" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ "derive_more-impl 1.0.0", ] @@ -2134,13 +2382,13 @@ dependencies = [ [[package]] name = "derive_more-impl" -version = "2.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", "unicode-xid", ] @@ -2152,7 +2400,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", "unicode-xid", ] @@ -2175,7 +2423,7 @@ dependencies = [ "dsl_auto_type", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -2184,7 +2432,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" dependencies = [ - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -2202,7 +2450,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", "crypto-common", "subtle", @@ -2258,7 +2506,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -2278,7 +2526,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -2311,7 +2559,7 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der 0.7.9", + "der 0.7.10", "digest 0.10.7", "elliptic-curve 0.13.8", "rfc6979 0.4.0", @@ -2320,6 +2568,18 @@ dependencies = [ "spki 0.7.3", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "either" version = "1.15.0" @@ -2413,6 +2673,26 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "enum_dispatch" version = "0.3.13" @@ -2422,7 +2702,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -2433,7 +2713,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -2447,9 +2727,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", @@ -2465,9 +2745,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", @@ -2568,7 +2848,7 @@ dependencies = [ "chrono", "ethers-core", "reqwest", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_json", "thiserror 1.0.69", @@ -2595,10 +2875,10 @@ dependencies = [ "path-slash", "rayon", "regex", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "solang-parser", "svm-rs", "svm-rs-builds", @@ -2713,7 +2993,7 @@ dependencies = [ "atomic", "pear", "serde", - "toml 0.8.20", + "toml 0.8.23", "uncased", "version_check", ] @@ -2738,9 +3018,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -2756,7 +3036,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "forge-fmt" @@ -2803,7 +3083,7 @@ dependencies = [ "regex", "reqwest", "revm-primitives 1.3.0", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_json", "serde_regex", @@ -2824,6 +3104,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "funty" version = "2.0.0" @@ -2871,7 +3157,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -2922,27 +3208,27 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -2954,7 +3240,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -2969,7 +3255,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "libc", "libgit2-sys", "log", @@ -2978,9 +3264,9 @@ dependencies = [ [[package]] name = "glam" -version = "0.30.1" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3aa70d918d2b234126ff4f850f628f172542bf0603ded26b8ee36e5e22d5f9" +checksum = "50a99dbe56b72736564cfa4b85bf9a33079f16ae8b74983ab06af3b1a3696b11" [[package]] name = "glob" @@ -3036,7 +3322,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.8.0", + "indexmap 2.9.0", "slab", "tokio", "tokio-util", @@ -3045,9 +3331,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" dependencies = [ "atomic-waker", "bytes", @@ -3055,7 +3341,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.3.1", - "indexmap 2.8.0", + "indexmap 2.9.0", "slab", "tokio", "tokio-util", @@ -3064,9 +3350,9 @@ dependencies = [ [[package]] name = "half" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -3181,7 +3467,7 @@ dependencies = [ "rayon", "serde", "serde_arrays", - "sha2", + "sha2 0.10.9", "static_assertions", "subtle", "unroll", @@ -3209,7 +3495,7 @@ dependencies = [ "rayon", "serde", "serde_arrays", - "sha2", + "sha2 0.10.9", "static_assertions", "subtle", "unroll", @@ -3256,9 +3542,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", "equivalent", @@ -3272,7 +3558,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.4", ] [[package]] @@ -3283,15 +3569,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -3302,6 +3582,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + [[package]] name = "hex-literal" version = "0.4.1" @@ -3442,7 +3731,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.8", + "h2 0.4.10", "http 1.3.1", "http-body 1.0.1", "httparse", @@ -3471,15 +3760,14 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", "http 1.3.1", "hyper 1.6.0", "hyper-util", - "rustls 0.23.25", + "rustls 0.23.27", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", @@ -3489,16 +3777,18 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ "bytes", "futures-channel", + "futures-core", "futures-util", "http 1.3.1", "http-body 1.0.1", "hyper 1.6.0", + "libc", "pin-project-lite", "socket2", "tokio", @@ -3508,9 +3798,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.62" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3532,21 +3822,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -3555,31 +3846,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -3587,65 +3858,52 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] @@ -3667,9 +3925,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -3710,7 +3968,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -3751,12 +4009,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.4", "serde", ] @@ -3787,7 +4045,7 @@ version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.5.0", + "hermit-abi", "libc", "windows-sys 0.59.0", ] @@ -3825,6 +4083,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -3842,10 +4109,11 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.3", "libc", ] @@ -3917,7 +4185,7 @@ dependencies = [ "ecdsa 0.16.9", "elliptic-curve 0.13.8", "once_cell", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -3986,9 +4254,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" [[package]] name = "libgit2-sys" @@ -4004,25 +4272,25 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.53.2", ] [[package]] name = "libm" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libmimalloc-sys" -version = "0.1.40" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07d0e07885d6a754b9c7993f2625187ad694ee985d60f23355ff0e7077261502" +checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4" dependencies = [ "cc", "libc", @@ -4034,10 +4302,56 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "libc", ] +[[package]] +name = "libsecp256k1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" +dependencies = [ + "arrayref", + "base64 0.22.1", + "digest 0.9.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + [[package]] name = "libz-sys" version = "1.1.22" @@ -4064,21 +4378,21 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -4102,7 +4416,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.4", ] [[package]] @@ -4113,7 +4427,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -4147,9 +4461,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" @@ -4177,9 +4491,9 @@ checksum = "3d97bbf43eb4f088f8ca469930cde17fa036207c9a5e02ccc5107c4e8b17c964" [[package]] name = "metrics" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884adb57038347dfbaf2d5065887b6cf4312330dc8e94bc30a1a839bd79d3261" +checksum = "3045b4193fbdc5b5681f32f11070da9be3609f189a79f3390706d42587f46bb5" dependencies = [ "ahash", "portable-atomic", @@ -4191,7 +4505,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62a6a1f7141f1d9bc7a886b87536bbfc97752e08b369e1e0453a9acfab5f5da4" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.9.0", "itoa", "lockfree-object-pool", "metrics", @@ -4199,7 +4513,7 @@ dependencies = [ "once_cell", "tracing", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -4212,7 +4526,7 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "hashbrown 0.14.5", - "indexmap 2.8.0", + "indexmap 2.9.0", "metrics", "num_cpus", "ordered-float", @@ -4223,9 +4537,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.44" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99585191385958383e13f6b822e6b6d8d9cf928e7d286ceb092da92b43c87bc1" +checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af" dependencies = [ "libmimalloc-sys", ] @@ -4236,24 +4550,30 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] @@ -4423,11 +4743,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] @@ -4449,7 +4769,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -4492,17 +4812,29 @@ dependencies = [ name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" dependencies = [ "critical-section", "portable-atomic", ] +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "oorandom" version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "open-fastrlp" @@ -4541,7 +4873,7 @@ version = "1.2.1-rc.0" dependencies = [ "bytemuck", "chrono", - "getrandom 0.3.1", + "getrandom 0.3.3", "num-bigint 0.4.6", "openvm-custom-insn", "openvm-platform", @@ -4585,7 +4917,7 @@ version = "1.2.1-rc.0" dependencies = [ "openvm-macros-common", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -4611,7 +4943,7 @@ dependencies = [ "num-prime", "openvm-macros-common", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -4663,7 +4995,7 @@ dependencies = [ "openvm-stark-sdk", "openvm-transpiler", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -4713,7 +5045,7 @@ dependencies = [ "openvm-transpiler", "tempfile", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -4812,7 +5144,7 @@ version = "1.2.1-rc.0" dependencies = [ "itertools 0.14.0", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -4837,7 +5169,7 @@ version = "1.2.1-rc.0" dependencies = [ "itertools 0.14.0", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -4860,7 +5192,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -4881,6 +5213,7 @@ dependencies = [ "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-ecc-guest", "openvm-ecc-transpiler", "openvm-instructions", "openvm-mod-circuit-builder", @@ -4901,9 +5234,13 @@ dependencies = [ "elliptic-curve 0.13.8", "group 0.13.0", "halo2curves-axiom", + "hex-literal 0.4.1", + "lazy_static", + "num-bigint 0.4.6", "once_cell", "openvm", "openvm-algebra-guest", + "openvm-algebra-moduli-macros", "openvm-custom-insn", "openvm-ecc-sw-macros", "openvm-ecc-te-macros", @@ -4917,12 +5254,14 @@ name = "openvm-ecc-integration-tests" version = "1.2.1-rc.0" dependencies = [ "eyre", - "hex-literal", + "halo2curves-axiom", + "hex-literal 0.4.1", "num-bigint 0.4.6", "openvm-algebra-circuit", "openvm-algebra-transpiler", "openvm-circuit", "openvm-ecc-circuit", + "openvm-ecc-guest", "openvm-ecc-transpiler", "openvm-keccak256-transpiler", "openvm-rv32im-transpiler", @@ -4938,16 +5277,16 @@ version = "1.2.1-rc.0" dependencies = [ "openvm-macros-common", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "openvm-ecc-te-macros" -version = "1.0.0" +version = "1.2.1-rc.0" dependencies = [ "openvm-macros-common", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -5014,7 +5353,7 @@ dependencies = [ "quote", "strum", "strum_macros", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -5084,7 +5423,7 @@ dependencies = [ name = "openvm-macros-common" version = "1.2.1-rc.0" dependencies = [ - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -5164,7 +5503,7 @@ name = "openvm-native-compiler-derive" version = "1.2.1-rc.0" dependencies = [ "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -5314,7 +5653,6 @@ version = "1.2.1-rc.0" dependencies = [ "critical-section", "embedded-alloc", - "getrandom 0.2.15", "libm", "openvm-custom-insn", "openvm-rv32im-guest", @@ -5502,7 +5840,7 @@ dependencies = [ "openvm-stark-sdk", "openvm-toolchain-tests", "openvm-transpiler", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -5514,7 +5852,7 @@ dependencies = [ "openvm-stark-backend", "openvm-stark-sdk", "rand 0.8.5", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -5535,7 +5873,7 @@ dependencies = [ "openvm-stark-sdk", "rand 0.8.5", "serde", - "sha2", + "sha2 0.10.9", "strum", ] @@ -5593,7 +5931,7 @@ version = "1.1.1" source = "git+https://github.com/openvm-org/stark-backend.git?rev=f48090c9febd021f8ee0349bc929a775fb1fa3ad#f48090c9febd021f8ee0349bc929a775fb1fa3ad" dependencies = [ "derivative", - "derive_more 0.99.19", + "derive_more 0.99.20", "ff 0.13.1", "itertools 0.14.0", "metrics", @@ -5616,10 +5954,10 @@ dependencies = [ "serde", "serde_json", "static_assertions", - "toml 0.8.20", + "toml 0.8.23", "tracing", "tracing-forest", - "tracing-subscriber", + "tracing-subscriber 0.3.19", "zkhash", ] @@ -5711,7 +6049,7 @@ checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ "ecdsa 0.14.8", "elliptic-curve 0.12.3", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -5746,6 +6084,18 @@ dependencies = [ "serde", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "sha2 0.10.9", +] + [[package]] name = "p3-air" version = "0.1.0" @@ -6107,9 +6457,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.7.4" +version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9fde3d0718baf5bc92f577d652001da0f8d54cd03a7974e118d04fc888dc23d" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" dependencies = [ "arrayvec", "bitvec", @@ -6123,14 +6473,14 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.7.4" +version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581c837bb6b9541ce7faa9377c20616e4fb7650f6b0f68bc93c827ee504fb7b3" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -6141,9 +6491,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -6151,9 +6501,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -6224,7 +6574,7 @@ dependencies = [ "digest 0.10.7", "hmac", "password-hash", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -6247,7 +6597,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -6267,9 +6617,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", "thiserror 2.0.12", @@ -6283,7 +6633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.7.1", + "indexmap 2.9.0", ] [[package]] @@ -6316,7 +6666,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -6356,7 +6706,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der 0.7.9", + "der 0.7.10", "spki 0.7.3", ] @@ -6396,9 +6746,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "poseidon-primitives" @@ -6411,7 +6761,7 @@ dependencies = [ "lazy_static", "log", "rand 0.8.5", - "rand_xorshift", + "rand_xorshift 0.3.0", "thiserror 1.0.69", ] @@ -6443,7 +6793,7 @@ dependencies = [ "md-5", "memchr", "rand 0.9.1", - "sha2", + "sha2 0.10.9", "stringprep", ] @@ -6458,6 +6808,15 @@ dependencies = [ "postgres-protocol", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -6470,7 +6829,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.24", + "zerocopy", ] [[package]] @@ -6481,12 +6840,21 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "prettyplease" -version = "0.2.31" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" +checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55" dependencies = [ "proc-macro2", - "syn 2.0.100", + "syn 2.0.103", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve 0.13.8", ] [[package]] @@ -6509,7 +6877,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ - "toml_edit 0.22.24", + "toml_edit 0.22.27", ] [[package]] @@ -6531,14 +6899,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -6551,25 +6919,25 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", "version_check", "yansi 1.0.1", ] [[package]] name = "proptest" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" +checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" dependencies = [ "bit-set 0.8.0", "bit-vec 0.8.0", - "bitflags 2.8.0", + "bitflags 2.9.1", "lazy_static", "num-traits", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_xorshift", + "rand 0.9.1", + "rand_chacha 0.9.0", + "rand_xorshift 0.4.0", "regex-syntax 0.8.5", "rusty-fork", "tempfile", @@ -6578,9 +6946,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f239d656363bcee73afef85277f1b281e8ac6212a1d42aa90e55b90ed43c47a4" +checksum = "8970a78afe0628a3e3430376fc5fd76b6b45c4d43360ffd6cdd40bdde72b682a" dependencies = [ "libc", "memoffset", @@ -6592,9 +6960,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755ea671a1c34044fa165247aaf6f419ca39caa6003aee791a0df2713d8f1b6d" +checksum = "458eb0c55e7ece017adeba38f2248ff3ac615e53660d7c71a238d7d2a01c7598" dependencies = [ "once_cell", "target-lexicon 0.13.2", @@ -6602,9 +6970,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc95a2e67091e44791d4ea300ff744be5293f394f1bafd9f78c080814d35956e" +checksum = "7114fe5457c61b276ab77c5055f206295b812608083644a5c5b2640c3102565c" dependencies = [ "libc", "pyo3-build-config", @@ -6612,15 +6980,15 @@ dependencies = [ [[package]] name = "quanta" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" dependencies = [ "crossbeam-utils", "libc", "once_cell", "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "web-sys", "winapi", ] @@ -6691,6 +7059,7 @@ checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", + "serde", ] [[package]] @@ -6719,7 +7088,17 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", + "serde", ] [[package]] @@ -6731,13 +7110,22 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.3", +] + [[package]] name = "raw-cpuid" version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", ] [[package]] @@ -6762,11 +7150,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", ] [[package]] @@ -6775,11 +7163,31 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 1.0.69", ] +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "regex" version = "1.11.1" @@ -6841,11 +7249,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper", - "hyper-rustls", + "hyper 0.14.32", + "hyper-rustls 0.24.2", "ipnet", "js-sys", "log", @@ -6853,7 +7261,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", + "rustls 0.21.12", "rustls-pemfile", "serde", "serde_json", @@ -6861,7 +7269,7 @@ dependencies = [ "sync_wrapper", "system-configuration", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", @@ -6873,46 +7281,164 @@ dependencies = [ [[package]] name = "revm" -version = "18.0.0" +version = "24.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15689a3c6a8d14b647b4666f2e236ef47b5a5133cdfd423f545947986fff7013" +checksum = "01d277408ff8d6f747665ad9e52150ab4caf8d5eaf0d787614cf84633c8337b4" +dependencies = [ + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database", + "revm-database-interface", + "revm-handler", + "revm-inspector", + "revm-interpreter", + "revm-precompile", + "revm-primitives 19.2.0", + "revm-state", +] + +[[package]] +name = "revm-bytecode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942fe4724cf552fd28db6b0a2ca5b79e884d40dd8288a4027ed1e9090e0c6f49" +dependencies = [ + "bitvec", + "once_cell", + "phf", + "revm-primitives 19.2.0", + "serde", +] + +[[package]] +name = "revm-context" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01aad49e1233f94cebda48a4e5cef022f7c7ed29b4edf0d202b081af23435ef" dependencies = [ - "auto_impl", "cfg-if", - "dyn-clone", + "derive-where", + "revm-bytecode", + "revm-context-interface", + "revm-database-interface", + "revm-primitives 19.2.0", + "revm-state", + "serde", +] + +[[package]] +name = "revm-context-interface" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b844f48a411e62c7dde0f757bf5cce49c85b86d6fc1d3b2722c07f2bec4c3ce" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "auto_impl", + "either", + "revm-database-interface", + "revm-primitives 19.2.0", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad3fbe34f6bb00a9c3155723b3718b9cb9f17066ba38f9eb101b678cd3626775" +dependencies = [ + "alloy-eips", + "revm-bytecode", + "revm-database-interface", + "revm-primitives 19.2.0", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database-interface" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b8acd36784a6d95d5b9e1b7be3ce014f1e759abb59df1fa08396b30f71adc2a" +dependencies = [ + "auto_impl", + "revm-primitives 19.2.0", + "revm-state", + "serde", +] + +[[package]] +name = "revm-handler" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "481e8c3290ff4fa1c066592fdfeb2b172edfd14d12e6cade6f6f5588cad9359a" +dependencies = [ + "auto_impl", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database-interface", "revm-interpreter", "revm-precompile", + "revm-primitives 19.2.0", + "revm-state", + "serde", +] + +[[package]] +name = "revm-inspector" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc1167ef8937d8867888e63581d8ece729a72073d322119ef4627d813d99ecb" +dependencies = [ + "auto_impl", + "revm-context", + "revm-database-interface", + "revm-handler", + "revm-interpreter", + "revm-primitives 19.2.0", + "revm-state", "serde", "serde_json", ] [[package]] name = "revm-interpreter" -version = "14.0.0" +version = "20.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74e3f11d0fed049a4a10f79820c59113a79b38aed4ebec786a79d5c667bfeb51" +checksum = "b5ee65e57375c6639b0f50555e92a4f1b2434349dd32f52e2176f5c711171697" dependencies = [ - "revm-primitives 14.0.0", + "revm-bytecode", + "revm-context-interface", + "revm-primitives 19.2.0", "serde", ] [[package]] name = "revm-precompile" -version = "15.0.0" +version = "21.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e381060af24b750069a2b2d2c54bba273d84e8f5f9e8026fc9262298e26cc336" +checksum = "0f9311e735123d8d53a02af2aa81877bba185be7c141be7f931bb3d2f3af449c" dependencies = [ + "ark-bls12-381", + "ark-bn254 0.5.0", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", "aurora-engine-modexp", "blst", "c-kzg", "cfg-if", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libsecp256k1", "once_cell", - "revm-primitives 14.0.0", + "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "revm-primitives 19.2.0", "ripemd", "secp256k1", - "sha2", - "substrate-bn", + "sha2 0.10.9", ] [[package]] @@ -6924,7 +7450,7 @@ dependencies = [ "alloy-primitives 0.4.2", "alloy-rlp", "auto_impl", - "bitflags 2.8.0", + "bitflags 2.9.1", "bitvec", "enumn", "hashbrown 0.14.5", @@ -6933,21 +7459,24 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "14.0.0" +version = "19.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3702f132bb484f4f0d0ca4f6fbde3c82cfd745041abbedd6eda67730e1868ef0" +checksum = "1c1588093530ec4442461163be49c433c07a3235d1ca6f6799fef338dacc50d3" dependencies = [ - "alloy-eip2930", - "alloy-eip7702", - "alloy-primitives 0.8.25", - "auto_impl", - "bitflags 2.8.0", - "bitvec", - "c-kzg", - "cfg-if", - "dyn-clone", - "enumn", - "hex", + "alloy-primitives 1.2.0", + "num_enum", + "serde", +] + +[[package]] +name = "revm-state" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0040c61c30319254b34507383ba33d85f92949933adf6525a2cede05d165e1fa" +dependencies = [ + "bitflags 2.9.1", + "revm-bytecode", + "revm-primitives 19.2.0", "serde", ] @@ -6980,7 +7509,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -7033,34 +7562,10 @@ dependencies = [ name = "rrs-lib" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4382d3af3a4ebdae7f64ba6edd9114fff92c89808004c4943b393377a25d001" -dependencies = [ - "downcast-rs", - "paste", -] - -[[package]] -name = "ruint" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" -dependencies = [ - "alloy-rlp", - "ark-ff 0.3.0", - "ark-ff 0.4.2", - "bytes", - "fastrlp 0.3.1", - "num-bigint 0.4.6", - "num-traits", - "parity-scale-codec", - "primitive-types", - "proptest", - "rand 0.8.5", - "rlp", - "ruint-macro 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde", - "valuable", - "zeroize", +checksum = "b4382d3af3a4ebdae7f64ba6edd9114fff92c89808004c4943b393377a25d001" +dependencies = [ + "downcast-rs", + "paste", ] [[package]] @@ -7080,7 +7585,7 @@ dependencies = [ "bytemuck", "bytes", "criterion", - "der 0.7.9", + "der 0.7.10", "diesel", "ethereum_ssz", "eyre", @@ -7116,7 +7621,34 @@ dependencies = [ "serde_json", "sqlx-core", "subtle", - "thiserror 2.0.11", + "thiserror 2.0.12", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11256b5fe8c68f56ac6f39ef0720e592f33d2367a4782740d9c9142e889c7fb4" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.5", + "rand 0.9.1", + "rlp", + "ruint-macro 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", "valuable", "zeroize", ] @@ -7136,9 +7668,9 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -7182,7 +7714,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -7191,14 +7723,14 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.3" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] @@ -7216,14 +7748,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.25" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "aws-lc-rs", "once_cell", "rustls-pki-types", - "rustls-webpki 0.103.1", + "rustls-webpki 0.103.3", "subtle", "zeroize", ] @@ -7263,9 +7795,12 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] [[package]] name = "rustls-webpki" @@ -7279,9 +7814,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.1" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "aws-lc-rs", "ring", @@ -7291,9 +7826,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "rusty-fork" @@ -7343,7 +7878,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -7355,6 +7890,18 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -7392,7 +7939,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct 0.2.0", - "der 0.7.9", + "der 0.7.10", "generic-array", "pkcs8 0.10.2", "serdect", @@ -7402,10 +7949,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ + "bitcoin_hashes", "rand 0.8.5", "secp256k1-sys", ] @@ -7425,8 +7973,21 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.8.0", - "core-foundation", + "bitflags 2.9.1", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -7504,7 +8065,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -7513,7 +8074,7 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.9.0", "itoa", "memchr", "ryu", @@ -7532,9 +8093,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -7553,15 +8114,16 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.8.0", + "indexmap 2.9.0", + "schemars", "serde", "serde_derive", "serde_json", @@ -7571,14 +8133,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +checksum = "81679d9ed988d5e9a5e6531dc3f2c28efbd639cbd1dfb628df08edea6004da77" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -7604,9 +8166,22 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -7650,9 +8225,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -7691,24 +8266,21 @@ checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "snark-verifier" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28e4c4ed1edca41687fe2d8a09ba30badb0a5cc7fa56dd1159d62aeab7c99ace" +checksum = "c9203c416ff9de0762667270b21573ba5e6edaeda08743b3ca37dc8a5e0a4480" dependencies = [ "halo2-base", "halo2-ecc", @@ -7721,16 +8293,16 @@ dependencies = [ "pairing 0.23.0", "rand 0.8.5", "revm", - "ruint 1.12.3", + "ruint 1.15.0", "serde", "sha3", ] [[package]] name = "snark-verifier-sdk" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "babff70ce6292fce03f692d68569f76b8f6710dbac7be7fe5f32c915909c9065" +checksum = "290ae6e750d9d5fdf05393bbcae6bf7a63e3408eab023abf7d466156a234ac85" dependencies = [ "bincode", "ethereum-types", @@ -7751,9 +8323,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -7796,7 +8368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der 0.7.9", + "der 0.7.10", ] [[package]] @@ -7814,15 +8386,15 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.2", + "hashbrown 0.15.4", "hashlink", - "indexmap 2.7.1", + "indexmap 2.9.0", "log", "memchr", "once_cell", "percent-encoding", "smallvec", - "thiserror 2.0.11", + "thiserror 2.0.12", "tracing", "url", ] @@ -7893,20 +8465,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.100", -] - -[[package]] -name = "substrate-bn" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" -dependencies = [ - "byteorder", - "crunchy", - "lazy_static", - "rand 0.8.5", - "rustc-hex", + "syn 2.0.103", ] [[package]] @@ -7939,10 +8498,10 @@ dependencies = [ "hex", "once_cell", "reqwest", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "url", "zip", @@ -7956,7 +8515,7 @@ checksum = "aa64b5e8eecd3a8af7cfc311e29db31a268a62d5953233d3e8243ec77a71c4e3" dependencies = [ "build_const", "hex", - "semver 1.0.25", + "semver 1.0.26", "serde_json", "svm-rs", ] @@ -7974,9 +8533,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", @@ -7992,7 +8551,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -8003,13 +8562,13 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -8019,7 +8578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -8053,14 +8612,14 @@ checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", - "rustix 1.0.3", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -8093,7 +8652,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -8104,7 +8663,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "test-case-core", ] @@ -8116,7 +8675,7 @@ checksum = "e7f46083d221181166e5b6f6b1e5f1d499f3a76888826e6cb1d057554157cd0f" dependencies = [ "env_logger", "test-log-macros", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -8127,7 +8686,7 @@ checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -8156,7 +8715,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -8167,17 +8726,16 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -8253,9 +8811,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -8288,9 +8846,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.2" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -8311,7 +8869,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -8356,15 +8914,15 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.25", + "rustls 0.23.27", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -8379,7 +8937,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", @@ -8388,21 +8946,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.24", + "toml_edit 0.22.27", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] @@ -8413,7 +8971,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", @@ -8422,17 +8980,40 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.8.0", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.7.3", + "toml_write", + "winnow 0.7.11", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "tower-layer", + "tower-service", ] +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" version = "0.3.3" @@ -8453,20 +9034,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -8482,7 +9063,7 @@ dependencies = [ "smallvec", "thiserror 1.0.69", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.19", ] [[package]] @@ -8496,6 +9077,15 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.19" @@ -8579,7 +9169,7 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" @@ -8641,12 +9231,6 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -8661,9 +9245,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "valuable" @@ -8732,9 +9320,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -8745,6 +9333,12 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -8767,7 +9361,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "wasm-bindgen-shared", ] @@ -8802,7 +9396,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -8832,6 +9426,18 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + [[package]] name = "whoami" version = "1.6.0" @@ -8876,27 +9482,71 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "windows-implement" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ - "windows-targets 0.48.5", + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", ] [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] [[package]] name = "windows-sys" @@ -8940,13 +9590,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -8959,6 +9625,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -8971,6 +9643,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -8983,12 +9661,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -9001,6 +9691,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -9013,6 +9709,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -9025,6 +9727,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -9037,6 +9745,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.5.40" @@ -9048,9 +9762,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -9071,20 +9785,14 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -9115,9 +9823,9 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -9127,54 +9835,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive 0.8.24", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -9194,7 +9882,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "synstructure", ] @@ -9215,14 +9903,25 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", ] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -9231,13 +9930,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.103", ] [[package]] @@ -9281,7 +9980,7 @@ dependencies = [ "pasta_curves 0.5.1", "rand 0.8.5", "serde", - "sha2", + "sha2 0.10.9", "sha3", "subtle", ] diff --git a/benchmarks/prove/src/bin/ecrecover.rs b/benchmarks/prove/src/bin/ecrecover.rs index 268e68ff27..54fca3e3c2 100644 --- a/benchmarks/prove/src/bin/ecrecover.rs +++ b/benchmarks/prove/src/bin/ecrecover.rs @@ -66,22 +66,12 @@ pub struct Rv32ImEcRecoverConfig { pub ecc: EccExtension, } -impl InitFileGenerator for Rv32ImEcRecoverConfig { - fn generate_init_file_contnts(&self) -> Option { - Some(format!( - "// This file is automatically generated by cargo openvm. Do not rename or edit.\n{}\n{}\n", - self.modular.generate_moduli_init(), - self.ecc.generate_ecc_init() - )) - } -} - impl InitFileGenerator for Rv32ImEcRecoverConfig { fn generate_init_file_contents(&self) -> Option { Some(format!( "// This file is automatically generated by cargo openvm. Do not rename or edit.\n{}\n{}\n", self.modular.generate_moduli_init(), - self.weierstrass.generate_sw_init() + self.ecc.generate_ecc_init() )) } } diff --git a/crates/sdk/src/config/global.rs b/crates/sdk/src/config/global.rs index fb15631905..e3e165a5b0 100644 --- a/crates/sdk/src/config/global.rs +++ b/crates/sdk/src/config/global.rs @@ -260,7 +260,7 @@ impl InitFileGenerator for SdkVmConfig { } if let Some(ecc_config) = &self.ecc { - contents.push_str(&ecc_config.generate_sw_init()); + contents.push_str(&ecc_config.generate_ecc_init()); contents.push('\n'); } diff --git a/crates/toolchain/tests/tests/transpiler_tests.rs b/crates/toolchain/tests/tests/transpiler_tests.rs index bf07eccc42..e10a7e3a0c 100644 --- a/crates/toolchain/tests/tests/transpiler_tests.rs +++ b/crates/toolchain/tests/tests/transpiler_tests.rs @@ -16,7 +16,7 @@ use openvm_circuit::{ derive::VmConfig, utils::air_test, }; -use openvm_ecc_circuit::{SECP256K1_MODULUS, SECP256K1_ORDER}; +use openvm_ecc_circuit::SECP256K1_CONFIG; use openvm_instructions::exe::VmExe; use openvm_platform::memory::MEM_SIZE; use openvm_rv32im_circuit::{ @@ -130,8 +130,14 @@ impl InitFileGenerator for Rv32ModularFp2Int256Config { #[test_case("tests/data/rv32im-intrin-from-as")] fn test_intrinsic_runtime(elf_path: &str) -> Result<()> { let config = Rv32ModularFp2Int256Config::new( - vec![SECP256K1_MODULUS.clone(), SECP256K1_ORDER.clone()], - vec![("Secp256k1Coord".to_string(), SECP256K1_MODULUS.clone())], + vec![ + SECP256K1_CONFIG.modulus.clone(), + SECP256K1_CONFIG.scalar.clone(), + ], + vec![( + SECP256K1_CONFIG.struct_name.clone(), + SECP256K1_CONFIG.modulus.clone(), + )], ); let elf = get_elf(elf_path)?; let openvm_exe = VmExe::from_elf( diff --git a/extensions/ecc/circuit/Cargo.toml b/extensions/ecc/circuit/Cargo.toml index adfce69f36..e30df2f8a7 100644 --- a/extensions/ecc/circuit/Cargo.toml +++ b/extensions/ecc/circuit/Cargo.toml @@ -19,6 +19,7 @@ openvm-rv32im-circuit = { workspace = true } openvm-algebra-circuit = { workspace = true } openvm-rv32-adapters = { workspace = true } openvm-ecc-transpiler = { workspace = true } +openvm-ecc-guest = { workspace = true, features = ["ed25519"] } num-bigint = { workspace = true } num-traits = { workspace = true } diff --git a/extensions/ecc/circuit/src/config.rs b/extensions/ecc/circuit/src/config.rs index 1477ea9e70..0487f28dcc 100644 --- a/extensions/ecc/circuit/src/config.rs +++ b/extensions/ecc/circuit/src/config.rs @@ -48,12 +48,12 @@ impl Rv32EccConfig { } } -impl InitFileGenerator for Rv32WeierstrassConfig { +impl InitFileGenerator for Rv32EccConfig { fn generate_init_file_contents(&self) -> Option { Some(format!( "// This file is automatically generated by cargo openvm. Do not rename or edit.\n{}\n{}\n", self.modular.generate_moduli_init(), - self.weierstrass.generate_sw_init() + self.ecc.generate_ecc_init() )) } } diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index 2d4a20dc0c..df4b9c6fe6 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -1,10 +1,11 @@ use derive_more::derive::From; +use hex_literal::hex; use num_bigint::BigUint; use num_traits::{FromPrimitive, Zero}; use once_cell::sync::Lazy; -use openvm_algebra_guest::IntMod; -use openvm_circuit::arch::{ - SystemPort, VmExtension, VmInventory, VmInventoryBuilder, VmInventoryError, +use openvm_circuit::{ + arch::{SystemPort, VmExtension, VmInventory, VmInventoryBuilder, VmInventoryError}, + system::phantom::PhantomChip, }; use openvm_circuit_derive::{AnyEnum, InstructionExecutor}; use openvm_circuit_primitives::bitwise_op_lookup::{ @@ -12,9 +13,8 @@ use openvm_circuit_primitives::bitwise_op_lookup::{ }; use openvm_circuit_primitives_derive::{Chip, ChipUsageGetter}; use openvm_ecc_guest::{ + algebra::IntMod, ed25519::{CURVE_A as ED25519_A, CURVE_D as ED25519_D, ED25519_MODULUS, ED25519_ORDER}, - k256::{SECP256K1_MODULUS, SECP256K1_ORDER}, - p256::{CURVE_A as P256_A, CURVE_B as P256_B, P256_MODULUS, P256_ORDER}, }; use openvm_ecc_transpiler::{Rv32EdwardsOpcode, Rv32WeierstrassOpcode}; use openvm_instructions::{LocalOpcode, VmOpcode}; @@ -65,9 +65,13 @@ pub struct TeCurveCoeffs { } pub static SECP256K1_CONFIG: Lazy> = Lazy::new(|| CurveConfig { - struct_name: "Secp256k1".to_string(), - modulus: SECP256K1_MODULUS.clone(), - scalar: SECP256K1_ORDER.clone(), + struct_name: "Secp256k1Point".to_string(), + modulus: BigUint::from_bytes_be(&hex!( + "FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F" + )), + scalar: BigUint::from_bytes_be(&hex!( + "FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141" + )), coeffs: SwCurveCoeffs { a: BigUint::zero(), b: BigUint::from_u8(7u8).unwrap(), @@ -75,17 +79,25 @@ pub static SECP256K1_CONFIG: Lazy> = Lazy::new(|| Cur }); pub static P256_CONFIG: Lazy> = Lazy::new(|| CurveConfig { - struct_name: "P256".to_string(), - modulus: P256_MODULUS.clone(), - scalar: P256_ORDER.clone(), + struct_name: "P256Point".to_string(), + modulus: BigUint::from_bytes_be(&hex!( + "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff" + )), + scalar: BigUint::from_bytes_be(&hex!( + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" + )), coeffs: SwCurveCoeffs { - a: BigUint::from_bytes_le(P256_A.as_le_bytes()), - b: BigUint::from_bytes_le(P256_B.as_le_bytes()), + a: BigUint::from_bytes_le(&hex!( + "fcffffffffffffffffffffff00000000000000000000000001000000ffffffff" + )), + b: BigUint::from_bytes_le(&hex!( + "4b60d2273e3cce3bf6b053ccb0061d65bc86987655bdebb3e7933aaad835c65a" + )), }, }); pub static ED25519_CONFIG: Lazy> = Lazy::new(|| CurveConfig { - struct_name: "Ed25519".to_string(), + struct_name: "Ed25519Point".to_string(), modulus: ED25519_MODULUS.clone(), scalar: ED25519_ORDER.clone(), coeffs: TeCurveCoeffs { @@ -122,7 +134,7 @@ impl EccExtension { } } -#[derive(Chip, ChipUsageGetter, InstructionExecutor, AnyEnum, BytesStateful)] +#[derive(Chip, ChipUsageGetter, InstructionExecutor, AnyEnum)] pub enum EccExtensionExecutor { // 32 limbs prime SwEcAddNeRv32_32(SwAddNeChip), @@ -139,6 +151,8 @@ pub enum EccExtensionExecutor { #[derive(ChipUsageGetter, Chip, AnyEnum, From)] pub enum EccExtensionPeriphery { BitwiseOperationLookup(SharedBitwiseOperationLookupChip<8>), + // We put this only to get the generic to work + Phantom(PhantomChip), } impl VmExtension for EccExtension { diff --git a/extensions/ecc/guest/Cargo.toml b/extensions/ecc/guest/Cargo.toml index f997b7213c..a85f8c4597 100644 --- a/extensions/ecc/guest/Cargo.toml +++ b/extensions/ecc/guest/Cargo.toml @@ -16,14 +16,20 @@ elliptic-curve = { workspace = true, features = ["arithmetic", "sec1"] } openvm-custom-insn = { workspace = true } openvm-rv32im-guest = { workspace = true } openvm-algebra-guest = { workspace = true } +openvm-algebra-moduli-macros = { workspace = true } openvm-ecc-sw-macros = { workspace = true } openvm-ecc-te-macros = { workspace = true } once_cell = { workspace = true, features = ["race", "alloc"] } +num-bigint = { workspace = true } +hex-literal = { workspace = true } # Used for `halo2curves` feature halo2curves-axiom = { workspace = true, optional = true } group = "0.13.0" +[target.'cfg(not(target_os = "zkvm"))'.dependencies] +lazy_static = { workspace = true } + [features] default = [] ed25519 = [] diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs index e05a619f00..e76e7bed04 100644 --- a/extensions/ecc/guest/src/ed25519.rs +++ b/extensions/ecc/guest/src/ed25519.rs @@ -5,7 +5,7 @@ use hex_literal::hex; use lazy_static::lazy_static; #[cfg(not(target_os = "zkvm"))] use num_bigint::BigUint; -use openvm_algebra_guest::{Field, IntMod}; +use openvm_algebra_guest::IntMod; use super::group::{CyclicGroup, Group}; use crate::{edwards::CachedMulTable, IntrinsicCurve}; @@ -46,21 +46,6 @@ openvm_ecc_te_macros::te_declare! { Ed25519Point { mod_type = Ed25519Coord, a = CURVE_A, d = CURVE_D }, } -impl Field for Ed25519Coord { - const ZERO: Self = ::ZERO; - const ONE: Self = ::ONE; - - type SelfRef<'a> = &'a Self; - - fn double_assign(&mut self) { - IntMod::double_assign(self); - } - - fn square_assign(&mut self) { - IntMod::square_assign(self); - } -} - impl CyclicGroup for Ed25519Point { // from_const_bytes is little endian const GENERATOR: Self = Ed25519Point { diff --git a/extensions/ecc/sw-macros/src/lib.rs b/extensions/ecc/sw-macros/src/lib.rs index 33e13a67d3..e8ab97eae0 100644 --- a/extensions/ecc/sw-macros/src/lib.rs +++ b/extensions/ecc/sw-macros/src/lib.rs @@ -211,7 +211,7 @@ pub fn sw_declare(input: TokenStream) -> TokenStream { use openvm_algebra_guest::IntMod; // Safety: Self::set_up_once() ensures IntMod::set_up_once() has been called. unsafe { - self.x.eq_impl::(&#intmod_type::ZERO) && self.y.eq_impl::(&#intmod_type::ZERO) + self.x.eq_impl::(&<#intmod_type as IntMod>::ZERO) && self.y.eq_impl::(&<#intmod_type as IntMod>::ZERO) } } } @@ -355,7 +355,7 @@ pub fn sw_declare(input: TokenStream) -> TokenStream { } mod #group_ops_mod_name { - use ::openvm_ecc_guest::{weierstrass::{WeierstrassPoint, FromCompressed}, impl_sw_group_ops, algebra::IntMod}; + use ::openvm_ecc_guest::{weierstrass::{WeierstrassPoint}, FromCompressed, impl_sw_group_ops, algebra::IntMod}; use super::*; impl_sw_group_ops!(#struct_name, #intmod_type); diff --git a/extensions/ecc/te-macros/src/lib.rs b/extensions/ecc/te-macros/src/lib.rs index 11e1f6adc9..8a06fb13dd 100644 --- a/extensions/ecc/te-macros/src/lib.rs +++ b/extensions/ecc/te-macros/src/lib.rs @@ -8,15 +8,17 @@ use syn::{ parse_macro_input, Expr, ExprPath, Path, Token, }; -/// This macro generates the code to setup a Twisted Edwards elliptic curve for a given modular type. Also it places the curve parameters into a special static variable to be later extracted from the ELF and used by the VM. -/// Usage: +/// This macro generates the code to setup a Twisted Edwards elliptic curve for a given modular +/// type. Also it places the curve parameters into a special static variable to be later extracted +/// from the ELF and used by the VM. Usage: /// ``` /// te_declare! { /// [TODO] /// } /// ``` /// -/// For this macro to work, you must import the `elliptic_curve` crate and the `openvm_ecc_guest` crate.. +/// For this macro to work, you must import the `elliptic_curve` crate and the `openvm_ecc_guest` +/// crate.. #[proc_macro] pub fn te_declare(input: TokenStream) -> TokenStream { let MacroArgs { items } = parse_macro_input!(input as MacroArgs); @@ -202,125 +204,29 @@ pub fn te_declare(input: TokenStream) -> TokenStream { } mod #group_ops_mod_name { - use ::openvm_ecc_guest::{edwards::TwistedEdwardsPoint, FromCompressed, DecompressionHint, impl_te_group_ops, algebra::{IntMod, DivUnsafe, DivAssignUnsafe, ExpBytes}}; + use ::openvm_ecc_guest::{edwards::TwistedEdwardsPoint, FromCompressed, impl_te_group_ops, algebra::{IntMod, DivUnsafe, DivAssignUnsafe, ExpBytes}}; use super::*; impl_te_group_ops!(#struct_name, #intmod_type); impl FromCompressed<#intmod_type> for #struct_name { fn decompress(y: #intmod_type, rec_id: &u8) -> Option { - match Self::honest_host_decompress(&y, rec_id) { - // successfully decompressed - Some(Some(ret)) => Some(ret), - // successfully proved that the point cannot be decompressed - Some(None) => None, - None => { - // host is dishonest, enter infinite loop - loop { - openvm::io::println("ERROR: Decompression hint is invalid. Entering infinite loop."); - } - } - } - } - - fn hint_decompress(y: &#intmod_type, rec_id: &u8) -> Option> { - #[cfg(not(target_os = "zkvm"))] - { - unimplemented!() - } - #[cfg(target_os = "zkvm")] - { - use openvm::platform as openvm_platform; // needed for hint_buffer_u32! - - let possible = core::mem::MaybeUninit::::uninit(); - let sqrt = core::mem::MaybeUninit::<#intmod_type>::uninit(); - unsafe { - #te_hint_decompress_extern_func(y as *const _ as usize, rec_id as *const u8 as usize); - let possible_ptr = possible.as_ptr() as *const u32; - openvm_rv32im_guest::hint_store_u32!(possible_ptr); - openvm_rv32im_guest::hint_buffer_u32!(sqrt.as_ptr() as *const u8, <#intmod_type as openvm_algebra_guest::IntMod>::NUM_LIMBS / 4); - let possible = possible.assume_init(); - if possible == 0 || possible == 1 { - Some(DecompressionHint { possible: possible == 1, sqrt: sqrt.assume_init() }) + use openvm_algebra_guest::{Sqrt, DivUnsafe}; + let x_squared = (<#intmod_type as openvm_algebra_guest::IntMod>::ONE - &y * &y).div_unsafe(<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_A - &<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_D * &y * &y); + let x = x_squared.sqrt(); + match x { + None => None, + Some(x) => { + let correct_x = if x.as_le_bytes()[0] & 1 == *rec_id & 1 { + x } else { - None - } - } - } - } - } - - impl #struct_name { - // Returns None if the hint is incorrect (i.e. the host is dishonest) - // Returns Some(None) if the hint proves that the point cannot be decompressed - fn honest_host_decompress(y: &#intmod_type, rec_id: &u8) -> Option> { - let hint = <#struct_name as FromCompressed<#intmod_type>>::hint_decompress(y, rec_id)?; - - if hint.possible { - // ensure x < modulus - hint.sqrt.assert_reduced(); - - if hint.sqrt.as_le_bytes()[0] & 1 != *rec_id & 1 { - None - } else { - let ret = <#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::from_xy(hint.sqrt, y.clone())?; - Some(Some(ret)) + -x + }; + // In order for sqrt() to return Some, we are guaranteed that x * x == x_squared, which already proves (correct_x, y) is on the curve + Some(<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::from_xy_unchecked(correct_x, y)) } - } else { - // ensure sqrt < modulus - hint.sqrt.assert_reduced(); - - let lhs = (&hint.sqrt * &hint.sqrt) * (&<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_D * y * y - &<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_A); - let rhs = y * y - &<#intmod_type as openvm_algebra_guest::IntMod>::ONE; - if lhs == rhs * Self::get_non_qr() { - Some(None) - } else { - None - } - } - } - - // Generate a non quadratic residue in the coordinate field by using a hint - fn init_non_qr() -> alloc::boxed::Box<::Coordinate> { - #[cfg(not(target_os = "zkvm"))] - { - unimplemented!(); - } - #[cfg(target_os = "zkvm")] - { - use openvm_algebra_guest::DivUnsafe; - use openvm::platform as openvm_platform; // needed for hint_buffer_u32 - let mut non_qr_uninit = core::mem::MaybeUninit::<#intmod_type>::uninit(); - let mut non_qr; - unsafe { - #hint_non_qr_extern_func(); - let ptr = non_qr_uninit.as_ptr() as *const u8; - openvm_rv32im_guest::hint_buffer_u32!(ptr, <#intmod_type as openvm_algebra_guest::IntMod>::NUM_LIMBS / 4); - non_qr = non_qr_uninit.assume_init(); - } - // ensure non_qr < modulus - non_qr.assert_reduced(); - - // construct exp = (p-1)/2 as an integer by first constraining exp = (p-1)/2 (mod p) and then exp < p - let exp = -<#intmod_type as openvm_algebra_guest::IntMod>::ONE.div_unsafe(#intmod_type::from_const_u8(2)); - exp.assert_reduced(); - - if non_qr.exp_bytes(true, &exp.to_be_bytes()) != -<#intmod_type as openvm_algebra_guest::IntMod>::ONE - { - // non_qr is not a non quadratic residue, so host is dishonest - loop { - openvm::io::println("ERROR: Non quadratic residue hint is invalid. Entering infinite loop."); - } - } - - alloc::boxed::Box::new(non_qr) } } - - pub fn get_non_qr() -> &'static #intmod_type { - static non_qr: ::openvm_ecc_guest::once_cell::race::OnceBox<#intmod_type> = ::openvm_ecc_guest::once_cell::race::OnceBox::new(); - &non_qr.get_or_init(Self::init_non_qr) - } } } }); diff --git a/extensions/ecc/tests/Cargo.toml b/extensions/ecc/tests/Cargo.toml index bcdaf6f539..b2283663be 100644 --- a/extensions/ecc/tests/Cargo.toml +++ b/extensions/ecc/tests/Cargo.toml @@ -13,6 +13,7 @@ openvm-circuit = { workspace = true, features = ["test-utils"] } openvm-transpiler.workspace = true openvm-algebra-circuit.workspace = true openvm-algebra-transpiler.workspace = true +openvm-ecc-guest.workspace = true openvm-ecc-transpiler.workspace = true openvm-ecc-circuit.workspace = true openvm-rv32im-transpiler.workspace = true @@ -22,7 +23,6 @@ openvm-sdk.workspace = true eyre.workspace = true num-bigint.workspace = true hex-literal.workspace = true -num-bigint.workspace = true halo2curves-axiom = { workspace = true } [features] diff --git a/extensions/ecc/tests/programs/examples/decompress.rs b/extensions/ecc/tests/programs/examples/decompress.rs index 498be5c66f..2099a4ccf6 100644 --- a/extensions/ecc/tests/programs/examples/decompress.rs +++ b/extensions/ecc/tests/programs/examples/decompress.rs @@ -10,7 +10,6 @@ use openvm_ecc_guest::{ algebra::{DivUnsafe, Field, IntMod}, ed25519::{Ed25519Coord, Ed25519Point}, edwards::TwistedEdwardsPoint, - k256::{Secp256k1Coord, Secp256k1Point}, weierstrass::WeierstrassPoint, FromCompressed, Group, }; @@ -101,13 +100,6 @@ fn test_possible_te_decompression Result<()> { - let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone()], vec![]); let elf = build_example_program_at_path_with_features( get_programs_dir!(), "ec", @@ -53,7 +53,7 @@ mod tests { #[test] fn test_ec_nonzero_a() -> Result<()> { - let config = Rv32EccConfig::new(vec![P256_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![P256_CONFIG.clone()], vec![]); let elf = build_example_program_at_path_with_features( get_programs_dir!(), "ec_nonzero_a", @@ -75,7 +75,8 @@ mod tests { #[test] fn test_ec_two_curves() -> Result<()> { - let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone(), P256_CONFIG.clone()]); + let config = + Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone(), P256_CONFIG.clone()], vec![]); let elf = build_example_program_at_path_with_features( get_programs_dir!(), "ec_two_curves", @@ -97,10 +98,7 @@ mod tests { #[test] fn test_decompress() -> Result<()> { - use ed25519::Ed25519Point; - use edwards::TwistedEdwardsPoint; use halo2curves_axiom::{ed25519::Ed25519Affine, group::Curve, secp256k1::Secp256k1Affine}; - use openvm_algebra_guest::IntMod; let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone(), @@ -131,9 +129,26 @@ mod tests { }, ], vec![ED25519_CONFIG.clone()]); - let p1 = Secp256k1Affine::generator(); - let p1 = (p1 + p1 + p1).to_affine(); - println!("secp256k1 decompressed: {:?}", p1); + let elf = build_example_program_at_path_with_features( + get_programs_dir!(), + "decompress", + ["k256", "ed25519"], + &config, + )?; + + let openvm_exe = VmExe::from_elf( + elf, + Transpiler::::default() + .with_extension(Rv32ITranspilerExtension) + .with_extension(Rv32MTranspilerExtension) + .with_extension(Rv32IoTranspilerExtension) + .with_extension(EccTranspilerExtension) + .with_extension(ModularTranspilerExtension), + )?; + + let p = Secp256k1Affine::generator(); + let p = (p + p + p).to_affine(); + println!("secp256k1 decompressed: {:?}", p); let q_x: [u8; 32] = hex!("0100000000000000000000000000000000000000000000000000000000000000"); let q_y: [u8; 32] = @@ -201,10 +216,12 @@ mod tests { #[test] fn test_edwards_ec() -> Result<()> { + let config = Rv32EccConfig::new(vec![], vec![ED25519_CONFIG.clone()]); let elf = build_example_program_at_path_with_features::<&str>( get_programs_dir!(), "edwards_ec", ["ed25519"], + &config, )?; let openvm_exe = VmExe::from_elf( elf, @@ -215,7 +232,6 @@ mod tests { .with_extension(EccTranspilerExtension) .with_extension(ModularTranspilerExtension), )?; - let config = Rv32EccConfig::new(vec![], vec![ED25519_CONFIG.clone()]); air_test(config, openvm_exe); Ok(()) } diff --git a/extensions/pairing/circuit/src/config.rs b/extensions/pairing/circuit/src/config.rs index 46e17dfc0f..3958eeddb2 100644 --- a/extensions/pairing/circuit/src/config.rs +++ b/extensions/pairing/circuit/src/config.rs @@ -23,7 +23,7 @@ pub struct Rv32PairingConfig { #[extension] pub fp2: Fp2Extension, #[extension] - pub weierstrass: EccExtension, + pub ecc: EccExtension, #[extension] pub pairing: PairingExtension, } @@ -48,10 +48,7 @@ impl Rv32PairingConfig { .zip(modulus_primes) .collect(), ), - weierstrass: EccExtension::new( - curves.iter().map(|c| c.curve_config()).collect(), - vec![], - ), + ecc: EccExtension::new(curves.iter().map(|c| c.curve_config()).collect(), vec![]), pairing: PairingExtension::new(curves), } } @@ -63,7 +60,7 @@ impl InitFileGenerator for Rv32PairingConfig { "// This file is automatically generated by cargo openvm. Do not rename or edit.\n{}\n{}\n{}\n", self.modular.generate_moduli_init(), self.fp2.generate_complex_init(&self.modular), - self.weierstrass.generate_sw_init() + self.ecc.generate_ecc_init() )) } } diff --git a/guest-libs/k256/src/point.rs b/guest-libs/k256/src/point.rs index 922457b8a4..117b2f9b28 100644 --- a/guest-libs/k256/src/point.rs +++ b/guest-libs/k256/src/point.rs @@ -14,10 +14,7 @@ use elliptic_curve::{ FieldBytesEncoding, }; use openvm_algebra_guest::IntMod; -use openvm_ecc_guest::{ - weierstrass::{IntrinsicCurve, WeierstrassPoint}, - CyclicGroup, -}; +use openvm_ecc_guest::{weierstrass::WeierstrassPoint, CyclicGroup, IntrinsicCurve}; use crate::{ internal::{Secp256k1Coord, Secp256k1Point, Secp256k1Scalar}, @@ -181,7 +178,7 @@ impl MulByGenerator for Secp256k1Point {} impl DecompressPoint for Secp256k1Point { /// Note that this is not constant time fn decompress(x_bytes: &FieldBytes, y_is_odd: Choice) -> CtOption { - use openvm_ecc_guest::weierstrass::FromCompressed; + use openvm_ecc_guest::FromCompressed; let x = Secp256k1Coord::from_be_bytes(x_bytes.as_slice()); let rec_id = y_is_odd.unwrap_u8(); diff --git a/guest-libs/k256/tests/lib.rs b/guest-libs/k256/tests/lib.rs index d55cdba60c..26cadc3aea 100644 --- a/guest-libs/k256/tests/lib.rs +++ b/guest-libs/k256/tests/lib.rs @@ -3,7 +3,7 @@ mod guest_tests { use eyre::Result; use openvm_algebra_transpiler::ModularTranspilerExtension; use openvm_circuit::{arch::instructions::exe::VmExe, utils::air_test}; - use openvm_ecc_circuit::{Rv32WeierstrassConfig, SECP256K1_CONFIG}; + use openvm_ecc_circuit::{Rv32EccConfig, SECP256K1_CONFIG}; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_rv32im_transpiler::{ Rv32ITranspilerExtension, Rv32IoTranspilerExtension, Rv32MTranspilerExtension, @@ -17,7 +17,7 @@ mod guest_tests { #[test] fn test_add() -> Result<()> { - let config = Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone()], vec![]); let elf = build_example_program_at_path(get_programs_dir!("tests/programs"), "add", &config)?; let openvm_exe = VmExe::from_elf( @@ -35,7 +35,7 @@ mod guest_tests { #[test] fn test_mul() -> Result<()> { - let config = Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone()], vec![]); let elf = build_example_program_at_path(get_programs_dir!("tests/programs"), "mul", &config)?; let openvm_exe = VmExe::from_elf( @@ -53,7 +53,7 @@ mod guest_tests { #[test] fn test_linear_combination() -> Result<()> { - let config = Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone()], vec![]); let elf = build_example_program_at_path( get_programs_dir!("tests/programs"), "linear_combination", @@ -82,8 +82,7 @@ mod guest_tests { derive::VmConfig, }; use openvm_ecc_circuit::{ - CurveConfig, WeierstrassExtension, WeierstrassExtensionExecutor, - WeierstrassExtensionPeriphery, + CurveConfig, EccExtension, EccExtensionExecutor, EccExtensionPeriphery, SwCurveCoeffs, }; use openvm_rv32im_circuit::{ Rv32I, Rv32IExecutor, Rv32IPeriphery, Rv32Io, Rv32IoExecutor, Rv32IoPeriphery, Rv32M, @@ -106,13 +105,13 @@ mod guest_tests { #[extension] pub modular: ModularExtension, #[extension] - pub weierstrass: WeierstrassExtension, + pub ecc: EccExtension, #[extension] pub sha256: Sha256, } impl EcdsaConfig { - pub fn new(curves: Vec) -> Self { + pub fn new(curves: Vec>) -> Self { let primes: Vec<_> = curves .iter() .flat_map(|c| [c.modulus.clone(), c.scalar.clone()]) @@ -123,7 +122,7 @@ mod guest_tests { mul: Default::default(), io: Default::default(), modular: ModularExtension::new(primes), - weierstrass: WeierstrassExtension::new(curves), + ecc: EccExtension::new(curves, vec![]), sha256: Default::default(), } } @@ -134,7 +133,7 @@ mod guest_tests { Some(format!( "// This file is automatically generated by cargo openvm. Do not rename or edit.\n{}\n{}\n", self.modular.generate_moduli_init(), - self.weierstrass.generate_sw_init() + self.ecc.generate_ecc_init() )) } } @@ -162,7 +161,7 @@ mod guest_tests { #[test] fn test_scalar_sqrt() -> Result<()> { - let config = Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone()], vec![]); let elf = build_example_program_at_path( get_programs_dir!("tests/programs"), "scalar_sqrt", diff --git a/guest-libs/p256/src/point.rs b/guest-libs/p256/src/point.rs index 83e061bdb7..78c4ea8a60 100644 --- a/guest-libs/p256/src/point.rs +++ b/guest-libs/p256/src/point.rs @@ -14,10 +14,7 @@ use elliptic_curve::{ FieldBytesEncoding, }; use openvm_algebra_guest::IntMod; -use openvm_ecc_guest::{ - weierstrass::{IntrinsicCurve, WeierstrassPoint}, - CyclicGroup, -}; +use openvm_ecc_guest::{weierstrass::WeierstrassPoint, CyclicGroup, IntrinsicCurve}; use crate::{ internal::{P256Coord, P256Point, P256Scalar}, @@ -177,7 +174,7 @@ impl MulByGenerator for P256Point {} impl DecompressPoint for P256Point { /// Note that this is not constant time fn decompress(x_bytes: &FieldBytes, y_is_odd: Choice) -> CtOption { - use openvm_ecc_guest::weierstrass::FromCompressed; + use openvm_ecc_guest::FromCompressed; let x = P256Coord::from_be_bytes(x_bytes.as_slice()); let rec_id = y_is_odd.unwrap_u8(); diff --git a/guest-libs/p256/tests/lib.rs b/guest-libs/p256/tests/lib.rs index 8be2c34850..c689e8c261 100644 --- a/guest-libs/p256/tests/lib.rs +++ b/guest-libs/p256/tests/lib.rs @@ -3,7 +3,7 @@ mod guest_tests { use eyre::Result; use openvm_algebra_transpiler::ModularTranspilerExtension; use openvm_circuit::{arch::instructions::exe::VmExe, utils::air_test}; - use openvm_ecc_circuit::{Rv32WeierstrassConfig, P256_CONFIG}; + use openvm_ecc_circuit::{Rv32EccConfig, P256_CONFIG}; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_rv32im_transpiler::{ Rv32ITranspilerExtension, Rv32IoTranspilerExtension, Rv32MTranspilerExtension, @@ -17,7 +17,7 @@ mod guest_tests { #[test] fn test_add() -> Result<()> { - let config = Rv32WeierstrassConfig::new(vec![P256_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![P256_CONFIG.clone()], vec![]); let elf = build_example_program_at_path(get_programs_dir!("tests/programs"), "add", &config)?; let openvm_exe = VmExe::from_elf( @@ -35,7 +35,7 @@ mod guest_tests { #[test] fn test_mul() -> Result<()> { - let config = Rv32WeierstrassConfig::new(vec![P256_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![P256_CONFIG.clone()], vec![]); let elf = build_example_program_at_path(get_programs_dir!("tests/programs"), "mul", &config)?; let openvm_exe = VmExe::from_elf( @@ -53,7 +53,7 @@ mod guest_tests { #[test] fn test_linear_combination() -> Result<()> { - let config = Rv32WeierstrassConfig::new(vec![P256_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![P256_CONFIG.clone()], vec![]); let elf = build_example_program_at_path( get_programs_dir!("tests/programs"), "linear_combination", @@ -82,8 +82,7 @@ mod guest_tests { derive::VmConfig, }; use openvm_ecc_circuit::{ - CurveConfig, WeierstrassExtension, WeierstrassExtensionExecutor, - WeierstrassExtensionPeriphery, + CurveConfig, EccExtension, EccExtensionExecutor, EccExtensionPeriphery, SwCurveCoeffs, }; use openvm_rv32im_circuit::{ Rv32I, Rv32IExecutor, Rv32IPeriphery, Rv32Io, Rv32IoExecutor, Rv32IoPeriphery, Rv32M, @@ -106,13 +105,13 @@ mod guest_tests { #[extension] pub modular: ModularExtension, #[extension] - pub weierstrass: WeierstrassExtension, + pub ecc: EccExtension, #[extension] pub sha256: Sha256, } impl EcdsaConfig { - pub fn new(curves: Vec) -> Self { + pub fn new(curves: Vec>) -> Self { let primes: Vec<_> = curves .iter() .flat_map(|c| [c.modulus.clone(), c.scalar.clone()]) @@ -123,7 +122,7 @@ mod guest_tests { mul: Default::default(), io: Default::default(), modular: ModularExtension::new(primes), - weierstrass: WeierstrassExtension::new(curves), + ecc: EccExtension::new(curves, vec![]), sha256: Default::default(), } } @@ -134,7 +133,7 @@ mod guest_tests { Some(format!( "// This file is automatically generated by cargo openvm. Do not rename or edit.\n{}\n{}\n", self.modular.generate_moduli_init(), - self.weierstrass.generate_sw_init() + self.ecc.generate_ecc_init() )) } } @@ -162,7 +161,7 @@ mod guest_tests { #[test] fn test_scalar_sqrt() -> Result<()> { - let config = Rv32WeierstrassConfig::new(vec![P256_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![P256_CONFIG.clone()], vec![]); let elf = build_example_program_at_path( get_programs_dir!("tests/programs"), "scalar_sqrt", From 7aa8cbfe6e3559184fcf9155e3f0e6a33af1ffbd Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 15:42:45 -0400 Subject: [PATCH 40/57] Add lazy setup for edwards curves --- extensions/ecc/te-macros/src/lib.rs | 77 +++++++++-------------------- 1 file changed, 24 insertions(+), 53 deletions(-) diff --git a/extensions/ecc/te-macros/src/lib.rs b/extensions/ecc/te-macros/src/lib.rs index 8a06fb13dd..c7b49f329d 100644 --- a/extensions/ecc/te-macros/src/lib.rs +++ b/extensions/ecc/te-macros/src/lib.rs @@ -79,16 +79,14 @@ pub fn te_declare(input: TokenStream) -> TokenStream { }; } create_extern_func!(te_add_extern_func); - create_extern_func!(te_hint_decompress_extern_func); - create_extern_func!(hint_non_qr_extern_func); + create_extern_func!(te_setup_extern_func); let group_ops_mod_name = format_ident!("{}_ops", struct_name.to_string().to_lowercase()); let result = TokenStream::from(quote::quote_spanned! { span.into() => extern "C" { fn #te_add_extern_func(rd: usize, rs1: usize, rs2: usize); - fn #te_hint_decompress_extern_func(rs1: usize, rs2: usize); - fn #hint_non_qr_extern_func(); + fn #te_setup_extern_func(); } #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] @@ -126,6 +124,7 @@ pub fn te_declare(input: TokenStream) -> TokenStream { } #[cfg(target_os = "zkvm")] { + Self::set_up_once(); let mut uninit: core::mem::MaybeUninit<#struct_name> = core::mem::MaybeUninit::uninit(); unsafe { #te_add_extern_func( @@ -137,6 +136,22 @@ pub fn te_declare(input: TokenStream) -> TokenStream { unsafe { uninit.assume_init() } } } + + // Helper function to call the setup instruction on first use + #[cfg(target_os = "zkvm")] + fn set_up_once() { + static is_setup: ::openvm_ecc_guest::once_cell::race::OnceBool = ::openvm_ecc_guest::once_cell::race::OnceBool::new(); + is_setup.get_or_init(|| { + unsafe { #te_setup_extern_func(); } + <#intmod_type as openvm_algebra_guest::IntMod>::set_up_once(); + true + }); + } + + #[cfg(not(target_os = "zkvm"))] + fn set_up_once() { + // No-op for non-ZKVM targets + } } impl ::openvm_ecc_guest::edwards::TwistedEdwardsPoint for #struct_name { @@ -263,8 +278,6 @@ pub fn te_init(input: TokenStream) -> TokenStream { let TeDefine { items } = parse_macro_input!(input as TeDefine); let mut externs = Vec::new(); - let mut setups = Vec::new(); - let mut setup_all_te_curves = Vec::new(); let span = proc_macro::Span::call_site(); @@ -277,14 +290,8 @@ pub fn te_init(input: TokenStream) -> TokenStream { .join("_"); let add_extern_func = syn::Ident::new(&format!("te_add_extern_func_{}", str_path), span.into()); - let te_hint_decompress_extern_func = syn::Ident::new( - &format!("te_hint_decompress_extern_func_{}", str_path), - span.into(), - ); - let hint_non_qr_extern_func = syn::Ident::new( - &format!("hint_non_qr_extern_func_{}", str_path), - span.into(), - ); + let setup_extern_func = + syn::Ident::new(&format!("te_setup_extern_func_{}", str_path), span.into()); externs.push(quote::quote_spanned! { span.into() => #[no_mangle] extern "C" fn #add_extern_func(rd: usize, rs1: usize, rs2: usize) { @@ -300,39 +307,10 @@ pub fn te_init(input: TokenStream) -> TokenStream { } #[no_mangle] - extern "C" fn #te_hint_decompress_extern_func(rs1: usize, rs2: usize) { - openvm::platform::custom_insn_r!( - opcode = TE_OPCODE, - funct3 = TE_FUNCT3 as usize, - funct7 = TeBaseFunct7::TeHintDecompress as usize + #ec_idx - * (TeBaseFunct7::TWISTED_EDWARDS_MAX_KINDS as usize), - rd = Const "x0", - rs1 = In rs1, - rs2 = In rs2 - ); - } - - #[no_mangle] - extern "C" fn #hint_non_qr_extern_func() { - openvm::platform::custom_insn_r!( - opcode = TE_OPCODE, - funct3 = TE_FUNCT3 as usize, - funct7 = TeBaseFunct7::TeHintNonQr as usize + #ec_idx - * (TeBaseFunct7::TWISTED_EDWARDS_MAX_KINDS as usize), - rd = Const "x0", - rs1 = Const "x0", - rs2 = Const "x0" - ); - } - }); - - let setup_function = syn::Ident::new(&format!("setup_te_{}", str_path), span.into()); - setups.push(quote::quote_spanned! { span.into() => - - #[allow(non_snake_case)] - pub fn #setup_function() { + extern "C" fn #setup_extern_func() { #[cfg(target_os = "zkvm")] { + use super::#item; let modulus_bytes = <<#item as openvm_ecc_guest::edwards::TwistedEdwardsPoint>::Coordinate as openvm_algebra_guest::IntMod>::MODULUS; let mut zero = [0u8; <<#item as openvm_ecc_guest::edwards::TwistedEdwardsPoint>::Coordinate as openvm_algebra_guest::IntMod>::NUM_LIMBS]; let curve_a_bytes = openvm_algebra_guest::IntMod::as_le_bytes(&<#item as openvm_ecc_guest::edwards::TwistedEdwardsPoint>::CURVE_A); @@ -353,22 +331,15 @@ pub fn te_init(input: TokenStream) -> TokenStream { } } }); - - setup_all_te_curves.push(quote::quote_spanned! { span.into() => - #setup_function(); - }); } TokenStream::from(quote::quote_spanned! { span.into() => + #[allow(non_snake_case)] #[cfg(target_os = "zkvm")] mod openvm_intrinsics_ffi_2_te { use ::openvm_ecc_guest::{TE_OPCODE, TE_FUNCT3, TeBaseFunct7}; #(#externs)* } - #(#setups)* - pub fn setup_all_te_curves() { - #(#setup_all_te_curves)* - } }) } From 02d07b6aa1dc9e7ce4d4080211756b6d663fd055 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 15:45:00 -0400 Subject: [PATCH 41/57] Delete commented code --- extensions/ecc/guest/src/ed25519.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs index e76e7bed04..18042a319c 100644 --- a/extensions/ecc/guest/src/ed25519.rs +++ b/extensions/ecc/guest/src/ed25519.rs @@ -67,18 +67,6 @@ impl CyclicGroup for Ed25519Point { }; } -/* -impl IntrinsicCurve for Ed25519Point { - type Scalar = Ed25519Scalar; - type Point = Ed25519Point; - - fn msm(coeffs: &[Self::Scalar], bases: &[Self::Point]) -> Self::Point { - // TODO: idk if this can be optimized - openvm_ecc_guest::msm(coeffs, bases) - } -} -*/ - impl IntrinsicCurve for Ed25519Point { type Scalar = Ed25519Scalar; type Point = Ed25519Point; From 9a694076d88a66284b2bc46c22543ca367935c3c Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 15:54:09 -0400 Subject: [PATCH 42/57] Add a bunch of #[inline(always)] for te curves --- extensions/ecc/guest/src/edwards.rs | 15 ++++++++------- extensions/ecc/te-macros/src/lib.rs | 10 ++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/extensions/ecc/guest/src/edwards.rs b/extensions/ecc/guest/src/edwards.rs index 88ffc9c084..fd313881b9 100644 --- a/extensions/ecc/guest/src/edwards.rs +++ b/extensions/ecc/guest/src/edwards.rs @@ -31,6 +31,7 @@ pub trait TwistedEdwardsPoint: Sized { fn add_impl(&self, p2: &Self) -> Self; + #[inline(always)] fn from_xy(x: Self::Coordinate, y: Self::Coordinate) -> Option where for<'a> &'a Self::Coordinate: Mul<&'a Self::Coordinate, Output = Self::Coordinate>, @@ -45,15 +46,15 @@ pub trait TwistedEdwardsPoint: Sized { } /// Macro to generate a newtype wrapper for [AffinePoint](crate::AffinePoint) -/// that implements elliptic curve operations by using the underlying field operations according to the -/// [formulas](https://en.wikipedia.org/wiki/Twisted_Edwards_curve) for twisted Edwards curves. +/// that implements elliptic curve operations by using the underlying field operations according to +/// the [formulas](https://en.wikipedia.org/wiki/Twisted_Edwards_curve) for twisted Edwards curves. /// /// The following imports are required: /// ```rust /// use core::ops::AddAssign; /// /// use openvm_algebra_guest::{DivUnsafe, Field}; -/// use openvm_ecc_guest::{AffinePoint, Group, edwards::TwistedEdwardsPoint}; +/// use openvm_ecc_guest::{edwards::TwistedEdwardsPoint, AffinePoint, Group}; /// ``` #[macro_export] macro_rules! impl_te_affine { @@ -148,8 +149,8 @@ macro_rules! impl_te_affine { } } -/// Implements `Group` on `$struct_name` assuming that `$struct_name` implements `TwistedEdwardsPoint`. -/// Assumes that `Neg` is implemented for `&$struct_name`. +/// Implements `Group` on `$struct_name` assuming that `$struct_name` implements +/// `TwistedEdwardsPoint`. Assumes that `Neg` is implemented for `&$struct_name`. #[macro_export] macro_rules! impl_te_group_ops { ($struct_name:ident, $field:ty) => { @@ -273,8 +274,8 @@ macro_rules! impl_te_group_ops { // This is the same as the Weierstrass version, but for Edwards curves we use // TwistedEdwardsPoint::add_impl instead of WeierstrassPoint::add_ne_nonidentity, etc. -// Unlike the Weierstrass version, we do not require the bases to have prime order, since our addition -// formulas are complete. +// Unlike the Weierstrass version, we do not require the bases to have prime order, since our +// addition formulas are complete. // MSM using preprocessed table (windowed method) // Reference: modified from https://github.com/arkworks-rs/algebra/blob/master/ec/src/scalar_mul/mod.rs diff --git a/extensions/ecc/te-macros/src/lib.rs b/extensions/ecc/te-macros/src/lib.rs index c7b49f329d..55b720fd13 100644 --- a/extensions/ecc/te-macros/src/lib.rs +++ b/extensions/ecc/te-macros/src/lib.rs @@ -139,6 +139,7 @@ pub fn te_declare(input: TokenStream) -> TokenStream { // Helper function to call the setup instruction on first use #[cfg(target_os = "zkvm")] + #[inline(always)] fn set_up_once() { static is_setup: ::openvm_ecc_guest::once_cell::race::OnceBool = ::openvm_ecc_guest::once_cell::race::OnceBool::new(); is_setup.get_or_init(|| { @@ -149,6 +150,7 @@ pub fn te_declare(input: TokenStream) -> TokenStream { } #[cfg(not(target_os = "zkvm"))] + #[inline(always)] fn set_up_once() { // No-op for non-ZKVM targets } @@ -163,34 +165,42 @@ pub fn te_declare(input: TokenStream) -> TokenStream { /// SAFETY: assumes that #intmod_type has a memory representation /// such that with repr(C), two coordinates are packed contiguously. + #[inline(always)] fn as_le_bytes(&self) -> &[u8] { unsafe { &*core::ptr::slice_from_raw_parts(self as *const Self as *const u8, <#intmod_type as openvm_algebra_guest::IntMod>::NUM_LIMBS * 2) } } + #[inline(always)] fn from_xy_unchecked(x: Self::Coordinate, y: Self::Coordinate) -> Self { Self { x, y } } + #[inline(always)] fn x(&self) -> &Self::Coordinate { &self.x } + #[inline(always)] fn y(&self) -> &Self::Coordinate { &self.y } + #[inline(always)] fn x_mut(&mut self) -> &mut Self::Coordinate { &mut self.x } + #[inline(always)] fn y_mut(&mut self) -> &mut Self::Coordinate { &mut self.y } + #[inline(always)] fn into_coords(self) -> (Self::Coordinate, Self::Coordinate) { (self.x, self.y) } + #[inline(always)] fn add_impl(&self, p2: &Self) -> Self { Self::add_chip(self, p2) } From 34fbcdaba692d466db1c14daa9d01e77ec54b514 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 17:09:27 -0400 Subject: [PATCH 43/57] Update comments on Group::is_identity impl --- extensions/ecc/guest/src/edwards.rs | 10 ++++++++++ extensions/ecc/guest/src/weierstrass.rs | 10 +++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/extensions/ecc/guest/src/edwards.rs b/extensions/ecc/guest/src/edwards.rs index fd313881b9..e9089e49d8 100644 --- a/extensions/ecc/guest/src/edwards.rs +++ b/extensions/ecc/guest/src/edwards.rs @@ -172,6 +172,16 @@ macro_rules! impl_te_group_ops { *self = self.add_impl(self) } } + + // Note: It was found that implementing `is_identity` in group.rs as a default + // implementation increases the cycle count by 50% on the ecrecover benchmark. For + // this reason, we implement it here instead. We hypothesize that this is due to + // compiler optimizations that are not possible when the `is_identity` function is + // defined in a different source file. + #[inline(always)] + fn is_identity(&self) -> bool { + self == &::IDENTITY + } } impl core::ops::Add<&$struct_name> for $struct_name { diff --git a/extensions/ecc/guest/src/weierstrass.rs b/extensions/ecc/guest/src/weierstrass.rs index bbf591f4a2..3c39cbcfe6 100644 --- a/extensions/ecc/guest/src/weierstrass.rs +++ b/extensions/ecc/guest/src/weierstrass.rs @@ -451,11 +451,11 @@ macro_rules! impl_sw_group_ops { self.double_assign_impl::(); } - // This implementation is the same as the default implementation in the `Group` trait, - // but it was found that overriding the default implementation reduced the cycle count - // by 50% on the ecrecover benchmark. - // We hypothesize that this is due to compiler optimizations that are not possible when - // the `is_identity` function is defined in a different source file. + // Note: It was found that implementing `is_identity` in group.rs as a default + // implementation increases the cycle count by 50% on the ecrecover benchmark. For + // this reason, we implement it here instead. We hypothesize that this is due to + // compiler optimizations that are not possible when the `is_identity` function is + // defined in a different source file. #[inline(always)] fn is_identity(&self) -> bool { self == &::IDENTITY From cf9e909bc77a469cce1d4e98162cfa174744965b Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 17:12:42 -0400 Subject: [PATCH 44/57] Add missing dep --- Cargo.lock | 1 + extensions/ecc/circuit/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 0c498ee962..323bdafb0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5204,6 +5204,7 @@ dependencies = [ "hex-literal 0.4.1", "lazy_static", "num-bigint 0.4.6", + "num-integer", "num-traits", "once_cell", "openvm-algebra-circuit", diff --git a/extensions/ecc/circuit/Cargo.toml b/extensions/ecc/circuit/Cargo.toml index e85a9ed353..8d282933bf 100644 --- a/extensions/ecc/circuit/Cargo.toml +++ b/extensions/ecc/circuit/Cargo.toml @@ -22,6 +22,7 @@ openvm-ecc-transpiler = { workspace = true } openvm-ecc-guest = { workspace = true, features = ["ed25519"] } num-bigint = { workspace = true } +num-integer = { workspace = true } num-traits = { workspace = true } strum = { workspace = true } derive_more = { workspace = true } From e1f69d0dafbbdb423d900e5942d6ebc35597dd05 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 17:39:41 -0400 Subject: [PATCH 45/57] Fix bugs --- guest-libs/pairing/src/bls12_381/mod.rs | 2 +- guest-libs/pairing/src/bn254/mod.rs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/guest-libs/pairing/src/bls12_381/mod.rs b/guest-libs/pairing/src/bls12_381/mod.rs index 0a7c150e1c..d3557ba61a 100644 --- a/guest-libs/pairing/src/bls12_381/mod.rs +++ b/guest-libs/pairing/src/bls12_381/mod.rs @@ -4,7 +4,7 @@ use core::ops::Neg; use openvm_algebra_guest::IntMod; use openvm_algebra_moduli_macros::moduli_declare; -use openvm_ecc_guest::{weierstrass::IntrinsicCurve, CyclicGroup, Group}; +use openvm_ecc_guest::{CyclicGroup, Group, IntrinsicCurve}; mod fp12; mod fp2; diff --git a/guest-libs/pairing/src/bn254/mod.rs b/guest-libs/pairing/src/bn254/mod.rs index 8384b8b3e8..a8d3f99f68 100644 --- a/guest-libs/pairing/src/bn254/mod.rs +++ b/guest-libs/pairing/src/bn254/mod.rs @@ -5,10 +5,7 @@ use core::ops::{Add, Neg}; use hex_literal::hex; use openvm_algebra_guest::IntMod; use openvm_algebra_moduli_macros::moduli_declare; -use openvm_ecc_guest::{ - weierstrass::{CachedMulTable, IntrinsicCurve}, - CyclicGroup, Group, -}; +use openvm_ecc_guest::{weierstrass::CachedMulTable, CyclicGroup, Group, IntrinsicCurve}; use openvm_ecc_sw_macros::sw_declare; use openvm_pairing_guest::pairing::PairingIntrinsics; From ba8fb349e516591fe6cff5f10d46cae4175fe4ed Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 17:43:32 -0400 Subject: [PATCH 46/57] Update ecc example --- examples/ecc/Cargo.toml | 2 +- examples/ecc/openvm.toml | 1 + examples/ecc/openvm_init.rs | 3 +- examples/ecc/src/main.rs | 75 +++++++------------------------------ 4 files changed, 17 insertions(+), 64 deletions(-) diff --git a/examples/ecc/Cargo.toml b/examples/ecc/Cargo.toml index c25809a41b..0206cba6a0 100644 --- a/examples/ecc/Cargo.toml +++ b/examples/ecc/Cargo.toml @@ -11,7 +11,7 @@ openvm = { git = "https://github.com/openvm-org/openvm.git", features = [ "std", ] } openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git" } -openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git" } +openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git", features = ["ed25519"]} openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", package = "k256" } hex-literal = { version = "0.4.1", default-features = false } serde = { version = "1.0", default-features = false, features = [ "derive" ] } diff --git a/examples/ecc/openvm.toml b/examples/ecc/openvm.toml index e23efc9d5f..db8e420efc 100644 --- a/examples/ecc/openvm.toml +++ b/examples/ecc/openvm.toml @@ -14,6 +14,7 @@ a = "0" b = "7" [[app_vm_config.ecc.supported_te_curves]] +struct_name = "Ed25519Point" modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" scalar = "7237005577332262213973186563042994240857116359379907606001950938285454250989" diff --git a/examples/ecc/openvm_init.rs b/examples/ecc/openvm_init.rs index bec9f527e9..eb3bca4373 100644 --- a/examples/ecc/openvm_init.rs +++ b/examples/ecc/openvm_init.rs @@ -1,3 +1,4 @@ // This file is automatically generated by cargo openvm. Do not rename or edit. -openvm_algebra_guest::moduli_macros::moduli_init! { "115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337" } +openvm_algebra_guest::moduli_macros::moduli_init! { "115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337", "57896044618658097711785492504343953926634992332820282019728792003956564819949" } openvm_ecc_guest::sw_macros::sw_init! { Secp256k1Point } +openvm_ecc_guest::te_macros::te_init! { Ed25519Point } diff --git a/examples/ecc/src/main.rs b/examples/ecc/src/main.rs index 2cfd9d99f7..dc6bb8abbf 100644 --- a/examples/ecc/src/main.rs +++ b/examples/ecc/src/main.rs @@ -1,72 +1,23 @@ // ANCHOR: imports use hex_literal::hex; -use openvm_algebra_guest::{Field, IntMod}; use openvm_ecc_guest::{ + algebra::IntMod, + ed25519::{Ed25519Coord, Ed25519Point}, edwards::TwistedEdwardsPoint, - weierstrass::WeierstrassPoint - Group, + weierstrass::WeierstrassPoint, }; use openvm_k256::{Secp256k1Coord, Secp256k1Point}; // ANCHOR_END: imports -openvm_algebra_guest::moduli_macros::moduli_declare! { - // The Secp256k1 modulus and scalar field modulus are already declared in the k256 module - Edwards25519Coord { modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" }, -} // ANCHOR: init openvm::init!(); /* The init! macro will expand to the following openvm_algebra_guest::moduli_macros::moduli_init! { - "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F", - "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141", - "57896044618658097711785492504343953926634992332820282019728792003956564819949", -} - -// have to implement Field for Edwards25519Coord because moduli_declare! only implements IntMod -impl Field for Edwards25519Coord { - const ZERO: Self = ::ZERO; - const ONE: Self = ::ONE; - - type SelfRef<'a> = &'a Self; - - fn double_assign(&mut self) { - IntMod::double_assign(self); - } - - fn square_assign(&mut self) { - IntMod::square_assign(self); - } -} - -// a = 57896044618658097711785492504343953926634992332820282019728792003956564819948 -// d = 37095705934669439343138083508754565189542113879843219016388785533085940283555 -// encoded in little endian, 32 limbs of 8 bits each -const CURVE_A: Edwards25519Coord = Edwards25519Coord::from_const_bytes([ - 236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, -]); -const CURVE_D: Edwards25519Coord = Edwards25519Coord::from_const_bytes([ - 163, 120, 89, 19, 202, 77, 235, 117, 171, 216, 65, 65, 77, 10, 112, 0, 152, 232, 121, 119, 121, - 64, 199, 140, 115, 254, 111, 43, 238, 108, 3, 82, -]); - -// Note that we are defining the Edwards25519 curve for illustrative purposes only. -// In practice, we would use the ed25519 module which defines the Edwards25519 curve for us. -openvm_ecc_guest::te_macros::te_declare! { - Edwards25519Point { - mod_type = Edwards25519Coord, - a = CURVE_A, - d = CURVE_D - } -} - -openvm_ecc_guest::te_macros::te_init! { - Edwards25519Point, -} - -openvm_ecc_guest::sw_macros::sw_init! { - Secp256k1Point, +"115792089237316195423570985008687907853269984665640564039457584007908834671663", +"115792089237316195423570985008687907852837564279074904382605163141518161494337" } +openvm_ecc_guest::sw_macros::sw_init! { Secp256k1Point } +openvm_ecc_guest::te_macros::te_init! { Ed25519Point } */ // ANCHOR_END: init @@ -87,19 +38,19 @@ pub fn main() { #[allow(clippy::op_ref)] let _p3 = &p1 + &p2; - let x1 = Edwards25519Coord::from_be_bytes(&hex!( + let x1 = Ed25519Coord::from_be_bytes(&hex!( "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" )); - let y1 = Edwards25519Coord::from_be_bytes(&hex!( + let y1 = Ed25519Coord::from_be_bytes(&hex!( "6666666666666666666666666666666666666666666666666666666666666658" )); - let p1 = Edwards25519Point::from_xy(x1, y1).unwrap(); + let p1 = Ed25519Point::from_xy(x1, y1).unwrap(); - let x2 = Edwards25519Coord::from_u32(2); - let y2 = Edwards25519Coord::from_be_bytes(&hex!( + let x2 = Ed25519Coord::from_u32(2); + let y2 = Ed25519Coord::from_be_bytes(&hex!( "1A43BF127BDDC4D71FF910403C11DDB5BA2BCDD2815393924657EF111E712631" )); - let p2 = Edwards25519Point::from_xy(x2, y2).unwrap(); + let p2 = Ed25519Point::from_xy(x2, y2).unwrap(); #[allow(clippy::op_ref)] let _p3 = &p1 + &p2; From 9eb373c6231b63db85266c312d7f9e783ff0109f Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 17:45:07 -0400 Subject: [PATCH 47/57] Fix lint --- extensions/ecc/circuit/src/edwards_chip/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ecc/circuit/src/edwards_chip/mod.rs b/extensions/ecc/circuit/src/edwards_chip/mod.rs index 03c5e1253e..50347817af 100644 --- a/extensions/ecc/circuit/src/edwards_chip/mod.rs +++ b/extensions/ecc/circuit/src/edwards_chip/mod.rs @@ -21,8 +21,8 @@ use utils::jacobi; /// BLOCK_SIZE: how many cells do we read at a time, must be a power of 2. /// BLOCKS: how many blocks do we need to represent one input or output -/// For example, for bls12_381, BLOCK_SIZE = 16, each element has 3 blocks and with two elements per input AffinePoint, BLOCKS = 6. -/// For secp256k1, BLOCK_SIZE = 32, BLOCKS = 2. +/// For example, for bls12_381, BLOCK_SIZE = 16, each element has 3 blocks and with two elements per +/// input AffinePoint, BLOCKS = 6. For secp256k1, BLOCK_SIZE = 32, BLOCKS = 2. #[derive(Chip, ChipUsageGetter, InstructionExecutor)] pub struct TeAddChip( pub VmChipWrapper< From 652bf3c1d7a2150d63a613985335fe7a73bd63fa Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 17:55:31 -0400 Subject: [PATCH 48/57] Update ecc chip READMEs --- .../ecc/circuit/src/edwards_chip/README.md | 18 +++++++++++++++++- .../ecc/circuit/src/weierstrass_chip/README.md | 10 +++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/extensions/ecc/circuit/src/edwards_chip/README.md b/extensions/ecc/circuit/src/edwards_chip/README.md index 009fa95887..24167e062a 100644 --- a/extensions/ecc/circuit/src/edwards_chip/README.md +++ b/extensions/ecc/circuit/src/edwards_chip/README.md @@ -1 +1,17 @@ -Twisted Edwards (te) curve operations \ No newline at end of file +# Twisted Edwards (TE) curve operations + +The `te_add` instruction is implemented in the `edwards_chip` module. + +### 1. `te_add` + +**Assumptions:** + +- Both points `(x1, y1)` and `(x2, y2)` lie on the curve. + +**Circuit statements:** + +- The chip takes two inputs: `(x1, y1)` and `(x2, y2)`, and returns `(x3, y3)` where: + - `x3 = (x1 * y2 + x2 * y1) / (1 + d * x1 * x2 * y1 * y2)` + - `y3 = (y1 * y2 - a * x1 * x2) / (1 - d * x1 * x2 * y1 * y2)` + +- The `TeAddChip` constrains that these field expressions are computed correctly over the field `C::Fp`. The coefficients `a` and `d` are taken from the `CurveConfig`. diff --git a/extensions/ecc/circuit/src/weierstrass_chip/README.md b/extensions/ecc/circuit/src/weierstrass_chip/README.md index 94d8df6847..ba7119b0fc 100644 --- a/extensions/ecc/circuit/src/weierstrass_chip/README.md +++ b/extensions/ecc/circuit/src/weierstrass_chip/README.md @@ -1,8 +1,8 @@ # Short Weierstrass (SW) Curve Operations -The `ec_add_ne` and `ec_double` instructions are implemented in the `weierstrass_chip` module. +The `sw_add_ne` and `sw_double` instructions are implemented in the `weierstrass_chip` module. -### 1. `ec_add_ne` +### 1. `sw_add_ne` **Assumptions:** @@ -16,9 +16,9 @@ The `ec_add_ne` and `ec_double` instructions are implemented in the `weierstrass - `x3 = lambda^2 - x1 - x2` - `y3 = lambda * (x1 - x3) - y1` -- The `EcAddNeChip` constrains that these field expressions are computed correctly over the field `C::Fp`. +- The `SwAddNeChip` constrains that these field expressions are computed correctly over the field `C::Fp`. -### 2. `ec_double` +### 2. `sw_double` **Assumptions:** @@ -31,4 +31,4 @@ The `ec_add_ne` and `ec_double` instructions are implemented in the `weierstrass - `x3 = lambda^2 - 2 * x1` - `y3 = lambda * (x1 - x3) - y1` -- The `EcDoubleChip` constrains that these expressions are computed correctly over the field `C::Fp`. The coefficient `a` is taken from the `CurveConfig`. +- The `SwDoubleChip` constrains that these expressions are computed correctly over the field `C::Fp`. The coefficient `a` is taken from the `CurveConfig`. From 021bb79aa3be42406aca40e785fe6e1048e2d7ad Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 17:58:01 -0400 Subject: [PATCH 49/57] Fix import path bugs in pairing guest lib --- guest-libs/pairing/tests/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/guest-libs/pairing/tests/lib.rs b/guest-libs/pairing/tests/lib.rs index 19cd7cfb15..98a6831a2b 100644 --- a/guest-libs/pairing/tests/lib.rs +++ b/guest-libs/pairing/tests/lib.rs @@ -15,7 +15,7 @@ mod bn254 { arch::SystemConfig, utils::{air_test, air_test_impl, air_test_with_min_segments}, }; - use openvm_ecc_circuit::{EccExtension, Rv32WeierstrassConfig}; + use openvm_ecc_circuit::{EccExtension, Rv32EccConfig}; use openvm_ecc_guest::{ algebra::{field::FieldExtension, IntMod}, AffinePoint, @@ -54,7 +54,7 @@ mod bn254 { io: Default::default(), modular: ModularExtension::new(primes.to_vec()), fp2: Fp2Extension::new(primes_with_names), - weierstrass: EccExtension::new(vec![], vec![]), + ecc: EccExtension::new(vec![], vec![]), pairing: PairingExtension::new(vec![PairingCurve::Bn254]), } } @@ -62,7 +62,7 @@ mod bn254 { #[test] fn test_bn_ec() -> Result<()> { let curve = PairingCurve::Bn254.curve_config(); - let config = Rv32WeierstrassConfig::new(vec![curve]); + let config = Rv32EccConfig::new(vec![curve], vec![]); let elf = build_example_program_at_path_with_features( get_programs_dir!("tests/programs"), "bn_ec", @@ -503,7 +503,7 @@ mod bls12_381 { io: Default::default(), modular: ModularExtension::new(primes.to_vec()), fp2: Fp2Extension::new(primes_with_names), - weierstrass: EccExtension::new(vec![], vec![]), + ecc: EccExtension::new(vec![], vec![]), pairing: PairingExtension::new(vec![PairingCurve::Bls12_381]), } } From 39e2547b28e1108bc74eb03cb217f1c97fb3aaa7 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 18:22:47 -0400 Subject: [PATCH 50/57] Minor change for clarity --- extensions/ecc/guest/src/ed25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs index 18042a319c..32f48cba58 100644 --- a/extensions/ecc/guest/src/ed25519.rs +++ b/extensions/ecc/guest/src/ed25519.rs @@ -8,7 +8,7 @@ use num_bigint::BigUint; use openvm_algebra_guest::IntMod; use super::group::{CyclicGroup, Group}; -use crate::{edwards::CachedMulTable, IntrinsicCurve}; +use crate::IntrinsicCurve; #[cfg(not(target_os = "zkvm"))] lazy_static! { @@ -76,7 +76,7 @@ impl IntrinsicCurve for Ed25519Point { for<'a> &'a Self::Point: Add<&'a Self::Point, Output = Self::Point>, { if coeffs.len() < 25 { - let table = CachedMulTable::::new(bases, 4); + let table = crate::edwards::CachedMulTable::::new(bases, 4); table.windowed_mul(coeffs) } else { crate::msm(coeffs, bases) From ba2814a273c67e49c75b8e9c6340ea6136cf696a Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 18:35:59 -0400 Subject: [PATCH 51/57] Update ecc sw-macro and te-macro READMEs --- extensions/ecc/sw-macros/README.md | 2 +- extensions/ecc/te-macros/README.md | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/extensions/ecc/sw-macros/README.md b/extensions/ecc/sw-macros/README.md index 71f8d553f4..fbb8989cd7 100644 --- a/extensions/ecc/sw-macros/README.md +++ b/extensions/ecc/sw-macros/README.md @@ -93,7 +93,7 @@ mod openvm_intrinsics_ffi_2 { 3. Again, if using the Rust bindings, then the `sw_setup_extern_func_*` function for every curve is automatically called on first use of any of the curve's intrinsics. -4. The order of the items in `sw_init!` **must match** the order of the moduli in the chip configuration -- more specifically, in the modular extension parameters (the order of `CurveConfig`s in `WeierstrassExtension::supported_curves`, which is usually defined with the whole `app_vm_config` in the `openvm.toml` file). +4. The order of the items in `sw_init!` **must match** the order of the moduli in the chip configuration -- more specifically, in the modular extension parameters (the order of `CurveConfig`s in `EccExtension::supported_sw_curves`, which is usually defined with the whole `app_vm_config` in the `openvm.toml` file). 5. Note that, due to the nature of function names, the name of the struct used in `sw_init!` must be the same as in `sw_declare!`. To illustrate, the following code will **fail** to compile: diff --git a/extensions/ecc/te-macros/README.md b/extensions/ecc/te-macros/README.md index 402b46ad06..6de5c50110 100644 --- a/extensions/ecc/te-macros/README.md +++ b/extensions/ecc/te-macros/README.md @@ -98,9 +98,9 @@ pub fn setup_all_te_curves() { } ``` -3. Again, the `setup` function for every used curve must be called before any other instructions for that curve. If all curves are used, one can call `setup_all_te_curves()` to setup all of them. +3. Again, if using the Rust bindings, then the `te_setup_extern_func_*` function for every curve is automatically called on first use of any of the curve's intrinsics. -4. The order of the items in `te_init!` **must match** the order of the moduli in the chip configuration -- more specifically, in the modular extension parameters (the order of `CurveConfig`s in `TwistedEdwardsExtension::supported_curves`, which is usually defined with the whole `app_vm_config` in the `openvm.toml` file). +4. The order of the items in `te_init!` **must match** the order of the moduli in the chip configuration -- more specifically, in the modular extension parameters (the order of `CurveConfig`s in `EccExtension::supported_te_curves`, which is usually defined with the whole `app_vm_config` in the `openvm.toml` file). 5. Note that, due to the nature of function names, the name of the struct used in `te_init!` must be the same as in `te_declare!`. To illustrate, the following code will **fail** to compile: @@ -119,3 +119,7 @@ te_init! { ``` The reason is that, for example, the function `sw_add_extern_func_Secp256k1Point` remains unimplemented, but we implement `sw_add_extern_func_Sw`. + +6. `cargo openvm build` will automatically generate a call to `te_init!` based on `openvm.toml`. +Note that `openvm.toml` must contain the name of each struct created by `te_declare!` as a string (in the example at the top of this document, its `"Ed25519Point"`). +The SDK also supports this feature. From d4beb7ee6d7a49ea543518d4b8d9d2a0441096e3 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Mon, 16 Jun 2025 18:37:22 -0400 Subject: [PATCH 52/57] Fix lint --- Cargo.lock | 1 - extensions/ecc/tests/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 323bdafb0e..6dbb2f23e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5260,7 +5260,6 @@ dependencies = [ "openvm-algebra-transpiler", "openvm-circuit", "openvm-ecc-circuit", - "openvm-ecc-guest", "openvm-ecc-transpiler", "openvm-keccak256-transpiler", "openvm-rv32im-transpiler", diff --git a/extensions/ecc/tests/Cargo.toml b/extensions/ecc/tests/Cargo.toml index b2283663be..e44cb130cb 100644 --- a/extensions/ecc/tests/Cargo.toml +++ b/extensions/ecc/tests/Cargo.toml @@ -13,7 +13,6 @@ openvm-circuit = { workspace = true, features = ["test-utils"] } openvm-transpiler.workspace = true openvm-algebra-circuit.workspace = true openvm-algebra-transpiler.workspace = true -openvm-ecc-guest.workspace = true openvm-ecc-transpiler.workspace = true openvm-ecc-circuit.workspace = true openvm-rv32im-transpiler.workspace = true From de5e835103527cae97ebdca3dd35187951a70b03 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Thu, 19 Jun 2025 18:36:09 -0400 Subject: [PATCH 53/57] fix: Handle decompression with x = 0 correctly --- extensions/ecc/te-macros/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extensions/ecc/te-macros/src/lib.rs b/extensions/ecc/te-macros/src/lib.rs index 55b720fd13..5b0b2fd106 100644 --- a/extensions/ecc/te-macros/src/lib.rs +++ b/extensions/ecc/te-macros/src/lib.rs @@ -247,6 +247,10 @@ pub fn te_declare(input: TokenStream) -> TokenStream { } else { -x }; + // handle the case where x = 0 + if correct_x.as_le_bytes()[0] & 1 != *rec_id & 1 { + return None; + } // In order for sqrt() to return Some, we are guaranteed that x * x == x_squared, which already proves (correct_x, y) is on the curve Some(<#struct_name as ::openvm_ecc_guest::edwards::TwistedEdwardsPoint>::from_xy_unchecked(correct_x, y)) } From 5a88dc6bed1df551631492d961247db916485b36 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Thu, 19 Jun 2025 19:25:49 -0400 Subject: [PATCH 54/57] Fix bad merge --- examples/ecc/src/main.rs | 6 +++--- extensions/ecc/tests/programs/Cargo.toml | 12 ------------ extensions/ecc/tests/programs/examples/decompress.rs | 4 ++-- extensions/ecc/tests/programs/examples/edwards_ec.rs | 10 +++++----- extensions/ecc/tests/src/lib.rs | 3 +-- 5 files changed, 11 insertions(+), 24 deletions(-) diff --git a/examples/ecc/src/main.rs b/examples/ecc/src/main.rs index a405e53476..7b903397db 100644 --- a/examples/ecc/src/main.rs +++ b/examples/ecc/src/main.rs @@ -38,16 +38,16 @@ pub fn main() { #[allow(clippy::op_ref)] let _p3 = &p1 + &p2; - let x1 = Ed25519Coord::from_be_bytes(&hex!( + let x1 = Ed25519Coord::from_be_bytes_unchecked(&hex!( "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" )); - let y1 = Ed25519Coord::from_be_bytes(&hex!( + let y1 = Ed25519Coord::from_be_bytes_unchecked(&hex!( "6666666666666666666666666666666666666666666666666666666666666658" )); let p1 = Ed25519Point::from_xy(x1, y1).unwrap(); let x2 = Ed25519Coord::from_u32(2); - let y2 = Ed25519Coord::from_be_bytes(&hex!( + let y2 = Ed25519Coord::from_be_bytes_unchecked(&hex!( "1A43BF127BDDC4D71FF910403C11DDB5BA2BCDD2815393924657EF111E712631" )); let p2 = Ed25519Point::from_xy(x2, y2).unwrap(); diff --git a/extensions/ecc/tests/programs/Cargo.toml b/extensions/ecc/tests/programs/Cargo.toml index fce74d5047..065dc404f2 100644 --- a/extensions/ecc/tests/programs/Cargo.toml +++ b/extensions/ecc/tests/programs/Cargo.toml @@ -83,18 +83,6 @@ required-features = ["k256"] name = "sec1_decode" required-features = ["k256"] -[[example]] -name = "ecdsa_recover_p256" -required-features = ["p256"] - -[[example]] -name = "ecdsa_recover_k256" -required-features = ["k256"] - -[[example]] -name = "sec1_decode" -required-features = ["k256"] - [[example]] name = "edwards_ec" required-features = ["ed25519"] diff --git a/extensions/ecc/tests/programs/examples/decompress.rs b/extensions/ecc/tests/programs/examples/decompress.rs index 7d645f574a..147c2cc2db 100644 --- a/extensions/ecc/tests/programs/examples/decompress.rs +++ b/extensions/ecc/tests/programs/examples/decompress.rs @@ -75,8 +75,8 @@ pub fn main() { test_impossible_sw_decompression::(&Fp1mod4::from_u8(1), rec_id); // ed25519 - let x = Ed25519Coord::from_le_bytes(&bytes[192..224]); - let y = Ed25519Coord::from_le_bytes(&bytes[224..256]); + let x = Ed25519Coord::from_le_bytes_unchecked(&bytes[192..224]); + let y = Ed25519Coord::from_le_bytes_unchecked(&bytes[224..256]); let rec_id = x.as_le_bytes()[0] & 1; test_possible_te_decompression::(&x, &y, rec_id); // y = 2 is not on the y-coordinate of any point on the Ed25519 curve diff --git a/extensions/ecc/tests/programs/examples/edwards_ec.rs b/extensions/ecc/tests/programs/examples/edwards_ec.rs index ccefb7656e..53214fb14a 100644 --- a/extensions/ecc/tests/programs/examples/edwards_ec.rs +++ b/extensions/ecc/tests/programs/examples/edwards_ec.rs @@ -27,24 +27,24 @@ pub fn main() { // random point on edwards25519 let x2 = Ed25519Coord::from_u32(2); - let y2 = Ed25519Coord::from_be_bytes(&hex!( + let y2 = Ed25519Coord::from_be_bytes_unchecked(&hex!( "1A43BF127BDDC4D71FF910403C11DDB5BA2BCDD2815393924657EF111E712631" )); let mut p2 = Ed25519Point::from_xy(x2, y2).unwrap(); // This is the sum of (x1, y1) and (x2, y2). - let x3 = Ed25519Coord::from_be_bytes(&hex!( + let x3 = Ed25519Coord::from_be_bytes_unchecked(&hex!( "636C0B519B2C5B1E0D3BFD213F45AFD5DAEE3CECC9B68CF88615101BC78329E6" )); - let y3 = Ed25519Coord::from_be_bytes(&hex!( + let y3 = Ed25519Coord::from_be_bytes_unchecked(&hex!( "704D8868CB335A7B609D04B9CD619511675691A78861F1DFF7A5EBC389C7EA92" )); // This is 2 * (x1, y1) - let x4 = Ed25519Coord::from_be_bytes(&hex!( + let x4 = Ed25519Coord::from_be_bytes_unchecked(&hex!( "56B98CC045559AD2BBC45CAB58D842ECEE264DB9395F6014B772501B62BB7EE8" )); - let y4 = Ed25519Coord::from_be_bytes(&hex!( + let y4 = Ed25519Coord::from_be_bytes_unchecked(&hex!( "1BCA918096D89C83A15105DF343DC9F7510494407750226DAC0A7620ACE77BEB" )); diff --git a/extensions/ecc/tests/src/lib.rs b/extensions/ecc/tests/src/lib.rs index 762f96a5ba..c63af1d373 100644 --- a/extensions/ecc/tests/src/lib.rs +++ b/extensions/ecc/tests/src/lib.rs @@ -14,8 +14,7 @@ mod tests { utils::{air_test, air_test_with_min_segments}, }; use openvm_ecc_circuit::{ - CurveConfig, EccExtension, Rv32EccConfig, SwCurveCoeffs, ED25519_CONFIG, P256_CONFIG, - SECP256K1_CONFIG, + CurveConfig, Rv32EccConfig, SwCurveCoeffs, ED25519_CONFIG, P256_CONFIG, SECP256K1_CONFIG, }; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_rv32im_transpiler::{ From cb4e446888e0c7e3acc940ca8d7f38ce967daa0e Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Thu, 19 Jun 2025 19:37:31 -0400 Subject: [PATCH 55/57] Add #[serde(default)] to EccExtenison (allow omitting sw or te curves) --- extensions/ecc/circuit/src/ecc_extension.rs | 2 ++ extensions/ecc/tests/programs/openvm_k256.toml | 4 +++- extensions/ecc/tests/programs/openvm_k256_keccak.toml | 4 +++- extensions/ecc/tests/programs/openvm_p256.toml | 4 +++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index df4b9c6fe6..3e15413940 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -108,7 +108,9 @@ pub static ED25519_CONFIG: Lazy> = Lazy::new(|| Curve #[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] pub struct EccExtension { + #[serde(default)] pub supported_sw_curves: Vec>, + #[serde(default)] pub supported_te_curves: Vec>, } diff --git a/extensions/ecc/tests/programs/openvm_k256.toml b/extensions/ecc/tests/programs/openvm_k256.toml index 571fdb895c..2fa80a5af3 100644 --- a/extensions/ecc/tests/programs/openvm_k256.toml +++ b/extensions/ecc/tests/programs/openvm_k256.toml @@ -8,9 +8,11 @@ supported_moduli = [ "115792089237316195423570985008687907852837564279074904382605163141518161494337", ] -[[app_vm_config.ecc.supported_curves]] +[[app_vm_config.ecc.supported_sw_curves]] struct_name = "Secp256k1Point" modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" + +[app_vm_config.ecc.supported_sw_curves.coeffs] a = "0" b = "7" diff --git a/extensions/ecc/tests/programs/openvm_k256_keccak.toml b/extensions/ecc/tests/programs/openvm_k256_keccak.toml index c1261ee458..4dc77ccd80 100644 --- a/extensions/ecc/tests/programs/openvm_k256_keccak.toml +++ b/extensions/ecc/tests/programs/openvm_k256_keccak.toml @@ -9,9 +9,11 @@ supported_moduli = [ "115792089237316195423570985008687907852837564279074904382605163141518161494337", ] -[[app_vm_config.ecc.supported_curves]] +[[app_vm_config.ecc.supported_sw_curves]] struct_name = "Secp256k1Point" modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" + +[app_vm_config.ecc.supported_sw_curves.coeffs] a = "0" b = "7" diff --git a/extensions/ecc/tests/programs/openvm_p256.toml b/extensions/ecc/tests/programs/openvm_p256.toml index 0035cd83da..2cc5bd92c3 100644 --- a/extensions/ecc/tests/programs/openvm_p256.toml +++ b/extensions/ecc/tests/programs/openvm_p256.toml @@ -7,9 +7,11 @@ supported_moduli = [ "115792089210356248762697446949407573529996955224135760342422259061068512044369", ] -[[app_vm_config.ecc.supported_curves]] +[[app_vm_config.ecc.supported_sw_curves]] struct_name = "P256Point" modulus = "115792089210356248762697446949407573530086143415290314195533631308867097853951" scalar = "115792089210356248762697446949407573529996955224135760342422259061068512044369" + +[app_vm_config.ecc.supported_sw_curves.coeffs] a = "115792089210356248762697446949407573530086143415290314195533631308867097853948" b = "41058363725152142129326129780047268409114441015993725554835256314039467401291" From 2e59e6f0bcdc68cd6d596d96f4fc06aeb023db53 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Fri, 11 Jul 2025 14:21:40 -0400 Subject: [PATCH 56/57] Fix typo in ecc tests --- extensions/ecc/tests/programs/examples/decompress.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/ecc/tests/programs/examples/decompress.rs b/extensions/ecc/tests/programs/examples/decompress.rs index 87e75deeaf..f6e9870a3e 100644 --- a/extensions/ecc/tests/programs/examples/decompress.rs +++ b/extensions/ecc/tests/programs/examples/decompress.rs @@ -7,7 +7,7 @@ extern crate alloc; use hex_literal::hex; use openvm::io::read_vec; use openvm_ecc_guest::{ - algebra::{DivUnsafe, Field, IntMod}, + algebra::{Field, IntMod}, ed25519::{Ed25519Coord, Ed25519Point}, edwards::TwistedEdwardsPoint, weierstrass::WeierstrassPoint, @@ -64,13 +64,13 @@ pub fn main() { test_possible_sw_decompression::(&x, &y, rec_id); // x = 0 is not on the x-coordinate of any point on the CurvePoint5mod8 curve - test_impossible_sw_decompression::(&Fp5mod8::ZERO, rec_id); + test_impossible_sw_decompression::(&::ZERO, rec_id); // this x is such that y^2 = x^3 + 6 = 0 // we want to test the case where y^2 = 0 and rec_id = 1 let x = Fp5mod8::from_le_bytes_unchecked(&hex!( "d634a701c3b9b8cbf7797988be3953b442863b74d2d5c4d5f1a9de3c0c256d90" )); - test_possible_sw_decompression::(&x, &Fp5mod8::ZERO, 0); + test_possible_sw_decompression::(&x, &::ZERO, 0); test_impossible_sw_decompression::(&x, 1); let x = Fp1mod4::from_le_bytes_unchecked(&bytes[128..160]); From 1f0d42c5adc589d316041595548ef89bfee47dd4 Mon Sep 17 00:00:00 2001 From: Avaneesh Kulkarni Date: Thu, 31 Jul 2025 20:34:50 -0400 Subject: [PATCH 57/57] Remove 48 limb twisted edwards curve support (unused) --- extensions/ecc/circuit/src/ecc_extension.rs | 24 --------------------- 1 file changed, 24 deletions(-) diff --git a/extensions/ecc/circuit/src/ecc_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs index 3e15413940..7753758bc4 100644 --- a/extensions/ecc/circuit/src/ecc_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -146,8 +146,6 @@ pub enum EccExtensionExecutor { SwEcDoubleRv32_48(SwDoubleChip), // 32 limbs prime TeEcAddRv32_32(TeAddChip), - // 48 limbs prime - TeEcAddRv32_48(TeAddChip), } #[derive(ChipUsageGetter, Chip, AnyEnum, From)] @@ -331,28 +329,6 @@ impl VmExtension for EccExtension { .clone() .map(|x| VmOpcode::from_usize(x + te_start_offset)), )?; - } else if bytes <= 48 { - let te_add_chip = TeAddChip::new( - Rv32VecHeapAdapterChip::::new( - execution_bus, - program_bus, - memory_bridge, - pointer_bits, - bitwise_lu_chip.clone(), - ), - config48.clone(), - te_start_offset, - curve.coeffs.a.clone(), - curve.coeffs.d.clone(), - range_checker.clone(), - offline_memory.clone(), - ); - inventory.add_executor( - EccExtensionExecutor::TeEcAddRv32_48(te_add_chip), - te_add_opcodes - .clone() - .map(|x| VmOpcode::from_usize(x + te_start_offset)), - )?; } else { panic!("Modulus too large"); }