Skip to main content

hekate_math/
hardware.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 crate::packable::PackedFlat;
19use crate::{PackableField, TowerField};
20use core::fmt::{self, Debug, Formatter};
21use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
22use zeroize::Zeroize;
23
24/// Trait for Hardware Isomorphism acceleration.
25pub trait HardwareField: TowerField + PackableField {
26    /// Convert standard Tower element
27    /// to hardware basis (Isomorphic).
28    fn to_hardware(self) -> Flat<Self>;
29
30    /// Convert hardware element back to Tower basis.
31    fn from_hardware(value: Flat<Self>) -> Self;
32
33    /// Sum two elements assuming they
34    /// are already in hardware basis.
35    fn add_hardware(lhs: Flat<Self>, rhs: Flat<Self>) -> Flat<Self>;
36
37    /// Sum packed vectors in hardware basis.
38    fn add_hardware_packed(lhs: PackedFlat<Self>, rhs: PackedFlat<Self>) -> PackedFlat<Self>;
39
40    /// Multiply two elements assuming
41    /// they are already in hardware basis.
42    fn mul_hardware(lhs: Flat<Self>, rhs: Flat<Self>) -> Flat<Self>;
43
44    /// Multiply packed vectors in hardware basis.
45    fn mul_hardware_packed(lhs: PackedFlat<Self>, rhs: PackedFlat<Self>) -> PackedFlat<Self>;
46
47    /// Multiply packed vectors by
48    /// a scalar in hardware basis.
49    fn mul_hardware_scalar_packed(lhs: PackedFlat<Self>, rhs: Flat<Self>) -> PackedFlat<Self>;
50
51    /// Extracts the `bit_idx` bit of the
52    /// canonical Tower representation
53    /// directly from the Hardware (Flat)
54    /// representation without a full basis
55    /// conversion. Strictly constant time.
56    fn tower_bit_from_hardware(value: Flat<Self>, bit_idx: usize) -> u8;
57}
58
59/// A field element stored in the hardware / flat basis.
60#[derive(Copy, Clone, Default, PartialEq, Eq, Zeroize)]
61#[repr(transparent)]
62pub struct Flat<F>(F);
63
64impl<F> Flat<F> {
65    #[inline(always)]
66    pub fn from_raw(raw: F) -> Self {
67        Self(raw)
68    }
69
70    #[inline(always)]
71    pub fn into_raw(self) -> F {
72        self.0
73    }
74
75    #[inline(always)]
76    pub fn as_raw(&self) -> &F {
77        &self.0
78    }
79}
80
81impl<F: Debug> Debug for Flat<F> {
82    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
83        f.debug_tuple("Flat").field(&self.0).finish()
84    }
85}
86
87impl<F: HardwareField> Flat<F> {
88    #[inline(always)]
89    pub fn to_tower(self) -> F {
90        F::from_hardware(self)
91    }
92
93    #[inline(always)]
94    pub fn tower_bit(self, bit_idx: usize) -> u8 {
95        F::tower_bit_from_hardware(self, bit_idx)
96    }
97}
98
99impl<F: HardwareField> Add for Flat<F> {
100    type Output = Self;
101
102    #[inline(always)]
103    fn add(self, rhs: Self) -> Self::Output {
104        F::add_hardware(self, rhs)
105    }
106}
107
108impl<F: HardwareField> AddAssign for Flat<F> {
109    #[inline(always)]
110    fn add_assign(&mut self, rhs: Self) {
111        *self = *self + rhs;
112    }
113}
114
115impl<F: HardwareField> Sub for Flat<F> {
116    type Output = Self;
117
118    #[inline(always)]
119    fn sub(self, rhs: Self) -> Self::Output {
120        F::add_hardware(self, rhs)
121    }
122}
123
124impl<F: HardwareField> SubAssign for Flat<F> {
125    #[inline(always)]
126    fn sub_assign(&mut self, rhs: Self) {
127        *self = *self - rhs;
128    }
129}
130
131impl<F: HardwareField> Mul for Flat<F> {
132    type Output = Self;
133
134    #[inline(always)]
135    fn mul(self, rhs: Self) -> Self::Output {
136        F::mul_hardware(self, rhs)
137    }
138}
139
140impl<F: HardwareField> MulAssign for Flat<F> {
141    #[inline(always)]
142    fn mul_assign(&mut self, rhs: Self) {
143        *self = *self * rhs;
144    }
145}
146
147/// Trait to efficiently promote smaller
148/// flat-basis fields to a larger flat-basis field
149/// bypassing redundant zero-byte lookups.
150pub trait FlatPromote<FromF>: HardwareField
151where
152    FromF: HardwareField,
153{
154    fn promote_flat(val: Flat<FromF>) -> Flat<Self>;
155
156    /// Batch promote a slice of flat elements.
157    ///
158    /// Default:
159    /// Scalar loop. Implementors may override
160    /// for SIMD or table acceleration.
161    fn promote_flat_batch(input: &[Flat<FromF>], output: &mut [Flat<Self>]) {
162        for (o, v) in output.iter_mut().zip(input.iter()) {
163            *o = Self::promote_flat(*v);
164        }
165    }
166}
167
168impl<F: HardwareField> FlatPromote<F> for F {
169    #[inline(always)]
170    fn promote_flat(val: Flat<F>) -> Flat<Self> {
171        val
172    }
173}