zkaluvm/gfa/instr.rs
1// AluVM extensions for zero knowledge, STARKs and SNARKs"
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Designed in 2024-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
6// Written in 2024-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
7//
8// Copyright (C) 2024-2025 Laboratories for Ubiquitous Deterministic Computing (UBIDECO),
9// Institute for Distributed and Cognitive Systems (InDCS), Switzerland.
10// Copyright (C) 2024-2025 Dr Maxim Orlovsky.
11// All rights under the above copyrights are reserved.
12//
13// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
14// in compliance with the License. You may obtain a copy of the License at
15//
16// http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software distributed under the License
19// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
20// or implied. See the License for the specific language governing permissions and limitations under
21// the License.
22
23use aluvm::isa::{CtrlInstr, ReservedInstr};
24use aluvm::SiteId;
25use amplify::num::{u2, u3};
26
27use crate::{fe256, RegE};
28
29#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display, From)]
30#[display(inner)]
31#[non_exhaustive]
32pub enum Instr<Id: SiteId> {
33 /// Control flow instructions.
34 #[from]
35 Ctrl(CtrlInstr<Id>),
36
37 #[from]
38 Gfa(FieldInstr),
39
40 /// Reserved instruction for future use in core `ALU` ISAs.
41 #[from]
42 Reserved(ReservedInstr),
43}
44
45/// Arithmetic instructions for finite fields.
46#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)]
47#[non_exhaustive]
48pub enum FieldInstr {
49 /// Tests if register contains a value and is not set to `None`.
50 ///
51 /// Sets `CO` register to [`Status::Ok`] if a register contains a value, and to [`Status::Fail`]
52 /// otherwise.
53 ///
54 /// Doesn't affect value in `CK` register.
55 #[display("test {src}")]
56 Test { src: RegE },
57
58 /// Clears register value by setting it to `None`.
59 ///
60 /// Doesn't affect values in `CO` and `CK` registers.
61 #[display("clr {dst}")]
62 Clr { dst: RegE },
63
64 /// Puts value into a register, replacing previous value in it, if there was any.
65 ///
66 /// Doesn't affect values in `CO` and `CK` registers.
67 #[display("mov {dst}, {data}")]
68 PutD { dst: RegE, data: fe256 },
69
70 /// Puts zero (`0`) value into a register, replacing previous value in it, if there was any.
71 ///
72 /// Doesn't affect values in `CO` and `CK` registers.
73 #[display("mov {dst}, 0")]
74 PutZ { dst: RegE },
75
76 /// Puts `val` value, which is a power of 2, into a register, replacing previous value in it, if
77 /// there was any.
78 ///
79 /// Doesn't affect values in `CO` and `CK` registers.
80 #[display("mov {dst}, {val}")]
81 PutV { dst: RegE, val: ConstVal },
82
83 /// Test whether a value in a register fits in the provided number of bits.
84 ///
85 /// Sets `CO` register to [`Status::Ok`] if the value fits given number of bits, and to
86 /// [`Status::Fail`] otherwise.
87 ///
88 /// If `src` is set to `None`, sets both `CO` and `CK` to [`Status::Fail`]; otherwise leaves
89 /// value in `CK` unchanged.
90 #[display("fits {src}, {bits}")]
91 Fits { src: RegE, bits: Bits },
92
93 /// Moves (copies) value from `src` to `dst` register, overwriting previous value in `dst`. If
94 /// `src` has no value (i.e. set to `None`), sets `dst` to `None`. State of `src` register
95 /// remains unaffected.
96 ///
97 /// Doesn't affect values in `CO` and `CK` registers.
98 #[display("mov {dst}, {src}")]
99 Mov { dst: RegE, src: RegE },
100
101 /// Checks whether `src1` and `src2` registers are equal. If both `src1` and `src2` registers
102 /// contain no value, considers them equal.
103 ///
104 /// Sets `CO` register to represent equivalence of the registers.
105 ///
106 /// Doesn't affect value in `CK` register.
107 #[display("eq {src1}, {src2}")]
108 Eq { src1: RegE, src2: RegE },
109
110 /// Negate value in `src` using finite-field arithmetics, and put result into `dst`.
111 ///
112 /// Doesn't affect values in `CO` register.
113 ///
114 /// If `src` is set to `None`, sets `CK` to [`Status::Fail`]; otherwise leaves value in `CK`
115 /// unchanged.
116 #[display("neg {dst}, {src}")]
117 Neg { dst: RegE, src: RegE },
118
119 /// Add `src` value to `dst_src` value using finite-field (modulo) arithmetics of the `order`,
120 /// putting result to `dst_src`.
121 ///
122 /// Doesn't affect values in `CO` register.
123 ///
124 /// If either `src` or `dst_src` (or both) is set to `None`, sets `CK` to [`Status::Fail`];
125 /// otherwise leaves value in `CK` unchanged.
126 #[display("add {dst_src}, {src}")]
127 Add { dst_src: RegE, src: RegE },
128
129 /// Multiply `src` value to `dst_src` value using finite-field (modulo) arithmetics of the
130 /// `order`, putting result to `dst_src`.
131 ///
132 /// Doesn't affect values in `CO` register.
133 ///
134 /// If either `src` or `dst_src` (or both) is set to `None`, sets `CK` to [`Status::Fail`];
135 /// otherwise leaves value in `CK` unchanged.
136 #[display("mul {dst_src}, {src}")]
137 Mul { dst_src: RegE, src: RegE },
138}
139
140#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)]
141#[repr(u8)]
142pub enum ConstVal {
143 #[display("1")]
144 Val1 = 0,
145
146 #[display("ffff_ffff_ffff_ffff#h")]
147 ValU64Max = 1,
148
149 #[display("ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff#h")]
150 ValU128Max = 2,
151
152 #[display("-1#fe")]
153 ValFeMAX = 3,
154}
155
156impl From<u2> for ConstVal {
157 fn from(val: u2) -> Self {
158 match val {
159 x if x == ConstVal::Val1.to_u2() => ConstVal::Val1,
160 x if x == ConstVal::ValU64Max.to_u2() => ConstVal::ValU64Max,
161 x if x == ConstVal::ValU128Max.to_u2() => ConstVal::ValU128Max,
162 x if x == ConstVal::ValFeMAX.to_u2() => ConstVal::ValFeMAX,
163 _ => unreachable!(),
164 }
165 }
166}
167
168impl ConstVal {
169 #[inline]
170 pub const fn to_u2(self) -> u2 { u2::with(self as u8) }
171
172 pub fn to_fe256(self) -> Option<fe256> {
173 let val = match self {
174 ConstVal::Val1 => 1u128,
175 ConstVal::ValU64Max => u64::MAX as u128,
176 ConstVal::ValU128Max => u128::MAX,
177 ConstVal::ValFeMAX => return None,
178 };
179 Some(fe256::from(val))
180 }
181}
182
183#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)]
184#[repr(u8)]
185pub enum Bits {
186 #[display("8:bits")]
187 Bits8,
188
189 #[display("16:bits")]
190 Bits16,
191
192 #[display("24:bits")]
193 Bits24,
194
195 #[display("32:bits")]
196 Bits32,
197
198 #[display("48:bits")]
199 Bits48,
200
201 #[display("64:bits")]
202 Bits64,
203
204 #[display("96:bits")]
205 Bits96,
206
207 #[display("128:bits")]
208 Bits128,
209}
210
211impl From<u3> for Bits {
212 fn from(val: u3) -> Self {
213 match val {
214 x if x == Bits::Bits8.to_u3() => Bits::Bits8,
215 x if x == Bits::Bits16.to_u3() => Bits::Bits16,
216 x if x == Bits::Bits24.to_u3() => Bits::Bits24,
217 x if x == Bits::Bits32.to_u3() => Bits::Bits32,
218 x if x == Bits::Bits48.to_u3() => Bits::Bits48,
219 x if x == Bits::Bits64.to_u3() => Bits::Bits64,
220 x if x == Bits::Bits96.to_u3() => Bits::Bits96,
221 x if x == Bits::Bits128.to_u3() => Bits::Bits96,
222 _ => unreachable!(),
223 }
224 }
225}
226
227impl Bits {
228 #[inline]
229 pub const fn to_u3(self) -> u3 { u3::with(self as u8) }
230
231 pub fn from_bit_len(len: usize) -> Self {
232 match len {
233 8 => Bits::Bits8,
234 16 => Bits::Bits16,
235 24 => Bits::Bits24,
236 32 => Bits::Bits32,
237 48 => Bits::Bits48,
238 64 => Bits::Bits64,
239 96 => Bits::Bits96,
240 128 => Bits::Bits128,
241 invalid => panic!("unsupported bit length {invalid}"),
242 }
243 }
244
245 pub const fn bit_len(self) -> usize {
246 match self {
247 Bits::Bits8 => 8,
248 Bits::Bits16 => 16,
249 Bits::Bits24 => 24,
250 Bits::Bits32 => 32,
251 Bits::Bits48 => 48,
252 Bits::Bits64 => 64,
253 Bits::Bits96 => 96,
254 Bits::Bits128 => 128,
255 }
256 }
257}