├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── evaluations.rs ├── bls12-381_coset ├── bls12-381_isogenies ├── bn254_coset ├── bn254_isogenies ├── curve25519_coset ├── curve25519_isogenies ├── get_params.sage └── src ├── bls12_381.rs ├── bn254.rs ├── curve25519.rs ├── ecfft.rs ├── lib.rs └── utils ├── isogeny.rs ├── matrix.rs └── mod.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | get_params.sage.py 3 | .vscode/ -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.8.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" 10 | dependencies = [ 11 | "cfg-if", 12 | "once_cell", 13 | "version_check", 14 | ] 15 | 16 | [[package]] 17 | name = "ark-bls12-381" 18 | version = "0.4.0" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" 21 | dependencies = [ 22 | "ark-ec", 23 | "ark-ff", 24 | "ark-serialize", 25 | "ark-std", 26 | ] 27 | 28 | [[package]] 29 | name = "ark-bn254" 30 | version = "0.4.0" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" 33 | dependencies = [ 34 | "ark-ec", 35 | "ark-ff", 36 | "ark-std", 37 | ] 38 | 39 | [[package]] 40 | name = "ark-curve25519" 41 | version = "0.4.0" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "4ab653b3eff27100f7dcb06b94785f2fbe0d1230408df55d543ee0ef48cd8760" 44 | dependencies = [ 45 | "ark-ec", 46 | "ark-ff", 47 | "ark-std", 48 | ] 49 | 50 | [[package]] 51 | name = "ark-ec" 52 | version = "0.4.1" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "3c60370a92f8e1a5f053cad73a862e1b99bc642333cd676fa11c0c39f80f4ac2" 55 | dependencies = [ 56 | "ark-ff", 57 | "ark-poly", 58 | "ark-serialize", 59 | "ark-std", 60 | "derivative", 61 | "hashbrown", 62 | "itertools", 63 | "num-traits", 64 | "zeroize", 65 | ] 66 | 67 | [[package]] 68 | name = "ark-ff" 69 | version = "0.4.1" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "4c2d42532524bee1da5a4f6f733eb4907301baa480829557adcff5dfaeee1d9a" 72 | dependencies = [ 73 | "ark-ff-asm", 74 | "ark-ff-macros", 75 | "ark-serialize", 76 | "ark-std", 77 | "derivative", 78 | "digest", 79 | "itertools", 80 | "num-bigint", 81 | "num-traits", 82 | "paste", 83 | "rustc_version", 84 | "zeroize", 85 | ] 86 | 87 | [[package]] 88 | name = "ark-ff-asm" 89 | version = "0.4.1" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "9d6873aaba7959593d89babed381d33e2329453368f1bf3c67e07686a1c1056f" 92 | dependencies = [ 93 | "quote", 94 | "syn", 95 | ] 96 | 97 | [[package]] 98 | name = "ark-ff-macros" 99 | version = "0.4.1" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "f3c2e7d0f2d67cc7fc925355c74d36e7eda19073639be4a0a233d4611b8c959d" 102 | dependencies = [ 103 | "num-bigint", 104 | "num-traits", 105 | "proc-macro2", 106 | "quote", 107 | "syn", 108 | ] 109 | 110 | [[package]] 111 | name = "ark-poly" 112 | version = "0.4.1" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "8f6ec811462cabe265cfe1b102fcfe3df79d7d2929c2425673648ee9abfd0272" 115 | dependencies = [ 116 | "ark-ff", 117 | "ark-serialize", 118 | "ark-std", 119 | "derivative", 120 | "hashbrown", 121 | ] 122 | 123 | [[package]] 124 | name = "ark-serialize" 125 | version = "0.4.1" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "e7e735959bc173ea4baf13327b19c22d452b8e9e8e8f7b7fc34e6bf0e316c33e" 128 | dependencies = [ 129 | "ark-serialize-derive", 130 | "ark-std", 131 | "digest", 132 | "num-bigint", 133 | ] 134 | 135 | [[package]] 136 | name = "ark-serialize-derive" 137 | version = "0.4.1" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "fd34f0920d995d2c932f38861c416f70de89a6de9875876b012557079603e6cc" 140 | dependencies = [ 141 | "proc-macro2", 142 | "quote", 143 | "syn", 144 | ] 145 | 146 | [[package]] 147 | name = "ark-std" 148 | version = "0.4.0" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" 151 | dependencies = [ 152 | "num-traits", 153 | "rand", 154 | ] 155 | 156 | [[package]] 157 | name = "atty" 158 | version = "0.2.14" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 161 | dependencies = [ 162 | "hermit-abi 0.1.19", 163 | "libc", 164 | "winapi", 165 | ] 166 | 167 | [[package]] 168 | name = "autocfg" 169 | version = "1.1.0" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 172 | 173 | [[package]] 174 | name = "bitflags" 175 | version = "1.3.2" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 178 | 179 | [[package]] 180 | name = "bumpalo" 181 | version = "3.12.0" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" 184 | 185 | [[package]] 186 | name = "cast" 187 | version = "0.3.0" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" 190 | 191 | [[package]] 192 | name = "cfg-if" 193 | version = "1.0.0" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 196 | 197 | [[package]] 198 | name = "clap" 199 | version = "2.34.0" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 202 | dependencies = [ 203 | "bitflags", 204 | "textwrap", 205 | "unicode-width", 206 | ] 207 | 208 | [[package]] 209 | name = "criterion" 210 | version = "0.3.6" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" 213 | dependencies = [ 214 | "atty", 215 | "cast", 216 | "clap", 217 | "criterion-plot", 218 | "csv", 219 | "itertools", 220 | "lazy_static", 221 | "num-traits", 222 | "oorandom", 223 | "plotters", 224 | "rayon", 225 | "regex", 226 | "serde", 227 | "serde_cbor", 228 | "serde_derive", 229 | "serde_json", 230 | "tinytemplate", 231 | "walkdir", 232 | ] 233 | 234 | [[package]] 235 | name = "criterion-plot" 236 | version = "0.4.5" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" 239 | dependencies = [ 240 | "cast", 241 | "itertools", 242 | ] 243 | 244 | [[package]] 245 | name = "crossbeam-channel" 246 | version = "0.5.7" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" 249 | dependencies = [ 250 | "cfg-if", 251 | "crossbeam-utils", 252 | ] 253 | 254 | [[package]] 255 | name = "crossbeam-deque" 256 | version = "0.8.3" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" 259 | dependencies = [ 260 | "cfg-if", 261 | "crossbeam-epoch", 262 | "crossbeam-utils", 263 | ] 264 | 265 | [[package]] 266 | name = "crossbeam-epoch" 267 | version = "0.9.14" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" 270 | dependencies = [ 271 | "autocfg", 272 | "cfg-if", 273 | "crossbeam-utils", 274 | "memoffset", 275 | "scopeguard", 276 | ] 277 | 278 | [[package]] 279 | name = "crossbeam-utils" 280 | version = "0.8.15" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" 283 | dependencies = [ 284 | "cfg-if", 285 | ] 286 | 287 | [[package]] 288 | name = "crypto-common" 289 | version = "0.1.6" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 292 | dependencies = [ 293 | "generic-array", 294 | "typenum", 295 | ] 296 | 297 | [[package]] 298 | name = "csv" 299 | version = "1.2.1" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" 302 | dependencies = [ 303 | "csv-core", 304 | "itoa", 305 | "ryu", 306 | "serde", 307 | ] 308 | 309 | [[package]] 310 | name = "csv-core" 311 | version = "0.1.10" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" 314 | dependencies = [ 315 | "memchr", 316 | ] 317 | 318 | [[package]] 319 | name = "derivative" 320 | version = "2.2.0" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 323 | dependencies = [ 324 | "proc-macro2", 325 | "quote", 326 | "syn", 327 | ] 328 | 329 | [[package]] 330 | name = "digest" 331 | version = "0.10.6" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" 334 | dependencies = [ 335 | "crypto-common", 336 | ] 337 | 338 | [[package]] 339 | name = "ecfft-bn254" 340 | version = "0.1.0" 341 | dependencies = [ 342 | "ark-bls12-381", 343 | "ark-bn254", 344 | "ark-curve25519", 345 | "ark-ff", 346 | "ark-poly", 347 | "ark-std", 348 | "criterion", 349 | ] 350 | 351 | [[package]] 352 | name = "either" 353 | version = "1.8.1" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" 356 | 357 | [[package]] 358 | name = "generic-array" 359 | version = "0.14.6" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" 362 | dependencies = [ 363 | "typenum", 364 | "version_check", 365 | ] 366 | 367 | [[package]] 368 | name = "half" 369 | version = "1.8.2" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" 372 | 373 | [[package]] 374 | name = "hashbrown" 375 | version = "0.13.2" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" 378 | dependencies = [ 379 | "ahash", 380 | ] 381 | 382 | [[package]] 383 | name = "hermit-abi" 384 | version = "0.1.19" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 387 | dependencies = [ 388 | "libc", 389 | ] 390 | 391 | [[package]] 392 | name = "hermit-abi" 393 | version = "0.2.6" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" 396 | dependencies = [ 397 | "libc", 398 | ] 399 | 400 | [[package]] 401 | name = "itertools" 402 | version = "0.10.5" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 405 | dependencies = [ 406 | "either", 407 | ] 408 | 409 | [[package]] 410 | name = "itoa" 411 | version = "1.0.6" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" 414 | 415 | [[package]] 416 | name = "js-sys" 417 | version = "0.3.61" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" 420 | dependencies = [ 421 | "wasm-bindgen", 422 | ] 423 | 424 | [[package]] 425 | name = "lazy_static" 426 | version = "1.4.0" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 429 | 430 | [[package]] 431 | name = "libc" 432 | version = "0.2.140" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" 435 | 436 | [[package]] 437 | name = "log" 438 | version = "0.4.17" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 441 | dependencies = [ 442 | "cfg-if", 443 | ] 444 | 445 | [[package]] 446 | name = "memchr" 447 | version = "2.5.0" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 450 | 451 | [[package]] 452 | name = "memoffset" 453 | version = "0.8.0" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" 456 | dependencies = [ 457 | "autocfg", 458 | ] 459 | 460 | [[package]] 461 | name = "num-bigint" 462 | version = "0.4.3" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" 465 | dependencies = [ 466 | "autocfg", 467 | "num-integer", 468 | "num-traits", 469 | ] 470 | 471 | [[package]] 472 | name = "num-integer" 473 | version = "0.1.45" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 476 | dependencies = [ 477 | "autocfg", 478 | "num-traits", 479 | ] 480 | 481 | [[package]] 482 | name = "num-traits" 483 | version = "0.2.15" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 486 | dependencies = [ 487 | "autocfg", 488 | ] 489 | 490 | [[package]] 491 | name = "num_cpus" 492 | version = "1.15.0" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" 495 | dependencies = [ 496 | "hermit-abi 0.2.6", 497 | "libc", 498 | ] 499 | 500 | [[package]] 501 | name = "once_cell" 502 | version = "1.17.1" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" 505 | 506 | [[package]] 507 | name = "oorandom" 508 | version = "11.1.3" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" 511 | 512 | [[package]] 513 | name = "paste" 514 | version = "1.0.12" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" 517 | 518 | [[package]] 519 | name = "plotters" 520 | version = "0.3.4" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" 523 | dependencies = [ 524 | "num-traits", 525 | "plotters-backend", 526 | "plotters-svg", 527 | "wasm-bindgen", 528 | "web-sys", 529 | ] 530 | 531 | [[package]] 532 | name = "plotters-backend" 533 | version = "0.3.4" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" 536 | 537 | [[package]] 538 | name = "plotters-svg" 539 | version = "0.3.3" 540 | source = "registry+https://github.com/rust-lang/crates.io-index" 541 | checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" 542 | dependencies = [ 543 | "plotters-backend", 544 | ] 545 | 546 | [[package]] 547 | name = "ppv-lite86" 548 | version = "0.2.17" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 551 | 552 | [[package]] 553 | name = "proc-macro2" 554 | version = "1.0.51" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" 557 | dependencies = [ 558 | "unicode-ident", 559 | ] 560 | 561 | [[package]] 562 | name = "quote" 563 | version = "1.0.23" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" 566 | dependencies = [ 567 | "proc-macro2", 568 | ] 569 | 570 | [[package]] 571 | name = "rand" 572 | version = "0.8.5" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 575 | dependencies = [ 576 | "rand_chacha", 577 | "rand_core", 578 | ] 579 | 580 | [[package]] 581 | name = "rand_chacha" 582 | version = "0.3.1" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 585 | dependencies = [ 586 | "ppv-lite86", 587 | "rand_core", 588 | ] 589 | 590 | [[package]] 591 | name = "rand_core" 592 | version = "0.6.4" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 595 | 596 | [[package]] 597 | name = "rayon" 598 | version = "1.7.0" 599 | source = "registry+https://github.com/rust-lang/crates.io-index" 600 | checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" 601 | dependencies = [ 602 | "either", 603 | "rayon-core", 604 | ] 605 | 606 | [[package]] 607 | name = "rayon-core" 608 | version = "1.11.0" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" 611 | dependencies = [ 612 | "crossbeam-channel", 613 | "crossbeam-deque", 614 | "crossbeam-utils", 615 | "num_cpus", 616 | ] 617 | 618 | [[package]] 619 | name = "regex" 620 | version = "1.7.1" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" 623 | dependencies = [ 624 | "regex-syntax", 625 | ] 626 | 627 | [[package]] 628 | name = "regex-syntax" 629 | version = "0.6.28" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" 632 | 633 | [[package]] 634 | name = "rustc_version" 635 | version = "0.4.0" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 638 | dependencies = [ 639 | "semver", 640 | ] 641 | 642 | [[package]] 643 | name = "ryu" 644 | version = "1.0.13" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" 647 | 648 | [[package]] 649 | name = "same-file" 650 | version = "1.0.6" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 653 | dependencies = [ 654 | "winapi-util", 655 | ] 656 | 657 | [[package]] 658 | name = "scopeguard" 659 | version = "1.1.0" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 662 | 663 | [[package]] 664 | name = "semver" 665 | version = "1.0.16" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" 668 | 669 | [[package]] 670 | name = "serde" 671 | version = "1.0.154" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "8cdd151213925e7f1ab45a9bbfb129316bd00799784b174b7cc7bcd16961c49e" 674 | 675 | [[package]] 676 | name = "serde_cbor" 677 | version = "0.11.2" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" 680 | dependencies = [ 681 | "half", 682 | "serde", 683 | ] 684 | 685 | [[package]] 686 | name = "serde_derive" 687 | version = "1.0.154" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "4fc80d722935453bcafdc2c9a73cd6fac4dc1938f0346035d84bf99fa9e33217" 690 | dependencies = [ 691 | "proc-macro2", 692 | "quote", 693 | "syn", 694 | ] 695 | 696 | [[package]] 697 | name = "serde_json" 698 | version = "1.0.94" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" 701 | dependencies = [ 702 | "itoa", 703 | "ryu", 704 | "serde", 705 | ] 706 | 707 | [[package]] 708 | name = "syn" 709 | version = "1.0.109" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 712 | dependencies = [ 713 | "proc-macro2", 714 | "quote", 715 | "unicode-ident", 716 | ] 717 | 718 | [[package]] 719 | name = "synstructure" 720 | version = "0.12.6" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" 723 | dependencies = [ 724 | "proc-macro2", 725 | "quote", 726 | "syn", 727 | "unicode-xid", 728 | ] 729 | 730 | [[package]] 731 | name = "textwrap" 732 | version = "0.11.0" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 735 | dependencies = [ 736 | "unicode-width", 737 | ] 738 | 739 | [[package]] 740 | name = "tinytemplate" 741 | version = "1.2.1" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" 744 | dependencies = [ 745 | "serde", 746 | "serde_json", 747 | ] 748 | 749 | [[package]] 750 | name = "typenum" 751 | version = "1.16.0" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 754 | 755 | [[package]] 756 | name = "unicode-ident" 757 | version = "1.0.8" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" 760 | 761 | [[package]] 762 | name = "unicode-width" 763 | version = "0.1.10" 764 | source = "registry+https://github.com/rust-lang/crates.io-index" 765 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" 766 | 767 | [[package]] 768 | name = "unicode-xid" 769 | version = "0.2.4" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" 772 | 773 | [[package]] 774 | name = "version_check" 775 | version = "0.9.4" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 778 | 779 | [[package]] 780 | name = "walkdir" 781 | version = "2.3.2" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 784 | dependencies = [ 785 | "same-file", 786 | "winapi", 787 | "winapi-util", 788 | ] 789 | 790 | [[package]] 791 | name = "wasm-bindgen" 792 | version = "0.2.84" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" 795 | dependencies = [ 796 | "cfg-if", 797 | "wasm-bindgen-macro", 798 | ] 799 | 800 | [[package]] 801 | name = "wasm-bindgen-backend" 802 | version = "0.2.84" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" 805 | dependencies = [ 806 | "bumpalo", 807 | "log", 808 | "once_cell", 809 | "proc-macro2", 810 | "quote", 811 | "syn", 812 | "wasm-bindgen-shared", 813 | ] 814 | 815 | [[package]] 816 | name = "wasm-bindgen-macro" 817 | version = "0.2.84" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" 820 | dependencies = [ 821 | "quote", 822 | "wasm-bindgen-macro-support", 823 | ] 824 | 825 | [[package]] 826 | name = "wasm-bindgen-macro-support" 827 | version = "0.2.84" 828 | source = "registry+https://github.com/rust-lang/crates.io-index" 829 | checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" 830 | dependencies = [ 831 | "proc-macro2", 832 | "quote", 833 | "syn", 834 | "wasm-bindgen-backend", 835 | "wasm-bindgen-shared", 836 | ] 837 | 838 | [[package]] 839 | name = "wasm-bindgen-shared" 840 | version = "0.2.84" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" 843 | 844 | [[package]] 845 | name = "web-sys" 846 | version = "0.3.61" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" 849 | dependencies = [ 850 | "js-sys", 851 | "wasm-bindgen", 852 | ] 853 | 854 | [[package]] 855 | name = "winapi" 856 | version = "0.3.9" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 859 | dependencies = [ 860 | "winapi-i686-pc-windows-gnu", 861 | "winapi-x86_64-pc-windows-gnu", 862 | ] 863 | 864 | [[package]] 865 | name = "winapi-i686-pc-windows-gnu" 866 | version = "0.4.0" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 869 | 870 | [[package]] 871 | name = "winapi-util" 872 | version = "0.1.5" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 875 | dependencies = [ 876 | "winapi", 877 | ] 878 | 879 | [[package]] 880 | name = "winapi-x86_64-pc-windows-gnu" 881 | version = "0.4.0" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 884 | 885 | [[package]] 886 | name = "zeroize" 887 | version = "1.5.7" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" 890 | dependencies = [ 891 | "zeroize_derive", 892 | ] 893 | 894 | [[package]] 895 | name = "zeroize_derive" 896 | version = "1.3.3" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" 899 | dependencies = [ 900 | "proc-macro2", 901 | "quote", 902 | "syn", 903 | "synstructure", 904 | ] 905 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ecfft-bn254" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["William Borgeaud "] 6 | 7 | [dependencies] 8 | ark-ff = "0.4.0" 9 | ark-bn254 = "0.4.0" 10 | ark-bls12-381 = "0.4.0" 11 | ark-curve25519 = "0.4.0" 12 | ark-std = "0.4.0" 13 | ark-poly = "0.4.0" 14 | 15 | [dev-dependencies] 16 | criterion = "0.3.5" 17 | 18 | [[bench]] 19 | name = "evaluations" 20 | harness = false 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 William Borgeaud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ECFFT algorithms on the BN254 base field 2 | 3 | This crate implements structs and traits for the ECFFT algorithms from the paper [Elliptic Curve Fast Fourier Transform (ECFFT) Part I: Fast Polynomial Algorithms over all Finite Fields](https://arxiv.org/abs/2107.08473) by Eli Ben-Sasson, Dan Carmon, Swastik Kopparty and David Levit. 4 | 5 | A concrete implementation is provided for the BN254 base field which is not FFT friendly (two-adicity of 1). 6 | 7 | ### Example 8 | 9 | ```rust 10 | fn test_evaluations() { 11 | type P = Bn254EcFftParameters; 12 | // ECFFT precomputations. 13 | let precomputation = P::precompute(); 14 | // Can interpolate polynomials up to degree 2^14. 15 | let log_n = 14; 16 | let mut rng = test_rng(); 17 | // Generate a random polynomial. 18 | let coeffs: Vec = (0..1 << log_n).map(|_| rng.gen()).collect(); 19 | let poly = DensePolynomial { coeffs }; 20 | // Naive evaluations. 21 | let evals = P::coset() 22 | .iter() 23 | .map(|x| poly.evaluate(x)) 24 | .collect::>(); 25 | // ECFFT evaluations. 26 | let ecfft_evals = precomputation.evaluate_over_domain(&poly); 27 | 28 | assert_eq!(evals, ecfft_evals); 29 | } 30 | ``` 31 | 32 | ### BLS12-381 33 | 34 | The base field of the BLS12-381 curve is also supported, for degrees up to `2^15`. Credits to [Saulius Grigaitis 35 | ](https://github.com/sauliusgrigaitis) for [finding a curve with 2-adicity 15](https://github.com/wborgeaud/ecfft-bn254/pull/2). 36 | 37 | ### Precomputations 38 | 39 | The implementation uses precomputations for the coset and isogenies used in the ECFFT. These precomputations are computed in `get_params.sage` and are stored in the `bn254_coset` and `bn254_isogenies` files. 40 | 41 | To implement the ECFFT for other fields, similar precomputations should be performed. For example, here is how to generate the precomputations for BLS12-381: 42 | 43 | ```bash 44 | # sage get_params.sage p a b output_filename 45 | sage get_params.sage 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab 0x1800fb41dab7368489a980e14a746abfe7c87588aac25c113301d524b734a5043bbc89dd7d0c5b41de5d348ac2e838c6 0x11c65a0a6e52b8b88366e0b0df28c6804f14f35cb833cb0d918c9e758f044d95777beb965a967af4ef518ad0618a809a bls12-381 46 | ``` 47 | 48 | ### Benchmarks 49 | 50 | Here is a comparison of the running time for the evaluation of a polynomial of degree `n-1` on a domain of `n` points using 3 algorithms: 51 | 52 | - the naive evaluation in `O(n^2)`, 53 | - the classic FFT (on the FFT-friendly BN254 scalar field) in `O(n * log n)`, 54 | - the ECFFT ENTER algorithm in `O(n * log^2 n)`. 55 | 56 | | `log n` | Naive (ms) | Classic (ms) | ECFFT (ms) | Naive/ECFFT | ECFFT/Classic | 57 | | ------- | ----------- | ------------ | ---------- | ----------- | ------------- | 58 | | 1 | 0.000165 | 0.000126 | 0.000384 | 0.429 | 3.056 | 59 | | 2 | 0.00046 | 0.000256 | 0.002144 | 0.214 | 8.36 | 60 | | 3 | 0.00203 | 0.000639 | 0.008599 | 0.236 | 13.456 | 61 | | 4 | 0.00688 | 0.001781 | 0.030458 | 0.226 | 17.103 | 62 | | 5 | 0.032354 | 0.003268 | 0.085556 | 0.378 | 26.177 | 63 | | 6 | 0.119391 | 0.007594 | 0.239939 | 0.498 | 31.595 | 64 | | 7 | 0.479542 | 0.018378 | 0.613242 | 0.782 | 33.368 | 65 | | 8 | 1.873195 | 0.043694 | 1.425794 | 1.314 | 32.632 | 66 | | 9 | 7.619662 | 0.093 | 3.964933 | 1.922 | 42.634 | 67 | | 10 | 30.034845 | 0.20955 | 9.308925 | 3.226 | 44.423 | 68 | | 11 | 121.564343 | 0.453727 | 22.186604 | 5.479 | 48.899 | 69 | | 12 | 482.728362 | 0.976134 | 51.505625 | 9.372 | 52.765 | 70 | | 13 | 1930.495799 | 2.166843 | 119.317395 | 16.18 | 55.065 | 71 | | 14 | 7745.103265 | 4.57555 | 275.499648 | 28.113 | 60.211 | 72 | 73 | ### References 74 | 75 | - [Elliptic Curve Fast Fourier Transform (ECFFT) Part I: Fast Polynomial Algorithms over all Finite Fields](https://arxiv.org/abs/2107.08473) by Eli Ben-Sasson, Dan Carmon, Swastik Kopparty and David Levit. 76 | - [The ECFFT algorithm](https://solvable.group/posts/ecfft/). 77 | - [ECFFT on the BN254 base field in Rust](https://solvable.group/posts/ecfft-bn254/). 78 | -------------------------------------------------------------------------------- /benches/evaluations.rs: -------------------------------------------------------------------------------- 1 | use ark_bn254::Fr; 2 | use ark_poly::univariate::DensePolynomial; 3 | use ark_poly::{EvaluationDomain, Polynomial, Radix2EvaluationDomain}; 4 | use ark_std::{rand::Rng, test_rng, time::Duration}; 5 | use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; 6 | use ecfft_bn254::bn254::{Bn254EcFftParameters, F}; 7 | use ecfft_bn254::ecfft::EcFftParameters; 8 | 9 | fn evaluations(c: &mut Criterion) { 10 | type P = Bn254EcFftParameters; 11 | let precomputation = P::precompute(); 12 | let mut rng = test_rng(); 13 | 14 | let mut group = c.benchmark_group("evaluations"); 15 | group.measurement_time(Duration::from_secs(30)); 16 | 17 | for log_n in 1..=P::LOG_N { 18 | group.bench_with_input(BenchmarkId::new("ECFFT", log_n), &log_n, |b, _| { 19 | let coeffs: Vec = (0..1 << log_n).map(|_| rng.gen()).collect(); 20 | let poly = DensePolynomial { coeffs }; 21 | b.iter(|| precomputation.evaluate_over_domain(&poly)); 22 | }); 23 | group.bench_with_input(BenchmarkId::new("Naive", log_n), &log_n, |b, _| { 24 | let coeffs: Vec = (0..1 << log_n).map(|_| rng.gen()).collect(); 25 | let poly = DensePolynomial { coeffs }; 26 | let coset = P::sub_coset(P::LOG_N - log_n); 27 | b.iter(|| coset.iter().map(|x| poly.evaluate(x)).collect::>()); 28 | }); 29 | group.bench_with_input(BenchmarkId::new("Classic", log_n), &log_n, |b, _| { 30 | let coeffs: Vec = (0..1 << log_n).map(|_| rng.gen()).collect(); 31 | let poly = DensePolynomial { coeffs }; 32 | let domain = Radix2EvaluationDomain::new(1 << log_n).unwrap(); 33 | b.iter(|| poly.clone().evaluate_over_domain(domain)); 34 | }); 35 | } 36 | } 37 | 38 | criterion_group!(benches, evaluations); 39 | criterion_main!(benches); 40 | -------------------------------------------------------------------------------- /bls12-381_isogenies: -------------------------------------------------------------------------------- 1 | 10019441515960201495 2 | 12251399044645995793 3 | 7883452005439278481 4 | 3897211416163680810 5 | 8043153036852132201 6 | 1186559139229239160 7 | 18408465965524393751 8 | 3564319996663308883 9 | 13167227810984103763 10 | 8032970197714385118 11 | 8421743250879330653 12 | 1103305576847362107 13 | 1 14 | 0 15 | 0 16 | 0 17 | 0 18 | 0 19 | 18408465965524393751 20 | 3564319996663308883 21 | 13167227810984103763 22 | 8032970197714385118 23 | 8421743250879330653 24 | 1103305576847362107 25 | 1 26 | 0 27 | 0 28 | 0 29 | 0 30 | 0 31 | 13678759592201433294 32 | 7212231931081816801 33 | 13939722725754492816 34 | 15679769740714150805 35 | 16565475032941244217 36 | 891488198288952439 37 | 8415037976522685706 38 | 12113802800809865373 39 | 4067517103865493524 40 | 15920382160741277527 41 | 8821010936823862759 42 | 816212698230445693 43 | 1 44 | 0 45 | 0 46 | 0 47 | 0 48 | 0 49 | 8415037976522685706 50 | 12113802800809865373 51 | 4067517103865493524 52 | 15920382160741277527 53 | 8821010936823862759 54 | 816212698230445693 55 | 1 56 | 0 57 | 0 58 | 0 59 | 0 60 | 0 61 | 13768373587079970966 62 | 13591594964998628308 63 | 11178607828469245715 64 | 3060472346903200247 65 | 8346352947899793137 66 | 1860792228028368058 67 | 3403132453064507928 68 | 8122084302822309408 69 | 4971172301415635176 70 | 13220861153717094963 71 | 7761311440560808440 72 | 35926331685087957 73 | 1 74 | 0 75 | 0 76 | 0 77 | 0 78 | 0 79 | 3403132453064507928 80 | 8122084302822309408 81 | 4971172301415635176 82 | 13220861153717094963 83 | 7761311440560808440 84 | 35926331685087957 85 | 1 86 | 0 87 | 0 88 | 0 89 | 0 90 | 0 91 | 566485086674003112 92 | 10187503009177743248 93 | 9345006422218436079 94 | 12734529998390021717 95 | 11567377276498953531 96 | 97678424578032445 97 | 1186682694471157069 98 | 6107789994524334675 99 | 9133442492608412237 100 | 8147765463811928875 101 | 1355074038519925617 102 | 1253714296581697377 103 | 1 104 | 0 105 | 0 106 | 0 107 | 0 108 | 0 109 | 1186682694471157069 110 | 6107789994524334675 111 | 9133442492608412237 112 | 8147765463811928875 113 | 1355074038519925617 114 | 1253714296581697377 115 | 1 116 | 0 117 | 0 118 | 0 119 | 0 120 | 0 121 | 13025817563280527790 122 | 15920148317486223917 123 | 12801517570586670286 124 | 1922711738545966269 125 | 10704932973124122547 126 | 321394180905222044 127 | 14566861664576700502 128 | 12973876367195432274 129 | 1418888884721148034 130 | 17150838641415633577 131 | 4699759852038321975 132 | 1046820335619678563 133 | 1 134 | 0 135 | 0 136 | 0 137 | 0 138 | 0 139 | 14566861664576700502 140 | 12973876367195432274 141 | 1418888884721148034 142 | 17150838641415633577 143 | 4699759852038321975 144 | 1046820335619678563 145 | 1 146 | 0 147 | 0 148 | 0 149 | 0 150 | 0 151 | 7993931490129472369 152 | 10601192167037019644 153 | 16815745131951906247 154 | 10733987016552542896 155 | 473650001482363551 156 | 365676021772025507 157 | 12435878616468314442 158 | 9592527262028060717 159 | 9293767993320450822 160 | 11603568297149905469 161 | 6020889616964660073 162 | 649386649976797097 163 | 1 164 | 0 165 | 0 166 | 0 167 | 0 168 | 0 169 | 12435878616468314442 170 | 9592527262028060717 171 | 9293767993320450822 172 | 11603568297149905469 173 | 6020889616964660073 174 | 649386649976797097 175 | 1 176 | 0 177 | 0 178 | 0 179 | 0 180 | 0 181 | 12282959806770580550 182 | 14945098567201422304 183 | 5359494249081411916 184 | 14202274564053305871 185 | 15004318381881814972 186 | 658188031532117710 187 | 7539088966942017100 188 | 10356420454760621507 189 | 7991306242111168070 190 | 6980015071688390035 191 | 2801017018180153473 192 | 608425349230303388 193 | 1 194 | 0 195 | 0 196 | 0 197 | 0 198 | 0 199 | 7539088966942017100 200 | 10356420454760621507 201 | 7991306242111168070 202 | 6980015071688390035 203 | 2801017018180153473 204 | 608425349230303388 205 | 1 206 | 0 207 | 0 208 | 0 209 | 0 210 | 0 211 | 1110213206524052260 212 | 17147540021768853624 213 | 10522108666391736184 214 | 15793035521351469169 215 | 17190157918361592644 216 | 868297539334359189 217 | 2009332547071032703 218 | 10094293667211589087 219 | 7436546710477361989 220 | 6624298660655466892 221 | 2736872736578462299 222 | 1406718177212056576 223 | 1 224 | 0 225 | 0 226 | 0 227 | 0 228 | 0 229 | 2009332547071032703 230 | 10094293667211589087 231 | 7436546710477361989 232 | 6624298660655466892 233 | 2736872736578462299 234 | 1406718177212056576 235 | 1 236 | 0 237 | 0 238 | 0 239 | 0 240 | 0 241 | 2167052047193392018 242 | 10208022710033770678 243 | 9145639589359088601 244 | 514108235292001788 245 | 14308022258035305221 246 | 1386012061215610702 247 | 4695806414304454529 248 | 9358947986483791058 249 | 14594381182976433485 250 | 2827816235374517627 251 | 4669483425530013101 252 | 1393805669968593041 253 | 1 254 | 0 255 | 0 256 | 0 257 | 0 258 | 0 259 | 4695806414304454529 260 | 9358947986483791058 261 | 14594381182976433485 262 | 2827816235374517627 263 | 4669483425530013101 264 | 1393805669968593041 265 | 1 266 | 0 267 | 0 268 | 0 269 | 0 270 | 0 271 | 10961714003972025645 272 | 9242111797547619 273 | 3821482454964077504 274 | 16591439486289384871 275 | 18204972621547608888 276 | 314495175912527816 277 | 10515575031066601338 278 | 9432276892068769168 279 | 17248241826232363055 280 | 5498057551951818293 281 | 5965541952762474285 282 | 1825141558858618931 283 | 1 284 | 0 285 | 0 286 | 0 287 | 0 288 | 0 289 | 10515575031066601338 290 | 9432276892068769168 291 | 17248241826232363055 292 | 5498057551951818293 293 | 5965541952762474285 294 | 1825141558858618931 295 | 1 296 | 0 297 | 0 298 | 0 299 | 0 300 | 0 301 | 11670562620781309789 302 | 5249836007435377455 303 | 14263120024033478734 304 | 7205003033382913599 305 | 4325381513385695615 306 | 958103570245919355 307 | 2997839840814596947 308 | 16688034164447826378 309 | 1939323879791141621 310 | 3049580938742080707 311 | 10092061693501524143 312 | 1307363670701959350 313 | 1 314 | 0 315 | 0 316 | 0 317 | 0 318 | 0 319 | 2997839840814596947 320 | 16688034164447826378 321 | 1939323879791141621 322 | 3049580938742080707 323 | 10092061693501524143 324 | 1307363670701959350 325 | 1 326 | 0 327 | 0 328 | 0 329 | 0 330 | 0 331 | 13084925592415542744 332 | 8196833794247957739 333 | 14947799882832925094 334 | 8188098974291774777 335 | 2249813432251635351 336 | 1454035010094322039 337 | 16165154560604004703 338 | 12793512026030073843 339 | 3913346827688866655 340 | 12355833684887840311 341 | 15752072201265304985 342 | 343855986661811343 343 | 1 344 | 0 345 | 0 346 | 0 347 | 0 348 | 0 349 | 16165154560604004703 350 | 12793512026030073843 351 | 3913346827688866655 352 | 12355833684887840311 353 | 15752072201265304985 354 | 343855986661811343 355 | 1 356 | 0 357 | 0 358 | 0 359 | 0 360 | 0 361 | 18397483683703704173 362 | 15893543488937901180 363 | 450223839400632586 364 | 6237663134144300753 365 | 901181374539311993 366 | 1052029291739469258 367 | 12333475341755350910 368 | 10029807894899527344 369 | 15779433125277103514 370 | 9795291872279951797 371 | 12287543020096150844 372 | 1793143453620295079 373 | 1 374 | 0 375 | 0 376 | 0 377 | 0 378 | 0 379 | 12333475341755350910 380 | 10029807894899527344 381 | 15779433125277103514 382 | 9795291872279951797 383 | 12287543020096150844 384 | 1793143453620295079 385 | 1 386 | 0 387 | 0 388 | 0 389 | 0 390 | 0 391 | 4678611711544242813 392 | 10982920136564552910 393 | 17516689699596113657 394 | 570299229325703871 395 | 6592690586405349750 396 | 994172016823770572 397 | 3668227902052337010 398 | 13316392548080074521 399 | 10816899007679548060 400 | 11172902568253762335 401 | 7545024823586310754 402 | 1015629472623351456 403 | 1 404 | 0 405 | 0 406 | 0 407 | 0 408 | 0 409 | 3668227902052337010 410 | 13316392548080074521 411 | 10816899007679548060 412 | 11172902568253762335 413 | 7545024823586310754 414 | 1015629472623351456 415 | 1 416 | 0 417 | 0 418 | 0 419 | 0 420 | 0 -------------------------------------------------------------------------------- /bn254_isogenies: -------------------------------------------------------------------------------- 1 | 17328056526601235878 2 | 13509310317870252778 3 | 17829493617456573088 4 | 1069804441592306257 5 | 4361217292254815710 6 | 5731219552351903952 7 | 7872573279406571821 8 | 1743843693402004043 9 | 1 10 | 0 11 | 0 12 | 0 13 | 4361217292254815710 14 | 5731219552351903952 15 | 7872573279406571821 16 | 1743843693402004043 17 | 1 18 | 0 19 | 0 20 | 0 21 | 14657749244776745846 22 | 16508790979857666950 23 | 18315597247613286358 24 | 1730337075437574957 25 | 5808091610280436774 26 | 4961817891533785992 27 | 7272782023091813329 28 | 395103364866840014 29 | 1 30 | 0 31 | 0 32 | 0 33 | 5808091610280436774 34 | 4961817891533785992 35 | 7272782023091813329 36 | 395103364866840014 37 | 1 38 | 0 39 | 0 40 | 0 41 | 3212978791115741147 42 | 3287057754728011730 43 | 14168161128189354291 44 | 293651531752948853 45 | 6411214533053155099 46 | 17569828599410405076 47 | 17466312037531455637 48 | 1534443183522201273 49 | 1 50 | 0 51 | 0 52 | 0 53 | 6411214533053155099 54 | 17569828599410405076 55 | 17466312037531455637 56 | 1534443183522201273 57 | 1 58 | 0 59 | 0 60 | 0 61 | 1197470391922381217 62 | 4740569454550983987 63 | 17489333788275958433 64 | 1513174446082297656 65 | 12704818141406185330 66 | 17360465425110800360 67 | 7486605681706247064 68 | 1069707573327383522 69 | 1 70 | 0 71 | 0 72 | 0 73 | 12704818141406185330 74 | 17360465425110800360 75 | 7486605681706247064 76 | 1069707573327383522 77 | 1 78 | 0 79 | 0 80 | 0 81 | 457143965381547451 82 | 11089794144018527328 83 | 15246025750041077789 84 | 182940366018517564 85 | 10524768395095527344 86 | 10933373754713201783 87 | 1599509174018058072 88 | 2234013556564145525 89 | 1 90 | 0 91 | 0 92 | 0 93 | 10524768395095527344 94 | 10933373754713201783 95 | 1599509174018058072 96 | 2234013556564145525 97 | 1 98 | 0 99 | 0 100 | 0 101 | 15171777418537627237 102 | 3124625772862394222 103 | 10093934188561156038 104 | 2302116650422300276 105 | 5284655034396254534 106 | 17178060130540162537 107 | 5209909404094876941 108 | 2127650080308184615 109 | 1 110 | 0 111 | 0 112 | 0 113 | 5284655034396254534 114 | 17178060130540162537 115 | 5209909404094876941 116 | 2127650080308184615 117 | 1 118 | 0 119 | 0 120 | 0 121 | 11995356816446055427 122 | 3123380196566193385 123 | 4649044392572630382 124 | 585493087127408777 125 | 3405755545918090396 126 | 3418335791132674795 127 | 18030764061133166614 128 | 3220069259296617730 129 | 1 130 | 0 131 | 0 132 | 0 133 | 3405755545918090396 134 | 3418335791132674795 135 | 18030764061133166614 136 | 3220069259296617730 137 | 1 138 | 0 139 | 0 140 | 0 141 | 1894017064282558722 142 | 12114622394964973170 143 | 4834442492812808613 144 | 2369592208880607861 145 | 3276564269566047820 146 | 12391740575802804390 147 | 15868952204709103332 148 | 71746980055315253 149 | 1 150 | 0 151 | 0 152 | 0 153 | 3276564269566047820 154 | 12391740575802804390 155 | 15868952204709103332 156 | 71746980055315253 157 | 1 158 | 0 159 | 0 160 | 0 161 | 17318629908150799259 162 | 7412129173882167829 163 | 7913243490614534713 164 | 2269278913218073579 165 | 18386146615358104348 166 | 660963884756719043 167 | 9049037380886854377 168 | 2649006244209432625 169 | 1 170 | 0 171 | 0 172 | 0 173 | 18386146615358104348 174 | 660963884756719043 175 | 9049037380886854377 176 | 2649006244209432625 177 | 1 178 | 0 179 | 0 180 | 0 181 | 17376534975274750004 182 | 14849367639812012305 183 | 10663408490940437065 184 | 1898354535145787790 185 | 12606470791617736501 186 | 4738100553450724479 187 | 5167362736903686031 188 | 1760702785282033861 189 | 1 190 | 0 191 | 0 192 | 0 193 | 12606470791617736501 194 | 4738100553450724479 195 | 5167362736903686031 196 | 1760702785282033861 197 | 1 198 | 0 199 | 0 200 | 0 201 | 8640224667271480015 202 | 15762514891968514763 203 | 14045772239709306720 204 | 2498179523787391813 205 | 4013894483028273451 206 | 2578391161573647666 207 | 12482678896356328276 208 | 1233229437763040671 209 | 1 210 | 0 211 | 0 212 | 0 213 | 4013894483028273451 214 | 2578391161573647666 215 | 12482678896356328276 216 | 1233229437763040671 217 | 1 218 | 0 219 | 0 220 | 0 221 | 5677485845661459682 222 | 2570193734270651099 223 | 10536437871892092274 224 | 2368712173648736722 225 | 5111729599102922276 226 | 16899843669661563667 227 | 8087861106745999671 228 | 214293734844239044 229 | 1 230 | 0 231 | 0 232 | 0 233 | 5111729599102922276 234 | 16899843669661563667 235 | 8087861106745999671 236 | 214293734844239044 237 | 1 238 | 0 239 | 0 240 | 0 241 | 9384929795705688470 242 | 5025530318578587566 243 | 14545744865835530352 244 | 684897024569318643 245 | 13550146825510563740 246 | 8909736062887159659 247 | 9228334219276209206 248 | 3078379185946684953 249 | 1 250 | 0 251 | 0 252 | 0 253 | 13550146825510563740 254 | 8909736062887159659 255 | 9228334219276209206 256 | 3078379185946684953 257 | 1 258 | 0 259 | 0 260 | 0 -------------------------------------------------------------------------------- /curve25519_isogenies: -------------------------------------------------------------------------------- 1 | 18250753526955890374 2 | 3431703125903537667 3 | 15402216077906893037 4 | 3268992335890600570 5 | 13280733386837440049 6 | 8025111811263743599 7 | 2155338667403011594 8 | 8084818981551498536 9 | 1 10 | 0 11 | 0 12 | 0 13 | 13280733386837440049 14 | 8025111811263743599 15 | 2155338667403011594 16 | 8084818981551498536 17 | 1 18 | 0 19 | 0 20 | 0 21 | 13988032677850752633 22 | 3405040797357317185 23 | 17557625663834405809 24 | 3627356277144699518 25 | 5088831315445513753 26 | 867270965838147534 27 | 12888396179951232214 28 | 6108128196867531812 29 | 1 30 | 0 31 | 0 32 | 0 33 | 5088831315445513753 34 | 867270965838147534 35 | 12888396179951232214 36 | 6108128196867531812 37 | 1 38 | 0 39 | 0 40 | 0 41 | 3460629074383107097 42 | 11596093038108756185 43 | 12252849755156509843 44 | 5293252798013863836 45 | 2061584853165631577 46 | 15160946875896142717 47 | 13201820957508304983 48 | 5983057767941958592 49 | 1 50 | 0 51 | 0 52 | 0 53 | 2061584853165631577 54 | 15160946875896142717 55 | 13201820957508304983 56 | 5983057767941958592 57 | 1 58 | 0 59 | 0 60 | 0 61 | 3506784914664150896 62 | 4577896222734806803 63 | 16910116971431611479 64 | 7208280856766391509 65 | 7697946304796749489 66 | 1886580025145639742 67 | 13994825257071670471 68 | 6178861941383745066 69 | 1 70 | 0 71 | 0 72 | 0 73 | 7697946304796749489 74 | 1886580025145639742 75 | 13994825257071670471 76 | 6178861941383745066 77 | 1 78 | 0 79 | 0 80 | 0 81 | 17935226452538035921 82 | 1371425479461507299 83 | 800673883954308537 84 | 5996827390664755035 85 | 5581939838366809596 86 | 8836319426390445837 87 | 18418034832512162616 88 | 7458859483996927954 89 | 1 90 | 0 91 | 0 92 | 0 93 | 5581939838366809596 94 | 8836319426390445837 95 | 18418034832512162616 96 | 7458859483996927954 97 | 1 98 | 0 99 | 0 100 | 0 101 | 12249249633422166199 102 | 2944335715359061693 103 | 8013229132642202922 104 | 4702773634747109447 105 | 5051465317776499721 106 | 3023072373907489444 107 | 9549044171287303895 108 | 770085118603800451 109 | 1 110 | 0 111 | 0 112 | 0 113 | 5051465317776499721 114 | 3023072373907489444 115 | 9549044171287303895 116 | 770085118603800451 117 | 1 118 | 0 119 | 0 120 | 0 121 | 3939547621768140960 122 | 9318688003897565113 123 | 7615713160045779131 124 | 7095246151228311755 125 | 5638968565136109135 126 | 6661881412868591479 127 | 12618078979978240652 128 | 1545642533508266215 129 | 1 130 | 0 131 | 0 132 | 0 133 | 5638968565136109135 134 | 6661881412868591479 135 | 12618078979978240652 136 | 1545642533508266215 137 | 1 138 | 0 139 | 0 140 | 0 141 | 936144587796917484 142 | 3180196862151665757 143 | 11731361653214014303 144 | 7560922247195029747 145 | 8163153901739529131 146 | 7514846908210010678 147 | 4460884577132751796 148 | 7897495809706014420 149 | 1 150 | 0 151 | 0 152 | 0 153 | 8163153901739529131 154 | 7514846908210010678 155 | 4460884577132751796 156 | 7897495809706014420 157 | 1 158 | 0 159 | 0 160 | 0 161 | 16183048265987989632 162 | 404188677782900007 163 | 8793443123573247567 164 | 276964536823584193 165 | 15282238391053763379 166 | 770032220178647876 167 | 17468034931924312949 168 | 1331779446341047334 169 | 1 170 | 0 171 | 0 172 | 0 173 | 15282238391053763379 174 | 770032220178647876 175 | 17468034931924312949 176 | 1331779446341047334 177 | 1 178 | 0 179 | 0 180 | 0 181 | 15742282521559883706 182 | 5142197949451316312 183 | 12256032812940121595 184 | 6041958765955045909 185 | 5139443376761881938 186 | 14500676489964581499 187 | 15190192606243821224 188 | 2764486858992725404 189 | 1 190 | 0 191 | 0 192 | 0 193 | 5139443376761881938 194 | 14500676489964581499 195 | 15190192606243821224 196 | 2764486858992725404 197 | 1 198 | 0 199 | 0 200 | 0 201 | 11665931354335512913 202 | 4163327265794331971 203 | 1587905529060105880 204 | 6385175905196867118 205 | 7112619987346182284 206 | 9538393238901028310 207 | 7330802162001586203 208 | 6997400698406799481 209 | 1 210 | 0 211 | 0 212 | 0 213 | 7112619987346182284 214 | 9538393238901028310 215 | 7330802162001586203 216 | 6997400698406799481 217 | 1 218 | 0 219 | 0 220 | 0 221 | 440859382812983676 222 | 13263634456547363460 223 | 2843380326767550817 224 | 2246481593061454925 225 | 6843308389272014864 226 | 17573459978444679137 227 | 9607587987388132471 228 | 6107098248203640919 229 | 1 230 | 0 231 | 0 232 | 0 233 | 6843308389272014864 234 | 17573459978444679137 235 | 9607587987388132471 236 | 6107098248203640919 237 | 1 238 | 0 239 | 0 240 | 0 241 | 2843209345878618899 242 | 12187158007177273730 243 | 6631331053902469362 244 | 2598999973123072897 245 | 3649798095907742354 246 | 16203758127337955920 247 | 4006782705514563825 248 | 4759146586393229551 249 | 1 250 | 0 251 | 0 252 | 0 253 | 3649798095907742354 254 | 16203758127337955920 255 | 4006782705514563825 256 | 4759146586393229551 257 | 1 258 | 0 259 | 0 260 | 0 261 | 16282143466422643478 262 | 3879929017130651767 263 | 7820727319359763989 264 | 2056188985745148280 265 | 16637356634947125645 266 | 10006043581239987343 267 | 6698695429675629455 268 | 1856146740272988716 269 | 1 270 | 0 271 | 0 272 | 0 273 | 16637356634947125645 274 | 10006043581239987343 275 | 6698695429675629455 276 | 1856146740272988716 277 | 1 278 | 0 279 | 0 280 | 0 281 | 13549990745049515663 282 | 11055704921160714433 283 | 14336809372416130412 284 | 7104431271070208359 285 | 1687399986665692738 286 | 12733095527298667534 287 | 14740736045835730062 288 | 6513025558337979689 289 | 1 290 | 0 291 | 0 292 | 0 293 | 1687399986665692738 294 | 12733095527298667534 295 | 14740736045835730062 296 | 6513025558337979689 297 | 1 298 | 0 299 | 0 300 | 0 -------------------------------------------------------------------------------- /get_params.sage: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | def to_limbs(x, n): 5 | mask = 2 ^ 64 - 1 6 | return [(x >> (64 * i)) & mask for i in range(n)] 7 | 8 | 9 | def curve_params(): 10 | args = sys.argv[1:] 11 | if len(args) == 4: 12 | p, a, b = [int(x, 16) if x.startswith("0x") else int(x) for x in args[:-1]] 13 | filename = args[-1] 14 | elif len(args) > 0: 15 | print( 16 | f"""Usage for curve Y^2 = X^3 + aX + b over basefield GF(p). Integers in base 10 or 16 with 0x prefix. 17 | sage {sys.argv[0]} p a b output_filename 18 | 19 | By default 20 | sage {sys.argv[0]} 21 | generates parameters for the BN254 curve. 22 | """ 23 | ) 24 | sys.exit() 25 | else: 26 | # BN254 parameters 27 | p, a, b, filename = ( 28 | 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD47, 29 | 1, 30 | 5612291247948481584627780310922020304781354847659642188369727566000581075360, 31 | "bn254", 32 | ) 33 | return p, a, b, filename 34 | 35 | 36 | p, a, b, filename = curve_params() 37 | F = GF(p) 38 | E = EllipticCurve(F, [a, b]) 39 | O = E.order() 40 | n = O.p_primary_part(2) 41 | log_n = n.log(2) 42 | print(f"Curve's scalar field 2-adicity: {log_n}") 43 | 44 | while True: 45 | g = E.random_point() 46 | G = (O // n) * g 47 | for i in range(log_n): 48 | if ((2 ^ i) * G).is_zero(): 49 | break 50 | else: 51 | break 52 | 53 | assert (n * G).is_zero() 54 | R = E.random_element() 55 | H = [R + i * G for i in range(2 ^ log_n)] 56 | L = [h.xy()[0] for h in H] 57 | S = [L[i] for i in range(0, n, 2)] 58 | S_prime = [L[i] for i in range(1, n, 2)] 59 | 60 | # Number of 64-bit limbs needed to represent field elements 61 | num_limbs = (p.bit_length() + 63) // 64 62 | s = "\n".join([str(l) for x in L for l in to_limbs(int(x), num_limbs)]) 63 | open(f"{filename}_coset", "w").write(s) 64 | 65 | 66 | def isogenies(log_n, S, S_prime, E): 67 | isos = [] 68 | for i in range(log_n, 0, -1): 69 | n = 1 << i 70 | nn = n // 2 71 | 72 | for iso in E.isogenies_prime_degree(2): 73 | psi = iso.x_rational_map() 74 | if len(set([psi(x) for x in S])) == nn: 75 | break 76 | isos.append(psi) 77 | S = [psi(x) for x in S[:nn]] 78 | S_prime = [psi(x) for x in S_prime[:nn]] 79 | E = iso.codomain() 80 | 81 | return isos 82 | 83 | 84 | isos = isogenies(log_n - 1, S, S_prime, E) 85 | s = "\n".join( 86 | [ 87 | str(l) 88 | for psi in isos 89 | for coeff in list(psi.numerator()) + list(psi.denominator()) 90 | for l in to_limbs(int(coeff), num_limbs) 91 | ] 92 | ) 93 | open(f"{filename}_isogenies", "w").write(s) 94 | -------------------------------------------------------------------------------- /src/bls12_381.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | 3 | use crate::{ecfft::EcFftParameters, utils::isogeny::Isogeny}; 4 | use ark_ff::BigInteger384; 5 | 6 | type F = ark_bls12_381::Fq; 7 | /// Number of 64-bit limbs needed to represent field elements. 8 | const NUM_LIMBS: usize = 6; 9 | 10 | /// ECFFT parameters for the BLS12-381 base field `F`. 11 | /// Computed with the curve `E = EllipticCurve(F, [a, b])` with 12 | /// `a, b = 0x287cc81c41f14f729fcbc12f57b2dd49bdcfc64938f9ad946c9fe5288aa3e9653670d336b09c058baad66ae717c1df7, 0x33f44f9b6fd7ba0080f0ad4843e076da70b11e6846d41e19792a15a4920e2294f9c971db67257eefea71c70514c6e54` 13 | pub struct Bls12381Parameters; 14 | 15 | impl EcFftParameters for Bls12381Parameters { 16 | /// The curve `E` has order `4002409555221667393417789825735904156556882819939007885330472032889288775404654397856791416969022033299503997812736` 17 | /// with factorization `2^15 * 122143846289723736371392511771725590715236902463958980875563721706826439679097119075219464629181580606063964777` 18 | const LOG_N: usize = 15; 19 | 20 | const N: usize = 1 << Self::LOG_N; 21 | 22 | /// Get the coset from the `bls12-381_coset` file. This file can be generated by running `get_params.sage`. 23 | fn coset() -> Vec { 24 | std::fs::read_to_string("bls12-381_coset") 25 | .expect("Run `get_params.sage` to generate the coset.") 26 | .split_whitespace() 27 | .map(|s| s.parse().unwrap()) 28 | .collect::>() 29 | .chunks(NUM_LIMBS) 30 | .map(|chunk| BigInteger384::new(chunk.try_into().unwrap()).into()) 31 | .collect() 32 | } 33 | 34 | /// Get the isogenies from the `bls12-381_isogenies` file. This file can be generated by running `get_params.sage`. 35 | fn isogenies() -> Vec> { 36 | std::fs::read_to_string("bls12-381_isogenies") 37 | .expect("Run `get_params.sage` to generate the coset.") 38 | .split_whitespace() 39 | .map(|s| s.parse().unwrap()) 40 | .collect::>() 41 | .chunks(5 * NUM_LIMBS) 42 | .map(|chunk| { 43 | let numerator = (0..3) 44 | .map(|i| { 45 | BigInteger384::new( 46 | chunk[i * NUM_LIMBS..(i + 1) * NUM_LIMBS] 47 | .try_into() 48 | .unwrap(), 49 | ) 50 | .into() 51 | }) 52 | .collect::>() 53 | .try_into() 54 | .unwrap(); 55 | let denominator = (3..5) 56 | .map(|i| { 57 | BigInteger384::new( 58 | chunk[i * NUM_LIMBS..(i + 1) * NUM_LIMBS] 59 | .try_into() 60 | .unwrap(), 61 | ) 62 | .into() 63 | }) 64 | .collect::>() 65 | .try_into() 66 | .unwrap(); 67 | Isogeny { 68 | numerator, 69 | denominator, 70 | } 71 | }) 72 | .collect() 73 | } 74 | } 75 | 76 | #[cfg(test)] 77 | mod tests { 78 | use crate::ecfft::{EcFftCosetPrecomputation, EcFftParameters, EcFftPrecomputationStep}; 79 | 80 | use super::{Bls12381Parameters, F}; 81 | use ark_ff::PrimeField; 82 | use ark_poly::{univariate::DensePolynomial, Polynomial}; 83 | use ark_std::{ 84 | rand::{distributions::Standard, prelude::Distribution, Rng}, 85 | test_rng, 86 | }; 87 | 88 | #[test] 89 | /// Tests that precomputations don't panic. 90 | fn test_precompute() { 91 | Bls12381Parameters::precompute_on_coset(&Bls12381Parameters::coset()); 92 | Bls12381Parameters::precompute_on_coset( 93 | &Bls12381Parameters::coset() 94 | .into_iter() 95 | .step_by(2) 96 | .collect::>(), 97 | ); 98 | } 99 | 100 | /// Tests the extend function with a polynomial of degree `2^i - 1`. 101 | fn test_extend_i>( 102 | i: usize, 103 | precomputation: &EcFftCosetPrecomputation, 104 | ) where 105 | Standard: Distribution, 106 | { 107 | let n = 1 << i; 108 | let mut rng = test_rng(); 109 | let coeffs: Vec = (0..n).map(|_| rng.gen()).collect(); 110 | let poly = DensePolynomial { coeffs }; 111 | let EcFftPrecomputationStep { s, s_prime, .. } = 112 | &precomputation.steps[Bls12381Parameters::LOG_N - 1 - i]; 113 | let evals_s = s.iter().map(|x| poly.evaluate(x)).collect::>(); 114 | let evals_s_prime = s_prime.iter().map(|x| poly.evaluate(x)).collect::>(); 115 | assert_eq!(evals_s_prime, precomputation.extend(&evals_s)); 116 | } 117 | 118 | #[test] 119 | /// Tests the extend function for various degrees. 120 | fn test_extend() { 121 | let precomputation = Bls12381Parameters::precompute_on_coset(&Bls12381Parameters::coset()); 122 | for i in 1..Bls12381Parameters::LOG_N { 123 | test_extend_i::(i, &precomputation); 124 | } 125 | } 126 | 127 | #[test] 128 | /// Tests the `evaluate_over_domain` function for various degrees. 129 | fn test_eval() { 130 | type P = Bls12381Parameters; 131 | let precomputation = P::precompute(); 132 | for i in 0..P::LOG_N { 133 | let mut rng = test_rng(); 134 | let coeffs: Vec = (0..P::N >> i).map(|_| rng.gen()).collect(); 135 | let poly = DensePolynomial { coeffs }; 136 | let now = std::time::Instant::now(); 137 | let evals = P::sub_coset(i) 138 | .iter() 139 | .map(|x| poly.evaluate(x)) 140 | .collect::>(); 141 | dbg!(now.elapsed().as_secs_f32()); 142 | assert_eq!(evals, precomputation.evaluate_over_domain(&poly)); 143 | dbg!(now.elapsed().as_secs_f32()); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/bn254.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | 3 | use crate::{ecfft::EcFftParameters, utils::isogeny::Isogeny}; 4 | use ark_ff::BigInteger256; 5 | 6 | pub type F = ark_bn254::Fq; 7 | /// Number of 64-bit limbs needed to represent field elements. 8 | const NUM_LIMBS: usize = 4; 9 | 10 | /// ECFFT parameters for the BN254 base field `F`. 11 | /// Computed with the curve `E = EllipticCurve(F, [a, b])` with 12 | /// `a, b = 1, 5612291247948481584627780310922020304781354847659642188369727566000581075360`. 13 | pub struct Bn254EcFftParameters; 14 | 15 | impl EcFftParameters for Bn254EcFftParameters { 16 | /// The curve `E` has order `21888242871839275222246405745257275088712935808829559400805562964428910444544` 17 | /// with factorization `2^14 * 3^2 * 229 * 503 * 205460939795467 * 55374745393148401254803 * 113267149255983544517087125127`. 18 | const LOG_N: usize = 14; 19 | 20 | const N: usize = 1 << Self::LOG_N; 21 | 22 | /// Get the coset from the `bn254_coset` file. This file can be generated by running `get_params.sage`. 23 | fn coset() -> Vec { 24 | std::fs::read_to_string("bn254_coset") 25 | .expect("Run `get_params.sage` to generate the coset.") 26 | .split_whitespace() 27 | .map(|s| s.parse().unwrap()) 28 | .collect::>() 29 | .chunks(NUM_LIMBS) 30 | .map(|chunk| BigInteger256::new(chunk.try_into().unwrap()).into()) 31 | .collect() 32 | } 33 | 34 | /// Get the isogenies from the `bn254_isogenies` file. This file can be generated by running `get_params.sage`. 35 | fn isogenies() -> Vec> { 36 | std::fs::read_to_string("bn254_isogenies") 37 | .expect("Run `get_params.sage` to generate the coset.") 38 | .split_whitespace() 39 | .map(|s| s.parse().unwrap()) 40 | .collect::>() 41 | .chunks(5 * NUM_LIMBS) 42 | .map(|chunk| { 43 | let numerator = (0..3) 44 | .map(|i| { 45 | BigInteger256::new( 46 | chunk[i * NUM_LIMBS..(i + 1) * NUM_LIMBS] 47 | .try_into() 48 | .unwrap(), 49 | ) 50 | .into() 51 | }) 52 | .collect::>() 53 | .try_into() 54 | .unwrap(); 55 | let denominator = (3..5) 56 | .map(|i| { 57 | BigInteger256::new( 58 | chunk[i * NUM_LIMBS..(i + 1) * NUM_LIMBS] 59 | .try_into() 60 | .unwrap(), 61 | ) 62 | .into() 63 | }) 64 | .collect::>() 65 | .try_into() 66 | .unwrap(); 67 | Isogeny { 68 | numerator, 69 | denominator, 70 | } 71 | }) 72 | .collect() 73 | } 74 | } 75 | 76 | #[cfg(test)] 77 | mod tests { 78 | use crate::ecfft::{EcFftCosetPrecomputation, EcFftParameters, EcFftPrecomputationStep}; 79 | 80 | use crate::bn254::{Bn254EcFftParameters, F}; 81 | use ark_ff::PrimeField; 82 | use ark_poly::{univariate::DensePolynomial, Polynomial}; 83 | use ark_std::{ 84 | rand::{distributions::Standard, prelude::Distribution, Rng}, 85 | test_rng, 86 | }; 87 | 88 | #[test] 89 | /// Tests that precomputations don't panic. 90 | fn test_precompute() { 91 | Bn254EcFftParameters::precompute_on_coset(&Bn254EcFftParameters::coset()); 92 | Bn254EcFftParameters::precompute_on_coset( 93 | &Bn254EcFftParameters::coset() 94 | .into_iter() 95 | .step_by(2) 96 | .collect::>(), 97 | ); 98 | } 99 | 100 | /// Tests the extend function with a polynomial of degree `2^i - 1`. 101 | fn test_extend_i>( 102 | i: usize, 103 | precomputation: &EcFftCosetPrecomputation, 104 | ) where 105 | Standard: Distribution, 106 | { 107 | let n = 1 << i; 108 | let mut rng = test_rng(); 109 | let coeffs: Vec = (0..n).map(|_| rng.gen()).collect(); 110 | let poly = DensePolynomial { coeffs }; 111 | let EcFftPrecomputationStep { s, s_prime, .. } = 112 | &precomputation.steps[Bn254EcFftParameters::LOG_N - 1 - i]; 113 | let evals_s = s.iter().map(|x| poly.evaluate(x)).collect::>(); 114 | let evals_s_prime = s_prime.iter().map(|x| poly.evaluate(x)).collect::>(); 115 | assert_eq!(evals_s_prime, precomputation.extend(&evals_s)); 116 | } 117 | 118 | #[test] 119 | /// Tests the extend function for various degrees. 120 | fn test_extend() { 121 | let precomputation = 122 | Bn254EcFftParameters::precompute_on_coset(&Bn254EcFftParameters::coset()); 123 | for i in 1..Bn254EcFftParameters::LOG_N { 124 | test_extend_i::(i, &precomputation); 125 | } 126 | } 127 | 128 | #[test] 129 | /// Tests the `evaluate_over_domain` function for various degrees. 130 | fn test_eval() { 131 | type P = Bn254EcFftParameters; 132 | let precomputation = P::precompute(); 133 | for i in 0..P::LOG_N { 134 | let mut rng = test_rng(); 135 | let coeffs: Vec = (0..P::N >> i).map(|_| rng.gen()).collect(); 136 | let poly = DensePolynomial { coeffs }; 137 | let now = std::time::Instant::now(); 138 | let evals = P::sub_coset(i) 139 | .iter() 140 | .map(|x| poly.evaluate(x)) 141 | .collect::>(); 142 | dbg!(now.elapsed().as_secs_f32()); 143 | assert_eq!(evals, precomputation.evaluate_over_domain(&poly)); 144 | dbg!(now.elapsed().as_secs_f32()); 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/curve25519.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | 3 | use crate::{ecfft::EcFftParameters, utils::isogeny::Isogeny}; 4 | use ark_ff::BigInteger256; 5 | 6 | type F = ark_curve25519::Fq; 7 | /// Number of 64-bit limbs needed to represent field elements. 8 | const NUM_LIMBS: usize = 4; 9 | 10 | /// ECFFT parameters for the Curve25519 base field `F`. 11 | /// Computed with the curve `E = EllipticCurve(F, [a, b])` with 12 | /// `a, b = 0x1, 0xd63` 13 | pub struct Curve25519Parameters; 14 | 15 | impl EcFftParameters for Curve25519Parameters { 16 | /// The curve `E` has order `57896044618658097711785492504343953926261577544886303154527763127846362480640` 17 | /// with factorization `2^16 * 883423532389192164791648750371459257908044090955906725380367479367772865` 18 | const LOG_N: usize = 16; 19 | 20 | const N: usize = 1 << Self::LOG_N; 21 | 22 | /// Get the coset from the `curve25519_coset` file. This file can be generated by running `get_params.sage`. 23 | fn coset() -> Vec { 24 | std::fs::read_to_string("curve25519_coset") 25 | .expect("Run `get_params.sage` to generate the coset.") 26 | .split_whitespace() 27 | .map(|s| s.parse().unwrap()) 28 | .collect::>() 29 | .chunks(NUM_LIMBS) 30 | .map(|chunk| BigInteger256::new(chunk.try_into().unwrap()).into()) 31 | .collect() 32 | } 33 | 34 | /// Get the isogenies from the `curve25519_isogenies` file. This file can be generated by running `get_params.sage`. 35 | fn isogenies() -> Vec> { 36 | std::fs::read_to_string("curve25519_isogenies") 37 | .expect("Run `get_params.sage` to generate the coset.") 38 | .split_whitespace() 39 | .map(|s| s.parse().unwrap()) 40 | .collect::>() 41 | .chunks(5 * NUM_LIMBS) 42 | .map(|chunk| { 43 | let numerator = (0..3) 44 | .map(|i| { 45 | BigInteger256::new( 46 | chunk[i * NUM_LIMBS..(i + 1) * NUM_LIMBS] 47 | .try_into() 48 | .unwrap(), 49 | ) 50 | .into() 51 | }) 52 | .collect::>() 53 | .try_into() 54 | .unwrap(); 55 | let denominator = (3..5) 56 | .map(|i| { 57 | BigInteger256::new( 58 | chunk[i * NUM_LIMBS..(i + 1) * NUM_LIMBS] 59 | .try_into() 60 | .unwrap(), 61 | ) 62 | .into() 63 | }) 64 | .collect::>() 65 | .try_into() 66 | .unwrap(); 67 | Isogeny { 68 | numerator, 69 | denominator, 70 | } 71 | }) 72 | .collect() 73 | } 74 | } 75 | 76 | #[cfg(test)] 77 | mod tests { 78 | use crate::ecfft::{EcFftCosetPrecomputation, EcFftParameters, EcFftPrecomputationStep}; 79 | 80 | use super::{Curve25519Parameters, F}; 81 | use ark_ff::PrimeField; 82 | use ark_poly::{univariate::DensePolynomial, Polynomial}; 83 | use ark_std::{ 84 | rand::{distributions::Standard, prelude::Distribution, Rng}, 85 | test_rng, 86 | }; 87 | 88 | #[test] 89 | /// Tests that precomputations don't panic. 90 | fn test_precompute() { 91 | Curve25519Parameters::precompute_on_coset(&Curve25519Parameters::coset()); 92 | Curve25519Parameters::precompute_on_coset( 93 | &Curve25519Parameters::coset() 94 | .into_iter() 95 | .step_by(2) 96 | .collect::>(), 97 | ); 98 | } 99 | 100 | /// Tests the extend function with a polynomial of degree `2^i - 1`. 101 | fn test_extend_i>( 102 | i: usize, 103 | precomputation: &EcFftCosetPrecomputation, 104 | ) where 105 | Standard: Distribution, 106 | { 107 | let n = 1 << i; 108 | let mut rng = test_rng(); 109 | let coeffs: Vec = (0..n).map(|_| rng.gen()).collect(); 110 | let poly = DensePolynomial { coeffs }; 111 | let EcFftPrecomputationStep { s, s_prime, .. } = 112 | &precomputation.steps[Curve25519Parameters::LOG_N - 1 - i]; 113 | let evals_s = s.iter().map(|x| poly.evaluate(x)).collect::>(); 114 | let evals_s_prime = s_prime.iter().map(|x| poly.evaluate(x)).collect::>(); 115 | assert_eq!(evals_s_prime, precomputation.extend(&evals_s)); 116 | } 117 | 118 | #[test] 119 | /// Tests the extend function for various degrees. 120 | fn test_extend() { 121 | let precomputation = 122 | Curve25519Parameters::precompute_on_coset(&Curve25519Parameters::coset()); 123 | for i in 1..Curve25519Parameters::LOG_N { 124 | test_extend_i::(i, &precomputation); 125 | } 126 | } 127 | 128 | #[test] 129 | /// Tests the `evaluate_over_domain` function for various degrees. 130 | fn test_eval() { 131 | type P = Curve25519Parameters; 132 | let precomputation = P::precompute(); 133 | for i in 0..P::LOG_N { 134 | let mut rng = test_rng(); 135 | let coeffs: Vec = (0..P::N >> i).map(|_| rng.gen()).collect(); 136 | let poly = DensePolynomial { coeffs }; 137 | let now = std::time::Instant::now(); 138 | let evals = P::sub_coset(i) 139 | .iter() 140 | .map(|x| poly.evaluate(x)) 141 | .collect::>(); 142 | dbg!(now.elapsed().as_secs_f32()); 143 | assert_eq!(evals, precomputation.evaluate_over_domain(&poly)); 144 | dbg!(now.elapsed().as_secs_f32()); 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/ecfft.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use ark_ff::PrimeField; 4 | use ark_poly::univariate::DensePolynomial; 5 | 6 | use crate::utils::{isogeny::Isogeny, matrix::Matrix}; 7 | 8 | pub trait EcFftParameters: Sized { 9 | /// Logarithm of the size of the maximal ECFFT coset in the curve. 10 | const LOG_N: usize; 11 | /// Size of the maximal ECFFT coset in the curve. 12 | const N: usize = 1 << Self::LOG_N; 13 | 14 | /// Maximal ECFFT coset in the curve. 15 | fn coset() -> Vec; 16 | 17 | /// `Self::coset()[::i]` 18 | fn sub_coset(i: usize) -> Vec { 19 | Self::coset().into_iter().step_by(1 << i).collect() 20 | } 21 | 22 | /// Isogenies of degree 2 used to compute the ECFFT. 23 | /// They form a chain of isogenies `E -> E' -> E'' -> ...` starting from the orignal curve. 24 | fn isogenies() -> Vec>; 25 | 26 | /// Computes the ECFFT precomputations on a given coset. 27 | fn precompute_on_coset(coset: &[F]) -> EcFftCosetPrecomputation { 28 | let n = coset.len(); 29 | let log_n = n.trailing_zeros() as usize; 30 | let isogenies = Self::isogenies(); 31 | debug_assert_eq!(isogenies.len(), Self::LOG_N - 1); 32 | 33 | let mut s = coset.iter().step_by(2).copied().collect::>(); 34 | let mut s_prime = coset.iter().skip(1).step_by(2).copied().collect::>(); 35 | 36 | let mut steps = Vec::new(); 37 | for i in (1..log_n).rev() { 38 | let n = 1 << i; 39 | let nn = n / 2; 40 | let q = nn - 1; 41 | let psi = isogenies[log_n - 1 - i]; 42 | let mut matrices = Vec::new(); 43 | let mut inverse_matrices = Vec::new(); 44 | for j in 0..nn { 45 | let (s0, s1) = (s[j], s[j + nn]); 46 | debug_assert_eq!(psi.eval(s0), psi.eval(s1)); 47 | inverse_matrices.push( 48 | Matrix([ 49 | [ 50 | psi.eval_den(s0).pow([q as u64]), 51 | s0 * psi.eval_den(s0).pow([q as u64]), 52 | ], 53 | [ 54 | psi.eval_den(s1).pow([q as u64]), 55 | s1 * psi.eval_den(s1).pow([q as u64]), 56 | ], 57 | ]) 58 | .inverse(), 59 | ); 60 | 61 | let (s0, s1) = (s_prime[j], s_prime[j + nn]); 62 | debug_assert_eq!(psi.eval(s0), psi.eval(s1)); 63 | matrices.push(Matrix([ 64 | [ 65 | psi.eval_den(s0).pow([q as u64]), 66 | s0 * psi.eval_den(s0).pow([q as u64]), 67 | ], 68 | [ 69 | psi.eval_den(s1).pow([q as u64]), 70 | s1 * psi.eval_den(s1).pow([q as u64]), 71 | ], 72 | ])); 73 | } 74 | steps.push(EcFftPrecomputationStep:: { 75 | s: s.clone(), 76 | s_prime: s_prime.clone(), 77 | matrices, 78 | inverse_matrices, 79 | _phantom: PhantomData, 80 | }); 81 | s = s.into_iter().take(nn).map(|x| psi.eval(x)).collect(); 82 | s_prime = s_prime.into_iter().take(nn).map(|x| psi.eval(x)).collect(); 83 | } 84 | debug_assert_eq!((s.len(), s_prime.len()), (1, 1)); 85 | 86 | EcFftCosetPrecomputation { 87 | coset: coset.to_vec(), 88 | steps, 89 | } 90 | } 91 | 92 | /// Computes the ECFFT precomputations of all `Self::sub_coset(i)`. 93 | fn precompute() -> EcFftPrecomputation { 94 | let mut coset_precomputations = Vec::new(); 95 | let mut coset = Self::coset(); 96 | for _ in 0..Self::LOG_N { 97 | coset_precomputations.push(Self::precompute_on_coset(&coset)); 98 | coset = coset.into_iter().step_by(2).collect(); 99 | } 100 | EcFftPrecomputation { 101 | coset_precomputations, 102 | } 103 | } 104 | } 105 | 106 | pub struct EcFftPrecomputationStep> { 107 | pub s: Vec, 108 | pub s_prime: Vec, 109 | pub matrices: Vec>, 110 | pub inverse_matrices: Vec>, 111 | pub _phantom: PhantomData

, 112 | } 113 | pub struct EcFftCosetPrecomputation> { 114 | pub coset: Vec, 115 | pub steps: Vec>, 116 | } 117 | 118 | pub struct EcFftPrecomputation> { 119 | pub coset_precomputations: Vec>, 120 | } 121 | 122 | impl> EcFftCosetPrecomputation { 123 | /// From `evals` the evaluations of a polynomial on `self.steps[0].s`, 124 | /// return the evaluations of the polynomial on `self.steps[0].s_prime` in `O(n * log n)`. 125 | /// See https://solvable.group/posts/ecfft/ for a simple explanation of this function. 126 | pub fn extend(&self, evals: &[F]) -> Vec { 127 | let mut evals = evals.to_vec(); 128 | self.extend_in_place(&mut evals); 129 | evals 130 | } 131 | 132 | /// Mutate `evals`, which contains the evaluations of a polynomial on `self.steps[0].s`, 133 | /// to store the evaluations of the polynomial on `self.steps[0].s_prime` in `O(n * log n)`. 134 | /// See https://solvable.group/posts/ecfft/ for a simple explanation of this function. 135 | pub fn extend_in_place(&self, evals: &mut [F]) { 136 | let n = evals.len(); 137 | if n == 1 { 138 | return; 139 | } 140 | assert_eq!( 141 | n.next_power_of_two(), 142 | n, 143 | "The number of evaluations should be a power of 2." 144 | ); 145 | let log_n = n.trailing_zeros() as usize; 146 | assert!( 147 | log_n < P::LOG_N, 148 | "Got {} evaluations, can extend at most {} evaluations.", 149 | n, 150 | 1 << (P::LOG_N - 1) 151 | ); 152 | 153 | let EcFftPrecomputationStep { 154 | matrices, 155 | inverse_matrices, 156 | .. 157 | } = &self.steps[self.steps.len() - log_n]; 158 | let nn = n / 2; 159 | let (p0_evals, p1_evals) = evals.split_at_mut(nn); 160 | 161 | for (m, (p0, p1)) in inverse_matrices 162 | .iter() 163 | .zip(p0_evals.iter_mut().zip(p1_evals.iter_mut())) 164 | { 165 | m.multiply_in_place(p0, p1); 166 | } 167 | self.extend_in_place(p0_evals); 168 | self.extend_in_place(p1_evals); 169 | 170 | for (m, (p0, p1)) in matrices 171 | .iter() 172 | .zip(p0_evals.iter_mut().zip(p1_evals.iter_mut())) 173 | { 174 | m.multiply_in_place(p0, p1) 175 | } 176 | } 177 | } 178 | 179 | impl> EcFftPrecomputation { 180 | /// Evaluates polynomial of degree `) -> Vec { 183 | let mut evaluations = poly.to_vec(); 184 | let mut scratch1 = poly.coeffs.clone(); 185 | self.ecfft_in_place(&mut evaluations, &mut scratch1); 186 | evaluations 187 | } 188 | 189 | /// Evaluates polynomial of degree ` { 6 | /// Coefficients of the isogeny's numerator. 7 | pub numerator: [F; 3], 8 | /// Coefficients of the isogeny's denominator. 9 | pub denominator: [F; 2], 10 | } 11 | 12 | impl Isogeny { 13 | /// Evaluate the (x-coordinate of the) isogeny on a field element. 14 | pub fn eval(&self, x: F) -> F { 15 | let Isogeny { 16 | numerator: [a0, a1, a2], 17 | denominator: [b0, b1], 18 | } = self; 19 | (*a0 + *a1 * x + *a2 * x * x) / (*b0 + *b1 * x) 20 | } 21 | 22 | /// Evaluate isogeny's denominator on a field element. 23 | pub fn eval_den(&self, x: F) -> F { 24 | let Isogeny { 25 | denominator: [b0, b1], 26 | .. 27 | } = self; 28 | *b0 + *b1 * x 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/utils/matrix.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::PrimeField; 2 | 3 | #[derive(Clone, Copy)] 4 | /// 2x2 matrix. 5 | pub struct Matrix(pub [[T; 2]; 2]); 6 | 7 | impl Matrix { 8 | /// Inverse of the matrix. Panics if the matrix is not invertible. 9 | pub fn inverse(&self) -> Self { 10 | let [[a, b], [c, d]] = self.0; 11 | let det = a * d - b * c; 12 | Self([[d / det, -b / det], [-c / det, a / det]]) 13 | } 14 | 15 | #[allow(clippy::many_single_char_names)] 16 | /// Multiply a vector of 2 field elements by the matrix. 17 | pub fn multiply(&self, v: [F; 2]) -> [F; 2] { 18 | let [[a, b], [c, d]] = self.0; 19 | let [x, y] = v; 20 | [a * x + b * y, c * x + d * y] 21 | } 22 | 23 | #[allow(clippy::many_single_char_names)] 24 | /// Multiply a vector of 2 field elements by the matrix. 25 | pub fn multiply_in_place(&self, x: &mut F, y: &mut F) { 26 | let [[a, b], [c, d]] = self.0; 27 | let (a, b) = (a * *x + b * *y, c * *x + d * *y); 28 | *x = a; 29 | *y = b; 30 | } 31 | } 32 | 33 | #[cfg(test)] 34 | mod tests { 35 | use ark_std::{rand::Rng, test_rng}; 36 | 37 | use crate::bn254::F; 38 | 39 | use super::Matrix; 40 | 41 | #[test] 42 | fn test_inverse() { 43 | let mut rng = test_rng(); 44 | for _ in 0..100 { 45 | let a: F = rng.gen(); 46 | let b: F = rng.gen(); 47 | let c: F = rng.gen(); 48 | let d: F = rng.gen(); 49 | let mat = Matrix([[a, b], [c, d]]); 50 | let mat_inv = mat.inverse(); 51 | let x: F = rng.gen(); 52 | let y: F = rng.gen(); 53 | let v = [x, y]; 54 | 55 | assert_eq!(v, mat_inv.multiply(mat.multiply(v))); 56 | assert_eq!(v, mat.multiply(mat_inv.multiply(v))); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod isogeny; 2 | pub mod matrix; 3 | --------------------------------------------------------------------------------