zkaluvm/core/
microcode.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::regs::Status;
24use aluvm::CoreExt;
25use amplify::num::u256;
26
27use crate::gfa::Bits;
28use crate::{fe256, GfaCore, RegE};
29
30/// Microcode for finite field arithmetics.
31impl GfaCore {
32    pub fn fq(&self) -> u256 { self.fq }
33
34    pub fn test(&self, src: RegE) -> Status {
35        if self.get(src).is_some() {
36            Status::Ok
37        } else {
38            Status::Fail
39        }
40    }
41
42    pub fn fits(&self, src: RegE, bits: Bits) -> Option<bool> {
43        let order = self.fq();
44        let a = self.get(src)?;
45        debug_assert!(a.to_u256() < order);
46        let check = a.to_u256() >> bits.bit_len();
47        Some(check == u256::ZERO)
48    }
49
50    pub fn mov(&mut self, dst: RegE, src: RegE) {
51        match self.get(src) {
52            Some(val) => {
53                self.set(dst, val);
54            }
55            None => {
56                self.clr(dst);
57            }
58        }
59    }
60
61    pub fn eqv(&mut self, src1: RegE, src2: RegE) -> Status {
62        let a = self.get(src1);
63        let b = self.get(src2);
64        if a == b {
65            Status::Ok
66        } else {
67            Status::Fail
68        }
69    }
70
71    #[inline]
72    pub fn add_mod(&mut self, dst_src: RegE, src: RegE) -> Status {
73        let order = self.fq();
74
75        let Some(a) = self.get(dst_src) else {
76            return Status::Fail;
77        };
78        let Some(b) = self.get(src) else {
79            return Status::Fail;
80        };
81
82        let a = a.to_u256();
83        let b = b.to_u256();
84        debug_assert!(a < order && b < order);
85
86        let (mut res, overflow) = a.overflowing_add(b);
87        if overflow {
88            res += u256::MAX - order;
89        }
90
91        let res = res % order;
92        self.set(dst_src, fe256::from(res));
93        Status::Ok
94    }
95
96    #[inline]
97    pub fn mul_mod(&mut self, dst_src: RegE, src: RegE) -> Status {
98        let order = self.fq();
99
100        let Some(a) = self.get(dst_src) else {
101            return Status::Fail;
102        };
103        let Some(b) = self.get(src) else {
104            return Status::Fail;
105        };
106
107        let a = a.to_u256();
108        let b = b.to_u256();
109        debug_assert!(a < order && b < order);
110
111        let (res, _) = mul_mod_int(order, a, b);
112
113        let res = res % order;
114        self.set(dst_src, fe256::from(res));
115        Status::Ok
116    }
117
118    #[inline]
119    pub fn neg_mod(&mut self, dst_src: RegE, src: RegE) -> Status {
120        let order = self.fq();
121
122        let Some(a) = self.get(src) else {
123            return Status::Fail;
124        };
125
126        debug_assert!(a.to_u256() < order);
127
128        let res = order - a.to_u256();
129        self.set(dst_src, fe256::from(res));
130        Status::Ok
131    }
132}
133
134fn mul_mod_int(order: u256, a: u256, b: u256) -> (u256, bool) {
135    let (mut res, overflow) = a.overflowing_mul(b);
136    if overflow {
137        let rem = u256::MAX - order;
138        res = mul_mod_int(order, res, rem).0;
139    }
140    (res % order, overflow)
141}