Repository navigation
Migrating from 2.x
fgf 3.0.0 replaces field-specific element wrappers with Elem<F> and makes scalar algebra, byte encoding, and generator selection separate capabilities. Migration changes both type names and the handling of noncanonical prime lanes.
The 3.0.0 changelog is the authoritative release record. This page groups the changes by caller task. Historical 2.x fragments are fenced as text because they do not compile against 3.0.0; all Rust-fenced replacements target 3.0.0.
| Released 2.x field | 3.0 field |
|---|---|
Gf8B |
Binary<8, Polynomial<AES>> |
Gf8D |
Binary<8, Polynomial<RS>> |
Gf16 |
Binary<16, Tower<Rijndael16>> |
Gf32 |
Binary<32, Tower<Rijndael32>> |
Gf64 |
Binary<64, Tower<Rijndael64>> |
FanPaarN field marker |
Binary<N, Tower<FanPaarN>>, where FanPaarN is a specification marker |
Gf2 |
Binary<1, Polynomial<3>> |
Mersenne31, Goldilocks, QuadMersenne31
|
Unchanged field marker names |
Every element type becomes Elem<the_field>. For example, gf16::Elem becomes Elem<Binary<16, Tower<Rijndael16>>>, and mersenne31::Elem becomes Elem<Mersenne31>. The crate supplies no compatibility field aliases. Applications can define their own aliases to keep signatures readable.
A historical 2.x scalar computation:
use fgf::gf16;
const A: gf16::Elem = gf16::Elem::from_raw(0x1234);
const B: gf16::Elem = gf16::Elem::from_raw(0x0108);
const PRODUCT: gf16::Elem = A.mul(B);
Its 3.0 replacement:
use fgf::{Binary, Elem, Rijndael16, Tower};
type F = Binary<16, Tower<Rijndael16>>;
const A: Elem<F> = Elem::<F>::from_raw(0x1234);
const B: Elem<F> = Elem::<F>::from_raw(0x0108);
const PRODUCT: Elem<F> = A.mul(B);
assert_eq!(PRODUCT.div(B), A);Import polynomial constants before using them in the const-generic position, such as Polynomial<AES>. The full polynomial type is Polynomial<P> with P: u128. RS names the unchanged 0x11D convention. Intermediate names from development branches are not compatibility aliases; the changelog also maps those spellings.
| Removed associated item or trait name | Replacement |
|---|---|
F::Elem |
Elem<F> |
Field::BITS |
FieldBuffer::STORAGE_BITS for lane width; Field::DEGREE for extension degree |
Field::CHARACTERISTIC |
<F::Characteristic as PrimeIdentity>::CHARACTERISTIC |
Field::GENERATOR |
Elem::<F>::GENERATOR with F: HasGenerator
|
Field::BYTES, encode, decode
|
FieldBuffer capability |
field::Elem trait |
FieldElem; import the trait separately from the Elem<F> wrapper |
Field::elem_count(bytes) |
Validate whole lanes, then divide by F::BYTES under FieldBuffer
|
A scalar-only generic algorithm uses F: Field. Encoding uses F: FieldBuffer; packed arithmetic uses F: FieldKernels, which implies FieldBuffer. Generator selection is optional rather than a universal field property.
Historical 2.x coefficient signature:
fn scale<F: fgf::FieldKernels>(dst: &mut [u8], c: F::Elem, src: &[u8]) {
fgf::ops::mul_into::<F>(dst, c, src);
}
The replacement keeps the operation but changes the value type:
use fgf::{AES, Binary, Elem, FieldKernels, Polynomial, ops};
fn scale<F: FieldKernels>(dst: &mut [u8], c: Elem<F>, src: &[u8]) {
ops::mul_into::<F>(dst, c, src);
}
type F = Binary<8, Polynomial<AES>>;
let mut destination = [0xa5u8; 3];
scale::<F>(&mut destination, Elem::<F>::from_raw(2), &[1, 2, 3]);
assert_eq!(destination, [2, 4, 6]);pow takes u128 on both the scalar trait and inherent shipped-family methods. Existing u64 variables need an explicit conversion such as u128::from(exponent). The separate QuadMersenne31::pow_u128 method is replaced by pow.
Coeff<F>, CoeffVec<F>, and CoeffMatrix<F> remain typed by the field; their constructors take Elem<F> coefficients. Matrix construction remains source-major, and application still borrows ordinary byte buffers. A field rename does not transpose coefficient axes or change row lengths.
use fgf::{AES, Binary, Elem, Polynomial, ops};
type F = Binary<8, Polynomial<AES>>;
let coefficient = ops::Coeff::<F>::new(Elem::<F>::from_raw(3));
let mut destination = [0xa5u8; 3];
ops::mul_into_with::<F>(&mut destination, &coefficient, &[1, 2, 3]);
assert_eq!(destination, [3, 6, 5]);Prepared values are not a serialized compatibility surface. Rebuild them from scalar values in the new process. Prepared coefficients explains owned collections and borrowed views.
In 2.x, prime construction and decoding could retain raw lanes, and canonical() reduced the element explicitly. In 3.0, construction and decoding store canonical coordinates, so canonical() is removed and to_raw() returns the reduced storage.
use fgf::{Elem, FieldBuffer, Mersenne31, mersenne31};
let input = mersenne31::MODULUS + 7;
let value = Elem::<Mersenne31>::from_raw(input);
assert_eq!(value.to_raw(), 7);
assert_eq!(Mersenne31::decode(&input.to_le_bytes()), value);
assert_eq!(value.to_bytes(), 7u32.to_le_bytes());Applications that relied on retaining unreduced bits must retain the original bytes separately. Published canonical encodings and mathematical values remain unchanged, but decoding a noncanonical alias and encoding it again does not preserve its original bytes.
Packed prime operations accept raw lane patterns supported by decoding. Manual input canonicalization is not a precondition for arithmetic. Zero-coefficient accumulation, unit in-place scaling, and unit overwrite copying can preserve raw bytes; those operations must not be treated as normalization requests. Prime fields gives an explicit decode–encode boundary and executable shortcut examples.
The gf16, gf32, gf64, and concrete Fan–Paar element modules are removed. The binary presentations live under field::binary; root re-exports provide the usual imports.
Module generator constants become Elem::<F>::GENERATOR under HasGenerator. Tower relation constants come from the specification's LINEAR_COEFFICIENT and CONSTANT_COEFFICIENT; the tower indeterminate is not necessarily its multiplicative generator.
TowerSpec declares a supported half-degree binary base and relation coefficients in that base's raw coordinates. TowerGeneratorSpec separately selects a generator. Custom specifications using intermediate A/B names replace them with the descriptive associated constants. Quadratic towers explains the relation and validity checks.
bits::dot_product returns Elem<Binary<1, Polynomial<3>>>. Scalar GF(2) is a Field, but its vectors remain bit-packed and do not implement the FieldBuffer contract.
use fgf::{Binary, Elem, Polynomial, bits};
type F = Binary<1, Polynomial<3>>;
let parity: Elem<F> = bits::dot_product(&[0b101], &[0b001], 3);
assert_eq!(parity, Elem::<F>::ONE);Logical bit length, LSB-first ordering, and caller-owned padding remain part of the buffer convention.
Migration checks compare canonical wire fixtures, generator-dependent schedules, rectangular coefficient geometry, and prime inputs near the modulus. A passing type check alone does not establish that a raw-coordinate reinterpretation is correct.
From a crate checkout, just examples exercises complete workflows and just doc builds the API reference. The type model is the entry point for rewriting generic library code; deployment covers feature-specific verification.
Using fgf
- Type model and generic algorithms
- Choosing a field and basis
- Coordinates and packed bytes
- Linear operations and row geometry
- Prepared coefficients
- Prime fields
- Bit-packed GF(2)
- Features and deployment
Presentations and extensions
Upgrading