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 <zeek@tuta.com>
4// Copyright (C) 2026 Oumuamua Labs. 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
18use alloc::vec;
19use alloc::vec::Vec;
20use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
21use zeroize::Zeroize;
22
23pub trait TowerField:
24 Copy
25 + Default
26 + Clone
27 + PartialEq
28 + Eq
29 + core::fmt::Debug
30 + Send
31 + Sync
32 + From<u8>
33 + From<u32>
34 + From<u64>
35 + From<u128>
36 + Add<Output = Self>
37 + Sub<Output = Self>
38 + Mul<Output = Self>
39 + AddAssign
40 + SubAssign
41 + MulAssign
42 + CanonicalSerialize
43 + CanonicalDeserialize
44 + Zeroize
45{
46 const BITS: usize;
47 const ZERO: Self;
48 const ONE: Self;
49
50 /// The constant `TAU` needed to extend
51 /// this field to the next level.
52 /// If we are in F, then the next field
53 /// F' is constructed as F[X] / (X^2 + X + EXTENSION_TAU).
54 const EXTENSION_TAU: Self;
55
56 /// Returns the multiplicative inverse
57 /// of the element. By cryptographic
58 /// convention, the inverse of 0 is
59 /// defined as 0 to ensure constant-time
60 /// execution without branching.
61 fn invert(&self) -> Self;
62
63 /// Constructs a field element from
64 /// uniform bytes (e.g. hash output).
65 /// Used for PRNG / Blinding.
66 ///
67 /// The input is strictly 32 bytes
68 /// (standard hash size). Implementations
69 /// should use as many bytes as needed
70 /// from the prefix and ignore the rest.
71 fn from_uniform_bytes(bytes: &[u8; 32]) -> Self;
72}
73
74/// Defines how field elements are converted to bytes.
75/// Standard: Little-Endian.
76pub trait CanonicalSerialize {
77 /// Returns the size in bytes.
78 fn serialized_size(&self) -> usize;
79
80 /// Serializes the element into a buffer.
81 /// Returns error if buffer is too small.
82 #[allow(clippy::result_unit_err)]
83 fn serialize(&self, writer: &mut [u8]) -> Result<(), ()>;
84
85 /// Convenience method:
86 /// returns a Vec<u8>.
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/// Defines how bytes are converted back to field elements.
97/// Standard: Little-Endian.
98pub trait CanonicalDeserialize: Sized {
99 /// Deserializes from a buffer.
100 /// Returns Err if buffer is too short.
101 #[allow(clippy::result_unit_err)]
102 fn deserialize(bytes: &[u8]) -> Result<Self, ()>;
103}