From d688e34d8e480dd953987b2d5daf4b41d475d248 Mon Sep 17 00:00:00 2001 From: kilic Date: Mon, 24 Jun 2024 12:56:04 +0300 Subject: [PATCH] init --- .gitignore | 2 + Cargo.lock | 666 +++++++++++++++++++++++++++++++++++++++ Cargo.toml | 26 ++ README.md | 5 + src/ed_on_bn254_twist.rs | 102 ++++++ src/eddsa.rs | 143 +++++++++ src/lib.rs | 55 ++++ src/poseidon.rs | 19 ++ src/signature.rs | 56 ++++ 9 files changed, 1074 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/ed_on_bn254_twist.rs create mode 100644 src/eddsa.rs create mode 100644 src/lib.rs create mode 100644 src/poseidon.rs create mode 100644 src/signature.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6466ebf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +*.py \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..697680e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,666 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "ark-algebra-test-templates" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "400bd3a79c741b1832f1416d4373ae077ef82ca14a8b4cee1248a2f11c8b9172" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "hex", + "num-bigint", + "num-integer", + "num-traits", + "serde", + "serde_derive", + "serde_json", + "sha2", +] + +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-crypto-primitives" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-snark", + "ark-std", + "blake2", + "derivative", + "digest", + "sha2", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ed-on-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6d678bb98a7e4f825bd4e332e93ac4f5a114ce2e3340dee4d7dc1c7ab5b323" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cde0f2aa063a2a5c28d39b47761aa102bda7c13c84fc118a61b87c7b2f785c" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ed-on-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71892f265d01650e34988a546b37ea1d2ba1da162a639597a03d1550f26004d8" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown", +] + +[[package]] +name = "ark-relations" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" +dependencies = [ + "ark-ff", + "ark-std", + "tracing", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-snark" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" +dependencies = [ + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arkeddsa" +version = "0.1.0" +dependencies = [ + "ark-algebra-test-templates", + "ark-crypto-primitives", + "ark-ec", + "ark-ed-on-bls12-381", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ed-on-bn254", + "ark-ff", + "ark-serialize", + "ark-std", + "blake2", + "digest", + "rand", + "rand_core", + "sha2", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zerocopy" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a2162ff --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,26 @@ +[package] +edition = "2021" +name = "arkeddsa" +version = "0.1.0" + +[dependencies] + +ark-crypto-primitives = {version = "^0.4.0", default-features = false, features = ["sponge", "crh"]} +ark-ec = "0.4" +ark-ed-on-bn254 = {version = "0.4.0"} +ark-ff = "0.4" +ark-serialize = "0.4" +ark-std = "0.4" +digest = "0.10.7" +rand = "0.8" +rand_core = {version = "0.6", default-features = false} + +[dev-dependencies] +ark-algebra-test-templates = "0.4.2" +ark-ed-on-bls12-381 = {version = "0.4.0"} +ark-ed-on-bls12-381-bandersnatch = {version = "0.4.0"} +blake2 = "0.10.6" +sha2 = "0.10.8" + +[features] +default = [] diff --git a/README.md b/README.md new file mode 100644 index 0000000..b7738c5 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# arkeddsa + +Do not use in production. + +EDDSA signature scheme implementation with Poseidon hasher and ark-works backend. Additionally circom compatible `ed_on_bn254_twist` twist is available. diff --git a/src/ed_on_bn254_twist.rs b/src/ed_on_bn254_twist.rs new file mode 100644 index 0000000..0e9574b --- /dev/null +++ b/src/ed_on_bn254_twist.rs @@ -0,0 +1,102 @@ +use ark_ec::{ + models::CurveConfig, + twisted_edwards::{Affine, MontCurveConfig, Projective, TECurveConfig}, +}; +use ark_ff::MontFp; +pub type EdwardsAffine = Affine; +pub type EdwardsProjective = Projective; + +/// Twist of `Baby-JubJub` is a twist of twisted Edwards curve. These curves have equations of the +/// form: ax² + y² = 1 + dx²y². +/// over some base finite field BaseField. +/// +/// q = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +#[derive(Clone, Default, PartialEq, Eq)] +pub struct EdwardsConfig; + +#[cfg(test)] +ark_algebra_test_templates::test_group!(te; EdwardsProjective; te); + +impl CurveConfig for EdwardsConfig { + type BaseField = ark_ed_on_bn254::Fq; + type ScalarField = ark_ed_on_bn254::Fr; + + /// COFACTOR = 8 + const COFACTOR: &'static [u64] = &[8]; + + /// COFACTOR^(-1) mod r = + /// 2394026564107420727433200628387514462817212225638746351800188703329891451411 + const COFACTOR_INV: ark_ed_on_bn254::Fr = + MontFp!("2394026564107420727433200628387514462817212225638746351800188703329891451411"); +} + +impl TECurveConfig for EdwardsConfig { + const COEFF_A: ark_ed_on_bn254::Fq = MontFp!("168700"); + + #[inline(always)] + fn mul_by_a(elem: Self::BaseField) -> Self::BaseField { + elem * ::COEFF_A + } + + const COEFF_D: ark_ed_on_bn254::Fq = MontFp!("168696"); + + const GENERATOR: EdwardsAffine = EdwardsAffine::new_unchecked(GENERATOR_X, GENERATOR_Y); + + type MontCurveConfig = EdwardsConfig; +} + +impl MontCurveConfig for EdwardsConfig { + /// COEFF_A = 168698 + const COEFF_A: ark_ed_on_bn254::Fq = MontFp!("168698"); + /// COEFF_B = 168700 + const COEFF_B: ark_ed_on_bn254::Fq = MontFp!("1"); + + type TECurveConfig = EdwardsConfig; +} + +/// GENERATOR_X = +/// 19698561148652590122159747500897617769866003486955115824547446575314762165298 +pub const GENERATOR_X: ark_ed_on_bn254::Fq = + MontFp!("5299619240641551281634865583518297030282874472190772894086521144482721001553"); + +/// GENERATOR_Y = +/// 19298250018296453272277890825869354524455968081175474282777126169995084727839 +pub const GENERATOR_Y: ark_ed_on_bn254::Fq = + MontFp!("16950150798460657717958625567821834550301663161624707787222815936182638968203"); + +#[test] +fn test_twist() { + fn twist(twist: ark_ed_on_bn254::EdwardsAffine) -> EdwardsAffine { + use ark_ff::Field; + let inv_sqrt_a = MontFp!("168700").sqrt().unwrap().inverse().unwrap(); + EdwardsAffine { + x: twist.x * inv_sqrt_a, + y: twist.y, + } + } + + fn untwist(curve: EdwardsAffine) -> ark_ed_on_bn254::EdwardsAffine { + use ark_ff::Field; + const A: ark_ed_on_bn254::Fq = MontFp!("168700"); + let sqrt_a = A.sqrt().unwrap(); + ark_ed_on_bn254::EdwardsAffine { + x: curve.x * sqrt_a, + y: curve.y, + } + } + + use ark_ec::{AffineRepr, CurveGroup}; + use ark_ed_on_bn254::Fr; + use ark_std::UniformRand; + use rand_core::OsRng; + + let v0: ark_ed_on_bn254::EdwardsAffine = ark_ed_on_bn254::EdwardsAffine::generator(); + let u0: crate::ed_on_bn254_twist::EdwardsAffine = twist(v0); + assert!(u0.is_on_curve()); + assert!(u0.is_in_correct_subgroup_assuming_on_curve()); + let x = Fr::rand(&mut OsRng); + let u1 = (u0 * x).into_affine(); + let v1 = (v0 * x).into_affine(); + let v2 = untwist(u1); + assert_eq!(v1, v2); +} diff --git a/src/eddsa.rs b/src/eddsa.rs new file mode 100644 index 0000000..5c4965f --- /dev/null +++ b/src/eddsa.rs @@ -0,0 +1,143 @@ +use crate::{signature::Signature, Error}; +use ark_crypto_primitives::sponge::{ + poseidon::{PoseidonConfig, PoseidonSponge}, + Absorb, CryptographicSponge, +}; +use ark_ec::{twisted_edwards::TECurveConfig, AffineRepr, CurveGroup}; +use ark_ff::PrimeField; +use digest::Digest; +use digest::OutputSizeUser; +use rand_core::CryptoRngCore; + +fn prune_buffer(mut bytes: [u8; 32]) -> F { + bytes[0] &= 0b1111_1000; + bytes[31] &= 0b0111_1111; + bytes[31] |= 0b0100_0000; + F::from_le_bytes_mod_order(&bytes[..]) +} + +#[derive(Copy, Clone, Debug)] +/// EdDSA secret key is 32 byte data +pub struct SecretKey([u8; 32]); + +impl SecretKey { + fn expand(&self) -> (F, [u8; 32]) { + let hash = D::new().chain_update(self.0).finalize(); + let (buffer, hash_prefix) = hash.split_at(32); + let buffer: [u8; 32] = buffer.try_into().unwrap(); + let hash_prefix: [u8; 32] = hash_prefix.try_into().unwrap(); + let x = prune_buffer(buffer); + (x, hash_prefix) + } +} + +#[derive(Copy, Clone, Debug)] +/// `PublicKey` is EdDSA signature verification key +pub struct PublicKey(A) +where + A::Config: TECurveConfig; + +#[derive(Copy, Clone, Debug)] +/// `SigningKey` produces EdDSA signatures for given message +pub struct SigningKey +where + A::Config: TECurveConfig, +{ + secret_key: SecretKey, + public_key: PublicKey, +} + +impl SigningKey +where + A::Config: TECurveConfig, + A::BaseField: PrimeField + Absorb, +{ + pub fn new(secret_key: &SecretKey) -> Result { + (::output_size() == 64) + .then_some(()) + .ok_or(Error::BadOutputSize)?; + + let (x, _) = secret_key.expand::(); + let public_key: A = (A::generator() * x).into_affine(); + let signing_key = Self { + secret_key: *secret_key, + public_key: PublicKey(public_key), + }; + + Ok(signing_key) + } + + pub fn generate(rng: &mut impl CryptoRngCore) -> Result { + let mut secret_key = SecretKey([0; 32]); + rng.fill_bytes(&mut secret_key.0); + Self::new::(&secret_key) + } + + pub fn public_key(&self) -> PublicKey { + self.public_key + } + + pub fn sign( + &self, + poseidon: &PoseidonConfig, + message: &[E], + ) -> Signature { + let (x, prefix) = self.secret_key.expand::(); + + let mut h = D::new(); + h.update(prefix); + message + .iter() + .for_each(|m| h.update(m.to_sponge_bytes_as_vec())); + let r: A::ScalarField = crate::from_digest(h); + let sig_r = (A::generator() * r).into_affine(); + + let mut poseidon = PoseidonSponge::new(poseidon); + let (sig_r_x, sig_r_y) = sig_r.xy().unwrap(); + poseidon.absorb(sig_r_x); + poseidon.absorb(sig_r_y); + let (vk_x, vk_y) = self.public_key.0.xy().unwrap(); + poseidon.absorb(vk_x); + poseidon.absorb(vk_y); + message.iter().for_each(|m| poseidon.absorb(m)); + + let k = poseidon.squeeze_field_elements::(1); + let k = k.first().unwrap(); + + let sig_s = (x * k) + r; + + Signature::new(sig_r, sig_s) + } +} + +impl PublicKey +where + A::Config: TECurveConfig, + A::BaseField: PrimeField + Absorb, +{ + pub fn verify( + &self, + poseidon: &PoseidonConfig, + message: &[E], + signature: &Signature, + ) -> Result<(), Error> { + let mut poseidon = PoseidonSponge::new(poseidon); + + let (sig_r_x, sig_r_y) = signature.r().xy().unwrap(); + poseidon.absorb(sig_r_x); + poseidon.absorb(sig_r_y); + let (vk_x, vk_y) = self.0.xy().unwrap(); + poseidon.absorb(vk_x); + poseidon.absorb(vk_y); + message.iter().for_each(|m| poseidon.absorb(m)); + + let k = poseidon.squeeze_field_elements::(1); + let k = k.first().unwrap(); + + let kx_b = self.0 * k; + let s_b = A::generator() * signature.s(); + let r_rec: A = (s_b - kx_b).into(); + + (signature.r() == &r_rec).then_some(()).ok_or(Error::Verify) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2eb9c38 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,55 @@ +pub mod ed_on_bn254_twist; +pub mod eddsa; +pub mod poseidon; +pub mod signature; + +use ark_ff::PrimeField; +use digest::Digest; +pub use eddsa::*; + +pub(crate) fn from_digest(digest: D) -> F { + let bytes = digest.finalize(); + F::from_le_bytes_mod_order(&bytes) +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Error { + Verify, + BadOutputSize, + InvalidData, +} + +#[cfg(test)] +mod test { + use ark_crypto_primitives::sponge::Absorb; + use ark_ec::{twisted_edwards::TECurveConfig, AffineRepr}; + use ark_ff::PrimeField; + use digest::Digest; + use rand_core::OsRng; + + use crate::SigningKey; + + fn run_test() + where + A::BaseField: Absorb + PrimeField, + A::Config: TECurveConfig, + { + let poseidon = crate::poseidon::poseidon_config(4, 8, 55); + let signing_key = SigningKey::::generate::(&mut OsRng).unwrap(); + let message = b"xxx yyy <<< zzz >>> bunny"; + let signature = signing_key.sign::(&poseidon, &message[..]); + let public_key = signing_key.public_key(); + public_key + .verify::<_>(&poseidon, &message[..], &signature) + .unwrap(); + } + + #[test] + fn test_eddsa() { + run_test::(); + run_test::(); + run_test::(); + run_test::(); + run_test::(); + } +} diff --git a/src/poseidon.rs b/src/poseidon.rs new file mode 100644 index 0000000..f856b32 --- /dev/null +++ b/src/poseidon.rs @@ -0,0 +1,19 @@ +use ark_crypto_primitives::sponge::poseidon::{find_poseidon_ark_and_mds, PoseidonConfig}; +use ark_ff::PrimeField; + +/// Generates poseidon constants and returns the config +pub fn poseidon_config( + rate: usize, + full_rounds: usize, + partial_rounds: usize, +) -> PoseidonConfig { + let prime_bits = F::MODULUS_BIT_SIZE as u64; + let (ark, mds) = find_poseidon_ark_and_mds( + prime_bits, + rate, + full_rounds as u64, + partial_rounds as u64, + 0, + ); + PoseidonConfig::new(full_rounds, partial_rounds, 5, mds, ark, rate, 1) +} diff --git a/src/signature.rs b/src/signature.rs new file mode 100644 index 0000000..505340b --- /dev/null +++ b/src/signature.rs @@ -0,0 +1,56 @@ +use crate::Error; +use ark_ec::twisted_edwards::TECurveConfig; +use ark_ec::AffineRepr; +use ark_serialize::CanonicalDeserialize; +use ark_serialize::CanonicalSerialize; + +#[derive(Clone, Copy, Debug)] +/// `SignatureComponents` contains the realized parts of a signature +pub struct Signature { + r: A, + s: A::ScalarField, +} + +impl Signature +where + A::Config: TECurveConfig, +{ + /// Serializes the signature components to bytes as uncompressed. + /// Expect output size to be `size_of(A::BaseField) * 2 + size_of(A::ScalarField)` + pub fn to_bytes(&self) -> Vec { + let mut bytes = Vec::new(); + self.r.serialize_uncompressed(&mut bytes).unwrap(); + self.s.serialize_uncompressed(&mut bytes).unwrap(); + bytes + } + + /// Checked deserialization of the signature components from bytes. + /// Expects input size to be `size_of(A::BaseField) * 2 + size_of(A::ScalarField)` + pub fn from_bytes(bytes: &[u8]) -> Result, Error> { + let point_size = A::Config::serialized_size(ark_serialize::Compress::No); + (bytes.len() == 32 + A::Config::serialized_size(ark_serialize::Compress::No)) + .then_some(true) + .ok_or(Error::InvalidData)?; + + let off1 = point_size; + let off2 = off1 + 32; + + let r = + A::deserialize_uncompressed(&bytes[00..off1]).map_err(|_| crate::Error::InvalidData)?; + let s = A::ScalarField::deserialize_uncompressed(&bytes[off1..off2]) + .map_err(|_| crate::Error::InvalidData)?; + Ok(Signature { r, s }) + } + + pub fn new(r: A, s: A::ScalarField) -> Self { + Self { r, s } + } + + pub(crate) fn r(&self) -> &A { + &self.r + } + + pub(crate) fn s(&self) -> &A::ScalarField { + &self.s + } +}