Skip to content

Commit 7b63e76

Browse files
committed
feat: Introduce instructions pick and place
These two new instructions simplify manipulation of the operational stack. Instruction `pick` + `i` moves the indicated stack element to the top of the stack. Instruction `place` + `i` is its dual, moving the top of the stack to the indicated position.
1 parent c683170 commit 7b63e76

File tree

11 files changed

+307
-19
lines changed

11 files changed

+307
-19
lines changed

specification/src/arithmetization-overview.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
| [CascadeTable](cascade-table.md) | 6 | 2 | 12 |
1616
| [LookupTable](lookup-table.md) | 4 | 2 | 10 |
1717
| [U32Table](u32-table.md) | 10 | 1 | 13 |
18-
| DegreeLowering | 212 | 36 | 320 |
18+
| DegreeLowering | 214 | 36 | 322 |
1919
| Randomizers | 0 | 1 | 3 |
20-
| **TOTAL** | **361** | **86** | **619** |
20+
| **TOTAL** | **363** | **86** | **621** |
2121
<!-- auto-gen info stop table_overview -->
2222

2323
## Constraints
@@ -50,7 +50,7 @@ After automatically lowering degree to 4:
5050
| table name | #initial | #consistency | #transition | #terminal |
5151
|:-----------------------------------------------|---------:|-------------:|------------:|----------:|
5252
| [ProgramTable](program-table.md) | 6 | 4 | 10 | 2 |
53-
| [ProcessorTable](processor-table.md) | 31 | 10 | 227 | 1 |
53+
| [ProcessorTable](processor-table.md) | 31 | 10 | 229 | 1 |
5454
| [OpStackTable](operational-stack-table.md) | 3 | 0 | 5 | 0 |
5555
| [RamTable](random-access-memory-table.md) | 7 | 0 | 13 | 1 |
5656
| [JumpStackTable](jump-stack-table.md) | 6 | 0 | 6 | 0 |
@@ -59,7 +59,7 @@ After automatically lowering degree to 4:
5959
| [LookupTable](lookup-table.md) | 3 | 1 | 4 | 1 |
6060
| [U32Table](u32-table.md) | 1 | 26 | 34 | 2 |
6161
| [Grand Cross-Table Argument](table-linking.md) | 0 | 0 | 0 | 14 |
62-
| **TOTAL** | **81** | **94** | **386** | **23** |
62+
| **TOTAL** | **81** | **94** | **388** | **23** |
6363
<!-- auto-gen info stop constraints_overview -->
6464

6565

@@ -71,5 +71,5 @@ In order to gauge the runtime cost for this step, the following table provides e
7171
<!-- auto-gen info start tasm_air_evaluation_cost -->
7272
| Processor | Op Stack | RAM |
7373
|----------:|---------:|------:|
74-
| 35689 | 66327 | 23592 |
74+
| 38237 | 71243 | 25503 |
7575
<!-- auto-gen info stop tasm_air_evaluation_cost -->

specification/src/instruction-groups.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ A summary of all instructions and which groups they are part of is given in the
4040
| `pop` + `n` | x | x | x | x | | | x | | | | | | | | x |
4141
| `push` + `a` | | | x | x | | | x | x | | | | | | | |
4242
| `divine` + `n` | x | x | x | x | | | x | | x | | | | | | |
43+
| `pick` + `i` | x | | x | x | | | x | | | x | | | | | |
44+
| `place` + `i` | x | | x | x | | | x | | | x | | | | | |
4345
| `dup` + `i` | x | | x | x | | | x | x | | | | | | | |
4446
| `swap` + `i` | x | | x | x | | | x | | | x | | | | | |
4547
| `nop` | | | x | x | | x | | | | x | 0 | x | | | |
@@ -86,7 +88,7 @@ In this and the following sections, a register marked with a `'` refers to the n
8688
For example, `st0' = st0 + 2` means that stack register `st0` is incremented by 2.
8789
An alternative view for the same concept is that registers marked with `'` are those of the next row in the table.
8890

89-
For instructions like `dup i`, `swap i`, `pop n`, _et cetera_, it is beneficial to have polynomials that evaluate to 1 if the instruction's argument is a specific value, and to 0 otherwise.
91+
For instructions like `pick`, `place`, `dup`, `swap`, `pop`, _et cetera_, it is beneficial to have polynomials that evaluate to 1 if the instruction's argument is a specific value, and to 0 otherwise.
9092
This allows indicating which registers are constraint, and in which way they are, depending on the argument.
9193
This is the purpose of the _indicator polynomials_ `ind_i`.
9294
Evaluated on the binary decomposition of `i`, they show the behavior described above.

specification/src/instruction-specific-transition-constraints.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,30 @@ In addition to its [instruction groups](instruction-groups.md), this instruction
2020

2121
This instruction is fully constrained by its [instruction groups](instruction-groups.md)
2222

23+
## Instruction `pick` + `i`
24+
25+
This instruction makes use of [indicator polynomials](instruction-groups.md#indicator-polynomials-ind_ihv3-hv2-hv1-hv0).
26+
In addition to its [instruction groups](instruction-groups.md), this instruction has the following constraints.
27+
28+
### Description
29+
30+
For 0 ⩽ `i` < 16:
31+
1. Stack element `i` is moved to the top.
32+
1. For 0 ⩽ `j` < `i`: stack element `j` is shifted down by 1.
33+
1. For `j` > `i`: stack element `j` remains unchanged.
34+
35+
## Instruction `place` + `i`
36+
37+
This instruction makes use of [indicator polynomials](instruction-groups.md#indicator-polynomials-ind_ihv3-hv2-hv1-hv0).
38+
In addition to its [instruction groups](instruction-groups.md), this instruction has the following constraints.
39+
40+
### Description
41+
42+
For 0 ⩽ `i` < 16:
43+
1. Stack element 0 is moved to position `i`.
44+
1. For 0 ⩽ `j` < `i`: stack element `j` is shifted up by 1.
45+
1. For `j` > `i`: stack element `j` remains unchanged.
46+
2347
## Instruction `dup` + `i`
2448

2549
This instruction makes use of [indicator polynomials](instruction-groups.md#indicator-polynomials-ind_ihv3-hv2-hv1-hv0).

specification/src/instructions.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ The third property allows efficient arithmetization of the running product for t
2525
| `pop` + `n` | 3 | e.g., `_ c b a` | e.g., `_` | Pops the `n` top elements from the stack. 1 ⩽ `n` ⩽ 5 |
2626
| `push` + `a` | 1 | `_` | `_ a` | Pushes `a` onto the stack. |
2727
| `divine` + `n` | 9 | e.g., `_` | e.g., `_ b a` | Pushes `n` non-deterministic elements `a` to the stack. Interface for secret input. 1 ⩽ `n` ⩽ 5 |
28-
| `dup` + `i` | 17 | e.g., `_ e d c b a` | e.g., `_ e d c b a d` | Duplicates the element `i` positions away from the top. 0 ⩽ `i` < 16 |
29-
| `swap` + `i` | 25 | e.g., `_ e d c b a` | e.g., `_ e a c b d` | Swaps the `i`th stack element with the top of the stack. 0 ⩽ `i` < 16 |
28+
| `pick` + `i` | 17 | e.g., `_ d x c b a` | e.g., `_ d c b a x` | Moves the element indicated by `i` to the top of the stack. 0 ⩽ `i` < 16 |
29+
| `place` + `i` | 25 | e.g., `_ d c b a x` | e.g., `_ d x c b a` | Moves the top of the stack to the indicated position `i`. 0 ⩽ `i` < 16 |
30+
| `dup` + `i` | 33 | e.g., `_ e d c b a` | e.g., `_ e d c b a d` | Duplicates the element `i` positions away from the top. 0 ⩽ `i` < 16 |
31+
| `swap` + `i` | 41 | e.g., `_ e d c b a` | e.g., `_ e a c b d` | Swaps the `i`th stack element with the top of the stack. 0 ⩽ `i` < 16 |
3032

3133
Instruction `divine n` (together with [`merkle_step`](#many-in-one)) make Triton a virtual machine that can execute non-deterministic programs.
3234
As programs go, this concept is somewhat unusual and benefits from additional explanation.
@@ -46,7 +48,7 @@ the divined values were supplied as and are read from secret input.
4648
| `halt` | 0 | `_` | `_` | `ip` | `ip+1` | `_` | `_` | Solves the halting problem (if the instruction is reached). Indicates graceful shutdown of the VM. |
4749
| `nop` | 8 | `_` | `_` | `ip` | `ip+1` | `_` | `_` | Do nothing |
4850
| `skiz` | 2 | `_ a` | `_` | `ip` | `ip+s` | `_` | `_` | Skip next instruction if `a` is zero. `s` ∈ {1, 2, 3} depends on `a` and whether the next instruction takes an argument. |
49-
| `call` + `d` | 33 | `_` | `_` | `ip` | `d` | `_` | `_ (ip+2, d)` | Push `(ip+2,d)` to the jump stack, and jump to absolute address `d` |
51+
| `call` + `d` | 49 | `_` | `_` | `ip` | `d` | `_` | `_ (ip+2, d)` | Push `(ip+2,d)` to the jump stack, and jump to absolute address `d` |
5052
| `return` | 16 | `_` | `_` | `ip` | `o` | `_ (o, d)` | `_` | Pop one pair off the jump stack and jump to that pair's return address (which is the first element). |
5153
| `recurse` | 24 | `_` | `_` | `ip` | `d` | `_ (o, d)` | `_ (o, d)` | Peek at the top pair of the jump stack and jump to that pair's destination address (which is the second element). |
5254
| `recurse_or_return` | 32 | `_ b a .....` | `_ b a .....` | `ip` | `d` or `o` | `_ (o, d)` | `_ (o, d)` or `_` | Like `recurse` if `st5 = a != b = st6`, like `return` if `a == b`. See also extended description below. |
@@ -64,7 +66,7 @@ The instruction is designed to facilitate loops using pointer equality as termin
6466

6567
| Instruction | Opcode | old op stack | new op stack | old RAM | new RAM | Description |
6668
|:------------------|-------:|:---------------------|:-----------------------|:--------------------|:--------------------|:---------------------------------------------------------------------------------------------------------------------------------------------|
67-
| `read_mem` + `n` | 41 | e.g., `_ p+2` | e.g., `_ v2 v1 v0 p-1` | [p: v0, p+1, v1, …] | [p: v0, p+1, v1, …] | Reads consecutive values `vi` from RAM at address `p` and puts them onto the op stack. Decrements RAM pointer (`st0`) by `n`. 1 ⩽ `n` ⩽ 5 |
69+
| `read_mem` + `n` | 57 | e.g., `_ p+2` | e.g., `_ v2 v1 v0 p-1` | [p: v0, p+1, v1, …] | [p: v0, p+1, v1, …] | Reads consecutive values `vi` from RAM at address `p` and puts them onto the op stack. Decrements RAM pointer (`st0`) by `n`. 1 ⩽ `n` ⩽ 5 |
6870
| `write_mem` + `n` | 11 | e.g., `_ v2 v1 v0 p` | e.g., `_ p+3` | [] | [p: v0, p+1, v1, …] | Writes op stack's `n` top-most values `vi` to RAM at the address `p+i`, popping the `vi`. Increments RAM pointer (`st0`) by `n`. 1 ⩽ `n` ⩽ 5 |
6971

7072
For the benefit of clarity, the effect of every possible argument is given below.
@@ -142,7 +144,7 @@ Triton VM cannot know the number of elements that will be absorbed.
142144

143145
| Instruction | Opcode | old op stack | new op stack | Description |
144146
|:-----------------|-------:|:----------------|:----------------|:-----------------------------------------------------------------------------------------|
145-
| `read_io` + `n` | 49 | e.g., `_` | e.g., `_ c b a` | Reads `n` B-Field elements from standard input and pushes them to the stack. 1 ⩽ `n` ⩽ 5 |
147+
| `read_io` + `n` | 65 | e.g., `_` | e.g., `_ c b a` | Reads `n` B-Field elements from standard input and pushes them to the stack. 1 ⩽ `n` ⩽ 5 |
146148
| `write_io` + `n` | 19 | e.g., `_ c b a` | e.g., `_` | Pops `n` elements from the stack and writes them to standard output. 1 ⩽ `n` ⩽ 5 |
147149

148150
## Many-In-One

triton-vm/src/instruction.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ pub enum AnInstruction<Dest: PartialEq + Default> {
160160
Pop(NumberOfWords),
161161
Push(BFieldElement),
162162
Divine(NumberOfWords),
163+
Pick(OpStackElement),
164+
Place(OpStackElement),
163165
Dup(OpStackElement),
164166
Swap(OpStackElement),
165167

@@ -224,17 +226,19 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
224226
Pop(_) => 3,
225227
Push(_) => 1,
226228
Divine(_) => 9,
227-
Dup(_) => 17,
228-
Swap(_) => 25,
229+
Pick(_) => 17,
230+
Place(_) => 25,
231+
Dup(_) => 33,
232+
Swap(_) => 41,
229233
Halt => 0,
230234
Nop => 8,
231235
Skiz => 2,
232-
Call(_) => 33,
236+
Call(_) => 49,
233237
Return => 16,
234238
Recurse => 24,
235239
RecurseOrReturn => 32,
236240
Assert => 10,
237-
ReadMem(_) => 41,
241+
ReadMem(_) => 57,
238242
WriteMem(_) => 11,
239243
Hash => 18,
240244
AssertVector => 26,
@@ -258,7 +262,7 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
258262
XxMul => 74,
259263
XInvert => 72,
260264
XbMul => 82,
261-
ReadIo(_) => 49,
265+
ReadIo(_) => 65,
262266
WriteIo(_) => 19,
263267
MerkleStep => 80,
264268
XxDotStep => 88,
@@ -271,6 +275,8 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
271275
Pop(_) => "pop",
272276
Push(_) => "push",
273277
Divine(_) => "divine",
278+
Pick(_) => "pick",
279+
Place(_) => "place",
274280
Dup(_) => "dup",
275281
Swap(_) => "swap",
276282
Halt => "halt",
@@ -321,6 +327,7 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
321327
match self {
322328
Pop(_) | Push(_) => 2,
323329
Divine(_) => 2,
330+
Pick(_) | Place(_) => 2,
324331
Dup(_) | Swap(_) => 2,
325332
Call(_) => 2,
326333
ReadMem(_) | WriteMem(_) => 2,
@@ -346,6 +353,8 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
346353
Pop(x) => Pop(*x),
347354
Push(x) => Push(*x),
348355
Divine(x) => Divine(*x),
356+
Pick(x) => Pick(*x),
357+
Place(x) => Place(*x),
349358
Dup(x) => Dup(*x),
350359
Swap(x) => Swap(*x),
351360
Halt => Halt,
@@ -393,6 +402,8 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
393402
Pop(n) => -(n.num_words() as i32),
394403
Push(_) => 1,
395404
Divine(n) => n.num_words() as i32,
405+
Pick(_) => 0,
406+
Place(_) => 0,
396407
Dup(_) => 1,
397408
Swap(_) => 0,
398409
Halt => 0,
@@ -450,6 +461,7 @@ impl<Dest: Display + PartialEq + Default> Display for AnInstruction<Dest> {
450461
match self {
451462
Push(arg) => write!(f, " {arg}"),
452463
Pop(arg) | Divine(arg) => write!(f, " {arg}"),
464+
Pick(arg) | Place(arg) => write!(f, " {arg}"),
453465
Dup(arg) | Swap(arg) => write!(f, " {arg}"),
454466
Call(arg) => write!(f, " {arg}"),
455467
ReadMem(arg) | WriteMem(arg) => write!(f, " {arg}"),
@@ -465,6 +477,7 @@ impl Instruction {
465477
match self {
466478
Push(arg) | Call(arg) => Some(*arg),
467479
Pop(arg) | Divine(arg) => Some(arg.into()),
480+
Pick(arg) | Place(arg) => Some(arg.into()),
468481
Dup(arg) | Swap(arg) => Some(arg.into()),
469482
ReadMem(arg) | WriteMem(arg) => Some(arg.into()),
470483
ReadIo(arg) | WriteIo(arg) => Some(arg.into()),
@@ -483,6 +496,8 @@ impl Instruction {
483496
Pop(_) => Pop(num_words?),
484497
Push(_) => Push(new_arg),
485498
Divine(_) => Divine(num_words?),
499+
Pick(_) => Pick(op_stack_element?),
500+
Place(_) => Place(op_stack_element?),
486501
Dup(_) => Dup(op_stack_element?),
487502
Swap(_) => Swap(op_stack_element?),
488503
Call(_) => Call(new_arg),
@@ -540,6 +555,8 @@ const fn all_instructions_without_args() -> [AnInstruction<BFieldElement>; Instr
540555
Pop(N1),
541556
Push(b_field_element::BFIELD_ZERO),
542557
Divine(N1),
558+
Pick(ST0),
559+
Place(ST0),
543560
Dup(ST0),
544561
Swap(ST0),
545562
Halt,

triton-vm/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ macro_rules! triton_asm {
400400
[pop $arg:literal; $num:expr] => { vec![ $crate::triton_instr!(pop $arg); $num ] };
401401
[push $arg:literal; $num:expr] => { vec![ $crate::triton_instr!(push $arg); $num ] };
402402
[divine $arg:literal; $num:expr] => { vec![ $crate::triton_instr!(divine $arg); $num ] };
403+
[pick $arg:literal; $num:expr] => { vec![ $crate::triton_instr!(pick $arg); $num ] };
404+
[place $arg:literal; $num:expr] => { vec![ $crate::triton_instr!(place $arg); $num ] };
403405
[dup $arg:literal; $num:expr] => { vec![ $crate::triton_instr!(dup $arg); $num ] };
404406
[swap $arg:literal; $num:expr] => { vec![ $crate::triton_instr!(swap $arg); $num ] };
405407
[call $arg:ident; $num:expr] => { vec![ $crate::triton_instr!(call $arg); $num ] };
@@ -448,6 +450,16 @@ macro_rules! triton_instr {
448450
let instruction = $crate::instruction::AnInstruction::<String>::Divine(argument);
449451
$crate::instruction::LabelledInstruction::Instruction(instruction)
450452
}};
453+
(pick $arg:literal) => {{
454+
let argument = $crate::op_stack::OpStackElement::try_from($arg).unwrap();
455+
let instruction = $crate::instruction::AnInstruction::<String>::Pick(argument);
456+
$crate::instruction::LabelledInstruction::Instruction(instruction)
457+
}};
458+
(place $arg:literal) => {{
459+
let argument = $crate::op_stack::OpStackElement::try_from($arg).unwrap();
460+
let instruction = $crate::instruction::AnInstruction::<String>::Place(argument);
461+
$crate::instruction::LabelledInstruction::Instruction(instruction)
462+
}};
451463
(dup $arg:literal) => {{
452464
let argument = $crate::op_stack::OpStackElement::try_from($arg).unwrap();
453465
let instruction = $crate::instruction::AnInstruction::<String>::Dup(argument);

0 commit comments

Comments
 (0)