diff --git a/.github/workflows/backend-benchmarks.yml b/.github/workflows/backend-benchmarks.yml index c216c961..0ce45210 100644 --- a/.github/workflows/backend-benchmarks.yml +++ b/.github/workflows/backend-benchmarks.yml @@ -11,7 +11,7 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest] # Excluding mcl for now due to they have different project layout - backend: [blst, zkcrypto, arkworks4, arkworks3, constantine] + backend: [blst, zkcrypto, arkworks5, arkworks4, arkworks3, constantine] include: # Setup exec_once_per_backend flag - os: ubuntu-latest @@ -21,6 +21,8 @@ jobs: support_ckzg: true - backend: zkcrypto support_ckzg: true + - backend: arkworks5 + support_ckzg: true - backend: arkworks4 support_ckzg: true - backend: arkworks3 diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml index 26942919..762bb096 100644 --- a/.github/workflows/backend-tests.yml +++ b/.github/workflows/backend-tests.yml @@ -65,7 +65,7 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest] # Excluding mcl for now due to they have different project layout - backend: [blst, zkcrypto, arkworks4, arkworks3, constantine] + backend: [blst, zkcrypto, arkworks5, arkworks4, arkworks3, constantine] include: # Set default clippy flag - clippy-flag: --features=default,std,rand,parallel @@ -86,6 +86,9 @@ jobs: - backend: arkworks3 support_wasm: true support_ckzg: true + - backend: arkworks5 + support_wasm: true + support_ckzg: true - backend: constantine # FIXME: Check for wasm support support_wasm: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 73af92f7..300deeb8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - backend: [blst, zkcrypto, arkworks4, arkworks3, constantine] + backend: [blst, zkcrypto, arkworks5, arkworks4, arkworks3, constantine] target: [windows, linux] include: # Set target-name for target builds diff --git a/Cargo.lock b/Cargo.lock index 108aa512..203b2ceb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,6 +45,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anes" version = "0.1.6" @@ -80,6 +86,18 @@ dependencies = [ "ark-std 0.4.0", ] +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + [[package]] name = "ark-ec" version = "0.3.0" @@ -107,7 +125,29 @@ dependencies = [ "ark-std 0.4.0", "derivative", "hashbrown 0.13.2", - "itertools", + "itertools 0.10.5", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash 0.8.6", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", + "itertools 0.13.0", + "num-bigint 0.4.4", + "num-integer", "num-traits", "rayon", "zeroize", @@ -144,7 +184,7 @@ dependencies = [ "ark-std 0.4.0", "derivative", "digest 0.10.7", - "itertools", + "itertools 0.10.5", "num-bigint 0.4.4", "num-traits", "paste", @@ -153,6 +193,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint 0.4.4", + "num-traits", + "paste", + "rayon", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -173,6 +234,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.38", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -198,6 +269,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint 0.4.4", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "ark-poly" version = "0.3.0" @@ -226,6 +310,22 @@ dependencies = [ "rayon", ] +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash 0.8.6", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", + "rayon", +] + [[package]] name = "ark-serialize" version = "0.3.0" @@ -249,6 +349,20 @@ dependencies = [ "num-bigint 0.4.4", ] +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint 0.4.4", + "rayon", +] + [[package]] name = "ark-serialize-derive" version = "0.3.0" @@ -271,6 +385,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -293,6 +418,17 @@ dependencies = [ "rayon", ] +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand", + "rayon", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -632,7 +768,7 @@ dependencies = [ "clap 2.34.0", "criterion-plot 0.4.5", "csv", - "itertools", + "itertools 0.10.5", "lazy_static", "num-traits", "oorandom", @@ -659,7 +795,7 @@ dependencies = [ "clap 4.4.7", "criterion-plot 0.5.0", "is-terminal", - "itertools", + "itertools 0.10.5", "num-traits", "once_cell", "oorandom", @@ -680,7 +816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -690,7 +826,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -800,12 +936,44 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -863,6 +1031,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "funty" version = "2.0.0" @@ -939,6 +1113,15 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", +] + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1019,6 +1202,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -1505,6 +1697,25 @@ dependencies = [ "rayon", ] +[[package]] +name = "rust-kzg-arkworks5" +version = "0.1.0" +dependencies = [ + "ark-bls12-381 0.5.0", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "criterion 0.5.1", + "hex", + "kzg", + "kzg-bench", + "libc", + "rand", + "rayon", +] + [[package]] name = "rust-kzg-blst" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index a9c923a4..6622395c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] resolver = "2" members = [ + "arkworks5", "arkworks4", "arkworks3", "arkworks3-sppark", diff --git a/arkworks5/Cargo.toml b/arkworks5/Cargo.toml new file mode 100644 index 00000000..7bbc9e3d --- /dev/null +++ b/arkworks5/Cargo.toml @@ -0,0 +1,85 @@ +[package] +name = "rust-kzg-arkworks5" +version = "0.1.0" +edition = "2021" + +[dependencies] +kzg = { path = "../kzg", default-features = false } +ark-std = { version = "^0.5.0", default-features = false } +ark-ff = { version = "^0.5.0", default-features = false, features = [ "asm" ] } +ark-ec = { version = "^0.5.0", default-features = false } +ark-poly = { version = "^0.5.0", default-features = false } +ark-bls12-381 = { version = "^0.5.0", default-features = false, features = [ "curve" ] } +ark-serialize = { version = "^0.5.0", default-features = false } +hex = "0.4.3" +rand = { version = "0.8.5", optional = true } +libc = { version = "0.2.148", default-features = false } +rayon = { version = "1.8.0", optional = true } + +[dev-dependencies] +criterion = "0.5.1" +kzg-bench = { path = "../kzg-bench" } +rand = { version = "0.8.5" } + +[features] +default = [ + "std", + "rand", + "bgmw", +] +std = [ + "ark-ff/std", "ark-ec/std", "ark-poly/std", "ark-std/std", + "kzg/std", + "libc/std" +] +parallel = [ +"dep:rayon", "kzg/parallel", +"ark-std/parallel", "ark-ff/parallel", "ark-ec/parallel", "ark-poly/parallel" +] +rand = [ + "dep:rand", + "kzg/rand", +] +bgmw = [ + "kzg/bgmw" +] +arkmsm = [ + "kzg/arkmsm" +] +c_bindings = [] + +[[bench]] +name = "fft" +harness = false + +[[bench]] +name = "kzg" +harness = false + +[[bench]] +name = "poly" +harness = false + +[[bench]] +name = "das" +harness = false + +[[bench]] +name = "fk_20" +harness = false + +[[bench]] +name = "recover" +harness = false + +[[bench]] +name = "zero_poly" +harness = false + +[[bench]] +name = "eip_4844" +harness = false + +[[bench]] +name = "lincomb" +harness = false diff --git a/arkworks5/benches/das.rs b/arkworks5/benches/das.rs new file mode 100644 index 00000000..8f9879e0 --- /dev/null +++ b/arkworks5/benches/das.rs @@ -0,0 +1,16 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kzg_bench::benches::das::bench_das_extension; +use rust_kzg_arkworks5::kzg_proofs::FFTSettings; +use rust_kzg_arkworks5::kzg_types::ArkFr; + +fn bench_das_extension_(c: &mut Criterion) { + bench_das_extension::(c); +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(10); + targets = bench_das_extension_ +} + +criterion_main!(benches); diff --git a/arkworks5/benches/eip_4844.rs b/arkworks5/benches/eip_4844.rs new file mode 100644 index 00000000..ef4e02b4 --- /dev/null +++ b/arkworks5/benches/eip_4844.rs @@ -0,0 +1,28 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kzg::eip_4844::{ + blob_to_kzg_commitment_rust, bytes_to_blob, compute_blob_kzg_proof_rust, + compute_kzg_proof_rust, verify_blob_kzg_proof_batch_rust, verify_blob_kzg_proof_rust, + verify_kzg_proof_rust, +}; +use kzg_bench::benches::eip_4844::bench_eip_4844; +use rust_kzg_arkworks5::eip_4844::load_trusted_setup_filename_rust; +use rust_kzg_arkworks5::kzg_proofs::{FFTSettings, KZGSettings}; +use rust_kzg_arkworks5::kzg_types::{ArkFp, ArkFr, ArkG1, ArkG1Affine, ArkG2}; +use rust_kzg_arkworks5::utils::PolyData; + +fn bench_eip_4844_(c: &mut Criterion) { + bench_eip_4844::( + c, + &load_trusted_setup_filename_rust, + &blob_to_kzg_commitment_rust, + &bytes_to_blob, + &compute_kzg_proof_rust, + &verify_kzg_proof_rust, + &compute_blob_kzg_proof_rust, + &verify_blob_kzg_proof_rust, + &verify_blob_kzg_proof_batch_rust, + ); +} + +criterion_group!(benches, bench_eip_4844_,); +criterion_main!(benches); diff --git a/arkworks5/benches/eip_7594.rs b/arkworks5/benches/eip_7594.rs new file mode 100644 index 00000000..e49a78f9 --- /dev/null +++ b/arkworks5/benches/eip_7594.rs @@ -0,0 +1,16 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kzg::eip_4844::{blob_to_kzg_commitment_rust, bytes_to_blob}; +use kzg_bench::benches::eip_7594::bench_eip_7594; +use rust_kzg_arkworks5::{eip_4844::load_trusted_setup_filename_rust, eip_7594::ArkBackend}; + +fn bench_eip_7594_(c: &mut Criterion) { + bench_eip_7594::( + c, + &load_trusted_setup_filename_rust, + &bytes_to_blob, + &blob_to_kzg_commitment_rust, + ); +} + +criterion_group!(benches, bench_eip_7594_); +criterion_main!(benches); diff --git a/arkworks5/benches/fft.rs b/arkworks5/benches/fft.rs new file mode 100644 index 00000000..e1099134 --- /dev/null +++ b/arkworks5/benches/fft.rs @@ -0,0 +1,20 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kzg_bench::benches::fft::{bench_fft_fr, bench_fft_g1}; +use rust_kzg_arkworks5::kzg_proofs::FFTSettings; +use rust_kzg_arkworks5::kzg_types::{ArkFr, ArkG1}; + +fn bench_fft_fr_(c: &mut Criterion) { + bench_fft_fr::(c); +} + +fn bench_fft_g1_(c: &mut Criterion) { + bench_fft_g1::(c); +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(10); + targets = bench_fft_fr_, bench_fft_g1_ +} + +criterion_main!(benches); diff --git a/arkworks5/benches/fk_20.rs b/arkworks5/benches/fk_20.rs new file mode 100644 index 00000000..20299d11 --- /dev/null +++ b/arkworks5/benches/fk_20.rs @@ -0,0 +1,21 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kzg_bench::benches::fk20::{bench_fk_multi_da, bench_fk_single_da}; +use rust_kzg_arkworks5::eip_7594::ArkBackend; +use rust_kzg_arkworks5::fk20_proofs::{KzgFK20MultiSettings, KzgFK20SingleSettings}; +use rust_kzg_arkworks5::kzg_proofs::generate_trusted_setup; + +fn bench_fk_single_da_(c: &mut Criterion) { + bench_fk_single_da::(c, &generate_trusted_setup) +} + +fn bench_fk_multi_da_(c: &mut Criterion) { + bench_fk_multi_da::(c, &generate_trusted_setup) +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(10); + targets = bench_fk_single_da_, bench_fk_multi_da_ +} + +criterion_main!(benches); diff --git a/arkworks5/benches/kzg.rs b/arkworks5/benches/kzg.rs new file mode 100644 index 00000000..abc20dfc --- /dev/null +++ b/arkworks5/benches/kzg.rs @@ -0,0 +1,21 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kzg_bench::benches::kzg::{bench_commit_to_poly, bench_compute_proof_single}; + +use rust_kzg_arkworks5::eip_7594::ArkBackend; +use rust_kzg_arkworks5::kzg_proofs::generate_trusted_setup; + +fn bench_commit_to_poly_(c: &mut Criterion) { + bench_commit_to_poly::(c, &generate_trusted_setup); +} + +fn bench_compute_proof_single_(c: &mut Criterion) { + bench_compute_proof_single::(c, &generate_trusted_setup); +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(10); + targets = bench_commit_to_poly_, bench_compute_proof_single_ +} + +criterion_main!(benches); diff --git a/arkworks5/benches/lincomb.rs b/arkworks5/benches/lincomb.rs new file mode 100644 index 00000000..a409941d --- /dev/null +++ b/arkworks5/benches/lincomb.rs @@ -0,0 +1,16 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kzg_bench::benches::lincomb::bench_g1_lincomb; +use rust_kzg_arkworks5::fft_g1::g1_linear_combination; +use rust_kzg_arkworks5::kzg_types::{ArkFp, ArkFr, ArkG1, ArkG1Affine}; + +fn bench_g1_lincomb_(c: &mut Criterion) { + bench_g1_lincomb::(c, &g1_linear_combination); +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(10); + targets = bench_g1_lincomb_ +} + +criterion_main!(benches); diff --git a/arkworks5/benches/poly.rs b/arkworks5/benches/poly.rs new file mode 100644 index 00000000..d3e7fb60 --- /dev/null +++ b/arkworks5/benches/poly.rs @@ -0,0 +1,16 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kzg_bench::benches::poly::bench_new_poly_div; +use rust_kzg_arkworks5::kzg_types::ArkFr; +use rust_kzg_arkworks5::utils::PolyData; + +fn bench_new_poly_div_(c: &mut Criterion) { + bench_new_poly_div::(c); +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(10); + targets = bench_new_poly_div_ +} + +criterion_main!(benches); diff --git a/arkworks5/benches/recover.rs b/arkworks5/benches/recover.rs new file mode 100644 index 00000000..5a02a525 --- /dev/null +++ b/arkworks5/benches/recover.rs @@ -0,0 +1,18 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kzg_bench::benches::recover::bench_recover; + +use rust_kzg_arkworks5::kzg_proofs::FFTSettings; +use rust_kzg_arkworks5::kzg_types::ArkFr; +use rust_kzg_arkworks5::utils::PolyData; + +fn bench_recover_(c: &mut Criterion) { + bench_recover::(c); +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(10); + targets = bench_recover_ +} + +criterion_main!(benches); diff --git a/arkworks5/benches/zero_poly.rs b/arkworks5/benches/zero_poly.rs new file mode 100644 index 00000000..9bb3f7ae --- /dev/null +++ b/arkworks5/benches/zero_poly.rs @@ -0,0 +1,18 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use kzg_bench::benches::zero_poly::bench_zero_poly; + +use rust_kzg_arkworks5::kzg_proofs::FFTSettings; +use rust_kzg_arkworks5::kzg_types::ArkFr; +use rust_kzg_arkworks5::utils::PolyData; + +fn bench_zero_poly_(c: &mut Criterion) { + bench_zero_poly::(c); +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(10); + targets = bench_zero_poly_ +} + +criterion_main!(benches); diff --git a/arkworks5/csharp.patch b/arkworks5/csharp.patch new file mode 100644 index 00000000..690024f1 --- /dev/null +++ b/arkworks5/csharp.patch @@ -0,0 +1,34 @@ +From 5b1ad0fd02016130dcfea5a7e84dcf4de2c67a43 Mon Sep 17 00:00:00 2001 +From: sirse +Date: Wed, 23 Oct 2024 11:13:11 +0000 +Subject: [PATCH] Patch C# bindings + +--- + bindings/csharp/Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/bindings/csharp/Makefile b/bindings/csharp/Makefile +index df1730c..f115db1 100644 +--- a/bindings/csharp/Makefile ++++ b/bindings/csharp/Makefile +@@ -39,7 +39,7 @@ else + endif + + INCLUDE_DIRS = ../../src ../../blst/bindings +-TARGETS = ckzg_wrap.c ../../src/ckzg.c ../../blst/$(BLST_OBJ) ++TARGETS = ckzg_wrap.c + + CFLAGS += -O2 -Wall -Wextra -shared + CFLAGS += ${addprefix -I,${INCLUDE_DIRS}} +@@ -58,7 +58,7 @@ blst: + + .PHONY: ckzg + ckzg: blst +- $(CLANG_EXECUTABLE) $(CFLAGS) -o $(CKZG_LIBRARY_PATH) $(TARGETS) ++ $(CLANG_EXECUTABLE) $(CFLAGS) -o $(CKZG_LIBRARY_PATH) $(TARGETS) -L ../../lib -lrust_kzg_arkworks5 -u verify_cell_kzg_proof_batch + + .PHONY: ckzg-dotnet + ckzg-dotnet: ckzg +-- +2.47.0 + diff --git a/arkworks5/go.patch b/arkworks5/go.patch new file mode 100644 index 00000000..ce71bba2 --- /dev/null +++ b/arkworks5/go.patch @@ -0,0 +1,43 @@ +From 6de1858704912a5f3d7da23b7f630c821c9cf506 Mon Sep 17 00:00:00 2001 +From: sirse +Date: Wed, 2 Oct 2024 07:45:45 +0000 +Subject: [PATCH] Patch Go binding + +--- + bindings/go/main.go | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/bindings/go/main.go b/bindings/go/main.go +index c912d09..edcc96f 100644 +--- a/bindings/go/main.go ++++ b/bindings/go/main.go +@@ -2,7 +2,15 @@ package ckzg4844 + + // #cgo CFLAGS: -I${SRCDIR}/../../src + // #cgo CFLAGS: -I${SRCDIR}/blst_headers +-// #include "ckzg.c" ++// #ifndef BYTES_PER_G1 ++// #define BYTES_PER_G1 48 ++// #endif ++// #ifndef BYTES_PER_G2 ++// #define BYTES_PER_G2 96 ++// #endif ++// #include ++// #include "ckzg.h" ++// #cgo LDFLAGS: -ldl -L${SRCDIR}/../../lib -lrust_kzg_arkworks5 -lm + import "C" + + import ( +@@ -11,9 +19,6 @@ import ( + "errors" + "fmt" + "unsafe" +- +- // So its functions are available during compilation. +- _ "github.com/supranational/blst/bindings/go" + ) + + const ( +-- +2.46.1 + diff --git a/arkworks5/java.patch b/arkworks5/java.patch new file mode 100644 index 00000000..966d1da6 --- /dev/null +++ b/arkworks5/java.patch @@ -0,0 +1,24 @@ +From fb604e554db3670493b1c1863022bbcd6634a9d2 Mon Sep 17 00:00:00 2001 +From: sirse +Date: Wed, 2 Oct 2024 07:39:28 +0000 +Subject: [PATCH] Patch Java bindings + +--- + bindings/java/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/bindings/java/Makefile b/bindings/java/Makefile +index 3f646ef..4be49ba 100644 +--- a/bindings/java/Makefile ++++ b/bindings/java/Makefile +@@ -1,6 +1,6 @@ + INCLUDE_DIRS = ../../src ../../blst/bindings + +-TARGETS=ckzg_jni.c ../../src/ckzg.c ../../lib/libblst.a ++TARGETS=ckzg_jni.c ../../lib/librust_kzg_arkworks5.a + + CC_FLAGS= + OPTIMIZATION_LEVEL=-O2 +-- +2.46.1 + diff --git a/arkworks5/nim.patch b/arkworks5/nim.patch new file mode 100644 index 00000000..9401bba2 --- /dev/null +++ b/arkworks5/nim.patch @@ -0,0 +1,27 @@ +From ae2200466c384f478ac25a26b8612c25eab484b9 Mon Sep 17 00:00:00 2001 +From: sirse +Date: Wed, 2 Oct 2024 07:47:54 +0000 +Subject: [PATCH] Patch Nim binding + +--- + bindings/nim/kzg_abi.nim | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/bindings/nim/kzg_abi.nim b/bindings/nim/kzg_abi.nim +index 0570efd..59e678e 100644 +--- a/bindings/nim/kzg_abi.nim ++++ b/bindings/nim/kzg_abi.nim +@@ -20,7 +21,9 @@ when not defined(kzgExternalBlst): + {.compile: blstPath & "src/server.c"} + {.passc: "-D__BLST_PORTABLE__"} + +-{.compile: srcPath & "ckzg.c"} ++{.passl: "-L" & kzgPath & "lib" .} ++{.passl: "-lrust_kzg_arkworks5" .} ++{.passl: "-lm" .} + + {.passc: "-I" & escape(bindingsPath) .} + {.passc: "-I" & escape(srcPath) .} +-- +2.46.1 + diff --git a/arkworks5/nodejs.patch b/arkworks5/nodejs.patch new file mode 100644 index 00000000..29b65f9d --- /dev/null +++ b/arkworks5/nodejs.patch @@ -0,0 +1,51 @@ +From 43ef934fbf7d904b3014d9a37a37dc2d853f27b0 Mon Sep 17 00:00:00 2001 +From: sirse +Date: Wed, 2 Oct 2024 07:43:11 +0000 +Subject: [PATCH] Patch node.js bindings + +--- + bindings/node.js/binding.gyp | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/bindings/node.js/binding.gyp b/bindings/node.js/binding.gyp +index d01e38b..1591b8e 100644 +--- a/bindings/node.js/binding.gyp ++++ b/bindings/node.js/binding.gyp +@@ -3,22 +3,22 @@ + { + "target_name": "kzg", + "sources": [ +- "src/kzg.cxx", +- "deps/blst/src/server.c", +- "deps/c-kzg/ckzg.c" ++ "src/kzg.cxx" + ], + "include_dirs": [ + "<(module_root_dir)/deps/blst/bindings", + "<(module_root_dir)/deps/c-kzg", + " +Date: Sat, 12 Oct 2024 16:57:40 +0000 +Subject: [PATCH] Patch python bindings + +--- + setup.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/setup.py b/setup.py +index d16c833..b604f1d 100644 +--- a/setup.py ++++ b/setup.py +@@ -35,10 +35,10 @@ def main(): + ext_modules=[ + Extension( + "ckzg", +- sources=["bindings/python/ckzg_wrap.c", "src/ckzg.c"], ++ sources=["bindings/python/ckzg_wrap.c"], + include_dirs=["inc", "src"], + library_dirs=["lib"], +- libraries=["blst"] ++ libraries=["rust_kzg_arkworks5"] + ) + ], + cmdclass={ +-- +2.46.1 + diff --git a/arkworks5/rust.patch b/arkworks5/rust.patch new file mode 100644 index 00000000..effcac81 --- /dev/null +++ b/arkworks5/rust.patch @@ -0,0 +1,78 @@ +From 5a3930e0f7d593e49cb5787b758db7cb1261d94b Mon Sep 17 00:00:00 2001 +From: sirse +Date: Wed, 2 Oct 2024 06:53:08 +0000 +Subject: [PATCH] Patch rust bindings + +--- + Cargo.toml | 1 + + bindings/rust/build.rs | 44 +++--------------------------------------- + 2 files changed, 4 insertions(+), 41 deletions(-) + +diff --git a/Cargo.toml b/Cargo.toml +index 197badf..a164920 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -1,3 +1,4 @@ ++[workspace] + [package] + name = "c-kzg" + version = "2.0.1" +diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs +index 45eb72d..994c83f 100644 +--- a/bindings/rust/build.rs ++++ b/bindings/rust/build.rs +@@ -3,48 +3,10 @@ use std::{env, path::PathBuf}; + fn main() { + let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + +- // Obtain the header files of blst +- let blst_base_dir = root_dir.join("blst"); +- let blst_headers_dir = blst_base_dir.join("bindings"); ++ let rust_kzg_target_dir = root_dir.join("lib"); + +- let c_src_dir = root_dir.join("src"); +- +- let mut cc = cc::Build::new(); +- +- #[cfg(all(windows, target_env = "msvc"))] +- { +- cc.flag("-D_CRT_SECURE_NO_WARNINGS"); +- +- // In blst, if __STDC_VERSION__ isn't defined as c99 or greater, it will typedef a bool to +- // an int. There is a bug in bindgen associated with this. It assumes that a bool in C is +- // the same size as a bool in Rust. This is the root cause of the issues on Windows. If/when +- // this is fixed in bindgen, it should be safe to remove this compiler flag. +- cc.flag("/std:c11"); +- } +- +- cc.include(c_src_dir.clone()); +- cc.include(blst_headers_dir.clone()); +- cc.warnings(false); +- cc.file(c_src_dir.join("ckzg.c")); +- #[cfg(not(debug_assertions))] +- cc.define("NDEBUG", None); +- +- cc.try_compile("ckzg").expect("Failed to compile ckzg"); +- +- #[cfg(feature = "generate-bindings")] +- { +- let header_path = c_src_dir.join("ckzg.h"); +- let bindings_out_path = root_dir.join("bindings/rust/src/bindings/generated.rs"); +- make_bindings( +- header_path.to_str().expect("valid header path"), +- c_src_dir.to_str().expect("valid c src path"), +- blst_headers_dir.to_str().expect("valid blst header path"), +- &bindings_out_path, +- ); +- } +- +- // Finally, tell cargo this provides ckzg/ckzg_min +- println!("cargo:rustc-link-lib=ckzg"); ++ println!("cargo:rustc-link-search={}", rust_kzg_target_dir.display()); ++ println!("cargo:rustc-link-arg=-lrust_kzg_arkworks5"); + } + + #[cfg(feature = "generate-bindings")] +-- +2.46.1 + diff --git a/arkworks5/src/consts.rs b/arkworks5/src/consts.rs new file mode 100644 index 00000000..7138a8b6 --- /dev/null +++ b/arkworks5/src/consts.rs @@ -0,0 +1,268 @@ +use kzg::eth::c_bindings::{blst_fp, blst_fp2, blst_p1, blst_p2}; + +use crate::kzg_types::{ArkG1, ArkG2}; + +/** The G1 identity/infinity */ +#[rustfmt::skip] +pub const G1_IDENTITY: ArkG1 = ArkG1::from_blst_p1( blst_p1 { + x: blst_fp { l: [0, 0, 0, 0, 0, 0], }, + y: blst_fp { l: [0, 0, 0, 0, 0, 0], }, + z: blst_fp { l: [0, 0, 0, 0, 0, 0], }, +}); + +pub const SCALE_FACTOR: u64 = 5; + +pub const NUM_ROOTS: usize = 32; + +#[rustfmt::skip] +pub const SCALE2_ROOT_OF_UNITY: [[u64; 4]; 32] = [ + [0x0000000000000001, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000], + [0xffffffff00000000, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48], + [0x0001000000000000, 0xec03000276030000, 0x8d51ccce760304d0, 0x0000000000000000], + [0x7228fd3397743f7a, 0xb38b21c28713b700, 0x8c0625cd70d77ce2, 0x345766f603fa66e7], + [0x53ea61d87742bcce, 0x17beb312f20b6f76, 0xdd1c0af834cec32c, 0x20b1ce9140267af9], + [0x360c60997369df4e, 0xbf6e88fb4c38fb8a, 0xb4bcd40e22f55448, 0x50e0903a157988ba], + [0x8140d032f0a9ee53, 0x2d967f4be2f95155, 0x14a1e27164d8fdbd, 0x45af6345ec055e4d], + [0x5130c2c1660125be, 0x98d0caac87f5713c, 0xb7c68b4d7fdd60d0, 0x6898111413588742], + [0x4935bd2f817f694b, 0x0a0865a899e8deff, 0x6b368121ac0cf4ad, 0x4f9b4098e2e9f12e], + [0x4541b8ff2ee0434e, 0xd697168a3a6000fe, 0x39feec240d80689f, 0x095166525526a654], + [0x3c28d666a5c2d854, 0xea437f9626fc085e, 0x8f4de02c0f776af3, 0x325db5c3debf77a1], + [0x4a838b5d59cd79e5, 0x55ea6811be9c622d, 0x09f1ca610a08f166, 0x6d031f1b5c49c834], + [0xe206da11a5d36306, 0x0ad1347b378fbf96, 0xfc3e8acfe0f8245f, 0x564c0a11a0f704f4], + [0x6fdd00bfc78c8967, 0x146b58bc434906ac, 0x2ccddea2972e89ed, 0x485d512737b1da3d], + [0x034d2ff22a5ad9e1, 0xae4622f6a9152435, 0xdc86b01c0d477fa6, 0x56624634b500a166], + [0xfbd047e11279bb6e, 0xc8d5f51db3f32699, 0x483405417a0cbe39, 0x3291357ee558b50d], + [0xd7118f85cd96b8ad, 0x67a665ae1fcadc91, 0x88f39a78f1aeb578, 0x2155379d12180caa], + [0x08692405f3b70f10, 0xcd7f2bd6d0711b7d, 0x473a2eef772c33d6, 0x224262332d8acbf4], + [0x6f421a7d8ef674fb, 0xbb97a3bf30ce40fd, 0x652f717ae1c34bb0, 0x2d3056a530794f01], + [0x194e8c62ecb38d9d, 0xad8e16e84419c750, 0xdf625e80d0adef90, 0x520e587a724a6955], + [0xfece7e0e39898d4b, 0x2f69e02d265e09d9, 0xa57a6e07cb98de4a, 0x03e1c54bcb947035], + [0xcd3979122d3ea03a, 0x46b3105f04db5844, 0xc70d0874b0691d4e, 0x47c8b5817018af4f], + [0xc6e7a6ffb08e3363, 0xe08fec7c86389bee, 0xf2d38f10fbb8d1bb, 0x0abe6a5e5abcaa32], + [0x5616c57de0ec9eae, 0xc631ffb2585a72db, 0x5121af06a3b51e3c, 0x73560252aa0655b2], + [0x92cf4deb77bd779c, 0x72cf6a8029b7d7bc, 0x6e0bcd91ee762730, 0x291cf6d68823e687], + [0xce32ef844e11a51e, 0xc0ba12bb3da64ca5, 0x0454dc1edc61a1a3, 0x019fe632fd328739], + [0x531a11a0d2d75182, 0x02c8118402867ddc, 0x116168bffbedc11d, 0x0a0a77a3b1980c0d], + [0xe2d0a7869f0319ed, 0xb94f1101b1d7a628, 0xece8ea224f31d25d, 0x23397a9300f8f98b], + [0xd7b688830a4f2089, 0x6558e9e3f6ac7b41, 0x99e276b571905a7d, 0x52dd465e2f094256], + [0x474650359d8e211b, 0x84d37b826214abc6, 0x8da40c1ef2bb4598, 0x0c83ea7744bf1bee], + [0x694341f608c9dd56, 0xed3a181fabb30adc, 0x1339a815da8b398f, 0x2c6d4e4511657e1e], + [0x63e7cb4906ffc93f, 0xf070bb00e28a193d, 0xad1715b02e5713b5, 0x4b5371495990693f], +]; + +/** The G1 generator */ +pub const G1_GENERATOR: ArkG1 = ArkG1::from_blst_p1(blst_p1 { + x: blst_fp { + l: [ + 0x5cb38790fd530c16, + 0x7817fc679976fff5, + 0x154f95c7143ba1c1, + 0xf0ae6acdf3d0e747, + 0xedce6ecc21dbf440, + 0x120177419e0bfb75, + ], + }, + y: blst_fp { + l: [ + 0xbaac93d50ce72271, + 0x8c22631a7918fd8e, + 0xdd595f13570725ce, + 0x51ac582950405194, + 0x0e1c8c3fad0059c0, + 0x0bbc3efc5008a26a, + ], + }, + z: blst_fp { + l: [ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ], + }, +}); + +pub const G1_NEGATIVE_GENERATOR: ArkG1 = ArkG1::from_blst_p1(blst_p1 { + x: blst_fp { + l: [ + 0x5cb38790fd530c16, + 0x7817fc679976fff5, + 0x154f95c7143ba1c1, + 0xf0ae6acdf3d0e747, + 0xedce6ecc21dbf440, + 0x120177419e0bfb75, + ], + }, + y: blst_fp { + l: [ + 0xff526c2af318883a, + 0x92899ce4383b0270, + 0x89d7738d9fa9d055, + 0x12caf35ba344c12a, + 0x3cff1b76964b5317, + 0x0e44d2ede9774430, + ], + }, + z: blst_fp { + l: [ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ], + }, +}); + +pub const G2_GENERATOR: ArkG2 = ArkG2::from_blst_p2(blst_p2 { + x: blst_fp2 { + fp: [ + blst_fp { + l: [ + 0xf5f28fa202940a10, + 0xb3f5fb2687b4961a, + 0xa1a893b53e2ae580, + 0x9894999d1a3caee9, + 0x6f67b7631863366b, + 0x058191924350bcd7, + ], + }, + blst_fp { + l: [ + 0xa5a9c0759e23f606, + 0xaaa0c59dbccd60c3, + 0x3bb17e18e2867806, + 0x1b1ab6cc8541b367, + 0xc2b6ed0ef2158547, + 0x11922a097360edf3, + ], + }, + ], + }, + y: blst_fp2 { + fp: [ + blst_fp { + l: [ + 0x4c730af860494c4a, + 0x597cfa1f5e369c5a, + 0xe7e6856caa0a635a, + 0xbbefb5e96e0d495f, + 0x07d3a975f0ef25a2, + 0x0083fd8e7e80dae5, + ], + }, + blst_fp { + l: [ + 0xadc0fc92df64b05d, + 0x18aa270a2b1461dc, + 0x86adac6a3be4eba0, + 0x79495c4ec93da33a, + 0xe7175850a43ccaed, + 0x0b2bc2a163de1bf2, + ], + }, + ], + }, + z: blst_fp2 { + fp: [ + blst_fp { + l: [ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ], + }, + blst_fp { + l: [ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + ], + }, + ], + }, +}); + +pub const G2_NEGATIVE_GENERATOR: ArkG2 = ArkG2::from_blst_p2(blst_p2 { + x: blst_fp2 { + fp: [ + blst_fp { + l: [ + 0xf5f28fa202940a10, + 0xb3f5fb2687b4961a, + 0xa1a893b53e2ae580, + 0x9894999d1a3caee9, + 0x6f67b7631863366b, + 0x058191924350bcd7, + ], + }, + blst_fp { + l: [ + 0xa5a9c0759e23f606, + 0xaaa0c59dbccd60c3, + 0x3bb17e18e2867806, + 0x1b1ab6cc8541b367, + 0xc2b6ed0ef2158547, + 0x11922a097360edf3, + ], + }, + ], + }, + y: blst_fp2 { + fp: [ + blst_fp { + l: [ + 0x6d8bf5079fb65e61, + 0xc52f05df531d63a5, + 0x7f4a4d344ca692c9, + 0xa887959b8577c95f, + 0x4347fe40525c8734, + 0x197d145bbaff0bb5, + ], + }, + blst_fp { + l: [ + 0x0c3e036d209afa4e, + 0x0601d8f4863f9e23, + 0xe0832636bacc0a84, + 0xeb2def362a476f84, + 0x64044f659f0ee1e9, + 0x0ed54f48d5a1caa7, + ], + }, + ], + }, + z: blst_fp2 { + fp: [ + blst_fp { + l: [ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ], + }, + blst_fp { + l: [ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + ], + }, + ], + }, +}); diff --git a/arkworks5/src/das.rs b/arkworks5/src/das.rs new file mode 100644 index 00000000..d619e23c --- /dev/null +++ b/arkworks5/src/das.rs @@ -0,0 +1,87 @@ +use crate::kzg_proofs::FFTSettings; +use crate::kzg_types::ArkFr as BlstFr; +use kzg::{DASExtension, Fr}; +use std::cmp::Ordering; + +impl FFTSettings { + fn das_fft_extension_stride(&self, ab: &mut [BlstFr], stride: usize) { + match ab.len().cmp(&2_usize) { + Ordering::Less => {} + Ordering::Greater => { + let half = ab.len(); + let halfhalf = half / 2; + + for i in 0..halfhalf { + let tmp1 = ab[i].add(&ab[halfhalf + i]); + let tmp2 = ab[i].sub(&ab[halfhalf + i]); + ab[halfhalf + i] = tmp2.mul(&self.reverse_roots_of_unity[i * 2 * stride]); + ab[i] = tmp1; + } + + #[cfg(feature = "parallel")] + { + if ab.len() > 32 { + let (lo, hi) = ab.split_at_mut(halfhalf); + rayon::join( + || self.das_fft_extension_stride(hi, stride * 2), + || self.das_fft_extension_stride(lo, stride * 2), + ); + } else { + self.das_fft_extension_stride(&mut ab[..halfhalf], stride * 2); + self.das_fft_extension_stride(&mut ab[halfhalf..], stride * 2); + } + } + #[cfg(not(feature = "parallel"))] + { + self.das_fft_extension_stride(&mut ab[..halfhalf], stride * 2); + self.das_fft_extension_stride(&mut ab[halfhalf..], stride * 2); + } + for i in 0..halfhalf { + let x = ab[i]; + let y = ab[halfhalf + i]; + let y_times_root = y.mul(&self.roots_of_unity[(1 + 2 * i) * stride]); + ab[i] = x.add(&y_times_root); + ab[halfhalf + i] = x.sub(&y_times_root); + } + } + Ordering::Equal => { + let x = ab[0].add(&ab[1]); + let y = ab[0].sub(&ab[1]); + let tmp = y.mul(&self.roots_of_unity[stride]); + + ab[0] = x.add(&tmp); + ab[1] = x.sub(&tmp); + } + } + } +} + +impl DASExtension for FFTSettings { + fn das_fft_extension(&self, vals: &[BlstFr]) -> Result, String> { + if vals.is_empty() { + return Err(String::from("vals can not be empty")); + } + if !vals.len().is_power_of_two() { + return Err(String::from("vals lenght has to be power of 2")); + } + if vals.len() * 2 > self.max_width { + return Err(String::from( + "vals lenght * 2 has to equal or less than FFTSetings max width", + )); + } + + let mut vals = vals.to_vec(); + let stride = self.max_width / (vals.len() * 2); + + self.das_fft_extension_stride(&mut vals, stride); + + let invlen = BlstFr::from_u64(vals.len() as u64); + let invlen = invlen.inverse(); + + for val in &mut vals { + val.fr *= invlen.fr + } + + Ok(vals) + } +} diff --git a/arkworks5/src/eip_4844.rs b/arkworks5/src/eip_4844.rs new file mode 100644 index 00000000..688f3f4d --- /dev/null +++ b/arkworks5/src/eip_4844.rs @@ -0,0 +1,487 @@ +extern crate alloc; + +use crate::kzg_proofs::KZGSettings as LKZGSettings; +#[cfg(feature = "c_bindings")] +use crate::utils::PRECOMPUTATION_TABLES; +#[cfg(feature = "c_bindings")] +use kzg::{ + eth::{ + self, + c_bindings::{Blob, Bytes32, Bytes48, CKZGSettings, CKzgRet, KZGCommitment, KZGProof}, + }, + Fr, G1, +}; + +#[cfg(feature = "c_bindings")] +use core::ptr; +#[cfg(all(feature = "std", feature = "c_bindings"))] +use libc::FILE; +#[cfg(feature = "std")] +use std::fs::File; +#[cfg(feature = "std")] +use std::io::Read; + +#[cfg(feature = "std")] +use kzg::eip_4844::load_trusted_setup_string; + +#[cfg(feature = "std")] +pub fn load_trusted_setup_filename_rust( + filepath: &str, +) -> Result { + use kzg::eip_4844::load_trusted_setup_rust; + + let mut file = File::open(filepath).map_err(|_| "Unable to open file".to_string())?; + let mut contents = String::new(); + file.read_to_string(&mut contents) + .map_err(|_| "Unable to read file".to_string())?; + + let (g1_monomial_bytes, g1_lagrange_bytes, g2_monomial_bytes) = + load_trusted_setup_string(&contents)?; + load_trusted_setup_rust(&g1_monomial_bytes, &g1_lagrange_bytes, &g2_monomial_bytes) +} + +#[cfg(feature = "c_bindings")] +pub(crate) fn kzg_settings_to_c(rust_settings: &LKZGSettings) -> CKZGSettings { + CKZGSettings { + roots_of_unity: Box::leak( + rust_settings + .fs + .roots_of_unity + .iter() + .map(|r| r.to_blst_fr()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + brp_roots_of_unity: Box::leak( + rust_settings + .fs + .brp_roots_of_unity + .iter() + .map(|r| r.to_blst_fr()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + reverse_roots_of_unity: Box::leak( + rust_settings + .fs + .reverse_roots_of_unity + .iter() + .map(|r| r.to_blst_fr()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + g1_values_monomial: Box::leak( + rust_settings + .g1_values_monomial + .iter() + .map(|r| r.to_blst_p1()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + g1_values_lagrange_brp: Box::leak( + rust_settings + .g1_values_lagrange_brp + .iter() + .map(|r| r.to_blst_p1()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + g2_values_monomial: Box::leak( + rust_settings + .g2_values_monomial + .iter() + .map(|r| r.to_blst_p2()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + x_ext_fft_columns: Box::leak( + rust_settings + .x_ext_fft_columns + .iter() + .map(|r| { + Box::leak( + r.iter() + .map(|it| it.to_blst_p1()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr() + }) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + tables: core::ptr::null_mut(), + wbits: 0, + scratch_size: 0, + } +} + +#[cfg(feature = "c_bindings")] +macro_rules! handle_ckzg_badargs { + ($x: expr) => { + match $x { + Ok(value) => value, + Err(_) => return CKzgRet::BadArgs, + } + }; +} + +/// # Safety +#[cfg(feature = "c_bindings")] +#[no_mangle] +pub unsafe extern "C" fn blob_to_kzg_commitment( + out: *mut KZGCommitment, + blob: *const Blob, + s: &CKZGSettings, +) -> CKzgRet { + use kzg::eip_4844::{ + blob_to_kzg_commitment_raw, FIELD_ELEMENTS_PER_BLOB, TRUSTED_SETUP_NUM_G1_POINTS, + }; + + if TRUSTED_SETUP_NUM_G1_POINTS == 0 { + // FIXME: load_trusted_setup should set this value, but if not, it fails + TRUSTED_SETUP_NUM_G1_POINTS = FIELD_ELEMENTS_PER_BLOB + }; + + let settings: LKZGSettings = handle_ckzg_badargs!(s.try_into()); + let tmp = handle_ckzg_badargs!(blob_to_kzg_commitment_raw((*blob).bytes, &settings)); + + (*out).bytes = tmp.to_bytes(); + CKzgRet::Ok +} + +/// # Safety +#[cfg(feature = "c_bindings")] +#[no_mangle] +pub unsafe extern "C" fn load_trusted_setup( + out: *mut CKZGSettings, + g1_monomial_bytes: *const u8, + num_g1_monomial_bytes: u64, + g1_lagrange_bytes: *const u8, + num_g1_lagrange_bytes: u64, + g2_monomial_bytes: *const u8, + num_g2_monomial_bytes: u64, + _precompute: u64, +) -> CKzgRet { + use kzg::eip_4844::{load_trusted_setup_rust, BYTES_PER_G1, TRUSTED_SETUP_NUM_G1_POINTS}; + + *out = CKZGSettings { + brp_roots_of_unity: ptr::null_mut(), + roots_of_unity: ptr::null_mut(), + reverse_roots_of_unity: ptr::null_mut(), + g1_values_monomial: ptr::null_mut(), + g1_values_lagrange_brp: ptr::null_mut(), + g2_values_monomial: ptr::null_mut(), + x_ext_fft_columns: ptr::null_mut(), + tables: ptr::null_mut(), + wbits: 0, + scratch_size: 0, + }; + + let g1_monomial_bytes = + core::slice::from_raw_parts(g1_monomial_bytes, num_g1_monomial_bytes as usize); + let g1_lagrange_bytes = + core::slice::from_raw_parts(g1_lagrange_bytes, num_g1_lagrange_bytes as usize); + let g2_monomial_bytes = + core::slice::from_raw_parts(g2_monomial_bytes, num_g2_monomial_bytes as usize); + TRUSTED_SETUP_NUM_G1_POINTS = num_g1_monomial_bytes as usize / BYTES_PER_G1; + let mut settings = handle_ckzg_badargs!(load_trusted_setup_rust( + g1_monomial_bytes, + g1_lagrange_bytes, + g2_monomial_bytes + )); + + let c_settings = kzg_settings_to_c(&settings); + + PRECOMPUTATION_TABLES.save_precomputation(settings.precomputation.take(), &c_settings); + + *out = c_settings; + CKzgRet::Ok +} + +/// # Safety +#[cfg(all(feature = "std", feature = "c_bindings"))] +#[no_mangle] +pub unsafe extern "C" fn load_trusted_setup_file( + out: *mut CKZGSettings, + in_: *mut FILE, +) -> CKzgRet { + use kzg::eip_4844::{ + load_trusted_setup_rust, BYTES_PER_G1, FIELD_ELEMENTS_PER_BLOB, TRUSTED_SETUP_NUM_G1_POINTS, + }; + + *out = CKZGSettings { + brp_roots_of_unity: ptr::null_mut(), + roots_of_unity: ptr::null_mut(), + reverse_roots_of_unity: ptr::null_mut(), + g1_values_monomial: ptr::null_mut(), + g1_values_lagrange_brp: ptr::null_mut(), + g2_values_monomial: ptr::null_mut(), + x_ext_fft_columns: ptr::null_mut(), + tables: ptr::null_mut(), + wbits: 0, + scratch_size: 0, + }; + + let mut buf = vec![0u8; 1024 * 1024]; + let len: usize = libc::fread(buf.as_mut_ptr() as *mut libc::c_void, 1, buf.len(), in_); + let s = handle_ckzg_badargs!(String::from_utf8(buf[..len].to_vec())); + let (g1_monomial_bytes, g1_lagrange_bytes, g2_monomial_bytes) = + handle_ckzg_badargs!(load_trusted_setup_string(&s)); + TRUSTED_SETUP_NUM_G1_POINTS = g1_monomial_bytes.len() / BYTES_PER_G1; + if TRUSTED_SETUP_NUM_G1_POINTS != FIELD_ELEMENTS_PER_BLOB { + // Helps pass the Java test "shouldThrowExceptionOnIncorrectTrustedSetupFromFile", + // as well as 5 others that pass only if this one passes (likely because Java doesn't + // deallocate its KZGSettings pointer when no exception is thrown). + return CKzgRet::BadArgs; + } + let mut settings = handle_ckzg_badargs!(load_trusted_setup_rust( + &g1_monomial_bytes, + &g1_lagrange_bytes, + &g2_monomial_bytes + )); + + let c_settings = kzg_settings_to_c(&settings); + + PRECOMPUTATION_TABLES.save_precomputation(settings.precomputation.take(), &c_settings); + + *out = c_settings; + + CKzgRet::Ok +} + +/// # Safety +#[cfg(feature = "c_bindings")] +#[no_mangle] +pub unsafe extern "C" fn free_trusted_setup(s: *mut CKZGSettings) { + use kzg::eip_4844::{FIELD_ELEMENTS_PER_BLOB, TRUSTED_SETUP_NUM_G2_POINTS}; + + if s.is_null() { + return; + } + + PRECOMPUTATION_TABLES.remove_precomputation(&*s); + + if !(*s).roots_of_unity.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).roots_of_unity, + eth::FIELD_ELEMENTS_PER_EXT_BLOB + 1, + )); + drop(v); + (*s).roots_of_unity = ptr::null_mut(); + } + + if !(*s).brp_roots_of_unity.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).brp_roots_of_unity, + eth::FIELD_ELEMENTS_PER_EXT_BLOB, + )); + drop(v); + (*s).brp_roots_of_unity = ptr::null_mut(); + } + + if !(*s).reverse_roots_of_unity.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).reverse_roots_of_unity, + eth::FIELD_ELEMENTS_PER_EXT_BLOB + 1, + )); + drop(v); + (*s).reverse_roots_of_unity = ptr::null_mut(); + } + + if !(*s).g1_values_monomial.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).g1_values_monomial, + FIELD_ELEMENTS_PER_BLOB, + )); + drop(v); + (*s).g1_values_monomial = ptr::null_mut(); + } + + if !(*s).g1_values_lagrange_brp.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).g1_values_lagrange_brp, + FIELD_ELEMENTS_PER_BLOB, + )); + drop(v); + (*s).g1_values_lagrange_brp = ptr::null_mut(); + } + + if !(*s).g2_values_monomial.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).g2_values_monomial, + TRUSTED_SETUP_NUM_G2_POINTS, + )); + drop(v); + (*s).g2_values_monomial = ptr::null_mut(); + } + + if !(*s).x_ext_fft_columns.is_null() { + let x_ext_fft_columns = core::slice::from_raw_parts_mut( + (*s).x_ext_fft_columns, + 2 * ((eth::FIELD_ELEMENTS_PER_EXT_BLOB / 2) / eth::FIELD_ELEMENTS_PER_CELL), + ); + + for column in x_ext_fft_columns.iter_mut() { + if !(*column).is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + *column, + eth::FIELD_ELEMENTS_PER_CELL, + )); + drop(v); + *column = ptr::null_mut(); + } + } + + let v = Box::from_raw(x_ext_fft_columns); + drop(v); + (*s).x_ext_fft_columns = ptr::null_mut(); + } +} + +/// # Safety +#[cfg(feature = "c_bindings")] +#[no_mangle] +pub unsafe extern "C" fn verify_kzg_proof( + ok: *mut bool, + commitment_bytes: *const Bytes48, + z_bytes: *const Bytes32, + y_bytes: *const Bytes32, + proof_bytes: *const Bytes48, + s: &CKZGSettings, +) -> CKzgRet { + use kzg::eip_4844::verify_kzg_proof_raw; + + let settings: LKZGSettings = handle_ckzg_badargs!(s.try_into()); + + let result = handle_ckzg_badargs!(verify_kzg_proof_raw( + (*commitment_bytes).bytes, + (*z_bytes).bytes, + (*y_bytes).bytes, + (*proof_bytes).bytes, + &settings + )); + + *ok = result; + CKzgRet::Ok +} + +/// # Safety +#[cfg(feature = "c_bindings")] +#[no_mangle] +pub unsafe extern "C" fn verify_blob_kzg_proof( + ok: *mut bool, + blob: *const Blob, + commitment_bytes: *const Bytes48, + proof_bytes: *const Bytes48, + s: &CKZGSettings, +) -> CKzgRet { + use kzg::eip_4844::verify_blob_kzg_proof_raw; + + let settings: LKZGSettings = handle_ckzg_badargs!(s.try_into()); + + let result = handle_ckzg_badargs!(verify_blob_kzg_proof_raw( + (*blob).bytes, + (*commitment_bytes).bytes, + (*proof_bytes).bytes, + &settings, + )); + + *ok = result; + CKzgRet::Ok +} + +/// # Safety +#[cfg(feature = "c_bindings")] +#[no_mangle] +pub unsafe extern "C" fn verify_blob_kzg_proof_batch( + ok: *mut bool, + blobs: *const Blob, + commitments_bytes: *const Bytes48, + proofs_bytes: *const Bytes48, + n: usize, + s: &CKZGSettings, +) -> CKzgRet { + use kzg::eip_4844::verify_blob_kzg_proof_batch_raw; + + let blobs = core::slice::from_raw_parts(blobs, n) + .iter() + .map(|v| v.bytes) + .collect::>(); + let commitments = core::slice::from_raw_parts(commitments_bytes, n) + .iter() + .map(|v| v.bytes) + .collect::>(); + let proofs = core::slice::from_raw_parts(proofs_bytes, n) + .iter() + .map(|v| v.bytes) + .collect::>(); + + *ok = false; + + let settings: LKZGSettings = handle_ckzg_badargs!(s.try_into()); + + let result = handle_ckzg_badargs!(verify_blob_kzg_proof_batch_raw( + &blobs, + &commitments, + &proofs, + &settings + )); + + *ok = result; + + CKzgRet::Ok +} + +/// # Safety +#[cfg(feature = "c_bindings")] +#[no_mangle] +pub unsafe extern "C" fn compute_blob_kzg_proof( + out: *mut KZGProof, + blob: *const Blob, + commitment_bytes: *const Bytes48, + s: &CKZGSettings, +) -> CKzgRet { + use kzg::eip_4844::compute_blob_kzg_proof_raw; + + let settings: LKZGSettings = handle_ckzg_badargs!(s.try_into()); + let proof = handle_ckzg_badargs!(compute_blob_kzg_proof_raw( + (*blob).bytes, + (*commitment_bytes).bytes, + &settings + )); + + (*out).bytes = proof.to_bytes(); + CKzgRet::Ok +} + +/// # Safety +#[cfg(feature = "c_bindings")] +#[no_mangle] +pub unsafe extern "C" fn compute_kzg_proof( + proof_out: *mut KZGProof, + y_out: *mut Bytes32, + blob: *const Blob, + z_bytes: *const Bytes32, + s: &CKZGSettings, +) -> CKzgRet { + use kzg::eip_4844::compute_kzg_proof_raw; + + let settings: LKZGSettings = handle_ckzg_badargs!(s.try_into()); + let (proof_out_tmp, fry_tmp) = handle_ckzg_badargs!(compute_kzg_proof_raw( + (*blob).bytes, + (*z_bytes).bytes, + &settings + )); + + (*proof_out).bytes = proof_out_tmp.to_bytes(); + (*y_out).bytes = fry_tmp.to_bytes(); + CKzgRet::Ok +} diff --git a/arkworks5/src/eip_7594.rs b/arkworks5/src/eip_7594.rs new file mode 100644 index 00000000..da6c68ca --- /dev/null +++ b/arkworks5/src/eip_7594.rs @@ -0,0 +1,28 @@ +extern crate alloc; + +use kzg::EcBackend; + +use crate::kzg_proofs::FFTSettings; +use crate::kzg_proofs::KZGSettings; +use crate::kzg_types::ArkFp; +use crate::kzg_types::ArkFr; +use crate::kzg_types::ArkG1; +use crate::kzg_types::ArkG1Affine; +use crate::kzg_types::ArkG2; +use crate::utils::PolyData; + +pub struct ArkBackend; + +impl EcBackend for ArkBackend { + type Fr = ArkFr; + type G1Fp = ArkFp; + type G1Affine = ArkG1Affine; + type G1 = ArkG1; + type G2 = ArkG2; + type Poly = PolyData; + type FFTSettings = FFTSettings; + type KZGSettings = KZGSettings; +} + +#[cfg(feature = "c_bindings")] +kzg::c_bindings_eip7594!(ArkBackend); diff --git a/arkworks5/src/fft.rs b/arkworks5/src/fft.rs new file mode 100644 index 00000000..27f49055 --- /dev/null +++ b/arkworks5/src/fft.rs @@ -0,0 +1,107 @@ +use crate::kzg_proofs::FFTSettings; +use crate::kzg_types::ArkFr as BlstFr; +use kzg::{FFTFr, Fr as FFr}; + +impl FFTFr for FFTSettings { + fn fft_fr(&self, data: &[BlstFr], inverse: bool) -> Result, String> { + if data.len() > self.max_width { + return Err(String::from("data length is longer than allowed max width")); + } + if !data.len().is_power_of_two() { + return Err(String::from("data length is not power of 2")); + } + + let stride = self.max_width / data.len(); + let mut ret = vec![BlstFr::default(); data.len()]; + + let roots = if inverse { + &self.reverse_roots_of_unity + } else { + &self.roots_of_unity + }; + + fft_fr_fast(&mut ret, data, 1, roots, stride); + + if inverse { + let inv_fr_len = BlstFr::from_u64(data.len() as u64).inverse(); + ret[..data.len()] + .iter_mut() + .for_each(|f| *f = BlstFr::mul(f, &inv_fr_len)); + } + + Ok(ret) + } +} + +pub fn fft_fr_fast( + ret: &mut [BlstFr], + data: &[BlstFr], + stride: usize, + roots: &[BlstFr], + roots_stride: usize, +) { + let half: usize = ret.len() / 2; + if half > 0 { + #[cfg(not(feature = "parallel"))] + { + fft_fr_fast(&mut ret[..half], data, stride * 2, roots, roots_stride * 2); + fft_fr_fast( + &mut ret[half..], + &data[stride..], + stride * 2, + roots, + roots_stride * 2, + ); + } + + #[cfg(feature = "parallel")] + { + if half > 256 { + let (lo, hi) = ret.split_at_mut(half); + rayon::join( + || fft_fr_fast(lo, data, stride * 2, roots, roots_stride * 2), + || fft_fr_fast(hi, &data[stride..], stride * 2, roots, roots_stride * 2), + ); + } else { + fft_fr_fast(&mut ret[..half], data, stride * 2, roots, roots_stride * 2); + fft_fr_fast( + &mut ret[half..], + &data[stride..], + stride * 2, + roots, + roots_stride * 2, + ); + } + } + + for i in 0..half { + let y_times_root = ret[i + half].mul(&roots[i * roots_stride]); + ret[i + half] = ret[i].sub(&y_times_root); + ret[i] = ret[i].add(&y_times_root); + } + } else { + ret[0] = data[0]; + } +} + +pub fn fft_fr_slow( + ret: &mut [BlstFr], + data: &[BlstFr], + stride: usize, + roots: &[BlstFr], + roots_stride: usize, +) { + let mut v; + let mut jv; + let mut r; + + for i in 0..data.len() { + ret[i] = data[0].mul(&roots[0]); + for j in 1..data.len() { + jv = data[j * stride]; + r = roots[((i * j) % data.len()) * roots_stride]; + v = jv.mul(&r); + ret[i] = ret[i].add(&v); + } + } +} diff --git a/arkworks5/src/fft_g1.rs b/arkworks5/src/fft_g1.rs new file mode 100644 index 00000000..992c89a8 --- /dev/null +++ b/arkworks5/src/fft_g1.rs @@ -0,0 +1,129 @@ +use crate::consts::G1_GENERATOR; +use crate::kzg_proofs::FFTSettings; +use crate::kzg_types::{ArkFp, ArkFr, ArkG1, ArkG1Affine}; + +use crate::kzg_types::ArkG1ProjAddAffine; + +use kzg::msm::msm_impls::msm; + +use kzg::msm::precompute::PrecomputationTable; +use kzg::{Fr as KzgFr, G1Mul}; +use kzg::{FFTG1, G1}; +use std::ops::MulAssign; + +extern crate alloc; + +pub fn g1_linear_combination( + out: &mut ArkG1, + points: &[ArkG1], + scalars: &[ArkFr], + len: usize, + precomputation: Option<&PrecomputationTable>, +) { + *out = msm::( + points, + scalars, + len, + precomputation, + ); +} + +pub fn make_data(data: usize) -> Vec { + let mut vec = Vec::new(); + if data != 0 { + vec.push(G1_GENERATOR); + for i in 1..data as u64 { + let res = vec[(i - 1) as usize].add_or_dbl(&G1_GENERATOR); + vec.push(res); + } + } + vec +} + +impl FFTG1 for FFTSettings { + fn fft_g1(&self, data: &[ArkG1], inverse: bool) -> Result, String> { + if data.len() > self.max_width { + return Err(String::from("data length is longer than allowed max width")); + } + if !data.len().is_power_of_two() { + return Err(String::from("data length is not power of 2")); + } + + let stride: usize = self.max_width / data.len(); + let mut ret = vec![ArkG1::default(); data.len()]; + + let roots = if inverse { + &self.reverse_roots_of_unity + } else { + &self.roots_of_unity + }; + + fft_g1_fast(&mut ret, data, 1, roots, stride); + + if inverse { + let inv_fr_len = ArkFr::from_u64(data.len() as u64).inverse(); + ret[..data.len()] + .iter_mut() + .for_each(|f| f.0.mul_assign(&inv_fr_len.fr)); + } + Ok(ret) + } +} + +pub fn fft_g1_slow( + ret: &mut [ArkG1], + data: &[ArkG1], + stride: usize, + roots: &[ArkFr], + roots_stride: usize, +) { + for i in 0..data.len() { + ret[i] = data[0].mul(&roots[0]); + for j in 1..data.len() { + let jv = data[j * stride]; + let r = roots[((i * j) % data.len()) * roots_stride]; + let v = jv.mul(&r); + ret[i] = ret[i].add_or_dbl(&v); + } + } +} + +pub fn fft_g1_fast( + ret: &mut [ArkG1], + data: &[ArkG1], + stride: usize, + roots: &[ArkFr], + roots_stride: usize, +) { + let half = ret.len() / 2; + if half > 0 { + #[cfg(feature = "parallel")] + { + let (lo, hi) = ret.split_at_mut(half); + rayon::join( + || fft_g1_fast(hi, &data[stride..], stride * 2, roots, roots_stride * 2), + || fft_g1_fast(lo, data, stride * 2, roots, roots_stride * 2), + ); + } + + #[cfg(not(feature = "parallel"))] + { + fft_g1_fast(&mut ret[..half], data, stride * 2, roots, roots_stride * 2); + fft_g1_fast( + &mut ret[half..], + &data[stride..], + stride * 2, + roots, + roots_stride * 2, + ); + } + + for i in 0..half { + let y_times_root = ret[i + half].mul(&roots[i * roots_stride]); + ret[i + half] = ret[i].sub(&y_times_root); + ret[i] = ret[i].add_or_dbl(&y_times_root); + } + } else { + ret[0] = data[0]; + } +} diff --git a/arkworks5/src/fk20_proofs.rs b/arkworks5/src/fk20_proofs.rs new file mode 100644 index 00000000..65ccefee --- /dev/null +++ b/arkworks5/src/fk20_proofs.rs @@ -0,0 +1,324 @@ +use crate::consts::G1_IDENTITY; +use crate::kzg_proofs::{FFTSettings, KZGSettings}; +use crate::kzg_types::{ArkFp, ArkFr as BlstFr, ArkG1, ArkG1Affine, ArkG2}; +use crate::utils::PolyData; +use kzg::common_utils::reverse_bit_order; +use kzg::{FFTFr, FK20MultiSettings, FK20SingleSettings, Fr, G1Mul, Poly, FFTG1, G1}; + +#[cfg(feature = "parallel")] +use rayon::prelude::*; + +#[repr(C)] +#[derive(Debug, Clone, Default)] +pub struct KzgFK20SingleSettings { + pub ks: KZGSettings, + pub x_ext_fft: Vec, + pub x_ext_fft_len: usize, +} + +#[repr(C)] +#[derive(Debug, Clone, Default)] +pub struct KzgFK20MultiSettings { + pub ks: KZGSettings, + pub chunk_len: usize, + pub x_ext_fft_files: Vec>, +} + +impl + FK20SingleSettings + for KzgFK20SingleSettings +{ + fn new(ks: &KZGSettings, n2: usize) -> Result { + let n = n2 / 2; + + if n2 > ks.fs.max_width { + return Err(String::from( + "n2 must be equal or less than kzg settings max width", + )); + } + if !n2.is_power_of_two() { + return Err(String::from("n2 must be power of 2")); + } + if n2 < 2 { + return Err(String::from("n2 must be equal or greater than 2")); + } + + let mut x = Vec::new(); + for i in 0..(n - 1) { + x.push(ks.g1_values_lagrange_brp[n - 2 - i]) + } + x.push(G1_IDENTITY); + + let new_ks = KZGSettings { + fs: ks.fs.clone(), + ..KZGSettings::default() + }; + + Ok(KzgFK20SingleSettings { + ks: new_ks, + x_ext_fft: toeplitz_part_1(&x, &ks.fs).unwrap(), + x_ext_fft_len: n2, + }) + } + + fn data_availability(&self, p: &PolyData) -> Result, String> { + let n = p.len(); + let n2 = n * 2; + + if n2 > self.ks.fs.max_width { + return Err(String::from( + "n2 must be equal or less than kzg settings max width", + )); + } + if !n.is_power_of_two() { + return Err(String::from("n2 must be power of 2")); + } + + let mut out = fk20_single_da_opt(p, self).unwrap(); + reverse_bit_order(&mut out)?; + Ok(out) + } + + fn data_availability_optimized(&self, p: &PolyData) -> Result, String> { + fk20_single_da_opt(p, self) + } +} + +impl FK20MultiSettings + for KzgFK20MultiSettings +{ + fn new(ks: &KZGSettings, n2: usize, chunk_len: usize) -> Result { + if n2 > ks.fs.max_width { + return Err(String::from( + "n2 must be equal or less than kzg settings max width", + )); + } + if !n2.is_power_of_two() { + return Err(String::from("n2 must be power of 2")); + } + if n2 < 2 { + return Err(String::from("n2 must be equal or greater than 2")); + } + if chunk_len > n2 / 2 { + return Err(String::from("chunk_len must be equal or less than n2/2")); + } + if !chunk_len.is_power_of_two() { + return Err(String::from("chunk_len must be power of 2")); + } + if chunk_len == 0 { + return Err(String::from("chunk_len must be greater than 0")); + } + + let n = n2 / 2; + let k = n / chunk_len; + + let mut x_ext_fft_files = Vec::new(); + + for offset in 0..chunk_len { + let mut x = vec![ArkG1::default(); k]; + let start = if n >= chunk_len + 1 + offset { + n - chunk_len - 1 - offset + } else { + 0 + }; + let mut j = start; + for i in x.iter_mut().take(k - 1) { + i.0 = ks.g1_values_lagrange_brp[j].0; + if j >= chunk_len { + j -= chunk_len; + } else { + j = 0; + } + } + x[k - 1] = G1_IDENTITY; + x_ext_fft_files.push(toeplitz_part_1(&x, &ks.fs).unwrap()); + } + + let new_ks = KZGSettings { + fs: ks.fs.clone(), + ..KZGSettings::default() + }; + + Ok(KzgFK20MultiSettings { + ks: new_ks, + x_ext_fft_files, + chunk_len, + }) + } + + fn data_availability(&self, p: &PolyData) -> Result, String> { + let n = p.len(); + let n2 = n * 2; + + if n2 > self.ks.fs.max_width { + return Err(String::from( + "n2 must be equal or less than kzg settings max width", + )); + } + if !n.is_power_of_two() { + return Err(String::from("n2 must be power of 2")); + } + + let mut out = fk20_multi_da_opt(p, self).unwrap(); + reverse_bit_order(&mut out)?; + Ok(out) + } + + fn data_availability_optimized(&self, p: &PolyData) -> Result, String> { + fk20_multi_da_opt(p, self) + } +} + +fn fk20_single_da_opt(p: &PolyData, fk: &KzgFK20SingleSettings) -> Result, String> { + let n = p.len(); + let n2 = n * 2; + + if n2 > fk.ks.fs.max_width { + return Err(String::from( + "n2 must be equal or less than kzg settings max width", + )); + } + if !n.is_power_of_two() { + return Err(String::from("n2 must be power of 2")); + } + + let outlen = 2 * p.len(); + let toeplitz_coeffs = toeplitz_coeffs_step(p, outlen).unwrap(); + let h_ext_fft = toeplitz_part_2(&toeplitz_coeffs, &fk.x_ext_fft, &fk.ks.fs).unwrap(); + let h = toeplitz_part_3(&h_ext_fft, &fk.ks.fs).unwrap(); + + fk.ks.fs.fft_g1(&h, false) +} + +fn fk20_multi_da_opt(p: &PolyData, fk: &KzgFK20MultiSettings) -> Result, String> { + let n = p.len(); + let n2 = n * 2; + + if n2 > fk.ks.fs.max_width { + return Err(String::from( + "n2 must be equal or less than kzg settings max width", + )); + } + if !n.is_power_of_two() { + return Err(String::from("n2 must be power of 2")); + } + + let n = n2 / 2; + let k = n / fk.chunk_len; + let k2 = k * 2; + + let mut h_ext_fft = Vec::new(); + for _i in 0..k2 { + h_ext_fft.push(G1_IDENTITY); + } + + let mut toeplitz_coeffs = PolyData::new(n2 / fk.chunk_len); + for i in 0..fk.chunk_len { + toeplitz_coeffs = + toeplitz_coeffs_stride(p, i, fk.chunk_len, toeplitz_coeffs.len()).unwrap(); + let h_ext_fft_file = + toeplitz_part_2(&toeplitz_coeffs, &fk.x_ext_fft_files[i], &fk.ks.fs).unwrap(); + for j in 0..k2 { + h_ext_fft[j] = h_ext_fft[j].add_or_dbl(&h_ext_fft_file[j]); + } + } + + // Calculate `h` + let mut h = toeplitz_part_3(&h_ext_fft, &fk.ks.fs).unwrap(); + + // Overwrite the second half of `h` with zero + for i in h.iter_mut().take(k2).skip(k) { + i.0 = G1_IDENTITY.0; + } + + fk.ks.fs.fft_g1(&h, false) +} + +fn toeplitz_coeffs_step(p: &PolyData, outlen: usize) -> Result { + toeplitz_coeffs_stride(p, 0, 1, outlen) +} + +fn toeplitz_coeffs_stride( + poly: &PolyData, + offset: usize, + stride: usize, + outlen: usize, +) -> Result { + let n = poly.len(); + + if stride == 0 { + return Err(String::from("stride must be greater than 0")); + } + + let k = n / stride; + let k2 = k * 2; + + if outlen < k2 { + return Err(String::from("outlen must be equal or greater than k2")); + } + + let mut out = PolyData::new(outlen); + out.set_coeff_at(0, &poly.coeffs[n - 1 - offset]); + let mut i = 1; + while i <= (k + 1) && i < k2 { + out.set_coeff_at(i, &BlstFr::zero()); + i += 1; + } + let mut j = 2 * stride - offset - 1; + for i in (k + 2)..k2 { + out.set_coeff_at(i, &poly.coeffs[j]); + j += stride; + } + Ok(out) +} + +fn toeplitz_part_1(x: &[ArkG1], fs: &FFTSettings) -> Result, String> { + let n = x.len(); + let n2 = n * 2; + + let mut x_ext = Vec::new(); + for i in x.iter().take(n) { + x_ext.push(*i); + } + for _i in n..n2 { + x_ext.push(G1_IDENTITY); + } + fs.fft_g1(&x_ext, false) +} + +fn toeplitz_part_2( + toeplitz_coeffs: &PolyData, + x_ext_fft: &[ArkG1], + fs: &FFTSettings, +) -> Result, String> { + let toeplitz_coeffs_fft = fs.fft_fr(&toeplitz_coeffs.coeffs, false).unwrap(); + + #[cfg(feature = "parallel")] + { + let out: Vec<_> = (0..toeplitz_coeffs.len()) + .into_par_iter() + .map(|i| x_ext_fft[i].mul(&toeplitz_coeffs_fft[i])) + .collect(); + Ok(out) + } + + #[cfg(not(feature = "parallel"))] + { + let mut out = Vec::new(); + for i in 0..toeplitz_coeffs.len() { + out.push(x_ext_fft[i].mul(&toeplitz_coeffs_fft[i])); + } + Ok(out) + } +} + +fn toeplitz_part_3(h_ext_fft: &[ArkG1], fs: &FFTSettings) -> Result, String> { + let n = h_ext_fft.len() / 2; + let mut out = fs.fft_g1(h_ext_fft, true).unwrap(); + + // Zero the second half of h + for i in out.iter_mut().take(h_ext_fft.len()).skip(n) { + i.0 = G1_IDENTITY.0; + } + Ok(out) +} diff --git a/arkworks5/src/kzg_proofs.rs b/arkworks5/src/kzg_proofs.rs new file mode 100644 index 00000000..4f993716 --- /dev/null +++ b/arkworks5/src/kzg_proofs.rs @@ -0,0 +1,96 @@ +#![allow(non_camel_case_types)] + +extern crate alloc; +use super::utils::{blst_poly_into_pc_poly, PolyData}; +use crate::consts::{G1_GENERATOR, G2_GENERATOR}; +use crate::kzg_types::{ArkFp, ArkFr, ArkG1Affine}; +use crate::kzg_types::{ArkFr as BlstFr, ArkG1, ArkG2}; +use alloc::sync::Arc; +use ark_bls12_381::Bls12_381; +use ark_ec::pairing::Pairing; +use ark_ec::CurveGroup; +use ark_poly::Polynomial; +use ark_std::{vec, One}; +use kzg::eip_4844::hash_to_bls_field; +use kzg::msm::precompute::PrecomputationTable; +use kzg::Fr as FrTrait; +use kzg::{G1Mul, G2Mul}; +use std::ops::Neg; + +#[derive(Debug, Clone)] +pub struct FFTSettings { + pub max_width: usize, + pub root_of_unity: BlstFr, + pub reverse_roots_of_unity: Vec, + pub roots_of_unity: Vec, + pub brp_roots_of_unity: Vec, +} + +pub fn expand_root_of_unity(root: &BlstFr, width: usize) -> Result, String> { + let mut generated_powers = vec![BlstFr::one(), *root]; + + while !(generated_powers.last().unwrap().is_one()) { + if generated_powers.len() > width { + return Err(String::from("Root of unity multiplied for too long")); + } + + generated_powers.push(generated_powers.last().unwrap().mul(root)); + } + + if generated_powers.len() != width + 1 { + return Err(String::from("Root of unity has invalid scale")); + } + + Ok(generated_powers) +} + +#[derive(Debug, Clone, Default)] +pub struct KZGSettings { + pub fs: FFTSettings, + pub g1_values_monomial: Vec, + pub g1_values_lagrange_brp: Vec, + pub g2_values_monomial: Vec, + pub precomputation: Option>>, + pub x_ext_fft_columns: Vec>, + pub cell_size: usize, +} + +pub fn generate_trusted_setup( + len: usize, + secret: [u8; 32usize], +) -> (Vec, Vec, Vec) { + let s = hash_to_bls_field::(&secret); + let mut s_pow = ArkFr::one(); + + let mut s1 = Vec::with_capacity(len); + let mut s2 = Vec::with_capacity(len); + let mut s3 = Vec::with_capacity(len); + + for _ in 0..len { + s1.push(G1_GENERATOR.mul(&s_pow)); + s2.push(G1_GENERATOR.mul(&s_pow)); + s3.push(G2_GENERATOR.mul(&s_pow)); + + s_pow = s_pow.mul(&s); + } + + (s1, s2, s3) +} + +pub fn eval_poly(p: &PolyData, x: &BlstFr) -> BlstFr { + let poly = blst_poly_into_pc_poly(&p.coeffs); + BlstFr { + fr: poly.evaluate(&x.fr), + } +} + +pub fn pairings_verify(a1: &ArkG1, a2: &ArkG2, b1: &ArkG1, b2: &ArkG2) -> bool { + let ark_a1_neg = a1.0.neg().into_affine(); + let ark_b1 = b1.0.into_affine(); + let ark_a2 = a2.0.into_affine(); + let ark_b2 = b2.0.into_affine(); + + Bls12_381::multi_pairing([ark_a1_neg, ark_b1], [ark_a2, ark_b2]) + .0 + .is_one() +} diff --git a/arkworks5/src/kzg_types.rs b/arkworks5/src/kzg_types.rs new file mode 100644 index 00000000..366cabd1 --- /dev/null +++ b/arkworks5/src/kzg_types.rs @@ -0,0 +1,1121 @@ +use crate::consts::{ + G1_GENERATOR, G1_IDENTITY, G1_NEGATIVE_GENERATOR, G2_GENERATOR, G2_NEGATIVE_GENERATOR, + SCALE2_ROOT_OF_UNITY, +}; +use crate::fft_g1::g1_linear_combination; +use crate::kzg_proofs::{ + eval_poly, expand_root_of_unity, pairings_verify, FFTSettings as LFFTSettings, + KZGSettings as LKZGSettings, +}; +use crate::poly::{poly_fast_div, poly_inverse, poly_long_div, poly_mul_direct, poly_mul_fft}; +use crate::recover::{scale_poly, unscale_poly}; +use crate::utils::{ + blst_fp_into_pc_fq, blst_fr_into_pc_fr, blst_p1_into_pc_g1projective, + blst_p2_into_pc_g2projective, fft_settings_to_rust, pc_fr_into_blst_fr, + pc_g1projective_into_blst_p1, pc_g2projective_into_blst_p2, PolyData, PRECOMPUTATION_TABLES, +}; +use ark_bls12_381::{g1, g2, Fr, G1Affine, G2Affine}; +use ark_ec::{models::short_weierstrass::Projective, AdditiveGroup, AffineRepr}; +use ark_ec::{CurveConfig, CurveGroup}; +use ark_ff::{biginteger::BigInteger256, BigInteger, Field}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::{One, Zero}; + +#[cfg(feature = "rand")] +use ark_std::UniformRand; +use kzg::eth::c_bindings::{blst_fp, blst_fr, blst_p1, blst_p2, CKZGSettings}; + +use crate::fft_g1::fft_g1_fast; + +use kzg::common_utils::reverse_bit_order; +use kzg::msm::precompute::{precompute, PrecomputationTable}; +use kzg::{ + eth, FFTFr, FFTSettings, FFTSettingsPoly, Fr as KzgFr, G1Affine as G1AffineTrait, G1Fp, + G1GetFp, G1LinComb, G1Mul, G1ProjAddAffine, G2Mul, KZGSettings, PairingVerify, Poly, Scalar256, + G1, G2, +}; +use std::ops::{AddAssign, Mul, Neg, Sub}; + +use kzg::eip_4844::{BYTES_PER_FIELD_ELEMENT, BYTES_PER_G1, BYTES_PER_G2}; + +extern crate alloc; +use alloc::sync::Arc; + +fn bytes_be_to_uint64(inp: &[u8]) -> u64 { + u64::from_be_bytes(inp.try_into().expect("Input wasn't 8 elements...")) +} + +const BLS12_381_MOD_256: [u64; 4] = [ + 0xffffffff00000001, + 0x53bda402fffe5bfe, + 0x3339d80809a1d805, + 0x73eda753299d7d48, +]; + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] +pub struct ArkFr { + pub fr: Fr, +} + +impl ArkFr { + pub fn from_blst_fr(fr: blst_fr) -> Self { + Self { + fr: blst_fr_into_pc_fr(fr), + } + } + + pub fn to_blst_fr(&self) -> blst_fr { + pc_fr_into_blst_fr(self.fr) + } +} + +fn bigint_check_mod_256(a: &[u64; 4]) -> bool { + let (_, overflow) = a[0].overflowing_sub(BLS12_381_MOD_256[0]); + let (_, overflow) = a[1].overflowing_sub(BLS12_381_MOD_256[1] + overflow as u64); + let (_, overflow) = a[2].overflowing_sub(BLS12_381_MOD_256[2] + overflow as u64); + let (_, overflow) = a[3].overflowing_sub(BLS12_381_MOD_256[3] + overflow as u64); + overflow +} + +impl KzgFr for ArkFr { + fn null() -> Self { + Self { + fr: Fr::new_unchecked(BigInteger256::new([u64::MAX; 4])), + } + } + + fn zero() -> Self { + // Self::from_u64(0) + Self { fr: Fr::zero() } + } + + fn one() -> Self { + let one = Fr::one(); + // assert_eq!(one.0.0, [0, 1, 1, 1], "must be eq"); + Self { fr: one } + // Self::from_u64(1) + } + + #[cfg(feature = "rand")] + fn rand() -> Self { + let mut rng = rand::thread_rng(); + Self { + fr: Fr::rand(&mut rng), + } + } + + fn from_bytes(bytes: &[u8]) -> Result { + bytes + .try_into() + .map_err(|_| { + format!( + "Invalid byte length. Expected {}, got {}", + BYTES_PER_FIELD_ELEMENT, + bytes.len() + ) + }) + .and_then(|bytes: &[u8; BYTES_PER_FIELD_ELEMENT]| { + let storage: [u64; 4] = [ + bytes_be_to_uint64(&bytes[24..32]), + bytes_be_to_uint64(&bytes[16..24]), + bytes_be_to_uint64(&bytes[8..16]), + bytes_be_to_uint64(&bytes[0..8]), + ]; + let big_int = BigInteger256::new(storage); + if !big_int.is_zero() && !bigint_check_mod_256(&big_int.0) { + return Err("Invalid scalar".to_string()); + } + Ok(Self { + fr: Fr::new(big_int), + }) + }) + } + + fn from_bytes_unchecked(bytes: &[u8]) -> Result { + bytes + .try_into() + .map_err(|_| { + format!( + "Invalid byte length. Expected {}, got {}", + BYTES_PER_FIELD_ELEMENT, + bytes.len() + ) + }) + .map(|bytes: &[u8; BYTES_PER_FIELD_ELEMENT]| { + let storage: [u64; 4] = [ + bytes_be_to_uint64(&bytes[24..32]), + bytes_be_to_uint64(&bytes[16..24]), + bytes_be_to_uint64(&bytes[8..16]), + bytes_be_to_uint64(&bytes[0..8]), + ]; + let big_int = BigInteger256::new(storage); + Self { + fr: Fr::new(big_int), + } + }) + } + + fn from_hex(hex: &str) -> Result { + let bytes = hex::decode(&hex[2..]).unwrap(); + Self::from_bytes(&bytes) + } + + fn from_u64_arr(u: &[u64; 4]) -> Self { + Self { + fr: Fr::new(BigInteger256::new(*u)), + } + } + + fn from_u64(val: u64) -> Self { + Self::from_u64_arr(&[val, 0, 0, 0]) + } + + fn to_bytes(&self) -> [u8; 32] { + let big_int_256: BigInteger256 = Fr::into(self.fr); + <[u8; 32]>::try_from(big_int_256.to_bytes_be()).unwrap() + } + + fn to_u64_arr(&self) -> [u64; 4] { + let b: BigInteger256 = Fr::into(self.fr); + b.0 + } + + fn is_one(&self) -> bool { + self.fr.is_one() + } + + fn is_zero(&self) -> bool { + self.fr.is_zero() + } + + fn is_null(&self) -> bool { + self.equals(&ArkFr::null()) + } + + fn sqr(&self) -> Self { + Self { + fr: self.fr.square(), + } + } + + fn mul(&self, b: &Self) -> Self { + Self { fr: self.fr * b.fr } + } + + fn add(&self, b: &Self) -> Self { + Self { fr: self.fr + b.fr } + } + + fn sub(&self, b: &Self) -> Self { + Self { fr: self.fr - b.fr } + } + + fn eucl_inverse(&self) -> Self { + // Inverse and eucl inverse work the same way + Self { + fr: self.fr.inverse().unwrap(), + } + } + + fn negate(&self) -> Self { + Self { fr: self.fr.neg() } + } + + fn inverse(&self) -> Self { + Self { + fr: self.fr.inverse().unwrap(), + } + } + + fn pow(&self, n: usize) -> Self { + Self { + fr: self.fr.pow([n as u64]), + } + } + + fn div(&self, b: &Self) -> Result { + let div = self.fr / b.fr; + if div.0 .0.is_empty() { + Ok(Self { fr: Fr::zero() }) + } else { + Ok(Self { fr: div }) + } + } + + fn equals(&self, b: &Self) -> bool { + self.fr == b.fr + } + + fn to_scalar(&self) -> Scalar256 { + Scalar256::from_u64(BigInteger256::from(self.fr).0) + } +} + +#[repr(C)] +#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] +pub struct ArkG1(pub Projective); + +impl ArkG1 { + pub const fn from_blst_p1(p1: blst_p1) -> Self { + Self(blst_p1_into_pc_g1projective(&p1)) + } + + pub const fn to_blst_p1(&self) -> blst_p1 { + pc_g1projective_into_blst_p1(self.0) + } +} + +impl From for ArkG1 { + fn from(p1: blst_p1) -> Self { + Self(blst_p1_into_pc_g1projective(&p1)) + } +} + +impl G1 for ArkG1 { + fn identity() -> Self { + G1_IDENTITY + } + + fn generator() -> Self { + G1_GENERATOR + } + + fn negative_generator() -> Self { + G1_NEGATIVE_GENERATOR + } + + #[cfg(feature = "rand")] + fn rand() -> Self { + let mut rng = rand::thread_rng(); + Self(Projective::rand(&mut rng)) + } + + #[allow(clippy::bind_instead_of_map)] + fn from_bytes(bytes: &[u8]) -> Result { + bytes + .try_into() + .map_err(|_| { + format!( + "Invalid byte length. Expected {}, got {}", + BYTES_PER_G1, + bytes.len() + ) + }) + .and_then(|bytes: &[u8; BYTES_PER_G1]| { + let affine = G1Affine::deserialize_compressed(bytes.as_slice()); + match affine { + Err(x) => Err("Failed to deserialize G1: ".to_owned() + &(x.to_string())), + Ok(x) => Ok(Self(x.into_group())), + } + }) + } + + fn from_hex(hex: &str) -> Result { + let bytes = hex::decode(&hex[2..]).unwrap(); + Self::from_bytes(&bytes) + } + + fn to_bytes(&self) -> [u8; 48] { + let mut buff = [0u8; BYTES_PER_G1]; + self.0.serialize_compressed(&mut &mut buff[..]).unwrap(); + buff + } + + fn add_or_dbl(&self, b: &Self) -> Self { + Self(self.0 + b.0) + } + + fn is_inf(&self) -> bool { + let temp = &self.0; + temp.z.is_zero() + } + + fn is_valid(&self) -> bool { + true + } + + fn dbl(&self) -> Self { + Self(self.0.double()) + } + + fn add(&self, b: &Self) -> Self { + Self(self.0 + b.0) + } + + fn sub(&self, b: &Self) -> Self { + Self(self.0.sub(&b.0)) + } + + fn equals(&self, b: &Self) -> bool { + self.0.eq(&b.0) + } + + fn zero() -> ArkG1 { + ArkG1::from_blst_p1(blst_p1 { + x: blst_fp { + l: [ + 8505329371266088957, + 17002214543764226050, + 6865905132761471162, + 8632934651105793861, + 6631298214892334189, + 1582556514881692819, + ], + }, + y: blst_fp { + l: [ + 8505329371266088957, + 17002214543764226050, + 6865905132761471162, + 8632934651105793861, + 6631298214892334189, + 1582556514881692819, + ], + }, + z: blst_fp { + l: [0, 0, 0, 0, 0, 0], + }, + }) + } + + fn add_or_dbl_assign(&mut self, b: &Self) { + self.0 += b.0; + } + + fn add_assign(&mut self, b: &Self) { + self.0.add_assign(b.0); + } + + fn dbl_assign(&mut self) { + self.0.double_in_place(); + } +} + +impl G1Mul for ArkG1 { + fn mul(&self, b: &ArkFr) -> Self { + Self(self.0.mul(b.fr)) + } +} + +impl G1LinComb for ArkG1 { + fn g1_lincomb( + points: &[Self], + scalars: &[ArkFr], + len: usize, + precomputation: Option<&PrecomputationTable>, + ) -> Self { + let mut out = Self::default(); + g1_linear_combination(&mut out, points, scalars, len, precomputation); + out + } +} + +impl PairingVerify for ArkG1 { + fn verify(a1: &ArkG1, a2: &ArkG2, b1: &ArkG1, b2: &ArkG2) -> bool { + pairings_verify(a1, a2, b1, b2) + } +} + +#[repr(C)] +#[derive(Debug, Default, PartialEq, Eq, Clone)] +pub struct ArkG2(pub Projective); + +impl ArkG2 { + pub const fn from_blst_p2(p2: blst_p2) -> Self { + Self(blst_p2_into_pc_g2projective(&p2)) + } + + pub const fn to_blst_p2(&self) -> blst_p2 { + pc_g2projective_into_blst_p2(self.0) + } +} + +impl G2 for ArkG2 { + fn generator() -> Self { + G2_GENERATOR + } + + fn negative_generator() -> Self { + G2_NEGATIVE_GENERATOR + } + + #[allow(clippy::bind_instead_of_map)] + fn from_bytes(bytes: &[u8]) -> Result { + bytes + .try_into() + .map_err(|_| { + format!( + "Invalid byte length. Expected {}, got {}", + BYTES_PER_G2, + bytes.len() + ) + }) + .and_then(|bytes: &[u8; BYTES_PER_G2]| { + let affine = G2Affine::deserialize_compressed(bytes.as_slice()); + match affine { + Err(x) => Err("Failed to deserialize G2: ".to_owned() + &(x.to_string())), + Ok(x) => Ok(Self(x.into_group())), + } + }) + } + + fn to_bytes(&self) -> [u8; 96] { + let mut buff = [0u8; BYTES_PER_G2]; + self.0.serialize_compressed(&mut &mut buff[..]).unwrap(); + buff + } + + fn add_or_dbl(&mut self, b: &Self) -> Self { + Self(self.0 + b.0) + } + + fn dbl(&self) -> Self { + Self(self.0.double()) + } + + fn sub(&self, b: &Self) -> Self { + Self(self.0 - b.0) + } + + fn equals(&self, b: &Self) -> bool { + self.0.eq(&b.0) + } +} + +impl G2Mul for ArkG2 { + fn mul(&self, b: &ArkFr) -> Self { + Self(self.0.mul(&b.fr)) + } +} + +impl Poly for PolyData { + fn new(size: usize) -> PolyData { + Self { + coeffs: vec![ArkFr::default(); size], + } + } + + fn get_coeff_at(&self, i: usize) -> ArkFr { + self.coeffs[i] + } + + fn set_coeff_at(&mut self, i: usize, x: &ArkFr) { + self.coeffs[i] = *x; + } + + fn get_coeffs(&self) -> &[ArkFr] { + &self.coeffs + } + + fn len(&self) -> usize { + self.coeffs.len() + } + + fn eval(&self, x: &ArkFr) -> ArkFr { + eval_poly(self, x) + } + + fn scale(&mut self) { + scale_poly(self); + } + + fn unscale(&mut self) { + unscale_poly(self); + } + + fn inverse(&mut self, new_len: usize) -> Result { + poly_inverse(self, new_len) + } + + fn div(&mut self, x: &Self) -> Result { + if x.len() >= self.len() || x.len() < 128 { + poly_long_div(self, x) + } else { + poly_fast_div(self, x) + } + } + + fn long_div(&mut self, x: &Self) -> Result { + poly_long_div(self, x) + } + + fn fast_div(&mut self, x: &Self) -> Result { + poly_fast_div(self, x) + } + + fn mul_direct(&mut self, x: &Self, len: usize) -> Result { + poly_mul_direct(self, x, len) + } +} + +impl FFTSettingsPoly for LFFTSettings { + fn poly_mul_fft( + a: &PolyData, + x: &PolyData, + len: usize, + fs: Option<&LFFTSettings>, + ) -> Result { + poly_mul_fft(a, x, fs, len) + } +} + +impl Default for LFFTSettings { + fn default() -> Self { + Self { + max_width: 0, + root_of_unity: ArkFr::zero(), + reverse_roots_of_unity: Vec::new(), + roots_of_unity: Vec::new(), + brp_roots_of_unity: Vec::new(), + } + } +} + +impl FFTSettings for LFFTSettings { + fn new(scale: usize) -> Result { + if scale >= SCALE2_ROOT_OF_UNITY.len() { + return Err(String::from( + "Scale is expected to be within root of unity matrix row size", + )); + } + + let max_width: usize = 1 << scale; + let root_of_unity = ArkFr::from_u64_arr(&SCALE2_ROOT_OF_UNITY[scale]); + + let roots_of_unity = expand_root_of_unity(&root_of_unity, max_width)?; + + let mut brp_roots_of_unity = roots_of_unity.clone(); + brp_roots_of_unity.pop(); + reverse_bit_order(&mut brp_roots_of_unity)?; + + let mut reverse_roots_of_unity = roots_of_unity.clone(); + reverse_roots_of_unity.reverse(); + + Ok(LFFTSettings { + max_width, + root_of_unity, + reverse_roots_of_unity, + roots_of_unity, + brp_roots_of_unity, + }) + } + + fn get_max_width(&self) -> usize { + self.max_width + } + + fn get_reverse_roots_of_unity_at(&self, i: usize) -> ArkFr { + self.reverse_roots_of_unity[i] + } + + fn get_reversed_roots_of_unity(&self) -> &[ArkFr] { + &self.reverse_roots_of_unity + } + + fn get_roots_of_unity_at(&self, i: usize) -> ArkFr { + self.roots_of_unity[i] + } + + fn get_roots_of_unity(&self) -> &[ArkFr] { + &self.roots_of_unity + } + + fn get_brp_roots_of_unity(&self) -> &[ArkFr] { + &self.brp_roots_of_unity + } + + fn get_brp_roots_of_unity_at(&self, i: usize) -> ArkFr { + self.brp_roots_of_unity[i] + } +} + +fn toeplitz_part_1( + field_elements_per_ext_blob: usize, + output: &mut [ArkG1], + x: &[ArkG1], + s: &LFFTSettings, +) -> Result<(), String> { + let n = x.len(); + let n2 = n * 2; + let mut x_ext = vec![ArkG1::identity(); n2]; + + x_ext[..n].copy_from_slice(x); + + let x_ext = &x_ext[..]; + + /* Ensure the length is valid */ + if x_ext.len() > field_elements_per_ext_blob || !x_ext.len().is_power_of_two() { + return Err("Invalid input size".to_string()); + } + + let roots_stride = field_elements_per_ext_blob / x_ext.len(); + fft_g1_fast(output, x_ext, 1, &s.roots_of_unity, roots_stride); + + Ok(()) +} + +impl KZGSettings for LKZGSettings { + fn new( + g1_monomial: &[ArkG1], + g1_lagrange_brp: &[ArkG1], + g2_monomial: &[ArkG2], + fft_settings: &LFFTSettings, + cell_size: usize, + ) -> Result { + if g1_monomial.len() != g1_lagrange_brp.len() { + return Err("G1 point length mismatch".to_string()); + } + + let field_elements_per_blob = g1_monomial.len(); + let field_elements_per_ext_blob = field_elements_per_blob * 2; + + let n = field_elements_per_ext_blob / 2; + let k = n / cell_size; + let k2 = 2 * k; + + let mut points = vec![ArkG1::default(); k2]; + let mut x = vec![ArkG1::default(); k]; + let mut x_ext_fft_columns = vec![vec![ArkG1::default(); cell_size]; k2]; + + for offset in 0..cell_size { + let start = n - cell_size - 1 - offset; + for (i, p) in x.iter_mut().enumerate().take(k - 1) { + let j = start - i * cell_size; + *p = g1_monomial[j]; + } + x[k - 1] = ArkG1::identity(); + + toeplitz_part_1(field_elements_per_ext_blob, &mut points, &x, fft_settings)?; + + for row in 0..k2 { + x_ext_fft_columns[row][offset] = points[row]; + } + } + + Ok(Self { + g1_values_monomial: g1_monomial.to_vec(), + g1_values_lagrange_brp: g1_lagrange_brp.to_vec(), + g2_values_monomial: g2_monomial.to_vec(), + fs: fft_settings.clone(), + x_ext_fft_columns, + precomputation: precompute(g1_lagrange_brp).ok().flatten().map(Arc::new), + cell_size, + }) + } + + fn commit_to_poly(&self, p: &PolyData) -> Result { + if p.coeffs.len() > self.g1_values_lagrange_brp.len() { + return Err(String::from("Polynomial is longer than secret g1")); + } + + let mut out = ArkG1::default(); + g1_linear_combination( + &mut out, + &self.g1_values_lagrange_brp, + &p.coeffs, + p.coeffs.len(), + self.get_precomputation(), + ); + + Ok(out) + } + + fn compute_proof_single(&self, p: &PolyData, x: &ArkFr) -> Result { + if p.coeffs.is_empty() { + return Err(String::from("Polynomial must not be empty")); + } + + // `-(x0^n)`, where `n` is `1` + let divisor_0 = x.negate(); + + // Calculate `q = p / (x^n - x0^n)` for our reduced case (see `compute_proof_multi` for + // generic implementation) + let mut out_coeffs = Vec::from(&p.coeffs[1..]); + for i in (1..out_coeffs.len()).rev() { + let tmp = out_coeffs[i].mul(&divisor_0); + out_coeffs[i - 1] = out_coeffs[i - 1].sub(&tmp); + } + + let q = PolyData { coeffs: out_coeffs }; + let ret = self.commit_to_poly(&q)?; + Ok(ret) + // Ok(compute_single(p, x, self)) + } + + fn check_proof_single( + &self, + com: &ArkG1, + proof: &ArkG1, + x: &ArkFr, + y: &ArkFr, + ) -> Result { + let x_g2: ArkG2 = G2_GENERATOR.mul(x); + let s_minus_x: ArkG2 = self.g2_values_monomial[1].sub(&x_g2); + let y_g1 = G1_GENERATOR.mul(y); + let commitment_minus_y: ArkG1 = com.sub(&y_g1); + + Ok(pairings_verify( + &commitment_minus_y, + &G2_GENERATOR, + proof, + &s_minus_x, + )) + } + + fn compute_proof_multi(&self, p: &PolyData, x: &ArkFr, n: usize) -> Result { + if p.coeffs.is_empty() { + return Err(String::from("Polynomial must not be empty")); + } + + if !n.is_power_of_two() { + return Err(String::from("n must be a power of two")); + } + + // Construct x^n - x0^n = (x - x0.w^0)(x - x0.w^1)...(x - x0.w^(n-1)) + let mut divisor = PolyData { + coeffs: Vec::with_capacity(n + 1), + }; + + // -(x0^n) + let x_pow_n = x.pow(n); + + divisor.coeffs.push(x_pow_n.negate()); + + // Zeros + for _ in 1..n { + divisor.coeffs.push(ArkFr { fr: Fr::zero() }); + } + + // x^n + divisor.coeffs.push(ArkFr { fr: Fr::one() }); + + let mut new_polina = p.clone(); + + // Calculate q = p / (x^n - x0^n) + // let q = p.div(&divisor).unwrap(); + let q = new_polina.div(&divisor)?; + let ret = self.commit_to_poly(&q)?; + Ok(ret) + } + + fn check_proof_multi( + &self, + com: &ArkG1, + proof: &ArkG1, + x: &ArkFr, + ys: &[ArkFr], + n: usize, + ) -> Result { + if !n.is_power_of_two() { + return Err(String::from("n is not a power of two")); + } + + // Interpolate at a coset. + let mut interp = PolyData { + coeffs: self.fs.fft_fr(ys, true)?, + }; + + let inv_x = x.inverse(); // Not euclidean? + let mut inv_x_pow = inv_x; + for i in 1..n { + interp.coeffs[i] = interp.coeffs[i].mul(&inv_x_pow); + inv_x_pow = inv_x_pow.mul(&inv_x); + } + + // [x^n]_2 + let x_pow = inv_x_pow.inverse(); + + let xn2 = G2_GENERATOR.mul(&x_pow); + + // [s^n - x^n]_2 + let xn_minus_yn = self.g2_values_monomial[n].sub(&xn2); + + // [interpolation_polynomial(s)]_1 + let is1 = self.commit_to_poly(&interp).unwrap(); + + // [commitment - interpolation_polynomial(s)]_1 = [commit]_1 - [interpolation_polynomial(s)]_1 + let commit_minus_interp = com.sub(&is1); + + let ret = pairings_verify(&commit_minus_interp, &G2_GENERATOR, proof, &xn_minus_yn); + + Ok(ret) + } + + fn get_roots_of_unity_at(&self, i: usize) -> ArkFr { + self.fs.get_roots_of_unity_at(i) + } + + fn get_fft_settings(&self) -> &LFFTSettings { + &self.fs + } + + fn get_g1_lagrange_brp(&self) -> &[ArkG1] { + &self.g1_values_lagrange_brp + } + + fn get_g1_monomial(&self) -> &[ArkG1] { + &self.g1_values_monomial + } + + fn get_g2_monomial(&self) -> &[ArkG2] { + &self.g2_values_monomial + } + + fn get_precomputation(&self) -> Option<&PrecomputationTable> { + self.precomputation.as_ref().map(|v| v.as_ref()) + } + + fn get_x_ext_fft_column(&self, index: usize) -> &[ArkG1] { + &self.x_ext_fft_columns[index] + } + + fn get_cell_size(&self) -> usize { + self.cell_size + } +} + +impl<'a> TryFrom<&'a CKZGSettings> for LKZGSettings { + type Error = String; + + fn try_from(c_settings: &'a CKZGSettings) -> Result { + Ok(LKZGSettings { + fs: fft_settings_to_rust(c_settings)?, + g1_values_monomial: unsafe { + core::slice::from_raw_parts( + c_settings.g1_values_monomial, + eth::FIELD_ELEMENTS_PER_BLOB, + ) + } + .iter() + .map(|r| ArkG1::from_blst_p1(*r)) + .collect::>(), + g1_values_lagrange_brp: unsafe { + core::slice::from_raw_parts( + c_settings.g1_values_lagrange_brp, + eth::FIELD_ELEMENTS_PER_BLOB, + ) + } + .iter() + .map(|r| ArkG1::from_blst_p1(*r)) + .collect::>(), + g2_values_monomial: unsafe { + core::slice::from_raw_parts( + c_settings.g2_values_monomial, + eth::TRUSTED_SETUP_NUM_G2_POINTS, + ) + } + .iter() + .map(|r| ArkG2::from_blst_p2(*r)) + .collect::>(), + x_ext_fft_columns: unsafe { + core::slice::from_raw_parts( + c_settings.x_ext_fft_columns, + 2 * ((eth::FIELD_ELEMENTS_PER_EXT_BLOB / 2) / eth::FIELD_ELEMENTS_PER_CELL), + ) + } + .iter() + .map(|it| { + unsafe { core::slice::from_raw_parts(*it, eth::FIELD_ELEMENTS_PER_CELL) } + .iter() + .map(|it| ArkG1::from_blst_p1(*it)) + .collect::>() + }) + .collect::>(), + precomputation: unsafe { PRECOMPUTATION_TABLES.get_precomputation(c_settings) }, + cell_size: eth::FIELD_ELEMENTS_PER_CELL, + }) + } +} + +type ArkFpInt = ::BaseField; +#[repr(C)] +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +pub struct ArkFp(pub ArkFpInt); + +impl G1Fp for ArkFp { + fn is_zero(&self) -> bool { + self.0.is_zero() + } + + fn set_zero(&mut self) { + self.0.set_zero(); + } + + fn is_one(&self) -> bool { + self.0.is_one() + } + + fn set_one(&mut self) { + self.0.set_one(); + } + + fn inverse(&self) -> Option { + Some(Self(self.0.inverse().unwrap())) + } + + fn square(&self) -> Self { + Self(self.0.square()) + } + + fn double(&self) -> Self { + Self(self.0.double()) + } + + fn from_underlying_arr(arr: &[u64; 6]) -> Self { + let mut default = ArkFpInt::default(); + default.0 .0 = *arr; + Self(default) + } + + fn neg_assign(&mut self) { + self.0 = -self.0; + } + + fn mul_assign_fp(&mut self, b: &Self) { + self.0 *= b.0; + } + + fn sub_assign_fp(&mut self, b: &Self) { + self.0 -= b.0; + } + + fn add_assign_fp(&mut self, b: &Self) { + self.0 += b.0; + } + + fn zero() -> Self { + Self(ArkFpInt::ZERO) + } + fn one() -> Self { + Self(ArkFpInt::ONE) + } + fn bls12_381_rx_p() -> Self { + Self(blst_fp_into_pc_fq(&blst_fp { + l: [ + 8505329371266088957, + 17002214543764226050, + 6865905132761471162, + 8632934651105793861, + 6631298214892334189, + 1582556514881692819, + ], + })) + } +} + +impl G1GetFp for ArkG1 { + fn x(&self) -> &ArkFp { + unsafe { + // Transmute safe due to repr(C) on FsFp + core::mem::transmute(&self.0.x) + } + } + + fn y(&self) -> &ArkFp { + unsafe { + // Transmute safe due to repr(C) on FsFp + core::mem::transmute(&self.0.y) + } + } + + fn z(&self) -> &ArkFp { + unsafe { + // Transmute safe due to repr(C) on FsFp + core::mem::transmute(&self.0.z) + } + } + + fn x_mut(&mut self) -> &mut ArkFp { + unsafe { + // Transmute safe due to repr(C) on FsFp + core::mem::transmute(&mut self.0.x) + } + } + + fn y_mut(&mut self) -> &mut ArkFp { + unsafe { + // Transmute safe due to repr(C) on FsFp + core::mem::transmute(&mut self.0.y) + } + } + + fn z_mut(&mut self) -> &mut ArkFp { + unsafe { + // Transmute safe due to repr(C) on FsFp + core::mem::transmute(&mut self.0.z) + } + } +} + +#[repr(C)] +#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] +pub struct ArkG1Affine { + pub aff: G1Affine, +} + +impl G1AffineTrait for ArkG1Affine { + fn into_affine(g1: &ArkG1) -> Self { + Self { + aff: g1.0.into_affine(), + } + } + + fn into_affines(g1: &[ArkG1]) -> Vec { + let ark_points: &[Projective] = unsafe { core::mem::transmute(g1) }; + let ark_points = CurveGroup::normalize_batch(ark_points); + unsafe { core::mem::transmute(ark_points) } + } + + fn into_affines_loc(out: &mut [Self], g1: &[ArkG1]) { + out.copy_from_slice(&Self::into_affines(g1)); + } + + fn to_proj(&self) -> ArkG1 { + ArkG1(self.aff.into_group()) + } + + fn x(&self) -> &ArkFp { + unsafe { core::mem::transmute(&self.aff.x) } + } + + fn y(&self) -> &ArkFp { + unsafe { core::mem::transmute(&self.aff.y) } + } + + fn is_infinity(&self) -> bool { + self.aff.infinity + } + + fn is_zero(&self) -> bool { + self.aff.is_zero() + } + + fn zero() -> Self { + Self { + aff: G1Affine { + x: ArkFp::zero().0, + y: ArkFp::zero().0, + infinity: true, + }, + } + } + + fn x_mut(&mut self) -> &mut ArkFp { + unsafe { core::mem::transmute(&mut self.aff.x) } + } + + fn y_mut(&mut self) -> &mut ArkFp { + unsafe { core::mem::transmute(&mut self.aff.y) } + } +} + +pub struct ArkG1ProjAddAffine; +impl G1ProjAddAffine for ArkG1ProjAddAffine { + fn add_assign_affine(proj: &mut ArkG1, aff: &ArkG1Affine) { + proj.0 += aff.aff; + } + + fn add_or_double_assign_affine(proj: &mut ArkG1, aff: &ArkG1Affine) { + proj.0 += aff.aff; + } +} diff --git a/arkworks5/src/lib.rs b/arkworks5/src/lib.rs new file mode 100644 index 00000000..bee1eca9 --- /dev/null +++ b/arkworks5/src/lib.rs @@ -0,0 +1,13 @@ +pub mod consts; +pub mod das; +pub mod eip_4844; +pub mod eip_7594; +pub mod fft; +pub mod fft_g1; +pub mod fk20_proofs; +pub mod kzg_proofs; +pub mod kzg_types; +pub mod poly; +pub mod recover; +pub mod utils; +pub mod zero_poly; diff --git a/arkworks5/src/poly.rs b/arkworks5/src/poly.rs new file mode 100644 index 00000000..d3975f0b --- /dev/null +++ b/arkworks5/src/poly.rs @@ -0,0 +1,251 @@ +use super::kzg_proofs::FFTSettings; +use super::utils::{blst_poly_into_pc_poly, PolyData}; +use crate::kzg_types::ArkFr as BlstFr; +use crate::utils::pc_poly_into_blst_poly; +use crate::zero_poly::pad_poly; +use ark_bls12_381::Fr; +use ark_poly::univariate::DensePolynomial; +use ark_poly::DenseUVPolynomial; +use ark_std::{log2, Zero}; +use kzg::common_utils::{log2_pow2, next_pow_of_2}; +use kzg::{FFTFr, FFTSettings as FFTSettingsT, Fr as FrTrait, Poly}; +use std::cmp::min; + +pub fn poly_inverse(b: &PolyData, output_len: usize) -> Result { + if b.coeffs.is_empty() { + return Err(String::from("b.coeffs is empty")); + } + + if BlstFr::is_zero(&b.coeffs[0]) { + return Err(String::from("b.coeffs[0] is zero")); + } + + let mut output = PolyData { + coeffs: vec![BlstFr::zero(); output_len], + }; + if b.coeffs.len() == 1 { + output.coeffs[0] = b.coeffs[0].inverse(); + for i in 1..output_len { + output.coeffs[i] = BlstFr::zero(); + } + return Ok(output); + } + + let maxd = output_len - 1; + let scale = next_pow_of_2(log2_pow2(2 * output_len - 1)); + let fs = FFTSettings::new(scale).unwrap(); + + let mut tmp0: PolyData; + let mut tmp1: PolyData; + + output.coeffs[0] = b.coeffs[0].inverse(); + let mut d: usize = 0; + let mut mask: usize = 1 << log2(maxd); + + while mask != 0 { + d = 2 * d + usize::from((maxd & mask) != 0); + mask >>= 1; + + let len_temp: usize = min(d + 1, b.coeffs.len() + output.coeffs.len() - 1); + + tmp0 = poly_mul(b, &output, Some(&fs), len_temp).unwrap(); + + for i in 0..len_temp { + tmp0.coeffs[i] = tmp0.coeffs[i].negate(); + } + let fr_two = BlstFr { fr: Fr::from(2) }; + tmp0.coeffs[0] = tmp0.coeffs[0].add(&fr_two); + + let len_temp2: usize = d + 1; + + tmp1 = poly_mul(&output, &tmp0, Some(&fs), len_temp2).unwrap(); + + if tmp1.coeffs.len() > output_len { + tmp1.coeffs = tmp1.coeffs[..output_len].to_vec(); + } + for i in 0..tmp1.coeffs.len() { + output.coeffs[i] = tmp1.coeffs[i]; + } + } + if d + 1 != output_len { + return Err(String::from("d + 1 is not equals to output_len")); + } + Ok(output) +} + +pub fn poly_mul_direct(p1: &PolyData, p2: &PolyData, len: usize) -> Result { + let p1 = blst_poly_into_pc_poly(&p1.coeffs); + let p2 = blst_poly_into_pc_poly(&p2.coeffs); + if p1.is_zero() || p2.is_zero() { + Ok(pc_poly_into_blst_poly(DensePolynomial::zero())) + } else { + let mut result = vec![Fr::zero(); len]; + for (i, self_coeff) in p1.coeffs.iter().enumerate() { + for (j, other_coeff) in p2.coeffs.iter().enumerate() { + if i + j >= len { + break; + } + result[i + j] += &(*self_coeff * other_coeff); + } + } + let p = pc_poly_into_blst_poly(DensePolynomial::from_coefficients_vec(result)); + Ok(PolyData { + coeffs: pad_poly(&p, len).unwrap(), + }) + } +} + +pub fn poly_long_div(p1: &PolyData, p2: &PolyData) -> Result { + Ok(pc_poly_into_blst_poly( + &blst_poly_into_pc_poly(&p1.coeffs) / &blst_poly_into_pc_poly(&p2.coeffs), + )) +} + +pub fn poly_mul( + a: &PolyData, + b: &PolyData, + fs: Option<&FFTSettings>, + len: usize, +) -> Result { + if a.coeffs.len() < 64 || b.coeffs.len() < 64 || len < 128 { + poly_mul_direct(a, b, len) + } else { + poly_mul_fft(a, b, fs, len) + } +} + +pub fn poly_mul_fft( + a: &PolyData, + b: &PolyData, + fs: Option<&FFTSettings>, + len: usize, +) -> Result { + // Truncate a and b so as not to do excess work for the number of coefficients required. + let a_len = min(a.len(), len); + let b_len = min(b.len(), len); + let length = next_pow_of_2(a_len + b_len - 1); + + // If the FFT settings are NULL then make a local set, otherwise use the ones passed in. + let fs_p = if let Some(x) = fs { + x.clone() + } else { + let scale = log2_pow2(length); + FFTSettings::new(scale).unwrap() + }; + + if length > fs_p.max_width { + return Err(String::from( + "length should be equals or less than FFTSettings max width", + )); + } + + let a = PolyData { + coeffs: a.coeffs[..a_len].to_vec(), + }; + let b = PolyData { + coeffs: b.coeffs[..b_len].to_vec(), + }; + let a_pad = PolyData { + coeffs: pad_poly(&a, length).unwrap(), + }; + let b_pad = PolyData { + coeffs: pad_poly(&b, length).unwrap(), + }; + + let a_fft; + let b_fft; + #[cfg(feature = "parallel")] + { + if length > 1024 { + let mut a_fft_temp = vec![]; + let mut b_fft_temp = vec![]; + + rayon::join( + || a_fft_temp = fs_p.fft_fr(&a_pad.coeffs, false).unwrap(), + || b_fft_temp = fs_p.fft_fr(&b_pad.coeffs, false).unwrap(), + ); + + a_fft = a_fft_temp; + b_fft = b_fft_temp; + } else { + a_fft = fs_p.fft_fr(&a_pad.coeffs, false).unwrap(); + b_fft = fs_p.fft_fr(&b_pad.coeffs, false).unwrap(); + } + } + #[cfg(not(feature = "parallel"))] + { + a_fft = fs_p.fft_fr(&a_pad.coeffs, false).unwrap(); + b_fft = fs_p.fft_fr(&b_pad.coeffs, false).unwrap(); + } + let mut ab_fft = a_pad; + let mut ab = b_pad; + + for i in 0..length { + ab_fft.coeffs[i] = a_fft[i].mul(&b_fft[i]); + } + + ab.coeffs = fs_p.fft_fr(&ab_fft.coeffs, true).unwrap(); + + let data_len = min(len, length); + let mut out = PolyData::new(len); + + for i in 0..data_len { + out.coeffs[i] = ab.coeffs[i]; + } + for i in data_len..len { + out.coeffs[i] = BlstFr::zero(); + } + + Ok(out) +} + +pub fn poly_fast_div(dividend: &PolyData, divisor: &PolyData) -> Result { + if divisor.coeffs.is_empty() { + return Err(String::from("divisor coeffs are empty")); + } + + if divisor.coeffs[divisor.coeffs.len() - 1].is_zero() { + return Err(String::from("divisor coeffs last member is zero")); + } + + let m = dividend.coeffs.len() - 1; + let n = divisor.coeffs.len() - 1; + + if n > m { + return Ok(PolyData::new(0)); + } + + if divisor.coeffs[divisor.coeffs.len() - 1].is_zero() { + return Err(String::from("divisor coeffs last member is zero")); + } + + let mut out = PolyData::new(0); + + if divisor.len() == 1 { + for i in 0..dividend.len() { + out.coeffs + .push(dividend.coeffs[i].div(&divisor.coeffs[0]).unwrap()); + } + return Ok(out); + } + + let a_flip = poly_flip(dividend).unwrap(); + let b_flip = poly_flip(divisor).unwrap(); + + let inv_b_flip = poly_inverse(&b_flip, m - n + 1).unwrap(); + let q_flip = poly_mul(&a_flip, &inv_b_flip, None, m - n + 1).unwrap(); + + out = poly_flip(&q_flip).unwrap(); + + Ok(PolyData { + coeffs: out.coeffs[..m - n + 1].to_vec(), + }) +} + +pub fn poly_flip(input: &PolyData) -> Result { + let mut output = PolyData::new(0); + for i in 0..input.len() { + output.coeffs.push(input.coeffs[input.coeffs.len() - i - 1]); + } + Ok(output) +} diff --git a/arkworks5/src/recover.rs b/arkworks5/src/recover.rs new file mode 100644 index 00000000..c57f0c24 --- /dev/null +++ b/arkworks5/src/recover.rs @@ -0,0 +1,234 @@ +use crate::consts::SCALE_FACTOR; +use crate::kzg_proofs::FFTSettings; +use crate::kzg_types::ArkFr as BlstFr; +use crate::utils::PolyData; + +use kzg::{FFTFr, Fr, Poly, PolyRecover, ZeroPoly}; + +#[cfg(feature = "parallel")] +use kzg::common_utils::next_pow_of_2; + +#[cfg(feature = "parallel")] +static mut INVERSE_FACTORS: Vec = Vec::new(); +#[cfg(feature = "parallel")] +static mut UNSCALE_FACTOR_POWERS: Vec = Vec::new(); + +#[allow(clippy::needless_range_loop)] +pub fn scale_poly(p: &mut PolyData) { + let scale_factor = BlstFr::from_u64(SCALE_FACTOR); + let inv_factor = scale_factor.inverse(); + #[cfg(feature = "parallel")] + { + let optim = next_pow_of_2(p.len() - 1); + if optim <= 1024 { + unsafe { + if INVERSE_FACTORS.len() < p.len() { + if INVERSE_FACTORS.is_empty() { + INVERSE_FACTORS.push(BlstFr::one()); + } + for i in (INVERSE_FACTORS.len())..p.len() { + INVERSE_FACTORS.push(INVERSE_FACTORS[i - 1].mul(&inv_factor)); + } + } + + for i in 1..p.len() { + p.coeffs[i] = p.coeffs[i].mul(&INVERSE_FACTORS[i]); + } + } + } else { + let mut factor_power = BlstFr::one(); + for i in 1..p.len() { + factor_power = factor_power.mul(&inv_factor); + p.set_coeff_at(i, &p.get_coeff_at(i).mul(&factor_power)); + } + } + } + #[cfg(not(feature = "parallel"))] + { + let mut factor_power = BlstFr::one(); + for i in 1..p.len() { + factor_power = factor_power.mul(&inv_factor); + p.set_coeff_at(i, &p.get_coeff_at(i).mul(&factor_power)); + } + } +} + +#[allow(clippy::needless_range_loop)] +pub fn unscale_poly(p: &mut PolyData) { + let scale_factor = BlstFr::from_u64(SCALE_FACTOR); + #[cfg(feature = "parallel")] + { + unsafe { + if UNSCALE_FACTOR_POWERS.len() < p.len() { + if UNSCALE_FACTOR_POWERS.is_empty() { + UNSCALE_FACTOR_POWERS.push(BlstFr::one()); + } + for i in (UNSCALE_FACTOR_POWERS.len())..p.len() { + UNSCALE_FACTOR_POWERS.push(UNSCALE_FACTOR_POWERS[i - 1].mul(&scale_factor)); + } + } + + for i in 1..p.len() { + p.coeffs[i] = p.coeffs[i].mul(&UNSCALE_FACTOR_POWERS[i]); + } + } + } + #[cfg(not(feature = "parallel"))] + { + let mut factor_power = BlstFr::one(); + for i in 1..p.len() { + factor_power = factor_power.mul(&scale_factor); + p.set_coeff_at(i, &p.get_coeff_at(i).mul(&factor_power)); + } + } +} +impl PolyRecover for PolyData { + fn recover_poly_coeffs_from_samples( + samples: &[Option], + fs: &FFTSettings, + ) -> Result { + if !samples.len().is_power_of_two() { + return Err(String::from("samples lenght has to be power of 2")); + } + + let mut missing = Vec::new(); + + for (i, sample) in samples.iter().enumerate() { + if sample.is_none() { + missing.push(i); + } + } + + if missing.len() > samples.len() / 2 { + return Err(String::from( + "Impossible to recover, too many shards are missing", + )); + } + + // Calculate `Z_r,I` + let (zero_eval, mut zero_poly) = + fs.zero_poly_via_multiplication(samples.len(), missing.as_slice())?; + + // Check all is well + for (i, item) in zero_eval.iter().enumerate().take(samples.len()) { + if samples[i].is_none() != item.is_zero() { + return Err(String::from("sample and item are both zero")); + } + } + + // Construct E * Z_r,I: the loop makes the evaluation polynomial + + let mut poly_evaluations_with_zero = vec![BlstFr::zero(); samples.len()]; + + for i in 0..samples.len() { + if samples[i].is_none() { + poly_evaluations_with_zero[i] = BlstFr::zero(); + } else { + poly_evaluations_with_zero[i] = samples[i].unwrap().mul(&zero_eval[i]); + } + } + + // Now inverse FFT so that poly_with_zero is (E * Z_r,I)(x) = (D * Z_r,I)(x) + let mut poly_with_zero = PolyData { + coeffs: fs + .fft_fr(poly_evaluations_with_zero.as_slice(), true) + .unwrap(), + }; + + #[cfg(feature = "parallel")] + let optim = next_pow_of_2(poly_with_zero.len() - 1); + + #[cfg(feature = "parallel")] + { + if optim > 1024 { + rayon::join( + || scale_poly(&mut poly_with_zero), + || scale_poly(&mut zero_poly), + ); + } else { + scale_poly(&mut poly_with_zero); + scale_poly(&mut zero_poly); + } + } + #[cfg(not(feature = "parallel"))] + { + scale_poly(&mut poly_with_zero); + scale_poly(&mut zero_poly); + } + + // Q1 = (D * Z_r,I)(k * x) + let scaled_poly_with_zero = poly_with_zero; // Renaming + // Q2 = Z_r,I(k * x) + let scaled_zero_poly = zero_poly.coeffs; // Renaming + + let eval_scaled_poly_with_zero; + let eval_scaled_zero_poly; + + #[cfg(feature = "parallel")] + { + if optim > 1024 { + let mut eval_scaled_poly_with_zero_temp = vec![]; + let mut eval_scaled_zero_poly_temp = vec![]; + rayon::join( + || { + eval_scaled_poly_with_zero_temp = + fs.fft_fr(&scaled_poly_with_zero.coeffs, false).unwrap() + }, + || eval_scaled_zero_poly_temp = fs.fft_fr(&scaled_zero_poly, false).unwrap(), + ); + + eval_scaled_poly_with_zero = eval_scaled_poly_with_zero_temp; + eval_scaled_zero_poly = eval_scaled_zero_poly_temp; + } else { + eval_scaled_poly_with_zero = + fs.fft_fr(&scaled_poly_with_zero.coeffs, false).unwrap(); + eval_scaled_zero_poly = fs.fft_fr(&scaled_zero_poly, false).unwrap(); + } + } + #[cfg(not(feature = "parallel"))] + { + eval_scaled_poly_with_zero = fs.fft_fr(&scaled_poly_with_zero.coeffs, false).unwrap(); + eval_scaled_zero_poly = fs.fft_fr(&scaled_zero_poly, false).unwrap(); + } + + let mut eval_scaled_reconstructed_poly = eval_scaled_poly_with_zero.clone(); + for i in 0..samples.len() { + eval_scaled_reconstructed_poly[i] = eval_scaled_poly_with_zero[i] + .div(&eval_scaled_zero_poly[i]) + .unwrap(); + } + + // The result of the division is D(k * x): + let mut scaled_reconstructed_poly = PolyData { + coeffs: fs.fft_fr(&eval_scaled_reconstructed_poly, true).unwrap(), + }; + + // k * x -> x + unscale_poly(&mut scaled_reconstructed_poly); + + // Finally we have D(x) which evaluates to our original data at the powers of roots of unity + Ok(scaled_reconstructed_poly) + } + + fn recover_poly_from_samples( + samples: &[Option], + fs: &FFTSettings, + ) -> Result { + let reconstructed_poly = Self::recover_poly_coeffs_from_samples(samples, fs)?; + + // The evaluation polynomial for D(x) is the reconstructed data: + let out = PolyData { + coeffs: fs.fft_fr(&reconstructed_poly.coeffs, false).unwrap(), + }; + + // Check all is well + for (i, sample) in samples.iter().enumerate() { + if !sample.is_none() && !out.get_coeff_at(i).equals(&sample.unwrap()) { + return Err(String::from( + "sample is zero and out coeff at i is not equals to sample", + )); + } + } + Ok(out) + } +} diff --git a/arkworks5/src/utils.rs b/arkworks5/src/utils.rs new file mode 100644 index 00000000..46d0389b --- /dev/null +++ b/arkworks5/src/utils.rs @@ -0,0 +1,153 @@ +use crate::kzg_proofs::FFTSettings; +use crate::kzg_types::{ArkFp, ArkFr, ArkG1, ArkG1Affine}; +use ark_bls12_381::{g1, g2, Fq, Fq2, Fr as Bls12Fr}; +use ark_ec::models::short_weierstrass::Projective; +use ark_ff::Fp2; +use ark_poly::univariate::DensePolynomial as DensePoly; +use ark_poly::DenseUVPolynomial; + +use kzg::eip_4844::PrecomputationTableManager; +use kzg::eth::c_bindings::{blst_fp, blst_fp2, blst_fr, blst_p1, blst_p2, CKZGSettings}; + +use kzg::eth; + +#[derive(Debug, PartialEq, Eq)] +pub struct Error; + +#[derive(Debug, Clone, Eq, PartialEq, Default)] +pub struct PolyData { + pub coeffs: Vec, +} +// FIXME: Store just dense poly here + +pub fn pc_poly_into_blst_poly(poly: DensePoly) -> PolyData { + let mut bls_pol: Vec = { Vec::new() }; + for x in poly.coeffs { + bls_pol.push(ArkFr { fr: x }); + } + PolyData { coeffs: bls_pol } +} + +pub fn blst_poly_into_pc_poly(pd: &[ArkFr]) -> DensePoly { + let mut poly: Vec = vec![Bls12Fr::default(); pd.len()]; + for i in 0..pd.len() { + poly[i] = pd[i].fr; + } + DensePoly::from_coefficients_vec(poly) +} + +pub const fn pc_fq_into_blst_fp(fq: Fq) -> blst_fp { + blst_fp { l: fq.0 .0 } +} + +pub const fn blst_fr_into_pc_fr(fr: blst_fr) -> Bls12Fr { + Bls12Fr { + 0: ark_ff::BigInt(fr.l), + 1: core::marker::PhantomData, + } +} + +pub const fn pc_fr_into_blst_fr(fr: Bls12Fr) -> blst_fr { + blst_fr { l: fr.0 .0 } +} + +pub const fn blst_fp_into_pc_fq(fp: &blst_fp) -> Fq { + Fq { + 0: ark_ff::BigInt(fp.l), + 1: core::marker::PhantomData, + } +} + +pub const fn blst_fp2_into_pc_fq2(fp: &blst_fp2) -> Fq2 { + Fp2 { + c0: blst_fp_into_pc_fq(&fp.fp[0]), + c1: blst_fp_into_pc_fq(&fp.fp[1]), + } +} + +pub const fn blst_p1_into_pc_g1projective(p1: &blst_p1) -> Projective { + Projective { + x: blst_fp_into_pc_fq(&p1.x), + y: blst_fp_into_pc_fq(&p1.y), + z: blst_fp_into_pc_fq(&p1.z), + } +} + +pub const fn pc_g1projective_into_blst_p1(p1: Projective) -> blst_p1 { + blst_p1 { + x: blst_fp { l: p1.x.0 .0 }, + y: blst_fp { l: p1.y.0 .0 }, + z: blst_fp { l: p1.z.0 .0 }, + } +} + +pub const fn blst_p2_into_pc_g2projective(p2: &blst_p2) -> Projective { + Projective { + x: blst_fp2_into_pc_fq2(&p2.x), + y: blst_fp2_into_pc_fq2(&p2.y), + z: blst_fp2_into_pc_fq2(&p2.z), + } +} + +pub const fn pc_g2projective_into_blst_p2(p2: Projective) -> blst_p2 { + blst_p2 { + x: blst_fp2 { + fp: [blst_fp { l: p2.x.c0.0 .0 }, blst_fp { l: p2.x.c1.0 .0 }], + }, + y: blst_fp2 { + fp: [blst_fp { l: p2.y.c0.0 .0 }, blst_fp { l: p2.y.c1.0 .0 }], + }, + z: blst_fp2 { + fp: [blst_fp { l: p2.z.c0.0 .0 }, blst_fp { l: p2.z.c1.0 .0 }], + }, + } +} + +pub(crate) fn fft_settings_to_rust(c_settings: *const CKZGSettings) -> Result { + let settings = unsafe { &*c_settings }; + + let roots_of_unity = unsafe { + core::slice::from_raw_parts( + settings.roots_of_unity, + eth::FIELD_ELEMENTS_PER_EXT_BLOB + 1, + ) + .iter() + .map(|r| ArkFr::from_blst_fr(*r)) + .collect::>() + }; + + let brp_roots_of_unity = unsafe { + core::slice::from_raw_parts( + settings.brp_roots_of_unity, + eth::FIELD_ELEMENTS_PER_EXT_BLOB, + ) + .iter() + .map(|r| ArkFr::from_blst_fr(*r)) + .collect::>() + }; + + let reverse_roots_of_unity = unsafe { + core::slice::from_raw_parts( + settings.reverse_roots_of_unity, + eth::FIELD_ELEMENTS_PER_EXT_BLOB + 1, + ) + .iter() + .map(|r| ArkFr::from_blst_fr(*r)) + .collect::>() + }; + + Ok(FFTSettings { + max_width: eth::FIELD_ELEMENTS_PER_EXT_BLOB, + root_of_unity: roots_of_unity[0], + roots_of_unity, + brp_roots_of_unity, + reverse_roots_of_unity, + }) +} + +pub(crate) static mut PRECOMPUTATION_TABLES: PrecomputationTableManager< + ArkFr, + ArkG1, + ArkFp, + ArkG1Affine, +> = PrecomputationTableManager::new(); diff --git a/arkworks5/src/zero_poly.rs b/arkworks5/src/zero_poly.rs new file mode 100644 index 00000000..cb29ab68 --- /dev/null +++ b/arkworks5/src/zero_poly.rs @@ -0,0 +1,196 @@ +use super::kzg_proofs::FFTSettings; +use super::utils::{blst_poly_into_pc_poly, pc_poly_into_blst_poly, PolyData}; +use crate::kzg_types::ArkFr as BlstFr; +use kzg::common_utils::next_pow_of_2; +use kzg::{FFTFr, Fr as FrTrait, ZeroPoly}; +use std::cmp::{min, Ordering}; +use std::ops::Neg; + +pub(crate) fn pad_poly(poly: &PolyData, new_length: usize) -> Result, String> { + if new_length <= poly.coeffs.len() { + return Ok(poly.coeffs.clone()); + } + + let mut out = poly.coeffs.to_vec(); + + for _i in poly.coeffs.len()..new_length { + out.push(BlstFr::zero()) + } + + Ok(out) +} + +impl ZeroPoly for FFTSettings { + fn do_zero_poly_mul_partial( + &self, + indices: &[usize], + stride: usize, + ) -> Result { + if indices.is_empty() { + return Err(String::from("idx array must be non-zero")); + } + let blstpoly = PolyData { + coeffs: vec![BlstFr::one(); indices.len() + 1], + }; + let mut poly = blst_poly_into_pc_poly(&blstpoly.coeffs); + poly.coeffs[0] = (self.roots_of_unity[indices[0] * stride]).fr.neg(); + + for (i, indice) in indices.iter().enumerate().skip(1) { + let neg_di = (self.roots_of_unity[indice * stride]).fr.neg(); + + poly.coeffs[i] = neg_di + poly.coeffs[i - 1]; + + let mut j = i - 1; + while j > 0 { + let temp = poly.coeffs[j] * neg_di; + poly.coeffs[j] = temp + poly.coeffs[j - 1]; + j -= 1; + } + + poly.coeffs[0] *= neg_di; + } + + Ok(pc_poly_into_blst_poly(poly)) + } + + fn reduce_partials(&self, len_out: usize, partials: &[PolyData]) -> Result { + let mut out_degree: usize = 0; + for partial in partials { + out_degree += partial.coeffs.len() - 1; + } + + if out_degree + 1 > len_out { + return Err(String::from("Expected domain size to be a power of 2")); + } + + let mut p_partial = pad_poly(&partials[0], len_out).unwrap(); + let mut mul_eval_ps = self.fft_fr(&p_partial, false).unwrap(); + + for partial in partials.iter().skip(1) { + p_partial = pad_poly(partial, len_out)?; + + let p_eval = self.fft_fr(&p_partial, false).unwrap(); + for j in 0..len_out { + mul_eval_ps[j].fr *= p_eval[j].fr; + } + } + + let coeffs = self.fft_fr(&mul_eval_ps, true)?; + + let out = PolyData { + coeffs: coeffs[..(out_degree + 1)].to_vec(), + }; + + Ok(out) + } + + fn zero_poly_via_multiplication( + &self, + length: usize, + missing_indices: &[usize], + ) -> Result<(Vec, PolyData), String> { + let zero_eval: Vec; + let mut zero_poly: PolyData; + + if missing_indices.is_empty() { + zero_eval = Vec::new(); + zero_poly = PolyData { coeffs: Vec::new() }; + return Ok((zero_eval, zero_poly)); + } + + if missing_indices.len() >= length { + return Err(String::from("Missing idxs greater than domain size")); + } else if length > self.max_width { + return Err(String::from( + "Domain size greater than fft_settings.max_width", + )); + } else if !length.is_power_of_two() { + return Err(String::from("Domain size must be a power of 2")); + } + + let degree_of_partial = 256; + let missing_per_partial = degree_of_partial - 1; + let domain_stride = self.max_width / length; + let mut partial_count = + (missing_per_partial + missing_indices.len() - 1) / missing_per_partial; + let domain_ceiling = min(next_pow_of_2(partial_count * degree_of_partial), length); + + if missing_indices.len() <= missing_per_partial { + zero_poly = self.do_zero_poly_mul_partial(missing_indices, domain_stride)?; + } else { + let mut work = vec![BlstFr::zero(); next_pow_of_2(partial_count * degree_of_partial)]; + + let mut partial_lens = Vec::new(); + + let mut offset = 0; + let mut out_offset = 0; + let max = missing_indices.len(); + + for _i in 0..partial_count { + let end = min(offset + missing_per_partial, max); + + let mut partial = + self.do_zero_poly_mul_partial(&missing_indices[offset..end], domain_stride)?; + partial.coeffs = pad_poly(&partial, degree_of_partial)?; + work.splice( + out_offset..(out_offset + degree_of_partial), + partial.coeffs.to_vec(), + ); + partial_lens.push(degree_of_partial); + + offset += missing_per_partial; + out_offset += degree_of_partial; + } + + partial_lens[partial_count - 1] = + 1 + missing_indices.len() - (partial_count - 1) * missing_per_partial; + + let reduction_factor = 4; + while partial_count > 1 { + let reduced_count = 1 + (partial_count - 1) / reduction_factor; + let partial_size = next_pow_of_2(partial_lens[0]); + + for i in 0..reduced_count { + let start = i * reduction_factor; + let out_end = min((start + reduction_factor) * partial_size, domain_ceiling); + let reduced_len = min(out_end - start * partial_size, length); + let partials_num = min(reduction_factor, partial_count - start); + + let mut partial_vec = Vec::new(); + for j in 0..partials_num { + let k = (start + j) * partial_size; + partial_vec.push(PolyData { + coeffs: work[k..(k + partial_lens[i + j])].to_vec(), + }); + } + + if partials_num > 1 { + let mut reduced_poly = self.reduce_partials(reduced_len, &partial_vec)?; + partial_lens[i] = reduced_poly.coeffs.len(); + reduced_poly.coeffs = pad_poly(&reduced_poly, partial_size * partials_num)?; + work.splice( + (start * partial_size) + ..(start * partial_size + reduced_poly.coeffs.len()), + reduced_poly.coeffs, + ); + } else { + partial_lens[i] = partial_lens[start]; + } + } + + partial_count = reduced_count; + } + + zero_poly = PolyData { coeffs: work }; + } + + match zero_poly.coeffs.len().cmp(&length) { + Ordering::Less => zero_poly.coeffs = pad_poly(&zero_poly, length)?, + Ordering::Greater => zero_poly.coeffs = zero_poly.coeffs[..length].to_vec(), + Ordering::Equal => {} + } + + zero_eval = self.fft_fr(&zero_poly.coeffs, false)?; + Ok((zero_eval, zero_poly)) + } +} diff --git a/arkworks5/tests/batch_adder.rs b/arkworks5/tests/batch_adder.rs new file mode 100644 index 00000000..ad16f8dd --- /dev/null +++ b/arkworks5/tests/batch_adder.rs @@ -0,0 +1,70 @@ +#[cfg(test)] +mod tests { + use kzg_bench::tests::msm::batch_adder::{ + test_batch_add, test_batch_add_indexed, test_batch_add_indexed_single_bucket, + test_batch_add_step_n, test_phase_one_p_add_p, test_phase_one_p_add_q, + test_phase_one_p_add_q_twice, test_phase_one_zero_or_neg, test_phase_two_p_add_neg, + test_phase_two_p_add_p, test_phase_two_p_add_q, test_phase_two_zero_add_p, + }; + use rust_kzg_arkworks5::kzg_types::{ArkFp, ArkG1, ArkG1Affine}; + + #[test] + fn test_phase_one_zero_or_neg_() { + test_phase_one_zero_or_neg::(); + } + + #[test] + fn test_phase_one_p_add_p_() { + test_phase_one_p_add_p::(); + } + + #[test] + fn test_phase_one_p_add_q_() { + test_phase_one_p_add_q::(); + } + + #[test] + fn test_phase_one_p_add_q_twice_() { + test_phase_one_p_add_q_twice::(); + } + + #[test] + fn test_phase_two_zero_add_p_() { + test_phase_two_zero_add_p::(); + } + + #[test] + fn test_phase_two_p_add_neg_() { + test_phase_two_p_add_neg::(); + } + + #[test] + fn test_phase_two_p_add_q_() { + test_phase_two_p_add_q::(); + } + + #[test] + pub fn test_phase_two_p_add_p_() { + test_phase_two_p_add_p::(); + } + + #[test] + fn test_batch_add_() { + test_batch_add::(); + } + + #[test] + fn test_batch_add_step_n_() { + test_batch_add_step_n::(); + } + + #[test] + fn test_batch_add_indexed_() { + test_batch_add_indexed::(); + } + + #[test] + fn test_batch_add_indexed_single_bucket_() { + test_batch_add_indexed_single_bucket::(); + } +} diff --git a/arkworks5/tests/bls12_381.rs b/arkworks5/tests/bls12_381.rs new file mode 100644 index 00000000..5225a30e --- /dev/null +++ b/arkworks5/tests/bls12_381.rs @@ -0,0 +1,114 @@ +#[cfg(test)] +mod tests { + use kzg::common_utils::log_2_byte; + use kzg_bench::tests::bls12_381::*; + use rust_kzg_arkworks5::fft_g1::g1_linear_combination; + use rust_kzg_arkworks5::kzg_proofs::pairings_verify; + use rust_kzg_arkworks5::kzg_types::{ArkFp, ArkFr, ArkG1, ArkG1Affine, ArkG2}; + + #[test] + pub fn log_2_byte_works_() { + log_2_byte_works(&log_2_byte); + } + + #[test] + pub fn fr_is_zero_works_() { + fr_is_zero_works::(); + } + + #[test] + pub fn fr_is_one_works_() { + fr_is_one_works::(); + } + + #[test] + pub fn fr_from_uint64_works_() { + fr_from_uint64_works::(); + } + + #[test] + pub fn fr_equal_works_() { + fr_equal_works::(); + } + + #[test] + pub fn fr_negate_works_() { + fr_negate_works::(); + } + + #[test] + pub fn fr_pow_works_() { + fr_pow_works::(); + } + + #[test] + pub fn fr_div_works_() { + fr_div_works::(); + } + + #[test] + #[should_panic] + pub fn fr_div_by_zero_() { + fr_div_by_zero::(); + } + + #[test] + pub fn fr_uint64s_roundtrip_() { + fr_uint64s_roundtrip::(); + } + + #[test] + pub fn p1_mul_works_() { + p1_mul_works::(); + } + + #[test] + pub fn p1_sub_works_() { + p1_sub_works::(); + } + + #[test] + pub fn p2_add_or_dbl_works_() { + p2_add_or_dbl_works::(); + } + + #[test] + pub fn p2_mul_works_() { + p2_mul_works::(); + } + + #[test] + pub fn p2_sub_works_() { + p2_sub_works::(); + } + + #[test] + pub fn g1_identity_is_infinity_() { + g1_identity_is_infinity::(); + } + + #[test] + pub fn g1_identity_is_identity_() { + g1_identity_is_identity::(); + } + + #[test] + pub fn g1_make_linear_combination_() { + g1_make_linear_combination::(&g1_linear_combination); + } + + #[test] + pub fn g1_random_linear_combination_() { + g1_random_linear_combination::(&g1_linear_combination); + } + + #[test] + pub fn pairings_work_() { + pairings_work::(&pairings_verify); + } + + #[test] + pub fn fr_is_null_works_() { + fr_is_null_works::(); + } +} diff --git a/arkworks5/tests/bucket_msm.rs b/arkworks5/tests/bucket_msm.rs new file mode 100644 index 00000000..ba625425 --- /dev/null +++ b/arkworks5/tests/bucket_msm.rs @@ -0,0 +1,28 @@ +#[cfg(test)] +mod tests { + use kzg_bench::tests::msm::bucket_msm::{ + test_process_point_and_slices_deal_three_points, + test_process_point_and_slices_glv_deal_two_points, + }; + use rust_kzg_arkworks5::kzg_types::{ArkFp, ArkG1, ArkG1Affine, ArkG1ProjAddAffine}; + + #[test] + pub fn test_process_point_and_slices_deal_three_points_() { + test_process_point_and_slices_deal_three_points::< + ArkG1, + ArkFp, + ArkG1Affine, + ArkG1ProjAddAffine, + >(); + } + + #[test] + fn test_process_point_and_slices_glv_deal_two_points_() { + test_process_point_and_slices_glv_deal_two_points::< + ArkG1, + ArkFp, + ArkG1Affine, + ArkG1ProjAddAffine, + >(); + } +} diff --git a/arkworks5/tests/consts.rs b/arkworks5/tests/consts.rs new file mode 100644 index 00000000..f11f02e4 --- /dev/null +++ b/arkworks5/tests/consts.rs @@ -0,0 +1,36 @@ +#[cfg(test)] +mod tests { + use kzg_bench::tests::consts::{ + expand_roots_is_plausible, new_fft_settings_is_plausible, roots_of_unity_are_plausible, + roots_of_unity_is_the_expected_size, roots_of_unity_out_of_bounds_fails, + }; + use rust_kzg_arkworks5::consts::SCALE2_ROOT_OF_UNITY; + use rust_kzg_arkworks5::kzg_proofs::expand_root_of_unity; + use rust_kzg_arkworks5::kzg_proofs::FFTSettings; + use rust_kzg_arkworks5::kzg_types::ArkFr; + + #[test] + fn roots_of_unity_out_of_bounds_fails_() { + roots_of_unity_out_of_bounds_fails::(); + } + + #[test] + fn roots_of_unity_are_plausible_() { + roots_of_unity_are_plausible::(&SCALE2_ROOT_OF_UNITY); + } + + #[test] + fn expand_roots_is_plausible_() { + expand_roots_is_plausible::(&SCALE2_ROOT_OF_UNITY, &expand_root_of_unity); + } + + #[test] + fn new_fft_settings_is_plausible_() { + new_fft_settings_is_plausible::(); + } + + #[test] + fn roots_of_unity_is_the_expected_size_() { + roots_of_unity_is_the_expected_size(&SCALE2_ROOT_OF_UNITY); + } +} diff --git a/arkworks5/tests/das.rs b/arkworks5/tests/das.rs new file mode 100644 index 00000000..34e37de7 --- /dev/null +++ b/arkworks5/tests/das.rs @@ -0,0 +1,16 @@ +#[cfg(test)] +mod tests { + use kzg_bench::tests::das::{das_extension_test_known, das_extension_test_random}; + use rust_kzg_arkworks5::kzg_proofs::FFTSettings; + use rust_kzg_arkworks5::kzg_types::ArkFr; + + #[test] + fn das_extension_test_known_() { + das_extension_test_known::(); + } + + #[test] + fn das_extension_test_random_() { + das_extension_test_random::(); + } +} diff --git a/arkworks5/tests/eip_4844.rs b/arkworks5/tests/eip_4844.rs new file mode 100644 index 00000000..c0564faa --- /dev/null +++ b/arkworks5/tests/eip_4844.rs @@ -0,0 +1,336 @@ +#[cfg(test)] +mod tests { + use kzg::eip_4844::{ + blob_to_kzg_commitment_rust, blob_to_polynomial, bytes_to_blob, + compute_blob_kzg_proof_rust, compute_kzg_proof_rust, compute_powers, + evaluate_polynomial_in_evaluation_form, verify_blob_kzg_proof_batch_rust, + verify_blob_kzg_proof_rust, verify_kzg_proof_rust, + }; + use kzg::Fr; + use kzg_bench::tests::eip_4844::{ + blob_to_kzg_commitment_test, bytes_to_bls_field_test, + compute_and_verify_blob_kzg_proof_fails_with_incorrect_proof_test, + compute_and_verify_blob_kzg_proof_test, + compute_and_verify_kzg_proof_fails_with_incorrect_proof_test, + compute_and_verify_kzg_proof_round_trip_test, + compute_and_verify_kzg_proof_within_domain_test, compute_kzg_proof_test, + compute_powers_test, test_vectors_blob_to_kzg_commitment, + test_vectors_compute_blob_kzg_proof, test_vectors_compute_kzg_proof, + test_vectors_verify_blob_kzg_proof, test_vectors_verify_blob_kzg_proof_batch, + test_vectors_verify_kzg_proof, verify_kzg_proof_batch_fails_with_incorrect_proof_test, + verify_kzg_proof_batch_test, + }; + use rust_kzg_arkworks5::consts::SCALE2_ROOT_OF_UNITY; + use rust_kzg_arkworks5::eip_4844::load_trusted_setup_filename_rust; + use rust_kzg_arkworks5::kzg_proofs::{expand_root_of_unity, FFTSettings, KZGSettings}; + use rust_kzg_arkworks5::kzg_types::{ArkFp, ArkFr, ArkG1, ArkG1Affine, ArkG2}; + use rust_kzg_arkworks5::utils::PolyData; + + #[test] + pub fn bytes_to_bls_field_test_() { + bytes_to_bls_field_test::(); + } + + #[test] + pub fn compute_powers_test_() { + compute_powers_test::(&compute_powers); + } + + #[test] + pub fn blob_to_kzg_commitment_test_() { + blob_to_kzg_commitment_test::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &blob_to_kzg_commitment_rust, + ); + } + + #[test] + pub fn compute_kzg_proof_test_() { + compute_kzg_proof_test::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &compute_kzg_proof_rust, + &blob_to_polynomial, + &evaluate_polynomial_in_evaluation_form, + ); + } + + #[test] + pub fn compute_and_verify_kzg_proof_round_trip_test_() { + compute_and_verify_kzg_proof_round_trip_test::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &blob_to_kzg_commitment_rust, + &bytes_to_blob, + &compute_kzg_proof_rust, + &blob_to_polynomial, + &evaluate_polynomial_in_evaluation_form, + &verify_kzg_proof_rust, + ); + } + + #[test] + pub fn compute_and_verify_kzg_proof_within_domain_test_() { + compute_and_verify_kzg_proof_within_domain_test::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &blob_to_kzg_commitment_rust, + &bytes_to_blob, + &compute_kzg_proof_rust, + &blob_to_polynomial, + &evaluate_polynomial_in_evaluation_form, + &verify_kzg_proof_rust, + ); + } + + #[test] + pub fn compute_and_verify_kzg_proof_fails_with_incorrect_proof_test_() { + compute_and_verify_kzg_proof_fails_with_incorrect_proof_test::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &blob_to_kzg_commitment_rust, + &bytes_to_blob, + &compute_kzg_proof_rust, + &blob_to_polynomial, + &evaluate_polynomial_in_evaluation_form, + &verify_kzg_proof_rust, + ); + } + + #[test] + pub fn compute_and_verify_blob_kzg_proof_test_() { + compute_and_verify_blob_kzg_proof_test::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &blob_to_kzg_commitment_rust, + &bytes_to_blob, + &compute_blob_kzg_proof_rust, + &verify_blob_kzg_proof_rust, + ); + } + + #[test] + pub fn compute_and_verify_blob_kzg_proof_fails_with_incorrect_proof_test_() { + compute_and_verify_blob_kzg_proof_fails_with_incorrect_proof_test::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &blob_to_kzg_commitment_rust, + &bytes_to_blob, + &compute_blob_kzg_proof_rust, + &verify_blob_kzg_proof_rust, + ); + } + + #[test] + pub fn verify_kzg_proof_batch_test_() { + verify_kzg_proof_batch_test::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &blob_to_kzg_commitment_rust, + &bytes_to_blob, + &compute_blob_kzg_proof_rust, + &verify_blob_kzg_proof_batch_rust, + ); + } + + #[test] + pub fn verify_kzg_proof_batch_fails_with_incorrect_proof_test_() { + verify_kzg_proof_batch_fails_with_incorrect_proof_test::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &blob_to_kzg_commitment_rust, + &bytes_to_blob, + &compute_blob_kzg_proof_rust, + &verify_blob_kzg_proof_batch_rust, + ); + } + + #[test] + pub fn test_vectors_blob_to_kzg_commitment_() { + test_vectors_blob_to_kzg_commitment::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &blob_to_kzg_commitment_rust, + &bytes_to_blob, + ); + } + + #[test] + pub fn test_vectors_compute_kzg_proof_() { + test_vectors_compute_kzg_proof::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &compute_kzg_proof_rust, + &bytes_to_blob, + ); + } + + #[test] + pub fn test_vectors_compute_blob_kzg_proof_() { + test_vectors_compute_blob_kzg_proof::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &bytes_to_blob, + &compute_blob_kzg_proof_rust, + ); + } + + #[test] + pub fn test_vectors_verify_kzg_proof_() { + test_vectors_verify_kzg_proof::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >(&load_trusted_setup_filename_rust, &verify_kzg_proof_rust); + } + + #[test] + pub fn test_vectors_verify_blob_kzg_proof_() { + test_vectors_verify_blob_kzg_proof::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &bytes_to_blob, + &verify_blob_kzg_proof_rust, + ); + } + + #[test] + pub fn test_vectors_verify_blob_kzg_proof_batch_() { + test_vectors_verify_blob_kzg_proof_batch::< + ArkFr, + ArkG1, + ArkG2, + PolyData, + FFTSettings, + KZGSettings, + ArkFp, + ArkG1Affine, + >( + &load_trusted_setup_filename_rust, + &bytes_to_blob, + &verify_blob_kzg_proof_batch_rust, + ); + } + + #[test] + pub fn expand_root_of_unity_too_long() { + let out = expand_root_of_unity(&ArkFr::from_u64_arr(&SCALE2_ROOT_OF_UNITY[1]), 1); + assert!(out.is_err()); + } + + #[test] + pub fn expand_root_of_unity_too_short() { + let out = expand_root_of_unity(&ArkFr::from_u64_arr(&SCALE2_ROOT_OF_UNITY[1]), 3); + assert!(out.is_err()); + } +} diff --git a/arkworks5/tests/eip_7594.rs b/arkworks5/tests/eip_7594.rs new file mode 100644 index 00000000..c387c283 --- /dev/null +++ b/arkworks5/tests/eip_7594.rs @@ -0,0 +1,28 @@ +#[cfg(test)] +mod tests { + use kzg::eip_4844::bytes_to_blob; + use kzg_bench::tests::eip_7594::{ + test_vectors_compute_cells_and_kzg_proofs, test_vectors_recover_cells_and_kzg_proofs, + test_vectors_verify_cell_kzg_proof_batch, + }; + use rust_kzg_arkworks5::eip_4844::load_trusted_setup_filename_rust; + use rust_kzg_arkworks5::eip_7594::ArkBackend; + + #[test] + pub fn test_vectors_compute_cells_and_kzg_proofs_() { + test_vectors_compute_cells_and_kzg_proofs::( + &load_trusted_setup_filename_rust, + &bytes_to_blob, + ); + } + + #[test] + pub fn test_vectors_recover_cells_and_kzg_proofs_() { + test_vectors_recover_cells_and_kzg_proofs::(&load_trusted_setup_filename_rust); + } + + #[test] + pub fn test_vectors_verify_cell_kzg_proof_batch_() { + test_vectors_verify_cell_kzg_proof_batch::(&load_trusted_setup_filename_rust); + } +} diff --git a/arkworks5/tests/fft_fr.rs b/arkworks5/tests/fft_fr.rs new file mode 100644 index 00000000..4e2bb425 --- /dev/null +++ b/arkworks5/tests/fft_fr.rs @@ -0,0 +1,29 @@ +mod batch_adder; + +#[cfg(test)] +mod tests { + use kzg_bench::tests::fft_fr::{compare_sft_fft, inverse_fft, roundtrip_fft, stride_fft}; + use rust_kzg_arkworks5::fft::{fft_fr_fast, fft_fr_slow}; + use rust_kzg_arkworks5::kzg_proofs::FFTSettings; + use rust_kzg_arkworks5::kzg_types::ArkFr; + + #[test] + fn compare_sft_fft_() { + compare_sft_fft::(&fft_fr_slow, &fft_fr_fast); + } + + #[test] + fn roundtrip_fft_() { + roundtrip_fft::(); + } + + #[test] + fn inverse_fft_() { + inverse_fft::(); + } + + #[test] + fn stride_fft_() { + stride_fft::(); + } +} diff --git a/arkworks5/tests/fft_g1.rs b/arkworks5/tests/fft_g1.rs new file mode 100644 index 00000000..18a1b883 --- /dev/null +++ b/arkworks5/tests/fft_g1.rs @@ -0,0 +1,22 @@ +#[cfg(test)] +mod tests { + use kzg_bench::tests::fft_g1::{compare_ft_fft, roundtrip_fft, stride_fft}; + use rust_kzg_arkworks5::fft_g1::{fft_g1_fast, fft_g1_slow, make_data}; + use rust_kzg_arkworks5::kzg_proofs::FFTSettings; + use rust_kzg_arkworks5::kzg_types::{ArkFr, ArkG1}; + + #[test] + fn roundtrip_fft_() { + roundtrip_fft::(&make_data); + } + + #[test] + fn stride_fft_() { + stride_fft::(&make_data); + } + + #[test] + fn compare_sft_fft_() { + compare_ft_fft::(&fft_g1_slow, &fft_g1_fast, &make_data); + } +} diff --git a/arkworks5/tests/fk20_proofs.rs b/arkworks5/tests/fk20_proofs.rs new file mode 100644 index 00000000..393d41a6 --- /dev/null +++ b/arkworks5/tests/fk20_proofs.rs @@ -0,0 +1,38 @@ +#[cfg(test)] +mod tests { + use kzg_bench::tests::fk20_proofs::*; + + use rust_kzg_arkworks5::eip_7594::ArkBackend; + use rust_kzg_arkworks5::fk20_proofs::{KzgFK20MultiSettings, KzgFK20SingleSettings}; + use rust_kzg_arkworks5::kzg_proofs::generate_trusted_setup; + + #[test] + fn test_fk_single() { + fk_single::(&generate_trusted_setup); + } + + #[test] + fn test_fk_single_strided() { + fk_single_strided::(&generate_trusted_setup); + } + + #[test] + fn test_fk_multi_settings() { + fk_multi_settings::(&generate_trusted_setup); + } + + #[test] + fn test_fk_multi_chunk_len_1_512() { + fk_multi_chunk_len_1_512::(&generate_trusted_setup); + } + + #[test] + fn test_fk_multi_chunk_len_16_512() { + fk_multi_chunk_len_16_512::(&generate_trusted_setup); + } + + #[test] + fn test_fk_multi_chunk_len_16_16() { + fk_multi_chunk_len_16_16::(&generate_trusted_setup); + } +} diff --git a/arkworks5/tests/kzg_proofs.rs b/arkworks5/tests/kzg_proofs.rs new file mode 100644 index 00000000..67e2821e --- /dev/null +++ b/arkworks5/tests/kzg_proofs.rs @@ -0,0 +1,28 @@ +#[cfg(test)] +mod tests { + use kzg_bench::tests::kzg_proofs::{ + commit_to_nil_poly, commit_to_too_long_poly_returns_err, proof_multi, proof_single, + }; + use rust_kzg_arkworks5::eip_7594::ArkBackend; + use rust_kzg_arkworks5::kzg_proofs::generate_trusted_setup; + + #[test] + fn proof_single_() { + proof_single::(&generate_trusted_setup); + } + + #[test] + fn commit_to_nil_poly_() { + commit_to_nil_poly::(&generate_trusted_setup); + } + + #[test] + fn commit_to_too_long_poly_() { + commit_to_too_long_poly_returns_err::(&generate_trusted_setup); + } + + #[test] + fn proof_multi_() { + proof_multi::(&generate_trusted_setup); + } +} diff --git a/arkworks5/tests/msm.rs b/arkworks5/tests/msm.rs new file mode 100644 index 00000000..40a8e5ea --- /dev/null +++ b/arkworks5/tests/msm.rs @@ -0,0 +1,27 @@ +#[cfg(test)] +mod tests { + use kzg_bench::tests::msm::msm_slice::{ + test_msm_slice_window_size_1, test_msm_slice_window_size_16, test_msm_slice_window_size_2, + test_msm_slice_window_size_3, + }; + + #[test] + pub fn test_msm_slice_window_size_1_() { + test_msm_slice_window_size_1() + } + + #[test] + fn test_msm_slice_window_size_2_() { + test_msm_slice_window_size_2(); + } + + #[test] + fn test_msm_slice_window_size_3_() { + test_msm_slice_window_size_3(); + } + + #[test] + fn test_msm_slice_window_size_16_() { + test_msm_slice_window_size_16(); + } +} diff --git a/arkworks5/tests/poly.rs b/arkworks5/tests/poly.rs new file mode 100644 index 00000000..f92ee2fd --- /dev/null +++ b/arkworks5/tests/poly.rs @@ -0,0 +1,83 @@ +#[cfg(test)] +mod tests { + use kzg_bench::tests::poly::{ + create_poly_of_length_ten, poly_div_by_zero, poly_div_fast_test, poly_div_long_test, + poly_div_random, poly_eval_0_check, poly_eval_check, poly_eval_nil_check, + poly_inverse_simple_0, poly_inverse_simple_1, poly_mul_direct_test, poly_mul_fft_test, + poly_mul_random, poly_test_div, + }; + use rust_kzg_arkworks5::kzg_proofs::FFTSettings; + use rust_kzg_arkworks5::kzg_types::ArkFr; + use rust_kzg_arkworks5::utils::PolyData; + + #[test] + fn create_poly_of_length_ten_() { + create_poly_of_length_ten::(); + } + + #[test] + fn poly_eval_check_() { + poly_eval_check::(); + } + + #[test] + fn poly_eval_0_check_() { + poly_eval_0_check::(); + } + + #[test] + fn poly_eval_nil_check_() { + poly_eval_nil_check::(); + } + + #[test] + fn poly_inverse_simple_0_() { + poly_inverse_simple_0::(); + } + + #[test] + fn poly_inverse_simple_1_() { + poly_inverse_simple_1::(); + } + + #[test] + fn poly_test_div_() { + poly_test_div::(); + } + + #[test] + #[should_panic] + fn poly_div_by_zero_() { + poly_div_by_zero::(); + } + + #[test] + fn poly_mul_direct_test_() { + poly_mul_direct_test::(); + } + + #[test] + fn poly_mul_fft_test_() { + poly_mul_fft_test::(); + } + + #[test] + fn poly_mul_random_() { + poly_mul_random::(); + } + + #[test] + fn poly_div_random_() { + poly_div_random::(); + } + + #[test] + fn poly_div_long_test_() { + poly_div_long_test::() + } + + #[test] + fn poly_div_fast_test_() { + poly_div_fast_test::() + } +} diff --git a/arkworks5/tests/recover.rs b/arkworks5/tests/recover.rs new file mode 100644 index 00000000..cd6a88f0 --- /dev/null +++ b/arkworks5/tests/recover.rs @@ -0,0 +1,23 @@ +#[cfg(test)] +mod recover_tests { + use kzg_bench::tests::recover::*; + use rust_kzg_arkworks5::kzg_proofs::FFTSettings; + use rust_kzg_arkworks5::kzg_types::ArkFr as Fr; + use rust_kzg_arkworks5::utils::PolyData; + + #[test] + fn recover_simple_() { + recover_simple::(); + } + + //Could be not working because of zero poly. + #[test] + fn recover_random_() { + recover_random::(); + } + + #[test] + fn more_than_half_missing_() { + more_than_half_missing::(); + } +} diff --git a/arkworks5/tests/zero_poly.rs b/arkworks5/tests/zero_poly.rs new file mode 100644 index 00000000..0b247d89 --- /dev/null +++ b/arkworks5/tests/zero_poly.rs @@ -0,0 +1,45 @@ +#[cfg(test)] +mod tests { + use kzg_bench::tests::zero_poly::{ + check_test_data, reduce_partials_random, test_reduce_partials, zero_poly_252, + zero_poly_all_but_one, zero_poly_known, zero_poly_random, + }; + use rust_kzg_arkworks5::kzg_proofs::FFTSettings; + use rust_kzg_arkworks5::kzg_types::ArkFr; + use rust_kzg_arkworks5::utils::PolyData; + + #[test] + fn test_reduce_partials_() { + test_reduce_partials::(); + } + + #[test] + fn reduce_partials_random_() { + reduce_partials_random::(); + } + + #[test] + fn check_test_data_() { + check_test_data::(); + } + + #[test] + fn zero_poly_known_() { + zero_poly_known::(); + } + + #[test] + fn zero_poly_random_() { + zero_poly_random::(); + } + + #[test] + fn zero_poly_all_but_one_() { + zero_poly_all_but_one::(); + } + + #[test] + fn zero_poly_252_() { + zero_poly_252::(); + } +} diff --git a/readme.md b/readme.md index eb2e040d..aefd5ff4 100644 --- a/readme.md +++ b/readme.md @@ -11,6 +11,7 @@ Support for multiple backend ECC libraries is implemented via [Traits](https://g | [blst](https://github.com/supranational/blst) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: via [sppark](https://github.com/supranational/sppark) | | [constantine](https://github.com/mratsim/constantine) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | | [mcl](https://github.com/herumi/mcl) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | +| [arkworks5](https://github.com/arkworks-rs/algebra/tree/v0.5.0) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | | [arkworks4](https://github.com/arkworks-rs/algebra/tree/v0.4.2) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | | [arkworks3](https://github.com/arkworks-rs/algebra/tree/v0.3.0) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: via [sppark](https://github.com/supranational/sppark) and [wlc_msm](https://github.com/dunkirkturbo/wlc_msm/tree/master) | | [zkcrypto](https://github.com/zkcrypto/bls12_381) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | diff --git a/run-benchmarks.sh b/run-benchmarks.sh index 5a7f9335..66b834b3 100644 --- a/run-benchmarks.sh +++ b/run-benchmarks.sh @@ -187,13 +187,30 @@ do print_msg "rust-kzg with constantine backend (parallel, constantine_msm)" ../"$paste_file" taskset --cpu-list "${taskset_cpu_list[$i]}" cargo bench --manifest-path constantine/Cargo.toml --no-default-features --features std,rand,parallel,constantine_msm >> ../"$paste_file" - # 3.15. rust binding (rust-kzg with blst backend) + # 3.15. rust-kzg with arkworks4 backend (sequential) + print_msg "rust-kzg with arkworks4 backend (sequential)" ../"$paste_file" + taskset --cpu-list "${taskset_cpu_list[$i]}" cargo bench --manifest-path arkworks4/Cargo.toml --no-default-features --features std,rand >> ../"$paste_file" + + print_msg "rust-kzg with arkworks4 backend (sequential, arkmsm)" ../"$paste_file" + taskset --cpu-list "${taskset_cpu_list[$i]}" cargo bench --manifest-path arkworks4/Cargo.toml --no-default-features --features std,rand,arkmsm >> ../"$paste_file" + + print_msg "rust-kzg with arkworks4 backend (sequential, bgmw)" ../"$paste_file" + taskset --cpu-list "${taskset_cpu_list[$i]}" cargo bench --manifest-path arkworks4/Cargo.toml --no-default-features --features std,rand,bgmw >> ../"$paste_file" + + # 3.16. rust-kzg with arkworks5 backend (parallel) + print_msg "rust-kzg with arkworks5 backend (parallel)" ../"$paste_file" + taskset --cpu-list "${taskset_cpu_list[$i]}" cargo bench --manifest-path arkworks5/Cargo.toml --no-default-features --features std,rand,parallel >> ../"$paste_file" + + print_msg "rust-kzg with arkworks5 backend (parallel, bgmw)" ../"$paste_file" + taskset --cpu-list "${taskset_cpu_list[$i]}" cargo bench --manifest-path arkworks5/Cargo.toml --no-default-features --features std,rand,parallel,bgmw >> ../"$paste_file" + + # 3.17. rust binding (rust-kzg with blst backend) print_msg "rust binding (rust-kzg with blst backend)" ../"$paste_file" cd blst/c-kzg-4844/bindings/rust/ || exit taskset --cpu-list "${taskset_cpu_list[$i]}" cargo bench >> ../../../../../"$paste_file" cd ../../../.. - # 3.16. go binding (rust-kzg with blst backend) + # 3.18. go binding (rust-kzg with blst backend) print_msg "go binding (rust-kzg with blst backend)" ../"$paste_file" cd blst/c-kzg-4844/bindings/go/ || exit export CGO_CFLAGS="-O2 -D__BLST_PORTABLE__" diff --git a/run-c-kzg-4844-benches.sh b/run-c-kzg-4844-benches.sh index b84f6d9a..04b0c10c 100755 --- a/run-c-kzg-4844-benches.sh +++ b/run-c-kzg-4844-benches.sh @@ -16,7 +16,7 @@ while [[ -n $# ]]; do -p|--parallel) parallel=true ;; - blst|arkworks4|arkworks3|mcl|zkcrypto|constantine) + blst|arkworks5|arkworks4|arkworks3|mcl|zkcrypto|constantine) backend="$1" ;; *) diff --git a/run-c-kzg-4844-fuzz.sh b/run-c-kzg-4844-fuzz.sh index 0fad96de..b69cc986 100644 --- a/run-c-kzg-4844-fuzz.sh +++ b/run-c-kzg-4844-fuzz.sh @@ -27,7 +27,7 @@ while [[ -n $# ]]; do --bgmw) use_bgmw=true ;; - blst|arkworks4|arkworks3|mcl|zkcrypto|constantine) + blst|arkworks5|arkworks4|arkworks3|mcl|zkcrypto|constantine) backend="$1" ;; *) diff --git a/run-c-kzg-4844-tests.sh b/run-c-kzg-4844-tests.sh index 4ac07fcd..4b75a558 100755 --- a/run-c-kzg-4844-tests.sh +++ b/run-c-kzg-4844-tests.sh @@ -16,7 +16,7 @@ while [[ -n $# ]]; do -p|--parallel) parallel=true ;; - blst|arkworks4|arkworks3|mcl|zkcrypto|constantine) + blst|arkworks5|arkworks4|arkworks3|mcl|zkcrypto|constantine) backend="$1" ;; *)