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    Location,
24    Type,
25    UnaryOperation,
26    interpreter_value::{self, AsyncExecution, Value},
27};
28
29use snarkvm::{
30    prelude::{Identifier, LiteralType, PlaintextType, Register, TestnetV0},
31    synthesizer::{
32        Command,
33        Instruction,
34        program::{
35            CallOperator,
36            CastType,
37            CommitVariant,
38            DeserializeVariant,
39            ECDSAVerifyVariant,
40            HashVariant,
41            Operand,
42            SerializeVariant,
43        },
44    },
45};
46
47use std::mem;
48
49impl Cursor {
50    fn mapping_by_call_operator(&self, operator: &CallOperator<TestnetV0>) -> Option<&HashMap<Value, Value>> {
51        let (program, name) = match operator {
52            CallOperator::Locator(locator) => {
53                (Some(snarkvm_identifier_to_symbol(locator.name())), snarkvm_identifier_to_symbol(locator.resource()))
54            }
55            CallOperator::Resource(id) => (None, snarkvm_identifier_to_symbol(id)),
56        };
57        self.lookup_mapping(program, name)
58    }
59
60    fn get_register(&self, reg: &Register<TestnetV0>) -> Value {
61        let Some(Frame { element: Element::AleoExecution { registers, .. }, .. }) = self.frames.last() else {
62            panic!();
63        };
64        match reg {
65            Register::Locator(index) => {
66                registers.get(index).expect("valid .aleo code doesn't access undefined registers").clone()
67            }
68            Register::Access(index, accesses) => {
69                let value = registers.get(index).expect("valid .aleo code doesn't access undefined registers");
70                value.accesses(accesses.iter().cloned()).expect("Accesses should work.")
71            }
72        }
73    }
74
75    fn set_register(&mut self, reg: Register<TestnetV0>, value: Value) {
76        let Some(Frame { element: Element::AleoExecution { registers, .. }, .. }) = self.frames.last_mut() else {
77            panic!();
78        };
79
80        match reg {
81            Register::Locator(index) => {
82                registers.insert(index, value);
83            }
84            Register::Access(_, _) => panic!("Can't happen"),
85        }
86    }
87
88    fn instructions_len(&self) -> usize {
89        let Some(Frame { element: Element::AleoExecution { context, .. }, .. }) = self.frames.last() else {
90            panic!();
91        };
92        match &**context {
93            AleoContext::Closure(closure) => closure.instructions().len(),
94            AleoContext::Function(function) => function.instructions().len(),
95            AleoContext::Finalize(finalize) => finalize.commands().len(),
96        }
97    }
98
99    fn increment_instruction_index(&mut self) {
100        let Some(Frame { element: Element::AleoExecution { instruction_index, .. }, .. }) = self.frames.last_mut()
101        else {
102            panic!();
103        };
104        *instruction_index += 1;
105    }
106
107    fn execution_complete(&self) -> bool {
108        let Some(Frame { element: Element::AleoExecution { instruction_index, .. }, .. }) = self.frames.last() else {
109            panic!();
110        };
111        *instruction_index >= self.instructions_len()
112    }
113
114    fn next_instruction(&self) -> Option<&Instruction<TestnetV0>> {
115        let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) = self.frames.last()
116        else {
117            panic!();
118        };
119        match &**context {
120            AleoContext::Closure(closure) => closure.instructions().get(*instruction_index),
121            AleoContext::Function(function) => function.instructions().get(*instruction_index),
122            AleoContext::Finalize(_) => None,
123        }
124    }
125
126    fn next_command(&self) -> Option<&Command<TestnetV0>> {
127        let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) = self.frames.last()
128        else {
129            panic!();
130        };
131        match &**context {
132            AleoContext::Closure(_) | AleoContext::Function(_) => None,
133            AleoContext::Finalize(finalize) => finalize.commands().get(*instruction_index),
134        }
135    }
136
137    fn operand_value(&self, operand: &Operand<TestnetV0>) -> Value {
138        match operand {
139            Operand::Literal(literal) => literal.clone().into(),
140            Operand::Register(register) => self.get_register(register).clone(),
141            Operand::ProgramID(_) => todo!(),
142            Operand::Signer => self.signer.clone(),
143            Operand::Caller => {
144                if let Some(function_context) = self.contexts.last() {
145                    function_context.caller.clone()
146                } else {
147                    self.signer.clone()
148                }
149            }
150            Operand::BlockHeight => self.block_height.into(),
151            Operand::NetworkID => todo!(),
152            Operand::Checksum(_) => todo!(),
153            Operand::Edition(_) => todo!(),
154            Operand::ProgramOwner(_) => todo!(),
155        }
156    }
157
158    fn step_aleo_instruction(&mut self, instruction: Instruction<TestnetV0>) -> Result<()> {
159        // The Aleo VM code is a linear sequence of instructions, so we don't need to keep
160        // a stack of Elements (except for calls). Just run instructions in order.
161        use Instruction::*;
162
163        let Some(Frame { step, .. }) = self.frames.last() else {
164            panic!("frame expected");
165        };
166
167        macro_rules! unary {
168            ($svm_op: expr, $op: ident) => {{
169                let operand = self.operand_value(&$svm_op.operands()[0]);
170                let value =
171                    interpreter_value::evaluate_unary(Default::default(), UnaryOperation::$op, &operand, &None)?;
172                self.increment_instruction_index();
173                (value, $svm_op.destinations()[0].clone())
174            }};
175        }
176
177        macro_rules! binary {
178            ($svm_op: expr, $op: ident) => {{
179                let operand0 = self.operand_value(&$svm_op.operands()[0]);
180                let operand1 = self.operand_value(&$svm_op.operands()[1]);
181                let value = interpreter_value::evaluate_binary(
182                    Default::default(),
183                    BinaryOperation::$op,
184                    &operand0,
185                    &operand1,
186                    &None,
187                )?;
188                self.increment_instruction_index();
189                (value, $svm_op.destinations()[0].clone())
190            }};
191        }
192
193        macro_rules! commit_function {
194            ($commit: expr, $variant: expr) => {{
195                let core_function = CoreFunction::Commit($variant, $commit.destination_type());
196                let randomizer_value = self.operand_value(&$commit.operands()[0]);
197                let operand_value = self.operand_value(&$commit.operands()[1]);
198                self.values.push(randomizer_value);
199                self.values.push(operand_value);
200                let value = interpreter_value::evaluate_core_function(self, core_function, &[], Span::default())?;
201                self.increment_instruction_index();
202                (value.expect("Evaluation should work"), $commit.destinations()[0].clone())
203            }};
204        }
205
206        macro_rules! hash_function {
207            ($hash: expr, $variant: expr) => {{
208                // Note. The only supported output types of a `hash` function are literals or bit arrays.
209                let core_function =
210                    CoreFunction::Hash($variant, Type::from_snarkvm::<TestnetV0>($hash.destination_type(), None));
211                let operand_value = self.operand_value(&$hash.operands()[0]);
212                self.values.push(operand_value);
213                let value = interpreter_value::evaluate_core_function(self, core_function, &[], Span::default())?;
214                self.increment_instruction_index();
215                (value.expect("Evaluation should work"), $hash.destinations()[0].clone())
216            }};
217        }
218
219        macro_rules! ecdsa_function {
220            ($ecdsa: expr, $variant: expr) => {{
221                let core_function = CoreFunction::ECDSAVerify($variant);
222                let signature = self.operand_value(&$ecdsa.operands()[0]);
223                let public_key = self.operand_value(&$ecdsa.operands()[1]);
224                let message = self.operand_value(&$ecdsa.operands()[2]);
225                self.values.push(signature);
226                self.values.push(public_key);
227                self.values.push(message);
228                let value = interpreter_value::evaluate_core_function(self, core_function, &[], Span::default())?;
229                self.increment_instruction_index();
230                (value.expect("Evaluation should work"), $ecdsa.destinations()[0].clone())
231            }};
232        }
233
234        macro_rules! schnorr_function {
235            ($schnorr: expr, $variant: expr) => {{
236                let core_function = CoreFunction::SignatureVerify;
237                let signature = self.operand_value(&$schnorr.operands()[0]);
238                let public_key = self.operand_value(&$schnorr.operands()[1]);
239                let message = self.operand_value(&$schnorr.operands()[2]);
240                self.values.push(signature);
241                self.values.push(public_key);
242                self.values.push(message);
243                let value = interpreter_value::evaluate_core_function(self, core_function, &[], Span::default())?;
244                self.increment_instruction_index();
245                (value.expect("Evaluation should work"), $schnorr.destinations()[0].clone())
246            }};
247        }
248
249        macro_rules! serialize_function {
250            ($serialize: expr, $variant: expr) => {{
251                let core_function = CoreFunction::Serialize($variant);
252                let operand_value = self.operand_value(&$serialize.operands()[0]);
253                self.values.push(operand_value);
254                let value = interpreter_value::evaluate_core_function(self, core_function, &[], Span::default())?;
255                self.increment_instruction_index();
256                (value.expect("Evaluation should work"), $serialize.destinations()[0].clone())
257            }};
258        }
259
260        macro_rules! deserialize_function {
261            ($deserialize: expr, $variant: expr) => {{
262                let core_function = CoreFunction::Deserialize(
263                    $variant,
264                    Type::from_snarkvm::<TestnetV0>($deserialize.destination_type(), None),
265                );
266                let operand_value = self.operand_value(&$deserialize.operands()[0]);
267                self.values.push(operand_value);
268                let value = interpreter_value::evaluate_core_function(self, core_function, &[], Span::default())?;
269                self.increment_instruction_index();
270                (value.expect("Evaluation should work"), $deserialize.destinations()[0].clone())
271            }};
272        }
273
274        let (value, destination) = match instruction {
275            Abs(abs) => unary!(abs, Abs),
276            AbsWrapped(abs_wrapped) => unary!(abs_wrapped, AbsWrapped),
277            Add(add) => binary!(add, Add),
278            AddWrapped(add_wrapped) => binary!(add_wrapped, AddWrapped),
279            And(and) => binary!(and, BitwiseAnd),
280            AssertEq(assert_eq) => {
281                let operand0 = self.operand_value(&assert_eq.operands()[0]);
282                let operand1 = self.operand_value(&assert_eq.operands()[1]);
283                if !operand0.eq(&operand1)? {
284                    halt_no_span!("assertion failure: {operand0} != {operand1}");
285                }
286                self.increment_instruction_index();
287                return Ok(());
288            }
289            AssertNeq(assert_neq) => {
290                let operand0 = self.operand_value(&assert_neq.operands()[0]);
291                let operand1 = self.operand_value(&assert_neq.operands()[1]);
292                if operand0.eq(&operand1)? {
293                    halt_no_span!("assertion failure: {operand0} != {operand1}");
294                }
295                self.increment_instruction_index();
296                return Ok(());
297            }
298            Async(async_) if *step == 0 => {
299                let program = self.contexts.current_program().expect("there should be a program");
300                let name = snarkvm_identifier_to_symbol(async_.function_name());
301                let arguments: Vec<Value> = async_.operands().iter().map(|op| self.operand_value(op)).collect();
302                if self.really_async {
303                    self.increment_instruction_index();
304                    let async_ex =
305                        AsyncExecution::AsyncFunctionCall { function: Location::new(program, vec![name]), arguments };
306                    (vec![async_ex].into(), async_.destinations()[0].clone())
307                } else {
308                    self.do_call(
309                        program,
310                        &[name],
311                        arguments.into_iter(),
312                        true, // finalize
313                        Span::default(),
314                    )?;
315                    self.increment_step();
316                    return Ok(());
317                }
318            }
319            Call(call) if *step == 0 => {
320                let (program, name) = match call.operator() {
321                    CallOperator::Locator(locator) => (
322                        snarkvm_identifier_to_symbol(locator.resource()),
323                        snarkvm_identifier_to_symbol(locator.program_id().name()),
324                    ),
325                    CallOperator::Resource(id) => (
326                        snarkvm_identifier_to_symbol(id),
327                        self.contexts.current_program().expect("there should be a program"),
328                    ),
329                };
330                let arguments: Vec<Value> = call.operands().iter().map(|op| self.operand_value(op)).collect();
331                self.do_call(
332                    program,
333                    &[name],
334                    arguments.into_iter(),
335                    false, // finalize
336                    Span::default(),
337                )?;
338                self.increment_step();
339                return Ok(());
340            }
341            Async(async_) if *step == 1 => {
342                // We've done a call, and the result is on the value stack.
343                self.values.pop();
344                self.set_register(async_.destinations()[0].clone(), Vec::<AsyncExecution>::new().into());
345                self.increment_instruction_index();
346                return Ok(());
347            }
348            Call(call) if *step == 1 => {
349                // We've done a call, and the result is on the value stack.
350                let Some(result) = self.values.pop() else {
351                    panic!("should have a result");
352                };
353                if call.destinations().len() == 1 {
354                    self.set_register(call.destinations()[0].clone(), result);
355                } else {
356                    for (i, dest) in call.destinations().iter().enumerate() {
357                        self.set_register(
358                            dest.clone(),
359                            result.tuple_index(i).expect("Function returning multiple values should create a tuple."),
360                        );
361                    }
362                }
363                self.increment_instruction_index();
364                return Ok(());
365            }
366            Call(_) | Async(_) => unreachable!("all cases covered above"),
367            Cast(cast) => {
368                let destination = cast.destinations()[0].clone();
369
370                self.increment_instruction_index();
371
372                match cast.cast_type() {
373                    CastType::GroupXCoordinate => {
374                        let value = self.operand_value(&cast.operands()[0]);
375                        let mut values = vec![value];
376                        let Some(result_value) = interpreter_value::evaluate_core_function(
377                            &mut values,
378                            CoreFunction::GroupToXCoordinate,
379                            &[],
380                            Default::default(),
381                        )?
382                        else {
383                            halt_no_span!("GroupToXCoordinate didn't produce a value.");
384                        };
385                        (result_value, destination)
386                    }
387                    CastType::GroupYCoordinate => {
388                        let value = self.operand_value(&cast.operands()[0]);
389                        let mut values = vec![value];
390                        let Some(result_value) = interpreter_value::evaluate_core_function(
391                            &mut values,
392                            CoreFunction::GroupToYCoordinate,
393                            &[],
394                            Default::default(),
395                        )?
396                        else {
397                            halt_no_span!("GroupToYCoordinate didn't produce a value.");
398                        };
399                        (result_value, destination)
400                    }
401                    CastType::Plaintext(PlaintextType::Array(_array)) => {
402                        let value = Value::make_array(cast.operands().iter().map(|op| self.operand_value(op)));
403                        (value, destination)
404                    }
405                    CastType::Plaintext(PlaintextType::Literal(literal_type)) => {
406                        let operand = self.operand_value(&cast.operands()[0]);
407                        let Some(value) = operand.cast(&snarkvm_literal_type_to_type(*literal_type)) else {
408                            halt_no_span!("cast failure");
409                        };
410                        (value, destination)
411                    }
412                    CastType::Plaintext(PlaintextType::Struct(struct_name)) => {
413                        let name = Symbol::intern(&struct_name.to_string());
414                        let struct_type = self.structs.get([name].as_slice()).expect("struct type should exist");
415                        let operands = cast.operands().iter().map(|op| self.operand_value(op));
416                        let value = Value::make_struct(
417                            struct_type.keys().cloned().zip(operands),
418                            self.current_program().unwrap(),
419                            vec![name],
420                        );
421                        (value, destination)
422                    }
423                    CastType::Record(record_name) => {
424                        let program = self.current_program().unwrap();
425                        let name = Symbol::intern(&record_name.to_string());
426                        let path = vec![name];
427                        let record_type = self.records.get(&(program, path.clone())).expect("record type should exist");
428                        let operands = cast.operands().iter().map(|op| self.operand_value(op));
429                        let value =
430                            Value::make_record(record_type.keys().cloned().zip(operands), program, path.clone());
431                        (value, destination)
432                    }
433                    CastType::ExternalRecord(locator) => {
434                        let program = Symbol::intern(&locator.program_id().name().to_string());
435                        let name = Symbol::intern(&locator.resource().to_string());
436                        let path = vec![name];
437                        let record_type = self.records.get(&(program, path.clone())).expect("record type should exist");
438                        let operands = cast.operands().iter().map(|op| self.operand_value(op));
439                        let value =
440                            Value::make_record(record_type.keys().cloned().zip(operands), program, path.clone());
441                        (value, destination)
442                    }
443                }
444            }
445            CastLossy(cast_lossy) => {
446                match cast_lossy.cast_type() {
447                    CastType::Plaintext(PlaintextType::Literal(literal_type)) => {
448                        // This is the only variant supported for lossy casts.
449                        let operand = self.operand_value(&cast_lossy.operands()[0]);
450                        let Some(value) = operand.cast_lossy(literal_type) else {
451                            halt_no_span!("Cast failure");
452                        };
453                        let destination = cast_lossy.destinations()[0].clone();
454                        (value, destination)
455                    }
456                    _ => tc_fail!(),
457                }
458            }
459            CommitBHP256(commit) => commit_function!(commit, CommitVariant::CommitBHP256),
460            CommitBHP512(commit) => commit_function!(commit, CommitVariant::CommitBHP512),
461            CommitBHP768(commit) => commit_function!(commit, CommitVariant::CommitBHP768),
462            CommitBHP1024(commit) => commit_function!(commit, CommitVariant::CommitBHP1024),
463            CommitPED64(commit) => commit_function!(commit, CommitVariant::CommitPED64),
464            CommitPED128(commit) => commit_function!(commit, CommitVariant::CommitPED128),
465            Div(div) => binary!(div, Div),
466            DivWrapped(div_wrapped) => binary!(div_wrapped, DivWrapped),
467            Double(double) => unary!(double, Double),
468            GreaterThan(gt) => binary!(gt, Gt),
469            GreaterThanOrEqual(gte) => binary!(gte, Gte),
470            HashBHP256(hash) => hash_function!(hash, HashVariant::HashBHP256),
471            HashBHP512(hash) => hash_function!(hash, HashVariant::HashBHP512),
472            HashBHP768(hash) => hash_function!(hash, HashVariant::HashBHP768),
473            HashBHP1024(hash) => hash_function!(hash, HashVariant::HashBHP1024),
474            HashKeccak256(hash) => hash_function!(hash, HashVariant::HashKeccak256),
475            HashKeccak384(hash) => hash_function!(hash, HashVariant::HashKeccak384),
476            HashKeccak512(hash) => hash_function!(hash, HashVariant::HashKeccak512),
477            HashPED64(hash) => hash_function!(hash, HashVariant::HashPED64),
478            HashPED128(hash) => hash_function!(hash, HashVariant::HashPED128),
479            HashPSD2(hash) => hash_function!(hash, HashVariant::HashPSD2),
480            HashPSD4(hash) => hash_function!(hash, HashVariant::HashPSD4),
481            HashPSD8(hash) => hash_function!(hash, HashVariant::HashPSD8),
482            HashSha3_256(hash) => hash_function!(hash, HashVariant::HashSha3_256),
483            HashSha3_384(hash) => hash_function!(hash, HashVariant::HashSha3_384),
484            HashSha3_512(hash) => hash_function!(hash, HashVariant::HashSha3_512),
485            HashBHP256Raw(hash) => hash_function!(hash, HashVariant::HashBHP256Raw),
486            HashBHP512Raw(hash) => hash_function!(hash, HashVariant::HashBHP512Raw),
487            HashBHP768Raw(hash) => hash_function!(hash, HashVariant::HashBHP768Raw),
488            HashBHP1024Raw(hash) => hash_function!(hash, HashVariant::HashBHP1024Raw),
489            HashKeccak256Raw(hash) => hash_function!(hash, HashVariant::HashKeccak256Raw),
490            HashKeccak384Raw(hash) => hash_function!(hash, HashVariant::HashKeccak384Raw),
491            HashKeccak512Raw(hash) => hash_function!(hash, HashVariant::HashKeccak512Raw),
492            HashPED64Raw(hash) => hash_function!(hash, HashVariant::HashPED64Raw),
493            HashPED128Raw(hash) => hash_function!(hash, HashVariant::HashPED128Raw),
494            HashPSD2Raw(hash) => hash_function!(hash, HashVariant::HashPSD2Raw),
495            HashPSD4Raw(hash) => hash_function!(hash, HashVariant::HashPSD4Raw),
496            HashPSD8Raw(hash) => hash_function!(hash, HashVariant::HashPSD8Raw),
497            HashSha3_256Raw(hash) => hash_function!(hash, HashVariant::HashSha3_256Raw),
498            HashSha3_384Raw(hash) => hash_function!(hash, HashVariant::HashSha3_384Raw),
499            HashSha3_512Raw(hash) => hash_function!(hash, HashVariant::HashSha3_512Raw),
500            HashKeccak256Native(hash) => hash_function!(hash, HashVariant::HashKeccak256Native),
501            HashKeccak384Native(hash) => hash_function!(hash, HashVariant::HashKeccak384Native),
502            HashKeccak512Native(hash) => hash_function!(hash, HashVariant::HashKeccak512Native),
503            HashSha3_256Native(hash) => hash_function!(hash, HashVariant::HashSha3_256Native),
504            HashSha3_384Native(hash) => hash_function!(hash, HashVariant::HashSha3_384Native),
505            HashSha3_512Native(hash) => hash_function!(hash, HashVariant::HashSha3_512Native),
506            HashKeccak256NativeRaw(hash) => hash_function!(hash, HashVariant::HashKeccak256NativeRaw),
507            HashKeccak384NativeRaw(hash) => hash_function!(hash, HashVariant::HashKeccak384NativeRaw),
508            HashKeccak512NativeRaw(hash) => hash_function!(hash, HashVariant::HashKeccak512NativeRaw),
509            HashSha3_256NativeRaw(hash) => hash_function!(hash, HashVariant::HashSha3_256NativeRaw),
510            HashSha3_384NativeRaw(hash) => hash_function!(hash, HashVariant::HashSha3_384NativeRaw),
511            HashSha3_512NativeRaw(hash) => hash_function!(hash, HashVariant::HashSha3_512NativeRaw),
512            ECDSAVerifyDigest(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::Digest),
513            ECDSAVerifyDigestEth(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::DigestEth),
514            ECDSAVerifyKeccak256(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashKeccak256),
515            ECDSAVerifyKeccak256Raw(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashKeccak256Raw),
516            ECDSAVerifyKeccak256Eth(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashKeccak256Eth),
517            ECDSAVerifyKeccak384(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashKeccak384),
518            ECDSAVerifyKeccak384Raw(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashKeccak384Raw),
519            ECDSAVerifyKeccak384Eth(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashKeccak384Eth),
520            ECDSAVerifyKeccak512(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashKeccak512),
521            ECDSAVerifyKeccak512Raw(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashKeccak512Raw),
522            ECDSAVerifyKeccak512Eth(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashKeccak512Eth),
523            ECDSAVerifySha3_256(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashSha3_256),
524            ECDSAVerifySha3_256Raw(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashSha3_256Raw),
525            ECDSAVerifySha3_256Eth(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashSha3_256Eth),
526            ECDSAVerifySha3_384(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashSha3_384),
527            ECDSAVerifySha3_384Raw(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashSha3_384Raw),
528            ECDSAVerifySha3_384Eth(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashSha3_384Eth),
529            ECDSAVerifySha3_512(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashSha3_512),
530            ECDSAVerifySha3_512Raw(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashSha3_512Raw),
531            ECDSAVerifySha3_512Eth(ecdsa) => ecdsa_function!(ecdsa, ECDSAVerifyVariant::HashSha3_512Eth),
532            HashManyPSD2(_) | HashManyPSD4(_) | HashManyPSD8(_) => panic!("these functions don't exist yet"),
533            Inv(inv) => unary!(inv, Inverse),
534            IsEq(eq) => binary!(eq, Eq),
535            IsNeq(neq) => binary!(neq, Neq),
536            LessThan(lt) => binary!(lt, Lt),
537            LessThanOrEqual(lte) => binary!(lte, Lte),
538            Modulo(modulo) => binary!(modulo, Mod),
539            Mul(mul) => binary!(mul, Mul),
540            MulWrapped(mul_wrapped) => binary!(mul_wrapped, MulWrapped),
541            Nand(nand) => binary!(nand, Nand),
542            Neg(neg) => unary!(neg, Negate),
543            Nor(nor) => binary!(nor, Nor),
544            Not(not) => unary!(not, Not),
545            Or(or) => binary!(or, BitwiseOr),
546            Pow(pow) => binary!(pow, Pow),
547            PowWrapped(pow_wrapped) => binary!(pow_wrapped, PowWrapped),
548            Rem(rem) => binary!(rem, Rem),
549            RemWrapped(rem_wrapped) => binary!(rem_wrapped, RemWrapped),
550            Shl(shl) => binary!(shl, Shl),
551            ShlWrapped(shl_wrapped) => binary!(shl_wrapped, ShlWrapped),
552            Shr(shr) => binary!(shr, Shr),
553            ShrWrapped(shr_wrapped) => binary!(shr_wrapped, ShrWrapped),
554            SignVerify(schnorr) => schnorr_function!(schnorr, false),
555            Square(square) => unary!(square, Square),
556            SquareRoot(sqrt) => unary!(sqrt, SquareRoot),
557            Sub(sub) => binary!(sub, Sub),
558            SubWrapped(sub_wrapped) => binary!(sub_wrapped, SubWrapped),
559            Ternary(ternary) => {
560                let condition = self.operand_value(&ternary.operands()[0]);
561                let result = match condition.try_into() {
562                    Ok(true) => &ternary.operands()[1],
563                    Ok(false) => &ternary.operands()[2],
564                    _ => tc_fail!(),
565                };
566                self.increment_instruction_index();
567                (self.operand_value(result), ternary.destinations()[0].clone())
568            }
569            Xor(xor) => binary!(xor, Xor),
570            SerializeBits(serialize_bits) => serialize_function!(serialize_bits, SerializeVariant::ToBits),
571            SerializeBitsRaw(serialize_bits_raw) => {
572                serialize_function!(serialize_bits_raw, SerializeVariant::ToBitsRaw)
573            }
574            DeserializeBits(deserialize_bits) => deserialize_function!(deserialize_bits, DeserializeVariant::FromBits),
575            DeserializeBitsRaw(deserialize_bits_raw) => {
576                deserialize_function!(deserialize_bits_raw, DeserializeVariant::FromBitsRaw)
577            }
578        };
579
580        self.set_register(destination, value);
581
582        Ok(())
583    }
584
585    fn outputs(&self) -> Vec<Value> {
586        let Some(Frame { element, .. }) = self.frames.last() else {
587            panic!("frame expected");
588        };
589        let Element::AleoExecution { context, .. } = element else {
590            panic!("aleo execution expected");
591        };
592
593        let mut result = match &**context {
594            AleoContext::Closure(closure) => {
595                closure.outputs().iter().map(|output| self.operand_value(output.operand())).collect()
596            }
597            AleoContext::Function(function) => {
598                function.outputs().iter().map(|output| self.operand_value(output.operand())).collect()
599            }
600            AleoContext::Finalize(_finalize) => Vec::new(),
601        };
602
603        if result.is_empty() {
604            result.push(Value::make_unit());
605        }
606        result
607    }
608
609    fn step_aleo_command(&mut self, command: Command<TestnetV0>) -> Result<()> {
610        use Command::*;
611
612        let (value, destination) = match command {
613            Instruction(instruction) => {
614                self.step_aleo_instruction(instruction)?;
615                return Ok(());
616            }
617            Await(await_) => {
618                let value = self.get_register(await_.register());
619                let Some(asyncs) = value.as_future() else {
620                    halt_no_span!("attempted to await a non-future");
621                };
622                self.contexts.add_future(asyncs.to_vec());
623                self.increment_instruction_index();
624                return Ok(());
625            }
626            Contains(contains) => {
627                // Value has interior mutability, since SnarkVM's value does, but this is okay - it's just the OnceCell which houses its bits.
628                #[allow(clippy::mutable_key_type)]
629                let mapping = self.mapping_by_call_operator(contains.mapping()).expect("mapping should be present");
630                let key = self.operand_value(contains.key());
631                let result = mapping.contains_key(&key).into();
632                self.increment_instruction_index();
633                (result, contains.destination().clone())
634            }
635            Get(get) => {
636                let key = self.operand_value(get.key());
637                let value = self.mapping_by_call_operator(get.mapping()).and_then(|mapping| mapping.get(&key)).cloned();
638                self.increment_instruction_index();
639
640                match value {
641                    Some(v) => (v, get.destination().clone()),
642                    None => halt_no_span!("map access failure: {key}"),
643                }
644            }
645            GetOrUse(get_or_use) => {
646                let key = self.operand_value(get_or_use.key());
647                let value =
648                    self.mapping_by_call_operator(get_or_use.mapping()).and_then(|mapping| mapping.get(&key)).cloned();
649
650                let use_value = value.unwrap_or_else(|| self.operand_value(get_or_use.default()));
651                self.increment_instruction_index();
652
653                (use_value, get_or_use.destination().clone())
654            }
655            Remove(remove) => {
656                let key = self.operand_value(remove.key());
657                let mapping_name = snarkvm_identifier_to_symbol(remove.mapping_name());
658                let maybe_mapping = self.lookup_mapping_mut(None, mapping_name);
659                match maybe_mapping {
660                    None => halt_no_span!("no such mapping {mapping_name}"),
661                    Some(mapping) => {
662                        mapping.remove(&key);
663                    }
664                }
665                self.increment_instruction_index();
666                return Ok(());
667            }
668            Set(set) => {
669                let key = self.operand_value(set.key());
670                let value = self.operand_value(set.value());
671                let mapping_name = snarkvm_identifier_to_symbol(set.mapping_name());
672                let maybe_mapping = self.lookup_mapping_mut(None, mapping_name);
673                match maybe_mapping {
674                    None => halt_no_span!("no such mapping {mapping_name}"),
675                    Some(mapping) => {
676                        mapping.insert(key, value);
677                    }
678                }
679                self.increment_instruction_index();
680                return Ok(());
681            }
682            RandChaCha(rand) => {
683                // TODO - this is not using the other operands which are supposed to seed the RNG.
684                use CoreFunction::*;
685                let function = ChaChaRand(rand.destination_type());
686                let value =
687                    interpreter_value::evaluate_core_function(self, function, &[], Default::default())?.unwrap();
688                self.increment_instruction_index();
689                (value, rand.destination().clone())
690            }
691            BranchEq(branch_eq) => {
692                let first = self.operand_value(branch_eq.first());
693                let second = self.operand_value(branch_eq.second());
694                if first.eq(&second)? {
695                    self.branch(branch_eq.position());
696                } else {
697                    self.increment_instruction_index();
698                }
699                return Ok(());
700            }
701            BranchNeq(branch_neq) => {
702                let first = self.operand_value(branch_neq.first());
703                let second = self.operand_value(branch_neq.second());
704                if !first.eq(&second)? {
705                    self.branch(branch_neq.position());
706                } else {
707                    self.increment_instruction_index();
708                }
709                return Ok(());
710            }
711            Position(_) => {
712                self.increment_instruction_index();
713                return Ok(());
714            }
715        };
716
717        self.set_register(destination, value);
718
719        Ok(())
720    }
721
722    fn branch(&mut self, label: &Identifier<TestnetV0>) {
723        let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) =
724            self.frames.last_mut()
725        else {
726            panic!();
727        };
728        let AleoContext::Finalize(finalize) = &mut **context else {
729            panic!();
730        };
731        for (i, cmd) in finalize.commands().iter().enumerate() {
732            if let Command::Position(position) = cmd
733                && position.name() == label
734            {
735                *instruction_index = i;
736                return;
737            }
738        }
739        panic!("branch to nonexistent label {label}");
740    }
741
742    pub fn step_aleo(&mut self) -> Result<()> {
743        if let Some(command) = self.next_command().cloned() {
744            self.step_aleo_command(command)?;
745        } else if let Some(instruction) = self.next_instruction().cloned() {
746            self.step_aleo_instruction(instruction)?;
747        }
748
749        if self.execution_complete() {
750            let mut outputs = self.outputs();
751            self.frames.pop();
752            self.contexts.pop();
753            if outputs.len() > 1 {
754                self.values.push(Value::make_tuple(outputs));
755            } else {
756                self.values.push(mem::take(&mut outputs[0]));
757            }
758        }
759
760        Ok(())
761    }
762}
763
764fn snarkvm_literal_type_to_type(snarkvm_type: LiteralType) -> Type {
765    use Type::*;
766    match snarkvm_type {
767        LiteralType::Address => Address,
768        LiteralType::Boolean => Boolean,
769        LiteralType::Field => Field,
770        LiteralType::Group => Group,
771        LiteralType::I8 => Integer(IntegerType::I8),
772        LiteralType::I16 => Integer(IntegerType::I16),
773        LiteralType::I32 => Integer(IntegerType::I32),
774        LiteralType::I64 => Integer(IntegerType::I64),
775        LiteralType::I128 => Integer(IntegerType::I128),
776        LiteralType::U8 => Integer(IntegerType::U8),
777        LiteralType::U16 => Integer(IntegerType::U16),
778        LiteralType::U32 => Integer(IntegerType::U32),
779        LiteralType::U64 => Integer(IntegerType::U64),
780        LiteralType::U128 => Integer(IntegerType::U128),
781        LiteralType::Scalar => Scalar,
782        LiteralType::Signature => todo!(),
783        LiteralType::String => todo!(),
784    }
785}