1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00

Merge branch 'develop' into bigint-poc

This commit is contained in:
dark64 2023-06-13 12:36:52 +02:00
commit ce7708d7c6
33 changed files with 398 additions and 164 deletions

172
Cargo.lock generated
View file

@ -487,9 +487,9 @@ dependencies = [
[[package]]
name = "bellperson"
version = "0.24.1"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1a8623f815c0b1fd89efd9b5f4afbb937f91f51c1ebe3f6dda399c69fa938f3"
checksum = "93eaee4b4753554139ae52ecf0e8b8c128cbc561b32e1bfaa32f70cba8518c1f"
dependencies = [
"bincode 1.3.3",
"blake2s_simd 1.0.1",
@ -499,11 +499,11 @@ dependencies = [
"digest 0.10.6",
"ec-gpu",
"ec-gpu-gen",
"ff",
"group",
"ff 0.13.0",
"group 0.13.0",
"log",
"memmap2",
"pairing",
"pairing 0.23.0",
"rand 0.8.5",
"rand_core 0.6.4",
"rayon",
@ -695,15 +695,15 @@ dependencies = [
[[package]]
name = "blstrs"
version = "0.6.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ecb6f3a9429706971633edf4b84f922aba9d2e3a7d71bfb450337e64ccb7df0"
checksum = "33149fccb7f93271f0192614b884430cf274e880506bbd171cbc8918dcc95b14"
dependencies = [
"blst",
"byte-slice-cast",
"ff",
"group",
"pairing",
"ff 0.13.0",
"group 0.13.0",
"pairing 0.23.0",
"rand_core 0.6.4",
"serde",
"subtle 2.5.0",
@ -1137,16 +1137,16 @@ checksum = "bd63582de2b59ea1aa48d7c1941b5d87618d95484397521b3acdfa0e1e9f5e45"
[[package]]
name = "ec-gpu-gen"
version = "0.5.2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd09bf9d5313ad60379f70250590bccc10f7a04e2773062ac13255a37022584e"
checksum = "892df2aa20abec5b816e15d5d6383892ca142077708efa3067dd3ac44b75c664"
dependencies = [
"bitvec",
"crossbeam-channel 0.5.8",
"ec-gpu",
"execute",
"ff",
"group",
"ff 0.13.0",
"group 0.13.0",
"hex 0.4.3",
"log",
"num_cpus",
@ -1350,6 +1350,16 @@ name = "ff"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
dependencies = [
"rand_core 0.6.4",
"subtle 2.5.0",
]
[[package]]
name = "ff"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
dependencies = [
"bitvec",
"byteorder",
@ -1372,9 +1382,9 @@ dependencies = [
[[package]]
name = "ff_derive"
version = "0.12.1"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17db6fa0748f1f66e9dbafba1881009b50614948c0e900f59083afff2f8d784b"
checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a"
dependencies = [
"addchain",
"cfg-if 1.0.0",
@ -1400,23 +1410,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "fil_pasta_curves"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3303ea3c462ab949ab95b49f6e6d255d8d9396ebd4f1626ccb34c7037615aa8f"
dependencies = [
"blake2b_simd",
"ff",
"group",
"hex 0.4.3",
"lazy_static",
"rand 0.8.5",
"serde",
"static_assertions",
"subtle 2.5.0",
]
[[package]]
name = "fixed-hash"
version = "0.7.0"
@ -1445,7 +1438,7 @@ version = "0.10.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
dependencies = [
"spin",
"spin 0.9.8",
]
[[package]]
@ -1610,7 +1603,18 @@ version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
dependencies = [
"ff",
"ff 0.12.1",
"rand_core 0.6.4",
"subtle 2.5.0",
]
[[package]]
name = "group"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
"ff 0.13.0",
"rand 0.8.5",
"rand_core 0.6.4",
"rand_xorshift",
@ -1841,6 +1845,9 @@ name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
dependencies = [
"spin 0.5.2",
]
[[package]]
name = "libc"
@ -1873,19 +1880,6 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "lurk-pasta-msm"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12992280292a2a4ff84591308c426029245d49094c75df079b286f1bb8496e6c"
dependencies = [
"cc",
"fil_pasta_curves",
"semolina",
"sppark",
"which",
]
[[package]]
name = "maybe-uninit"
version = "2.0.0"
@ -1936,20 +1930,19 @@ dependencies = [
[[package]]
name = "neptune"
version = "8.1.1"
version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d47b29bc49c7d957eb446e298f96cd7088829e2d7a549ab04b36bc82434e27b"
checksum = "4227e5557caad6d2a910b7770f2479f0c9aeb8ddc1dc537623cb6ffec7f01d31"
dependencies = [
"bellperson",
"blake2s_simd 0.5.11",
"blstrs",
"byteorder",
"ff",
"fil_pasta_curves",
"ff 0.13.0",
"generic-array 0.14.7",
"itertools 0.8.2",
"lazy_static",
"log",
"pasta_curves",
"serde",
"trait-set",
]
@ -1962,25 +1955,25 @@ checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "nova-snark"
version = "0.20.3"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09c8cf02c93500dee9244cd73547f20d133ca6d3fbbe9eae0205e5b2db05f36"
checksum = "d6247c61ab29e5da01c8f80403c25c40956045f0343d79793a2675bf7775dd80"
dependencies = [
"bellperson",
"bincode 1.3.3",
"bitvec",
"byteorder",
"digest 0.8.1",
"ff",
"fil_pasta_curves",
"ff 0.13.0",
"flate2",
"generic-array 0.14.7",
"itertools 0.9.0",
"lurk-pasta-msm",
"neptune",
"num-bigint 0.4.3",
"num-integer",
"num-traits 0.2.15",
"pasta-msm",
"pasta_curves",
"rand_chacha",
"rand_core 0.6.4",
"rayon",
@ -2128,7 +2121,16 @@ version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b"
dependencies = [
"group",
"group 0.12.1",
]
[[package]]
name = "pairing"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f"
dependencies = [
"group 0.13.0",
]
[[package]]
@ -2168,6 +2170,36 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "pasta-msm"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e85d75eba3e7e9ee3bd11342b669185e194dadda3557934bc1000d9b87159d3"
dependencies = [
"cc",
"pasta_curves",
"semolina",
"sppark",
"which",
]
[[package]]
name = "pasta_curves"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095"
dependencies = [
"blake2b_simd",
"ff 0.13.0",
"group 0.13.0",
"hex 0.4.3",
"lazy_static",
"rand 0.8.5",
"serde",
"static_assertions",
"subtle 2.5.0",
]
[[package]]
name = "paste"
version = "1.0.12"
@ -2670,9 +2702,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semolina"
version = "0.1.2"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e90759f733a01b95d6ba70180b954d1d96e3e7e11f86c3fb0da0231300972e05"
checksum = "2b0111fd4fa831becb0606b9a2285ef3bee3c6a70d690209b8ae9514e9befe23"
dependencies = [
"cc",
"glob 0.3.1",
@ -2849,6 +2881,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spin"
version = "0.9.8"
@ -3669,12 +3707,12 @@ name = "zokrates_bellperson"
version = "0.1.0"
dependencies = [
"bellperson",
"ff",
"fil_pasta_curves",
"ff 0.13.0",
"getrandom",
"hex 0.4.3",
"nova-snark",
"pairing",
"pairing 0.22.0",
"pasta_curves",
"rand 0.4.6",
"serde",
"typed-arena",
@ -3822,14 +3860,14 @@ dependencies = [
"bellman_ce",
"bellperson",
"bincode 0.8.0",
"ff",
"fil_pasta_curves",
"ff 0.13.0",
"lazy_static",
"nova-snark",
"num-bigint 0.2.6",
"num-integer",
"num-traits 0.2.15",
"pairing",
"pairing 0.22.0",
"pasta_curves",
"rand 0.4.6",
"serde",
"serde_derive",

View file

@ -0,0 +1 @@
Propagate embed call

View file

@ -0,0 +1 @@
Short-circuit on compile-time constant branch conditions

View file

@ -0,0 +1 @@
Fix invalid constant in mimc7

View file

@ -0,0 +1 @@
Allow composite type in assembly assignment statement

View file

@ -0,0 +1 @@
Detect division by zero on compile-time

View file

@ -33,6 +33,7 @@ pub enum Error {
InvalidValue(String),
OutOfBounds(u128, u128),
VariableLength(String),
DivisionByZero,
}
impl fmt::Display for Error {
@ -47,6 +48,9 @@ impl fmt::Display for Error {
index, size
),
Error::VariableLength(message) => write!(f, "{}", message),
Error::DivisionByZero => {
write!(f, "Division by zero detected during static analysis",)
}
}
}
}
@ -55,7 +59,7 @@ impl fmt::Display for Error {
pub struct Propagator<'ast, T> {
// constants keeps track of constant expressions
// we currently do not support partially constant expressions: `field [x, 1][1]` is not considered constant, `field [0, 1][1]` is
constants: Constants<'ast, T>,
pub constants: Constants<'ast, T>,
}
impl<'ast, T: Field> Propagator<'ast, T> {
@ -181,26 +185,22 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for Propagator<'ast, T> {
_: &E::Ty,
e: ConditionalExpression<'ast, T, E>,
) -> Result<ConditionalOrExpression<'ast, T, E>, Self::Error> {
Ok(
match (
self.fold_boolean_expression(*e.condition)?,
e.consequence.fold(self)?,
e.alternative.fold(self)?,
) {
(BooleanExpression::Value(v), consequence, _) if v.value => {
Ok(match self.fold_boolean_expression(*e.condition)? {
BooleanExpression::Value(v) if v.value => {
ConditionalOrExpression::Expression(e.consequence.fold(self)?.into_inner())
}
BooleanExpression::Value(v) if !v.value => {
ConditionalOrExpression::Expression(e.alternative.fold(self)?.into_inner())
}
condition => match (e.consequence.fold(self)?, e.alternative.fold(self)?) {
(consequence, alternative) if consequence == alternative => {
ConditionalOrExpression::Expression(consequence.into_inner())
}
(BooleanExpression::Value(v), _, alternative) if !v.value => {
ConditionalOrExpression::Expression(alternative.into_inner())
}
(_, consequence, alternative) if consequence == alternative => {
ConditionalOrExpression::Expression(consequence.into_inner())
}
(condition, consequence, alternative) => ConditionalOrExpression::Conditional(
(consequence, alternative) => ConditionalOrExpression::Conditional(
ConditionalExpression::new(condition, consequence, alternative, e.kind),
),
},
)
})
}
fn fold_assembly_assignment(
@ -944,12 +944,16 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for Propagator<'ast, T> {
let left = self.fold_field_expression(*e.left)?;
let right = self.fold_field_expression(*e.right)?;
Ok(match (left, right) {
(FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => {
FieldElementExpression::Value(ValueExpression::new(n1.value / n2.value))
match (left, right) {
(_, FieldElementExpression::Value(n)) if n.value == T::from(0) => {
Err(Error::DivisionByZero)
}
(e1, e2) => e1 / e2,
})
(e, FieldElementExpression::Value(n)) if n.value == T::from(1) => Ok(e),
(FieldElementExpression::Value(n1), FieldElementExpression::Value(n2)) => Ok(
FieldElementExpression::Value(ValueExpression::new(n1.value / n2.value)),
),
(e1, e2) => Ok(e1 / e2),
}
}
FieldElementExpression::IDiv(e) => {
let left = self.fold_field_expression(*e.left)?;
@ -1620,14 +1624,30 @@ mod tests {
#[test]
fn div() {
let e = FieldElementExpression::div(
FieldElementExpression::value(Bn128Field::from(6)),
FieldElementExpression::value(Bn128Field::from(2)),
let mut propagator = Propagator::default();
assert_eq!(
propagator.fold_field_expression(FieldElementExpression::div(
FieldElementExpression::value(Bn128Field::from(6)),
FieldElementExpression::value(Bn128Field::from(2)),
)),
Ok(FieldElementExpression::value(Bn128Field::from(3)))
);
assert_eq!(
Propagator::default().fold_field_expression(e),
Ok(FieldElementExpression::value(Bn128Field::from(3)))
propagator.fold_field_expression(FieldElementExpression::div(
FieldElementExpression::identifier("a".into()),
FieldElementExpression::value(Bn128Field::from(1)),
)),
Ok(FieldElementExpression::identifier("a".into()))
);
assert_eq!(
propagator.fold_field_expression(FieldElementExpression::div(
FieldElementExpression::value(Bn128Field::from(6)),
FieldElementExpression::value(Bn128Field::from(0)),
)),
Err(Error::DivisionByZero)
);
}

View file

@ -213,6 +213,8 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
let return_value = self.fold_expression(return_value)?;
let return_value = self.propagator.fold_expression(return_value)?;
Ok(FunctionCallOrExpression::Expression(
E::from(return_value).into_inner(),
))
@ -226,22 +228,28 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
FunctionCallExpression::<_, E>::new(e.function_key, generics, arguments)
))),
Err(InlineError::Flat(embed, generics, output_type)) => {
let identifier = self.ssa.issue_next_identifier(CoreIdentifier::Call(0));
let identifier = self.ssa.issue_next_identifier(CoreIdentifier::Call);
let var = Variable::new(identifier.clone(), output_type);
let v: TypedAssignee<'ast, T> = var.clone().into();
self.statement_buffer.push(
TypedStatement::embed_call_definition(
v,
EmbedCall::new(embed, generics, arguments),
)
.span(span),
);
Ok(FunctionCallOrExpression::Expression(
E::identifier(identifier).span(span),
))
let definition = TypedStatement::embed_call_definition(
v,
EmbedCall::new(embed, generics, arguments),
)
.span(span);
let definition = self.propagator.fold_statement(definition)?;
self.statement_buffer.extend(definition);
let e = match self.propagator.constants.get(&identifier) {
Some(v) => E::try_from(v.clone()).unwrap().into_inner(),
None => E::identifier(identifier),
};
Ok(FunctionCallOrExpression::Expression(e.span(span)))
}
};

View file

@ -64,12 +64,14 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ZirPropagator<'ast, T> {
&mut self,
f: ZirFunction<'ast, T>,
) -> Result<ZirFunction<'ast, T>, Self::Error> {
let (arguments, inputs) = f
.arguments
.into_iter()
.zip(f.signature.inputs.iter().cloned())
.filter(|(p, _)| !self.constants.contains_key(&p.id.id))
.unzip();
Ok(ZirFunction {
arguments: f
.arguments
.into_iter()
.filter(|p| !self.constants.contains_key(&p.id.id))
.collect(),
arguments,
statements: f
.statements
.into_iter()
@ -78,7 +80,7 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ZirPropagator<'ast, T> {
.into_iter()
.flatten()
.collect(),
..f
signature: f.signature.inputs(inputs),
})
}

View file

@ -5,7 +5,7 @@ use std::fmt;
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Hash, Eq)]
pub struct RefCall {
pub index: usize,
pub argument_count: usize,
pub signature: (usize, usize),
}
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Hash, Eq)]
@ -39,7 +39,7 @@ impl<'ast, T> fmt::Display for Solver<'ast, T> {
Solver::ShaCh => write!(f, "ShaCh"),
Solver::EuclideanDiv => write!(f, "EuclideanDiv"),
Solver::Zir(_) => write!(f, "Zir(..)"),
Solver::Ref(call) => write!(f, "Ref@{}({})", call.index, call.argument_count),
Solver::Ref(call) => write!(f, "Ref@{}", call.index),
#[cfg(feature = "bellman")]
Solver::Sha256Round => write!(f, "Sha256Round"),
#[cfg(feature = "ark")]
@ -59,8 +59,8 @@ impl<'ast, T> Solver<'ast, T> {
Solver::ShaAndXorAndXorAnd => (3, 1),
Solver::ShaCh => (3, 1),
Solver::EuclideanDiv => (2, 2),
Solver::Zir(f) => (f.arguments.len(), 1),
Solver::Ref(c) => (c.argument_count, 1),
Solver::Zir(f) => (f.signature.inputs.len(), f.signature.outputs.len()),
Solver::Ref(c) => c.signature,
#[cfg(feature = "bellman")]
Solver::Sha256Round => (768, 26935),
#[cfg(feature = "ark")]

View file

@ -31,9 +31,9 @@ impl<'ast, T: Field> Folder<'ast, T> for SolverIndexer<'ast, T> {
&mut self,
d: DirectiveStatement<'ast, T>,
) -> Vec<Statement<'ast, T>> {
let signature = d.solver.get_signature();
let res = match d.solver {
Solver::Zir(f) => {
let argument_count = f.arguments.len();
let h = hash(&f);
let index = match self.index_map.entry(h) {
Entry::Occupied(v) => *v.get(),
@ -46,10 +46,7 @@ impl<'ast, T: Field> Folder<'ast, T> for SolverIndexer<'ast, T> {
};
DirectiveStatement::new(
d.outputs,
Solver::Ref(RefCall {
index,
argument_count,
}),
Solver::Ref(RefCall { index, signature }),
d.inputs,
)
}

View file

@ -8,7 +8,7 @@ pub type SourceIdentifier<'ast> = std::borrow::Cow<'ast, str>;
pub enum CoreIdentifier<'ast> {
#[serde(borrow)]
Source(ShadowedIdentifier<'ast>),
Call(usize),
Call,
Constant(CanonicalConstantIdentifier<'ast>),
Condition(usize),
}
@ -17,7 +17,7 @@ impl<'ast> fmt::Display for CoreIdentifier<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CoreIdentifier::Source(s) => write!(f, "{}", s),
CoreIdentifier::Call(i) => write!(f, "#CALL_RETURN_AT_INDEX_{}", i),
CoreIdentifier::Call => write!(f, "#CALL_RETURN"),
CoreIdentifier::Constant(c) => write!(f, "{}/{}", c.module.display(), c.id),
CoreIdentifier::Condition(i) => write!(f, "#CONDITION_{}", i),
}

View file

@ -3486,6 +3486,20 @@ impl<'ast, T: Field> Block<'ast, T> for StructExpression<'ast, T> {
}
}
impl<'ast, T: Field> Block<'ast, T> for TypedExpression<'ast, T> {
fn block(statements: Vec<TypedStatement<'ast, T>>, value: Self) -> Self {
match value {
TypedExpression::Boolean(e) => BooleanExpression::block(statements, e).into(),
TypedExpression::FieldElement(e) => FieldElementExpression::block(statements, e).into(),
TypedExpression::Uint(e) => UExpression::block(statements, e).into(),
TypedExpression::Array(e) => ArrayExpression::block(statements, e).into(),
TypedExpression::Struct(e) => StructExpression::block(statements, e).into(),
TypedExpression::Tuple(e) => TupleExpression::block(statements, e).into(),
TypedExpression::Int(e) => unreachable!("{}", e),
}
}
}
pub trait Constant: Sized {
// return whether this is constant
fn is_constant(&self) -> bool;

View file

@ -942,6 +942,23 @@ impl<S> GType<S> {
}
}
impl<S: PartialEq> GType<S> {
pub fn is_composite_of_field(&self) -> bool {
match self {
GType::Array(array_type) => array_type.ty.is_composite_of_field(),
GType::Tuple(tuple_typle) => tuple_typle
.elements
.iter()
.all(|e| e.is_composite_of_field()),
GType::Struct(struct_type) => struct_type
.members
.iter()
.all(|m| m.ty.is_composite_of_field()),
other => other.eq(&Self::FieldElement),
}
}
}
impl<'ast, T: fmt::Display + PartialEq + fmt::Debug> Type<'ast, T> {
pub fn can_be_specialized_to(&self, other: &DeclarationType<'ast, T>) -> bool {
use self::GType::*;

View file

@ -282,7 +282,7 @@ impl<'ast, T: fmt::Display> fmt::Display for MultipleDefinitionStatement<'ast, T
write!(f, ", ")?;
}
}
write!(f, " = {};", self.rhs)
write!(f, " = {}", self.rhs)
}
}
@ -418,7 +418,7 @@ impl<'ast, T: fmt::Display> ZirStatement<'ast, T> {
write!(f, ";")
}
ZirStatement::Definition(ref s) => {
write!(f, "{}", s)
write!(f, "{};", s)
}
ZirStatement::IfElse(ref s) => {
writeln!(f, "if {} {{", s.condition)?;
@ -441,7 +441,7 @@ impl<'ast, T: fmt::Display> ZirStatement<'ast, T> {
}
}
ZirStatement::MultipleDefinition(ref s) => {
write!(f, "{}", s)
write!(f, "{};", s)
}
ZirStatement::Log(ref e) => write!(
f,

View file

@ -9,13 +9,13 @@ edition = "2021"
zokrates_field = { version = "0.5", path = "../zokrates_field", features = ["bellperson_extensions"] }
zokrates_ast = { version = "0.1", path = "../zokrates_ast", features = ["bellperson"] }
# zokrates_proof_systems = { version = "0.1", path = "../zokrates_proof_systems", default-features = false }
bellperson = { package = "bellperson", version = "^0.24", default-features = false }
bellperson = { package = "bellperson", version = "^0.25", default-features = false }
rand_0_4 = { version = "0.4", package = "rand" }#
getrandom = { version = "0.2", features = ["js", "wasm-bindgen"] }
hex = "0.4.2"
pairing = "0.22"
ff = { version = "0.12.0", default-features = false }
nova-snark = { version = "0.20.3" }
ff = { version = "0.13.0", default-features = false }
nova-snark = { version = "0.21.0" }
zokrates_interpreter = { version = "0.1", path = "../zokrates_interpreter" }
serde = { version = "1.0", features = ["derive"] }
@ -26,7 +26,7 @@ rand_0_4 = { version = "0.4", package = "rand" }
getrandom = { version = "0.2", features = ["js", "wasm-bindgen"] }
hex = "0.4.2"
pairing = "0.22"
pasta_curves = { version = "0.5.2", features = ["repr-c", "serde"], package = "fil_pasta_curves"}
pasta_curves = { version = "0.5", features = ["repr-c", "serde"] }
zokrates_core = { version = "0.7.3", path = "../zokrates_core" }

View file

@ -105,7 +105,7 @@ pub fn verify<T: NovaField>(
arguments: Vec<T>,
) -> Result<Vec<T>, Error> {
let z0_primary: Vec<_> = arguments.into_iter().map(|a| a.into_bellperson()).collect();
let z0_secondary = vec![<<T as Cycle>::Point as Group>::Base::one()];
let z0_secondary = vec![<<T as Cycle>::Point as Group>::Base::ONE];
proof
.proof
@ -149,7 +149,7 @@ pub fn verify_compressed<'ast, T: NovaField>(
step_count: usize,
) -> bool {
let z0_primary: Vec<_> = arguments.into_iter().map(|a| a.into_bellperson()).collect();
let z0_secondary = vec![<<T as Cycle>::Point as Group>::Base::one()];
let z0_secondary = vec![<<T as Cycle>::Point as Group>::Base::ONE];
proof
.verify(vk, step_count, z0_primary, z0_secondary)
@ -166,7 +166,7 @@ pub fn prove<'ast, T: NovaField>(
let c_primary = NovaComputation::try_from(Computation::without_witness(program))?;
let c_secondary = TrivialTestCircuit::default();
let z0_primary: Vec<_> = arguments.into_iter().map(|a| a.into_bellperson()).collect();
let z0_secondary = vec![<<T as Cycle>::Point as Group>::Base::one()];
let z0_secondary = vec![<<T as Cycle>::Point as Group>::Base::ONE];
for steps_private in steps {
let mut c_primary = c_primary.clone();

View file

@ -17,9 +17,19 @@ Assigning a value, in general, should be combined with adding a constraint:
{{#include ../../../zokrates_cli/examples/book/assembly/division.zok}}
```
> The operator `<--` can be sometimes misused, as this operator does not generate any constraints, resulting in unconstrained variables in the constraint system.
> Note that operator `<--` is used for unconstrained assignment and can be easily misused. This operator does not generate constraints, which could result in unconstrained variables in the constraint system.
In some cases we can combine the witness assignment and constraint generation with the `<==` operator:
Unconstrained assignment `<--` allows assignment to variables with complex types. The type must consist of field elements only (eg. `field[3]`):
```zok
field[3] mut c = [0; 3];
asm {
c <-- [2, 2, 4];
c[0] * c[1] === c[2];
}
```
In some cases we can combine the witness assignment and constraint generation with the `<==` operator (constrained assignment):
```zok
asm {
@ -36,6 +46,8 @@ asm {
}
```
In the case of constrained assignment `<==`, both sides of the statement have to be of type `field`.
A constraint can contain arithmetic expressions that are built using multiplication, addition, and other variables or `field` values. Only quadratic expressions are allowed to be included in constraints. Non-quadratic expressions or usage of other arithmetic operators like division or power are not allowed as constraints, but can be used in the witness assignment expression.
The following code is not allowed:

View file

@ -25,7 +25,7 @@ Booleans are available in ZoKrates. When a boolean is used as a parameter of the
### `u8/u16/u32/u64`
Unsigned integers represent positive numbers of the interval `[0, 2 ** bitwidth[`, where `bitwidth` is specified in the type's name, e.g., 32 bits in the case of u32. Their arithmetics are defined modulo `2 ** bitwidth`.
Unsigned integers represent positive numbers of the interval `[0, 2 ** bitwidth)`, where `bitwidth` is specified in the type's name, e.g., 32 bits in the case of u32. Their arithmetics are defined modulo `2 ** bitwidth`.
Internally, they use a binary encoding, which makes them particularly efficient for implementing programs that operate on that binary representation, e.g., the SHA256 hash function.

View file

@ -0,0 +1,6 @@
def main(bool a) {
bool mut b = false;
asm {
b <-- a;
}
}

View file

@ -0,0 +1,6 @@
def main() {
field[2] mut a = [0; 2];
asm {
a <== [1, 2];
}
}

View file

@ -1793,20 +1793,32 @@ impl<'ast, T: Field> Checker<'ast, T> {
AssemblyStatement::Assignment(assignee, expression, constrained) => {
let assignee = self.check_assignee(assignee, module_id, types)?;
let e = self.check_expression(expression, module_id, types)?;
let e = FieldElementExpression::try_from_typed(e).map_err(|e| ErrorInner {
span: Some(span),
message: format!(
"Expected right hand side of an assembly assignment to be of type field, found {}",
e.get_type(),
),
let e = TypedExpression::align_to_type(e, &assignee.get_type()).map_err(|e| {
ErrorInner {
span: Some(span),
message: format!(
"Expected value of type `{}`, found `{}` of type `{}`",
e.1,
e.0,
e.0.get_type()
),
}
})?;
match constrained {
true => {
let e = FieldElementExpression::block(vec![], e);
match assignee.get_type() {
Type::FieldElement => Ok(vec![
true => match assignee.get_type() {
// in case of `lhs <== rhs` we expect lhs and rhs to be of type field
Type::FieldElement => {
let e = FieldElementExpression::try_from_typed(e).map_err(|e| ErrorInner {
span: Some(span),
message: format!(
"Expected right hand side of an assembly constrained assignment to be of type field, found {}",
e.get_type(),
),
})?;
let e = FieldElementExpression::block(vec![], e);
Ok(vec![
TypedAssemblyStatement::assignment(
assignee.clone(),
e.clone().into(),
@ -1818,18 +1830,28 @@ impl<'ast, T: Field> Checker<'ast, T> {
SourceMetadata::new(module_id.display().to_string(), span.from),
)
.with_span(span),
]),
ty => Err(ErrorInner {
span: Some(span),
message: format!("Assignee must be of type field, found {}", ty),
}),
])
}
}
ty => Err(ErrorInner {
span: Some(span),
message: format!("Assignee must be of type field, found {}", ty),
}),
},
false => {
let e = FieldElementExpression::block(vec![], e);
Ok(vec![
TypedAssemblyStatement::assignment(assignee, e.into()).with_span(span)
])
// we can allow composite types in case of `<--` as no constraints are generated from this type of statement
// a composite type should only consist of field types
match e.get_type().is_composite_of_field() {
true => {
let e = TypedExpression::block(vec![], e);
Ok(vec![
TypedAssemblyStatement::assignment(assignee, e).with_span(span)
])
},
false => Err(ErrorInner {
span: Some(span),
message: "Assignee must be of type field or a composite type of field elements".to_string(),
})
}
}
}
}

View file

@ -0,0 +1,16 @@
{
"curves": ["Bn128"],
"max_constraint_count": 4,
"tests": [
{
"input": {
"values": ["1", "2"]
},
"output": {
"Ok": {
"value": ["3", "2"]
}
}
}
]
}

View file

@ -0,0 +1,15 @@
def foo(field a, field b) -> field[2] {
field c = a + b;
field d = a * b;
return [c, d];
}
def main(field a, field b) -> field[2] {
field[2] mut c = [0; 2];
asm {
c <-- foo(a, b);
a + b === c[0];
a * b === c[1];
}
return c;
}

View file

@ -0,0 +1,16 @@
{
"curves": ["Bn128"],
"max_constraint_count": 1,
"tests": [
{
"input": {
"values": ["2", "2", "4"]
},
"output": {
"Ok": {
"value": []
}
}
}
]
}

View file

@ -0,0 +1,7 @@
def main(field a, field b, field c) {
field[2] mut out = [0; 2];
asm {
out <-- [a, b];
out[0] * out[1] === c;
}
}

View file

@ -0,0 +1,3 @@
{
"tests": []
}

View file

@ -0,0 +1,6 @@
def main() {
field[2] a = [0; 2];
for u32 i in 1..2 {
field b = (i == 1) ? 0 : a[i - 2];
}
}

View file

@ -0,0 +1,5 @@
{
"entry_point": "./tests/tests/constants/propagate_embed.zok",
"max_constraint_count": 2,
"tests": []
}

View file

@ -0,0 +1,16 @@
import "utils/casts/field_to_u32";
from "EMBED" import unpack;
def foo<N>() -> field {
return 1;
}
def main() -> field {
u32 N = field_to_u32(1);
for u32 i in 0..N {
log("{}", i);
}
bool[1] B = unpack(1);
u32 P = B[0] ? 1 : 0;
return foo::<N>() + foo::<P>();
}

View file

@ -24,11 +24,11 @@ num-integer = { version = "0.1", default-features = false }
bellman_ce = { version = "^0.3", default-features = false, optional = true }
# bellperson
bellperson = { version = "0.24", default-features = false, optional = true }
bellperson = { version = "0.25", default-features = false, optional = true }
pairing = { version = "0.22", default-features = false, optional = true }
ff = { version = "0.12.0", default-features = false, optional = true }
pasta_curves = { version = "0.5.2", features = ["repr-c", "serde"], package = "fil_pasta_curves", optional = true }
nova-snark = { version = "0.20.3", optional = true }
ff = { version = "0.13.0", default-features = false, optional = true }
pasta_curves = { version = "0.5", features = ["repr-c", "serde"], optional = true }
nova-snark = { version = "0.21.0", optional = true }
# ark
ark-ff = { version = "^0.3.0", default-features = false }

View file

@ -523,7 +523,7 @@ mod tests {
let id = IdentifierExpression::new(Identifier::internal(0usize));
// (field i0) -> i0 * i0
let solvers = vec![Solver::Zir(ZirFunction {
let solver = Solver::Zir(ZirFunction {
arguments: vec![Parameter::new(Variable::field_element(id.id.clone()), true)],
statements: vec![ZirStatement::ret(vec![FieldElementExpression::mul(
FieldElementExpression::Identifier(id.clone()),
@ -533,13 +533,16 @@ mod tests {
signature: Signature::new()
.inputs(vec![Type::FieldElement])
.outputs(vec![Type::FieldElement]),
})];
});
let signature = solver.get_signature();
let solvers = vec![solver];
let inputs = vec![Bn128Field::from(2)];
let res = Interpreter::execute_solver(
&Solver::Ref(RefCall {
index: 0,
argument_count: 1,
signature,
}),
&inputs,
&solvers,

View file

@ -89,7 +89,7 @@ const field[91] C = [
4212716923652881254737947578600828255798948993302968210248673545442808456151,
7594017890037021425366623750593200398174488805473151513558919864633711506220,
18979889247746272055963929241596362599320706910852082477600815822482192194401,
1360213922981323134938688511315690179366171918090039581890971975815045550053
13602139229813231349386885113156901793661719180900395818909719758150455500533
];
def main<R>(field x_in, field k) -> field {
@ -109,4 +109,4 @@ def main<R>(field x_in, field k) -> field {
}
return t6[R - 1] * t + k;
}
}