Skip to content

Commit

Permalink
simplify the usage of Triton VM
Browse files Browse the repository at this point in the history
- don't expose BFieldElement
- include only a program's digest in the Claim, not the program itself
- implement hashing of programs
  • Loading branch information
jan-ferdinand committed Apr 21, 2023
1 parent e687c16 commit dda05e4
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 124 deletions.
16 changes: 13 additions & 3 deletions triton-opcodes/src/program.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use anyhow::Result;
use std::fmt::Display;
use std::io::Cursor;

use anyhow::Result;
use twenty_first::shared_math::b_field_element::BFieldElement;
use twenty_first::util_types::algebraic_hasher::Hashable;

use crate::instruction::{convert_labels, Instruction, LabelledInstruction};
use crate::parser::{parse, to_labelled};
use crate::instruction::convert_labels;
use crate::instruction::Instruction;
use crate::instruction::LabelledInstruction;
use crate::parser::parse;
use crate::parser::to_labelled;

#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Program {
Expand All @@ -27,6 +31,12 @@ impl Display for Program {
}
}

impl Hashable for Program {
fn to_sequence(&self) -> Vec<BFieldElement> {
self.to_bwords()
}
}

/// An `InstructionIter` loops the instructions of a `Program` by skipping duplicate placeholders.
pub struct InstructionIter {
cursor: Cursor<Vec<Instruction>>,
Expand Down
2 changes: 1 addition & 1 deletion triton-vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ default-features = false

[dependencies]
twenty-first = "0.19.3"
triton-opcodes = "0.19"
triton-opcodes = {path = "../triton-opcodes"}
triton-profiler = {path = "../triton-profiler"}
anyhow = "1.0"
bincode = "1.3"
Expand Down
14 changes: 9 additions & 5 deletions triton-vm/benches/prove_fib_100.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ use criterion::criterion_main;
use criterion::BenchmarkId;
use criterion::Criterion;
use triton_opcodes::program::Program;
use twenty_first::shared_math::b_field_element::BFieldElement;
use twenty_first::shared_math::tip5::Tip5;
use twenty_first::util_types::algebraic_hasher::AlgebraicHasher;

use triton_profiler::prof_start;
use triton_profiler::prof_stop;
use triton_profiler::triton_profiler::Report;
use triton_profiler::triton_profiler::TritonProfiler;

use triton_vm::proof::Claim;
use triton_vm::shared_tests::FIBONACCI_SEQUENCE;
use triton_vm::stark::Stark;
Expand All @@ -31,19 +34,20 @@ fn prove_fib_100(criterion: &mut Criterion) {
Ok(p) => p,
};
prof_stop!(maybe_profiler, "parse program");
let input = vec![100_u64.into()];
let input = vec![100];
let public_input = input.iter().map(|&e| BFieldElement::new(e)).collect();
prof_start!(maybe_profiler, "generate AET");
let (aet, output, err) = simulate(&program, input.clone(), vec![]);
let (aet, output, err) = simulate(&program, public_input, vec![]);
prof_stop!(maybe_profiler, "generate AET");
if let Some(error) = err {
panic!("The VM encountered the following problem: {error}");
}

let instructions = program.to_bwords();
let output = output.iter().map(|x| x.value()).collect();
let padded_height = MasterBaseTable::padded_height(&aet);
let claim = Claim {
input,
program: instructions,
program_digest: Tip5::hash(&program),
output,
padded_height,
};
Expand Down
8 changes: 5 additions & 3 deletions triton-vm/benches/prove_halt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ use criterion::criterion_group;
use criterion::criterion_main;
use criterion::Criterion;
use triton_opcodes::program::Program;
use twenty_first::shared_math::tip5::Tip5;
use twenty_first::util_types::algebraic_hasher::AlgebraicHasher;

use triton_profiler::prof_start;
use triton_profiler::prof_stop;
use triton_profiler::triton_profiler::Report;
use triton_profiler::triton_profiler::TritonProfiler;

use triton_vm::proof::Claim;
use triton_vm::shared_tests::save_proof;
use triton_vm::stark::Stark;
Expand Down Expand Up @@ -35,12 +37,12 @@ fn prove_halt(_criterion: &mut Criterion) {
panic!("The VM encountered the following problem: {error}");
}

let code = program.to_bwords();
let output = output.into_iter().map(|x| x.value()).collect();
let cycle_count = aet.processor_trace.nrows();
let padded_height = MasterBaseTable::padded_height(&aet);
let claim = Claim {
input: vec![],
program: code,
program_digest: Tip5::hash(&program),
output,
padded_height,
};
Expand Down
13 changes: 8 additions & 5 deletions triton-vm/benches/verify_halt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ use criterion::criterion_group;
use criterion::criterion_main;
use criterion::BenchmarkId;
use criterion::Criterion;
use triton_opcodes::program::Program;
use twenty_first::shared_math::tip5::Tip5;
use twenty_first::util_types::algebraic_hasher::AlgebraicHasher;

use triton_profiler::triton_profiler::Report;
use triton_profiler::triton_profiler::TritonProfiler;

use triton_opcodes::program::Program;
use triton_vm::proof::Claim;
use triton_vm::shared_tests::load_proof;
use triton_vm::shared_tests::proof_file_exists;
Expand All @@ -28,7 +30,7 @@ fn verify_halt(criterion: &mut Criterion) {
Ok(p) => p,
};

let instructions = program.to_bwords();
let program_digest = Tip5::hash(&program);
let stark_parameters = StarkParameters::default();
let filename = "halt.tsp";
let mut maybe_cycle_count = None;
Expand All @@ -40,7 +42,7 @@ fn verify_halt(criterion: &mut Criterion) {
let padded_height = proof.padded_height();
let claim = Claim {
input: vec![],
program: instructions,
program_digest,
output: vec![],
padded_height,
};
Expand All @@ -51,11 +53,12 @@ fn verify_halt(criterion: &mut Criterion) {
if let Some(error) = err {
panic!("The VM encountered the following problem: {error}");
}
let output = output.iter().map(|x| x.value()).collect();
maybe_cycle_count = Some(aet.processor_trace.nrows());
let padded_height = MasterBaseTable::padded_height(&aet);
let claim = Claim {
input: vec![],
program: instructions,
program_digest,
output,
padded_height,
};
Expand Down
23 changes: 16 additions & 7 deletions triton-vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
//! state-of-the-art ZKPS.
use triton_opcodes::program::Program;
use twenty_first::shared_math::b_field_element::BFieldElement;
pub use twenty_first::shared_math::b_field_element::BFieldElement;
pub use twenty_first::shared_math::tip5::Digest;
use twenty_first::shared_math::tip5::Tip5;
use twenty_first::util_types::algebraic_hasher::AlgebraicHasher;

use crate::proof::Claim;
pub use crate::proof::Claim;
use crate::proof::Proof;
use crate::stark::Stark;
use crate::stark::StarkParameters;
Expand Down Expand Up @@ -51,11 +54,12 @@ pub fn prove(source_code: &str, public_input: &[u64], secret_input: &[u64]) -> (
"Secret {canonical_representation_error}"
);

let public_input = public_input
// Convert the public and secret inputs to BFieldElements.
let public_input_bfe = public_input
.iter()
.map(|&e| BFieldElement::new(e))
.collect::<Vec<_>>();
let secret_input = secret_input
let secret_input_bfe = secret_input
.iter()
.map(|&e| BFieldElement::new(e))
.collect::<Vec<_>>();
Expand All @@ -68,7 +72,7 @@ pub fn prove(source_code: &str, public_input: &[u64], secret_input: &[u64]) -> (
// - the (public) output of the program, and
// - an error, if the program crashes.
let (aet, public_output, maybe_error) =
vm::simulate(&program, public_input.clone(), secret_input);
vm::simulate(&program, public_input_bfe, secret_input_bfe);

// Check for VM crashes, for example due to failing `assert` instructions or an out-of-bounds
// instruction pointer. Crashes can occur if any of the two inputs does not conform to the
Expand All @@ -78,11 +82,16 @@ pub fn prove(source_code: &str, public_input: &[u64], secret_input: &[u64]) -> (
panic!("Execution error: {error}");
}

// Convert the public output to a vector of u64.
let public_output = public_output.iter().map(|e| e.value()).collect::<Vec<_>>();

// Hash the program to obtain its digest.

// Set up the claim that is to be proven. The claim contains all public information. The
// proof is zero-knowledge with respect to everything else.
let claim = Claim {
input: public_input,
program: program.to_bwords(),
input: public_input.to_vec(),
program_digest: Tip5::hash(&program),
output: public_output,
padded_height: MasterBaseTable::padded_height(&aet),
};
Expand Down
30 changes: 27 additions & 3 deletions triton-vm/src/proof.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,45 @@
use serde::Deserialize;
use serde::Serialize;
use twenty_first::shared_math::b_field_element::BFieldElement;
use twenty_first::shared_math::tip5::Digest;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Proof(pub Vec<BFieldElement>);

/// Contains the necessary cryptographic information to verify a computation.
impl Proof {
pub fn padded_height(&self) -> usize {
// FIXME: This is very brittle.
self.0[1].value() as usize
}
}

/// Contains all the public information of a verifiably correct computation.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Claim {
pub input: Vec<BFieldElement>,
pub program: Vec<BFieldElement>,
pub output: Vec<BFieldElement>,
/// The public input to the computation.
pub input: Vec<u64>,

/// The hash digest of the program that was executed. The hash function in use is Tip5.
pub program_digest: Digest,

/// The public output of the computation.
pub output: Vec<u64>,

/// An upper bound on the length of the computation.
pub padded_height: usize,
}

impl Claim {
/// The public input as `BFieldElements`.
/// If u64s are needed, use field `input`.
pub fn public_input(&self) -> Vec<BFieldElement> {
self.input.iter().map(|&x| BFieldElement::new(x)).collect()
}

/// The public output as `BFieldElements`.
/// If u64s are needed, use field `output`.
pub fn public_output(&self) -> Vec<BFieldElement> {
self.output.iter().map(|&x| BFieldElement::new(x)).collect()
}
}
44 changes: 32 additions & 12 deletions triton-vm/src/shared_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ use std::path::Path;
use anyhow::Error;
use anyhow::Result;
use triton_opcodes::program::Program;
use twenty_first::shared_math::b_field_element::BFieldElement;
use twenty_first::shared_math::tip5::Tip5;
use twenty_first::util_types::algebraic_hasher::AlgebraicHasher;

use triton_profiler::prof_start;
use triton_profiler::prof_stop;
use triton_profiler::triton_profiler::TritonProfiler;
use twenty_first::shared_math::b_field_element::BFieldElement;

use crate::proof::Claim;
use crate::proof::Proof;
Expand All @@ -22,28 +25,34 @@ use crate::vm::AlgebraicExecutionTrace;

pub fn parse_setup_simulate(
code: &str,
input_symbols: Vec<BFieldElement>,
secret_input_symbols: Vec<BFieldElement>,
input_symbols: Vec<u64>,
secret_input_symbols: Vec<u64>,
maybe_profiler: &mut Option<TritonProfiler>,
) -> (AlgebraicExecutionTrace, Vec<BFieldElement>) {
) -> (AlgebraicExecutionTrace, Vec<u64>) {
let program = Program::from_code(code);

let program = program.expect("Program must parse.");
let public_input = input_symbols.into_iter().map(BFieldElement::new).collect();
let secret_input = secret_input_symbols
.into_iter()
.map(BFieldElement::new)
.collect();

prof_start!(maybe_profiler, "simulate");
let (aet, stdout, err) = simulate(&program, input_symbols, secret_input_symbols);
let (aet, stdout, err) = simulate(&program, public_input, secret_input);
if let Some(error) = err {
panic!("The VM encountered the following problem: {error}");
}
prof_stop!(maybe_profiler, "simulate");

let stdout = stdout.into_iter().map(|e| e.value()).collect();
(aet, stdout)
}

pub fn parse_simulate_prove(
code: &str,
input_symbols: Vec<BFieldElement>,
secret_input_symbols: Vec<BFieldElement>,
input_symbols: Vec<u64>,
secret_input_symbols: Vec<u64>,
maybe_profiler: &mut Option<TritonProfiler>,
) -> (Stark, Proof) {
let (aet, output_symbols) = parse_setup_simulate(
Expand All @@ -56,7 +65,7 @@ pub fn parse_simulate_prove(
let padded_height = MasterBaseTable::padded_height(&aet);
let claim = Claim {
input: input_symbols,
program: aet.program.to_bwords(),
program_digest: Tip5::hash(&aet.program),
output: output_symbols,
padded_height,
};
Expand All @@ -75,8 +84,8 @@ pub fn parse_simulate_prove(
/// Source code and associated input. Primarily for testing of the VM's instructions.
pub struct SourceCodeAndInput {
pub source_code: String,
pub input: Vec<BFieldElement>,
pub secret_input: Vec<BFieldElement>,
pub input: Vec<u64>,
pub secret_input: Vec<u64>,
}

impl SourceCodeAndInput {
Expand All @@ -88,10 +97,21 @@ impl SourceCodeAndInput {
}
}

pub fn public_input(&self) -> Vec<BFieldElement> {
self.input.iter().map(|&x| BFieldElement::new(x)).collect()
}

pub fn secret_input(&self) -> Vec<BFieldElement> {
self.secret_input
.iter()
.map(|&x| BFieldElement::new(x))
.collect()
}

#[deprecated(since = "0.19.0", note = "use `simulate` instead")]
pub fn run(&self) -> Vec<BFieldElement> {
let program = Program::from_code(&self.source_code).expect("Could not load source code");
let (_, output, err) = simulate(&program, self.input.clone(), self.secret_input.clone());
let (_, output, err) = simulate(&program, self.public_input(), self.secret_input());
if let Some(e) = err {
panic!("Running the program failed: {e}")
}
Expand All @@ -100,7 +120,7 @@ impl SourceCodeAndInput {

pub fn simulate(&self) -> (AlgebraicExecutionTrace, Vec<BFieldElement>, Option<Error>) {
let program = Program::from_code(&self.source_code).expect("Could not load source code.");
simulate(&program, self.input.clone(), self.secret_input.clone())
simulate(&program, self.public_input(), self.secret_input())
}
}

Expand Down
Loading

0 comments on commit dda05e4

Please sign in to comment.