o1vm/interpreters/mips/
interpreter.rs

1use crate::{
2    cannon::PAGE_ADDRESS_SIZE,
3    interpreters::mips::registers::{
4        REGISTER_CURRENT_IP, REGISTER_HEAP_POINTER, REGISTER_HI, REGISTER_LO, REGISTER_NEXT_IP,
5        REGISTER_PREIMAGE_KEY_END, REGISTER_PREIMAGE_OFFSET,
6    },
7    lookups::{Lookup, LookupTableIDs},
8};
9use ark_ff::{One, Zero};
10use strum::{EnumCount, IntoEnumIterator};
11use strum_macros::{EnumCount, EnumIter};
12
13pub const FD_STDIN: u32 = 0;
14pub const FD_STDOUT: u32 = 1;
15pub const FD_STDERR: u32 = 2;
16pub const FD_HINT_READ: u32 = 3;
17pub const FD_HINT_WRITE: u32 = 4;
18pub const FD_PREIMAGE_READ: u32 = 5;
19pub const FD_PREIMAGE_WRITE: u32 = 6;
20
21pub const SYSCALL_MMAP: u32 = 4090;
22pub const SYSCALL_BRK: u32 = 4045;
23pub const SYSCALL_CLONE: u32 = 4120;
24pub const SYSCALL_EXIT_GROUP: u32 = 4246;
25pub const SYSCALL_READ: u32 = 4003;
26pub const SYSCALL_WRITE: u32 = 4004;
27pub const SYSCALL_FCNTL: u32 = 4055;
28
29#[derive(Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Hash, Ord, PartialOrd)]
30pub enum Instruction {
31    RType(RTypeInstruction),
32    JType(JTypeInstruction),
33    IType(ITypeInstruction),
34    // A no-op operation that should only be used for testing. The semantic is
35    // not clearly defined.
36    NoOp,
37}
38
39#[derive(
40    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
41)]
42pub enum RTypeInstruction {
43    #[default]
44    ShiftLeftLogical, // sll
45    ShiftRightLogical,            // srl
46    ShiftRightArithmetic,         // sra
47    ShiftLeftLogicalVariable,     // sllv
48    ShiftRightLogicalVariable,    // srlv
49    ShiftRightArithmeticVariable, // srav
50    JumpRegister,                 // jr
51    JumpAndLinkRegister,          // jalr
52    SyscallMmap,                  // syscall (Mmap)
53    SyscallExitGroup,             // syscall (ExitGroup)
54    SyscallReadHint,              // syscall (Read 3)
55    SyscallReadPreimage,          // syscall (Read 5)
56    SyscallReadOther,             // syscall (Read ?)
57    SyscallWriteHint,             // syscall (Write 4)
58    SyscallWritePreimage,         // syscall (Write 6)
59    SyscallWriteOther,            // syscall (Write ?)
60    SyscallFcntl,                 // syscall (Fcntl)
61    SyscallOther,                 // syscall (Brk, Clone, ?)
62    MoveZero,                     // movz
63    MoveNonZero,                  // movn
64    Sync,                         // sync
65    MoveFromHi,                   // mfhi
66    MoveToHi,                     // mthi
67    MoveFromLo,                   // mflo
68    MoveToLo,                     // mtlo
69    Multiply,                     // mult
70    MultiplyUnsigned,             // multu
71    Div,                          // div
72    DivUnsigned,                  // divu
73    Add,                          // add
74    AddUnsigned,                  // addu
75    Sub,                          // sub
76    SubUnsigned,                  // subu
77    And,                          // and
78    Or,                           // or
79    Xor,                          // xor
80    Nor,                          // nor
81    SetLessThan,                  // slt
82    SetLessThanUnsigned,          // sltu
83    MultiplyToRegister,           // mul
84    CountLeadingOnes,             // clo
85    CountLeadingZeros,            // clz
86}
87
88#[derive(
89    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
90)]
91pub enum JTypeInstruction {
92    #[default]
93    Jump, // j
94    JumpAndLink, // jal
95}
96
97#[derive(
98    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
99)]
100pub enum ITypeInstruction {
101    #[default]
102    BranchEq, // beq
103    BranchNeq,                    // bne
104    BranchLeqZero,                // blez
105    BranchGtZero,                 // bgtz
106    BranchLtZero,                 // bltz
107    BranchGeqZero,                // bgez
108    AddImmediate,                 // addi
109    AddImmediateUnsigned,         // addiu
110    SetLessThanImmediate,         // slti
111    SetLessThanImmediateUnsigned, // sltiu
112    AndImmediate,                 // andi
113    OrImmediate,                  // ori
114    XorImmediate,                 // xori
115    LoadUpperImmediate,           // lui
116    Load8,                        // lb
117    Load16,                       // lh
118    Load32,                       // lw
119    Load8Unsigned,                // lbu
120    Load16Unsigned,               // lhu
121    LoadWordLeft,                 // lwl
122    LoadWordRight,                // lwr
123    Store8,                       // sb
124    Store16,                      // sh
125    Store32,                      // sw
126    Store32Conditional,           // sc
127    StoreWordLeft,                // swl
128    StoreWordRight,               // swr
129}
130
131impl IntoIterator for Instruction {
132    type Item = Instruction;
133    type IntoIter = std::vec::IntoIter<Self::Item>;
134
135    /// Iterate over the instruction variants
136    fn into_iter(self) -> Self::IntoIter {
137        match self {
138            Instruction::RType(_) => {
139                let mut iter_contents = Vec::with_capacity(RTypeInstruction::COUNT);
140                for rtype in RTypeInstruction::iter() {
141                    iter_contents.push(Instruction::RType(rtype));
142                }
143                iter_contents.into_iter()
144            }
145            Instruction::JType(_) => {
146                let mut iter_contents = Vec::with_capacity(JTypeInstruction::COUNT);
147                for jtype in JTypeInstruction::iter() {
148                    iter_contents.push(Instruction::JType(jtype));
149                }
150                iter_contents.into_iter()
151            }
152            Instruction::IType(_) => {
153                let mut iter_contents = Vec::with_capacity(ITypeInstruction::COUNT);
154                for itype in ITypeInstruction::iter() {
155                    iter_contents.push(Instruction::IType(itype));
156                }
157                iter_contents.into_iter()
158            }
159            Instruction::NoOp => vec![Instruction::NoOp].into_iter(),
160        }
161    }
162}
163
164pub trait InterpreterEnv {
165    /// A position can be seen as an indexed variable
166    type Position;
167
168    /// Allocate a new abstract variable for the current step.
169    /// The variable can be used to store temporary values.
170    /// The variables are "freed" after each step/instruction.
171    /// The variable allocation can be seen as an allocation on a stack that is
172    /// popped after each step execution.
173    /// At the moment, [crate::interpreters::mips::column::SCRATCH_SIZE - 46]
174    /// elements can be allocated. If more temporary variables are required for
175    /// an instruction, increase the value
176    /// [crate::interpreters::mips::column::SCRATCH_SIZE]
177    fn alloc_scratch(&mut self) -> Self::Position;
178
179    fn alloc_scratch_inverse(&mut self) -> Self::Position;
180
181    type Variable: Clone
182        + std::ops::Add<Self::Variable, Output = Self::Variable>
183        + std::ops::Sub<Self::Variable, Output = Self::Variable>
184        + std::ops::Mul<Self::Variable, Output = Self::Variable>
185        + std::fmt::Debug
186        + Zero
187        + One;
188
189    // Returns the variable in the current row corresponding to a given column alias.
190    fn variable(&self, column: Self::Position) -> Self::Variable;
191
192    /// Add a constraint to the proof system, asserting that
193    /// `assert_equals_zero` is 0.
194    fn add_constraint(&mut self, assert_equals_zero: Self::Variable);
195
196    /// Activate the selector for the given instruction.
197    fn activate_selector(&mut self, selector: Instruction);
198
199    /// Check that the witness value in `assert_equals_zero` is 0; otherwise abort.
200    fn check_is_zero(assert_equals_zero: &Self::Variable);
201
202    /// Assert that the value `assert_equals_zero` is 0, and add a constraint in the proof system.
203    fn assert_is_zero(&mut self, assert_equals_zero: Self::Variable) {
204        Self::check_is_zero(&assert_equals_zero);
205        self.add_constraint(assert_equals_zero);
206    }
207
208    /// Check that the witness values in `x` and `y` are equal; otherwise abort.
209    fn check_equal(x: &Self::Variable, y: &Self::Variable);
210
211    /// Assert that the values `x` and `y` are equal, and add a constraint in the proof system.
212    fn assert_equal(&mut self, x: Self::Variable, y: Self::Variable) {
213        // NB: We use a different function to give a better error message for debugging.
214        Self::check_equal(&x, &y);
215        self.add_constraint(x - y);
216    }
217
218    /// Check that the witness value `x` is a boolean (`0` or `1`); otherwise abort.
219    fn check_boolean(x: &Self::Variable);
220
221    /// Assert that the value `x` is boolean, and add a constraint in the proof system.
222    fn assert_boolean(&mut self, x: Self::Variable) {
223        Self::check_boolean(&x);
224        self.add_constraint(x.clone() * x.clone() - x);
225    }
226
227    fn add_lookup(&mut self, lookup: Lookup<Self::Variable>);
228
229    fn instruction_counter(&self) -> Self::Variable;
230
231    fn increase_instruction_counter(&mut self);
232
233    /// Fetch the value of the general purpose register with index `idx` and store it in local
234    /// position `output`.
235    ///
236    /// # Safety
237    ///
238    /// No lookups or other constraints are added as part of this operation. The caller must
239    /// manually add the lookups for this operation.
240    unsafe fn fetch_register(
241        &mut self,
242        idx: &Self::Variable,
243        output: Self::Position,
244    ) -> Self::Variable;
245
246    /// Set the general purpose register with index `idx` to `value` if `if_is_true` is true.
247    ///
248    /// # Safety
249    ///
250    /// No lookups or other constraints are added as part of this operation. The caller must
251    /// manually add the lookups for this operation.
252    unsafe fn push_register_if(
253        &mut self,
254        idx: &Self::Variable,
255        value: Self::Variable,
256        if_is_true: &Self::Variable,
257    );
258
259    /// Set the general purpose register with index `idx` to `value`.
260    ///
261    /// # Safety
262    ///
263    /// No lookups or other constraints are added as part of this operation. The caller must
264    /// manually add the lookups for this operation.
265    unsafe fn push_register(&mut self, idx: &Self::Variable, value: Self::Variable) {
266        self.push_register_if(idx, value, &Self::constant(1))
267    }
268
269    /// Fetch the last 'access index' for the general purpose register with index `idx`, and store
270    /// it in local position `output`.
271    ///
272    /// # Safety
273    ///
274    /// No lookups or other constraints are added as part of this operation. The caller must
275    /// manually add the lookups for this operation.
276    unsafe fn fetch_register_access(
277        &mut self,
278        idx: &Self::Variable,
279        output: Self::Position,
280    ) -> Self::Variable;
281
282    /// Set the last 'access index' for the general purpose register with index `idx` to `value` if
283    /// `if_is_true` is true.
284    ///
285    /// # Safety
286    ///
287    /// No lookups or other constraints are added as part of this operation. The caller must
288    /// manually add the lookups for this operation.
289    unsafe fn push_register_access_if(
290        &mut self,
291        idx: &Self::Variable,
292        value: Self::Variable,
293        if_is_true: &Self::Variable,
294    );
295
296    /// Set the last 'access index' for the general purpose register with index `idx` to `value`.
297    ///
298    /// # Safety
299    ///
300    /// No lookups or other constraints are added as part of this operation. The caller must
301    /// manually add the lookups for this operation.
302    unsafe fn push_register_access(&mut self, idx: &Self::Variable, value: Self::Variable) {
303        self.push_register_access_if(idx, value, &Self::constant(1))
304    }
305
306    /// Access the general purpose register with index `idx`, adding constraints asserting that the
307    /// old value was `old_value` and that the new value will be `new_value`, if `if_is_true` is
308    /// true.
309    ///
310    /// # Safety
311    ///
312    /// Callers of this function must manually update the registers if required, this function will
313    /// only update the access counter.
314    unsafe fn access_register_if(
315        &mut self,
316        idx: &Self::Variable,
317        old_value: &Self::Variable,
318        new_value: &Self::Variable,
319        if_is_true: &Self::Variable,
320    ) {
321        let last_accessed = {
322            let last_accessed_location = self.alloc_scratch();
323            unsafe { self.fetch_register_access(idx, last_accessed_location) }
324        };
325        let instruction_counter = self.instruction_counter();
326        let elapsed_time = instruction_counter.clone() - last_accessed.clone();
327        let new_accessed = {
328            // Here, we write as if the register had been written *at the start of the next
329            // instruction*. This ensures that we can't 'time travel' within this
330            // instruction, and claim to read the value that we're about to write!
331            instruction_counter + Self::constant(1)
332            // A register should allow multiple accesses to the same register within the same instruction.
333            // In order to allow this, we always increase the instruction counter by 1.
334        };
335        unsafe { self.push_register_access_if(idx, new_accessed.clone(), if_is_true) };
336        self.add_lookup(Lookup::write_if(
337            if_is_true.clone(),
338            LookupTableIDs::RegisterLookup,
339            vec![idx.clone(), last_accessed, old_value.clone()],
340        ));
341        self.add_lookup(Lookup::read_if(
342            if_is_true.clone(),
343            LookupTableIDs::RegisterLookup,
344            vec![idx.clone(), new_accessed, new_value.clone()],
345        ));
346        self.range_check64(&elapsed_time);
347
348        // Update instruction counter after accessing a register.
349        self.increase_instruction_counter();
350    }
351
352    fn read_register(&mut self, idx: &Self::Variable) -> Self::Variable {
353        let value = {
354            let value_location = self.alloc_scratch();
355            unsafe { self.fetch_register(idx, value_location) }
356        };
357        unsafe {
358            self.access_register(idx, &value, &value);
359        };
360        value
361    }
362
363    /// Access the general purpose register with index `idx`, adding constraints asserting that the
364    /// old value was `old_value` and that the new value will be `new_value`.
365    ///
366    /// # Safety
367    ///
368    /// Callers of this function must manually update the registers if required, this function will
369    /// only update the access counter.
370    unsafe fn access_register(
371        &mut self,
372        idx: &Self::Variable,
373        old_value: &Self::Variable,
374        new_value: &Self::Variable,
375    ) {
376        self.access_register_if(idx, old_value, new_value, &Self::constant(1))
377    }
378
379    fn write_register_if(
380        &mut self,
381        idx: &Self::Variable,
382        new_value: Self::Variable,
383        if_is_true: &Self::Variable,
384    ) {
385        let old_value = {
386            let value_location = self.alloc_scratch();
387            unsafe { self.fetch_register(idx, value_location) }
388        };
389        // Ensure that we only write 0 to the 0 register.
390        let actual_new_value = {
391            let idx_is_zero = self.is_zero(idx);
392            let pos = self.alloc_scratch();
393            self.copy(&((Self::constant(1) - idx_is_zero) * new_value), pos)
394        };
395        unsafe {
396            self.access_register_if(idx, &old_value, &actual_new_value, if_is_true);
397        };
398        unsafe {
399            self.push_register_if(idx, actual_new_value, if_is_true);
400        };
401    }
402
403    fn write_register(&mut self, idx: &Self::Variable, new_value: Self::Variable) {
404        self.write_register_if(idx, new_value, &Self::constant(1))
405    }
406
407    /// Fetch the memory value at address `addr` and store it in local position `output`.
408    ///
409    /// # Safety
410    ///
411    /// No lookups or other constraints are added as part of this operation. The caller must
412    /// manually add the lookups for this memory operation.
413    unsafe fn fetch_memory(
414        &mut self,
415        addr: &Self::Variable,
416        output: Self::Position,
417    ) -> Self::Variable;
418
419    /// Set the memory value at address `addr` to `value`.
420    ///
421    /// # Safety
422    ///
423    /// No lookups or other constraints are added as part of this operation. The caller must
424    /// manually add the lookups for this memory operation.
425    unsafe fn push_memory(&mut self, addr: &Self::Variable, value: Self::Variable);
426
427    /// Fetch the last 'access index' that the memory at address `addr` was written at, and store
428    /// it in local position `output`.
429    ///
430    /// # Safety
431    ///
432    /// No lookups or other constraints are added as part of this operation. The caller must
433    /// manually add the lookups for this memory operation.
434    unsafe fn fetch_memory_access(
435        &mut self,
436        addr: &Self::Variable,
437        output: Self::Position,
438    ) -> Self::Variable;
439
440    /// Set the last 'access index' for the memory at address `addr` to `value`.
441    ///
442    /// # Safety
443    ///
444    /// No lookups or other constraints are added as part of this operation. The caller must
445    /// manually add the lookups for this memory operation.
446    unsafe fn push_memory_access(&mut self, addr: &Self::Variable, value: Self::Variable);
447
448    /// Access the memory address `addr`, adding constraints asserting that the old value was
449    /// `old_value` and that the new value will be `new_value`.
450    ///
451    /// # Safety
452    ///
453    /// Callers of this function must manually update the memory if required, this function will
454    /// only update the access counter.
455    unsafe fn access_memory(
456        &mut self,
457        addr: &Self::Variable,
458        old_value: &Self::Variable,
459        new_value: &Self::Variable,
460    ) {
461        let last_accessed = {
462            let last_accessed_location = self.alloc_scratch();
463            unsafe { self.fetch_memory_access(addr, last_accessed_location) }
464        };
465        let instruction_counter = self.instruction_counter();
466        let elapsed_time = instruction_counter.clone() - last_accessed.clone();
467        let new_accessed = {
468            // Here, we write as if the memory had been written *at the start of the next
469            // instruction*. This ensures that we can't 'time travel' within this
470            // instruction, and claim to read the value that we're about to write!
471            instruction_counter + Self::constant(1)
472        };
473        unsafe { self.push_memory_access(addr, new_accessed.clone()) };
474        self.add_lookup(Lookup::write_one(
475            LookupTableIDs::MemoryLookup,
476            vec![addr.clone(), last_accessed, old_value.clone()],
477        ));
478        self.add_lookup(Lookup::read_one(
479            LookupTableIDs::MemoryLookup,
480            vec![addr.clone(), new_accessed, new_value.clone()],
481        ));
482        self.range_check64(&elapsed_time);
483
484        // Update instruction counter after accessing a memory address.
485        self.increase_instruction_counter();
486    }
487
488    fn read_memory(&mut self, addr: &Self::Variable) -> Self::Variable {
489        let value = {
490            let value_location = self.alloc_scratch();
491            unsafe { self.fetch_memory(addr, value_location) }
492        };
493        unsafe {
494            self.access_memory(addr, &value, &value);
495        };
496        value
497    }
498
499    fn write_memory(&mut self, addr: &Self::Variable, new_value: Self::Variable) {
500        let old_value = {
501            let value_location = self.alloc_scratch();
502            unsafe { self.fetch_memory(addr, value_location) }
503        };
504        unsafe {
505            self.access_memory(addr, &old_value, &new_value);
506        };
507        unsafe {
508            self.push_memory(addr, new_value);
509        };
510    }
511
512    /// Adds a lookup to the RangeCheck16Lookup table
513    fn lookup_16bits(&mut self, value: &Self::Variable) {
514        self.add_lookup(Lookup::read_one(
515            LookupTableIDs::RangeCheck16Lookup,
516            vec![value.clone()],
517        ));
518    }
519
520    /// Range checks with 2 lookups to the RangeCheck16Lookup table that a value
521    /// is at most 2^`bits`-1  (bits <= 16).
522    fn range_check16(&mut self, value: &Self::Variable, bits: u32) {
523        assert!(bits <= 16);
524        // 0 <= value < 2^bits
525        // First, check lowerbound: 0 <= value < 2^16
526        self.lookup_16bits(value);
527        // Second, check upperbound: value + 2^16 - 2^bits < 2^16
528        self.lookup_16bits(&(value.clone() + Self::constant(1 << 16) - Self::constant(1 << bits)));
529    }
530
531    /// Adds a lookup to the ByteLookup table
532    fn lookup_8bits(&mut self, value: &Self::Variable) {
533        self.add_lookup(Lookup::read_one(
534            LookupTableIDs::ByteLookup,
535            vec![value.clone()],
536        ));
537    }
538
539    /// Range checks with 2 lookups to the ByteLookup table that a value
540    /// is at most 2^`bits`-1  (bits <= 8).
541    fn range_check8(&mut self, value: &Self::Variable, bits: u32) {
542        assert!(bits <= 8);
543        // 0 <= value < 2^bits
544        // First, check lowerbound: 0 <= value < 2^8
545        self.lookup_8bits(value);
546        // Second, check upperbound: value + 2^8 - 2^bits < 2^8
547        self.lookup_8bits(&(value.clone() + Self::constant(1 << 8) - Self::constant(1 << bits)));
548    }
549
550    /// Adds a lookup to the AtMost4Lookup table
551    fn lookup_2bits(&mut self, value: &Self::Variable) {
552        self.add_lookup(Lookup::read_one(
553            LookupTableIDs::AtMost4Lookup,
554            vec![value.clone()],
555        ));
556    }
557
558    /// Range checks with 1 lookup to the AtMost4Lookup table 0 <= value < 4
559    fn range_check2(&mut self, value: &Self::Variable) {
560        self.lookup_2bits(value);
561    }
562
563    fn range_check64(&mut self, _value: &Self::Variable) {
564        // TODO
565    }
566
567    fn set_instruction_pointer(&mut self, ip: Self::Variable) {
568        let idx = Self::constant(REGISTER_CURRENT_IP as u32);
569        let new_accessed = self.instruction_counter() + Self::constant(1);
570        unsafe {
571            self.push_register_access(&idx, new_accessed.clone());
572        }
573        unsafe {
574            self.push_register(&idx, ip.clone());
575        }
576        self.add_lookup(Lookup::read_one(
577            LookupTableIDs::RegisterLookup,
578            vec![idx, new_accessed, ip],
579        ));
580    }
581
582    fn get_instruction_pointer(&mut self) -> Self::Variable {
583        let idx = Self::constant(REGISTER_CURRENT_IP as u32);
584        let ip = {
585            let value_location = self.alloc_scratch();
586            unsafe { self.fetch_register(&idx, value_location) }
587        };
588        self.add_lookup(Lookup::write_one(
589            LookupTableIDs::RegisterLookup,
590            vec![idx, self.instruction_counter(), ip.clone()],
591        ));
592        ip
593    }
594
595    fn set_next_instruction_pointer(&mut self, ip: Self::Variable) {
596        let idx = Self::constant(REGISTER_NEXT_IP as u32);
597        let new_accessed = self.instruction_counter() + Self::constant(1);
598        unsafe {
599            self.push_register_access(&idx, new_accessed.clone());
600        }
601        unsafe {
602            self.push_register(&idx, ip.clone());
603        }
604        self.add_lookup(Lookup::read_one(
605            LookupTableIDs::RegisterLookup,
606            vec![idx, new_accessed, ip],
607        ));
608    }
609
610    fn get_next_instruction_pointer(&mut self) -> Self::Variable {
611        let idx = Self::constant(REGISTER_NEXT_IP as u32);
612        let ip = {
613            let value_location = self.alloc_scratch();
614            unsafe { self.fetch_register(&idx, value_location) }
615        };
616        self.add_lookup(Lookup::write_one(
617            LookupTableIDs::RegisterLookup,
618            vec![idx, self.instruction_counter(), ip.clone()],
619        ));
620        ip
621    }
622
623    fn constant(x: u32) -> Self::Variable;
624
625    /// Extract the bits from the variable `x` between `highest_bit` and `lowest_bit`, and store
626    /// the result in `position`.
627    /// `lowest_bit` becomes the least-significant bit of the resulting value.
628    ///
629    /// # Safety
630    ///
631    /// There are no constraints on the returned value; callers must assert the relationship with
632    /// the source variable `x` and that the returned value fits in `highest_bit - lowest_bit`
633    /// bits.
634    ///
635    /// Do not call this function with highest_bit - lowest_bit >= 32.
636    // TODO: embed the range check in the function when highest_bit - lowest_bit <= 16?
637    unsafe fn bitmask(
638        &mut self,
639        x: &Self::Variable,
640        highest_bit: u32,
641        lowest_bit: u32,
642        position: Self::Position,
643    ) -> Self::Variable;
644
645    /// Return the result of shifting `x` by `by`, storing the result in `position`.
646    ///
647    /// # Safety
648    ///
649    /// There are no constraints on the returned value; callers must assert the relationship with
650    /// the source variable `x` and the shift amount `by`.
651    unsafe fn shift_left(
652        &mut self,
653        x: &Self::Variable,
654        by: &Self::Variable,
655        position: Self::Position,
656    ) -> Self::Variable;
657
658    /// Return the result of shifting `x` by `by`, storing the result in `position`.
659    ///
660    /// # Safety
661    ///
662    /// There are no constraints on the returned value; callers must assert the relationship with
663    /// the source variable `x` and the shift amount `by`.
664    unsafe fn shift_right(
665        &mut self,
666        x: &Self::Variable,
667        by: &Self::Variable,
668        position: Self::Position,
669    ) -> Self::Variable;
670
671    /// Return the result of shifting `x` by `by`, storing the result in `position`.
672    ///
673    /// # Safety
674    ///
675    /// There are no constraints on the returned value; callers must assert the relationship with
676    /// the source variable `x` and the shift amount `by`.
677    unsafe fn shift_right_arithmetic(
678        &mut self,
679        x: &Self::Variable,
680        by: &Self::Variable,
681        position: Self::Position,
682    ) -> Self::Variable;
683
684    /// Returns 1 if `x` is 0, or 0 otherwise, storing the result in `position`.
685    ///
686    /// # Safety
687    ///
688    /// There are no constraints on the returned value; callers must assert the relationship with
689    /// `x`.
690    unsafe fn test_zero(&mut self, x: &Self::Variable, position: Self::Position) -> Self::Variable;
691
692    fn is_zero(&mut self, x: &Self::Variable) -> Self::Variable;
693
694    /// Returns 1 if `x` is equal to `y`, or 0 otherwise, storing the result in `position`.
695    fn equal(&mut self, x: &Self::Variable, y: &Self::Variable) -> Self::Variable;
696
697    /// Returns 1 if `x < y` as unsigned integers, or 0 otherwise, storing the result in
698    /// `position`.
699    ///
700    /// # Safety
701    ///
702    /// There are no constraints on the returned value; callers must assert that the value
703    /// correctly represents the relationship between `x` and `y`
704    unsafe fn test_less_than(
705        &mut self,
706        x: &Self::Variable,
707        y: &Self::Variable,
708        position: Self::Position,
709    ) -> Self::Variable;
710
711    /// Returns 1 if `x < y` as signed integers, or 0 otherwise, storing the result in `position`.
712    ///
713    /// # Safety
714    ///
715    /// There are no constraints on the returned value; callers must assert that the value
716    /// correctly represents the relationship between `x` and `y`
717    unsafe fn test_less_than_signed(
718        &mut self,
719        x: &Self::Variable,
720        y: &Self::Variable,
721        position: Self::Position,
722    ) -> Self::Variable;
723
724    /// Returns `x or y`, storing the result in `position`.
725    ///
726    /// # Safety
727    ///
728    /// There are no constraints on the returned value; callers must manually add constraints to
729    /// ensure that it is correctly constructed.
730    unsafe fn and_witness(
731        &mut self,
732        x: &Self::Variable,
733        y: &Self::Variable,
734        position: Self::Position,
735    ) -> Self::Variable;
736
737    /// Returns `x or y`, storing the result in `position`.
738    ///
739    /// # Safety
740    ///
741    /// There are no constraints on the returned value; callers must manually add constraints to
742    /// ensure that it is correctly constructed.
743    unsafe fn or_witness(
744        &mut self,
745        x: &Self::Variable,
746        y: &Self::Variable,
747        position: Self::Position,
748    ) -> Self::Variable;
749
750    /// Returns `x nor y`, storing the result in `position`.
751    ///
752    /// # Safety
753    ///
754    /// There are no constraints on the returned value; callers must manually add constraints to
755    /// ensure that it is correctly constructed.
756    unsafe fn nor_witness(
757        &mut self,
758        x: &Self::Variable,
759        y: &Self::Variable,
760        position: Self::Position,
761    ) -> Self::Variable;
762
763    /// Returns `x xor y`, storing the result in `position`.
764    ///
765    /// # Safety
766    ///
767    /// There are no constraints on the returned value; callers must manually add constraints to
768    /// ensure that it is correctly constructed.
769    unsafe fn xor_witness(
770        &mut self,
771        x: &Self::Variable,
772        y: &Self::Variable,
773        position: Self::Position,
774    ) -> Self::Variable;
775
776    /// Returns `x + y` and the overflow bit, storing the results in `position_out` and
777    /// `position_overflow` respectively.
778    ///
779    /// # Safety
780    ///
781    /// There are no constraints on the returned values; callers must manually add constraints to
782    /// ensure that they are correctly constructed.
783    unsafe fn add_witness(
784        &mut self,
785        y: &Self::Variable,
786        x: &Self::Variable,
787        out_position: Self::Position,
788        overflow_position: Self::Position,
789    ) -> (Self::Variable, Self::Variable);
790
791    /// Returns `x + y` and the underflow bit, storing the results in `position_out` and
792    /// `position_underflow` respectively.
793    ///
794    /// # Safety
795    ///
796    /// There are no constraints on the returned values; callers must manually add constraints to
797    /// ensure that they are correctly constructed.
798    unsafe fn sub_witness(
799        &mut self,
800        y: &Self::Variable,
801        x: &Self::Variable,
802        out_position: Self::Position,
803        underflow_position: Self::Position,
804    ) -> (Self::Variable, Self::Variable);
805
806    /// Returns `x * y`, where `x` and `y` are treated as integers, storing the result in `position`.
807    ///
808    /// # Safety
809    ///
810    /// There are no constraints on the returned value; callers must manually add constraints to
811    /// ensure that it is correctly constructed.
812    unsafe fn mul_signed_witness(
813        &mut self,
814        x: &Self::Variable,
815        y: &Self::Variable,
816        position: Self::Position,
817    ) -> Self::Variable;
818
819    /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi`
820    /// and `position_lo` respectively.
821    ///
822    /// # Safety
823    ///
824    /// There are no constraints on the returned values; callers must manually add constraints to
825    /// ensure that the pair of returned values correspond to the given values `x` and `y`, and
826    /// that they fall within the desired range.
827    unsafe fn mul_hi_lo_signed(
828        &mut self,
829        x: &Self::Variable,
830        y: &Self::Variable,
831        position_hi: Self::Position,
832        position_lo: Self::Position,
833    ) -> (Self::Variable, Self::Variable);
834
835    /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi`
836    /// and `position_lo` respectively.
837    ///
838    /// # Safety
839    ///
840    /// There are no constraints on the returned values; callers must manually add constraints to
841    /// ensure that the pair of returned values correspond to the given values `x` and `y`, and
842    /// that they fall within the desired range.
843    unsafe fn mul_hi_lo(
844        &mut self,
845        x: &Self::Variable,
846        y: &Self::Variable,
847        position_hi: Self::Position,
848        position_lo: Self::Position,
849    ) -> (Self::Variable, Self::Variable);
850
851    /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and
852    /// `position_remainder` respectively.
853    ///
854    /// # Safety
855    ///
856    /// There are no constraints on the returned values; callers must manually add constraints to
857    /// ensure that the pair of returned values correspond to the given values `x` and `y`, and
858    /// that they fall within the desired range.
859    unsafe fn divmod_signed(
860        &mut self,
861        x: &Self::Variable,
862        y: &Self::Variable,
863        position_quotient: Self::Position,
864        position_remainder: Self::Position,
865    ) -> (Self::Variable, Self::Variable);
866
867    /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and
868    /// `position_remainder` respectively.
869    ///
870    /// # Safety
871    ///
872    /// There are no constraints on the returned values; callers must manually add constraints to
873    /// ensure that the pair of returned values correspond to the given values `x` and `y`, and
874    /// that they fall within the desired range.
875    unsafe fn divmod(
876        &mut self,
877        x: &Self::Variable,
878        y: &Self::Variable,
879        position_quotient: Self::Position,
880        position_remainder: Self::Position,
881    ) -> (Self::Variable, Self::Variable);
882
883    /// Returns the number of leading 0s in `x`, storing the result in `position`.
884    ///
885    /// # Safety
886    ///
887    /// There are no constraints on the returned value; callers must manually add constraints to
888    /// ensure that it is correctly constructed.
889    unsafe fn count_leading_zeros(
890        &mut self,
891        x: &Self::Variable,
892        position: Self::Position,
893    ) -> Self::Variable;
894
895    /// Returns the number of leading 1s in `x`, storing the result in `position`.
896    ///
897    /// # Safety
898    ///
899    /// There are no constraints on the returned value; callers must manually add constraints to
900    /// ensure that it is correctly constructed.
901    unsafe fn count_leading_ones(
902        &mut self,
903        x: &Self::Variable,
904        position: Self::Position,
905    ) -> Self::Variable;
906
907    fn copy(&mut self, x: &Self::Variable, position: Self::Position) -> Self::Variable;
908
909    /// Increases the heap pointer by `by_amount` if `if_is_true` is `1`, and returns the previous
910    /// value of the heap pointer.
911    fn increase_heap_pointer(
912        &mut self,
913        by_amount: &Self::Variable,
914        if_is_true: &Self::Variable,
915    ) -> Self::Variable {
916        let idx = Self::constant(REGISTER_HEAP_POINTER as u32);
917        let old_ptr = {
918            let value_location = self.alloc_scratch();
919            unsafe { self.fetch_register(&idx, value_location) }
920        };
921        let new_ptr = old_ptr.clone() + by_amount.clone();
922        unsafe {
923            self.access_register_if(&idx, &old_ptr, &new_ptr, if_is_true);
924        };
925        unsafe {
926            self.push_register_if(&idx, new_ptr, if_is_true);
927        };
928        old_ptr
929    }
930
931    fn set_halted(&mut self, flag: Self::Variable);
932
933    /// Given a variable `x`, this function extends it to a signed integer of
934    /// `bitlength` bits.
935    fn sign_extend(&mut self, x: &Self::Variable, bitlength: u32) -> Self::Variable {
936        // FIXME: Constrain `high_bit`
937        let high_bit = {
938            let pos = self.alloc_scratch();
939            unsafe { self.bitmask(x, bitlength, bitlength - 1, pos) }
940        };
941        // Casting in u64 for special case of bitlength = 0 to avoid overflow.
942        // No condition for constant time execution.
943        // Decomposing the steps for readability.
944        let v: u64 = (1u64 << (32 - bitlength)) - 1;
945        let v: u64 = v << bitlength;
946        let v: u32 = v as u32;
947        high_bit * Self::constant(v) + x.clone()
948    }
949
950    fn report_exit(&mut self, exit_code: &Self::Variable);
951
952    /// Request the preimage oracle for `len` bytes and store the bytes starting
953    /// from `addr`, and it returns the number of bytes actually read.
954    /// The number of bytes actually read will be set into `pos`.
955    /// The first 8 bytes will be the length of the preimage, encoded as an
956    /// unsigned 64bits, and the rest will be the preimage.
957    fn request_preimage_write(
958        &mut self,
959        addr: &Self::Variable,
960        len: &Self::Variable,
961        pos: Self::Position,
962    ) -> Self::Variable;
963
964    fn request_hint_write(&mut self, addr: &Self::Variable, len: &Self::Variable);
965
966    /// Reset the environment to handle the next instruction
967    fn reset(&mut self);
968}
969
970pub fn interpret_instruction<Env: InterpreterEnv>(env: &mut Env, instr: Instruction) {
971    env.activate_selector(instr);
972
973    match instr {
974        Instruction::RType(instr) => interpret_rtype(env, instr),
975        Instruction::JType(instr) => interpret_jtype(env, instr),
976        Instruction::IType(instr) => interpret_itype(env, instr),
977        Instruction::NoOp => interpret_noop(env),
978    }
979}
980
981// FIXME: the noop should not be used in production. The interpreter semantic
982// should be refined. The padding is only for testing purposes when padding is
983// required to reach the size of the domain.
984pub fn interpret_noop<Env: InterpreterEnv>(env: &mut Env) {
985    let instruction_pointer = env.get_instruction_pointer();
986    let instruction = {
987        let v0 = env.read_memory(&instruction_pointer);
988        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
989        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
990        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
991        (v0 * Env::constant(1 << 24))
992            + (v1 * Env::constant(1 << 16))
993            + (v2 * Env::constant(1 << 8))
994            + v3
995    };
996    let opcode = {
997        let pos = env.alloc_scratch();
998        unsafe { env.bitmask(&instruction, 32, 26, pos) }
999    };
1000
1001    env.assert_is_zero(opcode);
1002    let next_instruction_pointer = env.get_next_instruction_pointer();
1003    env.set_instruction_pointer(next_instruction_pointer.clone());
1004    env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1005}
1006
1007pub fn interpret_rtype<Env: InterpreterEnv>(env: &mut Env, instr: RTypeInstruction) {
1008    let instruction_pointer = env.get_instruction_pointer();
1009    let next_instruction_pointer = env.get_next_instruction_pointer();
1010    let instruction = {
1011        let v0 = env.read_memory(&instruction_pointer);
1012        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
1013        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
1014        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
1015        (v0 * Env::constant(1 << 24))
1016            + (v1 * Env::constant(1 << 16))
1017            + (v2 * Env::constant(1 << 8))
1018            + v3
1019    };
1020    let opcode = {
1021        let pos = env.alloc_scratch();
1022        unsafe { env.bitmask(&instruction, 32, 26, pos) }
1023    };
1024    env.range_check8(&opcode, 6);
1025
1026    let rs = {
1027        let pos = env.alloc_scratch();
1028        unsafe { env.bitmask(&instruction, 26, 21, pos) }
1029    };
1030    env.range_check8(&rs, 5);
1031
1032    let rt = {
1033        let pos = env.alloc_scratch();
1034        unsafe { env.bitmask(&instruction, 21, 16, pos) }
1035    };
1036    env.range_check8(&rt, 5);
1037
1038    let rd = {
1039        let pos = env.alloc_scratch();
1040        unsafe { env.bitmask(&instruction, 16, 11, pos) }
1041    };
1042    env.range_check8(&rd, 5);
1043
1044    let shamt = {
1045        let pos = env.alloc_scratch();
1046        unsafe { env.bitmask(&instruction, 11, 6, pos) }
1047    };
1048    env.range_check8(&shamt, 5);
1049
1050    let funct = {
1051        let pos = env.alloc_scratch();
1052        unsafe { env.bitmask(&instruction, 6, 0, pos) }
1053    };
1054    env.range_check8(&funct, 6);
1055
1056    // Check correctness of decomposition of instruction into parts
1057    env.add_constraint(
1058        instruction
1059            - (opcode * Env::constant(1 << 26)
1060                + rs.clone() * Env::constant(1 << 21)
1061                + rt.clone() * Env::constant(1 << 16)
1062                + rd.clone() * Env::constant(1 << 11)
1063                + shamt.clone() * Env::constant(1 << 6)
1064                + funct),
1065    );
1066
1067    match instr {
1068        RTypeInstruction::ShiftLeftLogical => {
1069            let rt = env.read_register(&rt);
1070            // FIXME: Constrain this value
1071            let shifted = unsafe {
1072                let pos = env.alloc_scratch();
1073                env.shift_left(&rt, &shamt, pos)
1074            };
1075            env.write_register(&rd, shifted);
1076            env.set_instruction_pointer(next_instruction_pointer.clone());
1077            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1078        }
1079        RTypeInstruction::ShiftRightLogical => {
1080            let rt = env.read_register(&rt);
1081            // FIXME: Constrain this value
1082            let shifted = unsafe {
1083                let pos = env.alloc_scratch();
1084                env.shift_right(&rt, &shamt, pos)
1085            };
1086            env.write_register(&rd, shifted);
1087            env.set_instruction_pointer(next_instruction_pointer.clone());
1088            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1089        }
1090        RTypeInstruction::ShiftRightArithmetic => {
1091            let rt = env.read_register(&rt);
1092            // FIXME: Constrain this value
1093            let shifted = unsafe {
1094                let pos = env.alloc_scratch();
1095                env.shift_right_arithmetic(&rt, &shamt, pos)
1096            };
1097            env.write_register(&rd, shifted);
1098            env.set_instruction_pointer(next_instruction_pointer.clone());
1099            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1100        }
1101        RTypeInstruction::ShiftLeftLogicalVariable => {
1102            let rs = env.read_register(&rs);
1103            let rt = env.read_register(&rt);
1104            // FIXME: Constrain this value
1105            let shifted = unsafe {
1106                let pos = env.alloc_scratch();
1107                env.shift_left(&rt, &rs, pos)
1108            };
1109            env.write_register(&rd, shifted);
1110            env.set_instruction_pointer(next_instruction_pointer.clone());
1111            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1112        }
1113        RTypeInstruction::ShiftRightLogicalVariable => {
1114            let rs = env.read_register(&rs);
1115            let rt = env.read_register(&rt);
1116            // FIXME: Constrain this value
1117            let shifted = unsafe {
1118                let pos = env.alloc_scratch();
1119                env.shift_right(&rt, &rs, pos)
1120            };
1121            env.write_register(&rd, shifted);
1122            env.set_instruction_pointer(next_instruction_pointer.clone());
1123            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1124        }
1125        RTypeInstruction::ShiftRightArithmeticVariable => {
1126            let rs = env.read_register(&rs);
1127            let rt = env.read_register(&rt);
1128            // FIXME: Constrain this value
1129            let shifted = unsafe {
1130                let pos = env.alloc_scratch();
1131                env.shift_right_arithmetic(&rt, &rs, pos)
1132            };
1133            env.write_register(&rd, shifted);
1134            env.set_instruction_pointer(next_instruction_pointer.clone());
1135            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1136        }
1137        RTypeInstruction::JumpRegister => {
1138            let addr = env.read_register(&rs);
1139            env.set_instruction_pointer(next_instruction_pointer.clone());
1140            env.set_next_instruction_pointer(addr);
1141        }
1142        RTypeInstruction::JumpAndLinkRegister => {
1143            let addr = env.read_register(&rs);
1144            env.write_register(&rd, instruction_pointer + Env::constant(8u32));
1145            env.set_instruction_pointer(next_instruction_pointer.clone());
1146            env.set_next_instruction_pointer(addr);
1147        }
1148        RTypeInstruction::SyscallMmap => {
1149            let requested_alloc_size = env.read_register(&Env::constant(5));
1150            let size_in_pages = {
1151                // FIXME: Requires a range check
1152                let pos = env.alloc_scratch();
1153                unsafe { env.bitmask(&requested_alloc_size, 32, PAGE_ADDRESS_SIZE, pos) }
1154            };
1155            let requires_extra_page = {
1156                let remainder = requested_alloc_size
1157                    - (size_in_pages.clone() * Env::constant(1 << PAGE_ADDRESS_SIZE));
1158                Env::constant(1) - env.is_zero(&remainder)
1159            };
1160            let actual_alloc_size =
1161                (size_in_pages + requires_extra_page) * Env::constant(1 << PAGE_ADDRESS_SIZE);
1162            let address = env.read_register(&Env::constant(4));
1163            let address_is_zero = env.is_zero(&address);
1164            let old_heap_ptr = env.increase_heap_pointer(&actual_alloc_size, &address_is_zero);
1165            let return_position = {
1166                let pos = env.alloc_scratch();
1167                env.copy(
1168                    &(address_is_zero.clone() * old_heap_ptr
1169                        + (Env::constant(1) - address_is_zero) * address),
1170                    pos,
1171                )
1172            };
1173            env.write_register(&Env::constant(2), return_position);
1174            env.write_register(&Env::constant(7), Env::constant(0));
1175            env.set_instruction_pointer(next_instruction_pointer.clone());
1176            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1177        }
1178        RTypeInstruction::SyscallExitGroup => {
1179            let exit_code = env.read_register(&Env::constant(4));
1180            env.report_exit(&exit_code);
1181            env.set_halted(Env::constant(1));
1182        }
1183        RTypeInstruction::SyscallReadHint => {
1184            // We don't really write here, since the value is unused, per the cannon
1185            // implementation. Just claim that we wrote the correct length.
1186            let length = env.read_register(&Env::constant(6));
1187            env.write_register(&Env::constant(2), length);
1188            env.set_instruction_pointer(next_instruction_pointer.clone());
1189            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1190        }
1191        RTypeInstruction::SyscallReadPreimage => {
1192            let addr = env.read_register(&Env::constant(5));
1193            let length = env.read_register(&Env::constant(6));
1194            let preimage_offset =
1195                env.read_register(&Env::constant(REGISTER_PREIMAGE_OFFSET as u32));
1196
1197            let read_length = {
1198                let pos = env.alloc_scratch();
1199                env.request_preimage_write(&addr, &length, pos)
1200            };
1201            env.write_register(
1202                &Env::constant(REGISTER_PREIMAGE_OFFSET as u32),
1203                preimage_offset + read_length.clone(),
1204            );
1205            env.write_register(&Env::constant(2), read_length);
1206            env.write_register(&Env::constant(7), Env::constant(0));
1207            env.set_instruction_pointer(next_instruction_pointer.clone());
1208            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1209        }
1210        RTypeInstruction::SyscallReadOther => {
1211            let fd_id = env.read_register(&Env::constant(4));
1212            let mut check_equal = |expected_fd_id: u32| {
1213                // FIXME: Requires constraints
1214                let pos = env.alloc_scratch();
1215                unsafe { env.test_zero(&(fd_id.clone() - Env::constant(expected_fd_id)), pos) }
1216            };
1217            let is_stdin = check_equal(FD_STDIN);
1218            let is_preimage_read = check_equal(FD_PREIMAGE_READ);
1219            let is_hint_read = check_equal(FD_HINT_READ);
1220
1221            // FIXME: Should assert that `is_preimage_read` and `is_hint_read` cannot be true here.
1222            let other_fd = Env::constant(1) - is_stdin - is_preimage_read - is_hint_read;
1223
1224            // We're either reading stdin, in which case we get `(0, 0)` as desired, or we've hit a
1225            // bad FD that we reject with EBADF.
1226            let v0 = other_fd.clone() * Env::constant(0xFFFFFFFF);
1227            let v1 = other_fd * Env::constant(0x9); // EBADF
1228
1229            env.write_register(&Env::constant(2), v0);
1230            env.write_register(&Env::constant(7), v1);
1231            env.set_instruction_pointer(next_instruction_pointer.clone());
1232            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1233        }
1234        RTypeInstruction::SyscallWriteHint => {
1235            let addr = env.read_register(&Env::constant(5));
1236            let length = env.read_register(&Env::constant(6));
1237            // TODO: Message preimage oracle
1238            env.request_hint_write(&addr, &length);
1239            env.write_register(&Env::constant(2), length);
1240            env.write_register(&Env::constant(7), Env::constant(0));
1241            env.set_instruction_pointer(next_instruction_pointer.clone());
1242            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1243        }
1244        RTypeInstruction::SyscallWritePreimage => {
1245            let addr = env.read_register(&Env::constant(5));
1246            let write_length = env.read_register(&Env::constant(6));
1247
1248            // Cannon assumes that the remaining `byte_length` represents how much remains to be
1249            // read (i.e. all write calls send the full data in one syscall, and attempt to retry
1250            // with the rest until there is a success). This also simplifies the implementation
1251            // here, so we will follow suit.
1252            let bytes_to_preserve_in_register = {
1253                let pos = env.alloc_scratch();
1254                unsafe { env.bitmask(&write_length, 2, 0, pos) }
1255            };
1256            env.range_check2(&bytes_to_preserve_in_register);
1257            let register_idx = {
1258                let registers_left_to_write_after_this = {
1259                    let pos = env.alloc_scratch();
1260                    // The virtual register is 32 bits wide, so we can just read 6 bytes. If the
1261                    // register has an incorrect value, it will be unprovable and we'll fault.
1262                    unsafe { env.bitmask(&write_length, 6, 2, pos) }
1263                };
1264                env.range_check8(&registers_left_to_write_after_this, 4);
1265                Env::constant(REGISTER_PREIMAGE_KEY_END as u32) - registers_left_to_write_after_this
1266            };
1267
1268            let [r0, r1, r2, r3] = {
1269                let register_value = {
1270                    let initial_register_value = env.read_register(&register_idx);
1271
1272                    // We should clear the register if our offset into the read will replace all of its
1273                    // bytes.
1274                    let should_clear_register = env.is_zero(&bytes_to_preserve_in_register);
1275
1276                    let pos = env.alloc_scratch();
1277                    env.copy(
1278                        &((Env::constant(1) - should_clear_register) * initial_register_value),
1279                        pos,
1280                    )
1281                };
1282                [
1283                    {
1284                        let pos = env.alloc_scratch();
1285                        unsafe { env.bitmask(&register_value, 32, 24, pos) }
1286                    },
1287                    {
1288                        let pos = env.alloc_scratch();
1289                        unsafe { env.bitmask(&register_value, 24, 16, pos) }
1290                    },
1291                    {
1292                        let pos = env.alloc_scratch();
1293                        unsafe { env.bitmask(&register_value, 16, 8, pos) }
1294                    },
1295                    {
1296                        let pos = env.alloc_scratch();
1297                        unsafe { env.bitmask(&register_value, 8, 0, pos) }
1298                    },
1299                ]
1300            };
1301            env.lookup_8bits(&r0);
1302            env.lookup_8bits(&r1);
1303            env.lookup_8bits(&r2);
1304            env.lookup_8bits(&r3);
1305
1306            // We choose our read address so that the bytes we read come aligned with the target
1307            // bytes in the register, to avoid an expensive bitshift.
1308            let read_address = addr.clone() - bytes_to_preserve_in_register.clone();
1309
1310            let m0 = env.read_memory(&read_address);
1311            let m1 = env.read_memory(&(read_address.clone() + Env::constant(1)));
1312            let m2 = env.read_memory(&(read_address.clone() + Env::constant(2)));
1313            let m3 = env.read_memory(&(read_address.clone() + Env::constant(3)));
1314
1315            // Now, for some complexity. From the perspective of the write operation, we should be
1316            // reading the `4 - bytes_to_preserve_in_register`. However, to match cannon 1:1, we
1317            // only want to read the bytes up to the end of the current word.
1318            let [overwrite_0, overwrite_1, overwrite_2, overwrite_3] = {
1319                let next_word_addr = {
1320                    let byte_subaddr = {
1321                        // FIXME: Requires a range check
1322                        let pos = env.alloc_scratch();
1323                        unsafe { env.bitmask(&addr, 2, 0, pos) }
1324                    };
1325                    env.range_check2(&byte_subaddr);
1326                    addr.clone() + Env::constant(4) - byte_subaddr
1327                };
1328                let overwrite_0 = {
1329                    // We always write the first byte if we're not preserving it, since it will
1330                    // have been read from `addr`.
1331                    env.equal(&bytes_to_preserve_in_register, &Env::constant(0))
1332                };
1333                let overwrite_1 = {
1334                    // We write the second byte if:
1335                    //   we wrote the first byte
1336                    overwrite_0.clone()
1337                    //   and this isn't the start of the next word (which implies `overwrite_0`),
1338                    - env.equal(&(read_address.clone() + Env::constant(1)), &next_word_addr)
1339                    //   or this byte was read from `addr`
1340                    + env.equal(&bytes_to_preserve_in_register, &Env::constant(1))
1341                };
1342                let overwrite_2 = {
1343                    // We write the third byte if:
1344                    //   we wrote the second byte
1345                    overwrite_1.clone()
1346                    //   and this isn't the start of the next word (which implies `overwrite_1`),
1347                    - env.equal(&(read_address.clone() + Env::constant(2)), &next_word_addr)
1348                    //   or this byte was read from `addr`
1349                    + env.equal(&bytes_to_preserve_in_register, &Env::constant(2))
1350                };
1351                let overwrite_3 = {
1352                    // We write the fourth byte if:
1353                    //   we wrote the third byte
1354                    overwrite_2.clone()
1355                    //   and this isn't the start of the next word (which implies `overwrite_2`),
1356                    - env.equal(&(read_address.clone() + Env::constant(3)), &next_word_addr)
1357                    //   or this byte was read from `addr`
1358                    + env.equal(&bytes_to_preserve_in_register, &Env::constant(3))
1359                };
1360                [overwrite_0, overwrite_1, overwrite_2, overwrite_3]
1361            };
1362
1363            let value = {
1364                let value = ((overwrite_0.clone() * m0
1365                    + (Env::constant(1) - overwrite_0.clone()) * r0)
1366                    * Env::constant(1 << 24))
1367                    + ((overwrite_1.clone() * m1 + (Env::constant(1) - overwrite_1.clone()) * r1)
1368                        * Env::constant(1 << 16))
1369                    + ((overwrite_2.clone() * m2 + (Env::constant(1) - overwrite_2.clone()) * r2)
1370                        * Env::constant(1 << 8))
1371                    + (overwrite_3.clone() * m3 + (Env::constant(1) - overwrite_3.clone()) * r3);
1372                let pos = env.alloc_scratch();
1373                env.copy(&value, pos)
1374            };
1375
1376            // Update the preimage key.
1377            env.write_register(&register_idx, value);
1378            // Reset the preimage offset.
1379            env.write_register(
1380                &Env::constant(REGISTER_PREIMAGE_OFFSET as u32),
1381                Env::constant(0u32),
1382            );
1383            // Return the number of bytes read.
1384            env.write_register(
1385                &Env::constant(2),
1386                overwrite_0 + overwrite_1 + overwrite_2 + overwrite_3,
1387            );
1388            // Set the error register to 0.
1389            env.write_register(&Env::constant(7), Env::constant(0u32));
1390
1391            env.set_instruction_pointer(next_instruction_pointer.clone());
1392            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1393            // REMOVEME: when all itype instructions are implemented.
1394        }
1395        RTypeInstruction::SyscallWriteOther => {
1396            let fd_id = env.read_register(&Env::constant(4));
1397            let write_length = env.read_register(&Env::constant(6));
1398            let mut check_equal = |expected_fd_id: u32| {
1399                // FIXME: Requires constraints
1400                let pos = env.alloc_scratch();
1401                unsafe { env.test_zero(&(fd_id.clone() - Env::constant(expected_fd_id)), pos) }
1402            };
1403            let is_stdout = check_equal(FD_STDOUT);
1404            let is_stderr = check_equal(FD_STDERR);
1405            let is_preimage_write = check_equal(FD_PREIMAGE_WRITE);
1406            let is_hint_write = check_equal(FD_HINT_WRITE);
1407
1408            // FIXME: Should assert that `is_preimage_write` and `is_hint_write` cannot be true
1409            // here.
1410            let known_fd = is_stdout + is_stderr + is_preimage_write + is_hint_write;
1411            let other_fd = Env::constant(1) - known_fd.clone();
1412
1413            // We're either reading stdin, in which case we get `(0, 0)` as desired, or we've hit a
1414            // bad FD that we reject with EBADF.
1415            let v0 = known_fd * write_length + other_fd.clone() * Env::constant(0xFFFFFFFF);
1416            let v1 = other_fd * Env::constant(0x9); // EBADF
1417
1418            env.write_register(&Env::constant(2), v0);
1419            env.write_register(&Env::constant(7), v1);
1420            env.set_instruction_pointer(next_instruction_pointer.clone());
1421            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1422        }
1423        RTypeInstruction::SyscallFcntl => {
1424            let fd_id = env.read_register(&Env::constant(4));
1425            let fd_cmd = env.read_register(&Env::constant(5));
1426            let is_getfl = env.equal(&fd_cmd, &Env::constant(3));
1427            let is_stdin = env.equal(&fd_id, &Env::constant(FD_STDIN));
1428            let is_stdout = env.equal(&fd_id, &Env::constant(FD_STDOUT));
1429            let is_stderr = env.equal(&fd_id, &Env::constant(FD_STDERR));
1430            let is_hint_read = env.equal(&fd_id, &Env::constant(FD_HINT_READ));
1431            let is_hint_write = env.equal(&fd_id, &Env::constant(FD_HINT_WRITE));
1432            let is_preimage_read = env.equal(&fd_id, &Env::constant(FD_PREIMAGE_READ));
1433            let is_preimage_write = env.equal(&fd_id, &Env::constant(FD_PREIMAGE_WRITE));
1434
1435            // These variables are 1 if the condition is true, and 0 otherwise.
1436            let is_read = is_stdin + is_preimage_read + is_hint_read;
1437            let is_write = is_stdout + is_stderr + is_preimage_write + is_hint_write;
1438
1439            let v0 = is_getfl.clone()
1440                * (is_write.clone()
1441                    + (Env::constant(1) - is_read.clone() - is_write.clone())
1442                        * Env::constant(0xFFFFFFFF))
1443                + (Env::constant(1) - is_getfl.clone()) * Env::constant(0xFFFFFFFF);
1444            let v1 =
1445                is_getfl.clone() * (Env::constant(1) - is_read - is_write.clone())
1446                    * Env::constant(0x9) /* EBADF */
1447                + (Env::constant(1) - is_getfl.clone()) * Env::constant(0x16) /* EINVAL */;
1448
1449            env.write_register(&Env::constant(2), v0);
1450            env.write_register(&Env::constant(7), v1);
1451            env.set_instruction_pointer(next_instruction_pointer.clone());
1452            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1453        }
1454        RTypeInstruction::SyscallOther => {
1455            let syscall_num = env.read_register(&Env::constant(2));
1456            let is_sysbrk = env.equal(&syscall_num, &Env::constant(SYSCALL_BRK));
1457            let is_sysclone = env.equal(&syscall_num, &Env::constant(SYSCALL_CLONE));
1458            let v0 = { is_sysbrk * Env::constant(0x40000000) + is_sysclone };
1459            let v1 = Env::constant(0);
1460            env.write_register(&Env::constant(2), v0);
1461            env.write_register(&Env::constant(7), v1);
1462            env.set_instruction_pointer(next_instruction_pointer.clone());
1463            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1464        }
1465        RTypeInstruction::MoveZero => {
1466            let rt = env.read_register(&rt);
1467            let is_zero = env.is_zero(&rt);
1468            let rs = env.read_register(&rs);
1469            env.write_register_if(&rd, rs, &is_zero);
1470            env.set_instruction_pointer(next_instruction_pointer.clone());
1471            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1472        }
1473        RTypeInstruction::MoveNonZero => {
1474            let rt = env.read_register(&rt);
1475            let is_zero = Env::constant(1) - env.is_zero(&rt);
1476            let rs = env.read_register(&rs);
1477            env.write_register_if(&rd, rs, &is_zero);
1478            env.set_instruction_pointer(next_instruction_pointer.clone());
1479            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1480        }
1481        RTypeInstruction::Sync => {
1482            env.set_instruction_pointer(next_instruction_pointer.clone());
1483            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1484        }
1485        RTypeInstruction::MoveFromHi => {
1486            let hi = env.read_register(&Env::constant(REGISTER_HI as u32));
1487            env.write_register(&rd, hi);
1488            env.set_instruction_pointer(next_instruction_pointer.clone());
1489            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1490        }
1491        RTypeInstruction::MoveToHi => {
1492            let rs = env.read_register(&rs);
1493            env.write_register(&Env::constant(REGISTER_HI as u32), rs);
1494            env.set_instruction_pointer(next_instruction_pointer.clone());
1495            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1496        }
1497        RTypeInstruction::MoveFromLo => {
1498            let lo = env.read_register(&Env::constant(REGISTER_LO as u32));
1499            env.write_register(&rd, lo);
1500            env.set_instruction_pointer(next_instruction_pointer.clone());
1501            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1502        }
1503        RTypeInstruction::MoveToLo => {
1504            let rs = env.read_register(&rs);
1505            env.write_register(&Env::constant(REGISTER_LO as u32), rs);
1506            env.set_instruction_pointer(next_instruction_pointer.clone());
1507            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1508        }
1509        RTypeInstruction::Multiply => {
1510            let rs = env.read_register(&rs);
1511            let rt = env.read_register(&rt);
1512            let (hi, lo) = {
1513                // Fixme: constrain
1514                let hi_pos = env.alloc_scratch();
1515                let lo_pos = env.alloc_scratch();
1516                unsafe { env.mul_hi_lo_signed(&rs, &rt, hi_pos, lo_pos) }
1517            };
1518            env.write_register(&Env::constant(REGISTER_HI as u32), hi);
1519            env.write_register(&Env::constant(REGISTER_LO as u32), lo);
1520            env.set_instruction_pointer(next_instruction_pointer.clone());
1521            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1522        }
1523        RTypeInstruction::MultiplyUnsigned => {
1524            let rs = env.read_register(&rs);
1525            let rt = env.read_register(&rt);
1526            let (hi, lo) = {
1527                // Fixme: constrain
1528                let hi_pos = env.alloc_scratch();
1529                let lo_pos = env.alloc_scratch();
1530                unsafe { env.mul_hi_lo(&rs, &rt, hi_pos, lo_pos) }
1531            };
1532            env.write_register(&Env::constant(REGISTER_HI as u32), hi);
1533            env.write_register(&Env::constant(REGISTER_LO as u32), lo);
1534            env.set_instruction_pointer(next_instruction_pointer.clone());
1535            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1536        }
1537        RTypeInstruction::Div => {
1538            let rs = env.read_register(&rs);
1539            let rt = env.read_register(&rt);
1540            let (quotient, remainder) = {
1541                // Fixme: constrain
1542                let quotient_pos = env.alloc_scratch();
1543                let remainder_pos = env.alloc_scratch();
1544                unsafe { env.divmod_signed(&rs, &rt, quotient_pos, remainder_pos) }
1545            };
1546            env.write_register(&Env::constant(REGISTER_LO as u32), quotient);
1547            env.write_register(&Env::constant(REGISTER_HI as u32), remainder);
1548            env.set_instruction_pointer(next_instruction_pointer.clone());
1549            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1550        }
1551        RTypeInstruction::DivUnsigned => {
1552            let rs = env.read_register(&rs);
1553            let rt = env.read_register(&rt);
1554            let (quotient, remainder) = {
1555                // Fixme: constrain
1556                let quotient_pos = env.alloc_scratch();
1557                let remainder_pos = env.alloc_scratch();
1558                unsafe { env.divmod(&rs, &rt, quotient_pos, remainder_pos) }
1559            };
1560            env.write_register(&Env::constant(REGISTER_LO as u32), quotient);
1561            env.write_register(&Env::constant(REGISTER_HI as u32), remainder);
1562            env.set_instruction_pointer(next_instruction_pointer.clone());
1563            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1564        }
1565        RTypeInstruction::Add => {
1566            let rs = env.read_register(&rs);
1567            let rt = env.read_register(&rt);
1568            let res = {
1569                let res_scratch = env.alloc_scratch();
1570                let overflow_scratch = env.alloc_scratch();
1571                let (res, _overflow) =
1572                    unsafe { env.add_witness(&rs, &rt, res_scratch, overflow_scratch) };
1573                // FIXME: Requires a range check
1574                res
1575            };
1576            env.write_register(&rd, res);
1577            env.set_instruction_pointer(next_instruction_pointer.clone());
1578            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1579        }
1580        RTypeInstruction::AddUnsigned => {
1581            let rs = env.read_register(&rs);
1582            let rt = env.read_register(&rt);
1583            let res = {
1584                let res_scratch = env.alloc_scratch();
1585                let overflow_scratch = env.alloc_scratch();
1586                let (res, _overflow) =
1587                    unsafe { env.add_witness(&rs, &rt, res_scratch, overflow_scratch) };
1588                // FIXME: Requires a range check
1589                res
1590            };
1591            env.write_register(&rd, res);
1592            env.set_instruction_pointer(next_instruction_pointer.clone());
1593            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1594        }
1595        RTypeInstruction::Sub => {
1596            let rs = env.read_register(&rs);
1597            let rt = env.read_register(&rt);
1598            let res = {
1599                let res_scratch = env.alloc_scratch();
1600                let overflow_scratch = env.alloc_scratch();
1601                let (res, _overflow) =
1602                    unsafe { env.sub_witness(&rs, &rt, res_scratch, overflow_scratch) };
1603                // FIXME: Requires a range check
1604                res
1605            };
1606            env.write_register(&rd, res);
1607            env.set_instruction_pointer(next_instruction_pointer.clone());
1608            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1609        }
1610        RTypeInstruction::SubUnsigned => {
1611            let rs = env.read_register(&rs);
1612            let rt = env.read_register(&rt);
1613            let res = {
1614                let res_scratch = env.alloc_scratch();
1615                let overflow_scratch = env.alloc_scratch();
1616                let (res, _overflow) =
1617                    unsafe { env.sub_witness(&rs, &rt, res_scratch, overflow_scratch) };
1618                // FIXME: Requires a range check
1619                res
1620            };
1621            env.write_register(&rd, res);
1622            env.set_instruction_pointer(next_instruction_pointer.clone());
1623            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1624        }
1625        RTypeInstruction::And => {
1626            let rs = env.read_register(&rs);
1627            let rt = env.read_register(&rt);
1628            let res = {
1629                // FIXME: Constrain
1630                let pos = env.alloc_scratch();
1631                unsafe { env.and_witness(&rs, &rt, pos) }
1632            };
1633            env.write_register(&rd, res);
1634            env.set_instruction_pointer(next_instruction_pointer.clone());
1635            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1636        }
1637        RTypeInstruction::Or => {
1638            let rs = env.read_register(&rs);
1639            let rt = env.read_register(&rt);
1640            let res = {
1641                // FIXME: Constrain
1642                let pos = env.alloc_scratch();
1643                unsafe { env.or_witness(&rs, &rt, pos) }
1644            };
1645            env.write_register(&rd, res);
1646            env.set_instruction_pointer(next_instruction_pointer.clone());
1647            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1648        }
1649        RTypeInstruction::Xor => {
1650            let rs = env.read_register(&rs);
1651            let rt = env.read_register(&rt);
1652            let res = {
1653                // FIXME: Constrain
1654                let pos = env.alloc_scratch();
1655                unsafe { env.xor_witness(&rs, &rt, pos) }
1656            };
1657            env.write_register(&rd, res);
1658            env.set_instruction_pointer(next_instruction_pointer.clone());
1659            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1660        }
1661        RTypeInstruction::Nor => {
1662            let rs = env.read_register(&rs);
1663            let rt = env.read_register(&rt);
1664            let res = {
1665                // FIXME: Constrain
1666                let pos = env.alloc_scratch();
1667                unsafe { env.nor_witness(&rs, &rt, pos) }
1668            };
1669            env.write_register(&rd, res);
1670            env.set_instruction_pointer(next_instruction_pointer.clone());
1671            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1672        }
1673        RTypeInstruction::SetLessThan => {
1674            let rs = env.read_register(&rs);
1675            let rt = env.read_register(&rt);
1676            let res = {
1677                // FIXME: Constrain
1678                let pos = env.alloc_scratch();
1679                unsafe { env.test_less_than_signed(&rs, &rt, pos) }
1680            };
1681            env.write_register(&rd, res);
1682            env.set_instruction_pointer(next_instruction_pointer.clone());
1683            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1684        }
1685        RTypeInstruction::SetLessThanUnsigned => {
1686            let rs = env.read_register(&rs);
1687            let rt = env.read_register(&rt);
1688            let res = {
1689                // FIXME: Constrain
1690                let pos = env.alloc_scratch();
1691                unsafe { env.test_less_than(&rs, &rt, pos) }
1692            };
1693            env.write_register(&rd, res);
1694            env.set_instruction_pointer(next_instruction_pointer.clone());
1695            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1696        }
1697        RTypeInstruction::MultiplyToRegister => {
1698            let rs = env.read_register(&rs);
1699            let rt = env.read_register(&rt);
1700            let res = {
1701                // FIXME: Constrain
1702                let pos = env.alloc_scratch();
1703                unsafe { env.mul_signed_witness(&rs, &rt, pos) }
1704            };
1705            env.write_register(&rd, res);
1706            env.set_instruction_pointer(next_instruction_pointer.clone());
1707            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1708        }
1709        RTypeInstruction::CountLeadingOnes => {
1710            let rs = env.read_register(&rs);
1711            let leading_ones = {
1712                // FIXME: Constrain
1713                let pos = env.alloc_scratch();
1714                unsafe { env.count_leading_ones(&rs, pos) }
1715            };
1716            env.write_register(&rd, leading_ones);
1717            env.set_instruction_pointer(next_instruction_pointer.clone());
1718            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1719        }
1720        RTypeInstruction::CountLeadingZeros => {
1721            let rs = env.read_register(&rs);
1722            let leading_zeros = {
1723                // FIXME: Constrain
1724                let pos = env.alloc_scratch();
1725                unsafe { env.count_leading_zeros(&rs, pos) }
1726            };
1727            env.write_register(&rd, leading_zeros);
1728            env.set_instruction_pointer(next_instruction_pointer.clone());
1729            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1730        }
1731    };
1732}
1733
1734pub fn interpret_jtype<Env: InterpreterEnv>(env: &mut Env, instr: JTypeInstruction) {
1735    let instruction_pointer = env.get_instruction_pointer();
1736    let next_instruction_pointer = env.get_next_instruction_pointer();
1737    let instruction = {
1738        let v0 = env.read_memory(&instruction_pointer);
1739        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
1740        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
1741        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
1742        (v0 * Env::constant(1 << 24))
1743            + (v1 * Env::constant(1 << 16))
1744            + (v2 * Env::constant(1 << 8))
1745            + v3
1746    };
1747    let opcode = {
1748        let pos = env.alloc_scratch();
1749        unsafe { env.bitmask(&instruction, 32, 26, pos) }
1750    };
1751    env.range_check8(&opcode, 6);
1752
1753    let addr = {
1754        // FIXME: Requires a range check (cannot use range_check_bits here because 26 > 16)
1755        let pos = env.alloc_scratch();
1756        unsafe { env.bitmask(&instruction, 26, 0, pos) }
1757    };
1758    let instruction_pointer_high_bits = {
1759        let pos = env.alloc_scratch();
1760        unsafe { env.bitmask(&next_instruction_pointer, 32, 28, pos) }
1761    };
1762    env.range_check8(&instruction_pointer_high_bits, 4);
1763
1764    // Check correctness of decomposition of instruction into parts
1765    env.add_constraint(instruction - (opcode * Env::constant(1 << 26) + addr.clone()));
1766
1767    let target_addr =
1768        (instruction_pointer_high_bits * Env::constant(1 << 28)) + (addr * Env::constant(1 << 2));
1769    match instr {
1770        JTypeInstruction::Jump => (),
1771        JTypeInstruction::JumpAndLink => {
1772            env.write_register(&Env::constant(31), instruction_pointer + Env::constant(8));
1773        }
1774    };
1775    env.set_instruction_pointer(next_instruction_pointer);
1776    env.set_next_instruction_pointer(target_addr);
1777}
1778
1779pub fn interpret_itype<Env: InterpreterEnv>(env: &mut Env, instr: ITypeInstruction) {
1780    let instruction_pointer = env.get_instruction_pointer();
1781    let next_instruction_pointer = env.get_next_instruction_pointer();
1782    let instruction = {
1783        let v0 = env.read_memory(&instruction_pointer);
1784        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
1785        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
1786        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
1787        (v0 * Env::constant(1 << 24))
1788            + (v1 * Env::constant(1 << 16))
1789            + (v2 * Env::constant(1 << 8))
1790            + v3
1791    };
1792    let opcode = {
1793        let pos = env.alloc_scratch();
1794        unsafe { env.bitmask(&instruction, 32, 26, pos) }
1795    };
1796    env.range_check8(&opcode, 6);
1797
1798    let rs = {
1799        let pos = env.alloc_scratch();
1800        unsafe { env.bitmask(&instruction, 26, 21, pos) }
1801    };
1802    env.range_check8(&rs, 5);
1803
1804    let rt = {
1805        let pos = env.alloc_scratch();
1806        unsafe { env.bitmask(&instruction, 21, 16, pos) }
1807    };
1808    env.range_check8(&rt, 5);
1809
1810    let immediate = {
1811        let pos = env.alloc_scratch();
1812        unsafe { env.bitmask(&instruction, 16, 0, pos) }
1813    };
1814    env.lookup_16bits(&immediate);
1815
1816    // Check correctness of decomposition of instruction into parts
1817    env.add_constraint(
1818        instruction
1819            - (opcode * Env::constant(1 << 26)
1820                + rs.clone() * Env::constant(1 << 21)
1821                + rt.clone() * Env::constant(1 << 16)
1822                + immediate.clone()),
1823    );
1824
1825    match instr {
1826        ITypeInstruction::BranchEq => {
1827            let offset = env.sign_extend(&(immediate * Env::constant(1 << 2)), 18);
1828            let rs = env.read_register(&rs);
1829            let rt = env.read_register(&rt);
1830            let equals = env.equal(&rs, &rt);
1831            let offset = (Env::constant(1) - equals.clone()) * Env::constant(4) + equals * offset;
1832            let addr = {
1833                let res_scratch = env.alloc_scratch();
1834                let overflow_scratch = env.alloc_scratch();
1835                let (res, _overflow) = unsafe {
1836                    env.add_witness(
1837                        &next_instruction_pointer,
1838                        &offset,
1839                        res_scratch,
1840                        overflow_scratch,
1841                    )
1842                };
1843                // FIXME: Requires a range check
1844                res
1845            };
1846            env.set_instruction_pointer(next_instruction_pointer);
1847            env.set_next_instruction_pointer(addr);
1848        }
1849        ITypeInstruction::BranchNeq => {
1850            let offset = env.sign_extend(&(immediate * Env::constant(1 << 2)), 18);
1851            let rs = env.read_register(&rs);
1852            let rt = env.read_register(&rt);
1853            let equals = env.equal(&rs, &rt);
1854            let offset = equals.clone() * Env::constant(4) + (Env::constant(1) - equals) * offset;
1855            let addr = {
1856                let res_scratch = env.alloc_scratch();
1857                let overflow_scratch = env.alloc_scratch();
1858                let (res, _overflow) = unsafe {
1859                    env.add_witness(
1860                        &next_instruction_pointer,
1861                        &offset,
1862                        res_scratch,
1863                        overflow_scratch,
1864                    )
1865                };
1866                // FIXME: Requires a range check
1867                res
1868            };
1869            env.set_instruction_pointer(next_instruction_pointer);
1870            env.set_next_instruction_pointer(addr);
1871        }
1872        ITypeInstruction::BranchLeqZero => {
1873            let offset = env.sign_extend(&(immediate * Env::constant(1 << 2)), 18);
1874            let rs = env.read_register(&rs);
1875            let less_than_or_equal_to = {
1876                let greater_than_zero = {
1877                    // FIXME: Requires constraints
1878                    let pos = env.alloc_scratch();
1879                    unsafe { env.test_less_than_signed(&Env::constant(0), &rs, pos) }
1880                };
1881                Env::constant(1) - greater_than_zero
1882            };
1883            let offset = (Env::constant(1) - less_than_or_equal_to.clone()) * Env::constant(4)
1884                + less_than_or_equal_to * offset;
1885            let addr = {
1886                let res_scratch = env.alloc_scratch();
1887                let overflow_scratch = env.alloc_scratch();
1888                let (res, _overflow) = unsafe {
1889                    env.add_witness(
1890                        &next_instruction_pointer,
1891                        &offset,
1892                        res_scratch,
1893                        overflow_scratch,
1894                    )
1895                };
1896                // FIXME: Requires a range check
1897                res
1898            };
1899            env.set_instruction_pointer(next_instruction_pointer);
1900            env.set_next_instruction_pointer(addr);
1901        }
1902        ITypeInstruction::BranchGtZero => {
1903            let offset = env.sign_extend(&(immediate * Env::constant(1 << 2)), 18);
1904            let rs = env.read_register(&rs);
1905            let less_than = {
1906                // FIXME: Requires constraints
1907                let pos = env.alloc_scratch();
1908                unsafe { env.test_less_than_signed(&Env::constant(0), &rs, pos) }
1909            };
1910            let offset =
1911                (Env::constant(1) - less_than.clone()) * Env::constant(4) + less_than * offset;
1912            let addr = {
1913                let res_scratch = env.alloc_scratch();
1914                let overflow_scratch = env.alloc_scratch();
1915                let (res, _overflow) = unsafe {
1916                    env.add_witness(
1917                        &next_instruction_pointer,
1918                        &offset,
1919                        res_scratch,
1920                        overflow_scratch,
1921                    )
1922                };
1923                // FIXME: Requires a range check
1924                res
1925            };
1926            env.set_instruction_pointer(next_instruction_pointer);
1927            env.set_next_instruction_pointer(addr);
1928        }
1929        ITypeInstruction::BranchLtZero => {
1930            let offset = env.sign_extend(&(immediate * Env::constant(1 << 2)), 18);
1931            let rs = env.read_register(&rs);
1932            let less_than = {
1933                // FIXME: Requires constraints
1934                let pos = env.alloc_scratch();
1935                unsafe { env.test_less_than_signed(&rs, &Env::constant(0), pos) }
1936            };
1937            let offset =
1938                (Env::constant(1) - less_than.clone()) * Env::constant(4) + less_than * offset;
1939            let addr = {
1940                let res_scratch = env.alloc_scratch();
1941                let overflow_scratch = env.alloc_scratch();
1942                let (res, _overflow) = unsafe {
1943                    env.add_witness(
1944                        &next_instruction_pointer,
1945                        &offset,
1946                        res_scratch,
1947                        overflow_scratch,
1948                    )
1949                };
1950                // FIXME: Requires a range check
1951                res
1952            };
1953            env.set_instruction_pointer(next_instruction_pointer);
1954            env.set_next_instruction_pointer(addr);
1955        }
1956        ITypeInstruction::BranchGeqZero => {
1957            let offset = env.sign_extend(&(immediate * Env::constant(1 << 2)), 18);
1958            let rs = env.read_register(&rs);
1959            let less_than = {
1960                // FIXME: Requires constraints
1961                let pos = env.alloc_scratch();
1962                unsafe { env.test_less_than_signed(&rs, &Env::constant(0), pos) }
1963            };
1964            let offset =
1965                less_than.clone() * Env::constant(4) + (Env::constant(1) - less_than) * offset;
1966            let addr = {
1967                let res_scratch = env.alloc_scratch();
1968                let overflow_scratch = env.alloc_scratch();
1969                let (res, _overflow) = unsafe {
1970                    env.add_witness(
1971                        &next_instruction_pointer,
1972                        &offset,
1973                        res_scratch,
1974                        overflow_scratch,
1975                    )
1976                };
1977                // FIXME: Requires a range check
1978                res
1979            };
1980            env.set_instruction_pointer(next_instruction_pointer);
1981            env.set_next_instruction_pointer(addr);
1982        }
1983        ITypeInstruction::AddImmediate => {
1984            let register_rs = env.read_register(&rs);
1985            let offset = env.sign_extend(&immediate, 16);
1986            let res = {
1987                let res_scratch = env.alloc_scratch();
1988                let overflow_scratch = env.alloc_scratch();
1989                let (res, _overflow) = unsafe {
1990                    env.add_witness(&register_rs, &offset, res_scratch, overflow_scratch)
1991                };
1992                // FIXME: Requires a range check
1993                res
1994            };
1995            env.write_register(&rt, res);
1996            env.set_instruction_pointer(next_instruction_pointer.clone());
1997            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1998        }
1999        ITypeInstruction::AddImmediateUnsigned => {
2000            let register_rs = env.read_register(&rs);
2001            let offset = env.sign_extend(&immediate, 16);
2002            let res = {
2003                let res_scratch = env.alloc_scratch();
2004                let overflow_scratch = env.alloc_scratch();
2005                let (res, _overflow) = unsafe {
2006                    env.add_witness(&register_rs, &offset, res_scratch, overflow_scratch)
2007                };
2008                // FIXME: Requires a range check
2009                res
2010            };
2011            env.write_register(&rt, res);
2012            env.set_instruction_pointer(next_instruction_pointer.clone());
2013            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2014        }
2015        ITypeInstruction::SetLessThanImmediate => {
2016            let rs = env.read_register(&rs);
2017            let immediate = env.sign_extend(&immediate, 16);
2018            let res = {
2019                // FIXME: Constrain
2020                let pos = env.alloc_scratch();
2021                unsafe { env.test_less_than_signed(&rs, &immediate, pos) }
2022            };
2023            env.write_register(&rt, res);
2024            env.set_instruction_pointer(next_instruction_pointer.clone());
2025            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2026        }
2027        ITypeInstruction::SetLessThanImmediateUnsigned => {
2028            let rs = env.read_register(&rs);
2029            let immediate = env.sign_extend(&immediate, 16);
2030            let res = {
2031                // FIXME: Constrain
2032                let pos = env.alloc_scratch();
2033                unsafe { env.test_less_than(&rs, &immediate, pos) }
2034            };
2035            env.write_register(&rt, res);
2036            env.set_instruction_pointer(next_instruction_pointer.clone());
2037            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2038        }
2039        ITypeInstruction::AndImmediate => {
2040            let rs = env.read_register(&rs);
2041            let res = {
2042                // FIXME: Constraint
2043                let pos = env.alloc_scratch();
2044                unsafe { env.and_witness(&rs, &immediate, pos) }
2045            };
2046            env.write_register(&rt, res);
2047            env.set_instruction_pointer(next_instruction_pointer.clone());
2048            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2049        }
2050        ITypeInstruction::OrImmediate => {
2051            let rs = env.read_register(&rs);
2052            let res = {
2053                // FIXME: Constraint
2054                let pos = env.alloc_scratch();
2055                unsafe { env.or_witness(&rs, &immediate, pos) }
2056            };
2057            env.write_register(&rt, res);
2058            env.set_instruction_pointer(next_instruction_pointer.clone());
2059            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2060        }
2061        ITypeInstruction::XorImmediate => {
2062            let rs = env.read_register(&rs);
2063            let res = {
2064                // FIXME: Constraint
2065                let pos = env.alloc_scratch();
2066                unsafe { env.xor_witness(&rs, &immediate, pos) }
2067            };
2068            env.write_register(&rt, res);
2069            env.set_instruction_pointer(next_instruction_pointer.clone());
2070            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2071        }
2072        ITypeInstruction::LoadUpperImmediate => {
2073            // lui $reg, [most significant 16 bits of immediate]
2074            let immediate_value = immediate * Env::constant(1 << 16);
2075            env.write_register(&rt, immediate_value);
2076            env.set_instruction_pointer(next_instruction_pointer.clone());
2077            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2078        }
2079        ITypeInstruction::Load8 => {
2080            let base = env.read_register(&rs);
2081            let dest = rt;
2082            let offset = env.sign_extend(&immediate, 16);
2083            let addr = {
2084                let res_scratch = env.alloc_scratch();
2085                let overflow_scratch = env.alloc_scratch();
2086                let (res, _overflow) =
2087                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2088                // FIXME: Requires a range check
2089                res
2090            };
2091            let v0 = env.read_memory(&addr);
2092            let value = env.sign_extend(&v0, 8);
2093            env.write_register(&dest, value);
2094            env.set_instruction_pointer(next_instruction_pointer.clone());
2095            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2096        }
2097        ITypeInstruction::Load16 => {
2098            let base = env.read_register(&rs);
2099            let dest = rt;
2100            let offset = env.sign_extend(&immediate, 16);
2101            let addr = {
2102                let res_scratch = env.alloc_scratch();
2103                let overflow_scratch = env.alloc_scratch();
2104                let (res, _overflow) =
2105                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2106                // FIXME: Requires a range check
2107                res
2108            };
2109            let v0 = env.read_memory(&addr);
2110            let v1 = env.read_memory(&(addr.clone() + Env::constant(1)));
2111            let value = (v0 * Env::constant(1 << 8)) + v1;
2112            let value = env.sign_extend(&value, 16);
2113            env.write_register(&dest, value);
2114            env.set_instruction_pointer(next_instruction_pointer.clone());
2115            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2116        }
2117        ITypeInstruction::Load32 => {
2118            let base = env.read_register(&rs);
2119            let dest = rt;
2120            let offset = env.sign_extend(&immediate, 16);
2121            let addr = {
2122                let res_scratch = env.alloc_scratch();
2123                let overflow_scratch = env.alloc_scratch();
2124                let (res, _overflow) =
2125                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2126                // FIXME: Requires a range check
2127                res
2128            };
2129            // We load 4 bytes, i.e. one word.
2130            let v0 = env.read_memory(&addr);
2131            let v1 = env.read_memory(&(addr.clone() + Env::constant(1)));
2132            let v2 = env.read_memory(&(addr.clone() + Env::constant(2)));
2133            let v3 = env.read_memory(&(addr.clone() + Env::constant(3)));
2134            let value = (v0 * Env::constant(1 << 24))
2135                + (v1 * Env::constant(1 << 16))
2136                + (v2 * Env::constant(1 << 8))
2137                + v3;
2138            env.write_register(&dest, value);
2139            env.set_instruction_pointer(next_instruction_pointer.clone());
2140            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2141        }
2142        ITypeInstruction::Load8Unsigned => {
2143            let base = env.read_register(&rs);
2144            let dest = rt;
2145            let offset = env.sign_extend(&immediate, 16);
2146            let addr = {
2147                let res_scratch = env.alloc_scratch();
2148                let overflow_scratch = env.alloc_scratch();
2149                let (res, _overflow) =
2150                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2151                // FIXME: Requires a range check
2152                res
2153            };
2154            let v0 = env.read_memory(&addr);
2155            let value = v0;
2156            env.write_register(&dest, value);
2157            env.set_instruction_pointer(next_instruction_pointer.clone());
2158            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2159        }
2160        ITypeInstruction::Load16Unsigned => {
2161            let base = env.read_register(&rs);
2162            let dest = rt;
2163            let offset = env.sign_extend(&immediate, 16);
2164            let addr = {
2165                let res_scratch = env.alloc_scratch();
2166                let overflow_scratch = env.alloc_scratch();
2167                let (res, _overflow) =
2168                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2169                // FIXME: Requires a range check
2170                res
2171            };
2172            let v0 = env.read_memory(&addr);
2173            let v1 = env.read_memory(&(addr.clone() + Env::constant(1)));
2174            let value = v0 * Env::constant(1 << 8) + v1;
2175            env.write_register(&dest, value);
2176            env.set_instruction_pointer(next_instruction_pointer.clone());
2177            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2178        }
2179        ITypeInstruction::LoadWordLeft => {
2180            let base = env.read_register(&rs);
2181            let offset = env.sign_extend(&immediate, 16);
2182            let addr = {
2183                let res_scratch = env.alloc_scratch();
2184                let overflow_scratch = env.alloc_scratch();
2185                let (res, _overflow) =
2186                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2187                // FIXME: Requires a range check
2188                res
2189            };
2190
2191            let byte_subaddr = {
2192                // FIXME: Requires a range check
2193                let pos = env.alloc_scratch();
2194                unsafe { env.bitmask(&addr, 2, 0, pos) }
2195            };
2196
2197            let overwrite_3 = env.equal(&byte_subaddr, &Env::constant(0));
2198            let overwrite_2 = env.equal(&byte_subaddr, &Env::constant(1)) + overwrite_3.clone();
2199            let overwrite_1 = env.equal(&byte_subaddr, &Env::constant(2)) + overwrite_2.clone();
2200            let overwrite_0 = env.equal(&byte_subaddr, &Env::constant(3)) + overwrite_1.clone();
2201
2202            let m0 = env.read_memory(&addr);
2203            let m1 = env.read_memory(&(addr.clone() + Env::constant(1)));
2204            let m2 = env.read_memory(&(addr.clone() + Env::constant(2)));
2205            let m3 = env.read_memory(&(addr.clone() + Env::constant(3)));
2206
2207            let [r0, r1, r2, r3] = {
2208                let initial_register_value = env.read_register(&rt);
2209                [
2210                    {
2211                        let pos = env.alloc_scratch();
2212                        unsafe { env.bitmask(&initial_register_value, 32, 24, pos) }
2213                    },
2214                    {
2215                        let pos = env.alloc_scratch();
2216                        unsafe { env.bitmask(&initial_register_value, 24, 16, pos) }
2217                    },
2218                    {
2219                        let pos = env.alloc_scratch();
2220                        unsafe { env.bitmask(&initial_register_value, 16, 8, pos) }
2221                    },
2222                    {
2223                        let pos = env.alloc_scratch();
2224                        unsafe { env.bitmask(&initial_register_value, 8, 0, pos) }
2225                    },
2226                ]
2227            };
2228            env.lookup_8bits(&r0);
2229            env.lookup_8bits(&r1);
2230            env.lookup_8bits(&r2);
2231            env.lookup_8bits(&r3);
2232
2233            let value = {
2234                let value = ((overwrite_0.clone() * m0 + (Env::constant(1) - overwrite_0) * r0)
2235                    * Env::constant(1 << 24))
2236                    + ((overwrite_1.clone() * m1 + (Env::constant(1) - overwrite_1) * r1)
2237                        * Env::constant(1 << 16))
2238                    + ((overwrite_2.clone() * m2 + (Env::constant(1) - overwrite_2) * r2)
2239                        * Env::constant(1 << 8))
2240                    + (overwrite_3.clone() * m3 + (Env::constant(1) - overwrite_3) * r3);
2241                let pos = env.alloc_scratch();
2242                env.copy(&value, pos)
2243            };
2244            env.write_register(&rt, value);
2245            env.set_instruction_pointer(next_instruction_pointer.clone());
2246            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2247        }
2248        ITypeInstruction::LoadWordRight => {
2249            let base = env.read_register(&rs);
2250            let offset = env.sign_extend(&immediate, 16);
2251            let addr = {
2252                let res_scratch = env.alloc_scratch();
2253                let overflow_scratch = env.alloc_scratch();
2254                let (res, _overflow) =
2255                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2256                // FIXME: Requires a range check
2257                res
2258            };
2259
2260            let byte_subaddr = {
2261                let pos = env.alloc_scratch();
2262                unsafe { env.bitmask(&addr, 2, 0, pos) }
2263            };
2264            env.range_check2(&byte_subaddr);
2265
2266            let overwrite_0 = env.equal(&byte_subaddr, &Env::constant(3));
2267            let overwrite_1 = env.equal(&byte_subaddr, &Env::constant(2)) + overwrite_0.clone();
2268            let overwrite_2 = env.equal(&byte_subaddr, &Env::constant(1)) + overwrite_1.clone();
2269            let overwrite_3 = env.equal(&byte_subaddr, &Env::constant(0)) + overwrite_2.clone();
2270
2271            // The `-3` here feels odd, but simulates the `<< 24` in cannon, and matches the
2272            // behavior defined in the spec.
2273            // See e.g. 'MIPS IV Instruction Set' Rev 3.2, Table A-31 for reference.
2274            let m0 = env.read_memory(&(addr.clone() - Env::constant(3)));
2275            let m1 = env.read_memory(&(addr.clone() - Env::constant(2)));
2276            let m2 = env.read_memory(&(addr.clone() - Env::constant(1)));
2277            let m3 = env.read_memory(&addr);
2278
2279            let [r0, r1, r2, r3] = {
2280                let initial_register_value = env.read_register(&rt);
2281                [
2282                    {
2283                        let pos = env.alloc_scratch();
2284                        unsafe { env.bitmask(&initial_register_value, 32, 24, pos) }
2285                    },
2286                    {
2287                        let pos = env.alloc_scratch();
2288                        unsafe { env.bitmask(&initial_register_value, 24, 16, pos) }
2289                    },
2290                    {
2291                        let pos = env.alloc_scratch();
2292                        unsafe { env.bitmask(&initial_register_value, 16, 8, pos) }
2293                    },
2294                    {
2295                        let pos = env.alloc_scratch();
2296                        unsafe { env.bitmask(&initial_register_value, 8, 0, pos) }
2297                    },
2298                ]
2299            };
2300            env.lookup_8bits(&r0);
2301            env.lookup_8bits(&r1);
2302            env.lookup_8bits(&r2);
2303            env.lookup_8bits(&r3);
2304
2305            let value = {
2306                let value = ((overwrite_0.clone() * m0 + (Env::constant(1) - overwrite_0) * r0)
2307                    * Env::constant(1 << 24))
2308                    + ((overwrite_1.clone() * m1 + (Env::constant(1) - overwrite_1) * r1)
2309                        * Env::constant(1 << 16))
2310                    + ((overwrite_2.clone() * m2 + (Env::constant(1) - overwrite_2) * r2)
2311                        * Env::constant(1 << 8))
2312                    + (overwrite_3.clone() * m3 + (Env::constant(1) - overwrite_3) * r3);
2313                let pos = env.alloc_scratch();
2314                env.copy(&value, pos)
2315            };
2316            env.write_register(&rt, value);
2317            env.set_instruction_pointer(next_instruction_pointer.clone());
2318            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2319        }
2320        ITypeInstruction::Store8 => {
2321            let base = env.read_register(&rs);
2322            let offset = env.sign_extend(&immediate, 16);
2323            let addr = {
2324                let res_scratch = env.alloc_scratch();
2325                let overflow_scratch = env.alloc_scratch();
2326                let (res, _overflow) =
2327                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2328                // FIXME: Requires a range check
2329                res
2330            };
2331            let value = env.read_register(&rt);
2332            let v0 = {
2333                let pos = env.alloc_scratch();
2334                unsafe { env.bitmask(&value, 8, 0, pos) }
2335            };
2336            env.lookup_8bits(&v0);
2337
2338            env.write_memory(&addr, v0);
2339            env.set_instruction_pointer(next_instruction_pointer.clone());
2340            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2341        }
2342        ITypeInstruction::Store16 => {
2343            let base = env.read_register(&rs);
2344            let offset = env.sign_extend(&immediate, 16);
2345            let addr = {
2346                let res_scratch = env.alloc_scratch();
2347                let overflow_scratch = env.alloc_scratch();
2348                let (res, _overflow) =
2349                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2350                // FIXME: Requires a range check
2351                res
2352            };
2353            let value = env.read_register(&rt);
2354            let [v0, v1] = {
2355                [
2356                    {
2357                        let pos = env.alloc_scratch();
2358                        unsafe { env.bitmask(&value, 16, 8, pos) }
2359                    },
2360                    {
2361                        let pos = env.alloc_scratch();
2362                        unsafe { env.bitmask(&value, 8, 0, pos) }
2363                    },
2364                ]
2365            };
2366            env.lookup_8bits(&v0);
2367            env.lookup_8bits(&v1);
2368
2369            env.write_memory(&addr, v0);
2370            env.write_memory(&(addr.clone() + Env::constant(1)), v1);
2371            env.set_instruction_pointer(next_instruction_pointer.clone());
2372            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2373        }
2374        ITypeInstruction::Store32 => {
2375            let base = env.read_register(&rs);
2376            let offset = env.sign_extend(&immediate, 16);
2377            let addr = {
2378                let res_scratch = env.alloc_scratch();
2379                let overflow_scratch = env.alloc_scratch();
2380                let (res, _overflow) =
2381                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2382                // FIXME: Requires a range check
2383                res
2384            };
2385            let value = env.read_register(&rt);
2386            let [v0, v1, v2, v3] = {
2387                [
2388                    {
2389                        let pos = env.alloc_scratch();
2390                        unsafe { env.bitmask(&value, 32, 24, pos) }
2391                    },
2392                    {
2393                        let pos = env.alloc_scratch();
2394                        unsafe { env.bitmask(&value, 24, 16, pos) }
2395                    },
2396                    {
2397                        let pos = env.alloc_scratch();
2398                        unsafe { env.bitmask(&value, 16, 8, pos) }
2399                    },
2400                    {
2401                        let pos = env.alloc_scratch();
2402                        unsafe { env.bitmask(&value, 8, 0, pos) }
2403                    },
2404                ]
2405            };
2406            env.lookup_8bits(&v0);
2407            env.lookup_8bits(&v1);
2408            env.lookup_8bits(&v2);
2409            env.lookup_8bits(&v3);
2410
2411            // Checking that v is the correct decomposition.
2412            {
2413                let res = value
2414                    - v0.clone() * Env::constant(1 << 24)
2415                    - v1.clone() * Env::constant(1 << 16)
2416                    - v2.clone() * Env::constant(1 << 8)
2417                    - v3.clone();
2418                env.is_zero(&res)
2419            };
2420            env.write_memory(&addr, v0);
2421            env.write_memory(&(addr.clone() + Env::constant(1)), v1);
2422            env.write_memory(&(addr.clone() + Env::constant(2)), v2);
2423            env.write_memory(&(addr.clone() + Env::constant(3)), v3);
2424            env.set_instruction_pointer(next_instruction_pointer.clone());
2425            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2426        }
2427        ITypeInstruction::Store32Conditional => {
2428            let base = env.read_register(&rs);
2429            let offset = env.sign_extend(&immediate, 16);
2430            let addr = {
2431                let res_scratch = env.alloc_scratch();
2432                let overflow_scratch = env.alloc_scratch();
2433                let (res, _overflow) =
2434                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2435                // FIXME: Requires a range check
2436                res
2437            };
2438            let value = env.read_register(&rt);
2439            let [v0, v1, v2, v3] = {
2440                [
2441                    {
2442                        let pos = env.alloc_scratch();
2443                        unsafe { env.bitmask(&value, 32, 24, pos) }
2444                    },
2445                    {
2446                        let pos = env.alloc_scratch();
2447                        unsafe { env.bitmask(&value, 24, 16, pos) }
2448                    },
2449                    {
2450                        let pos = env.alloc_scratch();
2451                        unsafe { env.bitmask(&value, 16, 8, pos) }
2452                    },
2453                    {
2454                        let pos = env.alloc_scratch();
2455                        unsafe { env.bitmask(&value, 8, 0, pos) }
2456                    },
2457                ]
2458            };
2459            env.lookup_8bits(&v0);
2460            env.lookup_8bits(&v1);
2461            env.lookup_8bits(&v2);
2462            env.lookup_8bits(&v3);
2463
2464            env.write_memory(&addr, v0);
2465            env.write_memory(&(addr.clone() + Env::constant(1)), v1);
2466            env.write_memory(&(addr.clone() + Env::constant(2)), v2);
2467            env.write_memory(&(addr.clone() + Env::constant(3)), v3);
2468            // Write status flag.
2469            env.write_register(&rt, Env::constant(1));
2470            env.set_instruction_pointer(next_instruction_pointer.clone());
2471            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2472        }
2473        ITypeInstruction::StoreWordLeft => {
2474            let base = env.read_register(&rs);
2475            let offset = env.sign_extend(&immediate, 16);
2476            let addr = {
2477                let res_scratch = env.alloc_scratch();
2478                let overflow_scratch = env.alloc_scratch();
2479                let (res, _overflow) =
2480                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2481                // FIXME: Requires a range check
2482                res
2483            };
2484
2485            let byte_subaddr = {
2486                // FIXME: Requires a range check
2487                let pos = env.alloc_scratch();
2488                unsafe { env.bitmask(&addr, 2, 0, pos) }
2489            };
2490            env.range_check2(&byte_subaddr);
2491
2492            let overwrite_3 = env.equal(&byte_subaddr, &Env::constant(0));
2493            let overwrite_2 = env.equal(&byte_subaddr, &Env::constant(1)) + overwrite_3.clone();
2494            let overwrite_1 = env.equal(&byte_subaddr, &Env::constant(2)) + overwrite_2.clone();
2495            let overwrite_0 = env.equal(&byte_subaddr, &Env::constant(3)) + overwrite_1.clone();
2496
2497            let m0 = env.read_memory(&addr);
2498            let m1 = env.read_memory(&(addr.clone() + Env::constant(1)));
2499            let m2 = env.read_memory(&(addr.clone() + Env::constant(2)));
2500            let m3 = env.read_memory(&(addr.clone() + Env::constant(3)));
2501
2502            let [r0, r1, r2, r3] = {
2503                let initial_register_value = env.read_register(&rt);
2504                [
2505                    {
2506                        let pos = env.alloc_scratch();
2507                        unsafe { env.bitmask(&initial_register_value, 32, 24, pos) }
2508                    },
2509                    {
2510                        let pos = env.alloc_scratch();
2511                        unsafe { env.bitmask(&initial_register_value, 24, 16, pos) }
2512                    },
2513                    {
2514                        let pos = env.alloc_scratch();
2515                        unsafe { env.bitmask(&initial_register_value, 16, 8, pos) }
2516                    },
2517                    {
2518                        let pos = env.alloc_scratch();
2519                        unsafe { env.bitmask(&initial_register_value, 8, 0, pos) }
2520                    },
2521                ]
2522            };
2523            env.lookup_8bits(&r0);
2524            env.lookup_8bits(&r1);
2525            env.lookup_8bits(&r2);
2526            env.lookup_8bits(&r3);
2527
2528            let v0 = {
2529                let pos = env.alloc_scratch();
2530                env.copy(
2531                    &(overwrite_0.clone() * r0 + (Env::constant(1) - overwrite_0) * m0),
2532                    pos,
2533                )
2534            };
2535            let v1 = {
2536                let pos = env.alloc_scratch();
2537                env.copy(
2538                    &(overwrite_1.clone() * r1 + (Env::constant(1) - overwrite_1) * m1),
2539                    pos,
2540                )
2541            };
2542            let v2 = {
2543                let pos = env.alloc_scratch();
2544                env.copy(
2545                    &(overwrite_2.clone() * r2 + (Env::constant(1) - overwrite_2) * m2),
2546                    pos,
2547                )
2548            };
2549            let v3 = {
2550                let pos = env.alloc_scratch();
2551                env.copy(
2552                    &(overwrite_3.clone() * r3 + (Env::constant(1) - overwrite_3) * m3),
2553                    pos,
2554                )
2555            };
2556
2557            env.write_memory(&addr, v0);
2558            env.write_memory(&(addr.clone() + Env::constant(1)), v1);
2559            env.write_memory(&(addr.clone() + Env::constant(2)), v2);
2560            env.write_memory(&(addr.clone() + Env::constant(3)), v3);
2561            env.set_instruction_pointer(next_instruction_pointer.clone());
2562            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2563        }
2564        ITypeInstruction::StoreWordRight => {
2565            let base = env.read_register(&rs);
2566            let offset = env.sign_extend(&immediate, 16);
2567            let addr = {
2568                let res_scratch = env.alloc_scratch();
2569                let overflow_scratch = env.alloc_scratch();
2570                let (res, _overflow) =
2571                    unsafe { env.add_witness(&base, &offset, res_scratch, overflow_scratch) };
2572                // FIXME: Requires a range check
2573                res
2574            };
2575
2576            let byte_subaddr = {
2577                let pos = env.alloc_scratch();
2578                unsafe { env.bitmask(&addr, 2, 0, pos) }
2579            };
2580            env.range_check2(&byte_subaddr);
2581
2582            let overwrite_0 = env.equal(&byte_subaddr, &Env::constant(3));
2583            let overwrite_1 = env.equal(&byte_subaddr, &Env::constant(2)) + overwrite_0.clone();
2584            let overwrite_2 = env.equal(&byte_subaddr, &Env::constant(1)) + overwrite_1.clone();
2585            let overwrite_3 = env.equal(&byte_subaddr, &Env::constant(0)) + overwrite_2.clone();
2586
2587            // The `-3` here feels odd, but simulates the `<< 24` in cannon, and matches the
2588            // behavior defined in the spec.
2589            // See e.g. 'MIPS IV Instruction Set' Rev 3.2, Table A-31 for reference.
2590            let m0 = env.read_memory(&(addr.clone() - Env::constant(3)));
2591            let m1 = env.read_memory(&(addr.clone() - Env::constant(2)));
2592            let m2 = env.read_memory(&(addr.clone() - Env::constant(1)));
2593            let m3 = env.read_memory(&addr);
2594
2595            let [r0, r1, r2, r3] = {
2596                let initial_register_value = env.read_register(&rt);
2597                [
2598                    {
2599                        let pos = env.alloc_scratch();
2600                        unsafe { env.bitmask(&initial_register_value, 32, 24, pos) }
2601                    },
2602                    {
2603                        let pos = env.alloc_scratch();
2604                        unsafe { env.bitmask(&initial_register_value, 24, 16, pos) }
2605                    },
2606                    {
2607                        let pos = env.alloc_scratch();
2608                        unsafe { env.bitmask(&initial_register_value, 16, 8, pos) }
2609                    },
2610                    {
2611                        let pos = env.alloc_scratch();
2612                        unsafe { env.bitmask(&initial_register_value, 8, 0, pos) }
2613                    },
2614                ]
2615            };
2616            env.lookup_8bits(&r0);
2617            env.lookup_8bits(&r1);
2618            env.lookup_8bits(&r2);
2619            env.lookup_8bits(&r3);
2620
2621            let v0 = {
2622                let pos = env.alloc_scratch();
2623                env.copy(
2624                    &(overwrite_0.clone() * r0 + (Env::constant(1) - overwrite_0) * m0),
2625                    pos,
2626                )
2627            };
2628            let v1 = {
2629                let pos = env.alloc_scratch();
2630                env.copy(
2631                    &(overwrite_1.clone() * r1 + (Env::constant(1) - overwrite_1) * m1),
2632                    pos,
2633                )
2634            };
2635            let v2 = {
2636                let pos = env.alloc_scratch();
2637                env.copy(
2638                    &(overwrite_2.clone() * r2 + (Env::constant(1) - overwrite_2) * m2),
2639                    pos,
2640                )
2641            };
2642            let v3 = {
2643                let pos = env.alloc_scratch();
2644                env.copy(
2645                    &(overwrite_3.clone() * r3 + (Env::constant(1) - overwrite_3) * m3),
2646                    pos,
2647                )
2648            };
2649
2650            env.write_memory(&(addr.clone() - Env::constant(3)), v0);
2651            env.write_memory(&(addr.clone() - Env::constant(2)), v1);
2652            env.write_memory(&(addr.clone() - Env::constant(1)), v2);
2653            env.write_memory(&addr.clone(), v3);
2654            env.set_instruction_pointer(next_instruction_pointer.clone());
2655            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2656        }
2657    }
2658}
2659
2660pub mod debugging {
2661    use serde::{Deserialize, Serialize};
2662    #[derive(Debug, Clone, Copy, Eq, PartialEq, Default, Serialize, Deserialize)]
2663    pub struct InstructionParts {
2664        pub op_code: u32,
2665        pub rs: u32,
2666        pub rt: u32,
2667        pub rd: u32,
2668        pub shamt: u32,
2669        pub funct: u32,
2670    }
2671
2672    impl InstructionParts {
2673        pub fn decode(instruction: u32) -> Self {
2674            let op_code = (instruction >> 26) & ((1 << (32 - 26)) - 1);
2675            let rs = (instruction >> 21) & ((1 << (26 - 21)) - 1);
2676            let rt = (instruction >> 16) & ((1 << (21 - 16)) - 1);
2677            let rd = (instruction >> 11) & ((1 << (16 - 11)) - 1);
2678            let shamt = (instruction >> 6) & ((1 << (11 - 6)) - 1);
2679            let funct = instruction & ((1 << 6) - 1);
2680            InstructionParts {
2681                op_code,
2682                rs,
2683                rt,
2684                rd,
2685                shamt,
2686                funct,
2687            }
2688        }
2689
2690        pub fn encode(self) -> u32 {
2691            (self.op_code << 26)
2692                | (self.rs << 21)
2693                | (self.rt << 16)
2694                | (self.rd << 11)
2695                | (self.shamt << 6)
2696                | self.funct
2697        }
2698    }
2699}