binius_field/
tower_levels.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use std::{
4	array,
5	ops::{Add, AddAssign, Index, IndexMut},
6};
7
8/// Public API for recursive algorithms over data represented as an array of its limbs
9/// E.g. an F_{2^128} element expressed as 8 chunks of 2 bytes
10/// or a 256-bit integer represented as 32 individual bytes
11///
12/// Join and split can be used to combine and split underlying data into upper and lower halves
13///
14/// This is mostly useful for recursively implementing arithmetic operations
15///
16/// These separate implementations are necessary to overcome the limitations of const generics in Rust.
17/// These implementations eliminate costly bounds checking that would otherwise be imposed by the compiler
18/// and allow easy inlining of recursive functions.
19pub trait TowerLevel: 'static {
20	// WIDTH is ALWAYS a power of 2
21	const WIDTH: usize;
22
23	// The underlying Data should ALWAYS be a fixed-width array of T's
24	type Data<T>: AsMut<[T]>
25		+ AsRef<[T]>
26		+ Sized
27		+ Index<usize, Output = T>
28		+ IndexMut<usize, Output = T>;
29	type Base: TowerLevel;
30
31	// Split something of type Self::Data<T>into two equal halves
32	#[allow(clippy::type_complexity)]
33	fn split<T>(
34		data: &Self::Data<T>,
35	) -> (&<Self::Base as TowerLevel>::Data<T>, &<Self::Base as TowerLevel>::Data<T>);
36
37	// Split something of type Self::Data<T>into two equal mutable halves
38	#[allow(clippy::type_complexity)]
39	fn split_mut<T>(
40		data: &mut Self::Data<T>,
41	) -> (&mut <Self::Base as TowerLevel>::Data<T>, &mut <Self::Base as TowerLevel>::Data<T>);
42
43	// Join two equal-length arrays (the reverse of split)
44	#[allow(clippy::type_complexity)]
45	fn join<T: Copy + Default>(
46		first: &<Self::Base as TowerLevel>::Data<T>,
47		second: &<Self::Base as TowerLevel>::Data<T>,
48	) -> Self::Data<T>;
49
50	// Fills an array of T's containing WIDTH elements
51	fn from_fn<T: Copy>(f: impl FnMut(usize) -> T) -> Self::Data<T>;
52
53	// Fills an array of T's containing WIDTH elements with T::default()
54	fn default<T: Copy + Default>() -> Self::Data<T> {
55		Self::from_fn(|_| T::default())
56	}
57}
58
59pub trait TowerLevelWithArithOps: TowerLevel {
60	#[inline(always)]
61	fn add_into<T: AddAssign + Copy>(
62		field_element: &Self::Data<T>,
63		destination: &mut Self::Data<T>,
64	) {
65		for i in 0..Self::WIDTH {
66			destination[i] += field_element[i];
67		}
68	}
69
70	#[inline(always)]
71	fn copy_into<T: Copy>(field_element: &Self::Data<T>, destination: &mut Self::Data<T>) {
72		for i in 0..Self::WIDTH {
73			destination[i] = field_element[i];
74		}
75	}
76
77	#[inline(always)]
78	fn sum<T: Copy + Add<Output = T>>(
79		field_element_a: &Self::Data<T>,
80		field_element_b: &Self::Data<T>,
81	) -> Self::Data<T> {
82		Self::from_fn(|i| field_element_a[i] + field_element_b[i])
83	}
84}
85
86impl<T: TowerLevel> TowerLevelWithArithOps for T {}
87
88pub struct TowerLevel64;
89
90impl TowerLevel for TowerLevel64 {
91	const WIDTH: usize = 64;
92
93	type Data<T> = [T; 64];
94	type Base = TowerLevel32;
95
96	#[inline(always)]
97	fn split<T>(
98		data: &Self::Data<T>,
99	) -> (&<Self::Base as TowerLevel>::Data<T>, &<Self::Base as TowerLevel>::Data<T>) {
100		((data[0..32].try_into().unwrap()), (data[32..64].try_into().unwrap()))
101	}
102
103	#[inline(always)]
104	fn split_mut<T>(
105		data: &mut Self::Data<T>,
106	) -> (&mut <Self::Base as TowerLevel>::Data<T>, &mut <Self::Base as TowerLevel>::Data<T>) {
107		let (chunk_1, chunk_2) = data.split_at_mut(32);
108
109		((chunk_1.try_into().unwrap()), (chunk_2.try_into().unwrap()))
110	}
111
112	#[inline(always)]
113	fn join<T: Copy + Default>(
114		left: &<Self::Base as TowerLevel>::Data<T>,
115		right: &<Self::Base as TowerLevel>::Data<T>,
116	) -> Self::Data<T> {
117		let mut result = [T::default(); 64];
118		result[..32].copy_from_slice(left);
119		result[32..].copy_from_slice(right);
120		result
121	}
122
123	#[inline(always)]
124	fn from_fn<T>(f: impl FnMut(usize) -> T) -> Self::Data<T> {
125		array::from_fn(f)
126	}
127}
128
129pub struct TowerLevel32;
130
131impl TowerLevel for TowerLevel32 {
132	const WIDTH: usize = 32;
133
134	type Data<T> = [T; 32];
135	type Base = TowerLevel16;
136
137	#[inline(always)]
138	fn split<T>(
139		data: &Self::Data<T>,
140	) -> (&<Self::Base as TowerLevel>::Data<T>, &<Self::Base as TowerLevel>::Data<T>) {
141		((data[0..16].try_into().unwrap()), (data[16..32].try_into().unwrap()))
142	}
143
144	#[inline(always)]
145	fn split_mut<T>(
146		data: &mut Self::Data<T>,
147	) -> (&mut <Self::Base as TowerLevel>::Data<T>, &mut <Self::Base as TowerLevel>::Data<T>) {
148		let (chunk_1, chunk_2) = data.split_at_mut(16);
149
150		((chunk_1.try_into().unwrap()), (chunk_2.try_into().unwrap()))
151	}
152
153	#[inline(always)]
154	fn join<T: Copy + Default>(
155		left: &<Self::Base as TowerLevel>::Data<T>,
156		right: &<Self::Base as TowerLevel>::Data<T>,
157	) -> Self::Data<T> {
158		let mut result = [T::default(); 32];
159		result[..16].copy_from_slice(left);
160		result[16..].copy_from_slice(right);
161		result
162	}
163
164	#[inline(always)]
165	fn from_fn<T>(f: impl FnMut(usize) -> T) -> Self::Data<T> {
166		array::from_fn(f)
167	}
168}
169
170pub struct TowerLevel16;
171
172impl TowerLevel for TowerLevel16 {
173	const WIDTH: usize = 16;
174
175	type Data<T> = [T; 16];
176	type Base = TowerLevel8;
177
178	#[inline(always)]
179	fn split<T>(
180		data: &Self::Data<T>,
181	) -> (&<Self::Base as TowerLevel>::Data<T>, &<Self::Base as TowerLevel>::Data<T>) {
182		((data[0..8].try_into().unwrap()), (data[8..16].try_into().unwrap()))
183	}
184
185	#[inline(always)]
186	fn split_mut<T>(
187		data: &mut Self::Data<T>,
188	) -> (&mut <Self::Base as TowerLevel>::Data<T>, &mut <Self::Base as TowerLevel>::Data<T>) {
189		let (chunk_1, chunk_2) = data.split_at_mut(8);
190
191		((chunk_1.try_into().unwrap()), (chunk_2.try_into().unwrap()))
192	}
193
194	#[inline(always)]
195	fn join<T: Copy + Default>(
196		left: &<Self::Base as TowerLevel>::Data<T>,
197		right: &<Self::Base as TowerLevel>::Data<T>,
198	) -> Self::Data<T> {
199		let mut result = [T::default(); 16];
200		result[..8].copy_from_slice(left);
201		result[8..].copy_from_slice(right);
202		result
203	}
204
205	#[inline(always)]
206	fn from_fn<T>(f: impl FnMut(usize) -> T) -> Self::Data<T> {
207		array::from_fn(f)
208	}
209}
210
211pub struct TowerLevel8;
212
213impl TowerLevel for TowerLevel8 {
214	const WIDTH: usize = 8;
215
216	type Data<T> = [T; 8];
217	type Base = TowerLevel4;
218
219	#[inline(always)]
220	fn split<T>(
221		data: &Self::Data<T>,
222	) -> (&<Self::Base as TowerLevel>::Data<T>, &<Self::Base as TowerLevel>::Data<T>) {
223		((data[0..4].try_into().unwrap()), (data[4..8].try_into().unwrap()))
224	}
225
226	#[inline(always)]
227	fn split_mut<T>(
228		data: &mut Self::Data<T>,
229	) -> (&mut <Self::Base as TowerLevel>::Data<T>, &mut <Self::Base as TowerLevel>::Data<T>) {
230		let (chunk_1, chunk_2) = data.split_at_mut(4);
231
232		((chunk_1.try_into().unwrap()), (chunk_2.try_into().unwrap()))
233	}
234
235	#[inline(always)]
236	fn join<T: Copy + Default>(
237		left: &<Self::Base as TowerLevel>::Data<T>,
238		right: &<Self::Base as TowerLevel>::Data<T>,
239	) -> Self::Data<T> {
240		let mut result = [T::default(); 8];
241		result[..4].copy_from_slice(left);
242		result[4..].copy_from_slice(right);
243		result
244	}
245
246	#[inline(always)]
247	fn from_fn<T>(f: impl FnMut(usize) -> T) -> Self::Data<T> {
248		array::from_fn(f)
249	}
250}
251
252pub struct TowerLevel4;
253
254impl TowerLevel for TowerLevel4 {
255	const WIDTH: usize = 4;
256
257	type Data<T> = [T; 4];
258	type Base = TowerLevel2;
259
260	#[inline(always)]
261	fn split<T>(
262		data: &Self::Data<T>,
263	) -> (&<Self::Base as TowerLevel>::Data<T>, &<Self::Base as TowerLevel>::Data<T>) {
264		((data[0..2].try_into().unwrap()), (data[2..4].try_into().unwrap()))
265	}
266
267	#[inline(always)]
268	fn split_mut<T>(
269		data: &mut Self::Data<T>,
270	) -> (&mut <Self::Base as TowerLevel>::Data<T>, &mut <Self::Base as TowerLevel>::Data<T>) {
271		let (chunk_1, chunk_2) = data.split_at_mut(2);
272
273		((chunk_1.try_into().unwrap()), (chunk_2.try_into().unwrap()))
274	}
275
276	#[inline(always)]
277	fn join<T: Copy + Default>(
278		left: &<Self::Base as TowerLevel>::Data<T>,
279		right: &<Self::Base as TowerLevel>::Data<T>,
280	) -> Self::Data<T> {
281		let mut result = [T::default(); 4];
282		result[..2].copy_from_slice(left);
283		result[2..].copy_from_slice(right);
284		result
285	}
286
287	#[inline(always)]
288	fn from_fn<T>(f: impl FnMut(usize) -> T) -> Self::Data<T> {
289		array::from_fn(f)
290	}
291}
292
293pub struct TowerLevel2;
294
295impl TowerLevel for TowerLevel2 {
296	const WIDTH: usize = 2;
297
298	type Data<T> = [T; 2];
299	type Base = TowerLevel1;
300
301	#[inline(always)]
302	fn split<T>(
303		data: &Self::Data<T>,
304	) -> (&<Self::Base as TowerLevel>::Data<T>, &<Self::Base as TowerLevel>::Data<T>) {
305		((data[0..1].try_into().unwrap()), (data[1..2].try_into().unwrap()))
306	}
307
308	#[inline(always)]
309	fn split_mut<T>(
310		data: &mut Self::Data<T>,
311	) -> (&mut <Self::Base as TowerLevel>::Data<T>, &mut <Self::Base as TowerLevel>::Data<T>) {
312		let (chunk_1, chunk_2) = data.split_at_mut(1);
313
314		((chunk_1.try_into().unwrap()), (chunk_2.try_into().unwrap()))
315	}
316
317	#[inline(always)]
318	fn join<T: Copy + Default>(
319		left: &<Self::Base as TowerLevel>::Data<T>,
320		right: &<Self::Base as TowerLevel>::Data<T>,
321	) -> Self::Data<T> {
322		let mut result = [T::default(); 2];
323		result[..1].copy_from_slice(left);
324		result[1..].copy_from_slice(right);
325		result
326	}
327
328	#[inline(always)]
329	fn from_fn<T>(f: impl FnMut(usize) -> T) -> Self::Data<T> {
330		array::from_fn(f)
331	}
332}
333
334pub struct TowerLevel1;
335
336impl TowerLevel for TowerLevel1 {
337	const WIDTH: usize = 1;
338
339	type Data<T> = [T; 1];
340	type Base = Self;
341
342	// Level 1 is the atomic unit of backing data and must not be split.
343
344	#[inline(always)]
345	fn split<T>(
346		_data: &Self::Data<T>,
347	) -> (&<Self::Base as TowerLevel>::Data<T>, &<Self::Base as TowerLevel>::Data<T>) {
348		unreachable!()
349	}
350
351	#[inline(always)]
352	fn split_mut<T>(
353		_data: &mut Self::Data<T>,
354	) -> (&mut <Self::Base as TowerLevel>::Data<T>, &mut <Self::Base as TowerLevel>::Data<T>) {
355		unreachable!()
356	}
357
358	#[inline(always)]
359	fn join<T: Copy + Default>(
360		_left: &<Self::Base as TowerLevel>::Data<T>,
361		_right: &<Self::Base as TowerLevel>::Data<T>,
362	) -> Self::Data<T> {
363		unreachable!()
364	}
365
366	#[inline(always)]
367	fn from_fn<T>(f: impl FnMut(usize) -> T) -> Self::Data<T> {
368		array::from_fn(f)
369	}
370}