Skip to main content

binius_field/
packed_extension.rs

1// Copyright 2023-2025 Irreducible Inc.
2// Copyright 2026 The Binius Developers
3
4//! Reading a packed extension field element as a packing of its subfield.
5//!
6//! A packed extension field element and its subfield packing are the same bytes.
7//! They differ only in how wide a scalar those bytes are cut into.
8//! So every cast here is a reinterpretation rather than a conversion, and compiles to nothing.
9//!
10//! The subfield scalars come out in [`ExtensionField`] basis order:
11//!
12//! ```text
13//! cast_bases_mut(exts)  ==  exts.iter().flat_map(|ext| ext.iter_bases())
14//! ```
15//!
16//! The bare names do not say what is being cast, so call sites read best qualified by the module:
17//!
18//! ```text
19//! packed_extension::cast_base::<B1, _>(elem)
20//! ```
21
22use crate::{
23	BinaryField, ExtensionField, PackedField, packed_fields::primitive::PackedPrimitiveType,
24	underlier::UnderlierView,
25};
26
27/// The packing of `FSub` covering the same bits as the packed extension field type `P`.
28///
29/// A transparent wrapper over an underlier holds one contiguous bit string.
30/// Cutting that same string into `FSub` scalars is exactly a [`PackedPrimitiveType`].
31pub type PackedSubfield<P, FSub> = PackedPrimitiveType<<P as UnderlierView>::Underlier, FSub>;
32
33/// Reads a packed extension field element as a packed subfield element.
34pub fn cast_base<FSub, P>(ext: P) -> PackedSubfield<P, FSub>
35where
36	FSub: BinaryField,
37	P: PackedField<Scalar: ExtensionField<FSub>> + UnderlierView,
38	PackedSubfield<P, FSub>: PackedField<Scalar = FSub>,
39{
40	PackedSubfield::<P, FSub>::from_underlier(ext.to_underlier())
41}
42
43/// Reads a packed extension field element in place as a packed subfield element.
44pub fn cast_base_mut<FSub, P>(packed: &mut P) -> &mut PackedSubfield<P, FSub>
45where
46	FSub: BinaryField,
47	P: PackedField<Scalar: ExtensionField<FSub>> + UnderlierView,
48	PackedSubfield<P, FSub>: PackedField<Scalar = FSub>,
49{
50	PackedSubfield::<P, FSub>::from_underlier_ref_mut(packed.to_underlier_ref_mut())
51}
52
53/// Reads a packed subfield element as a packed extension field element.
54pub fn cast_ext<FSub, P>(base: PackedSubfield<P, FSub>) -> P
55where
56	FSub: BinaryField,
57	P: PackedField<Scalar: ExtensionField<FSub>> + UnderlierView,
58	PackedSubfield<P, FSub>: PackedField<Scalar = FSub>,
59{
60	P::from_underlier(base.to_underlier())
61}
62
63/// Reads a slice of packed extension field elements in place as packed subfield elements.
64pub fn cast_bases_mut<FSub, P>(packed: &mut [P]) -> &mut [PackedSubfield<P, FSub>]
65where
66	FSub: BinaryField,
67	P: PackedField<Scalar: ExtensionField<FSub>> + UnderlierView,
68	PackedSubfield<P, FSub>: PackedField<Scalar = FSub>,
69{
70	PackedSubfield::<P, FSub>::from_underliers_ref_mut(P::to_underliers_ref_mut(packed))
71}