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 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, ShiftRightLogical, ShiftRightArithmetic, ShiftLeftLogicalVariable, ShiftRightLogicalVariable, ShiftRightArithmeticVariable, JumpRegister, JumpAndLinkRegister, SyscallMmap, SyscallExitGroup, SyscallReadHint, SyscallReadPreimage, SyscallReadOther, SyscallWriteHint, SyscallWritePreimage, SyscallWriteOther, SyscallFcntl, SyscallOther, MoveZero, MoveNonZero, Sync, MoveFromHi, MoveToHi, MoveFromLo, MoveToLo, Multiply, MultiplyUnsigned, Div, DivUnsigned, Add, AddUnsigned, Sub, SubUnsigned, And, Or, Xor, Nor, SetLessThan, SetLessThanUnsigned, MultiplyToRegister, CountLeadingOnes, CountLeadingZeros, }
87
88#[derive(
89 Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
90)]
91pub enum JTypeInstruction {
92 #[default]
93 Jump, JumpAndLink, }
96
97#[derive(
98 Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
99)]
100pub enum ITypeInstruction {
101 #[default]
102 BranchEq, BranchNeq, BranchLeqZero, BranchGtZero, BranchLtZero, BranchGeqZero, AddImmediate, AddImmediateUnsigned, SetLessThanImmediate, SetLessThanImmediateUnsigned, AndImmediate, OrImmediate, XorImmediate, LoadUpperImmediate, Load8, Load16, Load32, Load8Unsigned, Load16Unsigned, LoadWordLeft, LoadWordRight, Store8, Store16, Store32, Store32Conditional, StoreWordLeft, StoreWordRight, }
130
131impl IntoIterator for Instruction {
132 type Item = Instruction;
133 type IntoIter = std::vec::IntoIter<Self::Item>;
134
135 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 type Position;
167
168 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 fn variable(&self, column: Self::Position) -> Self::Variable;
191
192 fn add_constraint(&mut self, assert_equals_zero: Self::Variable);
195
196 fn activate_selector(&mut self, selector: Instruction);
198
199 fn check_is_zero(assert_equals_zero: &Self::Variable);
201
202 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 fn check_equal(x: &Self::Variable, y: &Self::Variable);
210
211 fn assert_equal(&mut self, x: Self::Variable, y: Self::Variable) {
213 Self::check_equal(&x, &y);
215 self.add_constraint(x - y);
216 }
217
218 fn check_boolean(x: &Self::Variable);
220
221 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 unsafe fn fetch_register(
241 &mut self,
242 idx: &Self::Variable,
243 output: Self::Position,
244 ) -> Self::Variable;
245
246 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 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 unsafe fn fetch_register_access(
277 &mut self,
278 idx: &Self::Variable,
279 output: Self::Position,
280 ) -> Self::Variable;
281
282 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 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 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 instruction_counter + Self::constant(1)
332 };
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 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 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 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 unsafe fn fetch_memory(
414 &mut self,
415 addr: &Self::Variable,
416 output: Self::Position,
417 ) -> Self::Variable;
418
419 unsafe fn push_memory(&mut self, addr: &Self::Variable, value: Self::Variable);
426
427 unsafe fn fetch_memory_access(
435 &mut self,
436 addr: &Self::Variable,
437 output: Self::Position,
438 ) -> Self::Variable;
439
440 unsafe fn push_memory_access(&mut self, addr: &Self::Variable, value: Self::Variable);
447
448 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 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 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 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 fn range_check16(&mut self, value: &Self::Variable, bits: u32) {
523 assert!(bits <= 16);
524 self.lookup_16bits(value);
527 self.lookup_16bits(&(value.clone() + Self::constant(1 << 16) - Self::constant(1 << bits)));
529 }
530
531 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 fn range_check8(&mut self, value: &Self::Variable, bits: u32) {
542 assert!(bits <= 8);
543 self.lookup_8bits(value);
546 self.lookup_8bits(&(value.clone() + Self::constant(1 << 8) - Self::constant(1 << bits)));
548 }
549
550 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 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 }
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 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 unsafe fn shift_left(
652 &mut self,
653 x: &Self::Variable,
654 by: &Self::Variable,
655 position: Self::Position,
656 ) -> Self::Variable;
657
658 unsafe fn shift_right(
665 &mut self,
666 x: &Self::Variable,
667 by: &Self::Variable,
668 position: Self::Position,
669 ) -> Self::Variable;
670
671 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 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 fn equal(&mut self, x: &Self::Variable, y: &Self::Variable) -> Self::Variable;
696
697 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 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 unsafe fn and_witness(
731 &mut self,
732 x: &Self::Variable,
733 y: &Self::Variable,
734 position: Self::Position,
735 ) -> Self::Variable;
736
737 unsafe fn or_witness(
744 &mut self,
745 x: &Self::Variable,
746 y: &Self::Variable,
747 position: Self::Position,
748 ) -> Self::Variable;
749
750 unsafe fn nor_witness(
757 &mut self,
758 x: &Self::Variable,
759 y: &Self::Variable,
760 position: Self::Position,
761 ) -> Self::Variable;
762
763 unsafe fn xor_witness(
770 &mut self,
771 x: &Self::Variable,
772 y: &Self::Variable,
773 position: Self::Position,
774 ) -> Self::Variable;
775
776 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 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 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 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 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 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 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 unsafe fn count_leading_zeros(
890 &mut self,
891 x: &Self::Variable,
892 position: Self::Position,
893 ) -> Self::Variable;
894
895 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 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 fn sign_extend(&mut self, x: &Self::Variable, bitlength: u32) -> Self::Variable {
936 let high_bit = {
938 let pos = self.alloc_scratch();
939 unsafe { self.bitmask(x, bitlength, bitlength - 1, pos) }
940 };
941 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 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 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
981pub 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 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 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 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 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 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 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 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 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 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 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 let other_fd = Env::constant(1) - is_stdin - is_preimage_read - is_hint_read;
1223
1224 let v0 = other_fd.clone() * Env::constant(0xFFFFFFFF);
1227 let v1 = other_fd * Env::constant(0x9); 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 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 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 unsafe { env.bitmask(&write_length, 6, 2, pos) }
1263 };
1264 env.range_check8(®isters_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(®ister_idx);
1271
1272 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(®ister_value, 32, 24, pos) }
1286 },
1287 {
1288 let pos = env.alloc_scratch();
1289 unsafe { env.bitmask(®ister_value, 24, 16, pos) }
1290 },
1291 {
1292 let pos = env.alloc_scratch();
1293 unsafe { env.bitmask(®ister_value, 16, 8, pos) }
1294 },
1295 {
1296 let pos = env.alloc_scratch();
1297 unsafe { env.bitmask(®ister_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 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 let [overwrite_0, overwrite_1, overwrite_2, overwrite_3] = {
1319 let next_word_addr = {
1320 let byte_subaddr = {
1321 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 env.equal(&bytes_to_preserve_in_register, &Env::constant(0))
1332 };
1333 let overwrite_1 = {
1334 overwrite_0.clone()
1337 - env.equal(&(read_address.clone() + Env::constant(1)), &next_word_addr)
1339 + env.equal(&bytes_to_preserve_in_register, &Env::constant(1))
1341 };
1342 let overwrite_2 = {
1343 overwrite_1.clone()
1346 - env.equal(&(read_address.clone() + Env::constant(2)), &next_word_addr)
1348 + env.equal(&bytes_to_preserve_in_register, &Env::constant(2))
1350 };
1351 let overwrite_3 = {
1352 overwrite_2.clone()
1355 - env.equal(&(read_address.clone() + Env::constant(3)), &next_word_addr)
1357 + 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 env.write_register(®ister_idx, value);
1378 env.write_register(
1380 &Env::constant(REGISTER_PREIMAGE_OFFSET as u32),
1381 Env::constant(0u32),
1382 );
1383 env.write_register(
1385 &Env::constant(2),
1386 overwrite_0 + overwrite_1 + overwrite_2 + overwrite_3,
1387 );
1388 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 }
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 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 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 let v0 = known_fd * write_length + other_fd.clone() * Env::constant(0xFFFFFFFF);
1416 let v1 = other_fd * Env::constant(0x9); 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 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) + (Env::constant(1) - is_getfl.clone()) * Env::constant(0x16) ;
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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(®ister_rs, &offset, res_scratch, overflow_scratch)
1991 };
1992 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(®ister_rs, &offset, res_scratch, overflow_scratch)
2007 };
2008 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 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 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 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 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 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 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 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 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 res
2128 };
2129 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 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 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 res
2189 };
2190
2191 let byte_subaddr = {
2192 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 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 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 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 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 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 {
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 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 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 res
2483 };
2484
2485 let byte_subaddr = {
2486 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 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 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}