Skip to content

fgf 3.0.1

Latest

Choose a tag to compare

@nanithefkuc nanithefkuc released this 20 Oct 02:09
· 204 commits to main since this release
94b6ff4

3.0.1 is the first supported v3 release. The 3.0.0 published before it went
out by accident and was yanked; 3.0.1 is not API-compatible with that artifact
(see the 3.0.0 entry), and code locked to it must migrate. The supported
upgrade path is from 2.x: follow
Migrating from 2.x
and the breaking entries below.

Added

  • The canonical generic field family FiniteField<const P: u64, const N: u32, R: FiniteFieldRepr<P, N> = Residue> with the Residue presentation at
    degree one over every u64 prime. Each row exposes the full scalar and
    const element surface (from_raw, checked from_residue, to_residue,
    arithmetic, pow, canonical),
    total arithmetic under the crate-wide conventions (inv(0) == 0,
    x / 0 == 0, 0^0 == 1, with the explicit inverse-zero branch at
    P = 2), a little-endian wire lane sized to the characteristic —
    characteristic two uses an eight-byte lane, and an odd characteristic
    uses one, two, four, or eight bytes as its residues fit within 2^8,
    2^16, 2^32, and u64 — with FieldBuffer::decode/encode as the
    byte API of these rows, the checked packed
    operation surface with prepared coefficients, and vector routing on
    capable x86-64 hosts — AVX2 single-row kernels, AVX-512 under simd512 —
    with Scalar routing elsewhere. Broadcast add/sub take the modular path
    for every characteristic, so packed lanes stay canonical at P = 2.
    Values live in
    field::finite_field, re-exported at the root.
  • Sealed PrimeField marker for degree-one fields, the validated const
    integer reductions field::prime::reduce and reduce_wide, RangeError
    for out-of-range conversions, and the PrimeIdentity characteristic
    facts BITS, TWO_ADICITY, and RESIDUE_MOD_8.
  • just compile-fail compiles the negative consumer snippets under
    tests/compile_fail/ on the crate MSRV, each required to fail with its
    declared crate panic fragment, or simply to be rejected for trait-bound
    and privacy cases, and just msrv-accept runs
    those snippets plus the tests/consumers.rs compile-and-run matrix on
    the MSRV toolchain.
  • Wiki source guides cover the generic type model, field presentations,
    embeddings, custom towers and scalar fields, packed workflows, preparation,
    prime and bit-packed arithmetic, deployment, and migration from 2.x.
    wiki/Home.md and the sidebar organize the reader paths.
  • Sealed presentations MersenneFold (label mersenne-fold) and
    GoldilocksFold (label goldilocks-fold), re-exported at the root. Both
    rows implement PrimeField and gain const from_residue(u64) -> Result<Self, RangeError> and to_residue(self) -> Option<u64>. The
    default Residue row at either modulus remains a distinct type with its
    own lane width; values move between the two by residue conversion.
  • The binary degree-one rows FiniteField<2, 1, R> implement PrimeField
    and gain const from_residue(u64) -> Result<Self, RangeError> and
    to_residue(self) -> Option<u64>; they stay distinct from
    FiniteField<2, 1, Residue>, which stores a u64 residue.
  • just external-check type-checks every package under external/
    against the working copy.
  • The generic extension presentation FiniteField<P, N, Extension<S, D>>
    with data-only ExtensionSpec providers, the sealed storage family
    (Components, Packed, PackedPadded), the opaque const-constructible
    Relation, generic arithmetic under the crate-wide total conventions,
    component bytes and the checked packed surface with Scalar routing,
    ExtensionField component conversions, and BinaryField on
    characteristic-two rows over binary bases. The surface lives in
    field::extension, re-exported at the root. EmbeddingError gains the
    NoCanonicalMap variant for dividing degrees with no canonical map.
  • ComplexMersenne31, the ExtensionSpec<2> of QuadMersenne31:
    Mersenne31 extended by t^2 + 1 with Components storage,
    re-exported at the root.
  • An extension row whose base presentation, relation, and storage equal a
    shipped instance's runs that instance's specialized scalar arithmetic and
    reaches its kernel arms; every other extension row runs the generic body
    and reports Scalar.
  • FieldElem::from_residue/to_residue and from_index/to_index on
    every row: the prime-subfield value and the presentation index share one
    generic body over the crate-private row hooks, and the inherent const
    residue constructors check through the same bound.
  • The characteristic-independent relation surface in field::embedding,
    re-exported at the root: Embedding<S, T> over every pair of rows of
    equal characteristic whose degrees divide, with from_images,
    to_images, generator_count, generator, then, and
    Isomorphism<S, T> with apply, a total unapply,
    inverse, and composition; and the NoCanonicalMap and InvalidImages
    variants of EmbeddingError. Maps come from structural inclusions, the
    frozen binary ladder, or validated caller images; every pre-cutover
    binary result is unchanged.
  • Wiki reference for operation suffixes, destination behavior, prepared state,
    row addressing, and allocation.
  • One-time field migration verification is recorded in
    Issue #41, rather than a
    permanent expanded regression corpus.
  • Behavioral regressions cover irreducible and reducible extension relations,
    relation-field arithmetic, ordered-basis subfield embeddings, rejected
    restrictions and degree mismatches, and quadratic prime identity predicates.
  • Raw kernel dispatch is unreachable outside the crate: every FieldKernels
    kernel entry takes the crate-private RawDispatch proof argument, so code
    holding an F: FieldKernels bound — including under internals — cannot
    call the raw entries. The negative consumer snippet
    tests/compile_fail/raw_dispatch_without_proof.rs pins the rejection.
  • Three examples join the educational set, each running against the library
    with std and alloc disabled: custom_extensions defines a custom
    ExtensionSpec field, basis_maps moves values through Embedding
    between basis presentations, and packed_no_alloc runs packed row
    operations without an allocator. just examples-portable runs them in
    that configuration.
  • just release-accept runs the crate-specific release acceptance, separate
    from the shared pull-request gate just validate. Its pieces also stand
    alone: just test-gather-validation-32 runs the gather validation as a
    release i686 build with overflow checks disabled — the configuration the
    gather fix below required — and CI runs it as its own job;
    just benchmark-check validates portable benchmark fixtures and compares
    their inventory with compiler-derived public API declarations;
    just benchmark-check-native validates the GF16 presentation comparisons
    and existing native geometries on capable hosts. just isa-accept EXPECTED
    requires the requested process backend and positive execution evidence
    before running the full tier matrix. Native release acceptance uses
    dedicated Willow Cove (v4x) and Golden Cove (v3_gfni_crypto) hosts.
  • The surfaces benchmark artifact measures the public API end to end:
    scalar arithmetic, packed single-row and multi-row operations, prepared
    coefficient forms, and Embedding/Isomorphism maps, over representative
    fields including the AES byte field, the Rijndael sixteen tower, and the
    MersenneFold/GoldilocksFold prime rows. --inventory prints every
    registered measurement without timing, --check runs each fixture's
    correctness check once, and --smoke shortens repetition without
    dropping cases. Each timed record names its public callable paths, exact
    registered field label, scope, logical byte numerator, lane and
    source/destination counts, and the resolved backend; a byte-XOR control
    identifies itself with control and phase fields, and zero-work APIs
    report latency instead of throughput.
  • The native GF16 comparison gains --presentations, a separate output mode
    beside the legacy format so existing parsing is unchanged. It covers
    representative shipped Rijndael and Fan-Paar fields, custom RS-rooted
    fields, normal and Cantor bases, and competitor-matched fields, with
    duplicate fgf control arms, interleaved arms and fixed/cycling
    coefficients, and every map and fixture validated outside timing;
    --presentations --check validates every new geometry without timing,
    and --presentations --smoke shortens the sampling budget without
    dropping a registered case. Both output modes open with a
    BENCHMARK_MODE banner (full, smoke, or check), and each
    GF16_SURFACE record carries its sample count and calibrated batch size
    as samples and batch_reps. Presentation conversions run public scalar
    caller loops.
  • The capture family surfaces records the artifact and the GF16
    --presentations mode for current v3 in five rounds per host, published
    in the v3 record (benchmarks/v3/public-api.md, benchmarks/v3/maps.md,
    and the GF16 presentation panels). No released-v2 counterpart is
    fabricated for the new public APIs.

Changed

  • Breaking: generic residue rows size their byte lane to the
    characteristic instead of always storing eight bytes: characteristic
    two keeps an eight-byte lane, and an odd characteristic uses one, two,
    four, or eight bytes as its residues fit within 2^8, 2^16, 2^32,
    and u64 — for example FiniteField<7, 1> moves one byte per element
    and FiniteField<1_000_000_007, 1> moves four. FieldBuffer::decode
    and encode are the byte API of these rows. Migration: the inherent
    fixed-array from_bytes/to_bytes are absent for these rows (every
    characteristic, P = 2 included), and no const byte form exists for
    them — size buffers from FieldBuffer::BYTES, decode and encode
    through FieldBuffer, and in const code build from from_raw with
    u64::from_le_bytes and read back through to_raw. Extensions over a
    residue base shrink with the base lane; the named prime rows, binary
    rows, towers, and QuadMersenne31 keep their lane widths and fixed-array
    methods.
  • Breaking: Mersenne31 and Goldilocks are type aliases of the
    canonical family rows FiniteField<0x7FFF_FFFF, 1, MersenneFold> and
    FiniteField<0xFFFF_FFFF_0000_0001, 1, GoldilocksFold> instead of unit
    marker structs. Moduli, raw widths, bytes, generators, arithmetic, and
    kernel routing are unchanged. The aliases are no longer value
    expressions: replace Mersenne31 or Goldilocks used as a value with
    Mersenne31::default() (or drop the value where only the type was
    needed). Marker Debug now prints the family spelling, e.g.
    FiniteField<2147483647, 1, mersenne-fold>. Kernel receivers move to the
    rows with the aliases, so FieldKernels calls through the alias names
    compile unchanged.
  • Breaking: the Binary<N, R> marker is removed without an alias;
    binary fields are the canonical family rows FiniteField<2, N, R>.
    Replace Binary<8, Polynomial<AES>> with FiniteField<2, 8, Polynomial<AES>> and Binary::<…> with FiniteField::<2, …>, and
    import FiniteField instead of Binary. Raw widths, bytes, descriptors,
    coordinates, embeddings, bit-packed buffers, and kernel routing are
    unchanged.
  • Breaking: BinaryRepr<const N: u32> and BinaryDegree<const N: u32>
    take u32 degree parameters instead of u8; generic code declaring
    const N: u8 against them changes the parameter type.
  • Breaking: BinaryRepr now extends FiniteFieldRepr<2, N>, which
    owns NAME and VALID. Replace <R as BinaryRepr<N>>::NAME and
    ::VALID with <R as FiniteFieldRepr<2, N>>::NAME and ::VALID;
    DESCRIPTION and LOG_EXP stay on BinaryRepr.
  • Breaking: binary marker Debug prints the family spelling with the
    presentation label, e.g. FiniteField<2, 8, GF(2^8)/0x11B>, instead of
    the label alone. Element Debug and every wire format are unchanged.
  • Breaking: binary rows validate their defining data at every entry
    point: ZERO_RAW, ONE_RAW, and every raw Field method now fail const
    evaluation for an invalid polynomial or basis, as from_raw already did.
    Valid presentations are unaffected.
  • Breaking: Field, HasGenerator, and FieldBuffer are sealed.
    Implementing any of them outside the crate no longer compiles. Migrate a
    custom prime field to the family's degree-one row FiniteField<P, 1>
    (the default Residue presentation) at any checked u64 prime: it
    supplies Field, PrimeField, FieldBuffer, the checked packed
    operation surface, and the const element API. Migrate a custom
    extension to an ExtensionSpec over a crate row.
  • Breaking: the shipped towers are extension rows: FiniteField<2, N, Tower<S>> is spelled FiniteField<2, N, Extension<S, 2>> for S in
    Rijndael16, Rijndael32, Rijndael64, and FanPaar2 through
    FanPaar64, each now an ExtensionSpec<2> with Packed<W> storage
    (PackedPadded<u8> for FanPaar2 and FanPaar4). Raw words, bytes,
    coordinate words, generators, embeddings, and kernel routing are
    unchanged, and each instance keeps its const element surface and
    mul_alpha. Replace Tower<S> with Extension<S, 2> and import
    Extension.
  • Breaking: the wide shipped instances' component conversions take
    and return arrays: Elem::<F>::from_components(a, b) becomes
    from_components([a, b]) and to_components() returns [a, b] instead
    of (a, b), matching ExtensionField<2>.
  • Breaking: towers leave BinaryRepr: BinaryRepr<N> covers the flat
    presentations only, and no flat presentation exists at degrees 16, 32,
    and 64. Replace generic bounds R: BinaryRepr<N> that reached towers with
    field-level bounds (F: BinaryDegree<N> or F: BinaryField) and
    <Tower<S> as BinaryRepr<N>>::DESCRIPTION with F::DESCRIPTION.
  • Breaking: QuadMersenne31 is a type alias of
    FiniteField<0x7FFF_FFFF, 2, Extension<ComplexMersenne31, 2>> instead of
    a unit marker struct, and its raw word is [u32; 2] instead of
    (u32, u32), with the same limbs in the same order. Replace
    Elem::<QuadMersenne31>::from_raw(re, im) with from_raw([re, im]),
    to_raw().0 and .1 with to_raw()[0] and [1], from_components(re, im) with from_components([re, im]), and tuple destructuring of
    to_components() with array destructuring. Element Display prints
    [re, im] in the base field's form instead of (re+imi); bytes,
    arithmetic, the generator, I, conjugate, norm, and kernel routing
    are unchanged. Replace QuadMersenne31 used as a value with
    QuadMersenne31::default().
  • BinaryDescription::inv takes canonical coordinate words. On a
    polynomial-root description, a word with bits at or above degree()
    inverts its low degree() bits instead of returning an unspecified
    value; on other roots such a word still gives an unspecified result.
    Results on canonical words are unchanged.
  • Breaking: FieldElem owns the residue and index conversions
    from_residue/to_residue and from_index/to_index, shared by every
    row. BinaryField::to_coordinates/from_coordinates are removed: use
    to_index/from_index, identical words below degree 64 widened to
    u128. CoordinateError is replaced by fgf::RangeError (also
    fgf::field::RangeError). Residues and indices are distinct: the index
    of one is the presentation's coordinate encoding of one.
  • Binary embedding evaluation no longer uses precomputed linear columns:
    maps evaluate by Horner substitution and restrict through trace-dual
    bases, with unchanged results on every pair.
  • Breaking: the field::binary embedding paths are removed without
    an alias: fgf::field::binary::embedding, Embedding, and
    EmbeddingError under it. Import from the crate root or
    field::embedding instead; the struct bounds widen from BinaryField
    to Field, and Embedding keeps Clone, Copy, and Debug.
  • The dependency lock records published sources for locked MSRV checks;
    umbrella-local patch resolution is excluded from the publication lock.
  • Public documentation leads with FiniteField, its representations, and
    Elem<F>; named prime families appear as specializations. Wiki guides
    follow field selection, scalar arithmetic, packing, row operations,
    preparation, and deployment, with task-oriented navigation and a custom
    prime-base extension example.
  • Benchmark publication preserves the complete public-operation, field-map,
    GF16-presentation, size-sweep, and competitor inventory in task-oriented
    pages. Shared geometry is prose; varying counts occupy named columns.
    Exact callable paths, setup, resolved backends, and controls are expandable.
    SVG overviews complement exact figures. Public v2 and comparison pages are
    removed; their samples remain in raw campaign evidence.
  • Wiki guides use 3.0.1 as the base v3 release and lead from field construction
    and arithmetic through presentations, embeddings, and custom fields.
    Migration guidance goes directly from 2.x to 3.0.1.
  • Wiki navigation groups the reading path in the home page and sidebar instead
    of per-page Next: footers.
  • AVX-512 generic residue kernels under simd512: nibble-table u8,
    Shoup and Barrett u32, Montgomery u64, and delayed-reduction prepared
    matrices. Capable residue rows report V4x; short rows retain narrower
    or portable routes, and zero/unit coefficient byte behavior is unchanged.
  • Four-byte generic residue rows vectorize elementwise multiplication on
    AVX2-capable x86 hosts.
  • One-byte generic residue rows at moduli up to 127 vectorize prepared
    fixed-coefficient scaling through nibble-table lookups, four-byte rows
    through Shoup multiplication, and eight-byte rows at odd moduli through
    doubleword Montgomery multiplication; those rows report the vector
    backend, and vector-routed operations produce byte-identical output to
    the portable path on every input, applying the documented zero/unit
    shortcuts before vector dispatch.
  • Four-byte generic residue rows delay reduction across shared sources in
    prepared overwrite/accumulate four-output matrices with enough shared
    sources and modulus headroom, as recorded in
    the residue benchmark record, with delayed
    accumulation falling back to the repeated single-row path when an output
    row's coefficients are all zero.
  • Operation implementations move from ops.rs into the ops/ coefficient,
    single-row, scatter, gather, matrix, and packing modules, retaining public
    ops::* paths. Byte dispatch moves into kernel/bytes.rs.
  • Generic residue single-row AVX2 kernels move from residue/avx2/single.rs
    into residue/avx2/single/{u8,u32,u64}.rs.
  • Breaking: Unstable residue kernel entries use u8, u32, and u64
    lane names instead of byte, word, and doubleword; WordParams
    becomes U32Params. Migrate direct internals callers to the explicit
    lane-width spellings.
  • Breaking: Unstable residue routing queries report an actual
    Backend through single_row_backend and delayed_matrix_backend.
    Replace boolean selector calls with comparisons to Backend::Scalar;
    use avx2_floor_op_len for the AVX2-specific row floor.

Removed

  • Breaking: Tower, TowerSpec, and TowerGeneratorSpec are removed
    without an alias. A custom tower becomes an ExtensionSpec<2>: impl TowerSpec for S with LINEAR_COEFFICIENT = A and
    CONSTANT_COEFFICIENT = B becomes impl ExtensionSpec<2> for S with
    the same Base and NAME, type Storage = Packed<W> at the field's
    width (PackedPadded<u8> below one byte), and const RELATION: Relation = Relation::from_binary_words::<Base>(&[B, A]) — constant coefficient
    first, the reverse of the old field order. The row is
    FiniteField<2, N, Extension<S, 2>>.
  • Breaking: custom extension rows carry no generator:
    TowerGeneratorSpec has no replacement, and HasGenerator belongs to the
    shipped instances only. Request a shipped instance for a presentation that
    needs a checked generator.
  • Breaking: custom extension rows have no const element surface:
    from_raw, from_bytes, to_bytes, the arithmetic methods, and the
    component conversions that custom towers exposed as const fn are gone.
    Use the FieldElem methods and operators, FieldBuffer::decode and
    encode, and ExtensionField::from_components and to_components at
    run time; Elem::ZERO, Elem::ONE, and to_raw stay const.
  • The wiki migration guide written for the withdrawn v3 release candidate.

Fixed

  • ops::add_gather_offsets prevalidated its source spans with unchecked
    addition: on 32-bit targets, offset + dst.len() wraps when overflow
    checks are disabled, so a release build could admit a source row that
    reaches past region and panic mid-fold with the destination already
    partially mutated. The offset-plus-span check now uses checked arithmetic
    on every target, and the direct AVX2 gather prevalidates every offset —
    an invalid later offset included — before the first destination write.
    Invalid geometry still panics before any mutation; the defect was a
    partial write before the panic, never a memory-safety violation.
  • Default-feature 32-bit x86 builds use the portable backend. X64 capability
    tokens and their architecture kernels compile only for x86_64; enabling
    simd or internals on i686 no longer imports unavailable x64 entries.