zkaluvm/core/
core.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 core::fmt::{self, Debug, Formatter};
24
25use aluvm::{CoreExt, NoExt, Register, Supercore};
26use amplify::num::{u256, u4};
27
28use crate::fe256;
29
30pub const FIELD_ORDER_25519: u256 =
31    u256::from_inner([0xFFFF_FFFF_FFFF_FFEC, 0xFFFF_FFFF_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF, 0x8FFF_FFFF_FFFF_FFFF]);
32pub const FIELD_ORDER_STARK: u256 = u256::from_inner([1, 0, 17, 0x0800_0000_0000_0000]);
33pub const FIELD_ORDER_SECP: u256 =
34    u256::from_inner([0xFFFF_FFFE_FFFF_FC2E, 0xFFFF_FFFF_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF]);
35
36impl Default for GfaConfig {
37    fn default() -> Self {
38        Self {
39            field_order: FIELD_ORDER_25519,
40        }
41    }
42}
43
44#[derive(Copy, Clone, Eq, PartialEq)]
45pub struct GfaCore {
46    pub(super) fq: u256,
47    pub(super) e: [Option<fe256>; 16],
48}
49
50#[derive(Copy, Clone, Eq, PartialEq)]
51pub struct GfaConfig {
52    pub field_order: u256,
53}
54
55impl CoreExt for GfaCore {
56    type Reg = RegE;
57    type Config = GfaConfig; // Field order
58
59    #[inline]
60    fn with(config: Self::Config) -> Self {
61        GfaCore {
62            fq: config.field_order,
63            e: [None; 16],
64        }
65    }
66
67    #[inline]
68    fn get(&self, reg: Self::Reg) -> Option<fe256> { self.e[reg as usize] }
69
70    #[inline]
71    fn clr(&mut self, reg: Self::Reg) { self.e[reg as usize] = None; }
72
73    #[inline]
74    fn put(&mut self, reg: Self::Reg, val: Option<fe256>) {
75        let Some(val) = val else {
76            self.e[reg as usize] = None;
77            return;
78        };
79        assert!(val.to_u256() < self.fq, "value {val} exceeds field order {}", self.fq);
80        self.e[reg as usize] = Some(val);
81    }
82
83    #[inline]
84    fn reset(&mut self) { self.e = [None; 16]; }
85}
86
87impl Supercore<NoExt> for GfaCore {
88    fn subcore(&self) -> NoExt { NoExt }
89
90    fn merge_subcore(&mut self, _subcore: NoExt) {}
91}
92
93impl Debug for GfaCore {
94    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
95        let (sect, reg, val, reset) =
96            if f.alternate() { ("\x1B[0;4;1m", "\x1B[0;1m", "\x1B[0;32m", "\x1B[0m") } else { ("", "", "", "") };
97
98        writeln!(f)?;
99        writeln!(f, "{reg}FQ{reset} {val}{:X}{reset}#h", self.fq)?;
100        writeln!(f, "{sect}E-regs:{reset}")?;
101        for (no, item) in self.e.iter().enumerate() {
102            write!(f, "{reg}{}{reset} ", RegE::from(u4::with(no as u8)))?;
103            if let Some(e) = item {
104                writeln!(f, "{val}{e}{reset}#h")?;
105            } else {
106                writeln!(f, "~")?;
107            }
108        }
109        writeln!(f)
110    }
111}
112
113#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display)]
114#[display(uppercase)]
115#[repr(u8)]
116pub enum RegE {
117    E1 = 0b_0000,
118    E2 = 0b_0001,
119    E3 = 0b_0010,
120    E4 = 0b_0011,
121    E5 = 0b_0100,
122    E6 = 0b_0101,
123    E7 = 0b_0110,
124    E8 = 0b_0111,
125    EA = 0b_1000,
126    EB = 0b_1001,
127    EC = 0b_1010,
128    ED = 0b_1011,
129    EE = 0b_1100,
130    EF = 0b_1101,
131    EG = 0b_1110,
132    EH = 0b_1111,
133}
134
135impl Register for RegE {
136    type Value = fe256;
137
138    #[inline]
139    fn bytes(self) -> u16 { 16 }
140}
141
142impl From<u4> for RegE {
143    fn from(val: u4) -> Self {
144        match val {
145            x if x == RegE::E1.to_u4() => RegE::E1,
146            x if x == RegE::E2.to_u4() => RegE::E2,
147            x if x == RegE::E3.to_u4() => RegE::E3,
148            x if x == RegE::E4.to_u4() => RegE::E4,
149            x if x == RegE::E5.to_u4() => RegE::E5,
150            x if x == RegE::E6.to_u4() => RegE::E6,
151            x if x == RegE::E7.to_u4() => RegE::E7,
152            x if x == RegE::E8.to_u4() => RegE::E8,
153            x if x == RegE::EA.to_u4() => RegE::EA,
154            x if x == RegE::EB.to_u4() => RegE::EB,
155            x if x == RegE::EC.to_u4() => RegE::EC,
156            x if x == RegE::ED.to_u4() => RegE::ED,
157            x if x == RegE::EE.to_u4() => RegE::EE,
158            x if x == RegE::EF.to_u4() => RegE::EF,
159            x if x == RegE::EG.to_u4() => RegE::EG,
160            x if x == RegE::EH.to_u4() => RegE::EH,
161            _ => unreachable!(),
162        }
163    }
164}
165
166impl RegE {
167    pub const ALL: [Self; 16] = [
168        RegE::E1,
169        RegE::E2,
170        RegE::E3,
171        RegE::E4,
172        RegE::E5,
173        RegE::E6,
174        RegE::E7,
175        RegE::E8,
176        RegE::EA,
177        RegE::EB,
178        RegE::EC,
179        RegE::ED,
180        RegE::EE,
181        RegE::EF,
182        RegE::EG,
183        RegE::EH,
184    ];
185
186    #[inline]
187    pub const fn to_u4(self) -> u4 { u4::with(self as u8) }
188}