Skip to content

Commit

Permalink
User-directed transcript-based RAM checking. (#176)
Browse files Browse the repository at this point in the history
* user-directed transcript-based RAM checking

when the `transcript` type qualifier is used.

* fix ram tests

* fmt & lint

* rm incomplete test
  • Loading branch information
alex-ozdemir authored Nov 3, 2023
1 parent c035529 commit 68b0b45
Show file tree
Hide file tree
Showing 18 changed files with 251 additions and 95 deletions.
10 changes: 10 additions & 0 deletions examples/ZoKrates/pf/mem/ann_transcript_const.zok
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const u32 N = 100
const u32 A = 100
const field[N] TABLE = [4, ...[5; N-1]]

def main(field[A] is) -> field:
field sum = 0
for u32 i in 0..A do
sum = sum + TABLE[is[i]]
endfor
return sum
2 changes: 1 addition & 1 deletion examples/ZoKrates/pf/mem/arr_of_str.zok
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ struct Pt {
field y
field z
}
const Pt [LEN] array = [Pt {x: 4, y: 5, z: 6}, ...[Pt {x: 0, y: 1, z: 2}; LEN - 1]]
const transcript Pt [LEN] array = [Pt {x: 4, y: 5, z: 6}, ...[Pt {x: 0, y: 1, z: 2}; LEN - 1]]

def main(private field[ACCESSES] idx) -> field:
field prod = 1
Expand Down
2 changes: 1 addition & 1 deletion examples/ZoKrates/pf/mem/two_level_ptr.zok
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const u32 LEN = 4
const u32 ACCESSES = 2

const field[LEN] array = [0, ...[100; LEN-1]]
const transcript field[LEN] array = [0, ...[100; LEN-1]]

def main(private field[ACCESSES] y) -> field:
field result = 0
Expand Down
2 changes: 1 addition & 1 deletion examples/ZoKrates/pf/mem/volatile.zok
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const u32 LEN = 8196
const field ACC = 10

def main(private field x, private field y, private bool b) -> field:
field[LEN] array = [0; LEN]
transcript field[LEN] array = [0; LEN]
for field i in 0..ACC do
cond_store(array, x+i, 1f, b)
endfor
Expand Down
2 changes: 1 addition & 1 deletion examples/ZoKrates/pf/mem/volatile_struct.zok
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ struct Pt {
}

def main(private field x, private field y, private bool b) -> field:
Pt [LEN] array = [Pt {x: 0, y: 0} ; LEN]
transcript Pt [LEN] array = [Pt {x: 0, y: 0} ; LEN]
for field i in 0..ACCESSES do
array[x+i] = if b then Pt{x : 1, y: i} else array[x+i] fi
endfor
Expand Down
18 changes: 6 additions & 12 deletions examples/circ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,18 +270,12 @@ fn main() {
opts.push(Opt::ConstantFold(Box::new([])));
opts.push(Opt::Obliv);
// The obliv elim pass produces more tuples, that must be eliminated
if options.circ.ram.enabled {
// Waksman can only route scalars, so tuple first!
if options.circ.ram.permutation == circ_opt::PermutationStrategy::Waksman {
opts.push(Opt::Tuple);
}
opts.push(Opt::PersistentRam);
opts.push(Opt::VolatileRam);
opts.push(Opt::SkolemizeChallenges);
opts.push(Opt::ScalarizeVars);
opts.push(Opt::ConstantFold(Box::new([])));
opts.push(Opt::Obliv);
}
opts.push(Opt::PersistentRam);
opts.push(Opt::VolatileRam);
opts.push(Opt::SkolemizeChallenges);
opts.push(Opt::ScalarizeVars);
opts.push(Opt::ConstantFold(Box::new([])));
opts.push(Opt::Obliv);
opts.push(Opt::LinearScan);
// The linear scan pass produces more tuples, that must be eliminated
opts.push(Opt::Tuple);
Expand Down
8 changes: 5 additions & 3 deletions scripts/ram_test.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,18 @@ function ram_test {
proof_impl=$2
ex_name=$1
rm -rf P V pi
$BIN --ram true $=3 $ex_name r1cs --action setup --proof-impl $proof_impl
$BIN $=3 $ex_name r1cs --action setup --proof-impl $proof_impl
$ZK_BIN --inputs $ex_name.pin --action prove --proof-impl $proof_impl
$ZK_BIN --inputs $ex_name.vin --action verify --proof-impl $proof_impl
rm -rf P V pi
}

ram_test ./examples/ZoKrates/pf/mem/two_level_ptr.zok groth16 "--ram-permutation waksman --ram-index sort --ram-range bit-split"
ram_test ./examples/ZoKrates/pf/mem/volatile.zok groth16 "--ram-permutation waksman --ram-index sort --ram-range bit-split"
ram_test ./examples/ZoKrates/pf/mem/volatile_struct.zok groth16 "--ram-permutation waksman --ram-index sort --ram-range bit-split"
ram_test ./examples/ZoKrates/pf/mem/arr_of_str.zok groth16 "--ram-permutation waksman --ram-index sort --ram-range bit-split"
# waksman is broken for non-scalar array values
# ram_test ./examples/ZoKrates/pf/mem/volatile_struct.zok groth16 "--ram-permutation waksman --ram-index sort --ram-range bit-split"
# waksman is broken for non-scalar array values
# ram_test ./examples/ZoKrates/pf/mem/arr_of_str.zok groth16 "--ram-permutation waksman --ram-index sort --ram-range bit-split"
ram_test ./examples/ZoKrates/pf/mem/two_level_ptr.zok mirage ""
ram_test ./examples/ZoKrates/pf/mem/volatile.zok mirage ""
ram_test ./examples/ZoKrates/pf/mem/volatile_struct.zok mirage ""
Expand Down
125 changes: 93 additions & 32 deletions src/front/zsharp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::front::proof::PROVER_ID;
use crate::ir::proof::ConstraintMetadata;
use crate::ir::term::*;

use log::{debug, trace, warn};
use log::{debug, info, trace, warn};
use rug::Integer;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
Expand Down Expand Up @@ -141,7 +141,11 @@ fn loc_store(struct_: T, loc: &[ZAccess], val: T) -> Result<T, String> {
enum ZVis {
Public,
Private(u8),
}

enum ArrayParamMetadata {
Committed,
Transcript,
}

impl<'ast> ZGen<'ast> {
Expand Down Expand Up @@ -685,12 +689,25 @@ impl<'ast> ZGen<'ast> {
for p in f.parameters.iter() {
let ty = self.type_(&p.ty);
debug!("Entry param: {}: {}", p.id.value, ty);
let md = self.interpret_array_md(&p.array_metadata);
let vis = self.interpret_visibility(&p.visibility);
if let ZVis::Committed = &vis {
persistent_arrays.push(p.id.value.clone());
let r = self.circ_declare_input(p.id.value.clone(), &ty, vis, None, false, &md);
let unwrapped = self.unwrap(r, &p.span);
if let Some(md_some) = md {
match md_some {
ArrayParamMetadata::Committed => {
info!(
"Input committed array of type {} in {:?}",
ty,
self.file_stack.borrow().last().unwrap()
);
persistent_arrays.push(p.id.value.clone());
}
ArrayParamMetadata::Transcript => {
self.mark_array_as_transcript(&p.id.value, unwrapped);
}
}
}
let r = self.circ_declare_input(p.id.value.clone(), &ty, vis, None, false);
self.unwrap(r, &p.span);
}
for s in &f.statements {
self.unwrap(self.stmt_impl_::<false>(s), s.span());
Expand Down Expand Up @@ -722,7 +739,14 @@ impl<'ast> ZGen<'ast> {
let name = "return".to_owned();
let ret_val = r.unwrap_term();
let ret_var_val = self
.circ_declare_input(name, ty, ZVis::Public, Some(ret_val.clone()), false)
.circ_declare_input(
name,
ty,
ZVis::Public,
Some(ret_val.clone()),
false,
&None,
)
.expect("circ_declare return");
let ret_eq = eq(ret_val, ret_var_val).unwrap().term;
let mut assertions = std::mem::take(&mut *self.assertions.borrow_mut());
Expand Down Expand Up @@ -772,13 +796,20 @@ impl<'ast> ZGen<'ast> {
}
}
}
fn interpret_array_md(
&self,
md: &Option<ast::ArrayParamMetadata<'ast>>,
) -> Option<ArrayParamMetadata> {
match md {
Some(ast::ArrayParamMetadata::Committed(_)) => Some(ArrayParamMetadata::Committed),
Some(ast::ArrayParamMetadata::Transcript(_)) => Some(ArrayParamMetadata::Transcript),
None => None,
}
}

fn interpret_visibility(&self, visibility: &Option<ast::Visibility<'ast>>) -> ZVis {
match visibility {
None | Some(ast::Visibility::Public(_)) => ZVis::Public,
Some(ast::Visibility::Committed(_)) => match self.mode {
Mode::Proof => ZVis::Committed,
_ => unimplemented!(),
},
Some(ast::Visibility::Private(private)) => match self.mode {
Mode::Proof | Mode::Opt | Mode::ProofOfHighValue(_) => {
if private.number.is_some() {
Expand Down Expand Up @@ -1230,7 +1261,16 @@ impl<'ast> ZGen<'ast> {
l.identifier.value.clone(),
decl_ty,
e,
)
)?;
let md = self.interpret_array_md(&l.array_metadata);
if let Some(ArrayParamMetadata::Transcript) = md {
let value = self
.circ_get_value(Loc::local(l.identifier.value.clone()))
.map_err(|e| format!("{e}"))?
.unwrap_term();
self.mark_array_as_transcript(&l.identifier.value, value);
}
Ok(())
}
}
} else {
Expand Down Expand Up @@ -1465,6 +1505,13 @@ impl<'ast> ZGen<'ast> {
);
}

if let Some(ast::ArrayParamMetadata::Transcript(_)) = &c.array_metadata {
if !value.type_().is_array() {
self.err(format!("Non-array transcript {}", &c.id.value), &c.span);
}
self.mark_array_as_transcript(&c.id.value, value.clone());
}

// insert into constant map
if self
.constants
Expand Down Expand Up @@ -1849,6 +1896,22 @@ impl<'ast> ZGen<'ast> {
}
}

fn mark_array_as_transcript(&self, name: &str, array: T) {
info!(
"Transcript array {} of type {} in {:?}",
name,
array.ty,
self.file_stack.borrow().last().unwrap()
);
self.circ
.borrow()
.cir_ctx()
.cs
.borrow_mut()
.ram_arrays
.insert(array.term);
}

/*** circify wrapper functions (hides RefCell) ***/

fn circ_enter_condition(&self, cond: Term) {
Expand Down Expand Up @@ -1894,32 +1957,30 @@ impl<'ast> ZGen<'ast> {
vis: ZVis,
precomputed_value: Option<T>,
mangle_name: bool,
md: &Option<ArrayParamMetadata>,
) -> Result<T, CircError> {
match vis {
ZVis::Public => {
self.circ
.borrow_mut()
.declare_input(name, ty, None, precomputed_value, mangle_name)
}
ZVis::Private(i) => self.circ.borrow_mut().declare_input(
if let Some(ArrayParamMetadata::Committed) = md {
let size = match ty {
Ty::Array(size, _) => *size,
_ => panic!(),
};
Ok(self.circ.borrow_mut().start_persistent_array(
&name,
size,
default_field(),
crate::front::proof::PROVER_ID,
))
} else {
self.circ.borrow_mut().declare_input(
name,
ty,
Some(i),
match vis {
ZVis::Public => None,
ZVis::Private(i) => Some(i),
},
precomputed_value,
mangle_name,
),
ZVis::Committed => {
let size = match ty {
Ty::Array(size, _) => *size,
_ => panic!(),
};
Ok(self.circ.borrow_mut().start_persistent_array(
&name,
size,
default_field(),
crate::front::proof::PROVER_ID,
))
}
)
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/front/zsharp/term.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ impl Ty {
_ => panic!("Not an array type: {:?}", self),
}
}
/// Is this an array?
pub fn is_array(&self) -> bool {
matches!(self, Self::Array(_, _) | Self::MutArray(_))
}
}

#[derive(Clone, Debug)]
Expand Down
12 changes: 11 additions & 1 deletion src/front/zsharp/zvisit/walkfns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,24 @@ pub fn walk_parameter<'ast, Z: ZVisitorMut<'ast>>(
visitor.visit_span(&mut param.span)
}

pub fn walk_array_param_metadata<'ast, Z: ZVisitorMut<'ast>>(
visitor: &mut Z,
vis: &mut ast::ArrayParamMetadata<'ast>,
) -> ZVisitorResult {
use ast::ArrayParamMetadata::*;
match vis {
Committed(x) => visitor.visit_array_committed(x),
Transcript(x) => visitor.visit_array_transcript(x),
}
}

pub fn walk_visibility<'ast, Z: ZVisitorMut<'ast>>(
visitor: &mut Z,
vis: &mut ast::Visibility<'ast>,
) -> ZVisitorResult {
use ast::Visibility::*;
match vis {
Public(pu) => visitor.visit_public_visibility(pu),
Committed(c) => visitor.visit_commited_visibility(c),
Private(pr) => visitor.visit_private_visibility(pr),
}
}
Expand Down
13 changes: 12 additions & 1 deletion src/front/zsharp/zvisit/zvmut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,18 @@ pub trait ZVisitorMut<'ast>: Sized {
Ok(())
}

fn visit_commited_visibility(&mut self, _c: &mut ast::CommittedVisibility) -> ZVisitorResult {
fn visit_array_param_metadata(
&mut self,
vis: &mut ast::ArrayParamMetadata<'ast>,
) -> ZVisitorResult {
walk_array_param_metadata(self, vis)
}

fn visit_array_committed(&mut self, _c: &mut ast::ArrayCommitted<'ast>) -> ZVisitorResult {
Ok(())
}

fn visit_array_transcript(&mut self, _c: &mut ast::ArrayTranscript<'ast>) -> ZVisitorResult {
Ok(())
}

Expand Down
Loading

0 comments on commit 68b0b45

Please sign in to comment.