Skip to content

Commit 380da82

Browse files
TomWambsgansclaude
andauthored
Pin prime subfield koalabear (#264)
* field: pin the prover field's prime subfield to KoalaBear Replace the self-referential bound `EF: ExtensionField<PF<EF>>` (where `PF<EF> = <EF as PrimeCharacteristicRing>::PrimeSubfield`) with a named bound that states what the codebase already relies on: pub trait KoalaBearExtension: Field + ExtensionField<KoalaBear> + PrimeCharacteristicRing<PrimeSubfield = KoalaBear> {} Both accept exactly the same types -- there is one prime field and one extension field in the tree -- so this is a no-op for type checking. What changes is that `PF<EF>` now *normalizes* to the concrete `KoalaBear` instead of remaining an opaque projection, which pays off three ways: 1. Aeneas extraction. The old form made Charon diverge: translating the projection `PF<EF>` needs a proof of `EF: PrimeCharacteristicRing`, and with only that bound in scope the proof was rooted at a predicate that itself mentioned `PF<EF>`. Naming the base concretely removes the cycle at the root. `sumcheck::verify::sumcheck_verify` goes from stack overflow to a 1.3 MB LLBC; `whir::verify` and `lean_prover::verify_execution` also extract. 2. `EF: Algebra<KoalaBear>` now follows from `ExtensionField`'s supertrait, so code can operate on prime-field constants directly. 3. `PF<EF> == KoalaBear` becomes a fact the compiler knows. Clippy immediately flagged the two transmutes in `restore_merkle_paths` as transmutes-to-self, so that `TypeId` assert and both `unsafe` blocks are deleted. 16 `TypeId` sites remain elsewhere and are now provably unnecessary in the same way. Also drops 12 `PF<EF>: TwoAdicField` / `PrimeField64` bounds that the pinning makes redundant. One `WhirConfig` impl keeps its `PF<EF>: TwoAdicField` because it only requires `EF: Field`, so the projection stays opaque there; and `ConstraintFolderPacked`'s `AirBuilder` impl keeps the old bound because its `low_degree_block` override mentions `&mut Self` in a higher-ranked closure bound, where the solver will not look through the blanket-implemented alias. Verified: 66 tests pass, clippy -Dwarnings and rustfmt clean, and the workspace builds under no-SIMD, AVX2 and AVX-512. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * poseidon: drop the add_kb/mul_kb type-punning dispatch `AirBuilder::IF` now requires `Algebra<KoalaBear>` alongside `Algebra<Self::F>`: round constants are plain `KoalaBear` scalars while `Self::F` may be a SIMD packing, so `Algebra<PackedKoalaBear>` gave `+= PackedKoalaBear` but not `+= KoalaBear`. That gap is the entire reason the Poseidon AIR reached for `TypeId` + pointer casts. With the bound in place `add_kb(s, c)` becomes `*s += c` and `mul_kb(x, c)` becomes `x * c`, and both helpers are deleted along with `mds_air_16`'s five-way numeric dispatch -- 55 lines and 11 unsafe pointer casts, replaced by ordinary arithmetic. `mds_air_16` keeps its `SymbolicExpression` check, which is a real semantic fork (the dense matrix makes the zkDSL emit `dot_product_be` instead of Karatsuba), not type recovery. This is what `trace_gen.rs` already did with `F: Algebra<KoalaBear>`; the AIR side can now do the same. Pinning the prime subfield in the previous commit is what made this affordable. `PF<EF>` normalizes to `KoalaBear`, so the normal constraint folder satisfies `Algebra<KoalaBear>` for free and only one obligation propagates -- `EFPacking<EF>: Algebra<KoalaBear>`, since `PackedFieldExtension` supplies `Algebra<KoalaBear::Packing>` but not the unpacked scalar. Adding that to `PackedFieldExtension` directly is not possible: the quintic impl would then need a blanket `Algebra<F>` that overlaps its existing `Algebra<PF>` when the packing degenerates. So the two `Algebra<KoalaBear>`/`From<KoalaBear>` impls for `PackedQuinticExtensionField` are declared per concrete packing, and the bound is carried explicitly through the packed sumcheck path. One call site needed disambiguating: with the new bound in scope the solver has a second `PackedFieldExtension` candidate and can no longer infer the trait's parameters for `to_ext_iter`. Verified: 66 tests pass (including `test_prove_poseidon` and `display_poseidon_air_in_zk_dsl`, which exercise both the numeric and symbolic paths), clippy -Dwarnings and rustfmt clean, no-SIMD/AVX2/AVX-512 all build, and Charon still extracts `sumcheck_verify` and `verify_execution`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * whir: merge the merkle TypeId arms into one generic body `merkle_commit`, `merkle_open` and `merkle_verify` were generic over `<F: Field, EF: ExtensionField<F>>` but each dispatched at runtime on `TypeId::of::<(F, EF)>()` against `(KoalaBear, QuinticExtensionFieldKB)` and `(KoalaBear, KoalaBear)`, transmuting into the concrete types and falling into `unimplemented!()` otherwise. `F` was only ever `PF<EF>`, which now normalizes to `KoalaBear`, so it stops being a parameter. That removes the reason for the dispatch: the two arms were the same code at `BasedVectorSpace::DIMENSION` 5 and 1, and the flattening helpers (`flatten_to_base_arena`, `reconstitute_from_base`, `flatten_to_base`) are already generic over the degree. Each function collapses to a single body generic in `EF`, with the degree-1 case falling out of the reflexive `ExtensionField<F> for F` impl. merkle.rs goes from 224 to 161 lines and from 12 `unsafe` blocks to one (`ArenaVec::uninitialized`, unrelated). Workspace `TypeId::of` sites: 13 -> 7. Verified both degrees are actually exercised, not just compiled: instrumenting `test_run_whir` shows commit/open/verify each running at dim=1 (round 0, base field leaves) and dim=5 (later rounds), and the prove/verify roundtrip passes -- a width or flattening mistake in either path would break the Merkle root. 66 tests pass, clippy -Dwarnings and rustfmt clean, no-SIMD/AVX2/AVX-512 build, and `whir::verify` still extracts through Charon. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * field: unblock Aeneas by removing closures from trait declarations Aeneas rejects a trait declaration whose default method bodies contain closures: the closure types are children of the trait, but reference `Self`, so they land in the same dependency group and Aeneas reports "groups of mixed mutually recursive definitions". Two groups blocked the sumcheck verifier. `PackedFieldExtension::to_ext_iter` loses its default body and becomes a required method. `PackedQuinticExtensionField` already provided one; the reflexive `PackedFieldExtension<F, F> for F::Packing` impl gets an explicit body, which for DIMENSION = 1 reduces to picking lane `i` and so is equivalent to the default it replaces. `RawDataSerializable` is deleted outright rather than rewritten. Every one of its methods and its `NUM_BYTES` constant has zero callers anywhere in the workspace -- it is inherited from Plonky3 and only reached extraction because `Field` listed it as a supertrait. That removes the trait, the two `impl_raw_serializable_primefield{32,64}` macros, and both impls: 307 lines of dead code, and with them the second recursive group. Verified against Aeneas (HEAD 3a8586f, built against Charon 527ea8e3): both recursive groups are gone and Aeneas now proceeds through 62 prepasses into global translation before hitting an unrelated blocker. 66 tests pass, clippy -Dwarnings and rustfmt clean, no-SIMD/AVX2/AVX-512 build. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * field: drop constructs Aeneas cannot extract from the packing traits Two more Aeneas blockers on the sumcheck verifier, both in the packing traits. `PackedFieldExtension` declared `ExtField: ExtensionField<BaseField, ExtensionPacking = Self>`. Aeneas asserts signatures carry no associated-type equality constraints and reports an internal error otherwise. The equality is not needed to compile: every impl satisfies it anyway, and dropping it leaves the workspace building unchanged. `to_ext_iter(iter: impl IntoIterator<Item = Self>) -> impl Iterator<Item = ExtField>` is replaced by `to_ext_lanes(self) -> impl Iterator<Item = ExtField>`. The `impl IntoIterator` argument adds a hidden type parameter to the method, so the `aeneas` preset lifted the return type into an associated type *with* that parameter -- a GAT, which Aeneas cannot extract. Unpacking one element at a time needs no method generics. Eleven of the sixteen call sites passed a single-element array, so they get shorter: `EFPacking::<EF>::to_ext_iter([x])` becomes `x.to_ext_lanes()`. The genuine iterator sites use `.flat_map(_::to_ext_lanes)`, which is what the old body did internally. One site in `air_sumcheck` needs the qualified form because with a generic `EF` both `PackedFieldExtension` impls are candidates. Aeneas now gets past both traits. The remaining blocker is not fixable this way: `Field::Packing` and `ExtensionField::ExtensionPacking` are associated types Charon cannot lift, because `Field`/`PackedField` and `ExtensionField`/`PackedFieldExtension` are mutually recursive -- each names the other. Aeneas cannot handle un-lifted associated types, and the 12 errors it reports all trace back to those two. 66 tests pass, clippy -Dwarnings and rustfmt clean, no-SIMD/AVX2/AVX-512 build. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Tom Wambsgans <TomWambsgans@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent c83b40f commit 380da82

49 files changed

Lines changed: 324 additions & 728 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/backend/air/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ edition.workspace = true
55

66
[dependencies]
77
field = { path = "../field", package = "field" }
8+
koala-bear = { path = "../koala-bear", package = "koala-bear" }
89
poly = { path = "../poly", package = "poly" }

crates/backend/air/src/constraint_folder/normal.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use field::*;
33
use poly::*;
44

55
#[derive(Debug)]
6-
pub struct ConstraintFolder<'a, IF, EF: ExtensionField<PF<EF>>, ExtraData: AlphaPowers<EF>> {
6+
pub struct ConstraintFolder<'a, IF, EF: KoalaBearExtension, ExtraData: AlphaPowers<EF>> {
77
pub flat: &'a [IF],
88
pub shift: &'a [IF],
99
pub extra_data: &'a ExtraData,
@@ -13,7 +13,7 @@ pub struct ConstraintFolder<'a, IF, EF: ExtensionField<PF<EF>>, ExtraData: Alpha
1313

1414
impl<'a, IF, EF, ExtraData> ConstraintFolder<'a, IF, EF, ExtraData>
1515
where
16-
EF: ExtensionField<PF<EF>>,
16+
EF: KoalaBearExtension,
1717
ExtraData: AlphaPowers<EF>,
1818
{
1919
pub fn new(flat: &'a [IF], shift: &'a [IF], extra_data: &'a ExtraData) -> Self {
@@ -30,7 +30,7 @@ where
3030
impl<'a, IF, EF, ExtraData> AirBuilder for ConstraintFolder<'a, IF, EF, ExtraData>
3131
where
3232
IF: Algebra<PF<EF>> + 'static,
33-
EF: Field + ExtensionField<PF<EF>> + Mul<IF, Output = EF> + Add<IF, Output = EF>,
33+
EF: Field + KoalaBearExtension + Mul<IF, Output = EF> + Add<IF, Output = EF>,
3434
ExtraData: AlphaPowers<EF>,
3535
{
3636
type F = PF<EF>;

crates/backend/air/src/constraint_folder/packed.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::*;
22
use field::*;
3+
use koala_bear::KoalaBear;
34
use poly::*;
45

56
#[derive(Debug)]
@@ -38,7 +39,7 @@ where
3839

3940
impl<'a, IF, EF, ExtraData> AirBuilder for ConstraintFolderPacked<'a, IF, EF, ExtraData>
4041
where
41-
IF: Algebra<PFPacking<EF>> + 'static,
42+
IF: Algebra<PFPacking<EF>> + Algebra<KoalaBear> + 'static,
4243
EF: Field + ExtensionField<PF<EF>>,
4344
EFPacking<EF>: PrimeCharacteristicRing + Mul<IF, Output = EFPacking<EF>> + Add<IF, Output = EFPacking<EF>>,
4445
ExtraData: AlphaPowers<EF>,

crates/backend/air/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use core::ops::{Add, Mul, Sub};
44
use field::{Algebra, PrimeCharacteristicRing};
5+
use koala_bear::KoalaBear;
56

67
mod symbolic;
78
pub use symbolic::*;
@@ -36,7 +37,7 @@ pub trait AirBuilder: Sized {
3637
type F: PrimeCharacteristicRing + 'static;
3738
/// Intermediate field: equals F in base-field rounds, EF in extension rounds
3839
/// (or their respective SIMD packings).
39-
type IF: Algebra<Self::F> + 'static;
40+
type IF: Algebra<Self::F> + Algebra<KoalaBear> + 'static;
4041
/// Always the extension field (or its SIMD packing).
4142
type EF: PrimeCharacteristicRing
4243
+ 'static

crates/backend/air/src/symbolic.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use core::marker::PhantomData;
77
use core::ops::{Add, AddAssign, Deref, Mul, MulAssign, Neg, Sub, SubAssign};
88

99
use field::{Algebra, Field, InjectiveMonomial, PrimeCharacteristicRing};
10+
use koala_bear::KoalaBear;
1011

1112
use crate::{Air, AirBuilder};
1213

@@ -284,7 +285,10 @@ impl<F: Field> SymbolicAirBuilder<F> {
284285
}
285286
}
286287

287-
impl<F: Field> AirBuilder for SymbolicAirBuilder<F> {
288+
impl<F: Field> AirBuilder for SymbolicAirBuilder<F>
289+
where
290+
SymbolicExpression<F>: Algebra<KoalaBear>,
291+
{
288292
type F = F;
289293
type IF = SymbolicExpression<F>;
290294
type EF = SymbolicExpression<F>;
@@ -325,6 +329,7 @@ pub type SymbolicAirData<F> = (
325329
pub fn get_symbolic_constraints_and_bus_data_values<F: Field, A: Air>(air: &A) -> SymbolicAirData<F>
326330
where
327331
A::ExtraData: Default,
332+
SymbolicExpression<F>: Algebra<KoalaBear>,
328333
{
329334
let mut builder = SymbolicAirBuilder::<F>::new(air.n_columns(), air.n_shift_columns());
330335
air.eval(&mut builder, &Default::default());

crates/backend/fiat-shamir/src/prover.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use crate::{MerklePaths, PrunedMerklePaths, *};
33
use field::Field;
44
use field::PackedValue;
55
use field::PrimeCharacteristicRing;
6+
use field::PrimeField64;
67
use field::integers::QuotientMap;
7-
use field::{ExtensionField, PrimeField64};
8+
use koala_bear::KoalaBearExtension;
89
use koala_bear::symmetric::Permutation;
910
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
1011
use std::time::Duration;
@@ -24,16 +25,13 @@ pub fn reset_pow_grinding_time() {
2425
}
2526

2627
#[derive(Debug)]
27-
pub struct ProverState<EF: ExtensionField<PF<EF>>, P> {
28+
pub struct ProverState<EF: KoalaBearExtension, P> {
2829
challenger: Challenger<PF<EF>, P>,
2930
transcript: Vec<PF<EF>>,
3031
merkle_paths: Vec<PrunedMerklePaths<PF<EF>, PF<EF>>>,
3132
}
3233

33-
impl<EF: ExtensionField<PF<EF>>, P: Permutation<[PF<EF>; WIDTH]>> ProverState<EF, P>
34-
where
35-
PF<EF>: PrimeField64,
36-
{
34+
impl<EF: KoalaBearExtension, P: Permutation<[PF<EF>; WIDTH]>> ProverState<EF, P> {
3735
#[must_use]
3836
pub fn new(permutation: P, capacity: [PF<EF>; CAPACITY]) -> Self {
3937
assert!(EF::DIMENSION <= RATE);
@@ -52,10 +50,7 @@ where
5250
}
5351
}
5452

55-
impl<EF: ExtensionField<PF<EF>>, P: Permutation<[PF<EF>; WIDTH]>> ChallengeSampler<EF> for ProverState<EF, P>
56-
where
57-
PF<EF>: PrimeField64,
58-
{
53+
impl<EF: KoalaBearExtension, P: Permutation<[PF<EF>; WIDTH]>> ChallengeSampler<EF> for ProverState<EF, P> {
5954
fn sample_vec(&mut self, len: usize) -> Vec<EF> {
6055
sample_vec(&mut self.challenger, len)
6156
}
@@ -65,10 +60,8 @@ where
6560
}
6661
}
6762

68-
impl<EF: ExtensionField<PF<EF>>, P: Permutation<[PF<EF>; WIDTH]> + Permutation<[<PF<EF> as Field>::Packing; WIDTH]>>
63+
impl<EF: KoalaBearExtension, P: Permutation<[PF<EF>; WIDTH]> + Permutation<[<PF<EF> as Field>::Packing; WIDTH]>>
6964
FSProver<EF> for ProverState<EF, P>
70-
where
71-
PF<EF>: PrimeField64,
7265
{
7366
fn add_base_scalars(&mut self, scalars: &[PF<EF>]) {
7467
self.challenger.observe_many(scalars);

crates/backend/fiat-shamir/src/traits.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use field::ExtensionField;
1+
use koala_bear::KoalaBearExtension;
22

33
use crate::{
44
MerkleOpening, MerklePath, PF, ProofError, ProofResult, flatten_scalars_to_base, pack_scalars_to_extension,
@@ -12,7 +12,7 @@ pub trait ChallengeSampler<EF> {
1212
fn sample_in_range(&mut self, bits: usize, n_samples: usize) -> Vec<usize>;
1313
}
1414

15-
pub trait FSProver<EF: ExtensionField<PF<EF>>>: ChallengeSampler<EF> {
15+
pub trait FSProver<EF: KoalaBearExtension>: ChallengeSampler<EF> {
1616
fn state(&self) -> String;
1717
fn add_base_scalars(&mut self, scalars: &[PF<EF>]);
1818
fn observe_scalars(&mut self, scalars: &[PF<EF>]);
@@ -43,7 +43,7 @@ pub trait FSProver<EF: ExtensionField<PF<EF>>>: ChallengeSampler<EF> {
4343
}
4444
}
4545

46-
pub trait FSVerifier<EF: ExtensionField<PF<EF>>>: ChallengeSampler<EF> {
46+
pub trait FSVerifier<EF: KoalaBearExtension>: ChallengeSampler<EF> {
4747
fn state(&self) -> String;
4848
fn next_base_scalars_vec(&mut self, n: usize) -> Result<Vec<PF<EF>>, ProofError>;
4949
fn observe_scalars(&mut self, scalars: &[PF<EF>]);

crates/backend/fiat-shamir/src/verifier.rs

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ use crate::{
55
*,
66
};
77
use field::PrimeCharacteristicRing;
8-
use field::{ExtensionField, PrimeField64};
8+
use field::PrimeField64;
9+
use koala_bear::KoalaBearExtension;
910
use koala_bear::symmetric::Permutation;
1011
use koala_bear::{KoalaBear, default_koalabear_poseidon1_16};
11-
use std::any::TypeId;
1212
use std::collections::VecDeque;
1313
use std::iter::repeat_n;
1414
use symetric::CAPACITY;
1515
use symetric::RATE;
1616
use symetric::WIDTH;
1717

18-
pub struct VerifierState<EF: ExtensionField<PF<EF>>, P> {
18+
pub struct VerifierState<EF: KoalaBearExtension, P> {
1919
challenger: Challenger<PF<EF>, P>,
2020
transcript: Vec<PF<EF>>,
2121
transcript_offset: usize,
@@ -25,10 +25,7 @@ pub struct VerifierState<EF: ExtensionField<PF<EF>>, P> {
2525
raw_transcript: Vec<PF<EF>>, // reconstructed during the proof verification, it's the format that the zkVM recursion program expects (no Merkle pruning, no sumcheck optimization to send less data, etc)
2626
}
2727

28-
impl<EF: ExtensionField<PF<EF>>, P: Permutation<[PF<EF>; WIDTH]>> VerifierState<EF, P>
29-
where
30-
PF<EF>: PrimeField64,
31-
{
28+
impl<EF: KoalaBearExtension, P: Permutation<[PF<EF>; WIDTH]>> VerifierState<EF, P> {
3229
pub fn new(proof: Proof<PF<EF>>, permutation: P, capacity: [PF<EF>; CAPACITY]) -> Result<Self, ProofError> {
3330
Ok(Self {
3431
challenger: Challenger::new(permutation, capacity),
@@ -75,16 +72,12 @@ where
7572
Ok(scalars)
7673
}
7774

78-
#[allow(clippy::missing_transmute_annotations)]
7975
fn restore_merkle_paths(
80-
paths: PrunedMerklePaths<PF<EF>, PF<EF>>,
76+
paths: PrunedMerklePaths<KoalaBear, KoalaBear>,
8177
indices: &[usize],
8278
merkle_height: usize,
8379
leaf_len: usize,
84-
) -> Option<Vec<MerkleOpening<PF<EF>>>> {
85-
assert_eq!(TypeId::of::<PF<EF>>(), TypeId::of::<KoalaBear>());
86-
// SAFETY: We've confirmed PF<EF> == KoalaBear
87-
let paths: PrunedMerklePaths<KoalaBear, KoalaBear> = unsafe { std::mem::transmute(paths) };
80+
) -> Option<Vec<MerkleOpening<KoalaBear>>> {
8881
let perm = default_koalabear_poseidon1_16();
8982
let hash_fn = |data: &[KoalaBear]| symetric::hash_slice_rtl::<_, _, 16, 8, DIGEST_LEN_FE>(&perm, data);
9083
let combine_fn = |left: &[KoalaBear; DIGEST_LEN_FE], right: &[KoalaBear; DIGEST_LEN_FE]| {
@@ -100,15 +93,11 @@ where
10093
path: path.sibling_hashes,
10194
})
10295
.collect();
103-
// SAFETY: PF<EF> == KoalaBear
104-
Some(unsafe { std::mem::transmute(openings) })
96+
Some(openings)
10597
}
10698
}
10799

108-
impl<EF: ExtensionField<PF<EF>>, P: Permutation<[PF<EF>; WIDTH]>> ChallengeSampler<EF> for VerifierState<EF, P>
109-
where
110-
PF<EF>: PrimeField64,
111-
{
100+
impl<EF: KoalaBearExtension, P: Permutation<[PF<EF>; WIDTH]>> ChallengeSampler<EF> for VerifierState<EF, P> {
112101
fn sample_vec(&mut self, len: usize) -> Vec<EF> {
113102
sample_vec(&mut self.challenger, len)
114103
}
@@ -117,10 +106,7 @@ where
117106
}
118107
}
119108

120-
impl<EF: ExtensionField<PF<EF>>, P: Permutation<[PF<EF>; WIDTH]>> FSVerifier<EF> for VerifierState<EF, P>
121-
where
122-
PF<EF>: PrimeField64,
123-
{
109+
impl<EF: KoalaBearExtension, P: Permutation<[PF<EF>; WIDTH]>> FSVerifier<EF> for VerifierState<EF, P> {
124110
fn state(&self) -> String {
125111
format!(
126112
"state {} (offset: {}, merkle_idx: {})",

crates/backend/field/src/field.rs

Lines changed: 1 addition & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ use core::fmt::{Debug, Display};
66
use core::hash::Hash;
77
use core::iter::{Product, Sum};
88
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
9-
use core::{array, slice};
9+
use core::slice;
1010

1111
use serde::Serialize;
1212
use serde::de::DeserializeOwned;
13-
use utils::iter_array_chunks_padded;
1413

1514
use crate::exponentiation::bits_u64;
1615
use crate::integers::{QuotientMap, from_integer_types};
@@ -623,112 +622,12 @@ pub trait Algebra<F>:
623622
// Every ring is an algebra over itself.
624623
impl<R: PrimeCharacteristicRing> Algebra<R> for R {}
625624

626-
/// A collection of methods designed to help hash field elements.
627-
///
628-
/// Most fields will want to reimplement many/all of these methods as the default implementations
629-
/// are slow and involve converting to/from byte representations.
630-
pub trait RawDataSerializable: Sized {
631-
/// The number of bytes which this field element occupies in memory.
632-
/// Must be equal to the length of self.into_bytes().
633-
const NUM_BYTES: usize;
634-
635-
/// Convert a field element into a collection of bytes.
636-
#[must_use]
637-
fn into_bytes(self) -> impl IntoIterator<Item = u8>;
638-
639-
/// Convert an iterator of field elements into an iterator of bytes.
640-
#[must_use]
641-
fn into_byte_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u8> {
642-
input.into_iter().flat_map(|elem| elem.into_bytes())
643-
}
644-
645-
/// Convert an iterator of field elements into an iterator of u32s.
646-
///
647-
/// If `NUM_BYTES` does not divide `4`, multiple `F`s may be packed together to make a single `u32`. Furthermore,
648-
/// if `NUM_BYTES * input.len()` does not divide `4`, the final `u32` will involve padding bytes which are set to `0`.
649-
#[must_use]
650-
fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
651-
let bytes = Self::into_byte_stream(input);
652-
iter_array_chunks_padded(bytes, 0).map(u32::from_le_bytes)
653-
}
654-
655-
/// Convert an iterator of field elements into an iterator of u64s.
656-
///
657-
/// If `NUM_BYTES` does not divide `8`, multiple `F`s may be packed together to make a single `u64`. Furthermore,
658-
/// if `NUM_BYTES * input.len()` does not divide `8`, the final `u64` will involve padding bytes which are set to `0`.
659-
#[must_use]
660-
fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
661-
let bytes = Self::into_byte_stream(input);
662-
iter_array_chunks_padded(bytes, 0).map(u64::from_le_bytes)
663-
}
664-
665-
/// Convert an iterator of field element arrays into an iterator of byte arrays.
666-
///
667-
/// Converts an element `[F; N]` into the byte array `[[u8; N]; NUM_BYTES]`. This is
668-
/// intended for use with vectorized hash functions which use vector operations
669-
/// to compute several hashes in parallel.
670-
#[must_use]
671-
fn into_parallel_byte_streams<const N: usize>(
672-
input: impl IntoIterator<Item = [Self; N]>,
673-
) -> impl IntoIterator<Item = [u8; N]> {
674-
input.into_iter().flat_map(|vector| {
675-
let bytes = vector.map(|elem| elem.into_bytes().into_iter().collect::<Vec<_>>());
676-
(0..Self::NUM_BYTES).map(move |i| array::from_fn(|j| bytes[j][i]))
677-
})
678-
}
679-
680-
/// Convert an iterator of field element arrays into an iterator of u32 arrays.
681-
///
682-
/// Converts an element `[F; N]` into the u32 array `[[u32; N]; NUM_BYTES/4]`. This is
683-
/// intended for use with vectorized hash functions which use vector operations
684-
/// to compute several hashes in parallel.
685-
///
686-
/// This function is guaranteed to be equivalent to starting with `Iterator<[F; N]>` performing a transpose
687-
/// operation to get `[Iterator<F>; N]`, calling `into_u32_stream` on each element to get `[Iterator<u32>; N]` and then
688-
/// performing another transpose operation to get `Iterator<[u32; N]>`.
689-
///
690-
/// If `NUM_BYTES` does not divide `4`, multiple `[F; N]`s may be packed together to make a single `[u32; N]`. Furthermore,
691-
/// if `NUM_BYTES * input.len()` does not divide `4`, the final `[u32; N]` will involve padding bytes which are set to `0`.
692-
#[must_use]
693-
fn into_parallel_u32_streams<const N: usize>(
694-
input: impl IntoIterator<Item = [Self; N]>,
695-
) -> impl IntoIterator<Item = [u32; N]> {
696-
let bytes = Self::into_parallel_byte_streams(input);
697-
iter_array_chunks_padded(bytes, [0; N]).map(|byte_array: [[u8; N]; 4]| {
698-
array::from_fn(|i| u32::from_le_bytes(array::from_fn(|j| byte_array[j][i])))
699-
})
700-
}
701-
702-
/// Convert an iterator of field element arrays into an iterator of u64 arrays.
703-
///
704-
/// Converts an element `[F; N]` into the u64 array `[[u64; N]; NUM_BYTES/8]`. This is
705-
/// intended for use with vectorized hash functions which use vector operations
706-
/// to compute several hashes in parallel.
707-
///
708-
/// This function is guaranteed to be equivalent to starting with `Iterator<[F; N]>` performing a transpose
709-
/// operation to get `[Iterator<F>; N]`, calling `into_u64_stream` on each element to get `[Iterator<u64>; N]` and then
710-
/// performing another transpose operation to get `Iterator<[u64; N]>`.
711-
///
712-
/// If `NUM_BYTES` does not divide `8`, multiple `[F; N]`s may be packed together to make a single `[u64; N]`. Furthermore,
713-
/// if `NUM_BYTES * input.len()` does not divide `8`, the final `[u64; N]` will involve padding bytes which are set to `0`.
714-
#[must_use]
715-
fn into_parallel_u64_streams<const N: usize>(
716-
input: impl IntoIterator<Item = [Self; N]>,
717-
) -> impl IntoIterator<Item = [u64; N]> {
718-
let bytes = Self::into_parallel_byte_streams(input);
719-
iter_array_chunks_padded(bytes, [0; N]).map(|byte_array: [[u8; N]; 8]| {
720-
array::from_fn(|i| u64::from_le_bytes(array::from_fn(|j| byte_array[j][i])))
721-
})
722-
}
723-
}
724-
725625
/// A field `F`. This permits both modular fields `ℤ/p` along with their field extensions.
726626
///
727627
/// A ring is a field if every element `x` has a unique multiplicative inverse `x^{-1}`
728628
/// which satisfies `x * x^{-1} = F::ONE`.
729629
pub trait Field:
730630
Algebra<Self>
731-
+ RawDataSerializable
732631
+ Packable
733632
+ 'static
734633
+ Copy

0 commit comments

Comments
 (0)