From c813260257d5fc2a0201a72b6b9706bba71ec8b2 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:14:16 -0300 Subject: [PATCH 01/18] chore: update Rust toolchain to 1.91 --- .../benches-mina-prover-set-baseline.yml | 2 +- .github/workflows/benches-mina-prover.yml | 2 +- .github/workflows/benches.yml | 2 +- .github/workflows/ci-nightly.yml | 2 +- .github/workflows/ci.yml | 25 +++---------------- .github/workflows/o1vm-ci.yml | 2 +- .github/workflows/test-export-vectors.yml | 2 +- rust-toolchain.toml | 2 +- 8 files changed, 11 insertions(+), 28 deletions(-) diff --git a/.github/workflows/benches-mina-prover-set-baseline.yml b/.github/workflows/benches-mina-prover-set-baseline.yml index 379574219f7..02d72226dea 100644 --- a/.github/workflows/benches-mina-prover-set-baseline.yml +++ b/.github/workflows/benches-mina-prover-set-baseline.yml @@ -13,7 +13,7 @@ on: env: OCAML_VERSION: "4.14.2" - RUST_TOOLCHAIN_VERSION: "1.81" + RUST_TOOLCHAIN_VERSION: "1.91" jobs: diff --git a/.github/workflows/benches-mina-prover.yml b/.github/workflows/benches-mina-prover.yml index ba683cffe42..fb27bb605ce 100644 --- a/.github/workflows/benches-mina-prover.yml +++ b/.github/workflows/benches-mina-prover.yml @@ -5,7 +5,7 @@ on: env: OCAML_VERSION: "4.14.2" - RUST_TOOLCHAIN_VERSION: "1.81" + RUST_TOOLCHAIN_VERSION: "1.91" jobs: diff --git a/.github/workflows/benches.yml b/.github/workflows/benches.yml index ca1c621106d..3f4b4c5af24 100644 --- a/.github/workflows/benches.yml +++ b/.github/workflows/benches.yml @@ -7,7 +7,7 @@ on: env: OCAML_VERSION: "4.14.2" - RUST_TOOLCHAIN_VERSION: "1.81" + RUST_TOOLCHAIN_VERSION: "1.91" jobs: bench: diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml index e874031764f..22dac848e37 100644 --- a/.github/workflows/ci-nightly.yml +++ b/.github/workflows/ci-nightly.yml @@ -28,7 +28,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - rust_toolchain_version: ["1.81"] + rust_toolchain_version: ["1.91"] # FIXME: currently not available for 5.0.0. # It might be related to boxroot dependency, and we would need to bump # up the ocaml-rs dependency diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bcdd8da6834..7868265c909 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,21 +45,16 @@ jobs: run: echo 'version=["20"]' >> "$GITHUB_OUTPUT" - id: defaults run: | - echo 'rust_version=1.81' >> "$GITHUB_OUTPUT" + echo 'rust_version=1.91' >> "$GITHUB_OUTPUT" echo 'os=ubuntu-latest' >> "$GITHUB_OUTPUT" - id: matrix run: | - # NOTE: This custom matrix configuration is needed to use Rust 1.84 specifically for macOS. - # When https://github.com/o1-labs/proof-systems/issues/3254 is fixed, - # this can be simplified to use a standard matrix configuration. cat > matrix.json << 'EOF' { "include": [ - {"rust_toolchain_version": "1.81", "os": "ubuntu-latest"}, - {"rust_toolchain_version": "1.82", "os": "ubuntu-latest"}, - {"rust_toolchain_version": "1.81", "os": "ubuntu-24.04-arm"}, - {"rust_toolchain_version": "1.82", "os": "ubuntu-24.04-arm"}, - {"rust_toolchain_version": "1.84", "os": "macos-latest"} + {"rust_toolchain_version": "1.91", "os": "ubuntu-latest"}, + {"rust_toolchain_version": "1.91", "os": "ubuntu-24.04-arm"}, + {"rust_toolchain_version": "1.91", "os": "macos-latest"} ] } EOF @@ -98,10 +93,6 @@ jobs: rust_and_os: ${{ fromJSON(needs.define-matrix.outputs.matrix).include }} ocaml_version: ${{ fromJSON(needs.define-matrix.outputs.ocaml_version) }} node: ${{ fromJSON(needs.define-matrix.outputs.node) }} - exclude: - # Skip Rust 1.84 due to linting issues - remove when - # https://github.com/o1-labs/proof-systems/pull/3245 is fixed - - rust_and_os: {rust_toolchain_version: '1.84', os: 'macos-latest'} runs-on: ${{ matrix.rust_and_os.os }} steps: - name: Checkout repository @@ -203,10 +194,6 @@ jobs: rust_and_os: ${{ fromJSON(needs.define-matrix.outputs.matrix).include }} ocaml_version: ${{ fromJSON(needs.define-matrix.outputs.ocaml_version) }} node: ${{ fromJSON(needs.define-matrix.outputs.node) }} - exclude: - # Skip Rust 1.84 due to linting issues - remove when - # https://github.com/o1-labs/proof-systems/pull/3245 is fixed - - rust_and_os: {rust_toolchain_version: '1.84', os: 'macos-latest'} runs-on: ${{ matrix.rust_and_os.os }} steps: - name: Checkout repository @@ -276,10 +263,6 @@ jobs: rust_and_os: ${{ fromJSON(needs.define-matrix.outputs.matrix).include }} ocaml_version: ${{ fromJSON(needs.define-matrix.outputs.ocaml_version) }} node: ${{ fromJSON(needs.define-matrix.outputs.node) }} - exclude: - # Skip Rust 1.84 due to linting issues - remove when - # https://github.com/o1-labs/proof-systems/pull/3245 is fixed - - rust_and_os: {rust_toolchain_version: '1.84', os: 'macos-latest'} runs-on: ${{ matrix.rust_and_os.os }} steps: - name: Checkout repository diff --git a/.github/workflows/o1vm-ci.yml b/.github/workflows/o1vm-ci.yml index b2daf8bbe5d..71c98235e65 100644 --- a/.github/workflows/o1vm-ci.yml +++ b/.github/workflows/o1vm-ci.yml @@ -28,7 +28,7 @@ jobs: runs-on: ["ubuntu-latest"] strategy: matrix: - rust_toolchain_version: ["1.81"] + rust_toolchain_version: ["1.91"] # FIXME: currently not available for 5.0.0. # It might be related to boxroot dependency, and we would need to bump # up the ocaml-rs dependency diff --git a/.github/workflows/test-export-vectors.yml b/.github/workflows/test-export-vectors.yml index a64230b873b..f7c9e0371da 100644 --- a/.github/workflows/test-export-vectors.yml +++ b/.github/workflows/test-export-vectors.yml @@ -29,7 +29,7 @@ jobs: - name: Use shared Rust toolchain setting up steps uses: ./.github/actions/toolchain-shared with: - rust_toolchain_version: "1.81" + rust_toolchain_version: "1.91" - name: Use shared OCaml setting up steps uses: ./.github/actions/ocaml-shared diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 4cef0b738ff..1a35d66439a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.81" +channel = "1.91" From 19839ec3b3f1e7ee28d1fd02dd2cc292b8407119 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:14:46 -0300 Subject: [PATCH 02/18] fix(curves): allow asm cfg from ark-ff derive macros --- curves/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/curves/Cargo.toml b/curves/Cargo.toml index 3c06d1e8f41..300fba561ff 100644 --- a/curves/Cargo.toml +++ b/curves/Cargo.toml @@ -9,6 +9,9 @@ readme = "../README.md" edition = "2021" license = "Apache-2.0" +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ["cfg(feature, values(\"asm\"))"] } + [dependencies] ark-bn254.workspace = true ark-ec.workspace = true From a1cc4003f7445a0f469982f1e30dfd1989213068 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:24:21 -0300 Subject: [PATCH 03/18] fix(utils): use idiomatic Rust 1.91 methods --- utils/src/chunked_polynomial.rs | 2 +- utils/src/foreign_field.rs | 6 +++--- utils/src/math.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/src/chunked_polynomial.rs b/utils/src/chunked_polynomial.rs index 86f64a6b3cf..7bc8a575c3c 100644 --- a/utils/src/chunked_polynomial.rs +++ b/utils/src/chunked_polynomial.rs @@ -42,7 +42,7 @@ impl ChunkedPolynomial { scale *= zeta_n; } - while coeffs.last().map_or(false, |c| c.is_zero()) { + while coeffs.last().is_some_and(|c| c.is_zero()) { coeffs.pop(); } diff --git a/utils/src/foreign_field.rs b/utils/src/foreign_field.rs index fb05f4eb0db..8da5773c43d 100644 --- a/utils/src/foreign_field.rs +++ b/utils/src/foreign_field.rs @@ -77,7 +77,7 @@ impl ForeignElement { /// Obtains the big integer representation of the foreign field element pub fn to_biguint(&self) -> BigUint { let mut bytes = vec![]; - if B % 8 == 0 { + if B.is_multiple_of(8) { // limbs are stored in little endian for limb in self.limbs { let crumb = &limb.to_bytes()[0..B / 8]; @@ -91,7 +91,7 @@ impl ForeignElement { bits.extend(&f_bits_lower); } - let bytes_len = if (B * N) % 8 == 0 { + let bytes_len = if (B * N).is_multiple_of(8) { (B * N) / 8 } else { ((B * N) / 8) + 1 @@ -108,7 +108,7 @@ impl ForeignElement { /// elements of type `F` in little-endian. Right now it is written /// so that it gives `N` (limb count) limbs, even if it fits in less bits. fn big_to_vec(fe: BigUint) -> Vec { - if B % 8 == 0 { + if B.is_multiple_of(8) { let bytes = fe.to_bytes_le(); let chunks: Vec<&[u8]> = bytes.chunks(B / 8).collect(); chunks diff --git a/utils/src/math.rs b/utils/src/math.rs index b7781fdccf4..7705fb4c346 100644 --- a/utils/src/math.rs +++ b/utils/src/math.rs @@ -19,5 +19,5 @@ pub fn ceil_log2(d: usize) -> usize { /// This function is bound to be stable soon. See pub fn div_ceil(a: usize, b: usize) -> usize { - (a + b - 1) / b + a.div_ceil(b) } From 80d6cbf478f014f1b1e1cf5660df5a0dc1fe308d Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:25:06 -0300 Subject: [PATCH 04/18] fix(turshi): use idiomatic Rust 1.91 methods --- turshi/src/memory.rs | 4 ++-- turshi/src/runner.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/turshi/src/memory.rs b/turshi/src/memory.rs index b9b972c8777..534823e49ca 100644 --- a/turshi/src/memory.rs +++ b/turshi/src/memory.rs @@ -8,7 +8,7 @@ use std::{ use crate::{helper::*, word::CairoWord}; use ark_ff::Field; -use core::iter::repeat; +use core::iter::repeat_n; /// This data structure stores the memory of the program pub struct CairoMemory { @@ -85,7 +85,7 @@ impl CairoMemory { // you will need to extend the vector with enough spaces (taking into account that // vectors start by index 0, the 0 address is dummy, and size starts in 1) if let Some(additional) = addr.checked_sub(self.len() - 1) { - self.data.extend(repeat(None).take(additional as usize)); + self.data.extend(repeat_n(None, additional as usize)); } } diff --git a/turshi/src/runner.rs b/turshi/src/runner.rs index fe7664ddb98..ecc8690d2e6 100644 --- a/turshi/src/runner.rs +++ b/turshi/src/runner.rs @@ -261,7 +261,7 @@ pub struct CairoStep<'a, F> { impl<'a, F: Field> CairoStep<'a, F> { /// Creates a new Cairo execution step from a step index, a Cairo word, and current pointers - pub fn new(mem: &mut CairoMemory, ptrs: CairoState) -> CairoStep { + pub fn new(mem: &mut CairoMemory, ptrs: CairoState) -> CairoStep<'_, F> { CairoStep { mem, curr: ptrs, @@ -503,7 +503,7 @@ pub struct CairoProgram<'a, F> { impl<'a, F: Field> CairoProgram<'a, F> { /// Creates a Cairo execution from the public information (memory and initial pointers) - pub fn new(mem: &mut CairoMemory, pc: u64) -> CairoProgram { + pub fn new(mem: &mut CairoMemory, pc: u64) -> CairoProgram<'_, F> { let ap = mem.len(); let mut prog = CairoProgram { steps: F::zero(), From f8985bed0559d87e6f5cd20aa3ddd5624e05635e Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:26:12 -0300 Subject: [PATCH 05/18] fix(poseidon): allow non_local_definitions from ocaml derive macros --- poseidon/src/sponge.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/poseidon/src/sponge.rs b/poseidon/src/sponge.rs index 248d09af500..4db3a81bf8e 100644 --- a/poseidon/src/sponge.rs +++ b/poseidon/src/sponge.rs @@ -262,6 +262,7 @@ where // #[cfg(feature = "ocaml_types")] +#[allow(non_local_definitions)] pub mod caml { use super::*; From 41643393ee8bbfb46091853af62774f2792931a3 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:27:32 -0300 Subject: [PATCH 06/18] fix(internal-tracing): allow non_local_definitions from ocaml derive macros --- internal-tracing/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal-tracing/src/lib.rs b/internal-tracing/src/lib.rs index f274a50237e..1cc237bc9b9 100644 --- a/internal-tracing/src/lib.rs +++ b/internal-tracing/src/lib.rs @@ -107,6 +107,8 @@ macro_rules! decl_traces { } #[cfg(feature = "ocaml_types")] + #[allow(non_local_definitions)] + #[allow(dead_code)] pub mod caml { use super::*; From 4f86b36bf8fe67cde660ca00a960c2c943433e3a Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:28:36 -0300 Subject: [PATCH 07/18] fix(hasher): use div_ceil() instead of manual implementation --- hasher/src/roinput.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hasher/src/roinput.rs b/hasher/src/roinput.rs index 3ed80bb270d..63ddf073226 100644 --- a/hasher/src/roinput.rs +++ b/hasher/src/roinput.rs @@ -260,7 +260,7 @@ impl ROInput { // Check that the number of bytes is consistent with the expected lengths let expected_len_bits = fields_len * Fp::MODULUS_BIT_SIZE as usize + bits_len; // Round up to nearest multiple of 8 - let expected_len = (expected_len_bits + 7) / 8 + SER_HEADER_SIZE; + let expected_len = expected_len_bits.div_ceil(8) + SER_HEADER_SIZE; if input.len() != expected_len { return Err(Error); } From e5a76b69860bfd6d998dec1c755d3a0ab4cde338 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:30:41 -0300 Subject: [PATCH 08/18] fix(poly-commitment): use idiomatic Rust 1.91 methods and allow ocaml derive warnings --- poly-commitment/src/combine.rs | 2 +- poly-commitment/src/commitment.rs | 7 ++++--- poly-commitment/src/ipa.rs | 3 ++- poly-commitment/src/utils.rs | 6 +++--- poly-commitment/tests/commitment.rs | 2 +- poly-commitment/tests/ipa_commitment.rs | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/poly-commitment/src/combine.rs b/poly-commitment/src/combine.rs index ad303a8bb5f..df6892c54ac 100644 --- a/poly-commitment/src/combine.rs +++ b/poly-commitment/src/combine.rs @@ -26,7 +26,7 @@ use rayon::prelude::*; use std::ops::AddAssign; fn add_pairs_in_place(pairs: &mut Vec>) { - let len = if pairs.len() % 2 == 0 { + let len = if pairs.len().is_multiple_of(2) { pairs.len() } else { pairs.len() - 1 diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index 4e38d9ad757..dda1bec2563 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -269,7 +269,7 @@ where } } -impl<'a, 'b, C: AffineRepr> Add<&'a PolyComm> for &'b PolyComm { +impl<'a, C: AffineRepr> Add<&'a PolyComm> for &PolyComm { type Output = PolyComm; fn add(self, other: &'a PolyComm) -> PolyComm { @@ -290,7 +290,7 @@ impl<'a, 'b, C: AffineRepr> Add<&'a PolyComm> for &'b PolyComm { } } -impl<'a, 'b, C: AffineRepr + Sub> Sub<&'a PolyComm> for &'b PolyComm { +impl<'a, C: AffineRepr + Sub> Sub<&'a PolyComm> for &PolyComm { type Output = PolyComm; fn sub(self, other: &'a PolyComm) -> PolyComm { @@ -376,7 +376,7 @@ pub fn b_poly(chals: &[F], x: F) -> F { pow_twos.push(pow_twos[i - 1].square()); } - product((0..k).map(|i| (F::one() + (chals[i] * pow_twos[k - 1 - i])))) + product((0..k).map(|i| F::one() + (chals[i] * pow_twos[k - 1 - i]))) } pub fn b_poly_coefficients(chals: &[F]) -> Vec { @@ -638,6 +638,7 @@ pub fn combine_commitments( } #[cfg(feature = "ocaml_types")] +#[allow(non_local_definitions)] pub mod caml { // polynomial commitment use super::PolyComm; diff --git a/poly-commitment/src/ipa.rs b/poly-commitment/src/ipa.rs index 62882175e84..57063b8f81a 100644 --- a/poly-commitment/src/ipa.rs +++ b/poly-commitment/src/ipa.rs @@ -891,7 +891,7 @@ impl SRS { // polynomial commitments, we obtain a chunked commitment to the L_i // polynomials. let srs_size = self.g.len(); - let num_elems = (n + srs_size - 1) / srs_size; + let num_elems = n.div_ceil(srs_size); let mut chunks = Vec::with_capacity(num_elems); // For each chunk @@ -1027,6 +1027,7 @@ impl OpeningProof { } #[cfg(feature = "ocaml_types")] +#[allow(non_local_definitions)] pub mod caml { use super::OpeningProof; use ark_ec::AffineRepr; diff --git a/poly-commitment/src/utils.rs b/poly-commitment/src/utils.rs index 01237964438..eb8f6ab101f 100644 --- a/poly-commitment/src/utils.rs +++ b/poly-commitment/src/utils.rs @@ -33,7 +33,7 @@ impl ScaledChunkedPolynomial { } } -impl<'a, F: Field> ScaledChunkedPolynomial { +impl ScaledChunkedPolynomial { /// Compute the resulting scaled polynomial. /// Example: /// Given the two polynomials `1 + 2X` and `3 + 4X`, and the scaling @@ -74,9 +74,9 @@ impl<'a, F: Field> ScaledChunkedPolynomial { /// /// Parameters: /// - `plnms`: vector of polynomials, either in evaluations or coefficients form, together with -/// a set of scalars representing their blinders. +/// a set of scalars representing their blinders. /// - `polyscale`: scalar to combine the polynomials, which will be scaled based on the number of -/// polynomials to combine. +/// polynomials to combine. /// /// Output: /// - `combined_poly`: combined polynomial. The order of the output follows the order of `plnms`. diff --git a/poly-commitment/tests/commitment.rs b/poly-commitment/tests/commitment.rs index b2eace323d5..5ca718f3c79 100644 --- a/poly-commitment/tests/commitment.rs +++ b/poly-commitment/tests/commitment.rs @@ -78,7 +78,7 @@ impl AggregatedEvaluationProof { /// verify API understands pub fn verify_type( &self, - ) -> BatchEvaluationProof, OpeningProof> + ) -> BatchEvaluationProof<'_, Vesta, DefaultFqSponge, OpeningProof> { let mut coms = vec![]; for eval_com in &self.eval_commitments { diff --git a/poly-commitment/tests/ipa_commitment.rs b/poly-commitment/tests/ipa_commitment.rs index a109b391b77..686c522d698 100644 --- a/poly-commitment/tests/ipa_commitment.rs +++ b/poly-commitment/tests/ipa_commitment.rs @@ -96,7 +96,7 @@ fn test_offset_chunked_lagrange_commitments() { srs.get_lagrange_basis(domain); // Is this even taken into account?... - let num_chunks = (domain.size() + srs.g.len() - 1) / srs.g.len(); + let num_chunks = domain.size().div_ceil(srs.g.len()); assert!(num_chunks == 2); let expected_lagrange_commitments: Vec<_> = (0..n) From 306bfd0b28f98a9d77149d6a87a1288e58d1b088 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:31:39 -0300 Subject: [PATCH 09/18] fix(signer): use div_ceil() instead of manual implementation --- signer/src/schnorr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signer/src/schnorr.rs b/signer/src/schnorr.rs index 21f61a25427..a0ca0df1314 100644 --- a/signer/src/schnorr.rs +++ b/signer/src/schnorr.rs @@ -217,7 +217,7 @@ impl Schnorr { } // Convert bits to bytes for BLAKE2b - let mut input_bytes = vec![0u8; (all_bits.len() + 7) / 8]; + let mut input_bytes = vec![0u8; all_bits.len().div_ceil(8)]; for (i, &bit) in all_bits.iter().enumerate() { if bit { input_bytes[i / 8] |= 1 << (i % 8); From 814f775fecb11256aa5240ebbce6ac98ec82a1f9 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:38:53 -0300 Subject: [PATCH 10/18] fix(kimchi): apply Rust 1.91 clippy fixes --- kimchi/benches/amortization.rs | 4 +--- kimchi/benches/proof_criterion_mina.rs | 2 +- kimchi/benches/proof_iai.rs | 2 +- kimchi/src/alphas.rs | 2 +- kimchi/src/bin/flamegraph.rs | 2 +- kimchi/src/circuits/lookup/index.rs | 13 ++++++------- .../polynomials/foreign_field_add/witness.rs | 4 ++-- .../polynomials/foreign_field_mul/witness.rs | 4 ++-- kimchi/src/circuits/polynomials/keccak/constants.rs | 2 +- kimchi/src/circuits/polynomials/keccak/witness.rs | 1 + kimchi/src/circuits/polynomials/turshi.rs | 1 + kimchi/src/lib.rs | 1 + kimchi/src/prover.rs | 2 +- kimchi/src/snarky/runner.rs | 2 +- kimchi/src/tests/serde.rs | 2 +- 15 files changed, 22 insertions(+), 22 deletions(-) diff --git a/kimchi/benches/amortization.rs b/kimchi/benches/amortization.rs index a6c6f9529ce..1bbb6145a54 100644 --- a/kimchi/benches/amortization.rs +++ b/kimchi/benches/amortization.rs @@ -8,9 +8,7 @@ pub fn amortization(c: &mut Criterion) { let ctx = BenchmarkCtx::new(16); let proof_and_public = ctx.create_proof(); - let proofs: Vec<_> = core::iter::repeat(proof_and_public) - .take(1 << PROOFS) - .collect(); + let proofs: Vec<_> = std::iter::repeat_n(proof_and_public, 1 << PROOFS).collect(); group.sample_size(10); for size in 0..=PROOFS { diff --git a/kimchi/benches/proof_criterion_mina.rs b/kimchi/benches/proof_criterion_mina.rs index 0e0dfa26814..ff6c0527769 100644 --- a/kimchi/benches/proof_criterion_mina.rs +++ b/kimchi/benches/proof_criterion_mina.rs @@ -25,7 +25,7 @@ pub fn bench_proof_creation_mina(c: &mut Criterion) { // Parse filename "kimchi_inputs_CURVENAME_SEED.ser" into two parameters let (curve_name, seed): (&str, &str) = filename .split('/') - .last() + .next_back() .unwrap() .strip_prefix("kimchi_inputs_") .unwrap() diff --git a/kimchi/benches/proof_iai.rs b/kimchi/benches/proof_iai.rs index c5dc53ff850..b35a9caf937 100644 --- a/kimchi/benches/proof_iai.rs +++ b/kimchi/benches/proof_iai.rs @@ -8,7 +8,7 @@ fn bench_proof_creation() { fn bench_proof_creation_and_verification() { let ctx = BenchmarkCtx::new(14); let proof_and_public = ctx.create_proof(); - ctx.batch_verification(&vec![proof_and_public]); + ctx.batch_verification(&[proof_and_public]); } iai::main!(bench_proof_creation, bench_proof_creation_and_verification); diff --git a/kimchi/src/alphas.rs b/kimchi/src/alphas.rs index 83e9f519104..630e6539435 100644 --- a/kimchi/src/alphas.rs +++ b/kimchi/src/alphas.rs @@ -130,7 +130,7 @@ impl Alphas { &self, ty: ArgumentType, num: u32, - ) -> MustConsumeIterator>>>, F> { + ) -> MustConsumeIterator>>>, F> { let ty = if matches!(ty, ArgumentType::Gate(_)) { ArgumentType::Gate(GateType::Zero) } else { diff --git a/kimchi/src/bin/flamegraph.rs b/kimchi/src/bin/flamegraph.rs index 33c496c2193..76deb81cd50 100644 --- a/kimchi/src/bin/flamegraph.rs +++ b/kimchi/src/bin/flamegraph.rs @@ -27,7 +27,7 @@ fn main() { let ctx = BenchmarkCtx::new(4); let proof_and_public = ctx.create_proof(); loop { - ctx.batch_verification(black_box(&vec![proof_and_public.clone()])); + ctx.batch_verification(black_box(std::slice::from_ref(&proof_and_public))); } } _ => panic!("you must provide an argument (prove or verify)"), diff --git a/kimchi/src/circuits/lookup/index.rs b/kimchi/src/circuits/lookup/index.rs index 6644b333675..7d3d5d3aa59 100644 --- a/kimchi/src/circuits/lookup/index.rs +++ b/kimchi/src/circuits/lookup/index.rs @@ -13,7 +13,6 @@ use ark_poly::{ univariate::DensePolynomial as DP, EvaluationDomain, Evaluations as E, Radix2EvaluationDomain as D, }; -use core::iter; use itertools::repeat_n; use o1_utils::field_helpers::i32_to_field; use serde::{de::DeserializeOwned, Deserialize, Serialize}; @@ -287,12 +286,12 @@ impl LookupConstraintSystem { // it's 1 everywhere, except at the entries where // the runtime table applies - evals.extend(iter::repeat(F::one()).take(runtime_table_offset)); - evals.extend(iter::repeat(F::zero()).take(runtime_len)); - evals.extend( - iter::repeat(F::one()) - .take(d1_size - runtime_table_offset - runtime_len), - ); + evals.extend(std::iter::repeat_n(F::one(), runtime_table_offset)); + evals.extend(std::iter::repeat_n(F::zero(), runtime_len)); + evals.extend(std::iter::repeat_n( + F::one(), + d1_size - runtime_table_offset - runtime_len, + )); // although the last zk_rows are fine for e in evals.iter_mut().rev().take(zk_rows) { diff --git a/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs b/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs index 95b23771018..470330e6764 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_add/witness.rs @@ -156,7 +156,7 @@ pub fn create_chain( for i in 0..num { // Create foreign field addition row for w in &mut witness { - w.extend(core::iter::repeat(F::zero()).take(1)); + w.extend(std::iter::repeat_n(F::zero(), 1)); } let right = ForeignElement::from_biguint(inputs[i + 1].clone()); let (output, _sign, ovf, carry) = @@ -298,7 +298,7 @@ pub fn extend_witness_bound_addition( // Extend the witness for the add gate let offset = witness[0].len(); for col in witness.iter_mut().take(COLUMNS) { - col.extend(core::iter::repeat(F::zero()).take(2)) + col.extend(std::iter::repeat_n(F::zero(), 2)) } init_bound_rows( diff --git a/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs b/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs index d2b0e3c1721..0857fd9041c 100644 --- a/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs +++ b/kimchi/src/circuits/polynomials/foreign_field_mul/witness.rs @@ -198,7 +198,7 @@ pub fn create( // Extend the witness by two rows for foreign field multiplication for w in &mut witness { - w.extend(core::iter::repeat(F::zero()).take(2)); + w.extend(std::iter::repeat_n(F::zero(), 2)); } // Create the foreign field multiplication witness rows @@ -329,7 +329,7 @@ impl ExternalChecks { for chunk in self.high_bounds.clone().chunks(2) { // Extend the witness for the generic gate for col in witness.iter_mut().take(COLUMNS) { - col.extend(core::iter::repeat(F::zero()).take(1)) + col.extend(std::iter::repeat_n(F::zero(), 1)) } let last_row = witness[0].len() - 1; // Fill in with dummy if it is an odd number of bounds diff --git a/kimchi/src/circuits/polynomials/keccak/constants.rs b/kimchi/src/circuits/polynomials/keccak/constants.rs index e8416cf2db0..10ab6114093 100644 --- a/kimchi/src/circuits/polynomials/keccak/constants.rs +++ b/kimchi/src/circuits/polynomials/keccak/constants.rs @@ -1,4 +1,4 @@ -/// Constants for each witness' index offsets and lengths +// Constants for each witness' index offsets and lengths // KECCAK PARAMETERS /// The dimension of the Keccak state diff --git a/kimchi/src/circuits/polynomials/keccak/witness.rs b/kimchi/src/circuits/polynomials/keccak/witness.rs index f7b003c8b4d..abd115f8c78 100644 --- a/kimchi/src/circuits/polynomials/keccak/witness.rs +++ b/kimchi/src/circuits/polynomials/keccak/witness.rs @@ -393,6 +393,7 @@ impl PiRho { let aux = grid!(100, rotation_e.expand_rot); for y in 0..DIM { for x in 0..DIM { + #[allow(clippy::needless_range_loop)] for q in 0..QUARTERS { state_b[(2 * x + 3 * y) % DIM][y][q] = aux(y, x, q); } diff --git a/kimchi/src/circuits/polynomials/turshi.rs b/kimchi/src/circuits/polynomials/turshi.rs index 45e6b9e2aa3..dad4f9a783a 100644 --- a/kimchi/src/circuits/polynomials/turshi.rs +++ b/kimchi/src/circuits/polynomials/turshi.rs @@ -1,3 +1,4 @@ +#![allow(clippy::doc_overindented_list_items)] //! This implements the constraints of the Cairo gates //! //! Cairo programs can have the following assembly-like instructions: diff --git a/kimchi/src/lib.rs b/kimchi/src/lib.rs index 13187fccdda..4842c0c52eb 100644 --- a/kimchi/src/lib.rs +++ b/kimchi/src/lib.rs @@ -1,4 +1,5 @@ #![doc = include_str!("../README.md")] +#![allow(non_local_definitions)] pub use groupmap; pub use mina_curves; diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 129ed1226d8..16bde40cfe7 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -241,7 +241,7 @@ where } // padding - w.extend(core::iter::repeat(G::ScalarField::zero()).take(length_padding)); + w.extend(std::iter::repeat_n(G::ScalarField::zero(), length_padding)); // zk-rows for row in w.iter_mut().rev().take(index.cs.zk_rows as usize) { diff --git a/kimchi/src/snarky/runner.rs b/kimchi/src/snarky/runner.rs index e5b18198146..7efd1b69ed2 100644 --- a/kimchi/src/snarky/runner.rs +++ b/kimchi/src/snarky/runner.rs @@ -599,7 +599,7 @@ where } // pad with zeros for the public output part - public_input.extend(core::iter::repeat(F::zero()).take(self.public_output.len())); + public_input.extend(std::iter::repeat_n(F::zero(), self.public_output.len())); // re-initialize `next_var` (which will grow every time we compile or generate a witness) self.next_var = self.num_public_inputs; diff --git a/kimchi/src/tests/serde.rs b/kimchi/src/tests/serde.rs index b69cd23d170..8da853e75cc 100644 --- a/kimchi/src/tests/serde.rs +++ b/kimchi/src/tests/serde.rs @@ -49,7 +49,7 @@ mod tests { rmp_serde::from_slice(&ser_pf).unwrap(); // verify the deserialized proof (must accept the proof) - ctx.batch_verification(&vec![(de_pf, public_input)]); + ctx.batch_verification(&[(de_pf, public_input)]); } #[test] From 379cfb86f025fa4614733945db4f3fc1c6e1bb85 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:45:23 -0300 Subject: [PATCH 11/18] fix(msm): apply Rust 1.91 clippy fixes --- msm/src/circuit_design/witness.rs | 7 +++---- msm/src/fec/interpreter.rs | 2 ++ msm/src/lookups.rs | 7 +++---- msm/src/serialization/interpreter.rs | 2 +- msm/src/test/proof_system.rs | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/msm/src/circuit_design/witness.rs b/msm/src/circuit_design/witness.rs index 6246b16ee6b..0ed8e5c45e6 100644 --- a/msm/src/circuit_design/witness.rs +++ b/msm/src/circuit_design/witness.rs @@ -9,7 +9,7 @@ use crate::{ }; use ark_ff::PrimeField; use log::debug; -use std::{collections::BTreeMap, iter, marker::PhantomData}; +use std::{collections::BTreeMap, marker::PhantomData}; /// Witness builder environment. Operates on multiple rows at the same /// time. `CIx::N_COL` must be equal to `N_WIT + N_FSEL`; passing these two @@ -345,9 +345,8 @@ impl< ); if table_id.length() < domain_size { let n_repeated_dummy_value: usize = domain_size - table_id.length() - 1; - let repeated_dummy_value: Vec = iter::repeat(-F::one()) - .take(n_repeated_dummy_value) - .collect(); + let repeated_dummy_value: Vec = + std::iter::repeat_n(-F::one(), n_repeated_dummy_value).collect(); m.extend(repeated_dummy_value); m.push(F::from(n_repeated_dummy_value as u64)); } diff --git a/msm/src/fec/interpreter.rs b/msm/src/fec/interpreter.rs index 189bfd762b6..0e33baf952d 100644 --- a/msm/src/fec/interpreter.rs +++ b/msm/src/fec/interpreter.rs @@ -1,3 +1,5 @@ +#![allow(clippy::doc_overindented_list_items)] + use crate::{ circuit_design::{ capabilities::{read_column_array, write_column_array_const, write_column_const}, diff --git a/msm/src/lookups.rs b/msm/src/lookups.rs index c488a2f3c1a..387243b1246 100644 --- a/msm/src/lookups.rs +++ b/msm/src/lookups.rs @@ -4,7 +4,7 @@ use crate::logup::{Logup, LogupWitness, LookupTableID}; use ark_ff::{FftField, PrimeField}; use kimchi::circuits::domains::EvaluationDomains; use rand::{seq::SliceRandom, thread_rng, Rng}; -use std::{cmp::Ord, iter}; +use std::cmp::Ord; /// Dummy lookup table. For the cases when you don't need one -- a single dummy element 0. #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] @@ -144,9 +144,8 @@ impl LookupWitness { }; let dummy_value = F::rand(&mut rng); let repeated_dummy_value: Vec = { - let r: Vec = iter::repeat(dummy_value) - .take((domain.d1.size - table_size) as usize) - .collect(); + let r: Vec = + std::iter::repeat_n(dummy_value, (domain.d1.size - table_size) as usize).collect(); r }; let t_evals = { diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index fb57eaad4bd..95ce08eab29 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -330,7 +330,7 @@ pub fn combine_limbs_m_to_n< from_field: Func, x: [V; M], ) -> [V; N] { - assert!(BITSIZE_N % BITSIZE_M == 0); + assert!(BITSIZE_N.is_multiple_of(BITSIZE_M)); let k = BITSIZE_N / BITSIZE_M; let constant_bui = |x: BigUint| from_field(F::from(x)); let disparity: usize = M % k; diff --git a/msm/src/test/proof_system.rs b/msm/src/test/proof_system.rs index 491109c56d6..0f5cb9a0167 100644 --- a/msm/src/test/proof_system.rs +++ b/msm/src/test/proof_system.rs @@ -1,4 +1,4 @@ -/// Tests for the proof system itself, targeting prover and verifier. +//! Tests for the proof system itself, targeting prover and verifier. #[cfg(test)] mod tests { From 7239a08f62b2a8e34ad8b3a5feab1ea80fe27eee Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:45:30 -0300 Subject: [PATCH 12/18] fix(mvpoly): apply Rust 1.91 clippy fixes --- mvpoly/src/lib.rs | 4 ++-- mvpoly/src/utils.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mvpoly/src/lib.rs b/mvpoly/src/lib.rs index bc32baff777..1bb3636be1a 100644 --- a/mvpoly/src/lib.rs +++ b/mvpoly/src/lib.rs @@ -4,8 +4,8 @@ //! Different representations are provided in the sub-modules: //! - `monomials`: a representation based on monomials //! - `prime`: a representation based on a mapping from variables to prime -//! numbers. This representation is unmaintained for now. We leave it -//! for interested users. +//! numbers. This representation is unmaintained for now. We leave it +//! for interested users. //! //! "Expressions", as defined in the [kimchi] crate, can be converted into a //! multi-variate polynomial using the `from_expr` method. diff --git a/mvpoly/src/utils.rs b/mvpoly/src/utils.rs index b50e70ad485..fd503f92d86 100644 --- a/mvpoly/src/utils.rs +++ b/mvpoly/src/utils.rs @@ -16,12 +16,12 @@ pub fn is_prime(n: usize) -> bool { if n == 2 { return true; } - if n < 2 || n % 2 == 0 { + if n < 2 || n.is_multiple_of(2) { return false; } let mut i = 3; while i * i <= n { - if n % i == 0 { + if n.is_multiple_of(i) { return false; } i += 2; @@ -48,7 +48,7 @@ pub fn naive_prime_factors(n: usize, prime_gen: &mut PrimeNumberGenerator) -> Ve let mut i = 1; let mut p = prime_gen.get_nth_prime(i); while n != 1 { - if n % p == 0 { + if n.is_multiple_of(p) { hash_factors.entry(p).and_modify(|e| *e += 1).or_insert(1); n /= p; } else { @@ -113,7 +113,7 @@ impl PrimeNumberGenerator { let mut i = 1; let mut p = self.get_nth_prime(i); while p * p <= n { - if n % p == 0 { + if n.is_multiple_of(p) { return false; } i += 1; @@ -196,7 +196,7 @@ pub fn compute_all_two_factors_decomposition( let mut i = 1; let mut p = prime_numbers.get_nth_prime(i); while p * p <= n { - if n % p == 0 { + if n.is_multiple_of(p) { let res = n / p; let res_factors = compute_all_two_factors_decomposition(res, cache, prime_numbers); From dc74eb2917768b751cdf1ac5ba36e3daef9e4c87 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:48:10 -0300 Subject: [PATCH 13/18] fix(kimchi-stubs): allow ocaml derive macro warnings --- kimchi-stubs/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kimchi-stubs/src/lib.rs b/kimchi-stubs/src/lib.rs index b2cc631fc3e..b1e29eb015d 100644 --- a/kimchi-stubs/src/lib.rs +++ b/kimchi-stubs/src/lib.rs @@ -7,6 +7,9 @@ //! a math library that Proof-systems builds on top of. //! +#![allow(non_local_definitions)] +#![allow(unexpected_cfgs)] + extern crate libc; /// Caml helpers From 1b5d601a0bbe420957065007a98ebf2d37b2d8de Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:50:56 -0300 Subject: [PATCH 14/18] fix(plonk-wasm): apply Rust 1.91 clippy fixes --- plonk-wasm/src/rayon.rs | 1 + plonk-wasm/src/wasm_ocaml_serde/de.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plonk-wasm/src/rayon.rs b/plonk-wasm/src/rayon.rs index 5127f1e7262..d79f26b0f37 100644 --- a/plonk-wasm/src/rayon.rs +++ b/plonk-wasm/src/rayon.rs @@ -25,6 +25,7 @@ where OP: FnOnce() -> R + Send, R: Send, { + #[allow(static_mut_refs)] let pool = unsafe { THREAD_POOL.as_ref().unwrap() }; pool.install(op) } diff --git a/plonk-wasm/src/wasm_ocaml_serde/de.rs b/plonk-wasm/src/wasm_ocaml_serde/de.rs index e66b7d611db..f3ebe13c149 100644 --- a/plonk-wasm/src/wasm_ocaml_serde/de.rs +++ b/plonk-wasm/src/wasm_ocaml_serde/de.rs @@ -23,7 +23,7 @@ impl ObjectAccess { } } -fn str_deserializer(s: &str) -> de::value::StrDeserializer { +fn str_deserializer(s: &str) -> de::value::StrDeserializer<'_, Error> { de::IntoDeserializer::into_deserializer(s) } From 1d5bf8c75bcdf02d28d7505e7c772a7432110611 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:55:01 -0300 Subject: [PATCH 15/18] fix(arrabbiata): apply Rust 1.91 clippy fixes --- arrabbiata/src/interpreter.rs | 1 + arrabbiata/src/witness.rs | 46 +++++++++++++++++------------------ 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/arrabbiata/src/interpreter.rs b/arrabbiata/src/interpreter.rs index 38e4fcf4dbc..31161ab626d 100644 --- a/arrabbiata/src/interpreter.rs +++ b/arrabbiata/src/interpreter.rs @@ -1,3 +1,4 @@ +#![allow(clippy::doc_overindented_list_items)] //! This module contains the implementation of the IVC scheme in addition to //! running an arbitrary function that can use up to [crate::NUMBER_OF_COLUMNS] //! columns. diff --git a/arrabbiata/src/witness.rs b/arrabbiata/src/witness.rs index 87b2abe26ee..e6bd047c4eb 100644 --- a/arrabbiata/src/witness.rs +++ b/arrabbiata/src/witness.rs @@ -466,7 +466,7 @@ where let Column::X(idx) = col else { unimplemented!("Only works for private inputs") }; - let (modulus, srs_size): (BigInt, usize) = if self.current_iteration % 2 == 0 { + let (modulus, srs_size): (BigInt, usize) = if self.current_iteration.is_multiple_of(2) { ( E1::ScalarField::modulus_biguint().into(), self.indexed_relation.get_srs_size(), @@ -491,7 +491,7 @@ where } fn constrain_boolean(&mut self, x: Self::Variable) { - let modulus: BigInt = if self.current_iteration % 2 == 0 { + let modulus: BigInt = if self.current_iteration.is_multiple_of(2) { E1::ScalarField::modulus_biguint().into() } else { E2::ScalarField::modulus_biguint().into() @@ -575,7 +575,7 @@ where /// FIXME: check if we need to pick the left or right sponge fn coin_folding_combiner(&mut self, pos: Self::Position) -> Self::Variable { - let r = if self.current_iteration % 2 == 0 { + let r = if self.current_iteration.is_multiple_of(2) { self.sponge_e1[0].clone() } else { self.sponge_e2[0].clone() @@ -590,7 +590,7 @@ where } fn load_poseidon_state(&mut self, pos: Self::Position, i: usize) -> Self::Variable { - let state = if self.current_iteration % 2 == 0 { + let state = if self.current_iteration.is_multiple_of(2) { self.sponge_e1[i].clone() } else { self.sponge_e2[i].clone() @@ -599,7 +599,7 @@ where } fn get_poseidon_round_constant(&self, round: usize, i: usize) -> Self::Variable { - if self.current_iteration % 2 == 0 { + if self.current_iteration.is_multiple_of(2) { E1::sponge_params().round_constants[round][i] .to_biguint() .into() @@ -611,7 +611,7 @@ where } fn get_poseidon_mds_matrix(&mut self, i: usize, j: usize) -> Self::Variable { - if self.current_iteration % 2 == 0 { + if self.current_iteration.is_multiple_of(2) { E1::sponge_params().mds[i][j].to_biguint().into() } else { E2::sponge_params().mds[i][j].to_biguint().into() @@ -619,7 +619,7 @@ where } unsafe fn save_poseidon_state(&mut self, x: Self::Variable, i: usize) { - if self.current_iteration % 2 == 0 { + if self.current_iteration.is_multiple_of(2) { let modulus: BigInt = E1::ScalarField::modulus_biguint().into(); self.sponge_e1[i] = x.mod_floor(&modulus) } else { @@ -644,12 +644,12 @@ where let res = if idx < 2 * NUMBER_OF_COLUMNS { let idx_col = idx / 2; debug!("Absorbing the accumulator for the column index {idx_col}. After this, there will still be {} elements to absorb", NUMBER_OF_VALUES_TO_ABSORB_PUBLIC_IO - idx - 1); - if self.current_iteration % 2 == 0 { + if self.current_iteration.is_multiple_of(2) { let (pt_x, pt_y) = self.program_e2.accumulated_committed_state[idx_col] .get_first_chunk() .to_coordinates() .unwrap(); - if idx % 2 == 0 { + if idx.is_multiple_of(2) { self.write_column(pos, pt_x.to_biguint().into()) } else { self.write_column(pos, pt_y.to_biguint().into()) @@ -659,7 +659,7 @@ where .get_first_chunk() .to_coordinates() .unwrap(); - if idx % 2 == 0 { + if idx.is_multiple_of(2) { self.write_column(pos, pt_x.to_biguint().into()) } else { self.write_column(pos, pt_y.to_biguint().into()) @@ -685,7 +685,7 @@ where // In the left accumulator, we keep track of the value we keep doubling. // In the right accumulator, we keep the result. if bit == 0 { - if self.current_iteration % 2 == 0 { + if self.current_iteration.is_multiple_of(2) { match side { Side::Left => { let pt = self.program_e2.previous_committed_state[i_comm].get_first_chunk(); @@ -747,7 +747,7 @@ where // FIXME: we must get the scaled commitment, not simply the commitment let (pt_x, pt_y): (BigInt, BigInt) = match side { Side::Left => { - if self.current_iteration % 2 == 0 { + if self.current_iteration.is_multiple_of(2) { let pt = self.program_e2.accumulated_committed_state[i_comm].get_first_chunk(); let (x, y) = pt.to_coordinates().unwrap(); (x.to_biguint().into(), y.to_biguint().into()) @@ -758,7 +758,7 @@ where } } Side::Right => { - if self.current_iteration % 2 == 0 { + if self.current_iteration.is_multiple_of(2) { let pt = self.program_e2.previous_committed_state[i_comm].get_first_chunk(); let (x, y) = pt.to_coordinates().unwrap(); (x.to_biguint().into(), y.to_biguint().into()) @@ -824,7 +824,7 @@ where /// /// Zero is not allowed as an input. unsafe fn inverse(&mut self, pos: Self::Position, x: Self::Variable) -> Self::Variable { - let res = if self.current_iteration % 2 == 0 { + let res = if self.current_iteration.is_multiple_of(2) { E1::ScalarField::from_biguint(&x.to_biguint().unwrap()) .unwrap() .inverse() @@ -851,7 +851,7 @@ where x2: Self::Variable, y2: Self::Variable, ) -> Self::Variable { - let modulus: BigInt = if self.current_iteration % 2 == 0 { + let modulus: BigInt = if self.current_iteration.is_multiple_of(2) { E1::ScalarField::modulus_biguint().into() } else { E2::ScalarField::modulus_biguint().into() @@ -875,7 +875,7 @@ where unsafe { self.inverse(pos, double_y1) } }; let num = { - let a: BigInt = if self.current_iteration % 2 == 0 { + let a: BigInt = if self.current_iteration.is_multiple_of(2) { let a: E2::BaseField = E2::get_curve_params().0; a.to_biguint().into() } else { @@ -901,7 +901,7 @@ where x1: Self::Variable, y1: Self::Variable, ) -> (Self::Variable, Self::Variable) { - let modulus: BigInt = if self.current_iteration % 2 == 0 { + let modulus: BigInt = if self.current_iteration.is_multiple_of(2) { E1::ScalarField::modulus_biguint().into() } else { E2::ScalarField::modulus_biguint().into() @@ -917,7 +917,7 @@ where unsafe { self.inverse(lambda_pos, double_y1) } }; let num = { - let a: BigInt = if self.current_iteration % 2 == 0 { + let a: BigInt = if self.current_iteration.is_multiple_of(2) { let a: E2::BaseField = E2::get_curve_params().0; a.to_biguint().into() } else { @@ -1060,7 +1060,7 @@ where /// This method is supposed to be called after a new iteration of the /// program has been executed. pub fn commit_state(&mut self) { - if self.current_iteration % 2 == 0 { + if self.current_iteration.is_multiple_of(2) { assert_eq!( self.current_row as u64, self.indexed_relation.domain_fp.d1.size, @@ -1095,7 +1095,7 @@ where /// the expected instantiation, refer to the section "Message Passing" in /// [crate::interpreter]. pub fn absorb_state(&mut self) { - let state = if self.current_iteration % 2 == 0 { + let state = if self.current_iteration.is_multiple_of(2) { // Use program_e1's absorb_state method let state = self .program_e1 @@ -1147,7 +1147,7 @@ where pub fn coin_challenge(&mut self, chal: ChallengeTerm) { let sponge_state_vec: Vec = self.prover_sponge_state.to_vec(); - let (verifier_answer, new_state) = if self.current_iteration % 2 == 0 { + let (verifier_answer, new_state) = if self.current_iteration.is_multiple_of(2) { self.program_e1.coin_challenge(sponge_state_vec) } else { self.program_e2.coin_challenge(sponge_state_vec) @@ -1182,7 +1182,7 @@ where pub fn accumulate_program_state(&mut self) { let chal = self.challenges[ChallengeTerm::RelationCombiner].clone(); - if self.current_iteration % 2 == 0 { + if self.current_iteration.is_multiple_of(2) { self.program_e1 .accumulate_program_state(chal, &self.witness); } else { @@ -1212,7 +1212,7 @@ where pub fn accumulate_committed_state(&mut self) { let chal = self.challenges[ChallengeTerm::RelationCombiner].clone(); - if self.current_iteration % 2 == 0 { + if self.current_iteration.is_multiple_of(2) { self.program_e2.accumulate_committed_state(chal); } else { self.program_e1.accumulate_committed_state(chal); From f09ef58d51a1295e291f7c15b5a89fb776748d3a Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:56:46 -0300 Subject: [PATCH 16/18] fix(o1vm): apply Rust 1.91 clippy fixes --- o1vm/src/interpreters/keccak/column.rs | 2 +- o1vm/src/interpreters/keccak/interpreter.rs | 4 ++-- o1vm/src/interpreters/mips/witness.rs | 2 +- o1vm/src/pickles/lookup_prover.rs | 1 - o1vm/src/pickles/main.rs | 2 ++ o1vm/src/test_preimage_read.rs | 2 ++ 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/o1vm/src/interpreters/keccak/column.rs b/o1vm/src/interpreters/keccak/column.rs index d283039cb80..224e5d5dc37 100644 --- a/o1vm/src/interpreters/keccak/column.rs +++ b/o1vm/src/interpreters/keccak/column.rs @@ -356,7 +356,7 @@ impl From for usize { /// pub type KeccakWitness = Witness; -/// IMPLEMENTATIONS FOR COLUMN ALIAS +// IMPLEMENTATIONS FOR COLUMN ALIAS impl Index for KeccakWitness { type Output = T; diff --git a/o1vm/src/interpreters/keccak/interpreter.rs b/o1vm/src/interpreters/keccak/interpreter.rs index b1e06e4596d..55cd2d79d67 100644 --- a/o1vm/src/interpreters/keccak/interpreter.rs +++ b/o1vm/src/interpreters/keccak/interpreter.rs @@ -652,7 +652,7 @@ where } /////////////////////////// - /// SELECTOR OPERATIONS /// + // SELECTOR OPERATIONS // /////////////////////////// /// Returns a degree-2 variable that encodes whether the current step is a @@ -751,7 +751,7 @@ where } ///////////////////////// - /// COLUMN OPERATIONS /// + // COLUMN OPERATIONS // ///////////////////////// /// This function returns the composed sparse variable from shifts of any diff --git a/o1vm/src/interpreters/mips/witness.rs b/o1vm/src/interpreters/mips/witness.rs index 2f61955d987..f9c1cdc78cc 100644 --- a/o1vm/src/interpreters/mips/witness.rs +++ b/o1vm/src/interpreters/mips/witness.rs @@ -1294,7 +1294,7 @@ impl Env { StepFrequency::Never => false, StepFrequency::Always => true, StepFrequency::Exactly(n) => *n == m, - StepFrequency::Every(n) => m % *n == 0, + StepFrequency::Every(n) => m.is_multiple_of(*n), StepFrequency::Range(lo, hi_opt) => { m >= *lo && (hi_opt.is_none() || m < hi_opt.unwrap()) } diff --git a/o1vm/src/pickles/lookup_prover.rs b/o1vm/src/pickles/lookup_prover.rs index f5b7133ac71..7a3992a550c 100644 --- a/o1vm/src/pickles/lookup_prover.rs +++ b/o1vm/src/pickles/lookup_prover.rs @@ -15,7 +15,6 @@ use rand::{CryptoRng, RngCore}; /// This prover takes one Public Input and one Public Output /// It then proves that the sum 1/(beta + table) = PI - PO /// where the table term are term from fixed lookup or RAMLookup - pub fn lookup_prove< G: KimchiCurve, EFqSponge: FqSponge + Clone, diff --git a/o1vm/src/pickles/main.rs b/o1vm/src/pickles/main.rs index 113eda4f28e..b9e479da665 100644 --- a/o1vm/src/pickles/main.rs +++ b/o1vm/src/pickles/main.rs @@ -1,3 +1,5 @@ +#![allow(clippy::zombie_processes)] + use ark_ff::{UniformRand, Zero}; use clap::Parser; use kimchi::circuits::domains::EvaluationDomains; diff --git a/o1vm/src/test_preimage_read.rs b/o1vm/src/test_preimage_read.rs index be351afda79..3469f3ee168 100644 --- a/o1vm/src/test_preimage_read.rs +++ b/o1vm/src/test_preimage_read.rs @@ -1,3 +1,5 @@ +#![allow(clippy::zombie_processes)] + use crate::{ cannon::{PreimageKey, VmConfiguration}, cli, From 66159a79ec285b179e3de39937bb1fead02dc17a Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 11:57:31 -0300 Subject: [PATCH 17/18] fix(curves): apply toml formatting --- curves/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/curves/Cargo.toml b/curves/Cargo.toml index 300fba561ff..269059113e8 100644 --- a/curves/Cargo.toml +++ b/curves/Cargo.toml @@ -10,7 +10,9 @@ edition = "2021" license = "Apache-2.0" [lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ["cfg(feature, values(\"asm\"))"] } +unexpected_cfgs = { level = "warn", check-cfg = [ + "cfg(feature, values(\"asm\"))", +] } [dependencies] ark-bn254.workspace = true From 44866b0dcc987812567b49efbd9ad8f83ba42324 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 2 Dec 2025 12:23:32 -0300 Subject: [PATCH 18/18] fix: revert is_multiple_of usage for WASM nightly compatibility The WASM build uses nightly-2024-09-05 which doesn't have is_multiple_of stabilized. Use the % N == 0 form instead and add allow attributes. --- arrabbiata/src/witness.rs | 49 ++++++++++++++------------- msm/src/serialization/interpreter.rs | 5 ++- mvpoly/src/utils.rs | 12 ++++--- o1vm/src/interpreters/mips/witness.rs | 5 ++- poly-commitment/src/combine.rs | 4 ++- utils/src/foreign_field.rs | 8 +++-- 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/arrabbiata/src/witness.rs b/arrabbiata/src/witness.rs index e6bd047c4eb..5b8fabd91d7 100644 --- a/arrabbiata/src/witness.rs +++ b/arrabbiata/src/witness.rs @@ -1,3 +1,6 @@ +// We can't use is_multiple_of as it's not available in the older nightly used for WASM builds +#![allow(clippy::manual_is_multiple_of)] + use ark_ec::CurveConfig; use ark_ff::PrimeField; use ark_poly::Evaluations; @@ -466,7 +469,7 @@ where let Column::X(idx) = col else { unimplemented!("Only works for private inputs") }; - let (modulus, srs_size): (BigInt, usize) = if self.current_iteration.is_multiple_of(2) { + let (modulus, srs_size): (BigInt, usize) = if self.current_iteration % 2 == 0 { ( E1::ScalarField::modulus_biguint().into(), self.indexed_relation.get_srs_size(), @@ -491,7 +494,7 @@ where } fn constrain_boolean(&mut self, x: Self::Variable) { - let modulus: BigInt = if self.current_iteration.is_multiple_of(2) { + let modulus: BigInt = if self.current_iteration % 2 == 0 { E1::ScalarField::modulus_biguint().into() } else { E2::ScalarField::modulus_biguint().into() @@ -575,7 +578,7 @@ where /// FIXME: check if we need to pick the left or right sponge fn coin_folding_combiner(&mut self, pos: Self::Position) -> Self::Variable { - let r = if self.current_iteration.is_multiple_of(2) { + let r = if self.current_iteration % 2 == 0 { self.sponge_e1[0].clone() } else { self.sponge_e2[0].clone() @@ -590,7 +593,7 @@ where } fn load_poseidon_state(&mut self, pos: Self::Position, i: usize) -> Self::Variable { - let state = if self.current_iteration.is_multiple_of(2) { + let state = if self.current_iteration % 2 == 0 { self.sponge_e1[i].clone() } else { self.sponge_e2[i].clone() @@ -599,7 +602,7 @@ where } fn get_poseidon_round_constant(&self, round: usize, i: usize) -> Self::Variable { - if self.current_iteration.is_multiple_of(2) { + if self.current_iteration % 2 == 0 { E1::sponge_params().round_constants[round][i] .to_biguint() .into() @@ -611,7 +614,7 @@ where } fn get_poseidon_mds_matrix(&mut self, i: usize, j: usize) -> Self::Variable { - if self.current_iteration.is_multiple_of(2) { + if self.current_iteration % 2 == 0 { E1::sponge_params().mds[i][j].to_biguint().into() } else { E2::sponge_params().mds[i][j].to_biguint().into() @@ -619,7 +622,7 @@ where } unsafe fn save_poseidon_state(&mut self, x: Self::Variable, i: usize) { - if self.current_iteration.is_multiple_of(2) { + if self.current_iteration % 2 == 0 { let modulus: BigInt = E1::ScalarField::modulus_biguint().into(); self.sponge_e1[i] = x.mod_floor(&modulus) } else { @@ -644,12 +647,12 @@ where let res = if idx < 2 * NUMBER_OF_COLUMNS { let idx_col = idx / 2; debug!("Absorbing the accumulator for the column index {idx_col}. After this, there will still be {} elements to absorb", NUMBER_OF_VALUES_TO_ABSORB_PUBLIC_IO - idx - 1); - if self.current_iteration.is_multiple_of(2) { + if self.current_iteration % 2 == 0 { let (pt_x, pt_y) = self.program_e2.accumulated_committed_state[idx_col] .get_first_chunk() .to_coordinates() .unwrap(); - if idx.is_multiple_of(2) { + if idx % 2 == 0 { self.write_column(pos, pt_x.to_biguint().into()) } else { self.write_column(pos, pt_y.to_biguint().into()) @@ -659,7 +662,7 @@ where .get_first_chunk() .to_coordinates() .unwrap(); - if idx.is_multiple_of(2) { + if idx % 2 == 0 { self.write_column(pos, pt_x.to_biguint().into()) } else { self.write_column(pos, pt_y.to_biguint().into()) @@ -685,7 +688,7 @@ where // In the left accumulator, we keep track of the value we keep doubling. // In the right accumulator, we keep the result. if bit == 0 { - if self.current_iteration.is_multiple_of(2) { + if self.current_iteration % 2 == 0 { match side { Side::Left => { let pt = self.program_e2.previous_committed_state[i_comm].get_first_chunk(); @@ -747,7 +750,7 @@ where // FIXME: we must get the scaled commitment, not simply the commitment let (pt_x, pt_y): (BigInt, BigInt) = match side { Side::Left => { - if self.current_iteration.is_multiple_of(2) { + if self.current_iteration % 2 == 0 { let pt = self.program_e2.accumulated_committed_state[i_comm].get_first_chunk(); let (x, y) = pt.to_coordinates().unwrap(); (x.to_biguint().into(), y.to_biguint().into()) @@ -758,7 +761,7 @@ where } } Side::Right => { - if self.current_iteration.is_multiple_of(2) { + if self.current_iteration % 2 == 0 { let pt = self.program_e2.previous_committed_state[i_comm].get_first_chunk(); let (x, y) = pt.to_coordinates().unwrap(); (x.to_biguint().into(), y.to_biguint().into()) @@ -824,7 +827,7 @@ where /// /// Zero is not allowed as an input. unsafe fn inverse(&mut self, pos: Self::Position, x: Self::Variable) -> Self::Variable { - let res = if self.current_iteration.is_multiple_of(2) { + let res = if self.current_iteration % 2 == 0 { E1::ScalarField::from_biguint(&x.to_biguint().unwrap()) .unwrap() .inverse() @@ -851,7 +854,7 @@ where x2: Self::Variable, y2: Self::Variable, ) -> Self::Variable { - let modulus: BigInt = if self.current_iteration.is_multiple_of(2) { + let modulus: BigInt = if self.current_iteration % 2 == 0 { E1::ScalarField::modulus_biguint().into() } else { E2::ScalarField::modulus_biguint().into() @@ -875,7 +878,7 @@ where unsafe { self.inverse(pos, double_y1) } }; let num = { - let a: BigInt = if self.current_iteration.is_multiple_of(2) { + let a: BigInt = if self.current_iteration % 2 == 0 { let a: E2::BaseField = E2::get_curve_params().0; a.to_biguint().into() } else { @@ -901,7 +904,7 @@ where x1: Self::Variable, y1: Self::Variable, ) -> (Self::Variable, Self::Variable) { - let modulus: BigInt = if self.current_iteration.is_multiple_of(2) { + let modulus: BigInt = if self.current_iteration % 2 == 0 { E1::ScalarField::modulus_biguint().into() } else { E2::ScalarField::modulus_biguint().into() @@ -917,7 +920,7 @@ where unsafe { self.inverse(lambda_pos, double_y1) } }; let num = { - let a: BigInt = if self.current_iteration.is_multiple_of(2) { + let a: BigInt = if self.current_iteration % 2 == 0 { let a: E2::BaseField = E2::get_curve_params().0; a.to_biguint().into() } else { @@ -1060,7 +1063,7 @@ where /// This method is supposed to be called after a new iteration of the /// program has been executed. pub fn commit_state(&mut self) { - if self.current_iteration.is_multiple_of(2) { + if self.current_iteration % 2 == 0 { assert_eq!( self.current_row as u64, self.indexed_relation.domain_fp.d1.size, @@ -1095,7 +1098,7 @@ where /// the expected instantiation, refer to the section "Message Passing" in /// [crate::interpreter]. pub fn absorb_state(&mut self) { - let state = if self.current_iteration.is_multiple_of(2) { + let state = if self.current_iteration % 2 == 0 { // Use program_e1's absorb_state method let state = self .program_e1 @@ -1147,7 +1150,7 @@ where pub fn coin_challenge(&mut self, chal: ChallengeTerm) { let sponge_state_vec: Vec = self.prover_sponge_state.to_vec(); - let (verifier_answer, new_state) = if self.current_iteration.is_multiple_of(2) { + let (verifier_answer, new_state) = if self.current_iteration % 2 == 0 { self.program_e1.coin_challenge(sponge_state_vec) } else { self.program_e2.coin_challenge(sponge_state_vec) @@ -1182,7 +1185,7 @@ where pub fn accumulate_program_state(&mut self) { let chal = self.challenges[ChallengeTerm::RelationCombiner].clone(); - if self.current_iteration.is_multiple_of(2) { + if self.current_iteration % 2 == 0 { self.program_e1 .accumulate_program_state(chal, &self.witness); } else { @@ -1212,7 +1215,7 @@ where pub fn accumulate_committed_state(&mut self) { let chal = self.challenges[ChallengeTerm::RelationCombiner].clone(); - if self.current_iteration.is_multiple_of(2) { + if self.current_iteration % 2 == 0 { self.program_e2.accumulate_committed_state(chal); } else { self.program_e1.accumulate_committed_state(chal); diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index 95ce08eab29..422c1692c1a 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -1,3 +1,6 @@ +// We can't use is_multiple_of as it's not available in the older nightly used for WASM builds +#![allow(clippy::manual_is_multiple_of)] + use ark_ff::{PrimeField, Zero}; use num_bigint::{BigInt, BigUint, ToBigInt}; use num_integer::Integer; @@ -330,7 +333,7 @@ pub fn combine_limbs_m_to_n< from_field: Func, x: [V; M], ) -> [V; N] { - assert!(BITSIZE_N.is_multiple_of(BITSIZE_M)); + assert!(BITSIZE_N % BITSIZE_M == 0); let k = BITSIZE_N / BITSIZE_M; let constant_bui = |x: BigUint| from_field(F::from(x)); let disparity: usize = M % k; diff --git a/mvpoly/src/utils.rs b/mvpoly/src/utils.rs index fd503f92d86..7a86ee6cff6 100644 --- a/mvpoly/src/utils.rs +++ b/mvpoly/src/utils.rs @@ -1,3 +1,5 @@ +// We can't use is_multiple_of as it's not available in the older nightly used for WASM builds +#![allow(clippy::manual_is_multiple_of)] //! This module contains functions to work with prime numbers and to compute //! dimension of multivariate spaces @@ -16,12 +18,12 @@ pub fn is_prime(n: usize) -> bool { if n == 2 { return true; } - if n < 2 || n.is_multiple_of(2) { + if n < 2 || n % 2 == 0 { return false; } let mut i = 3; while i * i <= n { - if n.is_multiple_of(i) { + if n % i == 0 { return false; } i += 2; @@ -48,7 +50,7 @@ pub fn naive_prime_factors(n: usize, prime_gen: &mut PrimeNumberGenerator) -> Ve let mut i = 1; let mut p = prime_gen.get_nth_prime(i); while n != 1 { - if n.is_multiple_of(p) { + if n % p == 0 { hash_factors.entry(p).and_modify(|e| *e += 1).or_insert(1); n /= p; } else { @@ -113,7 +115,7 @@ impl PrimeNumberGenerator { let mut i = 1; let mut p = self.get_nth_prime(i); while p * p <= n { - if n.is_multiple_of(p) { + if n % p == 0 { return false; } i += 1; @@ -196,7 +198,7 @@ pub fn compute_all_two_factors_decomposition( let mut i = 1; let mut p = prime_numbers.get_nth_prime(i); while p * p <= n { - if n.is_multiple_of(p) { + if n % p == 0 { let res = n / p; let res_factors = compute_all_two_factors_decomposition(res, cache, prime_numbers); diff --git a/o1vm/src/interpreters/mips/witness.rs b/o1vm/src/interpreters/mips/witness.rs index f9c1cdc78cc..d4e4a885dfa 100644 --- a/o1vm/src/interpreters/mips/witness.rs +++ b/o1vm/src/interpreters/mips/witness.rs @@ -1,3 +1,6 @@ +// We can't use is_multiple_of as it's not available in the older nightly used for WASM builds +#![allow(clippy::manual_is_multiple_of)] + use super::column::{N_MIPS_SEL_COLS, SCRATCH_SIZE, SCRATCH_SIZE_INVERSE}; use crate::{ cannon::{ @@ -1294,7 +1297,7 @@ impl Env { StepFrequency::Never => false, StepFrequency::Always => true, StepFrequency::Exactly(n) => *n == m, - StepFrequency::Every(n) => m.is_multiple_of(*n), + StepFrequency::Every(n) => m % *n == 0, StepFrequency::Range(lo, hi_opt) => { m >= *lo && (hi_opt.is_none() || m < hi_opt.unwrap()) } diff --git a/poly-commitment/src/combine.rs b/poly-commitment/src/combine.rs index df6892c54ac..8a3d83c7abf 100644 --- a/poly-commitment/src/combine.rs +++ b/poly-commitment/src/combine.rs @@ -1,3 +1,5 @@ +// We can't use is_multiple_of as it's not available in the older nightly used for WASM builds +#![allow(clippy::manual_is_multiple_of)] //! Batch elliptic curve algorithms based on the batch-affine principle. //! //! The principle is the following: @@ -26,7 +28,7 @@ use rayon::prelude::*; use std::ops::AddAssign; fn add_pairs_in_place(pairs: &mut Vec>) { - let len = if pairs.len().is_multiple_of(2) { + let len = if pairs.len() % 2 == 0 { pairs.len() } else { pairs.len() - 1 diff --git a/utils/src/foreign_field.rs b/utils/src/foreign_field.rs index 8da5773c43d..d2603acae98 100644 --- a/utils/src/foreign_field.rs +++ b/utils/src/foreign_field.rs @@ -1,3 +1,5 @@ +// We can't use is_multiple_of as it's not available in the older nightly used for WASM builds +#![allow(clippy::manual_is_multiple_of)] //! Describes helpers for foreign field arithmetics //! Generic parameters are as follows: //! - `B` is a bit length of one limb @@ -77,7 +79,7 @@ impl ForeignElement { /// Obtains the big integer representation of the foreign field element pub fn to_biguint(&self) -> BigUint { let mut bytes = vec![]; - if B.is_multiple_of(8) { + if B % 8 == 0 { // limbs are stored in little endian for limb in self.limbs { let crumb = &limb.to_bytes()[0..B / 8]; @@ -91,7 +93,7 @@ impl ForeignElement { bits.extend(&f_bits_lower); } - let bytes_len = if (B * N).is_multiple_of(8) { + let bytes_len = if (B * N) % 8 == 0 { (B * N) / 8 } else { ((B * N) / 8) + 1 @@ -108,7 +110,7 @@ impl ForeignElement { /// elements of type `F` in little-endian. Right now it is written /// so that it gives `N` (limb count) limbs, even if it fits in less bits. fn big_to_vec(fe: BigUint) -> Vec { - if B.is_multiple_of(8) { + if B % 8 == 0 { let bytes = fe.to_bytes_le(); let chunks: Vec<&[u8]> = bytes.chunks(B / 8).collect(); chunks