|
| 1 | +include "constants_gen.pil"; |
| 2 | +include "precomputed.pil"; |
1 | 3 | include "range_check.pil";
|
2 | 4 |
|
3 | 5 | namespace memory;
|
4 | 6 |
|
5 |
| -pol commit sel; |
6 |
| -pol commit clk; |
7 |
| -pol commit address; |
| 7 | +// Link to design document: https://docs.google.com/document/d/1NM5zU39NG5xJReOjSObwWllbpqTCO4flr9v8kdRDK3E |
| 8 | + |
| 9 | +// Main memory values directly derived from the memory events. |
8 | 10 | pol commit value;
|
9 | 11 | pol commit tag;
|
10 |
| -pol commit rw; |
11 |
| -pol commit space_id; |
| 12 | +pol commit space_id; // Memory space identifier (16-bit). |
| 13 | +pol commit address; // Memory address (32-bit). |
| 14 | +pol commit clk; // Clock cycle. (32-bit) Row index of corresponding opcode in the execution trace. |
| 15 | +pol commit rw; // Memory operation type: 0 for read, 1 for write. |
| 16 | + |
| 17 | +// Boolean selectors. |
| 18 | +pol commit sel; // Main selector to toggle an active row (used by any interaction lookups.). |
| 19 | +pol commit last_access; // Last memory access for a given global address |
| 20 | +pol commit sel_rng_chk; // Every active row except the last one |
| 21 | +pol commit sel_tag_is_ff; // Toggles if tag == FF |
| 22 | +pol commit sel_rng_write; // Toggles if rw == 1 and tag != FF (Activate range check for write values.) |
| 23 | + |
| 24 | +// Derived values. |
| 25 | +pol commit global_addr; // Global unique address derived from space_id and address. |
| 26 | +pol commit timestamp; // Timestamp derived from clk and rw. |
| 27 | +pol commit diff; // Difference between timestamp or global_addr values of consecutive rows to prove that memory is correctly sorted. |
| 28 | +pol commit limb[3]; // 16-bit decomposition limbs for diff. |
| 29 | + |
| 30 | +// Others |
| 31 | +pol commit max_bits; // Number of bits corresponding to the tag. (Retrieved from precomputed subtrace.) |
| 32 | + |
| 33 | +// Trace entries ordering. |
| 34 | +// The memory entries are sorted in ascending order by space_id, address, clk, then rw. |
| 35 | +// Equivalently, they are sorted by global_addr and then timestamp. |
| 36 | +// last_access == 1 iff the last memory access for a given global address. |
| 37 | + |
| 38 | +// Trace shape |
| 39 | + |
| 40 | +// +-----+-----------+-------+-----+-----+---------------+------------+------------+--------------+-------------+ |
| 41 | +// | sel | space_id | address | clk | rw | global_addr | timestamp | last_access| diff | sel_rng_chk | |
| 42 | +// +-----+-----------+-------+-----+-----+---------------+------------+------------+--------------+-------------+ |
| 43 | +// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 11 | 0 | |
| 44 | +// | 1 | 1 | 27 | 5 | 1 | 2^32 + 27 | 5 * 2 + 1 | 1 | 1 | 1 | |
| 45 | +// | 1 | 1 | 28 | 12 | 1 | 2^32 + 28 | 12 * 2 + 1 | 1 | 2 * 2^32 + 3 | 1 | |
| 46 | +// | 1 | 3 | 31 | 7 | 0 | 3 * 2^32 + 31 | 7 * 2 + 0 | 0 | 3 | 1 | |
| 47 | +// | 1 | 3 | 31 | 8 | 1 | 3 * 2^32 + 31 | 8 * 2 + 1 | 1 | 2^32 + 15 | 1 | |
| 48 | +// | 1 | 4 | 46 | 5 | 0 | 4 * 2^32 + 46 | 5 * 2 + 0 | 0 | 0 | 1 | |
| 49 | +// | 1 | 4 | 46 | 5 | 0 | 4 * 2^32 + 46 | 5 * 2 + 0 | 0 | 1 | 1 | |
| 50 | +// | 1 | 4 | 46 | 5 | 1 | 4 * 2^32 + 46 | 5 * 2 + 1 | 0 | 1 | 1 | |
| 51 | +// | 1 | 4 | 46 | 6 | 1 | 4 * 2^32 + 46 | 6 * 2 + 1 | 1 | 43 | 1 | |
| 52 | +// | 1 | 4 | 89 | 2 | 1 | 4 * 2^32 + 89 | 2 * 2 + 1 | 1 |-4 * 2^32 - 89| 0 | |
| 53 | +// +-----+-----------+-------+-----+-------------+----------------------+----------+--------------+-------------+ |
| 54 | + |
| 55 | +#[skippable_if] |
| 56 | +sel + precomputed.first_row = 0; |
12 | 57 |
|
13 | 58 | // Permutation selectors (addressing.pil).
|
14 | 59 | pol commit sel_addressing_base;
|
@@ -53,11 +98,94 @@ sel = // Addressing.
|
53 | 98 | + sel_sha256_op[4] + sel_sha256_op[5] + sel_sha256_op[6] + sel_sha256_op[7];
|
54 | 99 | */
|
55 | 100 |
|
56 |
| -#[skippable_if] |
57 |
| -sel = 0; |
| 101 | +// Other boolean constraints. |
| 102 | +sel * (1 - sel) = 0; // Ensure mutual exclusivity of the permutation selectors. |
| 103 | +last_access * (1 - last_access) = 0; |
| 104 | +rw * (1 - rw) = 0; // TODO: should already be constrained by each source of interaction lookups. |
| 105 | +sel_tag_is_ff * (1 - sel_tag_is_ff) = 0; |
| 106 | + |
| 107 | +// Trace must be contiguous. |
| 108 | +// Except on first row: sel == 0 ==> sel' == 0 |
| 109 | +// As a consequence, the trace is empty or it starts just after the first row and |
| 110 | +// is contiguous. |
| 111 | +#[MEM_CONTIGUOUS] |
| 112 | +(1 - precomputed.first_row) * (1 - sel) * sel' = 0; |
| 113 | + |
| 114 | +// Boolean toggles at all active rows except the last one. |
| 115 | +// It is boolean by definition. |
| 116 | +#[SEL_RNG_CHK] |
| 117 | +sel_rng_chk = sel * sel'; |
| 118 | + |
| 119 | +// Derived values. |
| 120 | + |
| 121 | +#[GLOBAL_ADDR] |
| 122 | +global_addr = space_id * 2**32 + address; |
| 123 | + |
| 124 | +#[TIMESTAMP] |
| 125 | +timestamp = 2 * clk + rw; |
| 126 | + |
| 127 | +// last_access derivation |
| 128 | +// last_access == 0 iff global_addr' == global_addr |
| 129 | +pol GLOB_ADDR_DIFF = global_addr' - global_addr; |
| 130 | +pol commit glob_addr_diff_inv; // Helper column for non zero equality check |
| 131 | +#[LAST_ACCESS] |
| 132 | +sel_rng_chk * (GLOB_ADDR_DIFF * ((1 - last_access) * (1 - glob_addr_diff_inv) + glob_addr_diff_inv) - last_access) = 0; |
| 133 | + |
| 134 | +// diff derivation |
| 135 | +// We alternate between two different diffs: |
| 136 | +// - last_access == 1: diff = global_addr' - global_addr |
| 137 | +// - last_access == 0: diff = timestamp' - timestamp - rw' * rw |
| 138 | +#[DIFF] |
| 139 | +diff = sel_rng_chk * (last_access * GLOB_ADDR_DIFF + (1 - last_access) * (timestamp' - timestamp - rw' * rw)); |
| 140 | + |
| 141 | +// Decompose diff into 16-bit limbs. |
| 142 | +#[DIFF_DECOMP] |
| 143 | +diff = limb[0] + limb[1] * 2**16 + limb[2] * 2**32; |
| 144 | + |
| 145 | +// Range check limbs |
| 146 | + |
| 147 | +#[RANGE_CHECK_LIMB_0] |
| 148 | +sel_rng_chk { limb[0] } in precomputed.sel_range_16 { precomputed.clk }; |
| 149 | +#[RANGE_CHECK_LIMB_1] |
| 150 | +sel_rng_chk { limb[1] } in precomputed.sel_range_16 { precomputed.clk }; |
| 151 | +#[RANGE_CHECK_LIMB_2] |
| 152 | +sel_rng_chk { limb[2] } in precomputed.sel_range_16 { precomputed.clk }; |
| 153 | + |
| 154 | +// Memory Initialization |
| 155 | +#[MEMORY_INIT_VALUE] |
| 156 | +(last_access + precomputed.first_row) * (1 - rw') * value' = 0; |
| 157 | +#[MEMORY_INIT_TAG] |
| 158 | +(last_access + precomputed.first_row) * (1 - rw') * (tag' - constants.MEM_TAG_FF) = 0; |
| 159 | + |
| 160 | +// Read-Write Consistency |
| 161 | +// Note that last_access == 0 on the first row with our trace generation. If the first |
| 162 | +// memory entry is a READ, then the following constraints will be satisifed because |
| 163 | +// value == 0 and tag == MEM_TAG_FF == 0 will be set on the first row which corresponds |
| 164 | +// to an initial read. |
| 165 | +#[READ_WRITE_CONSISTENCY_VALUE] |
| 166 | +(1 - last_access) * (1 - rw') * (value' - value) = 0; |
| 167 | +#[READ_WRITE_CONSISTENCY_TAG] |
| 168 | +(1 - last_access) * (1 - rw') * (tag' - tag) = 0; |
| 169 | + |
| 170 | + |
| 171 | +// We prove that sel_tag_is_ff == 1 <==> tag == MEM_TAG_FF |
| 172 | +pol TAG_FF_DIFF = tag - constants.MEM_TAG_FF; |
| 173 | +pol commit tag_ff_diff_inv; |
| 174 | +#[TAG_IS_FF] |
| 175 | +sel * (TAG_FF_DIFF * (sel_tag_is_ff * (1 - tag_ff_diff_inv) + tag_ff_diff_inv) + sel_tag_is_ff - 1) = 0; |
| 176 | + |
| 177 | +// Boolean by definition. |
| 178 | +#[SEL_RNG_WRITE] |
| 179 | +sel_rng_write = rw * (1 - sel_tag_is_ff); |
58 | 180 |
|
59 |
| -sel * (sel - 1) = 0; |
60 |
| -rw * (1 - rw) = 0; |
| 181 | +// Retrieve the number of bits for the range check |
| 182 | +#[TAG_MAX_BITS] |
| 183 | +sel_rng_write { tag, max_bits } |
| 184 | +in |
| 185 | +precomputed.sel_tag_parameters { precomputed.clk, precomputed.tag_max_bits }; |
61 | 186 |
|
62 |
| -// TODO: consider tag-value consistency checking. |
63 |
| -// TODO: consider address range checking. |
| 187 | +// Range check for the tagged value validation |
| 188 | +#[RANGE_CHECK_WRITE_TAGGED_VALUE] |
| 189 | +sel_rng_write {value, max_bits} |
| 190 | +in |
| 191 | +range_check.sel { range_check.value, range_check.rng_chk_bits }; |
0 commit comments