Skip to content

Commit

Permalink
feat!: make instruction read_io take an argument in range 1..=5
Browse files Browse the repository at this point in the history
BREAKING CHANGE: instruction `read_io` takes an argument
  • Loading branch information
jan-ferdinand committed Nov 7, 2023
2 parents 067d005 + fd77762 commit e138f0a
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 129 deletions.
2 changes: 2 additions & 0 deletions triton-vm/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub enum InstructionError {
VectorAssertionFailed(usize, u32, OpStackElement, BFieldElement, BFieldElement),
IllegalPop(usize),
IllegalDivine(usize),
IllegalReadIo(usize),
SwapST0,
InverseOfZero,
DivisionByZero,
Expand Down Expand Up @@ -48,6 +49,7 @@ impl Display for InstructionError {
}
IllegalPop(st) => write!(f, "must pop at least 1, at most 5 elements, not {st}"),
IllegalDivine(st) => write!(f, "must divine at least 1, at most 5 elements, not {st}"),
IllegalReadIo(st) => write!(f, "must read_io at least 1, at most 5 elements, not {st}"),
SwapST0 => write!(f, "Cannot swap stack element 0 with itself"),
InverseOfZero => write!(f, "0 does not have a multiplicative inverse"),
DivisionByZero => write!(f, "Division by 0 is impossible"),
Expand Down
15 changes: 7 additions & 8 deletions triton-vm/src/example_programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn fibonacci_sequence() -> Program {
// initialize stack: ⊥ 0 1 i
push 0
push 1
read_io
read_io 1

// is any looping necessary?
dup 0
Expand Down Expand Up @@ -51,8 +51,7 @@ fn fibonacci_sequence() -> Program {

fn greatest_common_divisor() -> Program {
triton_program!(
read_io // _ a
read_io // _ a b
read_io 2 // _ a b
dup 1 // _ a b a
dup 1 // _ a b a b
lt // _ a b b<a
Expand Down Expand Up @@ -113,12 +112,12 @@ fn program_with_many_u32_instructions() -> Program {
/// - output: Result<(), VMFail>
fn merkle_tree_authentication_path_verify() -> Program {
triton_program!(
read_io // number of authentication paths to test
read_io 1 // number of authentication paths to test
// stack: [num]
mt_ap_verify: // proper program starts here
push 0 swap 1 write_mem pop 1 // store number of APs at RAM address 0
// stack: []
read_io read_io read_io read_io read_io // read Merkle root
read_io 5 // read Merkle root
// stack: [r4 r3 r2 r1 r0]
call check_aps
pop 5 // leave clean stack: Merkle root
Expand Down Expand Up @@ -148,8 +147,8 @@ fn merkle_tree_authentication_path_verify() -> Program {
// stack before: [*]
// stack after: [* idx l4 l3 l2 l1 l0]
get_idx_and_leaf:
read_io // read node index
read_io read_io read_io read_io read_io // read leaf's value
read_io 1 // read node index
read_io 5 // read leaf's value
return

// subroutine: go up tree
Expand Down Expand Up @@ -228,7 +227,7 @@ fn verify_sudoku() -> Program {

// Applies the mapping from legal Sudoku digits to distinct primes.
read1: // _
read_io // _ d
read_io 1 // _ d
read_mem // _ d p
swap 1 // _ p d
pop 1 // _ p
Expand Down
20 changes: 12 additions & 8 deletions triton-vm/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ pub enum AnInstruction<Dest: PartialEq + Default> {
XbMul,

// Read/write
ReadIo,
ReadIo(OpStackElement),
WriteIo,
}

Expand Down Expand Up @@ -192,7 +192,7 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
XxMul => 74,
XInvert => 80,
XbMul => 82,
ReadIo => 88,
ReadIo(_) => 41,
WriteIo => 90,
}
}
Expand Down Expand Up @@ -235,7 +235,7 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
XxMul => "xxmul",
XInvert => "xinvert",
XbMul => "xbmul",
ReadIo => "read_io",
ReadIo(_) => "read_io",
WriteIo => "write_io",
}
}
Expand All @@ -250,6 +250,7 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
Divine(_) => 2,
Dup(_) | Swap(_) => 2,
Call(_) => 2,
ReadIo(_) => 2,
_ => 1,
}
}
Expand Down Expand Up @@ -304,7 +305,7 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
XxMul => XxMul,
XInvert => XInvert,
XbMul => XbMul,
ReadIo => ReadIo,
ReadIo(x) => ReadIo(*x),
WriteIo => WriteIo,
}
}
Expand Down Expand Up @@ -359,7 +360,7 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
XxMul => -3,
XInvert => 0,
XbMul => -1,
ReadIo => 1,
ReadIo(n) => n.index() as i32,
WriteIo => -1,
}
}
Expand All @@ -377,6 +378,7 @@ impl<Dest: PartialEq + Default> AnInstruction<Dest> {
Pop(st) => *st < ST1 || ST5 < *st,
Divine(st) => *st < ST1 || ST5 < *st,
Swap(ST0) => true,
ReadIo(st) => *st < ST1 || ST5 < *st,
_ => false,
}
}
Expand All @@ -387,7 +389,7 @@ impl<Dest: Display + PartialEq + Default> Display for AnInstruction<Dest> {
write!(f, "{}", self.name())?;
match self {
Push(arg) => write!(f, " {arg}"),
Pop(arg) | Divine(arg) | Dup(arg) | Swap(arg) => write!(f, " {arg}"),
Pop(arg) | Divine(arg) | Dup(arg) | Swap(arg) | ReadIo(arg) => write!(f, " {arg}"),
Call(arg) => write!(f, " {arg}"),
_ => Ok(()),
}
Expand All @@ -399,7 +401,7 @@ impl Instruction {
pub fn arg(&self) -> Option<BFieldElement> {
match self {
Push(arg) | Call(arg) => Some(*arg),
Pop(arg) | Divine(arg) | Dup(arg) | Swap(arg) => Some(arg.into()),
Pop(arg) | Divine(arg) | Dup(arg) | Swap(arg) | ReadIo(arg) => Some(arg.into()),
_ => None,
}
}
Expand Down Expand Up @@ -429,6 +431,7 @@ impl Instruction {
Divine(_) => Some(Divine(stack_element)),
Dup(_) => Some(Dup(stack_element)),
Swap(_) => Some(Swap(stack_element)),
ReadIo(_) => Some(ReadIo(stack_element)),
_ => None,
};
if new_instruction?.has_illegal_argument() {
Expand Down Expand Up @@ -514,7 +517,7 @@ const fn all_instructions_without_args() -> [AnInstruction<BFieldElement>; Instr
XxMul,
XInvert,
XbMul,
ReadIo,
ReadIo(ST0),
WriteIo,
]
}
Expand Down Expand Up @@ -629,6 +632,7 @@ mod tests {
Pop(ST0) => Pop(ST1),
Divine(ST0) => Divine(ST1),
Swap(ST0) => Swap(ST1),
ReadIo(ST0) => ReadIo(ST1),
_ => self,
}
}
Expand Down
25 changes: 16 additions & 9 deletions triton-vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
//! ```
//! # use triton_vm::*;
//! let factorial_program = triton_program!(
//! read_io // n
//! read_io 1 // n
//! push 1 // n 1
//! call factorial // 0 n!
//! write_io // 0
Expand Down Expand Up @@ -82,7 +82,7 @@
//! ```
//! # use triton_vm::*;
//! let sum_of_squares_program = triton_program!(
//! read_io // n
//! read_io 1 // n
//! call sum_of_squares_secret_in // n sum_1
//! call sum_of_squares_ram // n sum_1 sum_2
//! add // n sum_1+sum_2
Expand Down Expand Up @@ -168,7 +168,7 @@ pub mod vm;
/// ```
/// # use triton_vm::triton_program;
/// let program = triton_program!(
/// read_io push 5 mul
/// read_io 1 push 5 mul
/// call check_eq_15
/// push 1 write_io
/// halt
Expand Down Expand Up @@ -258,12 +258,12 @@ macro_rules! triton_program {
/// ```
/// # use triton_vm::triton_asm;
/// # use triton_vm::instruction::LabelledInstruction;
/// # use triton_vm::instruction::AnInstruction::ReadIo;
/// let instructions = triton_asm![read_io; 3];
/// # use triton_vm::instruction::AnInstruction::SpongeAbsorb;
/// let instructions = triton_asm![sponge_absorb; 3];
/// assert_eq!(3, instructions.len());
/// assert_eq!(LabelledInstruction::Instruction(ReadIo), instructions[0]);
/// assert_eq!(LabelledInstruction::Instruction(ReadIo), instructions[1]);
/// assert_eq!(LabelledInstruction::Instruction(ReadIo), instructions[2]);
/// assert_eq!(LabelledInstruction::Instruction(SpongeAbsorb), instructions[0]);
/// assert_eq!(LabelledInstruction::Instruction(SpongeAbsorb), instructions[1]);
/// assert_eq!(LabelledInstruction::Instruction(SpongeAbsorb), instructions[2]);
/// ```
///
/// Inserting substring of labelled instructions:
Expand Down Expand Up @@ -341,6 +341,7 @@ macro_rules! triton_asm {
[dup $arg:literal; $num:expr] => { vec![ $crate::triton_instr!(dup $arg); $num ] };
[swap $arg:literal; $num:expr] => { vec![ $crate::triton_instr!(swap $arg); $num ] };
[call $arg:ident; $num:expr] => { vec![ $crate::triton_instr!(call $arg); $num ] };
[read_io $arg:literal; $num:expr] => { vec![ $crate::triton_instr!(read_io $arg); $num ] };
[$instr:ident; $num:expr] => { vec![ $crate::triton_instr!($instr); $num ] };

// entry point
Expand Down Expand Up @@ -400,6 +401,12 @@ macro_rules! triton_instr {
let instruction = $crate::instruction::AnInstruction::<String>::Call(argument);
$crate::instruction::LabelledInstruction::Instruction(instruction)
}};
(read_io $arg:literal) => {{
assert!(1_u32 <= $arg && $arg <= 5, "`read_io {}` is illegal.", $arg);
let argument: $crate::op_stack::OpStackElement = u32::try_into($arg).unwrap();
let instruction = $crate::instruction::AnInstruction::<String>::ReadIo(argument);
$crate::instruction::LabelledInstruction::Instruction(instruction)
}};
($instr:ident) => {{
let (_, instructions) = $crate::parser::tokenize(stringify!($instr)).unwrap();
instructions[0].to_labelled_instruction()
Expand Down Expand Up @@ -548,7 +555,7 @@ mod tests {
push 03612858832443241113
push 12064501419749299924
assert_vector
read_io read_io read_io read_io read_io
read_io 5
halt
);

Expand Down
36 changes: 29 additions & 7 deletions triton-vm/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ fn an_instruction(s: &str) -> ParseResult<AnInstruction<String>> {
));

// Read/write
let read_io = instruction("read_io", ReadIo);
let read_io = read_io_instruction();
let write_io = instruction("write_io", WriteIo);

let read_write = alt((read_io, write_io));
Expand Down Expand Up @@ -408,6 +408,21 @@ fn call_instruction<'a>() -> impl Fn(&'a str) -> ParseResult<AnInstruction<Strin
}
}

fn read_io_instruction() -> impl Fn(&str) -> ParseResult<AnInstruction<String>> {
move |s: &str| {
let (s, _) = token1("read_io")(s)?; // require space after instruction name
let (s, stack_register) = stack_register(s)?;
let (s, _) = comment_or_whitespace1(s)?;

let instruction = ReadIo(stack_register);
if instruction.has_illegal_argument() {
return cut(context("illegal argument for instruction `read_io`", fail))(s);
}

Ok((s, instruction))
}
}

fn field_element(s_orig: &str) -> ParseResult<BFieldElement> {
let (s, negative) = opt(token0("-"))(s_orig)?;
let (s, n) = digit1(s)?;
Expand Down Expand Up @@ -639,15 +654,17 @@ pub(crate) mod tests {
fn instruction_gen(labels: &mut Vec<String>) -> Vec<String> {
let mut rng = thread_rng();

let difficult_instructions = vec!["pop", "push", "divine", "dup", "swap", "skiz", "call"];
let difficult_instructions = vec![
"pop", "push", "divine", "dup", "swap", "skiz", "call", "read_io",
];
let simple_instructions = ALL_INSTRUCTION_NAMES
.into_iter()
.filter(|name| !difficult_instructions.contains(name))
.collect_vec();

let generators = [vec!["simple"], difficult_instructions].concat();
// Test difficult instructions more frequently.
let weights = vec![simple_instructions.len(), 2, 2, 2, 6, 6, 2, 10];
let weights = vec![simple_instructions.len(), 2, 2, 2, 6, 6, 2, 10, 2];

assert_eq!(
generators.len(),
Expand Down Expand Up @@ -680,12 +697,12 @@ pub(crate) mod tests {
}

"dup" => {
let arg: usize = rng.gen_range(0..15);
let arg: usize = rng.gen_range(0..16);
vec!["dup".to_string(), format!("{arg}")]
}

"swap" => {
let arg: usize = rng.gen_range(1..15);
let arg: usize = rng.gen_range(1..16);
vec!["swap".to_string(), format!("{arg}")]
}

Expand All @@ -700,6 +717,11 @@ pub(crate) mod tests {
vec!["call".to_string(), some_label]
}

"read_io" => {
let arg: usize = rng.gen_range(1..=5);
vec!["read_io".to_string(), format!("{arg}")]
}

unknown => panic!("Unknown generator, {unknown}"),
}
}
Expand Down Expand Up @@ -1098,8 +1120,8 @@ pub(crate) mod tests {
let expected_instructions = vec![Instruction(Push(42_u64.into())); 3];
assert_eq!(expected_instructions, instructions);

let instructions = triton_asm![read_io; 15];
let expected_instructions = vec![Instruction(ReadIo); 15];
let instructions = triton_asm![read_io 2; 15];
let expected_instructions = vec![Instruction(ReadIo(ST2)); 15];
assert_eq!(expected_instructions, instructions);

let instructions = triton_asm![divine 3; DIGEST_LENGTH];
Expand Down
2 changes: 1 addition & 1 deletion triton-vm/src/stark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1414,7 +1414,7 @@ pub(crate) mod tests {
#[test]
fn check_io_terminals() {
let read_nop_program = triton_program!(
read_io read_io read_io nop nop write_io push 17 write_io halt
read_io 3 nop nop write_io push 17 write_io halt
);
let public_input = vec![3, 5, 7].into();
let (_, claim, _, master_ext_table, all_challenges) =
Expand Down
Loading

0 comments on commit e138f0a

Please sign in to comment.