openvm_algebra_guest/lib.rs
1#![no_std]
2extern crate self as openvm_algebra_guest;
3
4/// This is custom-1 defined in RISC-V spec document
5pub const OPCODE: u8 = 0x2b;
6pub const MODULAR_ARITHMETIC_FUNCT3: u8 = 0b000;
7pub const COMPLEX_EXT_FIELD_FUNCT3: u8 = 0b010;
8
9/// Modular arithmetic is configurable.
10/// The funct7 field equals `mod_idx * MODULAR_ARITHMETIC_MAX_KINDS + base_funct7`.
11#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
12#[repr(u8)]
13pub enum ModArithBaseFunct7 {
14 AddMod = 0,
15 SubMod,
16 MulMod,
17 DivMod,
18 IsEqMod,
19 SetupMod,
20}
21
22impl ModArithBaseFunct7 {
23 pub const MODULAR_ARITHMETIC_MAX_KINDS: u8 = 8;
24}
25
26/// Complex extension field is configurable.
27/// The funct7 field equals `fp2_idx * COMPLEX_EXT_FIELD_MAX_KINDS + base_funct7`.
28#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
29#[repr(u8)]
30pub enum ComplexExtFieldBaseFunct7 {
31 Add = 0,
32 Sub,
33 Mul,
34 Div,
35 Setup,
36}
37
38impl ComplexExtFieldBaseFunct7 {
39 pub const COMPLEX_EXT_FIELD_MAX_KINDS: u8 = 8;
40}
41
42/// Modular arithmetic traits for use with OpenVM intrinsics.
43extern crate alloc;
44
45use alloc::vec::Vec;
46use core::{
47 fmt::Debug,
48 iter::{Product, Sum},
49 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
50};
51
52pub use field::Field;
53#[cfg(not(target_os = "zkvm"))]
54use num_bigint::BigUint;
55pub use openvm_algebra_complex_macros as complex_macros;
56pub use openvm_algebra_moduli_macros as moduli_macros;
57pub use serde_big_array::BigArray;
58use strum_macros::FromRepr;
59
60/// Field traits
61pub mod field;
62/// Implementation of this library's traits on halo2curves types.
63/// Used for testing and also VM runtime execution.
64/// These should **only** be importable on a host machine.
65#[cfg(all(not(target_os = "zkvm"), feature = "halo2curves"))]
66mod halo2curves;
67
68/// Exponentiation by bytes
69mod exp_bytes;
70pub use exp_bytes::*;
71
72/// Division operation that is undefined behavior when the denominator is not invertible.
73pub trait DivUnsafe<Rhs = Self>: Sized {
74 /// Output type of `div_unsafe`.
75 type Output;
76
77 /// Undefined behavior when denominator is not invertible.
78 fn div_unsafe(self, other: Rhs) -> Self::Output;
79}
80
81/// Division assignment operation that is undefined behavior when the denominator is not invertible.
82pub trait DivAssignUnsafe<Rhs = Self>: Sized {
83 /// Undefined behavior when denominator is not invertible.
84 fn div_assign_unsafe(&mut self, other: Rhs);
85}
86
87/// Trait definition for OpenVM modular integers, where each operation
88/// is done modulo MODULUS.
89///
90/// Division is only defined over the group of units in the ring of integers modulo MODULUS.
91/// It is undefined behavior outside of this group.
92pub trait IntMod:
93 Sized
94 + Eq
95 + Clone
96 + Debug
97 + Neg<Output = Self>
98 + Add<Output = Self>
99 + Sub<Output = Self>
100 + Mul<Output = Self>
101 + DivUnsafe<Output = Self>
102 + Sum
103 + Product
104 + for<'a> Add<&'a Self, Output = Self>
105 + for<'a> Sub<&'a Self, Output = Self>
106 + for<'a> Mul<&'a Self, Output = Self>
107 + for<'a> DivUnsafe<&'a Self, Output = Self>
108 + for<'a> Sum<&'a Self>
109 + for<'a> Product<&'a Self>
110 + AddAssign
111 + SubAssign
112 + MulAssign
113 + DivAssignUnsafe
114 + for<'a> AddAssign<&'a Self>
115 + for<'a> SubAssign<&'a Self>
116 + for<'a> MulAssign<&'a Self>
117 + for<'a> DivAssignUnsafe<&'a Self>
118{
119 /// Underlying representation of IntMod. Usually of the form `[u8; NUM_LIMBS]`.
120 type Repr: AsRef<[u8]> + AsMut<[u8]>;
121 /// `SelfRef<'a>` should almost always be `&'a Self`. This is a way to include implementations of binary operations where both sides are `&'a Self`.
122 type SelfRef<'a>: Add<&'a Self, Output = Self>
123 + Sub<&'a Self, Output = Self>
124 + Neg<Output = Self>
125 + Mul<&'a Self, Output = Self>
126 + DivUnsafe<&'a Self, Output = Self>
127 where
128 Self: 'a;
129
130 /// Modulus as a Repr.
131 const MODULUS: Self::Repr;
132
133 /// Number of limbs used to internally represent an element of `Self`.
134 const NUM_LIMBS: usize;
135
136 /// The zero element (i.e. the additive identity).
137 const ZERO: Self;
138
139 /// The one element (i.e. the multiplicative identity).
140 const ONE: Self;
141
142 /// Creates a new IntMod from an instance of Repr.
143 /// Does not enforce the integer value of `bytes` must be less than the modulus.
144 fn from_repr(repr: Self::Repr) -> Self;
145
146 /// Creates a new IntMod from an array of bytes, little endian.
147 /// Does not enforce the integer value of `bytes` must be less than the modulus.
148 fn from_le_bytes(bytes: &[u8]) -> Self;
149
150 /// Creates a new IntMod from an array of bytes, big endian.
151 /// Does not enforce the integer value of `bytes` must be less than the modulus.
152 fn from_be_bytes(bytes: &[u8]) -> Self;
153
154 /// Creates a new IntMod from a u8.
155 /// Does not enforce the integer value of `bytes` must be less than the modulus.
156 fn from_u8(val: u8) -> Self;
157
158 /// Creates a new IntMod from a u32.
159 /// Does not enforce the integer value of `bytes` must be less than the modulus.
160 fn from_u32(val: u32) -> Self;
161
162 /// Creates a new IntMod from a u64.
163 /// Does not enforce the integer value of `bytes` must be less than the modulus.
164 fn from_u64(val: u64) -> Self;
165
166 /// Value of this IntMod as an array of bytes, little endian.
167 fn as_le_bytes(&self) -> &[u8];
168
169 /// Value of this IntMod as an array of bytes, big endian.
170 fn to_be_bytes(&self) -> Self::Repr;
171
172 /// Modulus N as a BigUint.
173 #[cfg(not(target_os = "zkvm"))]
174 fn modulus_biguint() -> BigUint;
175
176 /// Creates a new IntMod from a BigUint.
177 #[cfg(not(target_os = "zkvm"))]
178 fn from_biguint(biguint: BigUint) -> Self;
179
180 /// Value of this IntMod as a BigUint.
181 #[cfg(not(target_os = "zkvm"))]
182 fn as_biguint(&self) -> BigUint;
183
184 fn neg_assign(&mut self);
185
186 /// Doubles `self` in-place.
187 fn double_assign(&mut self);
188
189 /// Doubles this IntMod.
190 fn double(&self) -> Self {
191 let mut ret = self.clone();
192 ret += self;
193 ret
194 }
195
196 /// Squares `self` in-place.
197 fn square_assign(&mut self);
198
199 /// Squares this IntMod.
200 fn square(&self) -> Self {
201 let mut ret = self.clone();
202 ret *= self;
203 ret
204 }
205
206 /// Cubes this IntMod.
207 fn cube(&self) -> Self {
208 let mut ret = self.square();
209 ret *= self;
210 ret
211 }
212
213 /// VM specific concept: during guest execution, it is not enforced that the representation
214 /// of `Self` must be the unique integer less than the modulus. The guest code may sometimes
215 /// want to enforce that the representation is the canonical one less than the modulus.
216 /// the host to an honest host to provide the canonical representation less than the modulus.
217 ///
218 /// This function should enforce that guest execution proceeds **if and only if** `self`
219 /// is in the unique representation less than the modulus.
220 fn assert_reduced(&self);
221
222 /// Is the integer representation of `self` less than the modulus?
223 fn is_reduced(&self) -> bool;
224}
225
226// Ref: https://docs.rs/elliptic-curve/latest/elliptic_curve/ops/trait.Reduce.html
227pub trait Reduce: Sized {
228 /// Interpret the given bytes as an integer and perform a modular reduction.
229 fn reduce_le_bytes(bytes: &[u8]) -> Self;
230 fn reduce_be_bytes(bytes: &[u8]) -> Self {
231 Self::reduce_le_bytes(&bytes.iter().rev().copied().collect::<Vec<_>>())
232 }
233}