hekate_math/field.rs
1// SPDX-License-Identifier: Apache-2.0
2// This file is part of the hekate-math project.
3// Copyright (C) 2026 Andrei Kochergin <andrei@oumuamua.dev>
4// Copyright (C) 2026 Oumuamua Labs <info@oumuamua.dev>. All rights reserved.
5//
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! `TowerField`, the tower-basis trait every block type
19//! implements, and the fixed little-endian byte encoding.
20
21use alloc::vec;
22use alloc::vec::Vec;
23use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
24use zeroize::Zeroize;
25
26/// GF(2^BITS) in the tower basis: `Bit` and `Block8`
27/// through `Block256`. Addition and subtraction are XOR.
28pub trait TowerField:
29 Copy
30 + Default
31 + Clone
32 + PartialEq
33 + Eq
34 + core::fmt::Debug
35 + Send
36 + Sync
37 + From<u8>
38 + From<u32>
39 + From<u64>
40 + From<u128>
41 + Add<Output = Self>
42 + Sub<Output = Self>
43 + Mul<Output = Self>
44 + AddAssign
45 + SubAssign
46 + MulAssign
47 + CanonicalSerialize
48 + CanonicalDeserialize
49 + Zeroize
50{
51 /// Degree over GF(2): 2^BITS elements.
52 const BITS: usize;
53
54 /// The additive identity.
55 const ZERO: Self;
56
57 /// The multiplicative identity.
58 const ONE: Self;
59
60 /// τ of the next level, F\[X\] / (X^2 + X + τ), for Block8 up.
61 /// Tr(τ) = 1 makes X^2 + X + τ irreducible.
62 const EXTENSION_TAU: Self;
63
64 /// Returns `self^-1`, or 0 for 0. No branch on the value in the default build.
65 fn invert(&self) -> Self;
66
67 /// Builds the element from the first `BITS` bits
68 /// of `bytes`, little-endian; ignores the rest.
69 fn from_uniform_bytes(bytes: &[u8; 32]) -> Self;
70}
71
72/// Fixed-size little-endian encoding of the tower bits:
73/// `BITS / 8` bytes, one byte for `Bit`.
74pub trait CanonicalSerialize {
75 /// Returns the encoded length in bytes.
76 fn serialized_size(&self) -> usize;
77
78 /// Writes the encoding to the start of `writer`;
79 /// later bytes are left as they are.
80 ///
81 /// # Errors
82 /// `Err(())` if `writer` is shorter than `serialized_size()`.
83 #[allow(clippy::result_unit_err)]
84 fn serialize(&self, writer: &mut [u8]) -> Result<(), ()>;
85
86 /// Encodes `self` into a new `Vec<u8>` of `serialized_size()` bytes.
87 fn to_bytes(&self) -> Vec<u8> {
88 let size = self.serialized_size();
89 let mut buf = vec![0u8; size];
90 self.serialize(&mut buf).expect("Size calculation matches");
91
92 buf
93 }
94}
95
96/// The inverse of [`CanonicalSerialize`].
97pub trait CanonicalDeserialize: Sized {
98 /// Reads an element from the start of `bytes`; ignores the rest.
99 ///
100 /// # Errors
101 /// `Err(())` if `bytes` is shorter than the encoding,
102 /// or, for `Bit`, if the byte is above 1.
103 #[allow(clippy::result_unit_err)]
104 fn deserialize(bytes: &[u8]) -> Result<Self, ()>;
105}