leo_interpreter/
cursor_aleo.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use super::*;
18
19use leo_ast::{
20    BinaryOperation,
21    CoreFunction,
22    IntegerType,
23    Type,
24    UnaryOperation,
25    interpreter_value::{self, AsyncExecution, Future, GlobalId, StructContents, Value},
26};
27
28use snarkvm::{
29    prelude::{
30        Access,
31        Boolean,
32        Field,
33        Identifier,
34        Literal,
35        LiteralType,
36        Network as _,
37        PlaintextType,
38        Register,
39        TestnetV0,
40        ToBits as _,
41        ToBytes as _,
42        integers::Integer,
43    },
44    synthesizer::{Command, Instruction},
45};
46use snarkvm_synthesizer_program::{CallOperator, CastType, Operand};
47
48use rand::Rng as _;
49use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
50use std::mem;
51
52impl Cursor {
53    fn mapping_by_call_operator(&self, operator: &CallOperator<TestnetV0>) -> Option<&HashMap<Value, Value>> {
54        let (program, name) = match operator {
55            CallOperator::Locator(locator) => {
56                (Some(snarkvm_identifier_to_symbol(locator.name())), snarkvm_identifier_to_symbol(locator.resource()))
57            }
58            CallOperator::Resource(id) => (None, snarkvm_identifier_to_symbol(id)),
59        };
60        self.lookup_mapping(program, name)
61    }
62
63    fn get_register(&self, reg: &Register<TestnetV0>) -> &Value {
64        let Some(Frame { element: Element::AleoExecution { registers, .. }, .. }) = self.frames.last() else {
65            panic!();
66        };
67        match reg {
68            Register::Locator(index) => {
69                registers.get(index).expect("valid .aleo code doesn't access undefined registers")
70            }
71            Register::Access(index, accesses) => {
72                let mut current_value =
73                    registers.get(index).expect("valid .aleo code doesn't access undefined registers");
74                for access in accesses.iter() {
75                    match access {
76                        Access::Member(id) => {
77                            if let Value::Struct(current_struct) = current_value {
78                                let name = snarkvm_identifier_to_symbol(id);
79                                current_value = current_struct.contents.get(&name).expect("struct missing member");
80                            } else {
81                                tc_fail!();
82                            }
83                        }
84                        Access::Index(index) => {
85                            if let Value::Array(current_array) = current_value {
86                                current_value = current_array.get(**index as usize).expect("array index out of bounds");
87                            } else {
88                                tc_fail!();
89                            }
90                        }
91                    }
92                }
93
94                current_value
95            }
96        }
97    }
98
99    fn set_register(&mut self, reg: Register<TestnetV0>, value: Value) {
100        let Some(Frame { element: Element::AleoExecution { registers, .. }, .. }) = self.frames.last_mut() else {
101            panic!();
102        };
103
104        match reg {
105            Register::Locator(index) => {
106                registers.insert(index, value);
107            }
108            Register::Access(_, _) => todo!(),
109        }
110    }
111
112    fn instructions_len(&self) -> usize {
113        let Some(Frame { element: Element::AleoExecution { context, .. }, .. }) = self.frames.last() else {
114            panic!();
115        };
116        match &**context {
117            AleoContext::Closure(closure) => closure.instructions().len(),
118            AleoContext::Function(function) => function.instructions().len(),
119            AleoContext::Finalize(finalize) => finalize.commands().len(),
120        }
121    }
122
123    fn increment_instruction_index(&mut self) {
124        let Some(Frame { element: Element::AleoExecution { instruction_index, .. }, .. }) = self.frames.last_mut()
125        else {
126            panic!();
127        };
128        *instruction_index += 1;
129    }
130
131    fn execution_complete(&self) -> bool {
132        let Some(Frame { element: Element::AleoExecution { instruction_index, .. }, .. }) = self.frames.last() else {
133            panic!();
134        };
135        *instruction_index >= self.instructions_len()
136    }
137
138    fn next_instruction(&self) -> Option<&Instruction<TestnetV0>> {
139        let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) = self.frames.last()
140        else {
141            panic!();
142        };
143        match &**context {
144            AleoContext::Closure(closure) => closure.instructions().get(*instruction_index),
145            AleoContext::Function(function) => function.instructions().get(*instruction_index),
146            AleoContext::Finalize(_) => None,
147        }
148    }
149
150    fn next_command(&self) -> Option<&Command<TestnetV0>> {
151        let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) = self.frames.last()
152        else {
153            panic!();
154        };
155        match &**context {
156            AleoContext::Closure(_) | AleoContext::Function(_) => None,
157            AleoContext::Finalize(finalize) => finalize.commands().get(*instruction_index),
158        }
159    }
160
161    fn operand_value(&self, operand: &Operand<TestnetV0>) -> Value {
162        match operand {
163            Operand::Literal(literal) => match literal {
164                Literal::Address(x) => Value::Address(*x),
165                Literal::Boolean(x) => Value::Bool(**x),
166                Literal::Field(x) => Value::Field(*x),
167                Literal::Group(x) => Value::Group(*x),
168                Literal::I8(x) => Value::I8(**x),
169                Literal::I16(x) => Value::I16(**x),
170                Literal::I32(x) => Value::I32(**x),
171                Literal::I64(x) => Value::I64(**x),
172                Literal::I128(x) => Value::I128(**x),
173                Literal::U8(x) => Value::U8(**x),
174                Literal::U16(x) => Value::U16(**x),
175                Literal::U32(x) => Value::U32(**x),
176                Literal::U64(x) => Value::U64(**x),
177                Literal::U128(x) => Value::U128(**x),
178                Literal::Scalar(x) => Value::Scalar(*x),
179                Literal::Signature(_) => todo!(),
180                Literal::String(_) => todo!(),
181            },
182            Operand::Register(register) => self.get_register(register).clone(),
183            Operand::ProgramID(_) => todo!(),
184            Operand::Signer => Value::Address(self.signer),
185            Operand::Caller => {
186                if let Some(function_context) = self.contexts.last() {
187                    Value::Address(function_context.caller)
188                } else {
189                    Value::Address(self.signer)
190                }
191            }
192            Operand::BlockHeight => Value::U32(self.block_height),
193            Operand::NetworkID => todo!(),
194        }
195    }
196
197    fn step_aleo_instruction(&mut self, instruction: Instruction<TestnetV0>) -> Result<()> {
198        // The Aleo VM code is a linear sequence of instructions, so we don't need to keep
199        // a stack of Elements (except for calls). Just run instructions in order.
200        use Instruction::*;
201
202        let Some(Frame { step, .. }) = self.frames.last() else {
203            panic!("frame expected");
204        };
205
206        macro_rules! unary {
207            ($svm_op: expr, $op: ident) => {{
208                let operand = self.operand_value(&$svm_op.operands()[0]);
209                let value = interpreter_value::evaluate_unary(Default::default(), UnaryOperation::$op, &operand)?;
210                self.increment_instruction_index();
211                (value, $svm_op.destinations()[0].clone())
212            }};
213        }
214
215        macro_rules! binary {
216            ($svm_op: expr, $op: ident) => {{
217                let operand0 = self.operand_value(&$svm_op.operands()[0]);
218                let operand1 = self.operand_value(&$svm_op.operands()[1]);
219                let value =
220                    interpreter_value::evaluate_binary(Default::default(), BinaryOperation::$op, &operand0, &operand1)?;
221                self.increment_instruction_index();
222                (value, $svm_op.destinations()[0].clone())
223            }};
224        }
225
226        macro_rules! commit_function {
227            ($commit: expr,
228             $to_address: ident,
229             $to_field: ident,
230             $to_group: ident,
231            ) => {{
232                let core_function = match $commit.destination_type() {
233                    LiteralType::Address => CoreFunction::$to_address,
234                    LiteralType::Field => CoreFunction::$to_field,
235                    LiteralType::Group => CoreFunction::$to_group,
236                    _ => panic!("invalid commit destination type"),
237                };
238
239                let randomizer_value = self.operand_value(&$commit.operands()[0]);
240                let operand_value = self.operand_value(&$commit.operands()[1]);
241                self.values.push(randomizer_value);
242                self.values.push(operand_value);
243                let value = interpreter_value::evaluate_core_function(self, core_function, &[], Span::default())?;
244                self.increment_instruction_index();
245                (value.expect("Evaluation should work"), $commit.destinations()[0].clone())
246            }};
247        }
248
249        macro_rules! hash_function {
250            ($hash: expr,
251             $to_address: ident,
252             $to_field: ident,
253             $to_group: ident,
254             $to_i8: ident,
255             $to_i16: ident,
256             $to_i32: ident,
257             $to_i64: ident,
258             $to_i128: ident,
259             $to_u8: ident,
260             $to_u16: ident,
261             $to_u32: ident,
262             $to_u64: ident,
263             $to_u128: ident,
264             $to_scalar: ident,
265            ) => {{
266                let core_function = match $hash.destination_type() {
267                    PlaintextType::Literal(LiteralType::Address) => CoreFunction::$to_address,
268                    PlaintextType::Literal(LiteralType::Field) => CoreFunction::$to_field,
269                    PlaintextType::Literal(LiteralType::Group) => CoreFunction::$to_group,
270                    PlaintextType::Literal(LiteralType::I8) => CoreFunction::$to_i8,
271                    PlaintextType::Literal(LiteralType::I16) => CoreFunction::$to_i16,
272                    PlaintextType::Literal(LiteralType::I32) => CoreFunction::$to_i32,
273                    PlaintextType::Literal(LiteralType::I64) => CoreFunction::$to_i64,
274                    PlaintextType::Literal(LiteralType::I128) => CoreFunction::$to_i128,
275                    PlaintextType::Literal(LiteralType::U8) => CoreFunction::$to_u8,
276                    PlaintextType::Literal(LiteralType::U16) => CoreFunction::$to_u16,
277                    PlaintextType::Literal(LiteralType::U32) => CoreFunction::$to_u32,
278                    PlaintextType::Literal(LiteralType::U64) => CoreFunction::$to_u64,
279                    PlaintextType::Literal(LiteralType::U128) => CoreFunction::$to_u128,
280                    PlaintextType::Literal(LiteralType::Scalar) => CoreFunction::$to_scalar,
281                    _ => panic!("invalid hash destination type"),
282                };
283                let operand_value = self.operand_value(&$hash.operands()[0]);
284                self.values.push(operand_value);
285                let value = interpreter_value::evaluate_core_function(self, core_function, &[], Span::default())?;
286                self.increment_instruction_index();
287                (value.expect("Evaluation should work"), $hash.destinations()[0].clone())
288            }};
289        }
290
291        let (value, destination) = match instruction {
292            Abs(abs) => unary!(abs, Abs),
293            AbsWrapped(abs_wrapped) => unary!(abs_wrapped, AbsWrapped),
294            Add(add) => binary!(add, Add),
295            AddWrapped(add_wrapped) => binary!(add_wrapped, AddWrapped),
296            And(and) => binary!(and, BitwiseAnd),
297            AssertEq(assert_eq) => {
298                let operand0 = self.operand_value(&assert_eq.operands()[0]);
299                let operand1 = self.operand_value(&assert_eq.operands()[1]);
300                if operand0.neq(&operand1)? {
301                    halt_no_span!("assertion failure: {operand0} != {operand1}");
302                }
303                self.increment_instruction_index();
304                return Ok(());
305            }
306            AssertNeq(assert_neq) => {
307                let operand0 = self.operand_value(&assert_neq.operands()[0]);
308                let operand1 = self.operand_value(&assert_neq.operands()[1]);
309                if operand0.eq(&operand1)? {
310                    halt_no_span!("assertion failure: {operand0} != {operand1}");
311                }
312                self.increment_instruction_index();
313                return Ok(());
314            }
315            Async(async_) if *step == 0 => {
316                let program = self.contexts.current_program().expect("there should be a program");
317                let name = snarkvm_identifier_to_symbol(async_.function_name());
318                let arguments: Vec<Value> = async_.operands().iter().map(|op| self.operand_value(op)).collect();
319                if self.really_async {
320                    self.increment_instruction_index();
321                    let async_ex = AsyncExecution { function: GlobalId { name, program }, arguments };
322                    (Value::Future(Future(vec![async_ex])), async_.destinations()[0].clone())
323                } else {
324                    self.do_call(
325                        program,
326                        name,
327                        arguments.into_iter(),
328                        true, // finalize
329                        Span::default(),
330                    )?;
331                    self.increment_step();
332                    return Ok(());
333                }
334            }
335            Call(call) if *step == 0 => {
336                let (program, name) = match call.operator() {
337                    CallOperator::Locator(locator) => (
338                        snarkvm_identifier_to_symbol(locator.resource()),
339                        snarkvm_identifier_to_symbol(locator.program_id().name()),
340                    ),
341                    CallOperator::Resource(id) => (
342                        snarkvm_identifier_to_symbol(id),
343                        self.contexts.current_program().expect("there should be a program"),
344                    ),
345                };
346                let arguments: Vec<Value> = call.operands().iter().map(|op| self.operand_value(op)).collect();
347                self.do_call(
348                    program,
349                    name,
350                    arguments.into_iter(),
351                    false, // finalize
352                    Span::default(),
353                )?;
354                self.increment_step();
355                return Ok(());
356            }
357            Async(async_) if *step == 1 => {
358                // We've done a call, and the result is on the value stack.
359                self.values.pop();
360                self.set_register(async_.destinations()[0].clone(), Value::Future(Future(Vec::new())));
361                self.increment_instruction_index();
362                return Ok(());
363            }
364            Call(call) if *step == 1 => {
365                // We've done a call, and the result is on the value stack.
366                let Some(result) = self.values.pop() else {
367                    panic!("should have a result");
368                };
369                if call.destinations().len() == 1 {
370                    self.set_register(call.destinations()[0].clone(), result);
371                } else {
372                    let Value::Tuple(tuple) = result else {
373                        panic!("function returning multiple values should create a tuple");
374                    };
375                    for (dest, value) in call.destinations().iter().zip(tuple.into_iter()) {
376                        self.set_register(dest.clone(), value);
377                    }
378                }
379                self.increment_instruction_index();
380                return Ok(());
381            }
382            Call(_) | Async(_) => unreachable!("all cases covered above"),
383            Cast(cast) => {
384                let destination = cast.destinations()[0].clone();
385
386                self.increment_instruction_index();
387
388                let make_struct = |program, name_identifier| {
389                    let name = snarkvm_identifier_to_symbol(name_identifier);
390                    let id = GlobalId { program, name };
391                    let struct_type = self.structs.get(&id).expect("struct type should exist");
392                    let operands = cast.operands().iter().map(|op| self.operand_value(op));
393                    Value::Struct(StructContents {
394                        name,
395                        contents: struct_type.iter().cloned().zip(operands).collect(),
396                    })
397                };
398
399                match cast.cast_type() {
400                    CastType::GroupXCoordinate => {
401                        let Value::Group(g) = self.operand_value(&cast.operands()[0]) else {
402                            tc_fail!();
403                        };
404                        let value = Value::Field(g.to_x_coordinate());
405                        (value, destination)
406                    }
407                    CastType::GroupYCoordinate => {
408                        let Value::Group(g) = self.operand_value(&cast.operands()[0]) else {
409                            tc_fail!();
410                        };
411                        let value = Value::Field(g.to_y_coordinate());
412                        (value, destination)
413                    }
414                    CastType::Plaintext(PlaintextType::Array(_array)) => {
415                        let value = Value::Array(cast.operands().iter().map(|op| self.operand_value(op)).collect());
416                        (value, destination)
417                    }
418                    CastType::Plaintext(PlaintextType::Literal(literal_type)) => {
419                        let operand = self.operand_value(&cast.operands()[0]);
420                        let value = match operand.cast(&snarkvm_literal_type_to_type(*literal_type)) {
421                            Some(value) => value,
422                            None => halt_no_span!("cast failure"),
423                        };
424                        (value, destination)
425                    }
426                    CastType::Record(struct_name) | CastType::Plaintext(PlaintextType::Struct(struct_name)) => {
427                        let program = self.contexts.current_program().expect("there should be a current program");
428                        let value = make_struct(program, struct_name);
429                        (value, destination)
430                    }
431                    CastType::ExternalRecord(locator) => {
432                        let program = snarkvm_identifier_to_symbol(locator.program_id().name());
433                        let value = make_struct(program, locator.name());
434                        (value, destination)
435                    }
436                }
437            }
438            CastLossy(cast_lossy) => {
439                match cast_lossy.cast_type() {
440                    CastType::Plaintext(PlaintextType::Literal(literal_type)) => {
441                        // This is the only variant supported for lossy casts.
442                        let operand = self.operand_value(&cast_lossy.operands()[0]);
443                        let operand_literal = value_to_snarkvm_literal(operand);
444                        let result_literal = match operand_literal.cast_lossy(*literal_type) {
445                            Ok(result_literal) => result_literal,
446                            Err(_) => halt_no_span!("cast failure"),
447                        };
448                        let destination = cast_lossy.destinations()[0].clone();
449                        self.increment_instruction_index();
450                        (snarkvm_literal_to_value(result_literal), destination)
451                    }
452                    _ => tc_fail!(),
453                }
454            }
455            CommitBHP256(commit) => {
456                commit_function!(commit, BHP256CommitToAddress, BHP256CommitToField, BHP256CommitToGroup,)
457            }
458            CommitBHP512(commit) => {
459                commit_function!(commit, BHP512CommitToAddress, BHP512CommitToField, BHP512CommitToGroup,)
460            }
461            CommitBHP768(commit) => {
462                commit_function!(commit, BHP768CommitToAddress, BHP768CommitToField, BHP768CommitToGroup,)
463            }
464            CommitBHP1024(commit) => {
465                commit_function!(commit, BHP1024CommitToAddress, BHP1024CommitToField, BHP1024CommitToGroup,)
466            }
467            CommitPED64(commit) => {
468                commit_function!(commit, Pedersen64CommitToAddress, Pedersen64CommitToField, Pedersen64CommitToGroup,)
469            }
470            CommitPED128(commit) => {
471                commit_function!(commit, Pedersen128CommitToAddress, Pedersen128CommitToField, Pedersen128CommitToGroup,)
472            }
473            Div(div) => binary!(div, Div),
474            DivWrapped(div_wrapped) => binary!(div_wrapped, DivWrapped),
475            Double(double) => unary!(double, Double),
476            GreaterThan(gt) => binary!(gt, Gt),
477            GreaterThanOrEqual(gte) => binary!(gte, Gte),
478            HashBHP256(hash) => hash_function!(
479                hash,
480                BHP256HashToAddress,
481                BHP256HashToField,
482                BHP256HashToGroup,
483                BHP256HashToI8,
484                BHP256HashToI16,
485                BHP256HashToI32,
486                BHP256HashToI64,
487                BHP256HashToI128,
488                BHP256HashToU8,
489                BHP256HashToU16,
490                BHP256HashToU32,
491                BHP256HashToU64,
492                BHP256HashToU128,
493                BHP256HashToScalar,
494            ),
495            HashBHP512(hash) => hash_function!(
496                hash,
497                BHP512HashToAddress,
498                BHP512HashToField,
499                BHP512HashToGroup,
500                BHP512HashToI8,
501                BHP512HashToI16,
502                BHP512HashToI32,
503                BHP512HashToI64,
504                BHP512HashToI128,
505                BHP512HashToU8,
506                BHP512HashToU16,
507                BHP512HashToU32,
508                BHP512HashToU64,
509                BHP512HashToU128,
510                BHP512HashToScalar,
511            ),
512            HashBHP768(hash) => hash_function!(
513                hash,
514                BHP768HashToAddress,
515                BHP768HashToField,
516                BHP768HashToGroup,
517                BHP768HashToI8,
518                BHP768HashToI16,
519                BHP768HashToI32,
520                BHP768HashToI64,
521                BHP768HashToI128,
522                BHP768HashToU8,
523                BHP768HashToU16,
524                BHP768HashToU32,
525                BHP768HashToU64,
526                BHP768HashToU128,
527                BHP768HashToScalar,
528            ),
529            HashBHP1024(hash) => hash_function!(
530                hash,
531                BHP1024HashToAddress,
532                BHP1024HashToField,
533                BHP1024HashToGroup,
534                BHP1024HashToI8,
535                BHP1024HashToI16,
536                BHP1024HashToI32,
537                BHP1024HashToI64,
538                BHP1024HashToI128,
539                BHP1024HashToU8,
540                BHP1024HashToU16,
541                BHP1024HashToU32,
542                BHP1024HashToU64,
543                BHP1024HashToU128,
544                BHP1024HashToScalar,
545            ),
546            HashKeccak256(hash) => hash_function!(
547                hash,
548                Keccak256HashToAddress,
549                Keccak256HashToField,
550                Keccak256HashToGroup,
551                Keccak256HashToI8,
552                Keccak256HashToI16,
553                Keccak256HashToI32,
554                Keccak256HashToI64,
555                Keccak256HashToI128,
556                Keccak256HashToU8,
557                Keccak256HashToU16,
558                Keccak256HashToU32,
559                Keccak256HashToU64,
560                Keccak256HashToU128,
561                Keccak256HashToScalar,
562            ),
563            HashKeccak384(hash) => hash_function!(
564                hash,
565                Keccak384HashToAddress,
566                Keccak384HashToField,
567                Keccak384HashToGroup,
568                Keccak384HashToI8,
569                Keccak384HashToI16,
570                Keccak384HashToI32,
571                Keccak384HashToI64,
572                Keccak384HashToI128,
573                Keccak384HashToU8,
574                Keccak384HashToU16,
575                Keccak384HashToU32,
576                Keccak384HashToU64,
577                Keccak384HashToU128,
578                Keccak384HashToScalar,
579            ),
580            HashKeccak512(hash) => hash_function!(
581                hash,
582                Keccak512HashToAddress,
583                Keccak512HashToField,
584                Keccak512HashToGroup,
585                Keccak512HashToI8,
586                Keccak512HashToI16,
587                Keccak512HashToI32,
588                Keccak512HashToI64,
589                Keccak512HashToI128,
590                Keccak512HashToU8,
591                Keccak512HashToU16,
592                Keccak512HashToU32,
593                Keccak512HashToU64,
594                Keccak512HashToU128,
595                Keccak512HashToScalar,
596            ),
597            HashPED64(hash) => hash_function!(
598                hash,
599                Pedersen64HashToAddress,
600                Pedersen64HashToField,
601                Pedersen64HashToGroup,
602                Pedersen64HashToI8,
603                Pedersen64HashToI16,
604                Pedersen64HashToI32,
605                Pedersen64HashToI64,
606                Pedersen64HashToI128,
607                Pedersen64HashToU8,
608                Pedersen64HashToU16,
609                Pedersen64HashToU32,
610                Pedersen64HashToU64,
611                Pedersen64HashToU128,
612                Pedersen64HashToScalar,
613            ),
614            HashPED128(hash) => hash_function!(
615                hash,
616                Pedersen128HashToAddress,
617                Pedersen128HashToField,
618                Pedersen128HashToGroup,
619                Pedersen128HashToI8,
620                Pedersen128HashToI16,
621                Pedersen128HashToI32,
622                Pedersen128HashToI64,
623                Pedersen128HashToI128,
624                Pedersen128HashToU8,
625                Pedersen128HashToU16,
626                Pedersen128HashToU32,
627                Pedersen128HashToU64,
628                Pedersen128HashToU128,
629                Pedersen128HashToScalar,
630            ),
631            HashPSD2(hash) => hash_function!(
632                hash,
633                Poseidon2HashToAddress,
634                Poseidon2HashToField,
635                Poseidon2HashToGroup,
636                Poseidon2HashToI8,
637                Poseidon2HashToI16,
638                Poseidon2HashToI32,
639                Poseidon2HashToI64,
640                Poseidon2HashToI128,
641                Poseidon2HashToU8,
642                Poseidon2HashToU16,
643                Poseidon2HashToU32,
644                Poseidon2HashToU64,
645                Poseidon2HashToU128,
646                Poseidon2HashToScalar,
647            ),
648            HashPSD4(hash) => hash_function!(
649                hash,
650                Poseidon4HashToAddress,
651                Poseidon4HashToField,
652                Poseidon4HashToGroup,
653                Poseidon4HashToI8,
654                Poseidon4HashToI16,
655                Poseidon4HashToI32,
656                Poseidon4HashToI64,
657                Poseidon4HashToI128,
658                Poseidon4HashToU8,
659                Poseidon4HashToU16,
660                Poseidon4HashToU32,
661                Poseidon4HashToU64,
662                Poseidon4HashToU128,
663                Poseidon4HashToScalar,
664            ),
665            HashPSD8(hash) => hash_function!(
666                hash,
667                Poseidon8HashToAddress,
668                Poseidon8HashToField,
669                Poseidon8HashToGroup,
670                Poseidon8HashToI8,
671                Poseidon8HashToI16,
672                Poseidon8HashToI32,
673                Poseidon8HashToI64,
674                Poseidon8HashToI128,
675                Poseidon8HashToU8,
676                Poseidon8HashToU16,
677                Poseidon8HashToU32,
678                Poseidon8HashToU64,
679                Poseidon8HashToU128,
680                Poseidon8HashToScalar,
681            ),
682            HashSha3_256(hash) => hash_function!(
683                hash,
684                SHA3_256HashToAddress,
685                SHA3_256HashToField,
686                SHA3_256HashToGroup,
687                SHA3_256HashToI8,
688                SHA3_256HashToI16,
689                SHA3_256HashToI32,
690                SHA3_256HashToI64,
691                SHA3_256HashToI128,
692                SHA3_256HashToU8,
693                SHA3_256HashToU16,
694                SHA3_256HashToU32,
695                SHA3_256HashToU64,
696                SHA3_256HashToU128,
697                SHA3_256HashToScalar,
698            ),
699            HashSha3_384(hash) => hash_function!(
700                hash,
701                SHA3_384HashToAddress,
702                SHA3_384HashToField,
703                SHA3_384HashToGroup,
704                SHA3_384HashToI8,
705                SHA3_384HashToI16,
706                SHA3_384HashToI32,
707                SHA3_384HashToI64,
708                SHA3_384HashToI128,
709                SHA3_384HashToU8,
710                SHA3_384HashToU16,
711                SHA3_384HashToU32,
712                SHA3_384HashToU64,
713                SHA3_384HashToU128,
714                SHA3_384HashToScalar,
715            ),
716            HashSha3_512(hash) => hash_function!(
717                hash,
718                SHA3_512HashToAddress,
719                SHA3_512HashToField,
720                SHA3_512HashToGroup,
721                SHA3_512HashToI8,
722                SHA3_512HashToI16,
723                SHA3_512HashToI32,
724                SHA3_512HashToI64,
725                SHA3_512HashToI128,
726                SHA3_512HashToU8,
727                SHA3_512HashToU16,
728                SHA3_512HashToU32,
729                SHA3_512HashToU64,
730                SHA3_512HashToU128,
731                SHA3_512HashToScalar,
732            ),
733            HashManyPSD2(_) | HashManyPSD4(_) | HashManyPSD8(_) => panic!("these instructions don't exist yet"),
734            Inv(inv) => unary!(inv, Inverse),
735            IsEq(eq) => binary!(eq, Eq),
736            IsNeq(neq) => binary!(neq, Neq),
737            LessThan(lt) => binary!(lt, Lt),
738            LessThanOrEqual(lte) => binary!(lte, Lte),
739            Modulo(modulo) => binary!(modulo, Mod),
740            Mul(mul) => binary!(mul, Mul),
741            MulWrapped(mul_wrapped) => binary!(mul_wrapped, MulWrapped),
742            Nand(nand) => binary!(nand, Nand),
743            Neg(neg) => unary!(neg, Negate),
744            Nor(nor) => binary!(nor, Nor),
745            Not(not) => unary!(not, Not),
746            Or(or) => binary!(or, BitwiseOr),
747            Pow(pow) => binary!(pow, Pow),
748            PowWrapped(pow_wrapped) => binary!(pow_wrapped, PowWrapped),
749            Rem(rem) => binary!(rem, Rem),
750            RemWrapped(rem_wrapped) => binary!(rem_wrapped, RemWrapped),
751            Shl(shl) => binary!(shl, Shl),
752            ShlWrapped(shl_wrapped) => binary!(shl_wrapped, ShlWrapped),
753            Shr(shr) => binary!(shr, Shr),
754            ShrWrapped(shr_wrapped) => binary!(shr_wrapped, ShrWrapped),
755            SignVerify(_) => todo!(),
756            Square(square) => unary!(square, Square),
757            SquareRoot(sqrt) => unary!(sqrt, SquareRoot),
758            Sub(sub) => binary!(sub, Sub),
759            SubWrapped(sub_wrapped) => binary!(sub_wrapped, SubWrapped),
760            Ternary(ternary) => {
761                let condition = self.operand_value(&ternary.operands()[0]);
762                let result = match condition {
763                    Value::Bool(true) => &ternary.operands()[1],
764                    Value::Bool(false) => &ternary.operands()[2],
765                    _ => panic!(),
766                };
767                self.increment_instruction_index();
768                (self.operand_value(result), ternary.destinations()[0].clone())
769            }
770            Xor(xor) => binary!(xor, Xor),
771        };
772
773        self.set_register(destination, value);
774
775        Ok(())
776    }
777
778    fn outputs(&self) -> Vec<Value> {
779        let Some(Frame { element, .. }) = self.frames.last() else {
780            panic!("frame expected");
781        };
782        let Element::AleoExecution { context, .. } = element else {
783            panic!("aleo execution expected");
784        };
785
786        let mut result = match &**context {
787            AleoContext::Closure(closure) => {
788                closure.outputs().iter().map(|output| self.operand_value(output.operand())).collect()
789            }
790            AleoContext::Function(function) => {
791                function.outputs().iter().map(|output| self.operand_value(output.operand())).collect()
792            }
793            AleoContext::Finalize(_finalize) => Vec::new(),
794        };
795
796        if result.is_empty() {
797            result.push(Value::Unit);
798        }
799        result
800    }
801
802    fn step_aleo_command(&mut self, command: Command<TestnetV0>) -> Result<()> {
803        use Command::*;
804
805        let (value, destination) = match command {
806            Instruction(instruction) => {
807                self.step_aleo_instruction(instruction)?;
808                return Ok(());
809            }
810            Await(await_) => {
811                let Value::Future(future) = self.get_register(await_.register()) else {
812                    halt_no_span!("attempted to await a non-future");
813                };
814                self.contexts.add_future(future.clone());
815                self.increment_instruction_index();
816                return Ok(());
817            }
818            Contains(contains) => {
819                let mapping = self.mapping_by_call_operator(contains.mapping()).expect("mapping should be present");
820                let key = self.operand_value(contains.key());
821                let result = Value::Bool(mapping.contains_key(&key));
822                self.increment_instruction_index();
823                (result, contains.destination().clone())
824            }
825            Get(get) => {
826                let key = self.operand_value(get.key());
827                let value = self.mapping_by_call_operator(get.mapping()).and_then(|mapping| mapping.get(&key)).cloned();
828                self.increment_instruction_index();
829
830                match value {
831                    Some(v) => (v, get.destination().clone()),
832                    None => halt_no_span!("map access failure: {key}"),
833                }
834            }
835            GetOrUse(get_or_use) => {
836                let key = self.operand_value(get_or_use.key());
837                let value =
838                    self.mapping_by_call_operator(get_or_use.mapping()).and_then(|mapping| mapping.get(&key)).cloned();
839
840                let use_value = value.unwrap_or_else(|| self.operand_value(get_or_use.default()));
841                self.increment_instruction_index();
842
843                (use_value, get_or_use.destination().clone())
844            }
845            Remove(remove) => {
846                let key = self.operand_value(remove.key());
847                let mapping_name = snarkvm_identifier_to_symbol(remove.mapping_name());
848                let maybe_mapping = self.lookup_mapping_mut(None, mapping_name);
849                match maybe_mapping {
850                    None => halt_no_span!("no such mapping {mapping_name}"),
851                    Some(mapping) => {
852                        mapping.remove(&key);
853                    }
854                }
855                self.increment_instruction_index();
856                return Ok(());
857            }
858            Set(set) => {
859                let key = self.operand_value(set.key());
860                let value = self.operand_value(set.value());
861                let mapping_name = snarkvm_identifier_to_symbol(set.mapping_name());
862                let maybe_mapping = self.lookup_mapping_mut(None, mapping_name);
863                match maybe_mapping {
864                    None => halt_no_span!("no such mapping {mapping_name}"),
865                    Some(mapping) => {
866                        mapping.insert(key, value);
867                    }
868                }
869                self.increment_instruction_index();
870                return Ok(());
871            }
872            RandChaCha(rand) => {
873                // If there are operands, they are additional seeds.
874                let mut bits = Vec::new();
875                for value in rand.operands().iter().map(|op| self.operand_value(op)) {
876                    value.write_bits_le(&mut bits);
877                }
878                let field: Field<TestnetV0> = self.rng.r#gen();
879                field.write_bits_le(&mut bits);
880                let seed_vec = TestnetV0::hash_bhp1024(&bits)?.to_bytes_le()?;
881                let mut seed = [0u8; 32];
882                seed.copy_from_slice(&seed_vec[..32]);
883                let mut rng = ChaCha20Rng::from_seed(seed);
884                let value = match rand.destination_type() {
885                    LiteralType::Address => Value::Address(rng.r#gen()),
886                    LiteralType::Boolean => Value::Bool(rng.r#gen()),
887                    LiteralType::Field => Value::Field(rng.r#gen()),
888                    LiteralType::Group => Value::Group(rng.r#gen()),
889                    LiteralType::I8 => Value::I8(rng.r#gen()),
890                    LiteralType::I16 => Value::I16(rng.r#gen()),
891                    LiteralType::I32 => Value::I32(rng.r#gen()),
892                    LiteralType::I64 => Value::I64(rng.r#gen()),
893                    LiteralType::I128 => Value::I128(rng.r#gen()),
894                    LiteralType::U8 => Value::U8(rng.r#gen()),
895                    LiteralType::U16 => Value::U16(rng.r#gen()),
896                    LiteralType::U32 => Value::U32(rng.r#gen()),
897                    LiteralType::U64 => Value::U64(rng.r#gen()),
898                    LiteralType::U128 => Value::U128(rng.r#gen()),
899                    LiteralType::Scalar => Value::Scalar(rng.r#gen()),
900                    LiteralType::Signature => halt_no_span!("Cannot create a random signature"),
901                    LiteralType::String => halt_no_span!("Cannot create a random string"),
902                };
903                self.increment_instruction_index();
904                (value, rand.destination().clone())
905            }
906            BranchEq(branch_eq) => {
907                let first = self.operand_value(branch_eq.first());
908                let second = self.operand_value(branch_eq.second());
909                if first.eq(&second)? {
910                    self.branch(branch_eq.position());
911                } else {
912                    self.increment_instruction_index();
913                }
914                return Ok(());
915            }
916            BranchNeq(branch_neq) => {
917                let first = self.operand_value(branch_neq.first());
918                let second = self.operand_value(branch_neq.second());
919                if first.neq(&second)? {
920                    self.branch(branch_neq.position());
921                } else {
922                    self.increment_instruction_index();
923                }
924                return Ok(());
925            }
926            Position(_) => return Ok(()),
927        };
928
929        self.set_register(destination, value);
930
931        Ok(())
932    }
933
934    fn branch(&mut self, label: &Identifier<TestnetV0>) {
935        let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) =
936            self.frames.last_mut()
937        else {
938            panic!();
939        };
940        let AleoContext::Finalize(finalize) = &mut **context else {
941            panic!();
942        };
943        for (i, cmd) in finalize.commands().iter().enumerate() {
944            if let Command::Position(position) = cmd {
945                if position.name() == label {
946                    *instruction_index = i;
947                    return;
948                }
949            }
950        }
951        panic!("branch to nonexistent label {}", label);
952    }
953
954    pub fn step_aleo(&mut self) -> Result<()> {
955        if let Some(command) = self.next_command().cloned() {
956            self.step_aleo_command(command)?;
957        } else if let Some(instruction) = self.next_instruction().cloned() {
958            self.step_aleo_instruction(instruction)?;
959        }
960
961        if self.execution_complete() {
962            let mut outputs = self.outputs();
963            self.frames.pop();
964            self.contexts.pop();
965            if outputs.len() > 1 {
966                self.values.push(Value::Tuple(outputs));
967            } else {
968                self.values.push(mem::take(&mut outputs[0]));
969            }
970        }
971
972        Ok(())
973    }
974}
975
976fn snarkvm_literal_type_to_type(snarkvm_type: LiteralType) -> Type {
977    use Type::*;
978    match snarkvm_type {
979        LiteralType::Address => Address,
980        LiteralType::Boolean => Boolean,
981        LiteralType::Field => Field,
982        LiteralType::Group => Group,
983        LiteralType::I8 => Integer(IntegerType::I8),
984        LiteralType::I16 => Integer(IntegerType::I16),
985        LiteralType::I32 => Integer(IntegerType::I32),
986        LiteralType::I64 => Integer(IntegerType::I64),
987        LiteralType::I128 => Integer(IntegerType::I128),
988        LiteralType::U8 => Integer(IntegerType::U8),
989        LiteralType::U16 => Integer(IntegerType::U16),
990        LiteralType::U32 => Integer(IntegerType::U32),
991        LiteralType::U64 => Integer(IntegerType::U64),
992        LiteralType::U128 => Integer(IntegerType::U128),
993        LiteralType::Scalar => Scalar,
994        LiteralType::Signature => todo!(),
995        LiteralType::String => todo!(),
996    }
997}
998
999fn snarkvm_literal_to_value(literal: Literal<TestnetV0>) -> Value {
1000    match literal {
1001        Literal::Address(x) => Value::Address(x),
1002        Literal::Boolean(x) => Value::Bool(*x),
1003        Literal::Field(x) => Value::Field(x),
1004        Literal::Group(x) => Value::Group(x),
1005        Literal::I8(x) => Value::I8(*x),
1006        Literal::I16(x) => Value::I16(*x),
1007        Literal::I32(x) => Value::I32(*x),
1008        Literal::I64(x) => Value::I64(*x),
1009        Literal::I128(x) => Value::I128(*x),
1010        Literal::U8(x) => Value::U8(*x),
1011        Literal::U16(x) => Value::U16(*x),
1012        Literal::U32(x) => Value::U32(*x),
1013        Literal::U64(x) => Value::U64(*x),
1014        Literal::U128(x) => Value::U128(*x),
1015        Literal::Scalar(x) => Value::Scalar(x),
1016        Literal::Signature(_) | Literal::String(_) => tc_fail!(),
1017    }
1018}
1019
1020fn value_to_snarkvm_literal(value: Value) -> Literal<TestnetV0> {
1021    match value {
1022        Value::Bool(x) => Literal::Boolean(Boolean::new(x)),
1023        Value::U8(x) => Literal::U8(Integer::new(x)),
1024        Value::U16(x) => Literal::U16(Integer::new(x)),
1025        Value::U32(x) => Literal::U32(Integer::new(x)),
1026        Value::U64(x) => Literal::U64(Integer::new(x)),
1027        Value::U128(x) => Literal::U128(Integer::new(x)),
1028        Value::I8(x) => Literal::I8(Integer::new(x)),
1029        Value::I16(x) => Literal::I16(Integer::new(x)),
1030        Value::I32(x) => Literal::I32(Integer::new(x)),
1031        Value::I64(x) => Literal::I64(Integer::new(x)),
1032        Value::I128(x) => Literal::I128(Integer::new(x)),
1033        Value::Group(x) => Literal::Group(x),
1034        Value::Field(x) => Literal::Field(x),
1035        Value::Scalar(x) => Literal::Scalar(x),
1036        Value::Address(x) => Literal::Address(x),
1037        Value::Array(_) | Value::Repeat(..) | Value::Tuple(_) | Value::Unit | Value::Future(_) | Value::Struct(_) => {
1038            tc_fail!()
1039        }
1040    }
1041}