Skip to main content

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}