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 }