1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
use crate::interpreters::mips::{
    witness::SCRATCH_SIZE,
    Instruction::{self, IType, JType, RType},
};
use kimchi_msm::{
    columns::{Column, ColumnIndexer},
    witness::Witness,
};
use std::ops::{Index, IndexMut};
use strum::EnumCount;

use super::{ITypeInstruction, JTypeInstruction, RTypeInstruction};

/// The number of hashes performed so far in the block
pub(crate) const MIPS_HASH_COUNTER_OFF: usize = 80;
/// The number of bytes of the preimage that have been read so far in this hash
pub(crate) const MIPS_BYTE_COUNTER_OFF: usize = 81;
/// A flag indicating whether the preimage has been read fully or not
pub(crate) const MIPS_END_OF_PREIMAGE_OFF: usize = 82;
/// The number of preimage bytes processed in this step
pub(crate) const MIPS_NUM_BYTES_READ_OFF: usize = 83;
/// The at most 4-byte chunk of the preimage that has been read in this step.
/// Contains a field element of at most 4 bytes.
pub(crate) const MIPS_PREIMAGE_CHUNK_OFF: usize = 84;
/// The at most 4-bytes of the preimage that are currently being processed
/// Consists of 4 field elements of at most 1 byte each.
pub(crate) const MIPS_PREIMAGE_BYTES_OFF: usize = 85;
/// The at most 4-bytes of the length that are currently being processed
pub(crate) const MIPS_LENGTH_BYTES_OFF: usize = 89;
/// Flags indicating whether at least N bytes have been processed in this step
pub(crate) const MIPS_HAS_N_BYTES_OFF: usize = 93;
/// The maximum size of a chunk (4 bytes)
pub(crate) const MIPS_CHUNK_BYTES_LEN: usize = 4;
/// The location of the preimage key as a field element of 248bits
pub(crate) const MIPS_PREIMAGE_KEY: usize = 97;

/// The number of columns used for relation witness in the MIPS circuit
pub const N_MIPS_REL_COLS: usize = SCRATCH_SIZE + 2;

/// The number of witness columns used to store the instruction selectors.
pub const N_MIPS_SEL_COLS: usize =
    RTypeInstruction::COUNT + JTypeInstruction::COUNT + ITypeInstruction::COUNT;

/// All the witness columns used in MIPS
pub const N_MIPS_COLS: usize = N_MIPS_REL_COLS + N_MIPS_SEL_COLS;

/// Abstract columns (or variables of our multi-variate polynomials) that will
/// be used to describe our constraints.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ColumnAlias {
    // Can be seen as the abstract indexed variable X_{i}
    ScratchState(usize),
    InstructionCounter,
    Selector(usize),
}

/// The columns used by the MIPS circuit. The MIPS circuit is split into three
/// main opcodes: RType, JType, IType. The columns are shared between different
/// instruction types. (the total number of columns refers to the maximum of
/// columns used by each mode)
impl From<ColumnAlias> for usize {
    fn from(alias: ColumnAlias) -> usize {
        // Note that SCRATCH_SIZE + 1 is for the error
        match alias {
            ColumnAlias::ScratchState(i) => {
                assert!(i < SCRATCH_SIZE);
                i
            }
            ColumnAlias::InstructionCounter => SCRATCH_SIZE,
            ColumnAlias::Selector(s) => SCRATCH_SIZE + 1 + s,
        }
    }
}

/// Returns the corresponding index of the corresponding DynamicSelector column.
impl From<Instruction> for usize {
    fn from(instr: Instruction) -> usize {
        match instr {
            RType(rtype) => N_MIPS_REL_COLS + rtype as usize,
            JType(jtype) => N_MIPS_REL_COLS + RTypeInstruction::COUNT + jtype as usize,
            IType(itype) => {
                N_MIPS_REL_COLS + RTypeInstruction::COUNT + JTypeInstruction::COUNT + itype as usize
            }
        }
    }
}

/// Represents one line of the execution trace of the virtual machine
/// It contain
/// + [SCRATCH_SIZE] columns
/// + 1 column to keep track of the instruction index
/// + 1 column for the system error code
/// + [N_MIPS_SEL_COLS]  columns for the instruction selectors.
/// The columns are, in order,
/// - the 32 general purpose registers
/// - the low and hi registers used by some arithmetic instructions
/// - the current instruction pointer
/// - the next instruction pointer
/// - the heap pointer
/// - the preimage key, splitted in 8 consecutive columns representing 4 bytes
/// of the 32 bytes long preimage key
/// - the preimage offset, i.e. the number of bytes that have been read for the
/// currently processing preimage
/// - `[SCRATCH_SIZE] - 46` intermediate columns that can be used by the
/// instruction set
/// - the hash counter
/// - the flag to indicate if the current instruction is a preimage syscall
/// - the flag to indicate if the current instruction is reading a preimage
/// - the number of bytes read so far for the current preimage
/// - how many bytes are left to be read for the current preimage
/// - the (at most) 4 bytes of the preimage key that are currently being
///   processed
/// - 4 helpers to check if at least n bytes were read in the current row
pub type MIPSWitness<T> = Witness<N_MIPS_COLS, T>;

// IMPLEMENTATIONS FOR COLUMN ALIAS

impl<T: Clone> Index<ColumnAlias> for MIPSWitness<T> {
    type Output = T;

    /// Map the column alias to the actual column index.
    fn index(&self, index: ColumnAlias) -> &Self::Output {
        &self.cols[usize::from(index)]
    }
}

impl<T: Clone> IndexMut<ColumnAlias> for MIPSWitness<T> {
    fn index_mut(&mut self, index: ColumnAlias) -> &mut Self::Output {
        &mut self.cols[usize::from(index)]
    }
}

impl ColumnIndexer for ColumnAlias {
    const N_COL: usize = N_MIPS_COLS;
    fn to_column(self) -> Column {
        match self {
            Self::ScratchState(ss) => {
                assert!(ss < SCRATCH_SIZE);
                Column::Relation(ss)
            }
            Self::InstructionCounter => Column::Relation(SCRATCH_SIZE),
            // TODO: what happens with error? It does not have a corresponding alias
            Self::Selector(s) => {
                assert!(s < N_MIPS_SEL_COLS);
                Column::DynamicSelector(s)
            }
        }
    }
}

// IMPLEMENTATIONS FOR SELECTOR

impl<T: Clone> Index<Instruction> for MIPSWitness<T> {
    type Output = T;

    /// Map the column alias to the actual column index.
    fn index(&self, index: Instruction) -> &Self::Output {
        &self.cols[usize::from(index)]
    }
}

impl<T: Clone> IndexMut<Instruction> for MIPSWitness<T> {
    fn index_mut(&mut self, index: Instruction) -> &mut Self::Output {
        &mut self.cols[usize::from(index)]
    }
}

impl ColumnIndexer for Instruction {
    const N_COL: usize = N_MIPS_REL_COLS + N_MIPS_SEL_COLS;
    fn to_column(self) -> Column {
        Column::DynamicSelector(usize::from(self) - N_MIPS_REL_COLS)
    }
}