1use super::registers::{REGISTER_CURRENT_IP, REGISTER_HEAP_POINTER, REGISTER_NEXT_IP};
32use crate::lookups::{Lookup, LookupTableIDs};
33use ark_ff::{One, Zero};
34use strum::{EnumCount, IntoEnumIterator};
35use strum_macros::{EnumCount, EnumIter};
36
37#[derive(Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Hash, Ord, PartialOrd)]
38pub enum Instruction {
39    RType(RInstruction),
40    IType(IInstruction),
41    SType(SInstruction),
42    SBType(SBInstruction),
43    UType(UInstruction),
44    UJType(UJInstruction),
45    SyscallType(SyscallInstruction),
46    MType(MInstruction),
47}
48
49#[derive(
53    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
54)]
55pub enum RInstruction {
56    #[default]
57    Add, Sub, ShiftLeftLogical, SetLessThan, SetLessThanUnsigned, Xor, ShiftRightLogical, ShiftRightArithmetic, Or, And, Fence, FenceI, }
127
128#[derive(
129    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
130)]
131pub enum IInstruction {
132    #[default]
133    LoadByte, LoadHalf, LoadWord, LoadByteUnsigned, LoadHalfUnsigned, ShiftLeftLogicalImmediate, ShiftRightLogicalImmediate, ShiftRightArithmeticImmediate, SetLessThanImmediate, SetLessThanImmediateUnsigned, AddImmediate, XorImmediate, OrImmediate, AndImmediate, JumpAndLinkRegister, }
217
218#[derive(
219    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
220)]
221pub enum SInstruction {
222    #[default]
223    StoreByte, StoreHalf, StoreWord, }
239
240#[derive(
241    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
242)]
243pub enum SBInstruction {
244    #[default]
245    BranchEq, BranchNeq, BranchLessThan, BranchGreaterThanEqual, BranchLessThanUnsigned, BranchGreaterThanEqualUnsigned, }
274
275#[derive(
276    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
277)]
278pub enum UInstruction {
279    #[default]
280    LoadUpperImmediate, AddUpperImmediate, }
294
295#[derive(
296    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
297)]
298pub enum UJInstruction {
299    #[default]
300    JumpAndLink, }
305
306#[derive(
307    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
308)]
309pub enum SyscallInstruction {
310    #[default]
311    SyscallSuccess,
312}
313
314#[derive(
317    Debug, Clone, Copy, Eq, PartialEq, EnumCount, EnumIter, Default, Hash, Ord, PartialOrd,
318)]
319pub enum MInstruction {
320    #[default]
326    Mul, Mulh, Mulhsu, Mulhu, Div, Divu, Rem, Remu, }
370
371impl IntoIterator for Instruction {
372    type Item = Instruction;
373    type IntoIter = std::vec::IntoIter<Instruction>;
374
375    fn into_iter(self) -> Self::IntoIter {
376        match self {
377            Instruction::RType(_) => {
378                let mut iter_contents = Vec::with_capacity(RInstruction::COUNT);
379                for rtype in RInstruction::iter() {
380                    iter_contents.push(Instruction::RType(rtype));
381                }
382                iter_contents.into_iter()
383            }
384            Instruction::IType(_) => {
385                let mut iter_contents = Vec::with_capacity(IInstruction::COUNT);
386                for itype in IInstruction::iter() {
387                    iter_contents.push(Instruction::IType(itype));
388                }
389                iter_contents.into_iter()
390            }
391            Instruction::SType(_) => {
392                let mut iter_contents = Vec::with_capacity(SInstruction::COUNT);
393                for stype in SInstruction::iter() {
394                    iter_contents.push(Instruction::SType(stype));
395                }
396                iter_contents.into_iter()
397            }
398            Instruction::SBType(_) => {
399                let mut iter_contents = Vec::with_capacity(SBInstruction::COUNT);
400                for sbtype in SBInstruction::iter() {
401                    iter_contents.push(Instruction::SBType(sbtype));
402                }
403                iter_contents.into_iter()
404            }
405            Instruction::UType(_) => {
406                let mut iter_contents = Vec::with_capacity(UInstruction::COUNT);
407                for utype in UInstruction::iter() {
408                    iter_contents.push(Instruction::UType(utype));
409                }
410                iter_contents.into_iter()
411            }
412            Instruction::UJType(_) => {
413                let mut iter_contents = Vec::with_capacity(UJInstruction::COUNT);
414                for ujtype in UJInstruction::iter() {
415                    iter_contents.push(Instruction::UJType(ujtype));
416                }
417                iter_contents.into_iter()
418            }
419            Instruction::SyscallType(_) => {
420                let mut iter_contents = Vec::with_capacity(SyscallInstruction::COUNT);
421                for syscall in SyscallInstruction::iter() {
422                    iter_contents.push(Instruction::SyscallType(syscall));
423                }
424                iter_contents.into_iter()
425            }
426            Instruction::MType(_) => {
427                let mut iter_contents = Vec::with_capacity(MInstruction::COUNT);
428                for mtype in MInstruction::iter() {
429                    iter_contents.push(Instruction::MType(mtype));
430                }
431                iter_contents.into_iter()
432            }
433        }
434    }
435}
436
437impl std::fmt::Display for Instruction {
438    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
439        match self {
440            Instruction::RType(rtype) => write!(f, "{}", rtype),
441            Instruction::IType(itype) => write!(f, "{}", itype),
442            Instruction::SType(stype) => write!(f, "{}", stype),
443            Instruction::SBType(sbtype) => write!(f, "{}", sbtype),
444            Instruction::UType(utype) => write!(f, "{}", utype),
445            Instruction::UJType(ujtype) => write!(f, "{}", ujtype),
446            Instruction::SyscallType(_syscall) => write!(f, "ecall"),
447            Instruction::MType(mtype) => write!(f, "{}", mtype),
448        }
449    }
450}
451
452impl std::fmt::Display for RInstruction {
453    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
454        match self {
455            RInstruction::Add => write!(f, "add"),
456            RInstruction::Sub => write!(f, "sub"),
457            RInstruction::ShiftLeftLogical => write!(f, "sll"),
458            RInstruction::SetLessThan => write!(f, "slt"),
459            RInstruction::SetLessThanUnsigned => write!(f, "sltu"),
460            RInstruction::Xor => write!(f, "xor"),
461            RInstruction::ShiftRightLogical => write!(f, "srl"),
462            RInstruction::ShiftRightArithmetic => write!(f, "sra"),
463            RInstruction::Or => write!(f, "or"),
464            RInstruction::And => write!(f, "and"),
465            RInstruction::Fence => write!(f, "fence"),
466            RInstruction::FenceI => write!(f, "fence.i"),
467        }
468    }
469}
470
471impl std::fmt::Display for IInstruction {
472    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
473        match self {
474            IInstruction::LoadByte => write!(f, "lb"),
475            IInstruction::LoadHalf => write!(f, "lh"),
476            IInstruction::LoadWord => write!(f, "lw"),
477            IInstruction::LoadByteUnsigned => write!(f, "lbu"),
478            IInstruction::LoadHalfUnsigned => write!(f, "lhu"),
479            IInstruction::ShiftLeftLogicalImmediate => write!(f, "slli"),
480            IInstruction::ShiftRightLogicalImmediate => write!(f, "srli"),
481            IInstruction::ShiftRightArithmeticImmediate => write!(f, "srai"),
482            IInstruction::SetLessThanImmediate => write!(f, "slti"),
483            IInstruction::SetLessThanImmediateUnsigned => write!(f, "sltiu"),
484            IInstruction::AddImmediate => write!(f, "addi"),
485            IInstruction::XorImmediate => write!(f, "xori"),
486            IInstruction::OrImmediate => write!(f, "ori"),
487            IInstruction::AndImmediate => write!(f, "andi"),
488            IInstruction::JumpAndLinkRegister => write!(f, "jalr"),
489        }
490    }
491}
492
493impl std::fmt::Display for SInstruction {
494    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
495        match self {
496            SInstruction::StoreByte => write!(f, "sb"),
497            SInstruction::StoreHalf => write!(f, "sh"),
498            SInstruction::StoreWord => write!(f, "sw"),
499        }
500    }
501}
502
503impl std::fmt::Display for SBInstruction {
504    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
505        match self {
506            SBInstruction::BranchEq => write!(f, "beq"),
507            SBInstruction::BranchNeq => write!(f, "bne"),
508            SBInstruction::BranchLessThan => write!(f, "blt"),
509            SBInstruction::BranchGreaterThanEqual => write!(f, "bge"),
510            SBInstruction::BranchLessThanUnsigned => write!(f, "bltu"),
511            SBInstruction::BranchGreaterThanEqualUnsigned => write!(f, "bgeu"),
512        }
513    }
514}
515
516impl std::fmt::Display for UInstruction {
517    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
518        match self {
519            UInstruction::LoadUpperImmediate => write!(f, "lui"),
520            UInstruction::AddUpperImmediate => write!(f, "auipc"),
521        }
522    }
523}
524
525impl std::fmt::Display for UJInstruction {
526    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
527        match self {
528            UJInstruction::JumpAndLink => write!(f, "jal"),
529        }
530    }
531}
532
533impl std::fmt::Display for MInstruction {
534    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
535        match self {
536            MInstruction::Mul => write!(f, "mul"),
537            MInstruction::Mulh => write!(f, "mulh"),
538            MInstruction::Mulhsu => write!(f, "mulhsu"),
539            MInstruction::Mulhu => write!(f, "mulhu"),
540            MInstruction::Div => write!(f, "div"),
541            MInstruction::Divu => write!(f, "divu"),
542            MInstruction::Rem => write!(f, "rem"),
543            MInstruction::Remu => write!(f, "remu"),
544        }
545    }
546}
547
548pub trait InterpreterEnv {
549    type Position;
551
552    fn alloc_scratch(&mut self) -> Self::Position;
562
563    fn alloc_scratch_inverse(&mut self) -> Self::Position;
564
565    type Variable: Clone
566        + std::ops::Add<Self::Variable, Output = Self::Variable>
567        + std::ops::Sub<Self::Variable, Output = Self::Variable>
568        + std::ops::Mul<Self::Variable, Output = Self::Variable>
569        + std::fmt::Debug
570        + Zero
571        + One;
572
573    fn variable(&self, column: Self::Position) -> Self::Variable;
575
576    fn add_constraint(&mut self, assert_equals_zero: Self::Variable);
579
580    fn activate_selector(&mut self, selector: Instruction);
582
583    fn check_is_zero(assert_equals_zero: &Self::Variable);
585
586    fn assert_is_zero(&mut self, assert_equals_zero: Self::Variable) {
588        Self::check_is_zero(&assert_equals_zero);
589        self.add_constraint(assert_equals_zero);
590    }
591
592    fn check_equal(x: &Self::Variable, y: &Self::Variable);
594
595    fn assert_equal(&mut self, x: Self::Variable, y: Self::Variable) {
597        Self::check_equal(&x, &y);
599        self.add_constraint(x - y);
600    }
601
602    fn assert_boolean(&mut self, x: &Self::Variable);
604
605    fn add_lookup(&mut self, lookup: Lookup<Self::Variable>);
606
607    fn instruction_counter(&self) -> Self::Variable;
608
609    fn increase_instruction_counter(&mut self);
610
611    unsafe fn fetch_register(
619        &mut self,
620        idx: &Self::Variable,
621        output: Self::Position,
622    ) -> Self::Variable;
623
624    unsafe fn push_register_if(
631        &mut self,
632        idx: &Self::Variable,
633        value: Self::Variable,
634        if_is_true: &Self::Variable,
635    );
636
637    unsafe fn push_register(&mut self, idx: &Self::Variable, value: Self::Variable) {
644        self.push_register_if(idx, value, &Self::constant(1))
645    }
646
647    unsafe fn fetch_register_access(
655        &mut self,
656        idx: &Self::Variable,
657        output: Self::Position,
658    ) -> Self::Variable;
659
660    unsafe fn push_register_access_if(
668        &mut self,
669        idx: &Self::Variable,
670        value: Self::Variable,
671        if_is_true: &Self::Variable,
672    );
673
674    unsafe fn push_register_access(&mut self, idx: &Self::Variable, value: Self::Variable) {
681        self.push_register_access_if(idx, value, &Self::constant(1))
682    }
683
684    unsafe fn access_register_if(
693        &mut self,
694        idx: &Self::Variable,
695        old_value: &Self::Variable,
696        new_value: &Self::Variable,
697        if_is_true: &Self::Variable,
698    ) {
699        let last_accessed = {
700            let last_accessed_location = self.alloc_scratch();
701            unsafe { self.fetch_register_access(idx, last_accessed_location) }
702        };
703        let instruction_counter = self.instruction_counter();
704        let elapsed_time = instruction_counter.clone() - last_accessed.clone();
705        let new_accessed = {
706            instruction_counter + Self::constant(1)
710            };
713        unsafe { self.push_register_access_if(idx, new_accessed.clone(), if_is_true) };
714        self.add_lookup(Lookup::write_if(
715            if_is_true.clone(),
716            LookupTableIDs::RegisterLookup,
717            vec![idx.clone(), last_accessed, old_value.clone()],
718        ));
719        self.add_lookup(Lookup::read_if(
720            if_is_true.clone(),
721            LookupTableIDs::RegisterLookup,
722            vec![idx.clone(), new_accessed, new_value.clone()],
723        ));
724        self.range_check64(&elapsed_time);
725
726        self.increase_instruction_counter();
728    }
729
730    fn read_register(&mut self, idx: &Self::Variable) -> Self::Variable {
731        let value = {
732            let value_location = self.alloc_scratch();
733            unsafe { self.fetch_register(idx, value_location) }
734        };
735        unsafe {
736            self.access_register(idx, &value, &value);
737        };
738        value
739    }
740
741    unsafe fn access_register(
749        &mut self,
750        idx: &Self::Variable,
751        old_value: &Self::Variable,
752        new_value: &Self::Variable,
753    ) {
754        self.access_register_if(idx, old_value, new_value, &Self::constant(1))
755    }
756
757    fn write_register_if(
758        &mut self,
759        idx: &Self::Variable,
760        new_value: Self::Variable,
761        if_is_true: &Self::Variable,
762    ) {
763        let old_value = {
764            let value_location = self.alloc_scratch();
765            unsafe { self.fetch_register(idx, value_location) }
766        };
767        let actual_new_value = {
769            let idx_is_zero = self.is_zero(idx);
770            let pos = self.alloc_scratch();
771            self.copy(&((Self::constant(1) - idx_is_zero) * new_value), pos)
772        };
773        unsafe {
774            self.access_register_if(idx, &old_value, &actual_new_value, if_is_true);
775        };
776        unsafe {
777            self.push_register_if(idx, actual_new_value, if_is_true);
778        };
779    }
780
781    fn write_register(&mut self, idx: &Self::Variable, new_value: Self::Variable) {
782        self.write_register_if(idx, new_value, &Self::constant(1))
783    }
784
785    unsafe fn fetch_memory(
792        &mut self,
793        addr: &Self::Variable,
794        output: Self::Position,
795    ) -> Self::Variable;
796
797    unsafe fn push_memory(&mut self, addr: &Self::Variable, value: Self::Variable);
804
805    unsafe fn fetch_memory_access(
813        &mut self,
814        addr: &Self::Variable,
815        output: Self::Position,
816    ) -> Self::Variable;
817
818    unsafe fn push_memory_access(&mut self, addr: &Self::Variable, value: Self::Variable);
825
826    unsafe fn access_memory(
834        &mut self,
835        addr: &Self::Variable,
836        old_value: &Self::Variable,
837        new_value: &Self::Variable,
838    ) {
839        let last_accessed = {
840            let last_accessed_location = self.alloc_scratch();
841            unsafe { self.fetch_memory_access(addr, last_accessed_location) }
842        };
843        let instruction_counter = self.instruction_counter();
844        let elapsed_time = instruction_counter.clone() - last_accessed.clone();
845        let new_accessed = {
846            instruction_counter + Self::constant(1)
850        };
851        unsafe { self.push_memory_access(addr, new_accessed.clone()) };
852        self.add_lookup(Lookup::write_one(
853            LookupTableIDs::MemoryLookup,
854            vec![addr.clone(), last_accessed, old_value.clone()],
855        ));
856        self.add_lookup(Lookup::read_one(
857            LookupTableIDs::MemoryLookup,
858            vec![addr.clone(), new_accessed, new_value.clone()],
859        ));
860        self.range_check64(&elapsed_time);
861
862        self.increase_instruction_counter();
864    }
865
866    fn read_memory(&mut self, addr: &Self::Variable) -> Self::Variable {
867        let value = {
868            let value_location = self.alloc_scratch();
869            unsafe { self.fetch_memory(addr, value_location) }
870        };
871        unsafe {
872            self.access_memory(addr, &value, &value);
873        };
874        value
875    }
876
877    fn write_memory(&mut self, addr: &Self::Variable, new_value: Self::Variable) {
878        let old_value = {
879            let value_location = self.alloc_scratch();
880            unsafe { self.fetch_memory(addr, value_location) }
881        };
882        unsafe {
883            self.access_memory(addr, &old_value, &new_value);
884        };
885        unsafe {
886            self.push_memory(addr, new_value);
887        };
888    }
889
890    fn lookup_16bits(&mut self, value: &Self::Variable) {
892        self.add_lookup(Lookup::read_one(
893            LookupTableIDs::RangeCheck16Lookup,
894            vec![value.clone()],
895        ));
896    }
897
898    fn range_check16(&mut self, value: &Self::Variable, bits: u32) {
901        assert!(bits <= 16);
902        self.lookup_16bits(value);
905        self.lookup_16bits(&(value.clone() + Self::constant(1 << 16) - Self::constant(1 << bits)));
907    }
908
909    fn lookup_8bits(&mut self, value: &Self::Variable) {
911        self.add_lookup(Lookup::read_one(
912            LookupTableIDs::ByteLookup,
913            vec![value.clone()],
914        ));
915    }
916
917    fn range_check8(&mut self, value: &Self::Variable, bits: u32) {
920        assert!(bits <= 8);
921        self.lookup_8bits(value);
924        self.lookup_8bits(&(value.clone() + Self::constant(1 << 8) - Self::constant(1 << bits)));
926    }
927
928    fn lookup_2bits(&mut self, value: &Self::Variable) {
930        self.add_lookup(Lookup::read_one(
931            LookupTableIDs::AtMost4Lookup,
932            vec![value.clone()],
933        ));
934    }
935
936    fn range_check64(&mut self, _value: &Self::Variable) {
937        }
939
940    fn set_instruction_pointer(&mut self, ip: Self::Variable) {
941        let idx = Self::constant(REGISTER_CURRENT_IP as u32);
942        let new_accessed = self.instruction_counter() + Self::constant(1);
943        unsafe {
944            self.push_register_access(&idx, new_accessed.clone());
945        }
946        unsafe {
947            self.push_register(&idx, ip.clone());
948        }
949        self.add_lookup(Lookup::read_one(
950            LookupTableIDs::RegisterLookup,
951            vec![idx, new_accessed, ip],
952        ));
953    }
954
955    fn get_instruction_pointer(&mut self) -> Self::Variable {
956        let idx = Self::constant(REGISTER_CURRENT_IP as u32);
957        let ip = {
958            let value_location = self.alloc_scratch();
959            unsafe { self.fetch_register(&idx, value_location) }
960        };
961        self.add_lookup(Lookup::write_one(
962            LookupTableIDs::RegisterLookup,
963            vec![idx, self.instruction_counter(), ip.clone()],
964        ));
965        ip
966    }
967
968    fn set_next_instruction_pointer(&mut self, ip: Self::Variable) {
969        let idx = Self::constant(REGISTER_NEXT_IP as u32);
970        let new_accessed = self.instruction_counter() + Self::constant(1);
971        unsafe {
972            self.push_register_access(&idx, new_accessed.clone());
973        }
974        unsafe {
975            self.push_register(&idx, ip.clone());
976        }
977        self.add_lookup(Lookup::read_one(
978            LookupTableIDs::RegisterLookup,
979            vec![idx, new_accessed, ip],
980        ));
981    }
982
983    fn get_next_instruction_pointer(&mut self) -> Self::Variable {
984        let idx = Self::constant(REGISTER_NEXT_IP as u32);
985        let ip = {
986            let value_location = self.alloc_scratch();
987            unsafe { self.fetch_register(&idx, value_location) }
988        };
989        self.add_lookup(Lookup::write_one(
990            LookupTableIDs::RegisterLookup,
991            vec![idx, self.instruction_counter(), ip.clone()],
992        ));
993        ip
994    }
995
996    fn constant(x: u32) -> Self::Variable;
997
998    unsafe fn bitmask(
1011        &mut self,
1012        x: &Self::Variable,
1013        highest_bit: u32,
1014        lowest_bit: u32,
1015        position: Self::Position,
1016    ) -> Self::Variable;
1017
1018    unsafe fn shift_left(
1025        &mut self,
1026        x: &Self::Variable,
1027        by: &Self::Variable,
1028        position: Self::Position,
1029    ) -> Self::Variable;
1030
1031    unsafe fn shift_right(
1038        &mut self,
1039        x: &Self::Variable,
1040        by: &Self::Variable,
1041        position: Self::Position,
1042    ) -> Self::Variable;
1043
1044    unsafe fn shift_right_arithmetic(
1051        &mut self,
1052        x: &Self::Variable,
1053        by: &Self::Variable,
1054        position: Self::Position,
1055    ) -> Self::Variable;
1056
1057    unsafe fn test_zero(&mut self, x: &Self::Variable, position: Self::Position) -> Self::Variable;
1064
1065    fn is_zero(&mut self, x: &Self::Variable) -> Self::Variable;
1066
1067    fn equal(&mut self, x: &Self::Variable, y: &Self::Variable) -> Self::Variable;
1069
1070    unsafe fn test_less_than(
1078        &mut self,
1079        x: &Self::Variable,
1080        y: &Self::Variable,
1081        position: Self::Position,
1082    ) -> Self::Variable;
1083
1084    unsafe fn test_less_than_signed(
1091        &mut self,
1092        x: &Self::Variable,
1093        y: &Self::Variable,
1094        position: Self::Position,
1095    ) -> Self::Variable;
1096
1097    unsafe fn and_witness(
1104        &mut self,
1105        x: &Self::Variable,
1106        y: &Self::Variable,
1107        position: Self::Position,
1108    ) -> Self::Variable;
1109
1110    unsafe fn or_witness(
1117        &mut self,
1118        x: &Self::Variable,
1119        y: &Self::Variable,
1120        position: Self::Position,
1121    ) -> Self::Variable;
1122
1123    unsafe fn nor_witness(
1130        &mut self,
1131        x: &Self::Variable,
1132        y: &Self::Variable,
1133        position: Self::Position,
1134    ) -> Self::Variable;
1135
1136    unsafe fn xor_witness(
1143        &mut self,
1144        x: &Self::Variable,
1145        y: &Self::Variable,
1146        position: Self::Position,
1147    ) -> Self::Variable;
1148
1149    unsafe fn add_witness(
1157        &mut self,
1158        y: &Self::Variable,
1159        x: &Self::Variable,
1160        out_position: Self::Position,
1161        overflow_position: Self::Position,
1162    ) -> (Self::Variable, Self::Variable);
1163
1164    unsafe fn sub_witness(
1172        &mut self,
1173        y: &Self::Variable,
1174        x: &Self::Variable,
1175        out_position: Self::Position,
1176        underflow_position: Self::Position,
1177    ) -> (Self::Variable, Self::Variable);
1178
1179    unsafe fn mul_signed_witness(
1186        &mut self,
1187        x: &Self::Variable,
1188        y: &Self::Variable,
1189        position: Self::Position,
1190    ) -> Self::Variable;
1191
1192    unsafe fn mul_hi_signed(
1200        &mut self,
1201        x: &Self::Variable,
1202        y: &Self::Variable,
1203        position: Self::Position,
1204    ) -> Self::Variable;
1205
1206    unsafe fn mul_lo_signed(
1214        &mut self,
1215        x: &Self::Variable,
1216        y: &Self::Variable,
1217        position: Self::Position,
1218    ) -> Self::Variable;
1219
1220    unsafe fn mul_hi(
1228        &mut self,
1229        x: &Self::Variable,
1230        y: &Self::Variable,
1231        position: Self::Position,
1232    ) -> Self::Variable;
1233
1234    unsafe fn mul_lo(
1242        &mut self,
1243        x: &Self::Variable,
1244        y: &Self::Variable,
1245        position: Self::Position,
1246    ) -> Self::Variable;
1247
1248    unsafe fn mul_hi_signed_unsigned(
1256        &mut self,
1257        x: &Self::Variable,
1258        y: &Self::Variable,
1259        position: Self::Position,
1260    ) -> Self::Variable;
1261
1262    unsafe fn div_signed(
1274        &mut self,
1275        x: &Self::Variable,
1276        y: &Self::Variable,
1277        position: Self::Position,
1278    ) -> Self::Variable;
1279
1280    unsafe fn mod_signed(
1288        &mut self,
1289        x: &Self::Variable,
1290        y: &Self::Variable,
1291        position: Self::Position,
1292    ) -> Self::Variable;
1293
1294    unsafe fn div(
1306        &mut self,
1307        x: &Self::Variable,
1308        y: &Self::Variable,
1309        position: Self::Position,
1310    ) -> Self::Variable;
1311
1312    unsafe fn mod_unsigned(
1320        &mut self,
1321        x: &Self::Variable,
1322        y: &Self::Variable,
1323        position: Self::Position,
1324    ) -> Self::Variable;
1325
1326    unsafe fn count_leading_zeros(
1333        &mut self,
1334        x: &Self::Variable,
1335        position: Self::Position,
1336    ) -> Self::Variable;
1337
1338    unsafe fn count_leading_ones(
1345        &mut self,
1346        x: &Self::Variable,
1347        position: Self::Position,
1348    ) -> Self::Variable;
1349
1350    fn copy(&mut self, x: &Self::Variable, position: Self::Position) -> Self::Variable;
1351
1352    fn increase_heap_pointer(
1355        &mut self,
1356        by_amount: &Self::Variable,
1357        if_is_true: &Self::Variable,
1358    ) -> Self::Variable {
1359        let idx = Self::constant(REGISTER_HEAP_POINTER as u32);
1360        let old_ptr = {
1361            let value_location = self.alloc_scratch();
1362            unsafe { self.fetch_register(&idx, value_location) }
1363        };
1364        let new_ptr = old_ptr.clone() + by_amount.clone();
1365        unsafe {
1366            self.access_register_if(&idx, &old_ptr, &new_ptr, if_is_true);
1367        };
1368        unsafe {
1369            self.push_register_if(&idx, new_ptr, if_is_true);
1370        };
1371        old_ptr
1372    }
1373
1374    fn set_halted(&mut self, flag: Self::Variable);
1375
1376    fn sign_extend(&mut self, x: &Self::Variable, bitlength: u32) -> Self::Variable {
1379        assert!(bitlength <= 32);
1380        let high_bit = {
1382            let pos = self.alloc_scratch();
1383            unsafe { self.bitmask(x, bitlength, bitlength - 1, pos) }
1384        };
1385        let v: u64 = (1u64 << (32 - bitlength)) - 1;
1389        let v: u64 = v << bitlength;
1390        let v: u32 = v as u32;
1391        high_bit * Self::constant(v) + x.clone()
1392    }
1393
1394    fn report_exit(&mut self, exit_code: &Self::Variable);
1395
1396    fn reset(&mut self);
1397}
1398
1399pub fn interpret_instruction<Env: InterpreterEnv>(env: &mut Env, instr: Instruction) {
1400    env.activate_selector(instr);
1401    match instr {
1402        Instruction::RType(rtype) => interpret_rtype(env, rtype),
1403        Instruction::IType(itype) => interpret_itype(env, itype),
1404        Instruction::SType(stype) => interpret_stype(env, stype),
1405        Instruction::SBType(sbtype) => interpret_sbtype(env, sbtype),
1406        Instruction::UType(utype) => interpret_utype(env, utype),
1407        Instruction::UJType(ujtype) => interpret_ujtype(env, ujtype),
1408        Instruction::SyscallType(syscall) => interpret_syscall(env, syscall),
1409        Instruction::MType(mtype) => interpret_mtype(env, mtype),
1410    }
1411}
1412
1413pub fn interpret_rtype<Env: InterpreterEnv>(env: &mut Env, instr: RInstruction) {
1422    let instruction_pointer = env.get_instruction_pointer();
1423    let next_instruction_pointer = env.get_next_instruction_pointer();
1424
1425    let instruction = {
1426        let v0 = env.read_memory(&instruction_pointer);
1427        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
1428        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
1429        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
1430        (v3 * Env::constant(1 << 24))
1431            + (v2 * Env::constant(1 << 16))
1432            + (v1 * Env::constant(1 << 8))
1433            + v0
1434    };
1435
1436    let opcode = {
1438        let pos = env.alloc_scratch();
1439        unsafe { env.bitmask(&instruction, 7, 0, pos) }
1440    };
1441    env.range_check8(&opcode, 7);
1442
1443    let rd = {
1444        let pos = env.alloc_scratch();
1445        unsafe { env.bitmask(&instruction, 12, 7, pos) }
1446    };
1447    env.range_check8(&rd, 5);
1448
1449    let funct3 = {
1450        let pos = env.alloc_scratch();
1451        unsafe { env.bitmask(&instruction, 15, 12, pos) }
1452    };
1453    env.range_check8(&funct3, 3);
1454
1455    let rs1 = {
1456        let pos = env.alloc_scratch();
1457        unsafe { env.bitmask(&instruction, 20, 15, pos) }
1458    };
1459    env.range_check8(&rs1, 5);
1460
1461    let rs2 = {
1462        let pos = env.alloc_scratch();
1463        unsafe { env.bitmask(&instruction, 25, 20, pos) }
1464    };
1465    env.range_check8(&rs2, 5);
1466
1467    let funct2 = {
1468        let pos = env.alloc_scratch();
1469        unsafe { env.bitmask(&instruction, 27, 25, pos) }
1470    };
1471    env.range_check8(&funct2, 2);
1472
1473    let funct5 = {
1474        let pos = env.alloc_scratch();
1475        unsafe { env.bitmask(&instruction, 32, 27, pos) }
1476    };
1477    env.range_check8(&funct5, 5);
1478
1479    env.add_constraint(
1481        instruction
1482    - (opcode.clone() * Env::constant(1 << 0))    - (rd.clone() * Env::constant(1 << 7))        - (funct3.clone() * Env::constant(1 << 12))   - (rs1.clone() * Env::constant(1 << 15))      - (rs2.clone() * Env::constant(1 << 20))      - (funct2.clone() * Env::constant(1 << 25))   - (funct5.clone() * Env::constant(1 << 27)), );
1490
1491    match instr {
1492        RInstruction::Add => {
1493            let local_rs1 = env.read_register(&rs1);
1495            let local_rs2 = env.read_register(&rs2);
1496            let local_rd = {
1497                let overflow_scratch = env.alloc_scratch();
1498                let rd_scratch = env.alloc_scratch();
1499                let (local_rd, _overflow) = unsafe {
1500                    env.add_witness(&local_rs1, &local_rs2, rd_scratch, overflow_scratch)
1501                };
1502                local_rd
1503            };
1504            env.write_register(&rd, local_rd);
1505
1506            env.set_instruction_pointer(next_instruction_pointer.clone());
1507            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1508        }
1509        RInstruction::Sub => {
1510            let local_rs1 = env.read_register(&rs1);
1512            let local_rs2 = env.read_register(&rs2);
1513            let local_rd = {
1514                let underflow_scratch = env.alloc_scratch();
1515                let rd_scratch = env.alloc_scratch();
1516                let (local_rd, _underflow) = unsafe {
1517                    env.sub_witness(&local_rs1, &local_rs2, rd_scratch, underflow_scratch)
1518                };
1519                local_rd
1520            };
1521            env.write_register(&rd, local_rd);
1522
1523            env.set_instruction_pointer(next_instruction_pointer.clone());
1524            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1525        }
1526        RInstruction::ShiftLeftLogical => {
1527            let local_rs1 = env.read_register(&rs1);
1529            let local_rs2 = env.read_register(&rs2);
1530            let local_rd = {
1531                let rd_scratch = env.alloc_scratch();
1532                unsafe { env.shift_left(&local_rs1, &local_rs2, rd_scratch) }
1533            };
1534            env.write_register(&rd, local_rd);
1535
1536            env.set_instruction_pointer(next_instruction_pointer.clone());
1537            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1538        }
1539        RInstruction::SetLessThan => {
1540            let local_rs1 = env.read_register(&rs1);
1542            let local_rs2 = env.read_register(&rs2);
1543            let local_rd = {
1544                let rd_scratch = env.alloc_scratch();
1545                unsafe { env.test_less_than_signed(&local_rs1, &local_rs2, rd_scratch) }
1546            };
1547            env.write_register(&rd, local_rd);
1548
1549            env.set_instruction_pointer(next_instruction_pointer.clone());
1550            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1551        }
1552        RInstruction::SetLessThanUnsigned => {
1553            let local_rs1 = env.read_register(&rs1);
1555            let local_rs2 = env.read_register(&rs2);
1556            let local_rd = {
1557                let pos = env.alloc_scratch();
1558                unsafe { env.test_less_than(&local_rs1, &local_rs2, pos) }
1559            };
1560            env.write_register(&rd, local_rd);
1561
1562            env.set_instruction_pointer(next_instruction_pointer.clone());
1563            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1564        }
1565        RInstruction::Xor => {
1566            let local_rs1 = env.read_register(&rs1);
1568            let local_rs2 = env.read_register(&rs2);
1569            let local_rd = {
1570                let pos = env.alloc_scratch();
1571                unsafe { env.xor_witness(&local_rs1, &local_rs2, pos) }
1572            };
1573            env.write_register(&rd, local_rd);
1574
1575            env.set_instruction_pointer(next_instruction_pointer.clone());
1576            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1577        }
1578        RInstruction::ShiftRightLogical => {
1579            let local_rs1 = env.read_register(&rs1);
1581            let local_rs2 = env.read_register(&rs2);
1582            let local_rd = {
1583                let pos = env.alloc_scratch();
1584                unsafe { env.shift_right(&local_rs1, &local_rs2, pos) }
1585            };
1586            env.write_register(&rd, local_rd);
1587
1588            env.set_instruction_pointer(next_instruction_pointer.clone());
1589            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1590        }
1591        RInstruction::ShiftRightArithmetic => {
1592            let local_rs1 = env.read_register(&rs1);
1594            let local_rs2 = env.read_register(&rs2);
1595            let local_rd = {
1596                let pos = env.alloc_scratch();
1597                unsafe { env.shift_right_arithmetic(&local_rs1, &local_rs2, pos) }
1598            };
1599            env.write_register(&rd, local_rd);
1600
1601            env.set_instruction_pointer(next_instruction_pointer.clone());
1602            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1603        }
1604        RInstruction::Or => {
1605            let local_rs1 = env.read_register(&rs1);
1607            let local_rs2 = env.read_register(&rs2);
1608            let local_rd = {
1609                let pos = env.alloc_scratch();
1610                unsafe { env.or_witness(&local_rs1, &local_rs2, pos) }
1611            };
1612            env.write_register(&rd, local_rd);
1613
1614            env.set_instruction_pointer(next_instruction_pointer.clone());
1615            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1616        }
1617        RInstruction::And => {
1618            let local_rs1 = env.read_register(&rs1);
1620            let local_rs2 = env.read_register(&rs2);
1621            let local_rd = {
1622                let pos = env.alloc_scratch();
1623                unsafe { env.and_witness(&local_rs1, &local_rs2, pos) }
1624            };
1625            env.write_register(&rd, local_rd);
1626
1627            env.set_instruction_pointer(next_instruction_pointer.clone());
1628            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1629        }
1630        RInstruction::Fence => {
1631            unimplemented!("Fence")
1632        }
1633        RInstruction::FenceI => {
1634            unimplemented!("FenceI")
1635        }
1636    };
1637}
1638
1639pub fn interpret_itype<Env: InterpreterEnv>(env: &mut Env, instr: IInstruction) {
1648    let instruction_pointer = env.get_instruction_pointer();
1649    let next_instruction_pointer = env.get_next_instruction_pointer();
1650
1651    let instruction = {
1652        let v0 = env.read_memory(&instruction_pointer);
1653        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
1654        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
1655        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
1656        (v3 * Env::constant(1 << 24))
1657            + (v2 * Env::constant(1 << 16))
1658            + (v1 * Env::constant(1 << 8))
1659            + v0
1660    };
1661
1662    let opcode = {
1663        let pos = env.alloc_scratch();
1664        unsafe { env.bitmask(&instruction, 7, 0, pos) }
1665    };
1666    env.range_check8(&opcode, 7);
1667
1668    let rd = {
1669        let pos = env.alloc_scratch();
1670        unsafe { env.bitmask(&instruction, 12, 7, pos) }
1671    };
1672    env.range_check8(&rd, 5);
1673
1674    let funct3 = {
1675        let pos = env.alloc_scratch();
1676        unsafe { env.bitmask(&instruction, 15, 12, pos) }
1677    };
1678    env.range_check8(&funct3, 3);
1679
1680    let rs1 = {
1681        let pos = env.alloc_scratch();
1682        unsafe { env.bitmask(&instruction, 20, 15, pos) }
1683    };
1684    env.range_check8(&rs1, 5);
1685
1686    let imm = {
1687        let pos = env.alloc_scratch();
1688        unsafe { env.bitmask(&instruction, 32, 20, pos) }
1689    };
1690
1691    env.range_check16(&imm, 12);
1692
1693    let shamt = {
1694        let pos = env.alloc_scratch();
1695        unsafe { env.bitmask(&imm, 5, 0, pos) }
1696    };
1697    env.range_check8(&shamt, 5);
1698
1699    let imm_header = {
1700        let pos = env.alloc_scratch();
1701        unsafe { env.bitmask(&imm, 12, 5, pos) }
1702    };
1703    env.range_check8(&imm_header, 7);
1704
1705    env.add_constraint(imm.clone() - (imm_header.clone() * Env::constant(1 << 5)) - shamt.clone());
1707
1708    env.add_constraint(
1710        instruction
1711            - (opcode.clone() * Env::constant(1 << 0))    - (rd.clone() * Env::constant(1 << 7))        - (funct3.clone() * Env::constant(1 << 12))   - (rs1.clone() * Env::constant(1 << 15))      - (imm.clone() * Env::constant(1 << 20)), );
1717
1718    match instr {
1719        IInstruction::LoadByte => {
1720            let local_rs1 = env.read_register(&rs1);
1722            let local_imm = env.sign_extend(&imm, 12);
1723            let address = {
1724                let address_scratch = env.alloc_scratch();
1725                let overflow_scratch = env.alloc_scratch();
1726                let (address, _overflow) = unsafe {
1727                    env.add_witness(&local_rs1, &local_imm, address_scratch, overflow_scratch)
1728                };
1729                address
1730            };
1731            let value = env.read_memory(&address);
1733            let value = env.sign_extend(&value, 8);
1734            env.write_register(&rd, value);
1735            env.set_instruction_pointer(next_instruction_pointer.clone());
1736            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1737        }
1738        IInstruction::LoadHalf => {
1739            let local_rs1 = env.read_register(&rs1);
1741            let local_imm = env.sign_extend(&imm, 12);
1742            let address = {
1743                let address_scratch = env.alloc_scratch();
1744                let overflow_scratch = env.alloc_scratch();
1745                let (address, _overflow) = unsafe {
1746                    env.add_witness(&local_rs1, &local_imm, address_scratch, overflow_scratch)
1747                };
1748                address
1749            };
1750            let v0 = env.read_memory(&address);
1752            let v1 = env.read_memory(&(address.clone() + Env::constant(1)));
1753            let value = (v0 * Env::constant(1 << 8)) + v1;
1754            let value = env.sign_extend(&value, 16);
1755            env.write_register(&rd, value);
1756            env.set_instruction_pointer(next_instruction_pointer.clone());
1757            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1758        }
1759        IInstruction::LoadWord => {
1760            let base = env.read_register(&rs1);
1762            let offset = env.sign_extend(&imm, 12);
1763            let address = {
1764                let address_scratch = env.alloc_scratch();
1765                let overflow_scratch = env.alloc_scratch();
1766                let (address, _overflow) =
1767                    unsafe { env.add_witness(&base, &offset, address_scratch, overflow_scratch) };
1768                address
1769            };
1770            let v0 = env.read_memory(&address);
1772            let v1 = env.read_memory(&(address.clone() + Env::constant(1)));
1773            let v2 = env.read_memory(&(address.clone() + Env::constant(2)));
1774            let v3 = env.read_memory(&(address.clone() + Env::constant(3)));
1775            let value = (v0 * Env::constant(1 << 24))
1776                + (v1 * Env::constant(1 << 16))
1777                + (v2 * Env::constant(1 << 8))
1778                + v3;
1779            let value = env.sign_extend(&value, 32);
1780            env.write_register(&rd, value);
1781            env.set_instruction_pointer(next_instruction_pointer.clone());
1782            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1783        }
1784        IInstruction::LoadByteUnsigned => {
1785            let local_rs1 = env.read_register(&rs1);
1787            let local_imm = env.sign_extend(&imm, 12);
1788            let address = {
1789                let address_scratch = env.alloc_scratch();
1790                let overflow_scratch = env.alloc_scratch();
1791                let (address, _overflow) = unsafe {
1792                    env.add_witness(&local_rs1, &local_imm, address_scratch, overflow_scratch)
1793                };
1794                address
1795            };
1796            let value = env.read_memory(&address);
1798            env.write_register(&rd, value);
1799            env.set_instruction_pointer(next_instruction_pointer.clone());
1800            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1801        }
1802        IInstruction::LoadHalfUnsigned => {
1803            let local_rs1 = env.read_register(&rs1);
1805            let local_imm = env.sign_extend(&imm, 12);
1806            let address = {
1807                let address_scratch = env.alloc_scratch();
1808                let overflow_scratch = env.alloc_scratch();
1809                let (address, _overflow) = unsafe {
1810                    env.add_witness(&local_rs1, &local_imm, address_scratch, overflow_scratch)
1811                };
1812                address
1813            };
1814            let v0 = env.read_memory(&address);
1816            let v1 = env.read_memory(&(address.clone() + Env::constant(1)));
1817            let value = (v0 * Env::constant(1 << 8)) + v1;
1818            env.write_register(&rd, value);
1819            env.set_instruction_pointer(next_instruction_pointer.clone());
1820            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1821        }
1822        IInstruction::ShiftLeftLogicalImmediate => {
1823            let local_rs1 = env.read_register(&rs1);
1825
1826            let local_rd = {
1827                let pos = env.alloc_scratch();
1828                unsafe { env.shift_left(&local_rs1, &shamt.clone(), pos) }
1829            };
1830
1831            env.write_register(&rd, local_rd);
1832            env.set_instruction_pointer(next_instruction_pointer.clone());
1833            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1834        }
1835        IInstruction::ShiftRightLogicalImmediate => {
1836            let local_rs1 = env.read_register(&rs1);
1838            let local_rd = {
1839                let pos = env.alloc_scratch();
1840                unsafe { env.shift_right(&local_rs1, &shamt, pos) }
1841            };
1842            env.write_register(&rd, local_rd);
1843            env.set_instruction_pointer(next_instruction_pointer.clone());
1844            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1845        }
1846        IInstruction::ShiftRightArithmeticImmediate => {
1847            let local_rs1 = env.read_register(&rs1);
1849
1850            let local_rd = {
1851                let pos = env.alloc_scratch();
1852                unsafe { env.shift_right_arithmetic(&local_rs1, &shamt, pos) }
1853            };
1854            env.write_register(&rd, local_rd);
1855            env.set_instruction_pointer(next_instruction_pointer.clone());
1856            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1857        }
1858        IInstruction::SetLessThanImmediate => {
1859            let local_rs1 = env.read_register(&rs1);
1861            let local_imm = env.sign_extend(&imm, 12);
1862            let local_rd = {
1863                let pos = env.alloc_scratch();
1864                unsafe { env.test_less_than_signed(&local_rs1, &local_imm, pos) }
1865            };
1866            env.write_register(&rd, local_rd);
1867            env.set_instruction_pointer(next_instruction_pointer.clone());
1868            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1869        }
1870        IInstruction::SetLessThanImmediateUnsigned => {
1871            let local_rs1 = env.read_register(&rs1);
1873            let local_imm = env.sign_extend(&imm, 12);
1874            let local_rd = {
1875                let pos = env.alloc_scratch();
1876                unsafe { env.test_less_than(&local_rs1, &local_imm, pos) }
1877            };
1878            env.write_register(&rd, local_rd);
1879            env.set_instruction_pointer(next_instruction_pointer.clone());
1880            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1881        }
1882        IInstruction::AddImmediate => {
1883            let local_rs1 = env.read_register(&(rs1.clone()));
1885            let local_imm = env.sign_extend(&imm, 12);
1886            let local_rd = {
1887                let overflow_scratch = env.alloc_scratch();
1888                let rd_scratch = env.alloc_scratch();
1889                let (local_rd, _overflow) = unsafe {
1890                    env.add_witness(&local_rs1, &local_imm, rd_scratch, overflow_scratch)
1891                };
1892                local_rd
1893            };
1894            env.write_register(&rd, local_rd);
1895            env.set_instruction_pointer(next_instruction_pointer.clone());
1896            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1897        }
1898        IInstruction::XorImmediate => {
1899            let local_rs1 = env.read_register(&rs1);
1901            let local_imm = env.sign_extend(&imm, 12);
1902            let local_rd = {
1903                let rd_scratch = env.alloc_scratch();
1904                unsafe { env.xor_witness(&local_rs1, &local_imm, rd_scratch) }
1905            };
1906            env.write_register(&rd, local_rd);
1907            env.set_instruction_pointer(next_instruction_pointer.clone());
1908            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1909        }
1910        IInstruction::OrImmediate => {
1911            let local_rs1 = env.read_register(&rs1);
1913            let local_imm = env.sign_extend(&imm, 12);
1914            let local_rd = {
1915                let rd_scratch = env.alloc_scratch();
1916                unsafe { env.or_witness(&local_rs1, &local_imm, rd_scratch) }
1917            };
1918            env.write_register(&rd, local_rd);
1919            env.set_instruction_pointer(next_instruction_pointer.clone());
1920            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1921        }
1922        IInstruction::AndImmediate => {
1923            let local_rs1 = env.read_register(&rs1);
1925            let local_imm = env.sign_extend(&imm, 12);
1926            let local_rd = {
1927                let rd_scratch = env.alloc_scratch();
1928                unsafe { env.and_witness(&local_rs1, &local_imm, rd_scratch) }
1929            };
1930            env.write_register(&rd, local_rd);
1931            env.set_instruction_pointer(next_instruction_pointer.clone());
1932            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
1933        }
1934        IInstruction::JumpAndLinkRegister => {
1935            let addr = env.read_register(&rs1);
1936            let offset = env.sign_extend(&imm, 12);
1942            let new_addr = {
1943                let res_scratch = env.alloc_scratch();
1944                let overflow_scratch = env.alloc_scratch();
1945                let (res, _overflow) =
1946                    unsafe { env.add_witness(&addr, &offset, res_scratch, overflow_scratch) };
1947                res
1948            };
1949            env.write_register(&rd, next_instruction_pointer.clone());
1950            env.set_instruction_pointer(new_addr.clone());
1951            env.set_next_instruction_pointer(new_addr.clone() + Env::constant(4u32));
1952        }
1953    };
1954}
1955
1956pub fn interpret_stype<Env: InterpreterEnv>(env: &mut Env, instr: SInstruction) {
1965    let instruction_pointer = env.get_instruction_pointer();
1967    let next_instruction_pointer = env.get_next_instruction_pointer();
1969    let instruction = {
1971        let v0 = env.read_memory(&instruction_pointer);
1972        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
1973        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
1974        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
1975        (v3 * Env::constant(1 << 24))
1976            + (v2 * Env::constant(1 << 16))
1977            + (v1 * Env::constant(1 << 8))
1978            + v0
1979    };
1980
1981    let opcode = {
1983        let pos = env.alloc_scratch();
1984        unsafe { env.bitmask(&instruction, 7, 0, pos) }
1985    };
1986    env.range_check8(&opcode, 7);
1988
1989    let imm0_4 = {
1990        let pos = env.alloc_scratch();
1991        unsafe { env.bitmask(&instruction, 12, 7, pos) }
1992        };
1994    env.range_check8(&imm0_4, 5);
1995    let funct3 = {
1996        let pos = env.alloc_scratch();
1997        unsafe { env.bitmask(&instruction, 15, 12, pos) }
1998    };
1999    env.range_check8(&funct3, 3);
2000
2001    let rs1 = {
2002        let pos = env.alloc_scratch();
2003        unsafe { env.bitmask(&instruction, 20, 15, pos) }
2004    };
2005    env.range_check8(&rs1, 5);
2006    let rs2 = {
2007        let pos = env.alloc_scratch();
2008        unsafe { env.bitmask(&instruction, 25, 20, pos) }
2009    };
2010    env.range_check8(&rs2, 5);
2011
2012    let imm5_11 = {
2013        let pos = env.alloc_scratch();
2014        unsafe { env.bitmask(&instruction, 32, 25, pos) }
2015        };
2017    env.range_check8(&imm5_11, 7);
2018
2019    env.add_constraint(
2021        instruction
2022         - (opcode.clone() * Env::constant(1 << 0))    - (imm0_4.clone() * Env::constant(1 << 7))    - (funct3.clone() * Env::constant(1 << 12))   - (rs1.clone() * Env::constant(1 << 15))      - (rs2.clone() * Env::constant(1 << 20))      - (imm5_11.clone() * Env::constant(1 << 25)), );
2029
2030    let local_rs1 = env.read_register(&rs1);
2031    let local_imm0_4 = env.sign_extend(&imm0_4, 5);
2032    let local_imm5_11 = env.sign_extend(&imm5_11, 7);
2033    let local_imm0_11 = {
2034        let pos = env.alloc_scratch();
2035        let shift_pos = env.alloc_scratch();
2036        let shifted_imm5_11 =
2037            unsafe { env.shift_left(&local_imm5_11, &Env::constant(5), shift_pos) };
2038        let local_imm0_11 = unsafe { env.or_witness(&shifted_imm5_11, &local_imm0_4, pos) };
2039        env.sign_extend(&local_imm0_11, 11)
2040    };
2041    let address = {
2042        let address_scratch = env.alloc_scratch();
2043        let overflow_scratch = env.alloc_scratch();
2044        let (address, _overflow) = unsafe {
2045            env.add_witness(
2046                &local_rs1,
2047                &local_imm0_11,
2048                address_scratch,
2049                overflow_scratch,
2050            )
2051        };
2052        address
2053    };
2054    let local_rs2 = env.read_register(&rs2);
2055
2056    match instr {
2057        SInstruction::StoreByte => {
2058            let v0 = {
2060                let value_scratch = env.alloc_scratch();
2061                unsafe { env.bitmask(&local_rs2, 8, 0, value_scratch) }
2062            };
2063
2064            env.lookup_8bits(&v0);
2065            env.write_memory(&address, v0);
2066
2067            env.set_instruction_pointer(next_instruction_pointer.clone());
2068            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2069        }
2070        SInstruction::StoreHalf => {
2071            let [v0, v1] = [
2073                {
2074                    let value_scratch = env.alloc_scratch();
2075                    unsafe { env.bitmask(&local_rs2, 8, 0, value_scratch) }
2076                },
2077                {
2078                    let value_scratch = env.alloc_scratch();
2079                    unsafe { env.bitmask(&local_rs2, 16, 8, value_scratch) }
2080                },
2081            ];
2082
2083            env.lookup_8bits(&v0);
2084            env.lookup_8bits(&v1);
2085
2086            env.write_memory(&address, v0);
2087            env.write_memory(&(address.clone() + Env::constant(1u32)), v1);
2088
2089            env.set_instruction_pointer(next_instruction_pointer.clone());
2090            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2091        }
2092        SInstruction::StoreWord => {
2093            let [v0, v1, v2, v3] = [
2095                {
2096                    let value_scratch = env.alloc_scratch();
2097                    unsafe { env.bitmask(&local_rs2, 32, 24, value_scratch) }
2098                },
2099                {
2100                    let value_scratch = env.alloc_scratch();
2101                    unsafe { env.bitmask(&local_rs2, 24, 16, value_scratch) }
2102                },
2103                {
2104                    let value_scratch = env.alloc_scratch();
2105                    unsafe { env.bitmask(&local_rs2, 16, 8, value_scratch) }
2106                },
2107                {
2108                    let value_scratch = env.alloc_scratch();
2109                    unsafe { env.bitmask(&local_rs2, 8, 0, value_scratch) }
2110                },
2111            ];
2112
2113            env.lookup_8bits(&v0);
2114            env.lookup_8bits(&v1);
2115            env.lookup_8bits(&v2);
2116            env.lookup_8bits(&v3);
2117
2118            env.write_memory(&address, v0);
2119            env.write_memory(&(address.clone() + Env::constant(1u32)), v1);
2120            env.write_memory(&(address.clone() + Env::constant(2u32)), v2);
2121            env.write_memory(&(address.clone() + Env::constant(3u32)), v3);
2122
2123            env.set_instruction_pointer(next_instruction_pointer.clone());
2124            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2125        }
2126    };
2127}
2128
2129pub fn interpret_sbtype<Env: InterpreterEnv>(env: &mut Env, instr: SBInstruction) {
2138    let instruction_pointer = env.get_instruction_pointer();
2139    let next_instruction_pointer = env.get_next_instruction_pointer();
2140    let instruction = {
2141        let v0 = env.read_memory(&instruction_pointer);
2142        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
2143        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
2144        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
2145        (v3 * Env::constant(1 << 24))
2146            + (v2 * Env::constant(1 << 16))
2147            + (v1 * Env::constant(1 << 8))
2148            + v0
2149    };
2150    let opcode = {
2151        let pos = env.alloc_scratch();
2152        unsafe { env.bitmask(&instruction, 7, 0, pos) }
2153    };
2154
2155    env.range_check8(&opcode, 7);
2156
2157    let funct3 = {
2158        let pos = env.alloc_scratch();
2159        unsafe { env.bitmask(&instruction, 15, 12, pos) }
2160    };
2161    env.range_check8(&funct3, 3);
2162
2163    let rs1 = {
2164        let pos = env.alloc_scratch();
2165        unsafe { env.bitmask(&instruction, 20, 15, pos) }
2166    };
2167    env.range_check8(&rs1, 5);
2168
2169    let rs2 = {
2170        let pos = env.alloc_scratch();
2171        unsafe { env.bitmask(&instruction, 25, 20, pos) }
2172    };
2173    env.range_check8(&rs2, 5);
2174
2175    let imm0_12 = {
2176        let imm11 = {
2177            let pos = env.alloc_scratch();
2178            unsafe { env.bitmask(&instruction, 8, 7, pos) }
2179        };
2180
2181        env.assert_boolean(&imm11);
2182
2183        let imm1_4 = {
2184            let pos = env.alloc_scratch();
2185            unsafe { env.bitmask(&instruction, 12, 8, pos) }
2186        };
2187        env.range_check8(&imm1_4, 4);
2188
2189        let imm5_10 = {
2190            let pos = env.alloc_scratch();
2191            unsafe { env.bitmask(&instruction, 31, 25, pos) }
2192        };
2193        env.range_check8(&imm5_10, 6);
2194
2195        let imm12 = {
2196            let pos = env.alloc_scratch();
2197            unsafe { env.bitmask(&instruction, 32, 31, pos) }
2198        };
2199        env.assert_boolean(&imm12);
2200
2201        env.add_constraint(
2203            instruction.clone()
2204                - (opcode * Env::constant(1 << 0))    - (imm11.clone() * Env::constant(1 << 7))     - (imm1_4.clone() * Env::constant(1 << 8))    - (funct3 * Env::constant(1 << 11))   - (rs1.clone() * Env::constant(1 << 14))      - (rs2.clone() * Env::constant(1 << 19))      - (imm5_10.clone() * Env::constant(1 << 24))  - (imm12.clone() * Env::constant(1 << 31)), );
2213
2214        (imm12 * Env::constant(1 << 12))
2215            + (imm11 * Env::constant(1 << 11))
2216            + (imm5_10 * Env::constant(1 << 5))
2217            + (imm1_4 * Env::constant(1 << 1))
2218    };
2219    let imm0_12 = env.sign_extend(&imm0_12, 13);
2221
2222    match instr {
2223        SBInstruction::BranchEq => {
2224            let local_rs1 = env.read_register(&rs1);
2226            let local_rs2 = env.read_register(&rs2);
2227
2228            let equals = env.equal(&local_rs1, &local_rs2);
2229            let offset = (Env::constant(1) - equals.clone()) * Env::constant(4) + equals * imm0_12;
2230            let offset = env.sign_extend(&offset, 12);
2231            let addr = {
2232                let res_scratch = env.alloc_scratch();
2233                let overflow_scratch = env.alloc_scratch();
2234                let (res, _overflow) = unsafe {
2235                    env.add_witness(
2236                        &next_instruction_pointer,
2237                        &offset,
2238                        res_scratch,
2239                        overflow_scratch,
2240                    )
2241                };
2242                res
2244            };
2245            env.set_instruction_pointer(next_instruction_pointer);
2246            env.set_next_instruction_pointer(addr);
2247        }
2248        SBInstruction::BranchNeq => {
2249            let local_rs1 = env.read_register(&rs1);
2251            let local_rs2 = env.read_register(&rs2);
2252
2253            let equals = env.equal(&local_rs1, &local_rs2);
2254            let offset = equals.clone() * Env::constant(4) + (Env::constant(1) - equals) * imm0_12;
2255            let addr = {
2256                let res_scratch = env.alloc_scratch();
2257                let overflow_scratch = env.alloc_scratch();
2258                let (res, _overflow) = unsafe {
2259                    env.add_witness(
2260                        &next_instruction_pointer,
2261                        &offset,
2262                        res_scratch,
2263                        overflow_scratch,
2264                    )
2265                };
2266                res
2268            };
2269            env.set_instruction_pointer(next_instruction_pointer);
2270            env.set_next_instruction_pointer(addr);
2271        }
2272        SBInstruction::BranchLessThan => {
2273            let local_rs1 = env.read_register(&rs1);
2275            let local_rs2 = env.read_register(&rs2);
2276
2277            let less_than = {
2278                let rd_scratch = env.alloc_scratch();
2279                unsafe { env.test_less_than_signed(&local_rs1, &local_rs2, rd_scratch) }
2280            };
2281            let offset = (less_than.clone()) * imm0_12
2282                + (Env::constant(1) - less_than.clone()) * Env::constant(4);
2283
2284            let addr = {
2285                let res_scratch = env.alloc_scratch();
2286                let overflow_scratch = env.alloc_scratch();
2287                let (res, _overflow) = unsafe {
2288                    env.add_witness(
2289                        &next_instruction_pointer,
2290                        &offset,
2291                        res_scratch,
2292                        overflow_scratch,
2293                    )
2294                };
2295                res
2297            };
2298            env.set_instruction_pointer(next_instruction_pointer);
2299            env.set_next_instruction_pointer(addr);
2300        }
2301        SBInstruction::BranchGreaterThanEqual => {
2302            let local_rs1 = env.read_register(&rs1);
2304            let local_rs2 = env.read_register(&rs2);
2305
2306            let less_than = {
2307                let rd_scratch = env.alloc_scratch();
2308                unsafe { env.test_less_than_signed(&local_rs1, &local_rs2, rd_scratch) }
2309            };
2310
2311            let offset =
2312                less_than.clone() * Env::constant(4) + (Env::constant(1) - less_than) * imm0_12;
2313            let addr = {
2315                let res_scratch = env.alloc_scratch();
2316                let overflow_scratch = env.alloc_scratch();
2317                let (res, _overflow) = unsafe {
2318                    env.add_witness(
2319                        &next_instruction_pointer,
2320                        &offset,
2321                        res_scratch,
2322                        overflow_scratch,
2323                    )
2324                };
2325                res
2327            };
2328            env.set_instruction_pointer(next_instruction_pointer);
2329            env.set_next_instruction_pointer(addr);
2330        }
2331        SBInstruction::BranchLessThanUnsigned => {
2332            let local_rs1 = env.read_register(&rs1);
2334            let local_rs2 = env.read_register(&rs2);
2335
2336            let less_than = {
2337                let rd_scratch = env.alloc_scratch();
2338                unsafe { env.test_less_than(&local_rs1, &local_rs2, rd_scratch) }
2339            };
2340
2341            let offset = (Env::constant(1) - less_than.clone()) * Env::constant(4)
2342                + less_than.clone() * imm0_12;
2343
2344            let addr = {
2345                let res_scratch = env.alloc_scratch();
2346                let overflow_scratch = env.alloc_scratch();
2347                let (res, _overflow) = unsafe {
2348                    env.add_witness(&instruction_pointer, &offset, res_scratch, overflow_scratch)
2349                };
2350                res
2352            };
2353
2354            env.set_instruction_pointer(next_instruction_pointer);
2355            env.set_next_instruction_pointer(addr);
2356        }
2357        SBInstruction::BranchGreaterThanEqualUnsigned => {
2358            let local_rs1 = env.read_register(&rs1);
2360            let local_rs2 = env.read_register(&rs2);
2361
2362            let rd_scratch = env.alloc_scratch();
2363            let less_than = unsafe { env.test_less_than(&local_rs1, &local_rs2, rd_scratch) };
2364            let offset =
2365                less_than.clone() * Env::constant(4) + (Env::constant(1) - less_than) * imm0_12;
2366
2367            let addr = {
2369                let res_scratch = env.alloc_scratch();
2370                let overflow_scratch = env.alloc_scratch();
2371                let (res, _overflow) = unsafe {
2372                    env.add_witness(&instruction_pointer, &offset, res_scratch, overflow_scratch)
2373                };
2374                res
2375            };
2376
2377            env.set_instruction_pointer(next_instruction_pointer);
2378            env.set_next_instruction_pointer(addr);
2379        }
2380    };
2381}
2382
2383pub fn interpret_utype<Env: InterpreterEnv>(env: &mut Env, instr: UInstruction) {
2392    let instruction_pointer = env.get_instruction_pointer();
2393    let next_instruction_pointer = env.get_next_instruction_pointer();
2394
2395    let instruction = {
2396        let v0 = env.read_memory(&instruction_pointer);
2397        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
2398        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
2399        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
2400        (v3 * Env::constant(1 << 24))
2401            + (v2 * Env::constant(1 << 16))
2402            + (v1 * Env::constant(1 << 8))
2403            + v0
2404    };
2405
2406    let opcode = {
2407        let pos = env.alloc_scratch();
2408        unsafe { env.bitmask(&instruction, 7, 0, pos) }
2409    };
2410    env.range_check8(&opcode, 7);
2411
2412    let rd = {
2413        let pos = env.alloc_scratch();
2414        unsafe { env.bitmask(&instruction, 12, 7, pos) }
2415    };
2416    env.range_check8(&rd, 5);
2417
2418    let imm = {
2419        let pos = env.alloc_scratch();
2420        unsafe { env.bitmask(&instruction, 32, 12, pos) }
2421    };
2422    env.add_constraint(
2426        instruction
2427            - (opcode.clone() * Env::constant(1 << 0))    - (rd.clone() * Env::constant(1 << 7))        - (imm.clone() * Env::constant(1 << 12)), );
2431
2432    match instr {
2433        UInstruction::LoadUpperImmediate => {
2434            let local_imm = {
2436                let shifted_imm = {
2437                    let pos = env.alloc_scratch();
2438                    unsafe { env.shift_left(&imm, &Env::constant(12), pos) }
2439                };
2440                env.sign_extend(&shifted_imm, 32)
2441            };
2442            env.write_register(&rd, local_imm);
2443
2444            env.set_instruction_pointer(next_instruction_pointer.clone());
2445            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2446        }
2447        UInstruction::AddUpperImmediate => {
2448            let local_imm = {
2450                let pos = env.alloc_scratch();
2451                let shifted_imm = unsafe { env.shift_left(&imm, &Env::constant(12), pos) };
2452                env.sign_extend(&shifted_imm, 32)
2453            };
2454            let local_pc = instruction_pointer.clone();
2455            let (local_rd, _) = {
2456                let pos = env.alloc_scratch();
2457                let overflow_pos = env.alloc_scratch();
2458                unsafe { env.add_witness(&local_pc, &local_imm, pos, overflow_pos) }
2459            };
2460            env.write_register(&rd, local_rd);
2461
2462            env.set_instruction_pointer(next_instruction_pointer.clone());
2463            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2464        }
2465    };
2466}
2467
2468pub fn interpret_ujtype<Env: InterpreterEnv>(env: &mut Env, instr: UJInstruction) {
2493    let instruction_pointer = env.get_instruction_pointer();
2494    let next_instruction_pointer = env.get_next_instruction_pointer();
2495
2496    let instruction = {
2497        let v0 = env.read_memory(&instruction_pointer);
2498        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
2499        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
2500        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
2501        (v3 * Env::constant(1 << 24))
2502            + (v2 * Env::constant(1 << 16))
2503            + (v1 * Env::constant(1 << 8))
2504            + v0
2505    };
2506
2507    let opcode = {
2508        let pos = env.alloc_scratch();
2509        unsafe { env.bitmask(&instruction, 7, 0, pos) }
2510    };
2511    env.range_check8(&opcode, 7);
2512
2513    let rd = {
2514        let pos = env.alloc_scratch();
2515        unsafe { env.bitmask(&instruction, 12, 7, pos) }
2516    };
2517    env.range_check8(&rd, 5);
2518
2519    let imm20 = {
2520        let pos = env.alloc_scratch();
2521        unsafe { env.bitmask(&instruction, 32, 31, pos) }
2522    };
2523    env.assert_boolean(&imm20);
2524
2525    let imm10_1 = {
2526        let pos = env.alloc_scratch();
2527        unsafe { env.bitmask(&instruction, 31, 21, pos) }
2528    };
2529    env.range_check16(&imm10_1, 10);
2530
2531    let imm11 = {
2532        let pos = env.alloc_scratch();
2533        unsafe { env.bitmask(&instruction, 21, 20, pos) }
2534    };
2535    env.assert_boolean(&imm11);
2536
2537    let imm19_12 = {
2538        let pos = env.alloc_scratch();
2539        unsafe { env.bitmask(&instruction, 20, 12, pos) }
2540    };
2541    env.range_check8(&imm19_12, 8);
2542
2543    let offset = {
2544        imm10_1.clone() * Env::constant(1 << 1)
2545            + imm11.clone() * Env::constant(1 << 11)
2546            + imm19_12.clone() * Env::constant(1 << 12)
2547            + imm20.clone() * Env::constant(1 << 20)
2548    };
2549
2550    match instr {
2553        UJInstruction::JumpAndLink => {
2554            let offset = env.sign_extend(&offset, 21);
2555            let new_addr = {
2556                let res_scratch = env.alloc_scratch();
2557                let overflow_scratch = env.alloc_scratch();
2558                let (res, _overflow) = unsafe {
2559                    env.add_witness(&instruction_pointer, &offset, res_scratch, overflow_scratch)
2560                };
2561                res
2562            };
2563            env.write_register(&rd, next_instruction_pointer.clone());
2564            env.set_instruction_pointer(new_addr.clone());
2565            env.set_next_instruction_pointer(new_addr + Env::constant(4u32));
2566        }
2567    }
2568}
2569
2570pub fn interpret_syscall<Env: InterpreterEnv>(env: &mut Env, _instr: SyscallInstruction) {
2571    env.set_halted(Env::constant(1));
2573}
2574
2575pub fn interpret_mtype<Env: InterpreterEnv>(env: &mut Env, instr: MInstruction) {
2584    let instruction_pointer = env.get_instruction_pointer();
2585    let next_instruction_pointer = env.get_next_instruction_pointer();
2586
2587    let instruction = {
2588        let v0 = env.read_memory(&instruction_pointer);
2589        let v1 = env.read_memory(&(instruction_pointer.clone() + Env::constant(1)));
2590        let v2 = env.read_memory(&(instruction_pointer.clone() + Env::constant(2)));
2591        let v3 = env.read_memory(&(instruction_pointer.clone() + Env::constant(3)));
2592        (v3 * Env::constant(1 << 24))
2593            + (v2 * Env::constant(1 << 16))
2594            + (v1 * Env::constant(1 << 8))
2595            + v0
2596    };
2597
2598    let opcode = {
2599        let pos = env.alloc_scratch();
2600        unsafe { env.bitmask(&instruction, 7, 0, pos) }
2601    };
2602    env.range_check8(&opcode, 7);
2603
2604    let rd = {
2605        let pos = env.alloc_scratch();
2606        unsafe { env.bitmask(&instruction, 12, 7, pos) }
2607    };
2608    env.range_check8(&rd, 5);
2609
2610    let funct3 = {
2611        let pos = env.alloc_scratch();
2612        unsafe { env.bitmask(&instruction, 15, 12, pos) }
2613    };
2614    env.range_check8(&funct3, 3);
2615
2616    let rs1 = {
2617        let pos = env.alloc_scratch();
2618        unsafe { env.bitmask(&instruction, 20, 15, pos) }
2619    };
2620    env.range_check8(&rs1, 5);
2621
2622    let rs2 = {
2623        let pos = env.alloc_scratch();
2624        unsafe { env.bitmask(&instruction, 25, 20, pos) }
2625    };
2626    env.range_check8(&rs2, 5);
2627
2628    let funct2 = {
2629        let pos = env.alloc_scratch();
2630        unsafe { env.bitmask(&instruction, 27, 25, pos) }
2631    };
2632    env.range_check8(&funct2, 2);
2634
2635    let funct5 = {
2636        let pos = env.alloc_scratch();
2637        unsafe { env.bitmask(&instruction, 32, 27, pos) }
2638    };
2639    env.range_check8(&funct5, 5);
2641
2642    env.add_constraint(
2644        instruction
2645            - (opcode.clone() * Env::constant(1 << 0))    - (rd.clone() * Env::constant(1 << 7))        - (funct3.clone() * Env::constant(1 << 12))   - (rs1.clone() * Env::constant(1 << 15))      - (rs2.clone() * Env::constant(1 << 20))      - (funct2.clone() * Env::constant(1 << 25))   - (funct5.clone() * Env::constant(1 << 27)), );
2653
2654    match instr {
2655        MInstruction::Mul => {
2656            let rs1 = env.read_register(&rs1);
2658            let rs2 = env.read_register(&rs2);
2659            let res = {
2661                let pos = env.alloc_scratch();
2662                unsafe { env.mul_lo_signed(&rs1, &rs2, pos) }
2663            };
2664            env.write_register(&rd, res);
2665
2666            env.set_instruction_pointer(next_instruction_pointer.clone());
2667            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2668        }
2669        MInstruction::Mulh => {
2670            let rs1 = env.read_register(&rs1);
2672            let rs2 = env.read_register(&rs2);
2673            let res = {
2675                let pos = env.alloc_scratch();
2676                unsafe { env.mul_hi_signed(&rs1, &rs2, pos) }
2677            };
2678            env.write_register(&rd, res);
2679
2680            env.set_instruction_pointer(next_instruction_pointer.clone());
2681            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2682        }
2683        MInstruction::Mulhsu => {
2684            let rs1 = env.read_register(&rs1);
2686            let rs2 = env.read_register(&rs2);
2687            let res = {
2689                let pos = env.alloc_scratch();
2690                unsafe { env.mul_hi_signed_unsigned(&rs1, &rs2, pos) }
2691            };
2692            env.write_register(&rd, res);
2693
2694            env.set_instruction_pointer(next_instruction_pointer.clone());
2695            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2696        }
2697        MInstruction::Mulhu => {
2698            let rs1 = env.read_register(&rs1);
2700            let rs2 = env.read_register(&rs2);
2701            let res = {
2703                let pos = env.alloc_scratch();
2704                unsafe { env.mul_hi(&rs1, &rs2, pos) }
2705            };
2706            env.write_register(&rd, res);
2707
2708            env.set_instruction_pointer(next_instruction_pointer.clone());
2709            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2710        }
2711        MInstruction::Div => {
2712            let rs1 = env.read_register(&rs1);
2714            let rs2 = env.read_register(&rs2);
2715            let res = {
2717                let pos = env.alloc_scratch();
2718                unsafe { env.div_signed(&rs1, &rs2, pos) }
2719            };
2720            env.write_register(&rd, res);
2721
2722            env.set_instruction_pointer(next_instruction_pointer.clone());
2723            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2724        }
2725        MInstruction::Divu => {
2726            let rs1 = env.read_register(&rs1);
2728            let rs2 = env.read_register(&rs2);
2729            let res = {
2731                let pos = env.alloc_scratch();
2732                unsafe { env.div(&rs1, &rs2, pos) }
2733            };
2734            env.write_register(&rd, res);
2735
2736            env.set_instruction_pointer(next_instruction_pointer.clone());
2737            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2738        }
2739        MInstruction::Rem => {
2740            let rs1 = env.read_register(&rs1);
2742            let rs2 = env.read_register(&rs2);
2743            let res = {
2745                let pos = env.alloc_scratch();
2746                unsafe { env.mod_signed(&rs1, &rs2, pos) }
2747            };
2748            env.write_register(&rd, res);
2749
2750            env.set_instruction_pointer(next_instruction_pointer.clone());
2751            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2752        }
2753        MInstruction::Remu => {
2754            let rs1 = env.read_register(&rs1);
2756            let rs2 = env.read_register(&rs2);
2757            let res = {
2759                let pos = env.alloc_scratch();
2760                unsafe { env.mod_unsigned(&rs1, &rs2, pos) }
2761            };
2762            env.write_register(&rd, res);
2763
2764            env.set_instruction_pointer(next_instruction_pointer.clone());
2765            env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32));
2766        }
2767    }
2768}