/ vm / instructions / whitelist.rs
whitelist.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  //! Instruction whitelist for AlphaVM.
 20  //!
 21  //! AlphaVM restricts the available instructions to a minimal set required for
 22  //! credit operations and governance. This module defines the whitelisted
 23  //! instructions organized by category.
 24  //!
 25  //! ## Instruction Categories
 26  //!
 27  //! ### Arithmetic (2 instructions)
 28  //! - `add` - Addition of numeric types
 29  //! - `sub` - Subtraction of numeric types
 30  //!
 31  //! ### Comparison (6 instructions)
 32  //! - `gte` - Greater than or equal comparison
 33  //! - `gt` - Greater than comparison
 34  //! - `lte` - Less than or equal comparison
 35  //! - `lt` - Less than comparison
 36  //! - `is.eq` - Equality check
 37  //! - `is.neq` - Inequality check
 38  //!
 39  //! ### Logic (3 instructions)
 40  //! - `and` - Logical AND
 41  //! - `or` - Logical OR
 42  //! - `nor` - Logical NOR
 43  //!
 44  //! ### Control (3 instructions)
 45  //! - `ternary` - Conditional selection
 46  //! - `async` - Asynchronous finalize call
 47  //! - `cast` - Type casting
 48  
 49  use core::fmt::{self, Display, Formatter};
 50  
 51  /// Categories of whitelisted instructions in AlphaVM.
 52  #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 53  pub enum InstructionCategory {
 54      /// Arithmetic operations: add, sub
 55      Arithmetic,
 56      /// Comparison operations: gte, gt, lte, lt, is.eq, is.neq
 57      Comparison,
 58      /// Logic operations: and, or, nor
 59      Logic,
 60      /// Control flow operations: ternary, async, cast
 61      Control,
 62  }
 63  
 64  impl InstructionCategory {
 65      /// The total number of instruction categories.
 66      pub const COUNT: usize = 4;
 67  
 68      /// Returns all instruction categories as a slice.
 69      pub const fn all() -> &'static [InstructionCategory] {
 70          &[
 71              InstructionCategory::Arithmetic,
 72              InstructionCategory::Comparison,
 73              InstructionCategory::Logic,
 74              InstructionCategory::Control,
 75          ]
 76      }
 77  
 78      /// Returns the category name as a string.
 79      pub const fn name(&self) -> &'static str {
 80          match self {
 81              Self::Arithmetic => "arithmetic",
 82              Self::Comparison => "comparison",
 83              Self::Logic => "logic",
 84              Self::Control => "control",
 85          }
 86      }
 87  }
 88  
 89  impl Display for InstructionCategory {
 90      fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 91          write!(f, "{}", self.name())
 92      }
 93  }
 94  
 95  /// The whitelisted instructions available in AlphaVM.
 96  ///
 97  /// AlphaVM uses a restricted instruction set compared to the full SnarkVM.
 98  /// Only these 14 instructions are permitted in AlphaVM programs.
 99  #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
100  pub enum WhitelistedInstruction {
101      // Arithmetic (2)
102      /// Addition operation.
103      Add,
104      /// Subtraction operation.
105      Sub,
106  
107      // Comparison (6)
108      /// Greater than or equal comparison.
109      Gte,
110      /// Greater than comparison.
111      Gt,
112      /// Less than or equal comparison.
113      Lte,
114      /// Less than comparison.
115      Lt,
116      /// Equality check.
117      IsEq,
118      /// Inequality check.
119      IsNeq,
120  
121      // Logic (3)
122      /// Logical AND operation.
123      And,
124      /// Logical OR operation.
125      Or,
126      /// Logical NOR operation.
127      Nor,
128  
129      // Control (3)
130      /// Conditional selection (ternary operator).
131      Ternary,
132      /// Asynchronous finalize call.
133      Async,
134      /// Type casting operation.
135      Cast,
136  }
137  
138  impl WhitelistedInstruction {
139      /// The total number of whitelisted instructions.
140      pub const COUNT: usize = 14;
141  
142      /// Returns all whitelisted instructions as a slice.
143      pub const fn all() -> &'static [WhitelistedInstruction] {
144          &[
145              // Arithmetic
146              WhitelistedInstruction::Add,
147              WhitelistedInstruction::Sub,
148              // Comparison
149              WhitelistedInstruction::Gte,
150              WhitelistedInstruction::Gt,
151              WhitelistedInstruction::Lte,
152              WhitelistedInstruction::Lt,
153              WhitelistedInstruction::IsEq,
154              WhitelistedInstruction::IsNeq,
155              // Logic
156              WhitelistedInstruction::And,
157              WhitelistedInstruction::Or,
158              WhitelistedInstruction::Nor,
159              // Control
160              WhitelistedInstruction::Ternary,
161              WhitelistedInstruction::Async,
162              WhitelistedInstruction::Cast,
163          ]
164      }
165  
166      /// Returns the opcode string for this instruction.
167      pub const fn opcode(&self) -> &'static str {
168          match self {
169              // Arithmetic
170              Self::Add => "add",
171              Self::Sub => "sub",
172              // Comparison
173              Self::Gte => "gte",
174              Self::Gt => "gt",
175              Self::Lte => "lte",
176              Self::Lt => "lt",
177              Self::IsEq => "is.eq",
178              Self::IsNeq => "is.neq",
179              // Logic
180              Self::And => "and",
181              Self::Or => "or",
182              Self::Nor => "nor",
183              // Control
184              Self::Ternary => "ternary",
185              Self::Async => "async",
186              Self::Cast => "cast",
187          }
188      }
189  
190      /// Returns the category of this instruction.
191      pub const fn category(&self) -> InstructionCategory {
192          match self {
193              Self::Add | Self::Sub => InstructionCategory::Arithmetic,
194              Self::Gte | Self::Gt | Self::Lte | Self::Lt | Self::IsEq | Self::IsNeq => InstructionCategory::Comparison,
195              Self::And | Self::Or | Self::Nor => InstructionCategory::Logic,
196              Self::Ternary | Self::Async | Self::Cast => InstructionCategory::Control,
197          }
198      }
199  
200      /// Returns all instructions in the given category.
201      pub fn by_category(category: InstructionCategory) -> &'static [WhitelistedInstruction] {
202          match category {
203              InstructionCategory::Arithmetic => &[Self::Add, Self::Sub],
204              InstructionCategory::Comparison => &[Self::Gte, Self::Gt, Self::Lte, Self::Lt, Self::IsEq, Self::IsNeq],
205              InstructionCategory::Logic => &[Self::And, Self::Or, Self::Nor],
206              InstructionCategory::Control => &[Self::Ternary, Self::Async, Self::Cast],
207          }
208      }
209  
210      /// Returns true if the given opcode is whitelisted.
211      pub fn is_whitelisted(opcode: &str) -> bool {
212          matches!(
213              opcode,
214              "add"
215                  | "sub"
216                  | "gte"
217                  | "gt"
218                  | "lte"
219                  | "lt"
220                  | "is.eq"
221                  | "is.neq"
222                  | "and"
223                  | "or"
224                  | "nor"
225                  | "ternary"
226                  | "async"
227                  | "cast"
228          )
229      }
230  
231      /// Attempts to parse an opcode into a WhitelistedInstruction.
232      pub fn from_opcode(opcode: &str) -> Option<Self> {
233          match opcode {
234              "add" => Some(Self::Add),
235              "sub" => Some(Self::Sub),
236              "gte" => Some(Self::Gte),
237              "gt" => Some(Self::Gt),
238              "lte" => Some(Self::Lte),
239              "lt" => Some(Self::Lt),
240              "is.eq" => Some(Self::IsEq),
241              "is.neq" => Some(Self::IsNeq),
242              "and" => Some(Self::And),
243              "or" => Some(Self::Or),
244              "nor" => Some(Self::Nor),
245              "ternary" => Some(Self::Ternary),
246              "async" => Some(Self::Async),
247              "cast" => Some(Self::Cast),
248              _ => None,
249          }
250      }
251  }
252  
253  impl Display for WhitelistedInstruction {
254      fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
255          write!(f, "{}", self.opcode())
256      }
257  }
258  
259  #[cfg(test)]
260  mod tests {
261      use super::*;
262  
263      #[test]
264      fn test_category_count() {
265          // Verify exactly 4 categories
266          assert_eq!(InstructionCategory::COUNT, 4);
267          assert_eq!(InstructionCategory::all().len(), 4);
268      }
269  
270      #[test]
271      fn test_category_contains_all() {
272          let categories = InstructionCategory::all();
273          assert!(categories.contains(&InstructionCategory::Arithmetic));
274          assert!(categories.contains(&InstructionCategory::Comparison));
275          assert!(categories.contains(&InstructionCategory::Logic));
276          assert!(categories.contains(&InstructionCategory::Control));
277      }
278  
279      #[test]
280      fn test_instruction_count() {
281          // Verify exactly 14 instructions (2 + 6 + 3 + 3)
282          assert_eq!(WhitelistedInstruction::COUNT, 14);
283          assert_eq!(WhitelistedInstruction::all().len(), 14);
284      }
285  
286      #[test]
287      fn test_arithmetic_instructions() {
288          let arithmetic = WhitelistedInstruction::by_category(InstructionCategory::Arithmetic);
289          assert_eq!(arithmetic.len(), 2);
290          assert!(arithmetic.contains(&WhitelistedInstruction::Add));
291          assert!(arithmetic.contains(&WhitelistedInstruction::Sub));
292      }
293  
294      #[test]
295      fn test_comparison_instructions() {
296          let comparison = WhitelistedInstruction::by_category(InstructionCategory::Comparison);
297          assert_eq!(comparison.len(), 6);
298          assert!(comparison.contains(&WhitelistedInstruction::Gte));
299          assert!(comparison.contains(&WhitelistedInstruction::Gt));
300          assert!(comparison.contains(&WhitelistedInstruction::Lte));
301          assert!(comparison.contains(&WhitelistedInstruction::Lt));
302          assert!(comparison.contains(&WhitelistedInstruction::IsEq));
303          assert!(comparison.contains(&WhitelistedInstruction::IsNeq));
304      }
305  
306      #[test]
307      fn test_logic_instructions() {
308          let logic = WhitelistedInstruction::by_category(InstructionCategory::Logic);
309          assert_eq!(logic.len(), 3);
310          assert!(logic.contains(&WhitelistedInstruction::And));
311          assert!(logic.contains(&WhitelistedInstruction::Or));
312          assert!(logic.contains(&WhitelistedInstruction::Nor));
313      }
314  
315      #[test]
316      fn test_control_instructions() {
317          let control = WhitelistedInstruction::by_category(InstructionCategory::Control);
318          assert_eq!(control.len(), 3);
319          assert!(control.contains(&WhitelistedInstruction::Ternary));
320          assert!(control.contains(&WhitelistedInstruction::Async));
321          assert!(control.contains(&WhitelistedInstruction::Cast));
322      }
323  
324      #[test]
325      fn test_opcodes() {
326          // Arithmetic
327          assert_eq!(WhitelistedInstruction::Add.opcode(), "add");
328          assert_eq!(WhitelistedInstruction::Sub.opcode(), "sub");
329  
330          // Comparison
331          assert_eq!(WhitelistedInstruction::Gte.opcode(), "gte");
332          assert_eq!(WhitelistedInstruction::Gt.opcode(), "gt");
333          assert_eq!(WhitelistedInstruction::Lte.opcode(), "lte");
334          assert_eq!(WhitelistedInstruction::Lt.opcode(), "lt");
335          assert_eq!(WhitelistedInstruction::IsEq.opcode(), "is.eq");
336          assert_eq!(WhitelistedInstruction::IsNeq.opcode(), "is.neq");
337  
338          // Logic
339          assert_eq!(WhitelistedInstruction::And.opcode(), "and");
340          assert_eq!(WhitelistedInstruction::Or.opcode(), "or");
341          assert_eq!(WhitelistedInstruction::Nor.opcode(), "nor");
342  
343          // Control
344          assert_eq!(WhitelistedInstruction::Ternary.opcode(), "ternary");
345          assert_eq!(WhitelistedInstruction::Async.opcode(), "async");
346          assert_eq!(WhitelistedInstruction::Cast.opcode(), "cast");
347      }
348  
349      #[test]
350      fn test_instruction_categories() {
351          // Arithmetic
352          assert_eq!(WhitelistedInstruction::Add.category(), InstructionCategory::Arithmetic);
353          assert_eq!(WhitelistedInstruction::Sub.category(), InstructionCategory::Arithmetic);
354  
355          // Comparison
356          assert_eq!(WhitelistedInstruction::Gte.category(), InstructionCategory::Comparison);
357          assert_eq!(WhitelistedInstruction::Gt.category(), InstructionCategory::Comparison);
358          assert_eq!(WhitelistedInstruction::Lte.category(), InstructionCategory::Comparison);
359          assert_eq!(WhitelistedInstruction::Lt.category(), InstructionCategory::Comparison);
360          assert_eq!(WhitelistedInstruction::IsEq.category(), InstructionCategory::Comparison);
361          assert_eq!(WhitelistedInstruction::IsNeq.category(), InstructionCategory::Comparison);
362  
363          // Logic
364          assert_eq!(WhitelistedInstruction::And.category(), InstructionCategory::Logic);
365          assert_eq!(WhitelistedInstruction::Or.category(), InstructionCategory::Logic);
366          assert_eq!(WhitelistedInstruction::Nor.category(), InstructionCategory::Logic);
367  
368          // Control
369          assert_eq!(WhitelistedInstruction::Ternary.category(), InstructionCategory::Control);
370          assert_eq!(WhitelistedInstruction::Async.category(), InstructionCategory::Control);
371          assert_eq!(WhitelistedInstruction::Cast.category(), InstructionCategory::Control);
372      }
373  
374      #[test]
375      fn test_is_whitelisted() {
376          // Whitelisted opcodes
377          assert!(WhitelistedInstruction::is_whitelisted("add"));
378          assert!(WhitelistedInstruction::is_whitelisted("sub"));
379          assert!(WhitelistedInstruction::is_whitelisted("gte"));
380          assert!(WhitelistedInstruction::is_whitelisted("gt"));
381          assert!(WhitelistedInstruction::is_whitelisted("lte"));
382          assert!(WhitelistedInstruction::is_whitelisted("lt"));
383          assert!(WhitelistedInstruction::is_whitelisted("is.eq"));
384          assert!(WhitelistedInstruction::is_whitelisted("is.neq"));
385          assert!(WhitelistedInstruction::is_whitelisted("and"));
386          assert!(WhitelistedInstruction::is_whitelisted("or"));
387          assert!(WhitelistedInstruction::is_whitelisted("nor"));
388          assert!(WhitelistedInstruction::is_whitelisted("ternary"));
389          assert!(WhitelistedInstruction::is_whitelisted("async"));
390          assert!(WhitelistedInstruction::is_whitelisted("cast"));
391  
392          // Non-whitelisted opcodes (from full SnarkVM)
393          assert!(!WhitelistedInstruction::is_whitelisted("mul"));
394          assert!(!WhitelistedInstruction::is_whitelisted("div"));
395          assert!(!WhitelistedInstruction::is_whitelisted("pow"));
396          assert!(!WhitelistedInstruction::is_whitelisted("rem"));
397          assert!(!WhitelistedInstruction::is_whitelisted("shl"));
398          assert!(!WhitelistedInstruction::is_whitelisted("shr"));
399          assert!(!WhitelistedInstruction::is_whitelisted("xor"));
400          assert!(!WhitelistedInstruction::is_whitelisted("nand"));
401          assert!(!WhitelistedInstruction::is_whitelisted("not"));
402          assert!(!WhitelistedInstruction::is_whitelisted("abs"));
403          assert!(!WhitelistedInstruction::is_whitelisted("neg"));
404          assert!(!WhitelistedInstruction::is_whitelisted("inv"));
405          assert!(!WhitelistedInstruction::is_whitelisted("double"));
406          assert!(!WhitelistedInstruction::is_whitelisted("square"));
407          assert!(!WhitelistedInstruction::is_whitelisted("hash.bhp256"));
408          assert!(!WhitelistedInstruction::is_whitelisted("commit.bhp256"));
409          assert!(!WhitelistedInstruction::is_whitelisted("call"));
410      }
411  
412      #[test]
413      fn test_from_opcode() {
414          // Valid opcodes
415          assert_eq!(WhitelistedInstruction::from_opcode("add"), Some(WhitelistedInstruction::Add));
416          assert_eq!(WhitelistedInstruction::from_opcode("sub"), Some(WhitelistedInstruction::Sub));
417          assert_eq!(WhitelistedInstruction::from_opcode("is.eq"), Some(WhitelistedInstruction::IsEq));
418          assert_eq!(WhitelistedInstruction::from_opcode("ternary"), Some(WhitelistedInstruction::Ternary));
419  
420          // Invalid opcodes
421          assert_eq!(WhitelistedInstruction::from_opcode("mul"), None);
422          assert_eq!(WhitelistedInstruction::from_opcode("invalid"), None);
423      }
424  
425      #[test]
426      fn test_display() {
427          assert_eq!(format!("{}", WhitelistedInstruction::Add), "add");
428          assert_eq!(format!("{}", WhitelistedInstruction::IsEq), "is.eq");
429          assert_eq!(format!("{}", WhitelistedInstruction::Ternary), "ternary");
430  
431          assert_eq!(format!("{}", InstructionCategory::Arithmetic), "arithmetic");
432          assert_eq!(format!("{}", InstructionCategory::Comparison), "comparison");
433      }
434  
435      #[test]
436      fn test_all_instructions_have_valid_category() {
437          for instruction in WhitelistedInstruction::all() {
438              let category = instruction.category();
439              let category_instructions = WhitelistedInstruction::by_category(category);
440              assert!(
441                  category_instructions.contains(instruction),
442                  "Instruction {:?} should be in category {:?}",
443                  instruction,
444                  category
445              );
446          }
447      }
448  
449      #[test]
450      fn test_category_instruction_counts() {
451          // Verify the sum of instructions per category equals total
452          let arithmetic_count = WhitelistedInstruction::by_category(InstructionCategory::Arithmetic).len();
453          let comparison_count = WhitelistedInstruction::by_category(InstructionCategory::Comparison).len();
454          let logic_count = WhitelistedInstruction::by_category(InstructionCategory::Logic).len();
455          let control_count = WhitelistedInstruction::by_category(InstructionCategory::Control).len();
456  
457          assert_eq!(arithmetic_count + comparison_count + logic_count + control_count, WhitelistedInstruction::COUNT);
458      }
459  }