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