1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//! Helpers shared across chiplets.
//!
//! Two themes:
//!
//! - **Field-element packing** ([`pack_le`], [`halves_le`]) — LSB-first base-`base` digit
//! reconstruction. Generic over the expression type `E` and the variable type `V`, so the same
//! helpers serve constraint evaluation against either an `AirBuilder` or a `LookupBuilder`. Both
//! use Horner's method.
//! - **Two-row window access** ([`current_main`], [`next_main`]) — extract a fixed-size `[V; N]`
//! from the current or next slice of any [`WindowAccess`]-bearing window. Used to pull a row out
//! of `builder.main()` (or any other windowed source) and release the window's borrow before
//! calling further mutating methods on the builder.
//!
//! Typical packing bases:
//!
//! - `base = 2` — bit decomposition reconstruction (e.g.
//! [`byte_pair_lut`](crate::primitives::byte_pair_lut)'s 8-bit operand reconstruction).
//! - `base = 256` — byte-into-32-bit-half packing (e.g. the `KeccakRound` bitwise chiplet's 64-bit
//! lane split).
use array;
use ;
use WindowAccess;
/// Pack base-`base` digits LSB-first into a Felt-algebra expression.
///
/// Computes `items[0] + base·items[1] + base²·items[2] + …` via
/// Horner's method. `E: Algebra<Felt>` is the natural shape for any
/// `AirBuilder::Expr` or `LookupBuilder::Expr` over Felt — both
/// satisfy `Algebra<Self::F>` with `F = Felt`. `base` must fit in the
/// canonical Goldilocks range (i.e. `base < 2^64 − 2^32 + 1`).
/// Split `items` in half and [`pack_le`] each half independently.
///
/// `items.len()` must be even; returns `[lo, hi]` where `lo` packs
/// the first half and `hi` packs the second.
///
/// Common use: splitting a 64-bit lane (8 bytes, `base = 256`) into the
/// two 32-bit halves needed because a single `Felt` cannot hold a full
/// `u64` canonically (Goldilocks `p ≈ 2^64 − 2^32 + 1`).
/// Snapshot `N` consecutive elements from `window`'s current slice,
/// starting at column `start`.
///
/// Generic over any [`WindowAccess`]-bearing window so it works against
/// `AirBuilder::main()` (returns a constraint-side window),
/// `LookupBuilder::main()` (returns the lookup-builder's mirror), or
/// any other source that exposes the same trait. Pass `start = 0` for
/// the full row.
///
/// Consuming the window by value lets the caller write the typical
/// terse form `current_main(builder.main(), 0)` — the helper produces
/// an owned `[V; N]` and drops the window so the caller can freely
/// resume mutating builder methods afterward.
where
W: ,
V: Copy,
/// Like [`current_main`], but reads from the next (cyclic) row.
where
W: ,
V: Copy,
/// Split a `u64` into 32-bit halves as `[lo, hi]`, each held in a `u64`
/// (zero-extended).
///
/// `lo = x & 0xFFFF_FFFF`, `hi = x >> 32`. Useful when the halves feed
/// into further `u64` arithmetic before becoming `Felt`s — e.g.
/// `(lo + 2^32)·k` in the `KeccakRound` bitwise chiplet's ROL row
/// construction, where doing the multiply in `u64` then converting is
/// cheaper than going through `Felt` mid-stream.
/// Split a `u64` into 32-bit halves as `[lo, hi]` field elements.
///
/// Goldilocks `p ≈ 2^64 − 2^32 + 1` cannot represent every `u64`
/// canonically, so 64-bit lane chiplets commit and encode the two
/// 32-bit halves rather than the full 64-bit value.