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 diff --git a/Cargo.lock b/Cargo.lock index 0de21f22b6..c5f073a611 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,7 +37,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -81,18 +81,18 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.21" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478bedf4d24e71ea48428d1bc278553bd7c6ae07c30ca063beb0b09fe58a9e74" +checksum = "8c77490fe91a0ce933a1f219029521f20fc28c2c0ca95d53fa4da9c00b8d9d4e" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", - "derive_more 1.0.0", + "derive_more 2.0.1", "foldhash", "hashbrown 0.15.2", - "indexmap 2.7.1", + "indexmap 2.8.0", "itoa", "k256", "keccak-asm", @@ -125,7 +125,7 @@ checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -210,9 +210,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.96" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "ark-ff" @@ -352,15 +352,21 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[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]] +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" @@ -379,7 +385,7 @@ checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -390,9 +396,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", @@ -400,7 +406,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", @@ -409,7 +415,7 @@ dependencies = [ "bytes", "fastrand", "hex", - "http 0.2.12", + "http 1.3.1", "ring", "time", "tokio", @@ -420,9 +426,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", @@ -430,17 +436,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", @@ -458,9 +487,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", @@ -468,7 +497,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", @@ -480,6 +509,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", + "http 1.3.1", "http-body 0.4.6", "lru", "once_cell", @@ -492,20 +522,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", @@ -514,20 +545,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", @@ -536,14 +568,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", @@ -551,6 +583,7 @@ dependencies = [ "aws-smithy-types", "aws-smithy-xml", "aws-types", + "fastrand", "http 0.2.12", "once_cell", "regex-lite", @@ -559,13 +592,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", @@ -574,7 +607,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.2.0", + "http 1.3.1", "once_cell", "p256 0.11.1", "percent-encoding", @@ -588,9 +621,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", @@ -599,11 +632,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", @@ -621,9 +654,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", @@ -632,16 +665,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", @@ -651,35 +686,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" @@ -692,42 +744,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", @@ -736,16 +786,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", @@ -771,9 +821,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", @@ -841,9 +891,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" @@ -854,6 +904,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" @@ -871,9 +944,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[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", @@ -890,14 +963,14 @@ checksum = "42b6b4cb608b8282dc3b53d0f4c9ab404655d562674c682db7e6c0458cc83c23" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bitvec" @@ -933,16 +1006,15 @@ 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", "cc", "cfg-if", "constant_time_eq", - "memmap2", ] [[package]] @@ -981,9 +1053,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", @@ -991,9 +1063,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", @@ -1001,7 +1073,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1012,15 +1084,15 @@ 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" @@ -1030,9 +1102,9 @@ 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" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "bytes-utils" @@ -1110,7 +1182,7 @@ checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_json", "thiserror 1.0.69", @@ -1124,15 +1196,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" @@ -1141,15 +1222,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[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", "num-traits", "serde", - "windows-targets", + "windows-link", ] [[package]] @@ -1179,11 +1260,22 @@ dependencies = [ "half", ] +[[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.30" +version = "4.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" +checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff" dependencies = [ "clap_builder", "clap_derive", @@ -1191,9 +1283,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", @@ -1203,14 +1295,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]] @@ -1219,6 +1311,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" @@ -1292,6 +1393,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" @@ -1489,9 +1600,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", @@ -1499,27 +1610,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]] @@ -1544,9 +1655,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", @@ -1571,7 +1682,7 @@ checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1582,7 +1693,7 @@ checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1595,7 +1706,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1604,7 +1715,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "derive_more-impl", + "derive_more-impl 1.0.0", +] + +[[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]] @@ -1615,7 +1735,19 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", + "unicode-xid", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", "unicode-xid", ] @@ -1648,7 +1780,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1657,11 +1789,17 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +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" @@ -1691,9 +1829,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" @@ -1730,7 +1868,7 @@ dependencies = [ "base16ct 0.2.0", "crypto-bigint 0.5.5", "digest 0.10.7", - "ff 0.13.0", + "ff 0.13.1", "generic-array", "group 0.13.0", "pkcs8 0.10.2", @@ -1767,7 +1905,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1778,7 +1916,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -1792,9 +1930,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", @@ -1892,9 +2030,9 @@ dependencies = [ [[package]] name = "ff" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ "bitvec", "byteorder", @@ -1905,12 +2043,11 @@ dependencies = [ [[package]] name = "ff_derive" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a" +checksum = "f10d12652036b0e99197587c6ba87a8fc3031986499973c030d8b44fcc151b60" dependencies = [ "addchain", - "cfg-if", "num-bigint 0.3.3", "num-integer", "num-traits", @@ -1939,9 +2076,9 @@ 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" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "form_urlencoded" @@ -1952,6 +2089,12 @@ dependencies = [ "percent-encoding", ] +[[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" @@ -2027,26 +2170,26 @@ 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", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[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]] @@ -2070,9 +2213,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" @@ -2098,7 +2241,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff 0.13.0", + "ff 0.13.1", "rand_core", "subtle", ] @@ -2115,7 +2258,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", @@ -2124,9 +2286,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", @@ -2149,7 +2311,7 @@ checksum = "62f0ca78d12ac5c893f286d7cdfe3869290305ab8cac376e2592cdc8396da102" dependencies = [ "blake2b_simd", "crossbeam", - "ff 0.13.0", + "ff 0.13.1", "group 0.13.0", "halo2curves-axiom", "itertools 0.11.0", @@ -2226,7 +2388,7 @@ checksum = "b756596082144af6e57105a20403b7b80fe9dccd085700b74fae3af523b74dba" dependencies = [ "blake2", "digest 0.10.7", - "ff 0.13.0", + "ff 0.13.1", "group 0.13.0", "halo2derive", "hex", @@ -2255,7 +2417,7 @@ checksum = "dd8309e4638b4f1bcf6613d72265a84074d26034c35edc5d605b5688e580b8b8" dependencies = [ "blake2b_simd", "digest 0.10.7", - "ff 0.13.0", + "ff 0.13.1", "group 0.13.0", "hex", "lazy_static", @@ -2329,9 +2491,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" @@ -2357,6 +2519,15 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "http" version = "0.2.12" @@ -2370,9 +2541,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", @@ -2397,27 +2568,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.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -2435,7 +2606,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "httparse", @@ -2449,6 +2620,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" @@ -2457,24 +2648,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 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", + "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", ] @@ -2529,9 +2758,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" @@ -2553,9 +2782,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" @@ -2574,9 +2803,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" @@ -2603,7 +2832,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -2650,7 +2879,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -2672,9 +2901,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", @@ -2683,11 +2912,11 @@ dependencies = [ [[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", ] @@ -2716,6 +2945,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" @@ -2727,9 +2965,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" @@ -2805,11 +3043,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" @@ -2823,6 +3067,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" @@ -2831,9 +3085,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", @@ -2841,9 +3095,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", @@ -2863,11 +3117,17 @@ 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" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" [[package]] name = "lockfree-object-pool" @@ -2877,9 +3137,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" @@ -2925,15 +3185,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memmap2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" -dependencies = [ - "libc", -] - [[package]] name = "memuse" version = "0.2.2" @@ -2956,7 +3207,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", @@ -2977,7 +3228,7 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "hashbrown 0.14.5", - "indexmap 2.7.1", + "indexmap 2.8.0", "metrics", "num_cpus", "ordered-float", @@ -2988,18 +3239,24 @@ 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", ] +[[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.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" dependencies = [ "adler2", ] @@ -3024,6 +3281,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" @@ -3179,15 +3446,15 @@ 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" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "openssl-probe" @@ -3243,7 +3510,7 @@ version = "0.1.0" dependencies = [ "openvm-macros-common", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -3264,7 +3531,7 @@ version = "1.0.0" dependencies = [ "openvm-macros-common", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -3451,7 +3718,7 @@ version = "1.0.0" dependencies = [ "itertools 0.14.0", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -3476,7 +3743,7 @@ version = "1.0.0" dependencies = [ "itertools 0.14.0", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -3499,7 +3766,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -3552,6 +3819,7 @@ dependencies = [ "openvm-algebra-moduli-macros", "openvm-custom-insn", "openvm-ecc-sw-macros", + "openvm-ecc-te-macros", "openvm-rv32im-guest", "p256 0.13.2", "serde", @@ -3585,7 +3853,16 @@ version = "1.0.0" dependencies = [ "openvm-macros-common", "quote", - "syn 2.0.98", + "syn 2.0.100", +] + +[[package]] +name = "openvm-ecc-te-macros" +version = "1.0.0" +dependencies = [ + "openvm-macros-common", + "quote", + "syn 2.0.100", ] [[package]] @@ -3625,7 +3902,7 @@ dependencies = [ "quote", "strum", "strum_macros", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -3694,7 +3971,7 @@ dependencies = [ name = "openvm-macros-common" version = "1.0.0" dependencies = [ - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -3774,7 +4051,7 @@ name = "openvm-native-compiler-derive" version = "1.0.0" dependencies = [ "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -4184,7 +4461,7 @@ source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.0.0#884f8e6 dependencies = [ "derivative", "derive_more 0.99.19", - "ff 0.13.0", + "ff 0.13.1", "itertools 0.14.0", "metrics", "metrics-tracing-context", @@ -4329,7 +4606,7 @@ name = "p3-bn254-fr" version = "0.1.0" source = "git+https://github.com/Plonky3/Plonky3.git?rev=1ba4e5c#1ba4e5c40417f4f7aae86bcca56b6484b4b2490b" dependencies = [ - "ff 0.13.0", + "ff 0.13.1", "halo2curves", "num-bigint 0.4.6", "p3-field", @@ -4661,7 +4938,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -4686,7 +4963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" dependencies = [ "blake2b_simd", - "ff 0.13.0", + "ff 0.13.1", "group 0.13.0", "lazy_static", "rand", @@ -4708,12 +4985,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", ] @@ -4751,9 +5028,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" @@ -4785,9 +5062,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" @@ -4796,7 +5073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e4aaeda7a092e21165cc5f0cbc738e72a46f31c03c3cbd87b71ceae9d2d93bc" dependencies = [ "bitvec", - "ff 0.13.0", + "ff 0.13.1", "lazy_static", "log", "rand", @@ -4812,21 +5089,21 @@ 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]] 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]] @@ -4842,9 +5119,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", ] @@ -4868,14 +5145,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", ] @@ -4923,13 +5200,19 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[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" @@ -4987,9 +5270,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", ] @@ -5151,9 +5434,9 @@ 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", @@ -5275,7 +5558,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]] @@ -5287,7 +5570,20 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys", + "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", + "errno", + "libc", + "linux-raw-sys 0.9.3", "windows-sys 0.59.0", ] @@ -5299,10 +5595,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" @@ -5312,7 +5622,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]] @@ -5324,6 +5646,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" @@ -5334,11 +5662,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" @@ -5354,9 +5694,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -5440,7 +5780,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags", - "core-foundation", + "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", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -5467,9 +5820,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", ] @@ -5485,9 +5838,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", ] @@ -5512,22 +5865,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", @@ -5553,7 +5906,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.1", + "indexmap 2.8.0", "serde", "serde_derive", "serde_json", @@ -5570,7 +5923,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -5804,7 +6157,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -5852,9 +6205,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", @@ -5869,7 +6222,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -5886,15 +6239,14 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[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 0.3.1", + "getrandom 0.3.2", "once_cell", - "rustix", + "rustix 1.0.3", "windows-sys 0.59.0", ] @@ -5916,7 +6268,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -5927,7 +6279,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", "test-case-core", ] @@ -5950,7 +6302,7 @@ checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -5964,11 +6316,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]] @@ -5979,18 +6331,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]] @@ -6034,9 +6386,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", @@ -6051,15 +6403,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", @@ -6096,9 +6448,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.43.0" +version = "1.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" dependencies = [ "backtrace", "bytes", @@ -6119,7 +6471,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -6128,15 +6480,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", @@ -6172,13 +6534,29 @@ 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", "winnow", ] +[[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" @@ -6204,7 +6582,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -6307,9 +6685,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" @@ -6376,9 +6754,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" @@ -6453,9 +6831,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -6482,7 +6860,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", "wasm-bindgen-shared", ] @@ -6504,7 +6882,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6528,6 +6906,18 @@ dependencies = [ "wasm-bindgen", ] +[[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 = "winapi" version = "0.3.9" @@ -6568,6 +6958,12 @@ dependencies = [ "windows-targets", ] +[[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" @@ -6652,18 +7048,18 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" dependencies = [ "memchr", ] [[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", ] @@ -6715,7 +7111,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", "synstructure", ] @@ -6725,8 +7121,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]] @@ -6737,27 +7141,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", ] @@ -6778,7 +7193,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] @@ -6800,7 +7215,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.100", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 943b8d798e..6943ee6808 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,7 @@ members = [ "extensions/ecc/transpiler", "extensions/ecc/guest", "extensions/ecc/sw-macros", + "extensions/ecc/te-macros", "extensions/ecc/tests", "extensions/pairing/circuit", "extensions/pairing/transpiler", @@ -155,6 +156,7 @@ 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-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/benchmarks/programs/ecrecover/src/main.rs b/benchmarks/programs/ecrecover/src/main.rs index fa29562fa6..2abef484e2 100644 --- a/benchmarks/programs/ecrecover/src/main.rs +++ b/benchmarks/programs/ecrecover/src/main.rs @@ -25,7 +25,7 @@ openvm_ecc_guest::sw_macros::sw_init! { pub fn main() { setup_all_moduli(); - setup_all_curves(); + setup_all_sw_curves(); let expected_address = read_vec(); for _ in 0..5 { diff --git a/benchmarks/programs/kitchen-sink/src/main.rs b/benchmarks/programs/kitchen-sink/src/main.rs index 8c12e165f7..781b80a09f 100644 --- a/benchmarks/programs/kitchen-sink/src/main.rs +++ b/benchmarks/programs/kitchen-sink/src/main.rs @@ -51,7 +51,7 @@ pub fn main() { // Setup will materialize every chip setup_all_moduli(); setup_all_complex_extensions(); - setup_all_curves(); + setup_all_sw_curves(); let [one, six] = [1, 6].map(Seven::from_u32); assert_eq!(one + six, Seven::ZERO); diff --git a/benchmarks/programs/pairing/src/main.rs b/benchmarks/programs/pairing/src/main.rs index 807c5d2866..b33a47f000 100644 --- a/benchmarks/programs/pairing/src/main.rs +++ b/benchmarks/programs/pairing/src/main.rs @@ -25,7 +25,7 @@ pub fn main() { setup_all_moduli(); setup_all_complex_extensions(); // Pairing doesn't need G1Affine intrinsics, but we trigger it anyways to test the chips - setup_all_curves(); + setup_all_sw_curves(); // copied from https://github.com/bluealloy/revm/blob/9e39df5dbc5fdc98779c644629b28b8bee75794a/crates/precompile/src/bn128.rs#L395 let input = hex::decode( diff --git a/benchmarks/src/bin/ecrecover.rs b/benchmarks/src/bin/ecrecover.rs index 5251fd8655..8df7a6b741 100644 --- a/benchmarks/src/bin/ecrecover.rs +++ b/benchmarks/src/bin/ecrecover.rs @@ -12,8 +12,8 @@ use openvm_circuit::{ derive::VmConfig, }; use openvm_ecc_circuit::{ - CurveConfig, WeierstrassExtension, WeierstrassExtensionExecutor, WeierstrassExtensionPeriphery, - SECP256K1_CONFIG, + CurveConfig, EccExtension, EccExtensionExecutor, EccExtensionPeriphery, SwCurveCoeffs, + TeCurveCoeffs, SECP256K1_CONFIG, }; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_keccak256_circuit::{Keccak256, Keccak256Executor, Keccak256Periphery}; @@ -63,15 +63,23 @@ pub struct Rv32ImEcRecoverConfig { #[extension] pub keccak: Keccak256, #[extension] - pub weierstrass: WeierstrassExtension, + pub ecc: EccExtension, } 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(), @@ -79,7 +87,7 @@ impl Rv32ImEcRecoverConfig { io: Default::default(), modular: ModularExtension::new(primes), keccak: Default::default(), - weierstrass: WeierstrassExtension::new(curves), + ecc: EccExtension::new(sw_curves, te_curves), } } } @@ -125,7 +133,7 @@ fn main() -> Result<()> { ); args.bench_from_exe( "ecrecover_program", - Rv32ImEcRecoverConfig::for_curves(vec![SECP256K1_CONFIG.clone()]), + Rv32ImEcRecoverConfig::for_curves(vec![SECP256K1_CONFIG.clone()], vec![]), exe, input_stream.into(), ) diff --git a/benchmarks/src/bin/kitchen_sink.rs b/benchmarks/src/bin/kitchen_sink.rs index 9ec4a26d71..e622bffd06 100644 --- a/benchmarks/src/bin/kitchen_sink.rs +++ b/benchmarks/src/bin/kitchen_sink.rs @@ -6,7 +6,7 @@ use num_bigint::BigUint; use openvm_algebra_circuit::{Fp2Extension, ModularExtension}; use openvm_benchmarks::utils::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_sdk::{ @@ -49,12 +49,15 @@ fn main() -> Result<()> { bn_config.modulus.clone(), 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/src/bin/pairing.rs b/benchmarks/src/bin/pairing.rs index 012285aa6c..3eb8f24421 100644 --- a/benchmarks/src/bin/pairing.rs +++ b/benchmarks/src/bin/pairing.rs @@ -3,7 +3,7 @@ use eyre::Result; use openvm_algebra_circuit::{Fp2Extension, ModularExtension}; use openvm_benchmarks::utils::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_MODULUS, BN254_ORDER}; use openvm_sdk::{config::SdkVmConfig, Sdk, StdIn}; @@ -24,9 +24,10 @@ fn main() -> Result<()> { BN254_ORDER.clone(), ])) .fp2(Fp2Extension::new(vec![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 sdk = Sdk::new(); diff --git a/book/src/custom-extensions/ecc.md b/book/src/custom-extensions/ecc.md index 331430d6ad..27618f0d16 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 short 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, it enumerates these curves and allows the compiler to produce optimized instructions: @@ -49,19 +60,24 @@ This creates `Bls12_381G1Affine` and `P256Affine` structs which implement the `G sw_init! { Bls12_381G1Affine, P256Affine, } +te_init! { + Edwards25519, +} ``` 3. **Setup**: Similar to the moduli and complex extensions, runtime setup instructions ensure that the correct curve parameters are being used, guaranteeing secure operation. **Summary**: -- `sw_declare!`: Declares elliptic curve structures. -- `sw_init!`: Initializes them once, linking them to the underlying moduli. -- `setup_sw_()`/`setup_all_curves()`: Secures runtime correctness. +- `sw_declare!`: Declares short Weierstrass elliptic curve structures. +- `te_declare!`: Declares twisted Edwards elliptic curve structures. +- `sw_init!`: Initializes the short Weierstrass elliptic curves once, linking them to the underlying moduli. +- `te_init!`: Initializes the twisted Edwards elliptic curves once, linking them to the underlying moduli. +- `setup_sw_()`/`setup_all_sw_curves()`/`setup_te_()`/`setup_all_te_curves()`: Secures runtime correctness. -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 @@ -100,15 +116,25 @@ For the guest program to build successfully, all used moduli and curves must be ```toml [app_vm_config.modular] -supported_modulus = ["115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337"] +supported_modulus = ["115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337", "57896044618658097711785492504343953926634992332820282019728792003956564819949"] -[[app_vm_config.ecc.supported_curves]] +[[app_vm_config.ecc.supported_sw_curves]] modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" + +[app_vm_config.ecc.supported_sw_curves.coeffs] a = "0" b = "7" + +[[app_vm_config.ecc.supported_te_curves]] +modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" +scalar = "7237005577332262213973186563042994240857116359379907606001950938285454250989" + +[app_vm_config.ecc.supported_te_curves.coeffs] +a = "57896044618658097711785492504343953926634992332820282019728792003956564819948" +d = "37095705934669439343138083508754565189542113879843219016388785533085940283555" ``` The `supported_modulus` 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. +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. \ No newline at end of file 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()), } } diff --git a/crates/sdk/src/config/global.rs b/crates/sdk/src/config/global.rs index 532c9b8d1c..038af16f94 100644 --- a/crates/sdk/src/config/global.rs +++ b/crates/sdk/src/config/global.rs @@ -14,9 +14,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; @@ -60,7 +58,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)] @@ -88,7 +86,7 @@ pub enum SdkVmConfigExecutor { #[any_enum] Pairing(PairingExtensionExecutor), #[any_enum] - Ecc(WeierstrassExtensionExecutor), + Ecc(EccExtensionExecutor), #[any_enum] CastF(CastFExtensionExecutor), } @@ -118,7 +116,7 @@ pub enum SdkVmConfigPeriphery { #[any_enum] Pairing(PairingExtensionPeriphery), #[any_enum] - Ecc(WeierstrassExtensionPeriphery), + Ecc(EccExtensionPeriphery), #[any_enum] CastF(CastFExtensionPeriphery), } diff --git a/docs/specs/ISA.md b/docs/specs/ISA.md index 1bc3d0c4a0..a6c73ad33f 100644 --- a/docs/specs/ISA.md +++ b/docs/specs/ISA.md @@ -666,12 +666,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` ( -defined below). The extension operates on address spaces `1` and `2`, meaning all memory cells are constrained to be +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. 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 @@ -689,12 +690,16 @@ 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 | | -------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 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`. | #### Phantom Sub-Instructions @@ -702,8 +707,10 @@ The elliptic curve extension defines the following phantom sub-instructions. | Name | Discriminant | Operands | Description | | -------------- | ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| HintDecompress | 0x40 | `a,b,c_upper` | Uses `c_upper = C::IDX` to determine the index of the curve `C`, from the list of enabled curves. Read from memory `x = [r32{0}(a): C::COORD_SIZE]_2` for an element in the coordinate field of `C`. Let `rec_id = [r32{0}(b)]_2` be a byte in memory for the recovery id, where the lowest bit is 1 if and only if the `y` coordinate of the corresponding point is odd. If there exists a unique `y` such that `(x, y)` is a point on `C` and `y` has the same parity as `rec_id`, then the sub-instruction resets the hint stream to `[1, 0, 0, 0]` followed by `y: [_; C::COORD_SIZE]`. Otherwise, it resets the hint stream to `[0, 0, 0, 0]` followed by `sqrt: [_; C::COORD_SIZE]` where `sqrt * sqrt == (x^3 + ax + b) * non_qr` (`non_qr` is a quadratic nonresidue of `C::Fp`). | -| HintNonQr | 0x41 | `_,_,c_upper` | Reset the hint stream to equal `non_qr: [_; C::COORD_SIZE]` where `non_qr` is a quadratic nonresidue of `C::Fp`. | +| SwHintDecompress | 0x40 | `a,b,c_upper` | Use `c_upper = C::IDX` to determine the index of the curve `C`, from the list of enabled short Weierstrass curves. Read from memory `x = [r32{0}(a): C::COORD_SIZE]_2` for an element in the coordinate field of `C`. Let `rec_id = [r32{0}(b)]_2` be a byte in memory for the recovery id, where the lowest bit is 1 if and only if the `y` coordinate of the corresponding point is odd. If there exists a unique `y` such that `(x, y)` is a point on `C` and `y` has the same parity as `rec_id`, then the sub-instruction resets the hint stream to `[1, 0, 0, 0]` followed by `y: [_; C::COORD_SIZE]`. Otherwise, it resets the hint stream to `[0, 0, 0, 0]` followed by `sqrt: [_; C::COORD_SIZE]` where `sqrt * sqrt == (x^3 + ax + b) * non_qr` where `non_qr` is a quadratic nonresidue of `C::Fp` that is fixed for the curve. | +| SwHintNonQr | 0x41 | `_,_,c_upper` | Reset the hint stream to equal `non_qr: [_; C::COORD_SIZE]` where `non_qr` is a quadratic nonresidue of `C::Fp`. This element is fixed for the curve during VM instantiation so multiple calls to this instruction will always return the same hint. | +| TeHintDecompress | 0x42 | `a,b,c_upper` | Use `c_upper = C::IDX` to determine the index of the curve `C`, from the list of enabled twisted Edwards curves. Read from memory `y = [r32{0}(a): C::COORD_SIZE]_2` for an element in the coordinate field of `C`. Let `rec_id = [r32{0}(b)]_2` be a byte in memory for the recovery id, where the lowest bit is 1 if and only if the `x` coordinate of the corresponding point is odd. If there exists a unique `x` such that `(x, y)` is a point on `C` and `x` has the same parity as `rec_id`, then the sub-instruction resets the hint stream to `[1, 0, 0, 0]` followed by `x: [_; C::COORD_SIZE]`. Otherwise, it resets the hint stream to `[0, 0, 0, 0]` followed by `sqrt: [_; C::COORD_SIZE]` where `sqrt * sqrt = (y^2 - 1) / (C::D * y^2 - C::A) * non_qr` where `non_qr` is a quadratic nonresidue of `C::Fp` that is fixed for the curve. | +| TeHintNonQr | 0x43 | `_,_,c_upper` | Reset the hint stream to equal `non_qr: [_; C::COORD_SIZE]` where `non_qr` is a quadratic nonresidue of `C::Fp`. This element is fixed for the curve during VM instantiation so multiple calls to this instruction will always return the same hint. | ### Pairing Extension diff --git a/docs/specs/RISCV.md b/docs/specs/RISCV.md index 7948272c66..c77e05a8fd 100644 --- a/docs/specs/RISCV.md +++ b/docs/specs/RISCV.md @@ -163,15 +163,20 @@ 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 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 | | --------------- | --- | ----------- | ------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 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` | -| hint_decompress | R | 0101011 | 001 | `idx*8+3` | Read `x: C::Fp` from `[rs1: C::COORD_SIZE]_2` and `rec_id: u8` from `[rs2]_2`. If there exists a unique `y: C::Fp` such that `(x, y)` is a point on `C` and `y` has the same parity as `rec_id`, then reset the hint stream to `[1u8, 0u8, 0u8, 0u8]` concatenated with the limbs representing `y` in little-endian order; otherwise, reset it to `[0u8; 4]` concatenated the limbs representing `sqrt` where `sqrt * sqrt == (x^3 + ax + b) * non_qr` (`non_qr` is a quadratic nonresidue of `C::Fp`). `rd` should be `x0`. | -| hint_non_qr | R | 0101011 | 001 | `idx*8+4` | Reset the hint stream to equal `non_qr` where `non_qr` is a quadratic nonresidue of `C::Fp`. `rd`, `rs1`, and `rs2` should be `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` | +| sw_hint_decompress\ | R | 0101011 | 001 | `idx*8+3` | Read `x: C::Fp` from `[rs1: C::COORD_SIZE]_2` and `rec_id: u8` from `[rs2]_2`. If there exists a unique `y: C::Fp` such that `(x, y)` is a point on `C` and `y` has the same parity as `rec_id`, then reset the hint stream to `[1u8, 0u8, 0u8, 0u8]` concatenated with the limbs representing `y` in little-endian order; otherwise, reset it to `[0u8; 4]` concatenated the limbs representing `sqrt` where `sqrt * sqrt == (x^3 + ax + b) * non_qr` where `non_qr` is a quadratic nonresidue of `C::Fp` that is fixed for the curve. `rd` should be `x0`. | +| sw_hint_non_qr\ | R | 0101011 | 001 | `idx*8+4` | Reset the hint stream to equal `non_qr` where `non_qr` is a quadratic nonresidue of `C::Fp`. This element is fixed for the curve during VM instantiation so multiple calls to this instruction will always return the same hint. `rd`, `rs1`, and `rs2` should be `x0`. | +| 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+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`. | +| te_hint_decompress\ | R | 0101011 | 100 | `idx*8+2` | Read `y: C::Fp` from `[rs1: C::COORD_SIZE]_2` and `rec_id: u8` from `[rs2]_2`. If there exists a unique `x: C::Fp` such that `(x, y)` is a point on `C` and `x` has the same parity as `rec_id`, then reset the hint stream to `[1u8, 0u8, 0u8, 0u8]` concatenated with the limbs representing `x` in little-endian order; otherwise, reset it to `[0u8; 4]` concatenated the limbs representing `sqrt` where `sqrt * sqrt == (y^2 - 1) / (C::D * y^2 - C::A) * non_qr` where `non_qr` is a quadratic nonresidue of `C::Fp` that is fixed for the curve. `rd` should be `x0`. | +| te_hint_non_qr\ | R | 0101011 | 100 | `idx*8+3` | Reset the hint stream to equal `non_qr` where `non_qr` is a quadratic nonresidue of `C::Fp`. This element is fixed for the curve during VM instantiation so multiple calls to this instruction will always return the same hint. `rd`, `rs1`, and `rs2` should be `x0`. | + 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 a8b94ef2b0..9c0a485f4b 100644 --- a/docs/specs/transpiler.md +++ b/docs/specs/transpiler.md @@ -203,9 +203,13 @@ 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` | -| hint_decompress | PHANTOM `ind(rs1), ind(rs2), phantom_c(curve_idx, HintDecompress)` | -| hint_non_qr | PHANTOM `0, 0, phantom_c(curve_idx, HintNonQr)` | +| 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` | +| sw_hint_decompress\ | PHANTOM `ind(rs1), ind(rs2), phantom_c(curve_idx, SwHintDecompress)` | +| sw_hint_non_qr\ | PHANTOM `0, 0, phantom_c(curve_idx, SwHintNonQr)` | +| 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` | +| te_hint_decompress\ | PHANTOM `ind(rd), ind(rs1), phantom_c(curve_idx, TeHintDecompress)` | +| te_hint_non_qr\ | PHANTOM `0, 0, phantom_c(curve_idx, TeHintNonQr)` | ### Pairing Extension diff --git a/examples/algebra/Cargo.toml b/examples/algebra/Cargo.toml index 58a7402e68..b4da3b89e2 100644 --- a/examples/algebra/Cargo.toml +++ b/examples/algebra/Cargo.toml @@ -9,10 +9,10 @@ members = [] [dependencies] openvm = { git = "https://github.com/openvm-org/openvm.git", features = [ "std", -] } -openvm-platform = { git = "https://github.com/openvm-org/openvm.git" } -openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git" } -openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git" } +], branch = "develop" } +openvm-platform = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } +openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } +openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } serde = { version = "1.0.216" } num-bigint = { version = "0.4.6", features = ["serde"] } diff --git a/examples/algebra/openvm/app.vmexe b/examples/algebra/openvm/app.vmexe new file mode 100644 index 0000000000..801ce82638 Binary files /dev/null and b/examples/algebra/openvm/app.vmexe differ diff --git a/examples/ecc/Cargo.toml b/examples/ecc/Cargo.toml index 55dd320b19..b16b8c87f1 100644 --- a/examples/ecc/Cargo.toml +++ b/examples/ecc/Cargo.toml @@ -8,9 +8,14 @@ members = [] [dependencies] openvm = { path = "../../crates/toolchain/openvm", features = ["std"] } +openvm-custom-insn = { path = "../../crates/toolchain/custom_insn", default-features = false } openvm-algebra-guest = { path = "../../extensions/algebra/guest" } openvm-ecc-guest = { path = "../../extensions/ecc/guest", features = ["k256"] } +openvm-rv32im-guest = { path = "../../extensions/rv32im/guest" } + 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.toml b/examples/ecc/openvm.toml index bd968d85a2..218e769bba 100644 --- a/examples/ecc/openvm.toml +++ b/examples/ecc/openvm.toml @@ -2,10 +2,20 @@ [app_vm_config.rv32m] [app_vm_config.io] [app_vm_config.modular] -supported_modulus = ["115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337"] +supported_modulus = ["115792089237316195423570985008687907853269984665640564039457584007908834671663", "115792089237316195423570985008687907852837564279074904382605163141518161494337", "57896044618658097711785492504343953926634992332820282019728792003956564819949"] -[[app_vm_config.ecc.supported_curves]] +[[app_vm_config.ecc.supported_sw_curves]] modulus = "115792089237316195423570985008687907853269984665640564039457584007908834671663" scalar = "115792089237316195423570985008687907852837564279074904382605163141518161494337" + +[app_vm_config.ecc.supported_sw_curves.coeffs] a = "0" -b = "7" \ No newline at end of file +b = "7" + +[[app_vm_config.ecc.supported_te_curves]] +modulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949" +scalar = "7237005577332262213973186563042994240857116359379907606001950938285454250989" + +[app_vm_config.ecc.supported_te_curves.coeffs] +a = "57896044618658097711785492504343953926634992332820282019728792003956564819948" +d = "37095705934669439343138083508754565189542113879843219016388785533085940283555" diff --git a/examples/ecc/openvm/app.vmexe b/examples/ecc/openvm/app.vmexe new file mode 100644 index 0000000000..910f3a4efd Binary files /dev/null and b/examples/ecc/openvm/app.vmexe differ diff --git a/examples/ecc/src/main.rs b/examples/ecc/src/main.rs index 2fbb4ba45b..9f335ddd63 100644 --- a/examples/ecc/src/main.rs +++ b/examples/ecc/src/main.rs @@ -1,16 +1,67 @@ // ANCHOR: imports use hex_literal::hex; -use openvm_algebra_guest::IntMod; +use openvm_algebra_guest::{Field, IntMod}; use openvm_ecc_guest::{ + edwards::TwistedEdwardsPoint, k256::{Secp256k1Coord, Secp256k1Point}, weierstrass::WeierstrassPoint, + Group, }; +extern crate alloc; + // 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_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, +]); + +// 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! { @@ -21,7 +72,9 @@ openvm_ecc_guest::sw_macros::sw_init! { // ANCHOR: main pub fn main() { setup_all_moduli(); - setup_all_curves(); + setup_all_sw_curves(); + setup_all_te_curves(); + let x1 = Secp256k1Coord::from_u32(1); let y1 = Secp256k1Coord::from_le_bytes(&hex!( "EEA7767E580D75BC6FDD7F58D2A84C2614FB22586068DB63B346C6E60AF21842" @@ -35,5 +88,21 @@ pub fn main() { let p2 = Secp256k1Point::from_xy_nonidentity(x2, y2).unwrap(); let _p3 = &p1 + &p2; + + let x1 = Edwards25519Coord::from_be_bytes(&hex!( + "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + )); + 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_be_bytes(&hex!( + "1A43BF127BDDC4D71FF910403C11DDB5BA2BCDD2815393924657EF111E712631" + )); + let p2 = Edwards25519Point::from_xy(x2, y2).unwrap(); + + let _p3 = &p1 + &p2; } // ANCHOR_END: main diff --git a/examples/i256/Cargo.toml b/examples/i256/Cargo.toml index 78c0fa9402..7c4c212457 100644 --- a/examples/i256/Cargo.toml +++ b/examples/i256/Cargo.toml @@ -9,8 +9,9 @@ members = [] [dependencies] openvm = { git = "https://github.com/openvm-org/openvm.git", features = [ "std", -] } -openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git" } +], branch = "develop" } +openvm-platform = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } +openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } [features] default = [] diff --git a/examples/i256/openvm/app.vmexe b/examples/i256/openvm/app.vmexe new file mode 100644 index 0000000000..e45a699ef3 Binary files /dev/null and b/examples/i256/openvm/app.vmexe differ diff --git a/examples/keccak/Cargo.toml b/examples/keccak/Cargo.toml index 45f48acea0..020b36c565 100644 --- a/examples/keccak/Cargo.toml +++ b/examples/keccak/Cargo.toml @@ -7,10 +7,11 @@ 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-guest = { git = "https://github.com/openvm-org/openvm.git" } +openvm-platform = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } +openvm-keccak256-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } hex = { version = "0.4.3" } [features] diff --git a/examples/pairing/Cargo.toml b/examples/pairing/Cargo.toml index dd64cfea53..a7b4f7ea4e 100644 --- a/examples/pairing/Cargo.toml +++ b/examples/pairing/Cargo.toml @@ -9,12 +9,12 @@ members = [] [dependencies] openvm = { git = "https://github.com/openvm-org/openvm.git", features = [ "std", -] } -openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git" } -openvm-algebra-moduli-macros = { git = "https://github.com/openvm-org/openvm.git" } -openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git" } -openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git" } -openvm-pairing-guest = { git = "https://github.com/openvm-org/openvm.git", features = [ +], branch = "develop" } +openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } +openvm-algebra-moduli-macros = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } +openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } +openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } +openvm-pairing-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop", features = [ "bls12_381", ] } hex-literal = { version = "0.4.1", default-features = false } diff --git a/examples/sha256/Cargo.toml b/examples/sha256/Cargo.toml index dd749c1afd..48d6887c5c 100644 --- a/examples/sha256/Cargo.toml +++ b/examples/sha256/Cargo.toml @@ -9,8 +9,8 @@ members = [] [dependencies] openvm = { git = "https://github.com/openvm-org/openvm.git", features = [ "std", -] } -openvm-sha256-guest = { git = "https://github.com/openvm-org/openvm.git" } +], branch = "develop" } +openvm-sha256-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } hex = { version = "0.4.3" } [features] diff --git a/examples/u256/Cargo.toml b/examples/u256/Cargo.toml index 2ee553bbee..1d4e298f17 100644 --- a/examples/u256/Cargo.toml +++ b/examples/u256/Cargo.toml @@ -9,8 +9,8 @@ members = [] [dependencies] openvm = { git = "https://github.com/openvm-org/openvm.git", features = [ "std", -] } -openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git" } +], branch = "develop" } +openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop" } [features] default = [] diff --git a/extensions/ecc/circuit/Cargo.toml b/extensions/ecc/circuit/Cargo.toml index 28ea661248..81b397e65b 100644 --- a/extensions/ecc/circuit/Cargo.toml +++ b/extensions/ecc/circuit/Cargo.toml @@ -44,5 +44,6 @@ openvm-ecc-guest = { workspace = true, features = [ "halo2curves", "k256", "p256", + "ed25519", ] } openvm-algebra-guest = { workspace = true } diff --git a/extensions/ecc/circuit/src/config.rs b/extensions/ecc/circuit/src/config.rs index ab8809aa6d..e01c460245 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,22 +20,30 @@ pub struct Rv32WeierstrassConfig { #[extension] pub modular: ModularExtension, #[extension] - pub weierstrass: WeierstrassExtension, + pub ecc: EccExtension, } -impl Rv32WeierstrassConfig { - pub fn new(curves: Vec) -> Self { - let primes: Vec<_> = curves +impl Rv32EccConfig { + 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), - weierstrass: WeierstrassExtension::new(curves), + ecc: EccExtension::new(sw_curves, te_curves), } } } diff --git a/extensions/ecc/circuit/src/weierstrass_extension.rs b/extensions/ecc/circuit/src/ecc_extension.rs similarity index 54% rename from extensions/ecc/circuit/src/weierstrass_extension.rs rename to extensions/ecc/circuit/src/ecc_extension.rs index c5b23ccd0d..3ef635dc24 100644 --- a/extensions/ecc/circuit/src/weierstrass_extension.rs +++ b/extensions/ecc/circuit/src/ecc_extension.rs @@ -13,10 +13,11 @@ use openvm_circuit_primitives::bitwise_op_lookup::{ }; 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}, p256::{CURVE_A as P256_A, CURVE_B as P256_B, P256_MODULUS, P256_ORDER}, }; -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; @@ -25,17 +26,24 @@ use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; use strum::EnumCount; -use super::{EcAddNeChip, EcDoubleChip}; +use super::{SwAddNeChip, SwDoubleChip, TeAddChip}; #[serde_as] #[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] -pub struct CurveConfig { +pub struct CurveConfig { /// The coordinate modulus of the curve. #[serde_as(as = "DisplayFromStr")] pub modulus: BigUint, /// The scalar field modulus of the curve. #[serde_as(as = "DisplayFromStr")] pub scalar: BigUint, + // curve-specific coefficients + pub coeffs: T, +} + +#[serde_as] +#[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] +pub struct SwCurveCoeffs { /// The coefficient a of y^2 = x^3 + ax + b. #[serde_as(as = "DisplayFromStr")] pub a: BigUint, @@ -44,44 +52,73 @@ pub struct CurveConfig { pub b: BigUint, } -pub static SECP256K1_CONFIG: Lazy = Lazy::new(|| CurveConfig { +#[serde_as] +#[derive(Clone, Debug, derive_new::new, Serialize, Deserialize)] +pub struct TeCurveCoeffs { + /// 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 { modulus: SECP256K1_MODULUS.clone(), scalar: SECP256K1_ORDER.clone(), - a: BigUint::zero(), - b: BigUint::from_u8(7u8).unwrap(), + 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(), - a: BigUint::from_bytes_le(P256_A.as_le_bytes()), - b: BigUint::from_bytes_le(P256_B.as_le_bytes()), + 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 WeierstrassExtension { - pub supported_curves: Vec, +pub struct EccExtension { + pub supported_sw_curves: Vec>, + pub supported_te_curves: Vec>, } #[derive(Chip, ChipUsageGetter, InstructionExecutor, AnyEnum)] -pub enum WeierstrassExtensionExecutor { +pub enum EccExtensionExecutor { + // 32 limbs prime + SwEcAddNeRv32_32(SwAddNeChip), + SwEcDoubleRv32_32(SwDoubleChip), + // 48 limbs prime + SwEcAddNeRv32_48(SwAddNeChip), + SwEcDoubleRv32_48(SwDoubleChip), // 32 limbs prime - EcAddNeRv32_32(EcAddNeChip), - EcDoubleRv32_32(EcDoubleChip), + TeEcAddRv32_32(TeAddChip), // 48 limbs prime - EcAddNeRv32_48(EcAddNeChip), - EcDoubleRv32_48(EcDoubleChip), + TeEcAddRv32_48(TeAddChip), } #[derive(ChipUsageGetter, Chip, AnyEnum, From)] -pub enum WeierstrassExtensionPeriphery { +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, @@ -107,14 +144,16 @@ 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) - ..=(Rv32WeierstrassOpcode::SETUP_EC_ADD_NE as usize); - let ec_double_opcodes = (Rv32WeierstrassOpcode::EC_DOUBLE as usize) - ..=(Rv32WeierstrassOpcode::SETUP_EC_DOUBLE as usize); - - for (i, curve) in self.supported_curves.iter().enumerate() { - let start_offset = - Rv32WeierstrassOpcode::CLASS_OFFSET + i * Rv32WeierstrassOpcode::COUNT; + + 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::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); let config32 = ExprBuilderConfig { modulus: curve.modulus.clone(), @@ -126,8 +165,11 @@ impl VmExtension for WeierstrassExtension { 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 + sw_idx * Rv32WeierstrassOpcode::COUNT; if bytes <= 32 { - let add_ne_chip = EcAddNeChip::new( + let sw_add_ne_chip = SwAddNeChip::new( Rv32VecHeapAdapterChip::::new( execution_bus, program_bus, @@ -136,17 +178,17 @@ impl VmExtension for WeierstrassExtension { bitwise_lu_chip.clone(), ), config32.clone(), - start_offset, + sw_start_offset, range_checker.clone(), offline_memory.clone(), ); inventory.add_executor( - WeierstrassExtensionExecutor::EcAddNeRv32_32(add_ne_chip), - ec_add_ne_opcodes + EccExtensionExecutor::SwEcAddNeRv32_32(sw_add_ne_chip), + sw_add_ne_opcodes .clone() - .map(|x| VmOpcode::from_usize(x + start_offset)), + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), )?; - let double_chip = EcDoubleChip::new( + let sw_double_chip = SwDoubleChip::new( Rv32VecHeapAdapterChip::::new( execution_bus, program_bus, @@ -156,18 +198,18 @@ impl VmExtension for WeierstrassExtension { ), range_checker.clone(), config32.clone(), - start_offset, - curve.a.clone(), + sw_start_offset, + curve.coeffs.a.clone(), offline_memory.clone(), ); inventory.add_executor( - WeierstrassExtensionExecutor::EcDoubleRv32_32(double_chip), - ec_double_opcodes + EccExtensionExecutor::SwEcDoubleRv32_32(sw_double_chip), + sw_double_opcodes .clone() - .map(|x| VmOpcode::from_usize(x + start_offset)), + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), )?; } else if bytes <= 48 { - let add_ne_chip = EcAddNeChip::new( + let sw_add_ne_chip = SwAddNeChip::new( Rv32VecHeapAdapterChip::::new( execution_bus, program_bus, @@ -176,17 +218,17 @@ impl VmExtension for WeierstrassExtension { bitwise_lu_chip.clone(), ), config48.clone(), - start_offset, + sw_start_offset, range_checker.clone(), offline_memory.clone(), ); inventory.add_executor( - WeierstrassExtensionExecutor::EcAddNeRv32_48(add_ne_chip), - ec_add_ne_opcodes + EccExtensionExecutor::SwEcAddNeRv32_48(sw_add_ne_chip), + sw_add_ne_opcodes .clone() - .map(|x| VmOpcode::from_usize(x + start_offset)), + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), )?; - let double_chip = EcDoubleChip::new( + let sw_double_chip = SwDoubleChip::new( Rv32VecHeapAdapterChip::::new( execution_bus, program_bus, @@ -196,28 +238,100 @@ impl VmExtension for WeierstrassExtension { ), range_checker.clone(), config48.clone(), - start_offset, - curve.a.clone(), + sw_start_offset, + curve.coeffs.a.clone(), offline_memory.clone(), ); inventory.add_executor( - WeierstrassExtensionExecutor::EcDoubleRv32_48(double_chip), - ec_double_opcodes + EccExtensionExecutor::SwEcDoubleRv32_48(sw_double_chip), + sw_double_opcodes .clone() - .map(|x| VmOpcode::from_usize(x + start_offset)), + .map(|x| VmOpcode::from_usize(x + sw_start_offset)), )?; } else { panic!("Modulus too large"); } } - let non_qr_hint_sub_ex = phantom::NonQrHintSubEx::new(self.supported_curves.clone()); + + 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(), + num_limbs: 32, + limb_bits: 8, + }; + let config48 = ExprBuilderConfig { + modulus: curve.modulus.clone(), + num_limbs: 48, + limb_bits: 8, + }; + let te_start_offset = + Rv32EdwardsOpcode::CLASS_OFFSET + te_idx * Rv32EdwardsOpcode::COUNT; + if bytes <= 32 { + 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 { + 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"); + } + } + let sw_non_qr_hint_sub_ex = phantom::NonQrHintSubEx::new(self.supported_sw_curves.clone()); + builder.add_phantom_sub_executor( + sw_non_qr_hint_sub_ex.clone(), + PhantomDiscriminant(EccPhantom::SwHintNonQr as u16), + )?; + builder.add_phantom_sub_executor( + phantom::DecompressHintSubEx::new(sw_non_qr_hint_sub_ex), + PhantomDiscriminant(EccPhantom::SwHintDecompress as u16), + )?; + let te_non_qr_hint_sub_ex = phantom::NonQrHintSubEx::new(self.supported_te_curves.clone()); builder.add_phantom_sub_executor( - non_qr_hint_sub_ex.clone(), - PhantomDiscriminant(EccPhantom::HintNonQr as u16), + te_non_qr_hint_sub_ex.clone(), + PhantomDiscriminant(EccPhantom::TeHintNonQr as u16), )?; builder.add_phantom_sub_executor( - phantom::DecompressHintSubEx::new(non_qr_hint_sub_ex), - PhantomDiscriminant(EccPhantom::HintDecompress as u16), + phantom::DecompressHintSubEx::new(te_non_qr_hint_sub_ex), + PhantomDiscriminant(EccPhantom::TeHintDecompress as u16), )?; Ok(inventory) @@ -238,26 +352,26 @@ pub(crate) mod phantom { arch::{PhantomSubExecutor, Streams}, system::memory::MemoryController, }; - use openvm_ecc_guest::weierstrass::DecompressionHint; + use openvm_ecc_guest::DecompressionHint; 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 rand::{rngs::StdRng, SeedableRng}; - use super::CurveConfig; + use super::{CurveConfig, SwCurveCoeffs, TeCurveCoeffs}; #[derive(derive_new::new)] - pub struct DecompressHintSubEx(NonQrHintSubEx); + pub struct DecompressHintSubEx(NonQrHintSubEx); - impl Deref for DecompressHintSubEx { - type Target = NonQrHintSubEx; + impl Deref for DecompressHintSubEx { + type Target = NonQrHintSubEx; - fn deref(&self) -> &NonQrHintSubEx { + fn deref(&self) -> &NonQrHintSubEx { &self.0 } } - impl PhantomSubExecutor for DecompressHintSubEx { + impl PhantomSubExecutor for DecompressHintSubEx { fn phantom_execute( &mut self, memory: &MemoryController, @@ -315,7 +429,7 @@ pub(crate) mod phantom { } } - impl DecompressHintSubEx { + impl DecompressHintSubEx { /// Given `x` in the coordinate field of the 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. @@ -329,7 +443,8 @@ pub(crate) mod phantom { curve_idx: usize, ) -> DecompressionHint { let curve = &self.supported_curves[curve_idx]; - let alpha = ((&x * &x * &x) + (&x * &curve.a) + &curve.b) % &curve.modulus; + let alpha = + ((&x * &x * &x) + (&x * &curve.coeffs.a) + &curve.coeffs.b) % &curve.modulus; match mod_sqrt(&alpha, &curve.modulus, &self.non_qrs[curve_idx]) { Some(beta) => { if is_y_odd == beta.is_odd() { @@ -365,6 +480,119 @@ pub(crate) mod phantom { } } + 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 y_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), + ); + y_limbs.push(limb.as_canonical_u32() as u8); + } + let y = BigUint::from_bytes_le(&y_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(y, 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 { + /// Given `y` in the coordinate field of the curve, and the recovery id, + /// return the unique `x` such that `(x, y)` is a point on the curve and + /// `x` has the same parity as the recovery id. + /// + /// If no such `x` exists, return the square root of `(y^2 - 1) / (d * y^2 - a) * non_qr` + /// where `non_qr` is a quadratic nonresidue of the field. + fn decompress_point( + &self, + y: BigUint, + is_x_odd: bool, + curve_idx: usize, + ) -> DecompressionHint { + let curve = &self.supported_curves[curve_idx]; + let numerator = (&y * &y + &curve.modulus - 1u8) % &curve.modulus; + let denominator = + (&curve.coeffs.d * &y * &y + &curve.modulus - &curve.coeffs.a) % &curve.modulus; + let rhs = numerator * denominator.modinv(&curve.modulus).unwrap() % &curve.modulus; + match mod_sqrt(&rhs, &curve.modulus, &self.non_qrs[curve_idx]) { + Some(x) => { + if is_x_odd == x.is_odd() { + DecompressionHint { + possible: true, + sqrt: x, + } + } else if x > 0u8.into() { + DecompressionHint { + possible: true, + sqrt: &curve.modulus - &x, + } + } else { + panic!("invalid rec_id. expected 0 found 1"); + } + } + 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( + &(&rhs * &self.non_qrs[curve_idx]), + &curve.modulus, + &self.non_qrs[curve_idx], + ) + .unwrap(); + DecompressionHint { + possible: false, + sqrt, + } + } + } + } + } + /// Find the square root of `x` modulo `modulus` with `non_qr` a /// quadratic nonresidue of the field. pub fn mod_sqrt(x: &BigUint, modulus: &BigUint, non_qr: &BigUint) -> Option { @@ -421,13 +649,13 @@ pub(crate) mod phantom { } #[derive(Clone)] - pub struct NonQrHintSubEx { - pub supported_curves: Vec, + pub struct NonQrHintSubEx { + pub supported_curves: Vec>, pub non_qrs: Vec, } - impl NonQrHintSubEx { - pub fn new(supported_curves: Vec) -> Self { + impl NonQrHintSubEx { + pub fn new(supported_curves: Vec>) -> Self { let non_qrs = supported_curves .iter() .map(|curve| find_non_qr(&curve.modulus)) @@ -439,7 +667,7 @@ pub(crate) mod phantom { } } - impl PhantomSubExecutor for NonQrHintSubEx { + impl PhantomSubExecutor for NonQrHintSubEx { fn phantom_execute( &mut self, _: &MemoryController, 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..03c5e1253e --- /dev/null +++ b/extensions/ecc/circuit/src/edwards_chip/mod.rs @@ -0,0 +1,66 @@ +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; +use openvm_circuit_primitives_derive::{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; +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)] +pub struct TeAddChip( + pub VmChipWrapper< + F, + Rv32VecHeapAdapterChip, + FieldExpressionCoreChip, + >, +); + +impl + TeAddChip +{ + pub fn new( + adapter: Rv32VecHeapAdapterChip, + config: ExprBuilderConfig, + offset: usize, + a: BigUint, + d: BigUint, + range_checker: SharedVariableRangeCheckerChip, + offline_memory: Arc>>, + ) -> Self { + // Ensure that the addition operation is complete + 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( + expr, + offset, + vec![ + Rv32EdwardsOpcode::TE_ADD as usize, + Rv32EdwardsOpcode::SETUP_TE_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..2d3c432d9b --- /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::TeAddChip; + +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 = TeAddChip::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_TE_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::TE_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/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/lib.rs b/extensions/ecc/circuit/src/lib.rs index c1ec864636..050bf57a3b 100644 --- a/extensions/ecc/circuit/src/lib.rs +++ b/extensions/ecc/circuit/src/lib.rs @@ -1,8 +1,11 @@ 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::*; mod config; pub use config::*; 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 1738c69556..923dbdf93a 100644 --- a/extensions/ecc/circuit/src/weierstrass_chip/mod.rs +++ b/extensions/ecc/circuit/src/weierstrass_chip/mod.rs @@ -26,7 +26,7 @@ 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 struct SwAddNeChip( pub VmChipWrapper< F, Rv32VecHeapAdapterChip, @@ -35,7 +35,7 @@ pub struct EcAddNeChip - EcAddNeChip + SwAddNeChip { pub fn new( adapter: Rv32VecHeapAdapterChip, @@ -44,13 +44,13 @@ 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, 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, @@ -62,7 +62,7 @@ impl } #[derive(Chip, ChipUsageGetter, InstructionExecutor)] -pub struct EcDoubleChip( +pub struct SwDoubleChip( pub VmChipWrapper< F, Rv32VecHeapAdapterChip, @@ -71,7 +71,7 @@ pub struct EcDoubleChip - EcDoubleChip + SwDoubleChip { pub fn new( adapter: Rv32VecHeapAdapterChip, @@ -81,13 +81,13 @@ 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, 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 751d351200..52f90a0499 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, @@ -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); @@ -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, @@ -194,7 +194,7 @@ fn test_double() { &mut tester, 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); @@ -202,7 +202,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); @@ -250,7 +250,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, @@ -282,7 +282,7 @@ fn test_p256_double() { &mut tester, 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); @@ -290,7 +290,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/guest/Cargo.toml b/extensions/ecc/guest/Cargo.toml index dbc1749fc2..34b89278ed 100644 --- a/extensions/ecc/guest/Cargo.toml +++ b/extensions/ecc/guest/Cargo.toml @@ -20,7 +20,9 @@ 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 } openvm-algebra-moduli-macros = { workspace = true } +num-bigint = { workspace = true } once_cell = { workspace = true, features = ["race", "alloc"] } # Used for `halo2curves` feature @@ -38,6 +40,7 @@ default = [] # only enable for the curves you use as it affects the init! macro k256 = ["dep:k256"] p256 = ["dep:p256"] +ed25519 = [] halo2curves = ["dep:halo2curves-axiom", "openvm-algebra-guest/halo2curves"] [package.metadata.cargo-shear] diff --git a/extensions/ecc/guest/src/ecdsa.rs b/extensions/ecc/guest/src/ecdsa.rs index ebcf975f08..86adb4a105 100644 --- a/extensions/ecc/guest/src/ecdsa.rs +++ b/extensions/ecc/guest/src/ecdsa.rs @@ -5,10 +5,7 @@ use ecdsa::{self, hazmat::bits2field, Error, RecoveryId, Result}; use elliptic_curve::{sec1::Tag, PrimeCurve}; use openvm_algebra_guest::{DivUnsafe, IntMod, Reduce}; -use crate::{ - weierstrass::{FromCompressed, IntrinsicCurve, WeierstrassPoint}, - CyclicGroup, Group, -}; +use crate::{weierstrass::WeierstrassPoint, CyclicGroup, FromCompressed, Group, IntrinsicCurve}; pub type Coordinate = <::Point as WeierstrassPoint>::Coordinate; pub type Scalar = ::Scalar; diff --git a/extensions/ecc/guest/src/ed25519.rs b/extensions/ecc/guest/src/ed25519.rs new file mode 100644 index 0000000000..e05a619f00 --- /dev/null +++ b/extensions/ecc/guest/src/ed25519.rs @@ -0,0 +1,112 @@ +use core::ops::Add; + +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}; +use crate::{edwards::CachedMulTable, IntrinsicCurve}; + +#[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_macros::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_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 { + x: Ed25519Coord::from_const_bytes(hex!( + "1AD5258F602D56C9B2A7259560C72C695CDCD6FD31E2A4C0FE536ECDD3366921" + )), + y: Ed25519Coord::from_const_bytes(hex!( + "5866666666666666666666666666666666666666666666666666666666666666" + )), + }; + const NEG_GENERATOR: Self = Ed25519Point { + 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" + )), + }; +} + +/* +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; + + 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 new file mode 100644 index 0000000000..88ffc9c084 --- /dev/null +++ b/extensions/ecc/guest/src/edwards.rs @@ -0,0 +1,385 @@ +use alloc::vec::Vec; +use core::ops::{AddAssign, Mul}; + +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`. + 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: Field; + + /// 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>, + { + let lhs = Self::CURVE_A * &x * &x + &y * &y; + let rhs = Self::CURVE_D * &x * &x * &y * &y + &Self::Coordinate::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); + } + } + }; +} + +// 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 + } +} diff --git a/extensions/ecc/guest/src/k256.rs b/extensions/ecc/guest/src/k256.rs index a3e63985ba..10372caf93 100644 --- a/extensions/ecc/guest/src/k256.rs +++ b/extensions/ecc/guest/src/k256.rs @@ -12,7 +12,7 @@ use openvm_algebra_moduli_macros::moduli_declare; use openvm_ecc_sw_macros::sw_declare; use super::group::{CyclicGroup, Group}; -use crate::weierstrass::{CachedMulTable, IntrinsicCurve}; +use crate::{weierstrass::CachedMulTable, 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 e780ccf891..0d76cf3d7b 100644 --- a/extensions/ecc/guest/src/lib.rs +++ b/extensions/ecc/guest/src/lib.rs @@ -8,6 +8,7 @@ pub use halo2curves_axiom as halo2curves; 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; @@ -19,6 +20,8 @@ pub use msm::*; /// ECDSA pub mod ecdsa; +/// Edwards curve traits +pub mod edwards; /// Weierstrass curve traits pub mod weierstrass; @@ -30,11 +33,14 @@ pub mod k256; #[cfg(feature = "p256")] pub mod p256; +#[cfg(feature = "ed25519")] +pub mod ed25519; + #[cfg(all(test, feature = "k256", feature = "p256", not(target_os = "zkvm")))] mod tests; /// 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. @@ -45,10 +51,81 @@ pub enum SwBaseFunct7 { SwAddNe = 0, SwDouble, SwSetup, - HintDecompress, - HintNonQr, + SwHintDecompress, + SwHintNonQr, } 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, + TeHintDecompress, + TeHintNonQr, +} + +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; +} + +// Hint for a decompression +// For short Weierstrass curves, +// - if possible is true, then `sqrt` is the decompressed y-coordinate +// - if possible is false, then `sqrt` is such that `sqrt^2 = (x^3 + a * x + b) * non_qr` +// For twisted Edwards curves, +// - if possible is true, then `sqrt` is the decompressed x-coordinate +// - if possible is false, then `sqrt` is such that `(d * y^2 - a) * x^2 = (y^2 - 1) * non_qr` +pub struct DecompressionHint { + pub possible: bool, + pub sqrt: T, +} + +pub trait FromCompressed { + /// For short Weierstrass curves, first parameter is the `x`-coordinate, for twisted Edwards curves, + /// it is the `y`-coordinate. + /// + /// Decompresses a point from its `x_or_y`-coordinate and a recovery identifier which indicates + /// the parity of the other coordinate. Given the `x_or_y`-coordinate, this function attempts to find the + /// corresponding `other_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_or_y: Coordinate, rec_id: &u8) -> Option + where + Self: core::marker::Sized; + + /// For short Weierstrass curves, first parameter is the `x`-coordinate, for twisted Edwards curves, + /// it is the `y`-coordinate. + /// + /// If it exists, hints the unique other coordinate `y_or_x` that is less than `Coordinate::MODULUS` + /// such that `x_or_y` along with `y_or_x` is a point on the curve and `y_or_x` has parity equal to `rec_id`. + /// If such `y_or_x` does not exist: + /// - for short Weierstrass curves, hints a coordinate `sqrt` such that `sqrt^2 = (x^3 + a * x + b) * non_qr` + /// - for twisted Edwards curves, hints a coordinate `sqrt` such that `(d * y^2 - a) * x^2 = (y^2 - 1) * non_qr` + /// + /// where `non_qr` is the non-quadratic residue for this curve that was initialized in the setup function. + /// + /// This is only a hint, and the returned value does not guarantee any of the above properties. + /// They must be checked separately. Normal users should use `decompress` directly. + /// + /// Returns None if the `DecompressionHint::possible` flag in the hint stream is not a boolean. + fn hint_decompress(x_or_y: &Coordinate, rec_id: &u8) -> Option>; +} diff --git a/extensions/ecc/guest/src/p256.rs b/extensions/ecc/guest/src/p256.rs index 6bbe4ab718..503d5819d8 100644 --- a/extensions/ecc/guest/src/p256.rs +++ b/extensions/ecc/guest/src/p256.rs @@ -8,7 +8,7 @@ use num_bigint::BigUint; use openvm_algebra_guest::{Field, IntMod}; use super::group::{CyclicGroup, Group}; -use crate::weierstrass::{CachedMulTable, IntrinsicCurve}; +use crate::{weierstrass::CachedMulTable, IntrinsicCurve}; #[cfg(not(target_os = "zkvm"))] lazy_static! { diff --git a/extensions/ecc/guest/src/weierstrass.rs b/extensions/ecc/guest/src/weierstrass.rs index 81672fbfb4..28ba92057c 100644 --- a/extensions/ecc/guest/src/weierstrass.rs +++ b/extensions/ecc/guest/src/weierstrass.rs @@ -4,6 +4,7 @@ use core::ops::{AddAssign, Mul}; use openvm_algebra_guest::{Field, IntMod}; use super::group::Group; +use crate::IntrinsicCurve; /// Short Weierstrass curve affine point. pub trait WeierstrassPoint: Sized { @@ -67,51 +68,6 @@ pub trait WeierstrassPoint: Sized { } } -// 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, -} - -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; - - /// 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, hints a coordinate `sqrt` such that `sqrt^2 = rhs * non_qr` - /// where `rhs` is the rhs of the curve equation and `non_qr` is the non-quadratic residue - /// for this curve that was initialized in the setup function. - /// - /// This is only a hint, and the returned value does not guarantee any of the above properties. - /// They must be checked separately. Normal users should use `decompress` directly. - /// - /// Returns None if the `DecompressionHint::possible` flag in the hint stream is not a boolean. - fn hint_decompress(x: &Coordinate, rec_id: &u8) -> Option>; -} - -/// 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/extensions/ecc/sw-macros/README.md b/extensions/ecc/sw-macros/README.md index 5c247959f1..9a9d4d3500 100644 --- a/extensions/ecc/sw-macros/README.md +++ b/extensions/ecc/sw-macros/README.md @@ -31,7 +31,7 @@ openvm_ecc_guest::sw_macros::sw_init! { pub fn main() { setup_all_moduli(); - setup_all_curves(); + setup_all_sw_curves(); // ... } ``` @@ -87,13 +87,13 @@ pub fn setup_sw_Secp256k1Point() { // ... } } -pub fn setup_all_curves() { +pub fn setup_all_sw_curves() { setup_sw_Secp256k1Point(); // 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_curves()` to setup all of them. +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_sw_curves()` to setup all of them. 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). diff --git a/extensions/ecc/sw-macros/src/lib.rs b/extensions/ecc/sw-macros/src/lib.rs index dbf8117bac..60518d5cba 100644 --- a/extensions/ecc/sw-macros/src/lib.rs +++ b/extensions/ecc/sw-macros/src/lib.rs @@ -83,7 +83,7 @@ pub fn sw_declare(input: TokenStream) -> TokenStream { } create_extern_func!(sw_add_ne_extern_func); create_extern_func!(sw_double_extern_func); - create_extern_func!(hint_decompress_extern_func); + create_extern_func!(sw_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()); @@ -92,7 +92,7 @@ pub fn sw_declare(input: TokenStream) -> TokenStream { extern "C" { fn #sw_add_ne_extern_func(rd: usize, rs1: usize, rs2: usize); fn #sw_double_extern_func(rd: usize, rs1: usize); - fn #hint_decompress_extern_func(rs1: usize, rs2: usize); + fn #sw_hint_decompress_extern_func(rs1: usize, rs2: usize); fn #hint_non_qr_extern_func(); } @@ -289,7 +289,7 @@ pub fn sw_declare(input: TokenStream) -> TokenStream { } mod #group_ops_mod_name { - use ::openvm_ecc_guest::{weierstrass::{WeierstrassPoint, FromCompressed, DecompressionHint}, impl_sw_group_ops, algebra::{IntMod, DivUnsafe, DivAssignUnsafe, ExpBytes}}; + use ::openvm_ecc_guest::{weierstrass::WeierstrassPoint, FromCompressed, DecompressionHint, impl_sw_group_ops, algebra::{IntMod, DivUnsafe, DivAssignUnsafe, ExpBytes}}; use super::*; impl_sw_group_ops!(#struct_name, #intmod_type); @@ -317,12 +317,12 @@ pub fn sw_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 possible = core::mem::MaybeUninit::::uninit(); let sqrt = core::mem::MaybeUninit::<#intmod_type>::uninit(); unsafe { - #hint_decompress_extern_func(x as *const _ as usize, rec_id as *const u8 as usize); + #sw_hint_decompress_extern_func(x 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); @@ -443,7 +443,7 @@ pub fn sw_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_sw_curves = Vec::new(); let span = proc_macro::Span::call_site(); @@ -458,8 +458,8 @@ pub fn sw_init(input: TokenStream) -> TokenStream { syn::Ident::new(&format!("sw_add_ne_extern_func_{}", str_path), span.into()); let double_extern_func = syn::Ident::new(&format!("sw_double_extern_func_{}", str_path), span.into()); - let hint_decompress_extern_func = syn::Ident::new( - &format!("hint_decompress_extern_func_{}", str_path), + let sw_hint_decompress_extern_func = syn::Ident::new( + &format!("sw_hint_decompress_extern_func_{}", str_path), span.into(), ); let hint_non_qr_extern_func = syn::Ident::new( @@ -470,7 +470,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), @@ -483,7 +483,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), @@ -494,11 +494,11 @@ pub fn sw_init(input: TokenStream) -> TokenStream { } #[no_mangle] - extern "C" fn #hint_decompress_extern_func(rs1: usize, rs2: usize) { + extern "C" fn #sw_hint_decompress_extern_func(rs1: usize, rs2: usize) { openvm::platform::custom_insn_r!( - opcode = OPCODE, + opcode = SW_OPCODE, funct3 = SW_FUNCT3 as usize, - funct7 = SwBaseFunct7::HintDecompress as usize + #ec_idx + funct7 = SwBaseFunct7::SwHintDecompress as usize + #ec_idx * (SwBaseFunct7::SHORT_WEIERSTRASS_MAX_KINDS as usize), rd = Const "x0", rs1 = In rs1, @@ -509,9 +509,9 @@ pub fn sw_init(input: TokenStream) -> TokenStream { #[no_mangle] extern "C" fn #hint_non_qr_extern_func() { openvm::platform::custom_insn_r!( - opcode = OPCODE, + opcode = SW_OPCODE, funct3 = SW_FUNCT3 as usize, - funct7 = SwBaseFunct7::HintNonQr as usize + #ec_idx + funct7 = SwBaseFunct7::SwHintNonQr as usize + #ec_idx * (SwBaseFunct7::SHORT_WEIERSTRASS_MAX_KINDS as usize), rd = Const "x0", rs1 = Const "x0", @@ -538,7 +538,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 @@ -548,7 +548,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 @@ -561,21 +561,21 @@ pub fn sw_init(input: TokenStream) -> TokenStream { } }); - setup_all_curves.push(quote::quote_spanned! { span.into() => + setup_all_sw_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::{OPCODE, SW_FUNCT3, SwBaseFunct7}; + mod openvm_intrinsics_ffi_2_sw { + use ::openvm_ecc_guest::{SW_OPCODE, SW_FUNCT3, SwBaseFunct7}; #(#externs)* } #(#setups)* - pub fn setup_all_curves() { - #(#setup_all_curves)* + pub fn setup_all_sw_curves() { + #(#setup_all_sw_curves)* } }) } diff --git a/extensions/ecc/te-macros/Cargo.toml b/extensions/ecc/te-macros/Cargo.toml new file mode 100644 index 0000000000..de3544ff87 --- /dev/null +++ b/extensions/ecc/te-macros/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "openvm-ecc-te-macros" +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 } + +[lib] +proc-macro = true 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`. diff --git a/extensions/ecc/te-macros/src/lib.rs b/extensions/ecc/te-macros/src/lib.rs new file mode 100644 index 0000000000..11e1f6adc9 --- /dev/null +++ b/extensions/ecc/te-macros/src/lib.rs @@ -0,0 +1,468 @@ +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); + 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()); + + 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(); + } + + #[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"))] + { + use openvm_algebra_guest::DivUnsafe; + + 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 - ::CURVE_A * x1x2).div_unsafe(&<#intmod_type as openvm_algebra_guest::IntMod>::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, FromCompressed, DecompressionHint, 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() }) + } 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); + 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) + } + } + } + }); + 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_te_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()); + 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(), + ); + 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 + ); + } + + #[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() { + #[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_te_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_te { + use ::openvm_ecc_guest::{TE_OPCODE, TE_FUNCT3, TeBaseFunct7}; + + #(#externs)* + } + #(#setups)* + pub fn setup_all_te_curves() { + #(#setup_all_te_curves)* + } + }) +} diff --git a/extensions/ecc/tests/Cargo.toml b/extensions/ecc/tests/Cargo.toml index 9a743ac00b..bea9a756c8 100644 --- a/extensions/ecc/tests/Cargo.toml +++ b/extensions/ecc/tests/Cargo.toml @@ -21,8 +21,9 @@ openvm-keccak256-transpiler.workspace = true openvm-toolchain-tests = { path = "../../../crates/toolchain/tests" } openvm-sdk.workspace = true eyre.workspace = true -hex-literal.workspace = true num-bigint.workspace = true +hex-literal.workspace = true + [features] default = ["parallel"] parallel = ["openvm-circuit/parallel"] diff --git a/extensions/ecc/tests/programs/Cargo.toml b/extensions/ecc/tests/programs/Cargo.toml index ccc3ba7387..7ce8566511 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-keccak256-guest = { path = "../../../keccak256/guest", default-features = false } @@ -26,6 +27,7 @@ k256 = { version = "0.13.3", default-features = false, features = [ "ecdsa-core", "ecdsa", ], optional = true } +num-bigint = "0.4.6" [target.'cfg(not(target_os = "zkvm"))'.dependencies] num-bigint = "0.4.6" @@ -35,6 +37,7 @@ default = [] std = ["serde/std", "openvm/std"] k256 = ["openvm-ecc-guest/k256", "dep:k256"] p256 = ["openvm-ecc-guest/p256"] +ed25519 = ["openvm-ecc-guest/ed25519"] # Features to enable specific tests within decompress_invalid_hint.rs # Note that these tests are expected to not terminate @@ -64,7 +67,7 @@ required-features = ["k256", "p256"] [[example]] name = "decompress" -required-features = ["k256"] +required-features = ["k256", "ed25519"] [[example]] name = "decompress_invalid_hint" @@ -74,6 +77,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/decompress.rs b/extensions/ecc/tests/programs/examples/decompress.rs index f47b7a05e0..bc17a241a5 100644 --- a/extensions/ecc/tests/programs/examples/decompress.rs +++ b/extensions/ecc/tests/programs/examples/decompress.rs @@ -7,10 +7,12 @@ 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}, - weierstrass::{FromCompressed, WeierstrassPoint}, - Group, + weierstrass::WeierstrassPoint, + FromCompressed, Group, }; openvm::entry!(main); @@ -29,6 +31,7 @@ openvm_algebra_moduli_macros::moduli_init! { "1000000007", "0xffffffffffffffffffffffffffffffff000000000000000000000001", "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d", + "57896044618658097711785492504343953926634992332820282019728792003956564819949", } const CURVE_B_5MOD8: Fp5mod8 = Fp5mod8::from_const_u8(3); @@ -88,19 +91,26 @@ openvm_ecc_sw_macros::sw_init! { CurvePoint1mod4, } +openvm_ecc_te_macros::te_init! { + Ed25519Point, +} + // test decompression under an honest host pub fn main() { setup_0(); setup_2(); setup_4(); - setup_all_curves(); + setup_all_sw_curves(); + setup_all_te_curves(); 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; - 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_secp256k1(&Secp256k1Coord::from_u8(5), rec_id); @@ -108,7 +118,7 @@ pub fn main() { 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_curvepoint5mod8(&Fp5mod8::from_u8(3), rec_id); @@ -116,12 +126,20 @@ pub fn main() { 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_curvepoint1mod4(&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; + 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_decompression_ed25519(&Ed25519Coord::from_u8(2), rec_id); } -fn test_possible_decompression>( +fn test_possible_sw_decompression>( x: &P::Coordinate, y: &P::Coordinate, rec_id: u8, @@ -138,24 +156,26 @@ fn test_possible_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 { - panic!("decompression should be impossible"); + assert_eq!(x, &hint.sqrt); } else { - let rhs = x * x * x - + x * &::CURVE_A - + &::CURVE_B; - assert_eq!(&hint.sqrt * &hint.sqrt, rhs * CurvePoint5mod8::get_non_qr()); + panic!("decompression should be possible"); } - let p = CurvePoint5mod8::decompress(x.clone(), &rec_id); - assert!(p.is_none()); + let p = P::decompress(y.clone(), &rec_id).unwrap(); + assert_eq!(p.x(), x); + assert_eq!(p.y(), y); } +// The test_impossible_decompression_* functions cannot be combined into a single function with a const generic parameter +// since the get_non_qr() function is not part of the WeierstrassPoint trait. + fn test_impossible_decompression_secp256k1(x: &Secp256k1Coord, rec_id: u8) { let hint = Secp256k1Point::hint_decompress(x, &rec_id).expect("hint should be well-formed"); if hint.possible { @@ -171,6 +191,21 @@ fn test_impossible_decompression_secp256k1(x: &Secp256k1Coord, rec_id: u8) { assert!(p.is_none()); } +fn test_impossible_decompression_curvepoint5mod8(x: &Fp5mod8, rec_id: u8) { + let hint = CurvePoint5mod8::hint_decompress(x, &rec_id).expect("hint should be well-formed"); + if hint.possible { + panic!("decompression should be impossible"); + } else { + let rhs = x * x * x + + x * &::CURVE_A + + &::CURVE_B; + assert_eq!(&hint.sqrt * &hint.sqrt, rhs * CurvePoint5mod8::get_non_qr()); + } + + let p = CurvePoint5mod8::decompress(x.clone(), &rec_id); + assert!(p.is_none()); +} + fn test_impossible_decompression_curvepoint1mod4(x: &Fp1mod4, rec_id: u8) { let hint = CurvePoint1mod4::hint_decompress(x, &rec_id).expect("hint should be well-formed"); if hint.possible { @@ -185,3 +220,19 @@ fn test_impossible_decompression_curvepoint1mod4(x: &Fp1mod4, rec_id: u8) { let p = CurvePoint1mod4::decompress(x.clone(), &rec_id); assert!(p.is_none()); } + +fn test_impossible_decompression_ed25519(y: &Ed25519Coord, rec_id: u8) { + let hint = Ed25519Point::hint_decompress(y, &rec_id).expect("hint should be well-formed"); + if hint.possible { + panic!("decompression should be impossible"); + } else { + let num = y * y - &::ONE; + let den = &::CURVE_D * y * y + - &::CURVE_A; + let rhs = num.div_unsafe(den); + assert_eq!(&hint.sqrt * &hint.sqrt, rhs * Ed25519Point::get_non_qr()); + } + + let p = Ed25519Point::decompress(y.clone(), &rec_id); + assert!(p.is_none()); +} diff --git a/extensions/ecc/tests/programs/examples/decompress_invalid_hint.rs b/extensions/ecc/tests/programs/examples/decompress_invalid_hint.rs index b73e068132..5891f8509f 100644 --- a/extensions/ecc/tests/programs/examples/decompress_invalid_hint.rs +++ b/extensions/ecc/tests/programs/examples/decompress_invalid_hint.rs @@ -9,8 +9,8 @@ use openvm::io::read_vec; use openvm_ecc_guest::{ algebra::{Field, IntMod}, k256::{Secp256k1Coord, Secp256k1Point}, - weierstrass::{DecompressionHint, FromCompressed, WeierstrassPoint}, - Group, + weierstrass::WeierstrassPoint, + DecompressionHint, FromCompressed, Group, }; openvm::entry!(main); @@ -208,7 +208,7 @@ pub fn main() { setup_0(); setup_2(); setup_4(); - setup_all_curves(); + setup_all_sw_curves(); let bytes = read_vec(); diff --git a/extensions/ecc/tests/programs/examples/ec.rs b/extensions/ecc/tests/programs/examples/ec.rs index cb4f63e62a..788ecd453d 100644 --- a/extensions/ecc/tests/programs/examples/ec.rs +++ b/extensions/ecc/tests/programs/examples/ec.rs @@ -2,8 +2,8 @@ #![cfg_attr(not(feature = "std"), no_std)] use hex_literal::hex; -use openvm_algebra_guest::IntMod; use openvm_ecc_guest::{ + algebra::IntMod, k256::{Secp256k1Coord, Secp256k1Point, Secp256k1Scalar}, msm, weierstrass::WeierstrassPoint, @@ -23,7 +23,7 @@ openvm::entry!(main); pub fn main() { setup_all_moduli(); - setup_all_curves(); + setup_all_sw_curves(); // Sample points got from https://asecuritysite.com/ecc/ecc_points2 and // https://learnmeabitcoin.com/technical/cryptography/elliptic-curve/#add diff --git a/extensions/ecc/tests/programs/examples/ec_nonzero_a.rs b/extensions/ecc/tests/programs/examples/ec_nonzero_a.rs index 18720e1ae1..b0d1a24bb4 100644 --- a/extensions/ecc/tests/programs/examples/ec_nonzero_a.rs +++ b/extensions/ecc/tests/programs/examples/ec_nonzero_a.rs @@ -2,8 +2,8 @@ #![cfg_attr(not(feature = "std"), no_std)] use hex_literal::hex; -use openvm_algebra_guest::IntMod; use openvm_ecc_guest::{ + algebra::IntMod, p256::{P256Coord, P256Point}, weierstrass::WeierstrassPoint, CyclicGroup, Group, @@ -22,7 +22,7 @@ openvm_ecc_sw_macros::sw_init! { pub fn main() { setup_all_moduli(); - setup_all_curves(); + setup_all_sw_curves(); // Sample points got from https://asecuritysite.com/ecc/p256p let x1 = P256Coord::from_u32(5); diff --git a/extensions/ecc/tests/programs/examples/ec_two_curves.rs b/extensions/ecc/tests/programs/examples/ec_two_curves.rs index ab96e9d240..0c526367ac 100644 --- a/extensions/ecc/tests/programs/examples/ec_two_curves.rs +++ b/extensions/ecc/tests/programs/examples/ec_two_curves.rs @@ -2,8 +2,8 @@ #![cfg_attr(not(feature = "std"), no_std)] use hex_literal::hex; -use openvm_algebra_guest::IntMod; use openvm_ecc_guest::{ + algebra::IntMod, k256::{Secp256k1Coord, Secp256k1Point, Secp256k1Scalar}, msm, p256::{P256Coord, P256Point}, @@ -27,7 +27,7 @@ openvm::entry!(main); pub fn main() { setup_all_moduli(); - setup_all_curves(); + setup_all_sw_curves(); // Sample points got from https://asecuritysite.com/ecc/ecc_points2 and // https://learnmeabitcoin.com/technical/cryptography/elliptic-curve/#add diff --git a/extensions/ecc/tests/programs/examples/ecdsa.rs b/extensions/ecc/tests/programs/examples/ecdsa.rs index 3fc3c12f4e..48cee1ea28 100644 --- a/extensions/ecc/tests/programs/examples/ecdsa.rs +++ b/extensions/ecc/tests/programs/examples/ecdsa.rs @@ -26,7 +26,7 @@ openvm_ecc_sw_macros::sw_init! { // Ref: https://docs.rs/k256/latest/k256/ecdsa/index.html pub fn main() { setup_all_moduli(); - setup_all_curves(); + setup_all_sw_curves(); let msg = b"example message"; 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..06ff06c523 --- /dev/null +++ b/extensions/ecc/tests/programs/examples/edwards_ec.rs @@ -0,0 +1,73 @@ +#![cfg_attr(not(feature = "std"), no_main)] +#![cfg_attr(not(feature = "std"), no_std)] + +use hex_literal::hex; +use openvm_algebra_guest::moduli_macros::moduli_init; +use openvm_ecc_guest::{ + algebra::IntMod, + ed25519::{Ed25519Coord, Ed25519Point}, + edwards::TwistedEdwardsPoint, + te_macros::te_init, + CyclicGroup, Group, +}; + +moduli_init! { + "57896044618658097711785492504343953926634992332820282019728792003956564819949", +} + +te_init! { + Ed25519Point, +} + +openvm::entry!(main); + +pub fn main() { + setup_all_moduli(); + setup_all_te_curves(); + + // Base point of edwards25519 + let mut p1 = Ed25519Point::GENERATOR; + + // random point on edwards25519 + 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 = Ed25519Coord::from_be_bytes(&hex!( + "636C0B519B2C5B1E0D3BFD213F45AFD5DAEE3CECC9B68CF88615101BC78329E6" + )); + let y3 = Ed25519Coord::from_be_bytes(&hex!( + "704D8868CB335A7B609D04B9CD619511675691A78861F1DFF7A5EBC389C7EA92" + )); + + // This is 2 * (x1, y1) + 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; + 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/programs/examples/invalid_setup.rs b/extensions/ecc/tests/programs/examples/invalid_setup.rs index 9c6e8a3a51..9544ca19c3 100644 --- a/extensions/ecc/tests/programs/examples/invalid_setup.rs +++ b/extensions/ecc/tests/programs/examples/invalid_setup.rs @@ -22,5 +22,5 @@ openvm::entry!(main); pub fn main() { setup_all_moduli(); // this should cause a debug assertion to fail - setup_all_curves(); + setup_all_sw_curves(); } diff --git a/extensions/ecc/tests/src/lib.rs b/extensions/ecc/tests/src/lib.rs index 6d90241156..5a4be9c223 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, EccExtension, Rv32EccConfig, SwCurveCoeffs, ED25519_CONFIG, P256_CONFIG, + SECP256K1_CONFIG, }; use openvm_ecc_transpiler::EccTranspilerExtension; use openvm_keccak256_transpiler::Keccak256TranspilerExtension; @@ -38,7 +39,7 @@ mod tests { .with_extension(EccTranspilerExtension) .with_extension(ModularTranspilerExtension), )?; - let config = Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone()], vec![]); air_test(config, openvm_exe); Ok(()) } @@ -59,7 +60,7 @@ mod tests { .with_extension(EccTranspilerExtension) .with_extension(ModularTranspilerExtension), )?; - let config = Rv32WeierstrassConfig::new(vec![P256_CONFIG.clone()]); + let config = Rv32EccConfig::new(vec![P256_CONFIG.clone()], vec![]); air_test(config, openvm_exe); Ok(()) } @@ -81,19 +82,21 @@ mod tests { .with_extension(ModularTranspilerExtension), )?; 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); Ok(()) } #[test] fn test_decompress() -> Result<()> { - use openvm_ecc_guest::halo2curves::{group::Curve, secp256k1::Secp256k1Affine}; + use openvm_ecc_guest::halo2curves::{ + ed25519::Ed25519Affine, group::Curve, secp256k1::Secp256k1Affine, + }; let elf = build_example_program_at_path_with_features( get_programs_dir!(), "decompress", - ["k256"], + ["k256", "ed25519"], )?; let openvm_exe = VmExe::from_elf( elf, @@ -105,31 +108,34 @@ mod tests { .with_extension(ModularTranspilerExtension), )?; let config = - Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone(), + Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone(), CurveConfig { modulus: BigUint::from_str("115792089237316195423570985008687907853269984665640564039457584007913129639501") .unwrap(), // unused, set to 10e9 + 7 scalar: BigUint::from_str("1000000007") .unwrap(), - a: BigUint::ZERO, - b: BigUint::from_str("3").unwrap(), + coeffs: SwCurveCoeffs { + a: BigUint::ZERO, + b: BigUint::from_str("3").unwrap(), + }, }, CurveConfig { modulus: BigUint::from_radix_be(&hex!("ffffffffffffffffffffffffffffffff000000000000000000000001"), 256) .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: SwCurveCoeffs { + a: BigUint::from_radix_be(&hex!("fffffffffffffffffffffffffffffffefffffffffffffffffffffffe"), 256) + .unwrap(), + b: BigUint::from_radix_be(&hex!("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"), 256) + .unwrap(), + }, }, - ]); + ], vec![ED25519_CONFIG.clone()]); let p = Secp256k1Affine::generator(); let p = (p + p + p).to_affine(); - println!("decompressed: {:?}", p); let q_x: [u8; 32] = hex!("0100000000000000000000000000000000000000000000000000000000000000"); let q_y: [u8; 32] = @@ -138,18 +144,32 @@ mod tests { hex!("211D5C11D68032342211C256D3C1034AB99013327FBFB46BBD0C0EB700000000"); let r_y: [u8; 32] = hex!("347E00859981D5446447075AA07543CDE6DF224CFB23F7B5886337BD00000000"); + let s = Ed25519Affine::generator(); + let s = (s + s + s).to_affine(); + println!("s: {:?}", s); - let coords = [p.x.to_bytes(), p.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(); air_test_with_min_segments(config, openvm_exe, vec![coords], 1); Ok(()) } fn test_decompress_invalid_specific_test(test_type: &str) -> Result<()> { - use openvm_ecc_guest::halo2curves::{group::Curve, secp256k1::Secp256k1Affine}; + use openvm_ecc_guest::halo2curves::{ + ed25519::Ed25519Affine, group::Curve, secp256k1::Secp256k1Affine, + }; let elf = build_example_program_at_path_with_features( get_programs_dir!(), @@ -166,31 +186,35 @@ mod tests { .with_extension(ModularTranspilerExtension), )?; let config = - Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone(), + Rv32EccConfig::new(vec![SECP256K1_CONFIG.clone(), CurveConfig { modulus: BigUint::from_str("115792089237316195423570985008687907853269984665640564039457584007913129639501") .unwrap(), // unused, set to 10e9 + 7 scalar: BigUint::from_str("1000000007") .unwrap(), - a: BigUint::ZERO, - b: BigUint::from_str("3").unwrap(), + coeffs: SwCurveCoeffs { + a: BigUint::ZERO, + b: BigUint::from_str("3").unwrap(), + }, }, CurveConfig { modulus: BigUint::from_radix_be(&hex!("ffffffffffffffffffffffffffffffff000000000000000000000001"), 256) .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: SwCurveCoeffs { + a: BigUint::from_radix_be(&hex!("fffffffffffffffffffffffffffffffefffffffffffffffffffffffe"), 256) + .unwrap(), + b: BigUint::from_radix_be(&hex!("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"), 256) + .unwrap(), + }, }, - ]); + ], vec![]); let p = Secp256k1Affine::generator(); let p = (p + p + p).to_affine(); - println!("decompressed: {:?}", p); + let q_x: [u8; 32] = hex!("0100000000000000000000000000000000000000000000000000000000000000"); let q_y: [u8; 32] = @@ -199,12 +223,24 @@ mod tests { hex!("211D5C11D68032342211C256D3C1034AB99013327FBFB46BBD0C0EB700000000"); let r_y: [u8; 32] = hex!("347E00859981D5446447075AA07543CDE6DF224CFB23F7B5886337BD00000000"); + let s = Ed25519Affine::generator(); + let s = (s + s + s).to_affine(); + + 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 coords = [p.x.to_bytes(), p.y.to_bytes(), q_x, q_y, r_x, r_y] - .concat() - .into_iter() - .map(FieldAlgebra::from_canonical_u8) - .collect(); air_test_with_min_segments(config, openvm_exe, vec![coords], 1); Ok(()) } @@ -259,7 +295,7 @@ mod tests { SECP256K1_CONFIG.scalar.clone(), ])) .keccak(Default::default()) - .ecc(WeierstrassExtension::new(vec![SECP256K1_CONFIG.clone()])) + .ecc(EccExtension::new(vec![SECP256K1_CONFIG.clone()], vec![])) .build(); let openvm_exe = VmExe::from_elf( elf, @@ -275,6 +311,27 @@ mod tests { Ok(()) } + #[test] + fn test_edwards_ec() -> Result<()> { + let elf = build_example_program_at_path_with_features::<&str>( + get_programs_dir!(), + "edwards_ec", + ["ed25519"], + )?; + 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 = Rv32EccConfig::new(vec![], vec![ED25519_CONFIG.clone()]); + air_test(config, openvm_exe); + Ok(()) + } + #[test] #[should_panic] fn test_invalid_setup() { @@ -295,7 +352,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 4dae6b2151..1b304ec022 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, @@ -16,17 +16,30 @@ 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( + Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EnumCount, EnumIter, FromRepr, LocalOpcode, +)] +#[opcode_offset = 0x680] +#[allow(non_camel_case_types)] +#[repr(usize)] +pub enum Rv32EdwardsOpcode { + TE_ADD, + SETUP_TE_ADD, } #[derive(Copy, Clone, Debug, PartialEq, Eq, FromRepr)] #[repr(u16)] pub enum EccPhantom { - HintDecompress = 0x40, - HintNonQr = 0x41, + SwHintDecompress = 0x40, + SwHintNonQr = 0x41, + TeHintDecompress = 0x42, + TeHintNonQr = 0x43, } #[derive(Default)] @@ -34,6 +47,16 @@ 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; } @@ -41,7 +64,78 @@ impl TranspilerExtension for EccTranspilerExtension { let opcode = (instruction_u32 & 0x7f) as u8; let funct3 = ((instruction_u32 >> 12) & 0b111) as u8; - if opcode != OPCODE { + 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 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 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( + 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::TE_ADD.global_opcode(), + _ => unimplemented!(), + }; + let global_opcode = global_opcode.as_usize() + curve_idx_shift; + Some(from_r_type(global_opcode, 2, &dec_insn, true)) + } + }; + instruction.map(TranspilerOutput::one_to_one) + } + + fn process_weierstrass_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 != SW_OPCODE { return None; } if funct3 != SW_FUNCT3 { @@ -58,21 +152,22 @@ impl TranspilerExtension for 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, ))); } - 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, @@ -80,8 +175,8 @@ impl TranspilerExtension for 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), @@ -95,18 +190,14 @@ impl TranspilerExtension for 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::SW_ADD_NE.global_opcode(), Some(SwBaseFunct7::SwDouble) => { assert!(dec_insn.rs2 == 0); - Rv32WeierstrassOpcode::EC_DOUBLE as usize - + Rv32WeierstrassOpcode::CLASS_OFFSET + Rv32WeierstrassOpcode::SW_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 4914fa433c..7c0b1f51cc 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, } @@ -42,8 +42,9 @@ impl Rv32PairingConfig { io: Default::default(), modular: ModularExtension::new(primes.to_vec()), fp2: Fp2Extension::new(primes.to_vec()), - weierstrass: WeierstrassExtension::new( + 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 eca4cea8dd..8845df9ad5 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::{CurveConfig, SwCurveCoeffs}; use openvm_instructions::PhantomDiscriminant; use openvm_pairing_guest::{ bls12_381::{BLS12_381_MODULUS, BLS12_381_ORDER, BLS12_381_XI_ISIZE}, @@ -30,19 +30,23 @@ pub enum PairingCurve { } impl PairingCurve { - pub fn curve_config(&self) -> CurveConfig { + pub fn curve_config(&self) -> CurveConfig { match self { PairingCurve::Bn254 => CurveConfig::new( BN254_MODULUS.clone(), BN254_ORDER.clone(), - BigUint::zero(), - BigUint::from_u8(3).unwrap(), + SwCurveCoeffs { + a: BigUint::zero(), + b: BigUint::from_u8(3).unwrap(), + }, ), PairingCurve::Bls12_381 => CurveConfig::new( BLS12_381_MODULUS.clone(), BLS12_381_ORDER.clone(), - BigUint::zero(), - BigUint::from_u8(4).unwrap(), + SwCurveCoeffs { + a: BigUint::zero(), + b: BigUint::from_u8(4).unwrap(), + }, ), } } diff --git a/extensions/pairing/guest/src/bls12_381/mod.rs b/extensions/pairing/guest/src/bls12_381/mod.rs index 707d3ba73a..c89084d414 100644 --- a/extensions/pairing/guest/src/bls12_381/mod.rs +++ b/extensions/pairing/guest/src/bls12_381/mod.rs @@ -2,7 +2,7 @@ use core::ops::Neg; use openvm_algebra_guest::{Field, 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/extensions/pairing/guest/src/bn254/mod.rs b/extensions/pairing/guest/src/bn254/mod.rs index 1c7bfaa2cd..a09ec433ba 100644 --- a/extensions/pairing/guest/src/bn254/mod.rs +++ b/extensions/pairing/guest/src/bn254/mod.rs @@ -7,10 +7,7 @@ use lazy_static::lazy_static; use num_bigint::BigUint; use openvm_algebra_guest::{Field, 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 crate::pairing::PairingIntrinsics; diff --git a/extensions/pairing/tests/programs/examples/bls_ec.rs b/extensions/pairing/tests/programs/examples/bls_ec.rs index dc59c7d702..7fbd724ce1 100644 --- a/extensions/pairing/tests/programs/examples/bls_ec.rs +++ b/extensions/pairing/tests/programs/examples/bls_ec.rs @@ -17,5 +17,5 @@ openvm::entry!(main); pub fn main() { setup_all_moduli(); - setup_all_curves(); + setup_all_sw_curves(); } diff --git a/extensions/pairing/tests/src/lib.rs b/extensions/pairing/tests/src/lib.rs index 33890ecb8a..875fed20db 100644 --- a/extensions/pairing/tests/src/lib.rs +++ b/extensions/pairing/tests/src/lib.rs @@ -11,7 +11,7 @@ mod bn254 { arch::SystemConfig, utils::{air_test_impl, air_test_with_min_segments}, }; - use openvm_ecc_circuit::WeierstrassExtension; + use openvm_ecc_circuit::EccExtension; use openvm_ecc_guest::{ algebra::{field::FieldExtension, IntMod}, halo2curves::{ @@ -47,7 +47,7 @@ mod bn254 { io: Default::default(), modular: ModularExtension::new(primes.to_vec()), fp2: Fp2Extension::new(primes.to_vec()), - weierstrass: WeierstrassExtension::new(vec![]), + weierstrass: EccExtension::new(vec![], vec![]), pairing: PairingExtension::new(vec![PairingCurve::Bn254]), } } @@ -414,7 +414,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::{CurveConfig, EccExtension, Rv32EccConfig, SwCurveCoeffs}; use openvm_ecc_guest::{ algebra::{field::FieldExtension, IntMod}, halo2curves::{ @@ -450,7 +450,7 @@ mod bls12_381 { io: Default::default(), modular: ModularExtension::new(primes.to_vec()), fp2: Fp2Extension::new(primes.to_vec()), - weierstrass: WeierstrassExtension::new(vec![]), + weierstrass: EccExtension::new(vec![], vec![]), pairing: PairingExtension::new(vec![PairingCurve::Bls12_381]), } } @@ -465,8 +465,10 @@ mod bls12_381 { let curve = CurveConfig { 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 openvm_exe = VmExe::from_elf( elf, @@ -477,7 +479,7 @@ mod bls12_381 { .with_extension(EccTranspilerExtension) .with_extension(ModularTranspilerExtension), )?; - let config = Rv32WeierstrassConfig::new(vec![curve]); + let config = Rv32EccConfig::new(vec![curve], vec![]); air_test(config, openvm_exe); Ok(()) }