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

merge develop, fix conflicts

This commit is contained in:
dark64 2021-10-05 17:56:47 +02:00
commit 13c0af63a8
64 changed files with 2984 additions and 1705 deletions

View file

@ -126,6 +126,7 @@ jobs:
- checkout
- run:
name: Build
no_output_timeout: "30m"
command: cd zokrates_js && npm run build:dev
zokrates_js_test:
docker:
@ -142,6 +143,7 @@ jobs:
command: cargo clippy -- -D warnings
- run:
name: Run tests
no_output_timeout: "30m"
command: npm run test
cross_build:
parameters:

View file

@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
https://github.com/Zokrates/ZoKrates/compare/latest...develop
## [0.7.7] - 2021-10-04
### Release
- https://github.com/Zokrates/ZoKrates/releases/tag/0.7.7 <!-- markdown-link-check-disable-line -->
### Changes
- Reduce the deployment cost of the g16 and pghr13 verifiers (#1008, @m1cm1c)
- Make operators table more clear in the book (#1017, @dark64)
- Allow calls in constant definitions (#975, @schaeff)
- Handle out of bound accesses gracefully (#1013, @schaeff)
- Improve error message on unconstrained variable detection (#1015, @dark64)
- Apply propagation in ZIR (#957, @dark64)
- Fail on mistyped constants (#974, @schaeff)
- Graceful error handling on unconstrained variable detection (#977, @dark64)
- Fix incorrect propagation of spreads (#987, @schaeff)
- Add range semantics to docs (#992, @dark64)
- Fix invalid cast to `usize` which caused wrong values in 32-bit environments (#998, @dark64)
## [0.7.6] - 2021-08-16
### Release

4
Cargo.lock generated
View file

@ -2383,7 +2383,7 @@ dependencies = [
[[package]]
name = "zokrates_cli"
version = "0.7.6"
version = "0.7.7"
dependencies = [
"assert_cli",
"bincode",
@ -2410,7 +2410,7 @@ version = "0.1.0"
[[package]]
name = "zokrates_core"
version = "0.6.6"
version = "0.6.7"
dependencies = [
"ark-bls12-377",
"ark-bn254",

View file

@ -1 +0,0 @@
Apply propagation in ZIR

View file

@ -1 +0,0 @@
Fail on mistyped constants

View file

@ -1 +0,0 @@
Graceful error handling on unconstrained variable detection

View file

@ -1 +0,0 @@
Fix incorrect propagation of spreads

View file

@ -1 +0,0 @@
Add range semantics to docs

View file

@ -1 +0,0 @@
Fix invalid cast to `usize` which caused wrong values in 32-bit environments

View file

@ -1 +1,2 @@
book
mdbook

View file

@ -87,7 +87,7 @@ Based on that Victor can run the setup phase and export a verifier smart contrac
{{#include ../../../zokrates_cli/examples/book/sha256_tutorial/test.sh:18:19}}
```
`setup` creates a `verifiation.key` file and a `proving.key` file. Victor gives the proving key to Peggy.
`setup` creates a `verification.key` file and a `proving.key` file. Victor gives the proving key to Peggy.
`export-verifier` creates a `verifier.sol` contract that contains our verification key and a function `verifyTx`. Victor deploys this smart contract to the Ethereum network.

View file

@ -9,7 +9,7 @@ ZoKrates is a toolbox for zkSNARKs on Ethereum. It helps you use verifiable comp
One particular family of ZKPs is described as zero-knowledge **S**uccinct **N**on-interactive **AR**guments of **K**nowledge, a.k.a. zkSNARKs. zkSNARKs are the most widely used zero-knowledge protocols, with the anonymous cryptocurrency Zcash and the smart-contract platform Ethereum among the notable early adopters.
For further details we refer the reader to some introductory material provided by the community: [[1]](https://z.cash/technology/zksnarks/),[[2]](https://medium.com/@VitalikButerin/zkSNARKs-under-the-hood-b33151a013f6), [[3]](https://blog.decentriq.ch/zk-SNARKs-primer-part-one/).
For further details we refer the reader to some introductory material provided by the community: [[1]](https://z.cash/technology/zksnarks/), [[2]](https://medium.com/@VitalikButerin/zkSNARKs-under-the-hood-b33151a013f6), [[3]](https://blog.decentriq.ch/zk-SNARKs-primer-part-one/).
## Motivation
@ -19,4 +19,4 @@ ZoKrates bridges this gap. It helps you create off-chain programs and link them
## License
ZoKrates is released under the GNU Lesser General Public License v3.
ZoKrates is released under the GNU Lesser General Public License v3.

View file

@ -1,22 +1,22 @@
## Operators
The following table lists the precedence and associativity of all operators. Operators are listed top to bottom, in ascending precedence. Operators in the same box group left to right. Operators are binary, unless the syntax is provided.
The following table lists the precedence and associativity of all operators. Operators are listed top to bottom, in ascending precedence. Operators in the same cell have the same precedence. Operators are binary, unless the syntax is provided.
| Operator | Description | Remarks |
|---------------------------------|-------------------------------------------------------------------|---------|
| `**` <br> | Power | [^1] |
| `+x` <br> `-x` <br> `!x` <br> | Positive <br> Negative <br> Negation <br> | |
| `*` <br> `/` <br> `%` <br> | Multiplication <br> Division <br> Remainder <br> | |
| `+` <br> `-` <br> | Addition <br> Subtraction <br> | |
| `<<` <br> `>>` <br> | Left shift <br> Right shift <br> | [^2] |
| `&` | Bitwise AND | |
| <code>&#124;</code> | Bitwise OR | |
| `^` | Bitwise XOR | |
| `>=` <br> `>` <br> `<=` <br> `<`| Greater or equal <br> Greater <br> Lower or equal <br> Lower <br> | [^3] |
| `!=` <br> `==` <br> | Not Equal <br> Equal <br> | |
| `&&` | Boolean AND | |
| <code>&#124;&#124;</code> | Boolean OR | |
| `if c then x else y fi` | Conditional expression | |
| Operator | Description | `field` | `u8/u16` `u32/u64` | `bool` | Associativity | Remarks |
|----------------------------|------------------------------------------------------------|------------------------------|-------------------------------|-----------------------------|---------------|---------|
| `**`<br> | Power | &check; | &nbsp; | &nbsp; | Left | [^1] |
| `+x`<br>`-x`<br>`!x`<br> | Positive<br>Negative<br>Negation<br> | &check;<br>&check;<br>&nbsp; | &check;<br>&check;<br>&nbsp; | &nbsp;<br>&nbsp;<br>&check; | Right | |
| `*`<br>`/`<br>`%`<br> | Multiplication<br> Division<br> Remainder<br> | &check;<br>&check;<br>&nbsp; | &check;<br>&check;<br>&check; | &nbsp;<br>&nbsp;<br>&nbsp; | Left | |
| `+`<br>`-`<br> | Addition<br> Subtraction<br> | &check; | &check; | &nbsp; | Left | |
| `<<`<br>`>>`<br> | Left shift<br> Right shift<br> | &nbsp; | &check; | &nbsp; | Left | [^2] |
| `&` | Bitwise AND | &nbsp; | &check; | &nbsp; | Left | |
| <code>&#124;</code> | Bitwise OR | &nbsp; | &check; | &nbsp; | Left | |
| `^` | Bitwise XOR | &nbsp; | &check; | &nbsp; | Left | |
| `>=`<br>`>`<br>`<=`<br>`<` | Greater or equal<br>Greater<br>Lower or equal<br>Lower<br> | &check; | &check; | &nbsp; | Left | [^3] |
| `!=`<br>`==`<br> | Not Equal<br>Equal<br> | &check; | &check; | &check; | Left | |
| `&&` | Boolean AND | &nbsp; | &nbsp; | &check; | Left | |
| <code>&#124;&#124;</code> | Boolean OR | &nbsp; | &nbsp; | &check; | Left | |
| `if c then x else y fi` | Conditional expression | &check; | &check; | &check; | Right | |
[^1]: The exponent must be a compile-time constant of type `u32`

View file

@ -6,7 +6,7 @@ ZoKrates currently exposes two primitive types and two complex types:
### `field`
This is the most basic type in ZoKrates, and it represents a field element with positive integer values in `[0, p - 1]` where `p` is a (large) prime number. Standard arithmetic operations are supported; note that [division in the finite field](https://en.wikipedia.org/wiki/Finite_field_arithmetic) behaves differently than in the case of integers.
This is the most basic type in ZoKrates, and it represents a field element with positive integer values in `[0, p - 1]` where `p` is a (large) prime number.
As an example, `p` is set to `21888242871839275222246405745257275088548364400416034343698204186575808495617` when working with the [ALT_BN128](../toolbox/proving_schemes.md#curves) curve supported by Ethereum.
@ -16,7 +16,8 @@ While `field` values mostly behave like unsigned integers, one should keep in mi
{{#include ../../../zokrates_cli/examples/book/field_overflow.zok}}
```
Note that for field elements, the division operation multiplies the numerator with the denominator's inverse field element. The results coincide with integer divisions for cases with remainder 0, but differ otherwise.
Note that [division in the finite field](https://en.wikipedia.org/wiki/Finite_field_arithmetic) behaves differently than in the case of integers.
For field elements, the division operation multiplies the numerator with the denominator's inverse field element. The results coincide with integer divisions for cases with remainder 0, but differ otherwise.
### `bool`

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_cli"
version = "0.7.6"
version = "0.7.7"
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>", "Thibaut Schaeffer <thibaut@schaeff.fr>"]
repository = "https://github.com/Zokrates/ZoKrates.git"
edition = "2018"

View file

@ -0,0 +1,11 @@
def myFct<N, N2>(u64[N] ignored) -> u64[N2]:
assert(2*N == N2)
return [0; N2]
const u32 N = 3
const u32 N2 = 2*N
def main(u64[N] arg) -> bool:
u64[N2] someVariable = myFct(arg)
return true

View file

@ -0,0 +1,10 @@
from "./call_in_const_aux.zok" import A, foo, F
def bar(field[A] x) -> field[A]:
return x
const field[A] Y = [...bar(foo::<A>(F))[..A - 1], 1]
def main(field[A] X):
assert(X == Y)
return

View file

@ -0,0 +1,9 @@
const field F = 10
const u32 A = 10
const u32 B = A
def foo<N>(field X) -> field[N]:
return [X; N]
def main():
return

View file

@ -0,0 +1,7 @@
def yes() -> bool:
return true
const bool TRUE = yes()
def main():
return

View file

@ -0,0 +1,14 @@
// this should not compile, as A == B
const u32 A = 1
const u32 B = 1
def foo(field[A] a) -> bool:
return true
def foo(field[B] a) -> bool:
return true
def main():
assert(foo([1]))
return

View file

@ -0,0 +1,14 @@
// this should actually compile, as A != B
const u32 A = 2
const u32 B = 1
def foo(field[A] a) -> bool:
return true
def foo(field[B] a) -> bool:
return true
def main():
assert(foo([1]))
return

View file

@ -0,0 +1,6 @@
from "EMBED" import bit_array_le
const bool CONST = bit_array_le([true], [true])
def main() -> bool:
return CONST

View file

@ -0,0 +1,7 @@
def foo(field[1] a) -> field[1]:
return a
def main(field a):
field[1] h = foo([a])
field f = h[1]
return

View file

@ -0,0 +1,7 @@
def foo(field[1] a) -> field[1]:
return a
def main(field a):
field[1] h = foo([a])
h[1] = 1
return

View file

@ -0,0 +1,14 @@
def constant() -> u32:
u32 res = 0
u32 x = 3
for u32 y in 0..x do
res = res + 1
endfor
return res
const u32 CONSTANT = 1 + constant()
const u32 OTHER_CONSTANT = 42
def main(field[CONSTANT] a) -> u32:
return CONSTANT + OTHER_CONSTANT

View file

@ -0,0 +1,15 @@
struct SomeStruct<N> {
u64[N] f
}
def myFct<N, N2, N3>(SomeStruct<N> ignored) -> u32[N2]:
assert(2*N == N2)
return [N3; N2]
const u32 N = 3
const u32 N2 = 2*N
def main(SomeStruct<N> arg) -> u32:
u32[N2] someVariable = myFct::<_, _, 42>(arg)
return someVariable[0]

View file

@ -410,14 +410,15 @@ mod integration {
for p in glob("./examples/book/rng_tutorial/*").expect("Failed to read glob pattern") {
let path = p.unwrap();
std::fs::copy(path.clone(), tmp_base.join(path.file_name().unwrap())).unwrap();
std::fs::hard_link(path.clone(), tmp_base.join(path.file_name().unwrap())).unwrap();
}
let stdlib = std::fs::canonicalize("../zokrates_stdlib/stdlib").unwrap();
let binary_path = std::fs::canonicalize("../target/release/zokrates").unwrap();
assert_cli::Assert::command(&[
"./test.sh",
env!("CARGO_BIN_EXE_zokrates"),
binary_path.to_str().unwrap(),
stdlib.to_str().unwrap(),
])
.current_dir(tmp_base)
@ -433,14 +434,15 @@ mod integration {
for p in glob("./examples/book/sha256_tutorial/*").expect("Failed to read glob pattern") {
let path = p.unwrap();
std::fs::copy(path.clone(), tmp_base.join(path.file_name().unwrap())).unwrap();
std::fs::hard_link(path.clone(), tmp_base.join(path.file_name().unwrap())).unwrap();
}
let stdlib = std::fs::canonicalize("../zokrates_stdlib/stdlib").unwrap();
let binary_path = std::fs::canonicalize("../target/release/zokrates").unwrap();
assert_cli::Assert::command(&[
"./test.sh",
env!("CARGO_BIN_EXE_zokrates"),
binary_path.to_str().unwrap(),
stdlib.to_str().unwrap(),
])
.current_dir(tmp_base)

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_core"
version = "0.6.6"
version = "0.6.7"
edition = "2018"
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>"]
repository = "https://github.com/Zokrates/ZoKrates"

View file

@ -9,6 +9,16 @@ pub struct Node<T> {
pub value: T,
}
impl<T> Node<T> {
pub fn mock(e: T) -> Self {
Self {
start: Position::mock(),
end: Position::mock(),
value: e,
}
}
}
impl<T: fmt::Display> Node<T> {
pub fn pos(&self) -> (Position, Position) {
(self.start, self.end)
@ -67,8 +77,7 @@ pub trait NodeValue: fmt::Display + fmt::Debug + Sized + PartialEq {
impl<V: NodeValue> From<V> for Node<V> {
fn from(v: V) -> Node<V> {
let mock_position = Position { col: 42, line: 42 };
Node::new(mock_position, mock_position, v)
Node::new(Position::mock(), Position::mock(), v)
}
}

View file

@ -164,7 +164,9 @@ impl fmt::Display for CompileErrorInner {
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct CompileConfig {
#[serde(default)]
pub allow_unconstrained_variables: bool,
#[serde(default)]
pub isolate_branches: bool,
}
@ -249,6 +251,8 @@ fn check_with_arena<'ast, T: Field, E: Into<imports::Error>>(
let typed_ast = Checker::check(compiled)
.map_err(|errors| CompileErrors(errors.into_iter().map(CompileError::from).collect()))?;
log::trace!("\n{}", typed_ast);
let main_module = typed_ast.main.clone();
log::debug!("Run static analysis");

View file

@ -1,3 +1,7 @@
use crate::absy::{
types::{UnresolvedSignature, UnresolvedType},
ConstantGenericNode, Expression,
};
use crate::flat_absy::{
FlatDirective, FlatExpression, FlatExpressionList, FlatFunction, FlatParameter, FlatStatement,
FlatVariable, RuntimeError,
@ -26,7 +30,7 @@ cfg_if::cfg_if! {
/// A low level function that contains non-deterministic introduction of variables. It is carried out as is until
/// the flattening step when it can be inlined.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)]
pub enum FlatEmbed {
BitArrayLe,
Unpack,
@ -45,7 +49,131 @@ pub enum FlatEmbed {
}
impl FlatEmbed {
pub fn signature(&self) -> DeclarationSignature<'static> {
pub fn signature(&self) -> UnresolvedSignature {
match self {
FlatEmbed::BitArrayLe => UnresolvedSignature::new()
.generics(vec![ConstantGenericNode::mock("N")])
.inputs(vec![
UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::Identifier("N").into(),
)
.into(),
UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::Identifier("N").into(),
)
.into(),
])
.outputs(vec![UnresolvedType::Boolean.into()]),
FlatEmbed::Unpack => UnresolvedSignature::new()
.generics(vec!["N".into()])
.inputs(vec![UnresolvedType::FieldElement.into()])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::Identifier("N").into(),
)
.into()]),
FlatEmbed::U8ToBits => UnresolvedSignature::new()
.inputs(vec![UnresolvedType::Uint(8).into()])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(8).into(),
)
.into()]),
FlatEmbed::U16ToBits => UnresolvedSignature::new()
.inputs(vec![UnresolvedType::Uint(16).into()])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(16).into(),
)
.into()]),
FlatEmbed::U32ToBits => UnresolvedSignature::new()
.inputs(vec![UnresolvedType::Uint(32).into()])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(32).into(),
)
.into()]),
FlatEmbed::U64ToBits => UnresolvedSignature::new()
.inputs(vec![UnresolvedType::Uint(64).into()])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(64).into(),
)
.into()]),
FlatEmbed::U8FromBits => UnresolvedSignature::new()
.outputs(vec![UnresolvedType::Uint(8).into()])
.inputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(8).into(),
)
.into()]),
FlatEmbed::U16FromBits => UnresolvedSignature::new()
.outputs(vec![UnresolvedType::Uint(16).into()])
.inputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(16).into(),
)
.into()]),
FlatEmbed::U32FromBits => UnresolvedSignature::new()
.outputs(vec![UnresolvedType::Uint(32).into()])
.inputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(32).into(),
)
.into()]),
FlatEmbed::U64FromBits => UnresolvedSignature::new()
.outputs(vec![UnresolvedType::Uint(64).into()])
.inputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(64).into(),
)
.into()]),
#[cfg(feature = "bellman")]
FlatEmbed::Sha256Round => UnresolvedSignature::new()
.inputs(vec![
UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(512).into(),
)
.into(),
UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(256).into(),
)
.into(),
])
.outputs(vec![UnresolvedType::array(
UnresolvedType::Boolean.into(),
Expression::U32Constant(256).into(),
)
.into()]),
#[cfg(feature = "ark")]
FlatEmbed::SnarkVerifyBls12377 => UnresolvedSignature::new()
.generics(vec!["N".into(), "V".into()])
.inputs(vec![
UnresolvedType::array(
UnresolvedType::FieldElement.into(),
Expression::Identifier("N").into(),
)
.into(), // inputs
UnresolvedType::array(
UnresolvedType::FieldElement.into(),
Expression::U32Constant(8).into(),
)
.into(), // proof
UnresolvedType::array(
UnresolvedType::FieldElement.into(),
Expression::Identifier("V").into(),
)
.into(), // 18 + (2 * n) // vk
])
.outputs(vec![UnresolvedType::Boolean.into()]),
}
}
pub fn typed_signature<T>(&self) -> DeclarationSignature<'static, T> {
match self {
FlatEmbed::BitArrayLe => DeclarationSignature::new()
.generics(vec![Some(DeclarationConstant::Generic(
@ -177,15 +305,13 @@ impl FlatEmbed {
}
}
pub fn generics<'ast>(&self, assignment: &ConcreteGenericsAssignment<'ast>) -> Vec<u32> {
let gen = self
.signature()
.generics
.into_iter()
.map(|c| match c.unwrap() {
pub fn generics<'ast, T>(&self, assignment: &ConcreteGenericsAssignment<'ast>) -> Vec<u32> {
let gen = self.typed_signature().generics.into_iter().map(
|c: Option<DeclarationConstant<'ast, T>>| match c.unwrap() {
DeclarationConstant::Generic(g) => g,
_ => unreachable!(),
});
},
);
assert_eq!(gen.len(), assignment.0.len());
gen.map(|g| *assignment.0.get(&g).unwrap() as u32).collect()

View file

@ -15,7 +15,6 @@ impl Position {
}
}
#[cfg(test)]
pub fn mock() -> Self {
Position { line: 42, col: 42 }
}

View file

@ -1,5 +1,5 @@
use crate::proof_system::scheme::{NonUniversalScheme, Scheme};
use crate::proof_system::solidity::{SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB};
use crate::proof_system::solidity::{solidity_pairing_lib, SOLIDITY_G2_ADDITION_LIB};
use crate::proof_system::{
G1Affine, G2Affine, G2AffineFq, SolidityCompatibleField, SolidityCompatibleScheme,
};
@ -48,10 +48,8 @@ impl Scheme<Bw6_761Field> for GM17 {
impl<T: SolidityCompatibleField + NotBw6_761Field> SolidityCompatibleScheme<T> for GM17 {
fn export_solidity_verifier(vk: <GM17 as Scheme<T>>::VerificationKey) -> String {
let (mut template_text, solidity_pairing_lib) = (
String::from(CONTRACT_TEMPLATE),
String::from(SOLIDITY_PAIRING_LIB),
);
let (mut template_text, solidity_pairing_lib) =
(String::from(CONTRACT_TEMPLATE), solidity_pairing_lib(true));
// replace things in template
let vk_regex = Regex::new(r#"(<%vk_[^i%]*%>)"#).unwrap();

View file

@ -1,5 +1,5 @@
use crate::proof_system::scheme::{NonUniversalScheme, Scheme};
use crate::proof_system::solidity::{SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB};
use crate::proof_system::solidity::solidity_pairing_lib;
use crate::proof_system::{G1Affine, G2Affine, SolidityCompatibleField, SolidityCompatibleScheme};
use regex::Regex;
use serde::{Deserialize, Serialize};
@ -32,10 +32,8 @@ impl<T: Field> NonUniversalScheme<T> for G16 {}
impl<T: SolidityCompatibleField> SolidityCompatibleScheme<T> for G16 {
fn export_solidity_verifier(vk: <G16 as Scheme<T>>::VerificationKey) -> String {
let (mut template_text, solidity_pairing_lib) = (
String::from(CONTRACT_TEMPLATE),
String::from(SOLIDITY_PAIRING_LIB),
);
let (mut template_text, solidity_pairing_lib_sans_bn256g2) =
(String::from(CONTRACT_TEMPLATE), solidity_pairing_lib(false));
let vk_regex = Regex::new(r#"(<%vk_[^i%]*%>)"#).unwrap();
let vk_gamma_abc_len_regex = Regex::new(r#"(<%vk_gamma_abc_length%>)"#).unwrap();
@ -122,10 +120,7 @@ impl<T: SolidityCompatibleField> SolidityCompatibleScheme<T> for G16 {
let re = Regex::new(r"(?P<v>0[xX][0-9a-fA-F]{64})").unwrap();
template_text = re.replace_all(&template_text, "uint256($v)").to_string();
format!(
"{}{}{}",
SOLIDITY_G2_ADDITION_LIB, solidity_pairing_lib, template_text
)
format!("{}{}", solidity_pairing_lib_sans_bn256g2, template_text)
}
}

View file

@ -1,5 +1,5 @@
use crate::proof_system::scheme::{NonUniversalScheme, Scheme};
use crate::proof_system::solidity::{SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB};
use crate::proof_system::solidity::solidity_pairing_lib;
use crate::proof_system::{G1Affine, G2Affine, SolidityCompatibleField, SolidityCompatibleScheme};
use regex::Regex;
use serde::{Deserialize, Serialize};
@ -41,10 +41,8 @@ impl<T: Field> NonUniversalScheme<T> for PGHR13 {}
impl<T: SolidityCompatibleField> SolidityCompatibleScheme<T> for PGHR13 {
fn export_solidity_verifier(vk: <PGHR13 as Scheme<T>>::VerificationKey) -> String {
let (mut template_text, solidity_pairing_lib) = (
String::from(CONTRACT_TEMPLATE),
String::from(SOLIDITY_PAIRING_LIB),
);
let (mut template_text, solidity_pairing_lib) =
(String::from(CONTRACT_TEMPLATE), solidity_pairing_lib(false));
// replace things in template
let vk_regex = Regex::new(r#"(<%vk_[^i%]*%>)"#).unwrap();
@ -138,10 +136,7 @@ impl<T: SolidityCompatibleField> SolidityCompatibleScheme<T> for PGHR13 {
let re = Regex::new(r"(?P<v>0[xX][0-9a-fA-F]{64})").unwrap();
template_text = re.replace_all(&template_text, "uint256($v)").to_string();
format!(
"{}{}{}",
SOLIDITY_G2_ADDITION_LIB, solidity_pairing_lib, template_text
)
format!("{}{}", solidity_pairing_lib, template_text)
}
}

View file

@ -406,7 +406,8 @@ library BN256G2 {
}
"#;
pub const SOLIDITY_PAIRING_LIB: &str = r#"// This file is MIT Licensed.
pub fn solidity_pairing_lib(with_g2_addition: bool) -> String {
let pairing_lib_beginning = r#"// This file is MIT Licensed.
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
@ -459,10 +460,16 @@ library Pairing {
}
require(success);
}
"#;
let pairing_lib_g2_addition = r#"
/// @return r the sum of two points of G2
function addition(G2Point memory p1, G2Point memory p2) internal view returns (G2Point memory r) {
(r.X[0], r.X[1], r.Y[0], r.Y[1]) = BN256G2.ECTwistAdd(p1.X[0],p1.X[1],p1.Y[0],p1.Y[1],p2.X[0],p2.X[1],p2.Y[0],p2.Y[1]);
}
"#;
let pairing_lib_ending = r#"
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) {
@ -553,3 +560,15 @@ library Pairing {
}
}
"#;
if !with_g2_addition {
[pairing_lib_beginning, pairing_lib_ending].join("\n")
} else {
[
pairing_lib_beginning,
pairing_lib_g2_addition,
pairing_lib_ending,
]
.join("\n")
}
}

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,9 @@ use crate::typed_absy::{
result_folder::{fold_expression_list_inner, fold_uint_expression_inner},
Constant, TypedExpressionListInner, Types, UBitwidth, UExpressionInner,
};
use std::fmt;
use zokrates_field::Field;
pub struct ConstantArgumentChecker;
impl ConstantArgumentChecker {
@ -14,7 +16,14 @@ impl ConstantArgumentChecker {
}
}
pub type Error = String;
#[derive(Debug)]
pub struct Error(String);
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantArgumentChecker {
type Error = Error;
@ -31,11 +40,11 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantArgumentChecker {
match by.as_inner() {
UExpressionInner::Value(_) => Ok(UExpressionInner::LeftShift(box e, box by)),
by => Err(format!(
by => Err(Error(format!(
"Cannot shift by a variable value, found `{} << {}`",
e,
by.clone().annotate(UBitwidth::B32)
)),
))),
}
}
UExpressionInner::RightShift(box e, box by) => {
@ -44,11 +53,11 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantArgumentChecker {
match by.as_inner() {
UExpressionInner::Value(_) => Ok(UExpressionInner::RightShift(box e, box by)),
by => Err(format!(
by => Err(Error(format!(
"Cannot shift by a variable value, found `{} >> {}`",
e,
by.clone().annotate(UBitwidth::B32)
)),
))),
}
}
e => fold_uint_expression_inner(self, bitwidth, e),
@ -74,10 +83,10 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantArgumentChecker {
arguments,
))
} else {
Err(format!(
Err(Error(format!(
"Cannot compare to a variable value, found `{}`",
arguments[1]
))
)))
}
}
l => fold_expression_list_inner(self, tys, l),

View file

@ -1,973 +0,0 @@
use crate::static_analysis::Propagator;
use crate::typed_absy::result_folder::*;
use crate::typed_absy::types::DeclarationConstant;
use crate::typed_absy::*;
use std::collections::HashMap;
use std::convert::TryInto;
use std::fmt;
use zokrates_field::Field;
type ProgramConstants<'ast, T> =
HashMap<OwnedTypedModuleId, HashMap<Identifier<'ast>, TypedExpression<'ast, T>>>;
#[derive(Debug, PartialEq)]
pub enum Error {
Type(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Type(s) => write!(f, "{}", s),
}
}
}
pub struct ConstantInliner<'ast, T> {
modules: TypedModules<'ast, T>,
location: OwnedTypedModuleId,
constants: ProgramConstants<'ast, T>,
}
impl<'ast, 'a, T: Field> ConstantInliner<'ast, T> {
pub fn new(
modules: TypedModules<'ast, T>,
location: OwnedTypedModuleId,
constants: ProgramConstants<'ast, T>,
) -> Self {
ConstantInliner {
modules,
location,
constants,
}
}
pub fn inline(p: TypedProgram<'ast, T>) -> Result<TypedProgram<'ast, T>, Error> {
let constants = ProgramConstants::new();
let mut inliner = ConstantInliner::new(p.modules.clone(), p.main.clone(), constants);
inliner.fold_program(p)
}
fn change_location(&mut self, location: OwnedTypedModuleId) -> OwnedTypedModuleId {
let prev = self.location.clone();
self.location = location;
self.constants.entry(self.location.clone()).or_default();
prev
}
fn treated(&self, id: &TypedModuleId) -> bool {
self.constants.contains_key(id)
}
fn get_constant(
&self,
id: &CanonicalConstantIdentifier<'ast>,
) -> Option<TypedExpression<'ast, T>> {
self.constants
.get(&id.module)
.and_then(|constants| constants.get(&id.id.into()))
.cloned()
}
fn get_constant_for_identifier(
&self,
id: &Identifier<'ast>,
) -> Option<TypedExpression<'ast, T>> {
self.constants
.get(&self.location)
.and_then(|constants| constants.get(&id))
.cloned()
}
}
impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantInliner<'ast, T> {
type Error = Error;
fn fold_program(
&mut self,
p: TypedProgram<'ast, T>,
) -> Result<TypedProgram<'ast, T>, Self::Error> {
self.fold_module_id(p.main.clone())?;
Ok(TypedProgram {
modules: std::mem::take(&mut self.modules),
..p
})
}
fn fold_module_id(
&mut self,
id: OwnedTypedModuleId,
) -> Result<OwnedTypedModuleId, Self::Error> {
// anytime we encounter a module id, visit the corresponding module if it hasn't been done yet
if !self.treated(&id) {
let current_m_id = self.change_location(id.clone());
let m = self.modules.remove(&id).unwrap();
let m = self.fold_module(m)?;
self.modules.insert(id.clone(), m);
self.change_location(current_m_id);
}
Ok(id)
}
fn fold_module(
&mut self,
m: TypedModule<'ast, T>,
) -> Result<TypedModule<'ast, T>, Self::Error> {
Ok(TypedModule {
constants: m
.constants
.into_iter()
.map(|(id, tc)| {
let id = self.fold_canonical_constant_identifier(id)?;
let constant = match tc {
TypedConstantSymbol::There(imported_id) => {
// visit the imported symbol. This triggers visiting the corresponding module if needed
let imported_id = self.fold_canonical_constant_identifier(imported_id)?;
// after that, the constant must have been defined defined in the global map. It is already reduced
// to a literal, so running propagation isn't required
self.get_constant(&imported_id).unwrap()
}
TypedConstantSymbol::Here(c) => {
let non_propagated_constant = fold_constant(self, c)?.expression;
// folding the constant above only reduces it to an expression containing only literals, not to a single literal.
// propagating with an empty map of constants reduces it to a single literal
Propagator::with_constants(&mut HashMap::default())
.fold_expression(non_propagated_constant)
.unwrap()
}
};
if crate::typed_absy::types::try_from_g_type::<_, UExpression<'ast, T>>(*id.ty.clone()).unwrap() == constant.get_type() {
// add to the constant map. The value added is always a single litteral
self.constants
.get_mut(&self.location)
.unwrap()
.insert(id.id.into(), constant.clone());
Ok((
id,
TypedConstantSymbol::Here(TypedConstant {
expression: constant,
}),
))
} else {
Err(Error::Type(format!("Expression of type `{}` cannot be assigned to constant `{}` of type `{}`", constant.get_type(), id.id, id.ty)))
}
})
.collect::<Result<Vec<_>, _>>()?,
functions: m
.functions
.into_iter()
.map::<Result<_, Self::Error>, _>(|(key, fun)| {
Ok((
self.fold_declaration_function_key(key)?,
self.fold_function_symbol(fun)?,
))
})
.collect::<Result<Vec<_>, _>>()
.into_iter()
.flatten()
.collect(),
})
}
fn fold_declaration_constant(
&mut self,
c: DeclarationConstant<'ast>,
) -> Result<DeclarationConstant<'ast>, Self::Error> {
match c {
// replace constants by their concrete value in declaration types
DeclarationConstant::Constant(id) => {
let id = CanonicalConstantIdentifier {
module: self.fold_module_id(id.module)?,
..id
};
Ok(DeclarationConstant::Concrete(match self.get_constant(&id).unwrap() {
TypedExpression::Uint(UExpression {
inner: UExpressionInner::Value(v),
..
}) => v as u32,
_ => unreachable!("all constants found in declaration types should be reduceable to u32 literals"),
}))
}
c => Ok(c),
}
}
fn fold_field_expression(
&mut self,
e: FieldElementExpression<'ast, T>,
) -> Result<FieldElementExpression<'ast, T>, Self::Error> {
match e {
FieldElementExpression::Identifier(ref id) => {
match self.get_constant_for_identifier(id) {
Some(c) => Ok(c.try_into().unwrap()),
None => fold_field_expression(self, e),
}
}
e => fold_field_expression(self, e),
}
}
fn fold_boolean_expression(
&mut self,
e: BooleanExpression<'ast, T>,
) -> Result<BooleanExpression<'ast, T>, Self::Error> {
match e {
BooleanExpression::Identifier(ref id) => match self.get_constant_for_identifier(id) {
Some(c) => Ok(c.try_into().unwrap()),
None => fold_boolean_expression(self, e),
},
e => fold_boolean_expression(self, e),
}
}
fn fold_uint_expression_inner(
&mut self,
size: UBitwidth,
e: UExpressionInner<'ast, T>,
) -> Result<UExpressionInner<'ast, T>, Self::Error> {
match e {
UExpressionInner::Identifier(ref id) => match self.get_constant_for_identifier(id) {
Some(c) => {
let e: UExpression<'ast, T> = c.try_into().unwrap();
Ok(e.into_inner())
}
None => fold_uint_expression_inner(self, size, e),
},
e => fold_uint_expression_inner(self, size, e),
}
}
fn fold_array_expression_inner(
&mut self,
ty: &ArrayType<'ast, T>,
e: ArrayExpressionInner<'ast, T>,
) -> Result<ArrayExpressionInner<'ast, T>, Self::Error> {
match e {
ArrayExpressionInner::Identifier(ref id) => {
match self.get_constant_for_identifier(id) {
Some(c) => {
let e: ArrayExpression<'ast, T> = c.try_into().unwrap();
Ok(e.into_inner())
}
None => fold_array_expression_inner(self, ty, e),
}
}
e => fold_array_expression_inner(self, ty, e),
}
}
fn fold_struct_expression_inner(
&mut self,
ty: &StructType<'ast, T>,
e: StructExpressionInner<'ast, T>,
) -> Result<StructExpressionInner<'ast, T>, Self::Error> {
match e {
StructExpressionInner::Identifier(ref id) => match self.get_constant_for_identifier(id)
{
Some(c) => {
let e: StructExpression<'ast, T> = c.try_into().unwrap();
Ok(e.into_inner())
}
None => fold_struct_expression_inner(self, ty, e),
},
e => fold_struct_expression_inner(self, ty, e),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::typed_absy::types::DeclarationSignature;
use crate::typed_absy::{
DeclarationArrayType, DeclarationFunctionKey, DeclarationType, FieldElementExpression,
GType, Identifier, TypedConstant, TypedExpression, TypedFunction, TypedFunctionSymbol,
TypedStatement,
};
use zokrates_field::Bn128Field;
#[test]
fn inline_const_field() {
// const field a = 1
//
// def main() -> field:
// return a
let const_id = "a";
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Identifier(Identifier::from(const_id)).into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
};
let constants: TypedConstantSymbols<_> = vec![(
CanonicalConstantIdentifier::new(
const_id,
"main".into(),
DeclarationType::FieldElement,
),
TypedConstantSymbol::Here(TypedConstant::new(TypedExpression::FieldElement(
FieldElementExpression::Number(Bn128Field::from(1)),
))),
)]
.into_iter()
.collect();
let program = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(main),
)]
.into_iter()
.collect(),
constants: constants.clone(),
},
)]
.into_iter()
.collect(),
};
let program = ConstantInliner::inline(program);
let expected_main = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Number(Bn128Field::from(1)).into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
};
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(expected_main),
)]
.into_iter()
.collect(),
constants,
},
)]
.into_iter()
.collect(),
};
assert_eq!(program, Ok(expected_program))
}
#[test]
fn inline_const_boolean() {
// const bool a = true
//
// def main() -> bool:
// return a
let const_id = "a";
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![BooleanExpression::Identifier(
Identifier::from(const_id),
)
.into()])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Boolean]),
};
let constants: TypedConstantSymbols<_> = vec![(
CanonicalConstantIdentifier::new(const_id, "main".into(), DeclarationType::Boolean),
TypedConstantSymbol::Here(TypedConstant::new(TypedExpression::Boolean(
BooleanExpression::Value(true),
))),
)]
.into_iter()
.collect();
let program = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Boolean]),
),
TypedFunctionSymbol::Here(main),
)]
.into_iter()
.collect(),
constants: constants.clone(),
},
)]
.into_iter()
.collect(),
};
let program = ConstantInliner::inline(program);
let expected_main = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
BooleanExpression::Value(true).into()
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Boolean]),
};
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Boolean]),
),
TypedFunctionSymbol::Here(expected_main),
)]
.into_iter()
.collect(),
constants,
},
)]
.into_iter()
.collect(),
};
assert_eq!(program, Ok(expected_program))
}
#[test]
fn inline_const_uint() {
// const u32 a = 0x00000001
//
// def main() -> u32:
// return a
let const_id = "a";
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![UExpressionInner::Identifier(
Identifier::from(const_id),
)
.annotate(UBitwidth::B32)
.into()])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
};
let constants: TypedConstantSymbols<_> = vec![(
CanonicalConstantIdentifier::new(
const_id,
"main".into(),
DeclarationType::Uint(UBitwidth::B32),
),
TypedConstantSymbol::Here(TypedConstant::new(
UExpressionInner::Value(1u128)
.annotate(UBitwidth::B32)
.into(),
)),
)]
.into_iter()
.collect();
let program = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
),
TypedFunctionSymbol::Here(main),
)]
.into_iter()
.collect(),
constants: constants.clone(),
},
)]
.into_iter()
.collect(),
};
let program = ConstantInliner::inline(program);
let expected_main = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![UExpressionInner::Value(1u128)
.annotate(UBitwidth::B32)
.into()])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
};
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
),
TypedFunctionSymbol::Here(expected_main),
)]
.into_iter()
.collect(),
constants,
},
)]
.into_iter()
.collect(),
};
assert_eq!(program, Ok(expected_program))
}
#[test]
fn inline_const_field_array() {
// const field[2] a = [2, 2]
//
// def main() -> field:
// return a[0] + a[1]
let const_id = "a";
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![FieldElementExpression::Add(
FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from(const_id))
.annotate(GType::FieldElement, 2usize),
UExpressionInner::Value(0u128).annotate(UBitwidth::B32),
)
.into(),
FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from(const_id))
.annotate(GType::FieldElement, 2usize),
UExpressionInner::Value(1u128).annotate(UBitwidth::B32),
)
.into(),
)
.into()])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
};
let constants: TypedConstantSymbols<_> = vec![(
CanonicalConstantIdentifier::new(
const_id,
"main".into(),
DeclarationType::Array(DeclarationArrayType::new(
DeclarationType::FieldElement,
2u32,
)),
),
TypedConstantSymbol::Here(TypedConstant::new(TypedExpression::Array(
ArrayExpressionInner::Value(
vec![
FieldElementExpression::Number(Bn128Field::from(2)).into(),
FieldElementExpression::Number(Bn128Field::from(2)).into(),
]
.into(),
)
.annotate(GType::FieldElement, 2usize),
))),
)]
.into_iter()
.collect();
let program = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(main),
)]
.into_iter()
.collect(),
constants: constants.clone(),
},
)]
.into_iter()
.collect(),
};
let program = ConstantInliner::inline(program);
let expected_main = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![FieldElementExpression::Add(
FieldElementExpression::select(
ArrayExpressionInner::Value(
vec![
FieldElementExpression::Number(Bn128Field::from(2)).into(),
FieldElementExpression::Number(Bn128Field::from(2)).into(),
]
.into(),
)
.annotate(GType::FieldElement, 2usize),
UExpressionInner::Value(0u128).annotate(UBitwidth::B32),
)
.into(),
FieldElementExpression::select(
ArrayExpressionInner::Value(
vec![
FieldElementExpression::Number(Bn128Field::from(2)).into(),
FieldElementExpression::Number(Bn128Field::from(2)).into(),
]
.into(),
)
.annotate(GType::FieldElement, 2usize),
UExpressionInner::Value(1u128).annotate(UBitwidth::B32),
)
.into(),
)
.into()])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
};
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(expected_main),
)]
.into_iter()
.collect(),
constants,
},
)]
.into_iter()
.collect(),
};
assert_eq!(program, Ok(expected_program))
}
#[test]
fn inline_nested_const_field() {
// const field a = 1
// const field b = a + 1
//
// def main() -> field:
// return b
let const_a_id = "a";
let const_b_id = "b";
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Identifier(Identifier::from(const_b_id)).into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
};
let program = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(main),
)]
.into_iter()
.collect(),
constants: vec![
(
CanonicalConstantIdentifier::new(
const_a_id,
"main".into(),
DeclarationType::FieldElement,
),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Number(
Bn128Field::from(1),
)),
)),
),
(
CanonicalConstantIdentifier::new(
const_b_id,
"main".into(),
DeclarationType::FieldElement,
),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Add(
box FieldElementExpression::Identifier(Identifier::from(
const_a_id,
)),
box FieldElementExpression::Number(Bn128Field::from(1)),
)),
)),
),
]
.into_iter()
.collect(),
},
)]
.into_iter()
.collect(),
};
let program = ConstantInliner::inline(program);
let expected_main = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Number(Bn128Field::from(2)).into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
};
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(expected_main),
)]
.into_iter()
.collect(),
constants: vec![
(
CanonicalConstantIdentifier::new(
const_a_id,
"main".into(),
DeclarationType::FieldElement,
),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Number(
Bn128Field::from(1),
)),
)),
),
(
CanonicalConstantIdentifier::new(
const_b_id,
"main".into(),
DeclarationType::FieldElement,
),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Number(
Bn128Field::from(2),
)),
)),
),
]
.into_iter()
.collect(),
},
)]
.into_iter()
.collect(),
};
assert_eq!(program, Ok(expected_program))
}
#[test]
fn inline_imported_constant() {
// ---------------------
// module `foo`
// --------------------
// const field FOO = 42
//
// def main():
// return
//
// ---------------------
// module `main`
// ---------------------
// from "foo" import FOO
//
// def main() -> field:
// return FOO
let foo_const_id = "FOO";
let foo_module = TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main")
.signature(DeclarationSignature::new().inputs(vec![]).outputs(vec![])),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![],
signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![]),
}),
)]
.into_iter()
.collect(),
constants: vec![(
CanonicalConstantIdentifier::new(
foo_const_id,
"foo".into(),
DeclarationType::FieldElement,
),
TypedConstantSymbol::Here(TypedConstant::new(TypedExpression::FieldElement(
FieldElementExpression::Number(Bn128Field::from(42)),
))),
)]
.into_iter()
.collect(),
};
let main_module = TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Identifier(Identifier::from(foo_const_id)).into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
}),
)]
.into_iter()
.collect(),
constants: vec![(
CanonicalConstantIdentifier::new(
foo_const_id,
"main".into(),
DeclarationType::FieldElement,
),
TypedConstantSymbol::There(CanonicalConstantIdentifier::new(
foo_const_id,
"foo".into(),
DeclarationType::FieldElement,
)),
)]
.into_iter()
.collect(),
};
let program = TypedProgram {
main: "main".into(),
modules: vec![
("main".into(), main_module),
("foo".into(), foo_module.clone()),
]
.into_iter()
.collect(),
};
let program = ConstantInliner::inline(program);
let expected_main_module = TypedModule {
functions: vec![(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Number(Bn128Field::from(42)).into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
}),
)]
.into_iter()
.collect(),
constants: vec![(
CanonicalConstantIdentifier::new(
foo_const_id,
"main".into(),
DeclarationType::FieldElement,
),
TypedConstantSymbol::Here(TypedConstant::new(TypedExpression::FieldElement(
FieldElementExpression::Number(Bn128Field::from(42)),
))),
)]
.into_iter()
.collect(),
};
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
main: "main".into(),
modules: vec![
("main".into(), expected_main_module),
("foo".into(), foo_module),
]
.into_iter()
.collect(),
};
assert_eq!(program, Ok(expected_program))
}
}

View file

@ -0,0 +1,844 @@
// Static analysis step to replace all imported constants with the imported value
// This does *not* reduce constants to their literal value
// This step cannot fail as the imports were checked during semantics
use crate::typed_absy::folder::*;
use crate::typed_absy::*;
use std::collections::HashMap;
use zokrates_field::Field;
// a map of the canonical constants in this program. with all imported constants reduced to their canonical value
type ProgramConstants<'ast, T> =
HashMap<OwnedTypedModuleId, HashMap<ConstantIdentifier<'ast>, TypedConstant<'ast, T>>>;
pub struct ConstantResolver<'ast, T> {
modules: TypedModules<'ast, T>,
location: OwnedTypedModuleId,
constants: ProgramConstants<'ast, T>,
}
impl<'ast, 'a, T: Field> ConstantResolver<'ast, T> {
pub fn new(
modules: TypedModules<'ast, T>,
location: OwnedTypedModuleId,
constants: ProgramConstants<'ast, T>,
) -> Self {
ConstantResolver {
modules,
location,
constants,
}
}
pub fn inline(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
let constants = ProgramConstants::new();
let mut inliner = ConstantResolver::new(p.modules.clone(), p.main.clone(), constants);
inliner.fold_program(p)
}
fn change_location(&mut self, location: OwnedTypedModuleId) -> OwnedTypedModuleId {
let prev = self.location.clone();
self.location = location;
self.constants.entry(self.location.clone()).or_default();
prev
}
fn treated(&self, id: &TypedModuleId) -> bool {
self.constants.contains_key(id)
}
fn get_constant(
&self,
id: &CanonicalConstantIdentifier<'ast>,
) -> Option<TypedConstant<'ast, T>> {
self.constants
.get(&id.module)
.and_then(|constants| constants.get(&id.id))
.cloned()
}
}
impl<'ast, T: Field> Folder<'ast, T> for ConstantResolver<'ast, T> {
fn fold_program(&mut self, p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
self.fold_module_id(p.main.clone());
TypedProgram {
modules: std::mem::take(&mut self.modules),
..p
}
}
fn fold_module_id(&mut self, id: OwnedTypedModuleId) -> OwnedTypedModuleId {
// anytime we encounter a module id, visit the corresponding module if it hasn't been done yet
if !self.treated(&id) {
let current_m_id = self.change_location(id.clone());
let m = self.modules.remove(&id).unwrap();
let m = self.fold_module(m);
self.modules.insert(id.clone(), m);
self.change_location(current_m_id);
}
id
}
fn fold_constant_symbol_declaration(
&mut self,
c: TypedConstantSymbolDeclaration<'ast, T>,
) -> TypedConstantSymbolDeclaration<'ast, T> {
let id = self.fold_canonical_constant_identifier(c.id);
let constant = match c.symbol {
TypedConstantSymbol::There(imported_id) => {
// visit the imported symbol. This triggers visiting the corresponding module if needed
let imported_id = self.fold_canonical_constant_identifier(imported_id);
// after that, the constant must have been defined in the global map
self.get_constant(&imported_id).unwrap()
}
TypedConstantSymbol::Here(c) => fold_constant(self, c),
};
self.constants
.get_mut(&self.location)
.unwrap()
.insert(id.id, constant.clone());
TypedConstantSymbolDeclaration {
id,
symbol: TypedConstantSymbol::Here(constant),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::typed_absy::types::DeclarationSignature;
use crate::typed_absy::{
DeclarationArrayType, DeclarationFunctionKey, DeclarationType, FieldElementExpression,
GType, Identifier, TypedConstant, TypedExpression, TypedFunction, TypedFunctionSymbol,
TypedStatement,
};
use zokrates_field::Bn128Field;
#[test]
fn inline_const_field() {
// in the absence of imports, a module is left unchanged
// const field a = 1
//
// def main() -> field:
// return a
let const_id = "a";
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Identifier(Identifier::from(const_id)).into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
};
let program = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
CanonicalConstantIdentifier::new(const_id, "main".into()),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Number(
Bn128Field::from(1),
)),
DeclarationType::FieldElement,
)),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(main),
)
.into(),
],
},
)]
.into_iter()
.collect(),
};
let expected_program = program.clone();
let program = ConstantResolver::inline(program);
assert_eq!(program, expected_program)
}
#[test]
fn no_op_const_boolean() {
// in the absence of imports, a module is left unchanged
// const bool a = true
//
// def main() -> bool:
// return main.zok/a
let const_id = CanonicalConstantIdentifier::new("a", "main".into());
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![BooleanExpression::Identifier(
Identifier::from(const_id.clone()),
)
.into()])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Boolean]),
};
let program = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
const_id,
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::Boolean(BooleanExpression::Value(true)),
DeclarationType::Boolean,
)),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Boolean]),
),
TypedFunctionSymbol::Here(main),
)
.into(),
],
},
)]
.into_iter()
.collect(),
};
let expected_program = program.clone();
let program = ConstantResolver::inline(program);
assert_eq!(program, expected_program)
}
#[test]
fn no_op_const_uint() {
// in the absence of imports, a module is left unchanged
// const u32 a = 0x00000001
//
// def main() -> u32:
// return a
let const_id = CanonicalConstantIdentifier::new("a", "main".into());
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![UExpressionInner::Identifier(
Identifier::from(const_id.clone()),
)
.annotate(UBitwidth::B32)
.into()])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
};
let program = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
const_id,
TypedConstantSymbol::Here(TypedConstant::new(
UExpressionInner::Value(1u128)
.annotate(UBitwidth::B32)
.into(),
DeclarationType::Uint(UBitwidth::B32),
)),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
),
TypedFunctionSymbol::Here(main),
)
.into(),
],
},
)]
.into_iter()
.collect(),
};
let expected_program = program.clone();
let program = ConstantResolver::inline(program);
assert_eq!(program, expected_program)
}
#[test]
fn no_op_const_field_array() {
// in the absence of imports, a module is left unchanged
// const field[2] a = [2, 2]
//
// def main() -> field:
// return a[0] + a[1]
let const_id = CanonicalConstantIdentifier::new("a", "main".into());
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![FieldElementExpression::Add(
FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from(const_id.clone()))
.annotate(GType::FieldElement, 2usize),
UExpressionInner::Value(0u128).annotate(UBitwidth::B32),
)
.into(),
FieldElementExpression::select(
ArrayExpressionInner::Identifier(Identifier::from(const_id.clone()))
.annotate(GType::FieldElement, 2usize),
UExpressionInner::Value(1u128).annotate(UBitwidth::B32),
)
.into(),
)
.into()])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
};
let program = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
const_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::Array(
ArrayExpressionInner::Value(
vec![
FieldElementExpression::Number(Bn128Field::from(2))
.into(),
FieldElementExpression::Number(Bn128Field::from(2))
.into(),
]
.into(),
)
.annotate(GType::FieldElement, 2usize),
),
DeclarationType::Array(DeclarationArrayType::new(
DeclarationType::FieldElement,
2u32,
)),
)),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(main),
)
.into(),
],
},
)]
.into_iter()
.collect(),
};
let expected_program = program.clone();
let program = ConstantResolver::inline(program);
assert_eq!(program, expected_program)
}
#[test]
fn no_op_nested_const_field() {
// const field a = 1
// const field b = a + 1
//
// def main() -> field:
// return b
let const_a_id = CanonicalConstantIdentifier::new("a", "main".into());
let const_b_id = CanonicalConstantIdentifier::new("a", "main".into());
let main: TypedFunction<Bn128Field> = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Identifier(Identifier::from(const_b_id.clone())).into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
};
let program = TypedProgram {
main: "main".into(),
modules: vec![(
"main".into(),
TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
const_a_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Number(
Bn128Field::from(1),
)),
DeclarationType::FieldElement,
)),
)
.into(),
TypedConstantSymbolDeclaration::new(
const_b_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Add(
box FieldElementExpression::Identifier(Identifier::from(
const_a_id.clone(),
)),
box FieldElementExpression::Number(Bn128Field::from(1)),
)),
DeclarationType::FieldElement,
)),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(main),
)
.into(),
],
},
)]
.into_iter()
.collect(),
};
let expected_program = program.clone();
let program = ConstantResolver::inline(program);
assert_eq!(program, expected_program)
}
#[test]
fn inline_imported_constant() {
// ---------------------
// module `foo`
// --------------------
// const field FOO = 42
// const field BAR = FOO
//
// def main():
// return
//
// ---------------------
// module `main`
// ---------------------
// from "foo" import BAR
//
// def main() -> field:
// return FOO
// Should be resolved to
// ---------------------
// module `foo`
// --------------------
// const field BAR = ./foo.zok/FOO
//
// def main():
// return
//
// ---------------------
// module `main`
// ---------------------
// const field FOO = 42
//
// def main() -> field:
// return FOO
let foo_const_id = CanonicalConstantIdentifier::new("FOO", "foo".into());
let bar_const_id = CanonicalConstantIdentifier::new("BAR", "foo".into());
let foo_module = TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
foo_const_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Number(
Bn128Field::from(42),
)),
DeclarationType::FieldElement,
)),
)
.into(),
TypedConstantSymbolDeclaration::new(
bar_const_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Identifier(
foo_const_id.clone().into(),
)),
DeclarationType::FieldElement,
)),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("foo", "main")
.signature(DeclarationSignature::new().inputs(vec![]).outputs(vec![])),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![],
signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![]),
}),
)
.into(),
],
};
let main_const_id = CanonicalConstantIdentifier::new("FOO", "main".into());
let main_module = TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
main_const_id.clone(),
TypedConstantSymbol::There(bar_const_id),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Identifier(Identifier::from(
main_const_id.clone(),
))
.into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
}),
)
.into(),
],
};
let program = TypedProgram {
main: "main".into(),
modules: vec![
("main".into(), main_module),
("foo".into(), foo_module.clone()),
]
.into_iter()
.collect(),
};
let program = ConstantResolver::inline(program);
let expected_main_module = TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
main_const_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Identifier(
foo_const_id.into(),
)),
DeclarationType::FieldElement,
)),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Identifier(Identifier::from(
main_const_id.clone(),
))
.into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
}),
)
.into(),
],
};
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
main: "main".into(),
modules: vec![
("main".into(), expected_main_module),
("foo".into(), foo_module),
]
.into_iter()
.collect(),
};
assert_eq!(program, expected_program)
}
#[test]
fn inline_imported_constant_with_generics() {
// ---------------------
// module `foo`
// --------------------
// const field FOO = 2
// const field[FOO] BAR = [1; FOO]
//
// def main():
// return
//
// ---------------------
// module `main`
// ---------------------
// from "foo" import FOO
// from "foo" import BAR
// const field[FOO] BAZ = BAR
//
// def main() -> field:
// return FOO
// Should be resolved to
// ---------------------
// module `foo`
// --------------------
// const field FOO = 2
// const field[FOO] BAR = [1; FOO]
//
// def main():
// return
//
// ---------------------
// module `main`
// ---------------------
// const FOO = 2
// const BAR = [1; ./foo.zok/FOO]
// const field[FOO] BAZ = BAR
//
// def main() -> field:
// return FOO
let foo_const_id = CanonicalConstantIdentifier::new("FOO", "foo".into());
let bar_const_id = CanonicalConstantIdentifier::new("BAR", "foo".into());
let foo_module = TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
foo_const_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::FieldElement(FieldElementExpression::Number(
Bn128Field::from(2),
)),
DeclarationType::FieldElement,
)),
)
.into(),
TypedConstantSymbolDeclaration::new(
bar_const_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::Array(
ArrayExpressionInner::Repeat(
box FieldElementExpression::Number(Bn128Field::from(1)).into(),
box UExpression::from(foo_const_id.clone()),
)
.annotate(Type::FieldElement, foo_const_id.clone()),
),
DeclarationType::Array(DeclarationArrayType::new(
DeclarationType::FieldElement,
DeclarationConstant::Constant(foo_const_id.clone()),
)),
)),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("foo", "main")
.signature(DeclarationSignature::new().inputs(vec![]).outputs(vec![])),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![],
signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![]),
}),
)
.into(),
],
};
let main_foo_const_id = CanonicalConstantIdentifier::new("FOO", "main".into());
let main_bar_const_id = CanonicalConstantIdentifier::new("BAR", "main".into());
let main_baz_const_id = CanonicalConstantIdentifier::new("BAZ", "main".into());
let main_module = TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
main_foo_const_id.clone(),
TypedConstantSymbol::There(foo_const_id.clone()),
)
.into(),
TypedConstantSymbolDeclaration::new(
main_bar_const_id.clone(),
TypedConstantSymbol::There(bar_const_id),
)
.into(),
TypedConstantSymbolDeclaration::new(
main_baz_const_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::Array(
ArrayExpressionInner::Identifier(main_bar_const_id.clone().into())
.annotate(Type::FieldElement, main_foo_const_id.clone()),
),
DeclarationType::Array(DeclarationArrayType::new(
DeclarationType::FieldElement,
DeclarationConstant::Constant(foo_const_id.clone()),
)),
)),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Identifier(Identifier::from(
main_foo_const_id.clone(),
))
.into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
}),
)
.into(),
],
};
let program = TypedProgram {
main: "main".into(),
modules: vec![
("main".into(), main_module),
("foo".into(), foo_module.clone()),
]
.into_iter()
.collect(),
};
let program = ConstantResolver::inline(program);
let expected_main_module = TypedModule {
symbols: vec![
TypedConstantSymbolDeclaration::new(
main_foo_const_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
FieldElementExpression::Number(Bn128Field::from(2)).into(),
DeclarationType::FieldElement,
)),
)
.into(),
TypedConstantSymbolDeclaration::new(
main_bar_const_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::Array(
ArrayExpressionInner::Repeat(
box FieldElementExpression::Number(Bn128Field::from(1)).into(),
box UExpression::from(foo_const_id.clone()),
)
.annotate(Type::FieldElement, foo_const_id.clone()),
),
DeclarationType::Array(DeclarationArrayType::new(
DeclarationType::FieldElement,
DeclarationConstant::Constant(foo_const_id.clone()),
)),
)),
)
.into(),
TypedConstantSymbolDeclaration::new(
main_baz_const_id.clone(),
TypedConstantSymbol::Here(TypedConstant::new(
TypedExpression::Array(
ArrayExpressionInner::Identifier(main_bar_const_id.into())
.annotate(Type::FieldElement, main_foo_const_id.clone()),
),
DeclarationType::Array(DeclarationArrayType::new(
DeclarationType::FieldElement,
DeclarationConstant::Constant(foo_const_id.clone()),
)),
)),
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![
FieldElementExpression::Identifier(Identifier::from(
main_foo_const_id.clone(),
))
.into(),
])],
signature: DeclarationSignature::new()
.inputs(vec![])
.outputs(vec![DeclarationType::FieldElement]),
}),
)
.into(),
],
};
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
main: "main".into(),
modules: vec![
("main".into(), expected_main_module),
("foo".into(), foo_module),
]
.into_iter()
.collect(),
};
assert_eq!(program, expected_program)
}
}

View file

@ -126,7 +126,7 @@ impl<'ast, T: Field> Flattener<T> {
fn fold_declaration_parameter(
&mut self,
p: typed_absy::DeclarationParameter<'ast>,
p: typed_absy::DeclarationParameter<'ast, T>,
) -> Vec<zir::Parameter<'ast>> {
let private = p.private;
self.fold_variable(crate::typed_absy::variable::try_from_g_variable(p.id).unwrap())
@ -1093,7 +1093,7 @@ fn fold_function<'ast, T: Field>(
statements: main_statements_buffer,
signature: typed_absy::types::ConcreteSignature::try_from(
crate::typed_absy::types::try_from_g_signature::<
crate::typed_absy::types::DeclarationConstant<'ast>,
crate::typed_absy::types::DeclarationConstant<'ast, T>,
crate::typed_absy::UExpression<'ast, T>,
>(fun.signature)
.unwrap(),
@ -1139,14 +1139,12 @@ fn fold_program<'ast, T: Field>(
let main_module = p.modules.remove(&p.main).unwrap();
let main_function = main_module
.functions
.into_iter()
.find(|(key, _)| key.id == "main")
.into_functions_iter()
.find(|d| d.key.id == "main")
.unwrap()
.1;
.symbol;
let main_function = match main_function {
typed_absy::TypedFunctionSymbol::Here(f) => f,
typed_absy::TypedFunctionSymbol::Here(main) => main,
_ => unreachable!(),
};

View file

@ -6,9 +6,10 @@
mod branch_isolator;
mod constant_argument_checker;
mod constant_inliner;
mod constant_resolver;
mod flat_propagation;
mod flatten_complex_types;
mod out_of_bounds;
mod propagation;
mod reducer;
mod uint_optimizer;
@ -19,6 +20,7 @@ mod zir_propagation;
use self::branch_isolator::Isolator;
use self::constant_argument_checker::ConstantArgumentChecker;
use self::flatten_complex_types::Flattener;
use self::out_of_bounds::OutOfBoundsChecker;
use self::propagation::Propagator;
use self::reducer::reduce_program;
use self::uint_optimizer::UintOptimizer;
@ -26,7 +28,7 @@ use self::unconstrained_vars::UnconstrainedVariableDetector;
use self::variable_write_remover::VariableWriteRemover;
use crate::compile::CompileConfig;
use crate::ir::Prog;
use crate::static_analysis::constant_inliner::ConstantInliner;
use crate::static_analysis::constant_resolver::ConstantResolver;
use crate::static_analysis::zir_propagation::ZirPropagator;
use crate::typed_absy::{abi::Abi, TypedProgram};
use crate::zir::ZirProgram;
@ -46,14 +48,8 @@ pub enum Error {
Propagation(self::propagation::Error),
ZirPropagation(self::zir_propagation::Error),
NonConstantArgument(self::constant_argument_checker::Error),
ConstantInliner(self::constant_inliner::Error),
UnconstrainedVariable(self::unconstrained_vars::Error),
}
impl From<constant_inliner::Error> for Error {
fn from(e: self::constant_inliner::Error) -> Self {
Error::ConstantInliner(e)
}
OutOfBounds(self::out_of_bounds::Error),
}
impl From<reducer::Error> for Error {
@ -74,6 +70,12 @@ impl From<zir_propagation::Error> for Error {
}
}
impl From<out_of_bounds::Error> for Error {
fn from(e: out_of_bounds::Error) -> Self {
Error::OutOfBounds(e)
}
}
impl From<constant_argument_checker::Error> for Error {
fn from(e: constant_argument_checker::Error) -> Self {
Error::NonConstantArgument(e)
@ -93,8 +95,8 @@ impl fmt::Display for Error {
Error::Propagation(e) => write!(f, "{}", e),
Error::ZirPropagation(e) => write!(f, "{}", e),
Error::NonConstantArgument(e) => write!(f, "{}", e),
Error::ConstantInliner(e) => write!(f, "{}", e),
Error::UnconstrainedVariable(e) => write!(f, "{}", e),
Error::OutOfBounds(e) => write!(f, "{}", e),
}
}
}
@ -103,7 +105,7 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
pub fn analyse(self, config: &CompileConfig) -> Result<(ZirProgram<'ast, T>, Abi), Error> {
// inline user-defined constants
log::debug!("Static analyser: Inline constants");
let r = ConstantInliner::inline(self).map_err(Error::from)?;
let r = ConstantResolver::inline(self);
log::trace!("\n{}", r);
// isolate branches
@ -141,6 +143,11 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
let r = ConstantArgumentChecker::check(r).map_err(Error::from)?;
log::trace!("\n{}", r);
// detect out of bounds reads and writes
log::debug!("Static analyser: Detect out of bound accesses");
let r = OutOfBoundsChecker::check(r).map_err(Error::from)?;
log::trace!("\n{}", r);
// convert to zir, removing complex types
log::debug!("Static analyser: Convert to zir");
let zir = Flattener::flatten(r);

View file

@ -0,0 +1,78 @@
use crate::typed_absy::{
result_folder::*, Expr, SelectExpression, SelectOrExpression, Type, TypedAssignee,
TypedProgram, UExpressionInner,
};
use std::fmt;
use zokrates_field::Field;
#[derive(Default)]
pub struct OutOfBoundsChecker;
#[derive(Debug)]
pub struct Error(String);
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl OutOfBoundsChecker {
pub fn check<T: Field>(p: TypedProgram<T>) -> Result<TypedProgram<T>, Error> {
Self::default().fold_program(p)
}
}
impl<'ast, T: Field> ResultFolder<'ast, T> for OutOfBoundsChecker {
type Error = Error;
fn fold_select_expression<E: Expr<'ast, T>>(
&mut self,
_: &E::Ty,
s: SelectExpression<'ast, T, E>,
) -> Result<SelectOrExpression<'ast, T, E>, Self::Error> {
match (s.index.as_inner(), s.array.size().as_inner()) {
(UExpressionInner::Value(index), UExpressionInner::Value(size)) if index >= size => {
Err(Error(format!(
"Out of bounds access `{}` because `{}` has size {}",
s, s.array, size
)))
}
_ => Ok(SelectOrExpression::Select(s)),
}
}
fn fold_assignee(
&mut self,
a: TypedAssignee<'ast, T>,
) -> Result<TypedAssignee<'ast, T>, Error> {
match a {
TypedAssignee::Select(box array, box index) => {
use crate::typed_absy::Typed;
let array = self.fold_assignee(array)?;
let size = match array.get_type() {
Type::Array(array_ty) => match array_ty.size.as_inner() {
UExpressionInner::Value(size) => *size,
_ => unreachable!(),
},
_ => unreachable!(),
};
match index.as_inner() {
UExpressionInner::Value(i) if i >= &size => Err(Error(format!(
"Out of bounds write to `{}` because `{}` has size {}",
TypedAssignee::Select(box array.clone(), box index),
array,
size
))),
_ => Ok(TypedAssignee::Select(
box self.fold_assignee(array)?,
box self.fold_uint_expression(index)?,
)),
}
}
a => fold_assignee(self, a),
}
}
}

View file

@ -16,7 +16,7 @@ use std::convert::{TryFrom, TryInto};
use std::fmt;
use zokrates_field::Field;
type Constants<'ast, T> = HashMap<Identifier<'ast>, TypedExpression<'ast, T>>;
pub type Constants<'ast, T> = HashMap<Identifier<'ast>, TypedExpression<'ast, T>>;
#[derive(Debug, PartialEq)]
pub enum Error {
@ -45,6 +45,7 @@ impl fmt::Display for Error {
}
}
#[derive(Debug)]
pub struct Propagator<'ast, 'a, T: Field> {
// 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
@ -149,21 +150,17 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> {
})
}
fn fold_module(&mut self, m: TypedModule<'ast, T>) -> Result<TypedModule<'ast, T>, Error> {
Ok(TypedModule {
functions: m
.functions
.into_iter()
.map(|(key, fun)| {
if key.id == "main" {
self.fold_function_symbol(fun).map(|f| (key, f))
} else {
Ok((key, fun))
}
})
.collect::<Result<_, _>>()?,
..m
})
fn fold_function_symbol_declaration(
&mut self,
s: TypedFunctionSymbolDeclaration<'ast, T>,
) -> Result<TypedFunctionSymbolDeclaration<'ast, T>, Error> {
if s.key.id == "main" {
let key = s.key;
self.fold_function_symbol(s.symbol)
.map(|f| TypedFunctionSymbolDeclaration { key, symbol: f })
} else {
Ok(s)
}
}
fn fold_function(

View file

@ -0,0 +1,169 @@
// given a (partial) map of values for program constants, replace where applicable constants by their value
use crate::static_analysis::reducer::ConstantDefinitions;
use crate::typed_absy::{
folder::*, ArrayExpression, ArrayExpressionInner, ArrayType, BooleanExpression, CoreIdentifier,
DeclarationConstant, Expr, FieldElementExpression, Identifier, StructExpression,
StructExpressionInner, StructType, TypedProgram, TypedSymbolDeclaration, UBitwidth,
UExpression, UExpressionInner,
};
use zokrates_field::Field;
use std::convert::{TryFrom, TryInto};
pub struct ConstantsReader<'a, 'ast, T> {
constants: &'a ConstantDefinitions<'ast, T>,
}
impl<'a, 'ast, T: Field> ConstantsReader<'a, 'ast, T> {
pub fn with_constants(constants: &'a ConstantDefinitions<'ast, T>) -> Self {
Self { constants }
}
pub fn read_into_program(&mut self, p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
self.fold_program(p)
}
pub fn read_into_symbol_declaration(
&mut self,
d: TypedSymbolDeclaration<'ast, T>,
) -> TypedSymbolDeclaration<'ast, T> {
self.fold_symbol_declaration(d)
}
}
impl<'a, 'ast, T: Field> Folder<'ast, T> for ConstantsReader<'a, 'ast, T> {
fn fold_field_expression(
&mut self,
e: FieldElementExpression<'ast, T>,
) -> FieldElementExpression<'ast, T> {
match e {
FieldElementExpression::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}) => {
assert_eq!(version, 0);
match self.constants.get(&c).cloned() {
Some(v) => v.try_into().unwrap(),
None => FieldElementExpression::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}),
}
}
e => fold_field_expression(self, e),
}
}
fn fold_boolean_expression(
&mut self,
e: BooleanExpression<'ast, T>,
) -> BooleanExpression<'ast, T> {
match e {
BooleanExpression::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}) => {
assert_eq!(version, 0);
match self.constants.get(&c).cloned() {
Some(v) => v.try_into().unwrap(),
None => BooleanExpression::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}),
}
}
e => fold_boolean_expression(self, e),
}
}
fn fold_uint_expression_inner(
&mut self,
ty: UBitwidth,
e: UExpressionInner<'ast, T>,
) -> UExpressionInner<'ast, T> {
match e {
UExpressionInner::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}) => {
assert_eq!(version, 0);
match self.constants.get(&c).cloned() {
Some(v) => UExpression::try_from(v).unwrap().into_inner(),
None => UExpressionInner::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}),
}
}
e => fold_uint_expression_inner(self, ty, e),
}
}
fn fold_array_expression_inner(
&mut self,
ty: &ArrayType<'ast, T>,
e: ArrayExpressionInner<'ast, T>,
) -> ArrayExpressionInner<'ast, T> {
match e {
ArrayExpressionInner::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}) => {
assert_eq!(version, 0);
match self.constants.get(&c).cloned() {
Some(v) => ArrayExpression::try_from(v).unwrap().into_inner(),
None => ArrayExpressionInner::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}),
}
}
e => fold_array_expression_inner(self, ty, e),
}
}
fn fold_struct_expression_inner(
&mut self,
ty: &StructType<'ast, T>,
e: StructExpressionInner<'ast, T>,
) -> StructExpressionInner<'ast, T> {
match e {
StructExpressionInner::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}) => {
assert_eq!(version, 0);
match self.constants.get(&c).cloned() {
Some(v) => StructExpression::try_from(v).unwrap().into_inner(),
None => StructExpressionInner::Identifier(Identifier {
id: CoreIdentifier::Constant(c),
version,
}),
}
}
e => fold_struct_expression_inner(self, ty, e),
}
}
fn fold_declaration_constant(
&mut self,
c: DeclarationConstant<'ast, T>,
) -> DeclarationConstant<'ast, T> {
match c {
DeclarationConstant::Constant(c) => {
let c = self.fold_canonical_constant_identifier(c);
match self.constants.get(&c).cloned() {
Some(e) => match UExpression::try_from(e).unwrap().into_inner() {
UExpressionInner::Value(v) => DeclarationConstant::Concrete(v as u32),
_ => unreachable!(),
},
None => DeclarationConstant::Constant(c),
}
}
c => fold_declaration_constant(self, c),
}
}
}

View file

@ -0,0 +1,163 @@
// A folder to inline all constant definitions down to a single literal and register them in the state for later use.
use crate::static_analysis::reducer::{
constants_reader::ConstantsReader, reduce_function, ConstantDefinitions, Error,
};
use crate::typed_absy::{
result_folder::*, types::ConcreteGenericsAssignment, OwnedTypedModuleId, TypedConstant,
TypedConstantSymbol, TypedConstantSymbolDeclaration, TypedModuleId, TypedProgram,
TypedSymbolDeclaration, UExpression,
};
use std::collections::{BTreeMap, HashSet};
use zokrates_field::Field;
pub struct ConstantsWriter<'ast, T> {
treated: HashSet<OwnedTypedModuleId>,
constants: ConstantDefinitions<'ast, T>,
location: OwnedTypedModuleId,
program: TypedProgram<'ast, T>,
}
impl<'ast, T: Field> ConstantsWriter<'ast, T> {
pub fn with_program(program: TypedProgram<'ast, T>) -> Self {
ConstantsWriter {
constants: ConstantDefinitions::default(),
location: program.main.clone(),
treated: HashSet::default(),
program,
}
}
fn change_location(&mut self, location: OwnedTypedModuleId) -> OwnedTypedModuleId {
let prev = self.location.clone();
self.location = location;
self.treated.insert(self.location.clone());
prev
}
fn treated(&self, id: &TypedModuleId) -> bool {
self.treated.contains(id)
}
fn update_program(&mut self) {
let mut p = TypedProgram {
main: "".into(),
modules: BTreeMap::default(),
};
std::mem::swap(&mut self.program, &mut p);
self.program = ConstantsReader::with_constants(&self.constants).read_into_program(p);
}
fn update_symbol_declaration(
&self,
d: TypedSymbolDeclaration<'ast, T>,
) -> TypedSymbolDeclaration<'ast, T> {
ConstantsReader::with_constants(&self.constants).read_into_symbol_declaration(d)
}
}
impl<'ast, T: Field> ResultFolder<'ast, T> for ConstantsWriter<'ast, T> {
type Error = Error;
fn fold_module_id(
&mut self,
id: OwnedTypedModuleId,
) -> Result<OwnedTypedModuleId, Self::Error> {
// anytime we encounter a module id, visit the corresponding module if it hasn't been done yet
if !self.treated(&id) {
let current_m_id = self.change_location(id.clone());
// I did not find a way to achieve this without cloning the module. Assuming we do not clone:
// to fold the module, we need to consume it, so it gets removed from the modules
// but to inline the calls while folding the module, all modules must be present
// therefore we clone...
// this does not lead to a module being folded more than once, as the first time
// we change location to this module, it's added to the `treated` set
let m = self.program.modules.get(&id).cloned().unwrap();
let m = self.fold_module(m)?;
self.program.modules.insert(id.clone(), m);
self.change_location(current_m_id);
}
Ok(id)
}
fn fold_symbol_declaration(
&mut self,
s: TypedSymbolDeclaration<'ast, T>,
) -> Result<TypedSymbolDeclaration<'ast, T>, Self::Error> {
// before we treat the symbol, propagate the constants into it, as may be using constants defined earlier in this module.
let s = self.update_symbol_declaration(s);
let s = fold_symbol_declaration(self, s)?;
// after we treat the symbol, propagate again, as treating this symbol may have triggered checking another module, resolving new constants which this symbol may be using.
Ok(self.update_symbol_declaration(s))
}
fn fold_constant_symbol_declaration(
&mut self,
d: TypedConstantSymbolDeclaration<'ast, T>,
) -> Result<TypedConstantSymbolDeclaration<'ast, T>, Self::Error> {
let id = self.fold_canonical_constant_identifier(d.id)?;
match d.symbol {
TypedConstantSymbol::Here(c) => {
let c = self.fold_constant(c)?;
use crate::typed_absy::{DeclarationSignature, TypedFunction, TypedStatement};
// wrap this expression in a function
let wrapper = TypedFunction {
arguments: vec![],
statements: vec![TypedStatement::Return(vec![c.expression])],
signature: DeclarationSignature::new().outputs(vec![c.ty.clone()]),
};
let mut inlined_wrapper = reduce_function(
wrapper,
ConcreteGenericsAssignment::default(),
&self.program,
)?;
if let TypedStatement::Return(mut expressions) =
inlined_wrapper.statements.pop().unwrap()
{
assert_eq!(expressions.len(), 1);
let constant_expression = expressions.pop().unwrap();
use crate::typed_absy::Constant;
if !constant_expression.is_constant() {
return Err(Error::ConstantReduction(id.id.to_string(), id.module));
};
use crate::typed_absy::Typed;
if crate::typed_absy::types::try_from_g_type::<_, UExpression<'ast, T>>(
c.ty.clone(),
)
.unwrap()
== constant_expression.get_type()
{
// add to the constant map
self.constants
.insert(id.clone(), constant_expression.clone());
// after we reduced a constant, propagate it through the whole program
self.update_program();
Ok(TypedConstantSymbolDeclaration {
id,
symbol: TypedConstantSymbol::Here(TypedConstant {
expression: constant_expression,
ty: c.ty,
}),
})
} else {
Err(Error::Type(format!("Expression of type `{}` cannot be assigned to constant `{}` of type `{}`", constant_expression.get_type(), id, c.ty)))
}
} else {
Err(Error::ConstantReduction(id.id.to_string(), id.module))
}
}
_ => unreachable!("all constants should be local"),
}
}
}

View file

@ -35,13 +35,13 @@ use crate::typed_absy::Identifier;
use crate::typed_absy::TypedAssignee;
use crate::typed_absy::{
ConcreteFunctionKey, ConcreteSignature, ConcreteVariable, DeclarationFunctionKey, Expr,
Signature, TypedExpression, TypedFunctionSymbol, TypedProgram, TypedStatement, Types,
UExpression, UExpressionInner, Variable,
Signature, TypedExpression, TypedFunctionSymbol, TypedFunctionSymbolDeclaration, TypedProgram,
TypedStatement, Types, UExpression, UExpressionInner, Variable,
};
use zokrates_field::Field;
pub enum InlineError<'ast, T> {
Generic(DeclarationFunctionKey<'ast>, ConcreteFunctionKey<'ast>),
Generic(DeclarationFunctionKey<'ast, T>, ConcreteFunctionKey<'ast>),
Flat(
FlatEmbed,
Vec<u32>,
@ -49,7 +49,7 @@ pub enum InlineError<'ast, T> {
Types<'ast, T>,
),
NonConstant(
DeclarationFunctionKey<'ast>,
DeclarationFunctionKey<'ast, T>,
Vec<Option<UExpression<'ast, T>>>,
Vec<TypedExpression<'ast, T>>,
Types<'ast, T>,
@ -57,20 +57,20 @@ pub enum InlineError<'ast, T> {
}
fn get_canonical_function<'ast, T: Field>(
function_key: DeclarationFunctionKey<'ast>,
function_key: DeclarationFunctionKey<'ast, T>,
program: &TypedProgram<'ast, T>,
) -> (DeclarationFunctionKey<'ast>, TypedFunctionSymbol<'ast, T>) {
match program
) -> TypedFunctionSymbolDeclaration<'ast, T> {
let s = program
.modules
.get(&function_key.module)
.unwrap()
.functions
.iter()
.find(|(key, _)| function_key == **key)
.unwrap()
{
(_, TypedFunctionSymbol::There(key)) => get_canonical_function(key.clone(), &program),
(key, s) => (key.clone(), s.clone()),
.functions_iter()
.find(|d| d.key == function_key)
.unwrap();
match &s.symbol {
TypedFunctionSymbol::There(key) => get_canonical_function(key.clone(), &program),
_ => s.clone(),
}
}
@ -80,7 +80,7 @@ type InlineResult<'ast, T> = Result<
>;
pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>(
k: DeclarationFunctionKey<'ast>,
k: DeclarationFunctionKey<'ast, T>,
generics: Vec<Option<UExpression<'ast, T>>>,
arguments: Vec<TypedExpression<'ast, T>>,
output: &E::Ty,
@ -134,7 +134,7 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>(
}
};
let (decl_key, symbol) = get_canonical_function(k.clone(), program);
let decl = get_canonical_function(k.clone(), program);
// get an assignment of generics for this call site
let assignment: ConcreteGenericsAssignment<'ast> = k
@ -144,18 +144,18 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>(
InlineError::Generic(
k.clone(),
ConcreteFunctionKey {
module: decl_key.module.clone(),
id: decl_key.id,
module: decl.key.module.clone(),
id: decl.key.id,
signature: inferred_signature.clone(),
},
)
})?;
let f = match symbol {
let f = match decl.symbol {
TypedFunctionSymbol::Here(f) => Ok(f),
TypedFunctionSymbol::Flat(e) => Err(InlineError::Flat(
e,
e.generics(&assignment),
e.generics::<T>(&assignment),
arguments.clone(),
output_types,
)),
@ -169,7 +169,7 @@ pub fn inline_call<'a, 'ast, T: Field, E: Expr<'ast, T>>(
Output::Incomplete(statements, for_loop_versions) => (statements, Some(for_loop_versions)),
};
let call_log = TypedStatement::PushCallLog(decl_key.clone(), assignment.clone());
let call_log = TypedStatement::PushCallLog(decl.key.clone(), assignment.clone());
let input_bindings: Vec<TypedStatement<'ast, T>> = ssa_f
.arguments

View file

@ -11,6 +11,8 @@
// - unroll loops
// - inline function calls. This includes applying shallow-ssa on the target function
mod constants_reader;
mod constants_writer;
mod inline;
mod shallow_ssa;
@ -18,26 +20,33 @@ use self::inline::{inline_call, InlineError};
use crate::typed_absy::result_folder::*;
use crate::typed_absy::types::ConcreteGenericsAssignment;
use crate::typed_absy::types::GGenericsAssignment;
use crate::typed_absy::CanonicalConstantIdentifier;
use crate::typed_absy::Folder;
use std::collections::HashMap;
use crate::typed_absy::{
ArrayExpressionInner, ArrayType, BlockExpression, CoreIdentifier, Expr, FunctionCall,
FunctionCallExpression, FunctionCallOrExpression, Id, Identifier, TypedExpression,
TypedExpressionList, TypedExpressionListInner, TypedFunction, TypedFunctionSymbol, TypedModule,
TypedProgram, TypedStatement, UExpression, UExpressionInner, Variable,
FunctionCallExpression, FunctionCallOrExpression, Id, Identifier, OwnedTypedModuleId,
TypedExpression, TypedExpressionList, TypedExpressionListInner, TypedFunction,
TypedFunctionSymbol, TypedFunctionSymbolDeclaration, TypedModule, TypedProgram, TypedStatement,
UExpression, UExpressionInner, Variable,
};
use zokrates_field::Field;
use self::constants_writer::ConstantsWriter;
use self::shallow_ssa::ShallowTransformer;
use crate::static_analysis::Propagator;
use crate::static_analysis::propagation::{Constants, Propagator};
use std::fmt;
const MAX_FOR_LOOP_SIZE: u128 = 2u128.pow(20);
// A map to register the canonical value of all constants. The values must be literals.
pub type ConstantDefinitions<'ast, T> =
HashMap<CanonicalConstantIdentifier<'ast>, TypedExpression<'ast, T>>;
// An SSA version map, giving access to the latest version number for each identifier
pub type Versions<'ast> = HashMap<CoreIdentifier<'ast>, usize>;
@ -55,6 +64,8 @@ pub enum Error {
// TODO: give more details about what's blocking the progress
NoProgress,
LoopTooLarge(u128),
ConstantReduction(String, OwnedTypedModuleId),
Type(String),
}
impl fmt::Display for Error {
@ -68,6 +79,8 @@ impl fmt::Display for Error {
Error::GenericsInMain => write!(f, "Cannot generate code for generic function"),
Error::NoProgress => write!(f, "Failed to unroll or inline program. Check that main function arguments aren't used as array size or for-loop bounds"),
Error::LoopTooLarge(size) => write!(f, "Found a loop of size {}, which is larger than the maximum allowed of {}. Check the loop bounds, especially for underflows", size, MAX_FOR_LOOP_SIZE),
Error::ConstantReduction(name, module) => write!(f, "Failed to reduce constant `{}` in module `{}` to a literal, try simplifying its declaration", name, module.display()),
Error::Type(message) => write!(f, "{}", message),
}
}
}
@ -159,6 +172,7 @@ fn register<'ast>(
}
}
#[derive(Debug)]
struct Reducer<'ast, 'a, T> {
statement_buffer: Vec<TypedStatement<'ast, T>>,
for_loop_versions: Vec<Versions<'ast>>,
@ -304,6 +318,13 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
})
}
fn fold_canonical_constant_identifier(
&mut self,
_: CanonicalConstantIdentifier<'ast>,
) -> Result<CanonicalConstantIdentifier<'ast>, Self::Error> {
unreachable!("canonical constant identifiers should not be folded, they should be inlined")
}
fn fold_statement(
&mut self,
s: TypedStatement<'ast, T>,
@ -487,15 +508,21 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
}
pub fn reduce_program<T: Field>(p: TypedProgram<T>) -> Result<TypedProgram<T>, Error> {
// inline all constants and replace them in the program
let mut constants_writer = ConstantsWriter::with_program(p.clone());
let p = constants_writer.fold_program(p)?;
// inline starting from main
let main_module = p.modules.get(&p.main).unwrap().clone();
let (main_key, main_function) = main_module
.functions
.iter()
.find(|(k, _)| k.id == "main")
let decl = main_module
.functions_iter()
.find(|d| d.key.id == "main")
.unwrap();
let main_function = match main_function {
let main_function = match &decl.symbol {
TypedFunctionSymbol::Here(f) => f.clone(),
_ => unreachable!(),
};
@ -509,13 +536,11 @@ pub fn reduce_program<T: Field>(p: TypedProgram<T>) -> Result<TypedProgram<T>, E
modules: vec![(
p.main.clone(),
TypedModule {
functions: vec![(
main_key.clone(),
symbols: vec![TypedFunctionSymbolDeclaration::new(
decl.key.clone(),
TypedFunctionSymbol::Here(main_function),
)]
.into_iter()
.collect(),
constants: Default::default(),
)
.into()],
},
)]
.into_iter()
@ -533,7 +558,9 @@ fn reduce_function<'ast, T: Field>(
) -> Result<TypedFunction<'ast, T>, Error> {
let mut versions = Versions::default();
match ShallowTransformer::transform(f, &generics, &mut versions) {
let mut constants = Constants::default();
let f = match ShallowTransformer::transform(f, &generics, &mut versions) {
Output::Complete(f) => Ok(f),
Output::Incomplete(new_f, new_for_loop_versions) => {
let mut for_loop_versions = new_for_loop_versions;
@ -542,8 +569,6 @@ fn reduce_function<'ast, T: Field>(
let mut substitutions = Substitutions::default();
let mut constants: HashMap<Identifier<'ast>, TypedExpression<'ast, T>> = HashMap::new();
let mut hash = None;
loop {
@ -600,7 +625,11 @@ fn reduce_function<'ast, T: Field>(
}
}
}
}
}?;
Propagator::with_constants(&mut constants)
.fold_function(f)
.map_err(|e| Error::Incompatible(format!("{}", e)))
}
fn compute_hash<T: Field>(f: &TypedFunction<T>) -> u64 {
@ -710,27 +739,26 @@ mod tests {
modules: vec![(
"main".into(),
TypedModule {
functions: vec![
(
symbols: vec![
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "foo").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(foo),
),
(
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(main),
),
]
.into_iter()
.collect(),
constants: Default::default(),
)
.into(),
],
},
)]
.into_iter()
@ -786,17 +814,15 @@ mod tests {
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
symbols: vec![TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(expected_main),
)]
.into_iter()
.collect(),
constants: Default::default(),
)
.into()],
},
)]
.into_iter()
@ -913,24 +939,23 @@ mod tests {
modules: vec![(
"main".into(),
TypedModule {
functions: vec![
(
symbols: vec![
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "foo")
.signature(foo_signature.clone()),
TypedFunctionSymbol::Here(foo),
),
(
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(main),
),
]
.into_iter()
.collect(),
constants: Default::default(),
)
.into(),
],
},
)]
.into_iter()
@ -1005,17 +1030,15 @@ mod tests {
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
symbols: vec![TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(expected_main),
)]
.into_iter()
.collect(),
constants: Default::default(),
)
.into()],
},
)]
.into_iter()
@ -1141,24 +1164,23 @@ mod tests {
modules: vec![(
"main".into(),
TypedModule {
functions: vec![
(
symbols: vec![
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "foo")
.signature(foo_signature.clone()),
TypedFunctionSymbol::Here(foo),
),
(
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(main),
),
]
.into_iter()
.collect(),
constants: Default::default(),
)
.into(),
],
},
)]
.into_iter()
@ -1233,17 +1255,15 @@ mod tests {
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
symbols: vec![TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new()
.inputs(vec![DeclarationType::FieldElement])
.outputs(vec![DeclarationType::FieldElement]),
),
TypedFunctionSymbol::Here(expected_main),
)]
.into_iter()
.collect(),
constants: Default::default(),
)
.into()],
},
)]
.into_iter()
@ -1399,25 +1419,25 @@ mod tests {
modules: vec![(
"main".into(),
TypedModule {
functions: vec![
(
symbols: vec![
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "bar")
.signature(bar_signature.clone()),
TypedFunctionSymbol::Here(bar),
),
(
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "foo")
.signature(foo_signature.clone()),
TypedFunctionSymbol::Here(foo),
),
(
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main"),
TypedFunctionSymbol::Here(main),
),
]
.into_iter()
.collect(),
constants: Default::default(),
)
.into(),
],
},
)]
.into_iter()
@ -1459,14 +1479,12 @@ mod tests {
modules: vec![(
"main".into(),
TypedModule {
functions: vec![(
symbols: vec![TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main")
.signature(DeclarationSignature::new()),
TypedFunctionSymbol::Here(expected_main),
)]
.into_iter()
.collect(),
constants: Default::default(),
)
.into()],
},
)]
.into_iter()
@ -1540,22 +1558,21 @@ mod tests {
modules: vec![(
"main".into(),
TypedModule {
functions: vec![
(
symbols: vec![
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "foo")
.signature(foo_signature.clone()),
TypedFunctionSymbol::Here(foo),
),
(
)
.into(),
TypedFunctionSymbolDeclaration::new(
DeclarationFunctionKey::with_location("main", "main").signature(
DeclarationSignature::new().inputs(vec![]).outputs(vec![]),
),
TypedFunctionSymbol::Here(main),
),
]
.into_iter()
.collect(),
constants: Default::default(),
)
.into(),
],
},
)]
.into_iter()

View file

@ -18,7 +18,7 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Found unconstrained variables during IR analysis (found {} occurrence{})",
"Found unconstrained variables during IR analysis (found {} occurrence{}). If this is intentional, use the `--allow-unconstrained-variables` flag.",
self.0,
if self.0 == 1 { "" } else { "s" }
)
@ -86,7 +86,7 @@ mod tests {
let result = UnconstrainedVariableDetector::detect(&p);
assert_eq!(
result.expect_err("expected an error").to_string(),
"Found unconstrained variables during IR analysis (found 1 occurrence)"
"Found unconstrained variables during IR analysis (found 1 occurrence). If this is intentional, use the `--allow-unconstrained-variables` flag."
);
}

View file

@ -35,15 +35,15 @@ mod tests {
};
use crate::typed_absy::{
parameter::DeclarationParameter, variable::DeclarationVariable, ConcreteType,
TypedFunction, TypedFunctionSymbol, TypedModule, TypedProgram,
TypedFunction, TypedFunctionSymbol, TypedFunctionSymbolDeclaration, TypedModule,
TypedProgram,
};
use std::collections::HashMap;
use std::collections::BTreeMap;
use zokrates_field::Bn128Field;
#[test]
fn generate_abi_from_typed_ast() {
let mut functions = HashMap::new();
functions.insert(
let symbols = vec![TypedFunctionSymbolDeclaration::new(
ConcreteFunctionKey::with_location("main", "main").into(),
TypedFunctionSymbol::Here(TypedFunction {
arguments: vec![
@ -62,16 +62,11 @@ mod tests {
.outputs(vec![ConcreteType::FieldElement])
.into(),
}),
);
)
.into()];
let mut modules = HashMap::new();
modules.insert(
"main".into(),
TypedModule {
functions,
constants: Default::default(),
},
);
let mut modules = BTreeMap::new();
modules.insert("main".into(), TypedModule { symbols });
let typed_ast: TypedProgram<Bn128Field> = TypedProgram {
main: "main".into(),

View file

@ -47,6 +47,27 @@ pub trait Folder<'ast, T: Field>: Sized {
fold_module(self, m)
}
fn fold_symbol_declaration(
&mut self,
s: TypedSymbolDeclaration<'ast, T>,
) -> TypedSymbolDeclaration<'ast, T> {
fold_symbol_declaration(self, s)
}
fn fold_function_symbol_declaration(
&mut self,
s: TypedFunctionSymbolDeclaration<'ast, T>,
) -> TypedFunctionSymbolDeclaration<'ast, T> {
fold_function_symbol_declaration(self, s)
}
fn fold_constant_symbol_declaration(
&mut self,
s: TypedConstantSymbolDeclaration<'ast, T>,
) -> TypedConstantSymbolDeclaration<'ast, T> {
fold_constant_symbol_declaration(self, s)
}
fn fold_constant(&mut self, c: TypedConstant<'ast, T>) -> TypedConstant<'ast, T> {
fold_constant(self, c)
}
@ -67,8 +88,8 @@ pub trait Folder<'ast, T: Field>: Sized {
fn fold_declaration_function_key(
&mut self,
key: DeclarationFunctionKey<'ast>,
) -> DeclarationFunctionKey<'ast> {
key: DeclarationFunctionKey<'ast, T>,
) -> DeclarationFunctionKey<'ast, T> {
fold_declaration_function_key(self, key)
}
@ -76,18 +97,24 @@ pub trait Folder<'ast, T: Field>: Sized {
fold_function(self, f)
}
fn fold_signature(&mut self, s: DeclarationSignature<'ast>) -> DeclarationSignature<'ast> {
fn fold_signature(
&mut self,
s: DeclarationSignature<'ast, T>,
) -> DeclarationSignature<'ast, T> {
fold_signature(self, s)
}
fn fold_declaration_constant(
&mut self,
c: DeclarationConstant<'ast>,
) -> DeclarationConstant<'ast> {
c: DeclarationConstant<'ast, T>,
) -> DeclarationConstant<'ast, T> {
fold_declaration_constant(self, c)
}
fn fold_parameter(&mut self, p: DeclarationParameter<'ast>) -> DeclarationParameter<'ast> {
fn fold_parameter(
&mut self,
p: DeclarationParameter<'ast, T>,
) -> DeclarationParameter<'ast, T> {
DeclarationParameter {
id: self.fold_declaration_variable(p.id),
..p
@ -107,8 +134,8 @@ pub trait Folder<'ast, T: Field>: Sized {
fn fold_declaration_variable(
&mut self,
v: DeclarationVariable<'ast>,
) -> DeclarationVariable<'ast> {
v: DeclarationVariable<'ast, T>,
) -> DeclarationVariable<'ast, T> {
DeclarationVariable {
id: self.fold_name(v.id),
_type: self.fold_declaration_type(v._type),
@ -155,7 +182,7 @@ pub trait Folder<'ast, T: Field>: Sized {
}
}
fn fold_declaration_type(&mut self, t: DeclarationType<'ast>) -> DeclarationType<'ast> {
fn fold_declaration_type(&mut self, t: DeclarationType<'ast, T>) -> DeclarationType<'ast, T> {
use self::GType::*;
match t {
@ -167,8 +194,8 @@ pub trait Folder<'ast, T: Field>: Sized {
fn fold_declaration_array_type(
&mut self,
t: DeclarationArrayType<'ast>,
) -> DeclarationArrayType<'ast> {
t: DeclarationArrayType<'ast, T>,
) -> DeclarationArrayType<'ast, T> {
DeclarationArrayType {
ty: box self.fold_declaration_type(*t.ty),
size: self.fold_declaration_constant(t.size),
@ -177,8 +204,8 @@ pub trait Folder<'ast, T: Field>: Sized {
fn fold_declaration_struct_type(
&mut self,
t: DeclarationStructType<'ast>,
) -> DeclarationStructType<'ast> {
t: DeclarationStructType<'ast, T>,
) -> DeclarationStructType<'ast, T> {
DeclarationStructType {
generics: t
.generics
@ -232,7 +259,6 @@ pub trait Folder<'ast, T: Field>: Sized {
CanonicalConstantIdentifier {
module: self.fold_module_id(i.module),
id: i.id,
ty: box self.fold_declaration_type(*i.ty),
}
}
@ -378,29 +404,48 @@ pub fn fold_module<'ast, T: Field, F: Folder<'ast, T>>(
m: TypedModule<'ast, T>,
) -> TypedModule<'ast, T> {
TypedModule {
constants: m
.constants
symbols: m
.symbols
.into_iter()
.map(|(id, tc)| {
(
f.fold_canonical_constant_identifier(id),
f.fold_constant_symbol(tc),
)
})
.collect(),
functions: m
.functions
.into_iter()
.map(|(key, fun)| {
(
f.fold_declaration_function_key(key),
f.fold_function_symbol(fun),
)
})
.map(|s| f.fold_symbol_declaration(s))
.collect(),
}
}
pub fn fold_symbol_declaration<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
d: TypedSymbolDeclaration<'ast, T>,
) -> TypedSymbolDeclaration<'ast, T> {
match d {
TypedSymbolDeclaration::Function(d) => {
TypedSymbolDeclaration::Function(f.fold_function_symbol_declaration(d))
}
TypedSymbolDeclaration::Constant(d) => {
TypedSymbolDeclaration::Constant(f.fold_constant_symbol_declaration(d))
}
}
}
pub fn fold_function_symbol_declaration<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
d: TypedFunctionSymbolDeclaration<'ast, T>,
) -> TypedFunctionSymbolDeclaration<'ast, T> {
TypedFunctionSymbolDeclaration {
key: f.fold_declaration_function_key(d.key),
symbol: f.fold_function_symbol(d.symbol),
}
}
pub fn fold_constant_symbol_declaration<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
d: TypedConstantSymbolDeclaration<'ast, T>,
) -> TypedConstantSymbolDeclaration<'ast, T> {
TypedConstantSymbolDeclaration {
id: f.fold_canonical_constant_identifier(d.id),
symbol: f.fold_constant_symbol(d.symbol),
}
}
pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
s: TypedStatement<'ast, T>,
@ -904,8 +949,8 @@ pub fn fold_block_expression<'ast, T: Field, E: Fold<'ast, T>, F: Folder<'ast, T
pub fn fold_declaration_function_key<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
key: DeclarationFunctionKey<'ast>,
) -> DeclarationFunctionKey<'ast> {
key: DeclarationFunctionKey<'ast, T>,
) -> DeclarationFunctionKey<'ast, T> {
DeclarationFunctionKey {
module: f.fold_module_id(key.module),
signature: f.fold_signature(key.signature),
@ -957,8 +1002,8 @@ pub fn fold_function<'ast, T: Field, F: Folder<'ast, T>>(
fn fold_signature<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
s: DeclarationSignature<'ast>,
) -> DeclarationSignature<'ast> {
s: DeclarationSignature<'ast, T>,
) -> DeclarationSignature<'ast, T> {
DeclarationSignature {
generics: s.generics,
inputs: s
@ -974,11 +1019,14 @@ fn fold_signature<'ast, T: Field, F: Folder<'ast, T>>(
}
}
fn fold_declaration_constant<'ast, T: Field, F: Folder<'ast, T>>(
_: &mut F,
c: DeclarationConstant<'ast>,
) -> DeclarationConstant<'ast> {
c
pub fn fold_declaration_constant<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
c: DeclarationConstant<'ast, T>,
) -> DeclarationConstant<'ast, T> {
match c {
DeclarationConstant::Expression(e) => DeclarationConstant::Expression(f.fold_expression(e)),
c => c,
}
}
pub fn fold_array_expression<'ast, T: Field, F: Folder<'ast, T>>(
@ -1058,6 +1106,7 @@ pub fn fold_constant<'ast, T: Field, F: Folder<'ast, T>>(
) -> TypedConstant<'ast, T> {
TypedConstant {
expression: f.fold_expression(c.expression),
ty: f.fold_declaration_type(c.ty),
}
}

View file

@ -1,10 +1,12 @@
use crate::typed_absy::CanonicalConstantIdentifier;
use std::convert::TryInto;
use std::fmt;
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
#[derive(Debug, PartialEq, Clone, Hash, Eq, PartialOrd, Ord)]
pub enum CoreIdentifier<'ast> {
Source(&'ast str),
Call(usize),
Constant(CanonicalConstantIdentifier<'ast>),
}
impl<'ast> fmt::Display for CoreIdentifier<'ast> {
@ -12,6 +14,7 @@ impl<'ast> fmt::Display for CoreIdentifier<'ast> {
match self {
CoreIdentifier::Source(s) => write!(f, "{}", s),
CoreIdentifier::Call(i) => write!(f, "#CALL_RETURN_AT_INDEX_{}", i),
CoreIdentifier::Constant(c) => write!(f, "{}/{}", c.module.display(), c.id),
}
}
}
@ -22,8 +25,14 @@ impl<'ast> From<&'ast str> for CoreIdentifier<'ast> {
}
}
impl<'ast> From<CanonicalConstantIdentifier<'ast>> for CoreIdentifier<'ast> {
fn from(s: CanonicalConstantIdentifier<'ast>) -> CoreIdentifier<'ast> {
CoreIdentifier::Constant(s)
}
}
/// A identifier for a variable
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
#[derive(Debug, PartialEq, Clone, Hash, Eq, PartialOrd, Ord)]
pub struct Identifier<'ast> {
/// the id of the variable
pub id: CoreIdentifier<'ast>,
@ -52,6 +61,12 @@ impl<'ast> fmt::Display for Identifier<'ast> {
}
}
impl<'ast> From<CanonicalConstantIdentifier<'ast>> for Identifier<'ast> {
fn from(id: CanonicalConstantIdentifier<'ast>) -> Identifier<'ast> {
Identifier::from(CoreIdentifier::Constant(id))
}
}
impl<'ast> From<&'ast str> for Identifier<'ast> {
fn from(id: &'ast str) -> Identifier<'ast> {
Identifier::from(CoreIdentifier::Source(id))

View file

@ -41,7 +41,7 @@ trait IntegerInference: Sized {
}
impl<'ast, T> IntegerInference for Type<'ast, T> {
type Pattern = DeclarationType<'ast>;
type Pattern = DeclarationType<'ast, T>;
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
match (self, other) {
@ -73,7 +73,7 @@ impl<'ast, T> IntegerInference for Type<'ast, T> {
}
impl<'ast, T> IntegerInference for ArrayType<'ast, T> {
type Pattern = DeclarationArrayType<'ast>;
type Pattern = DeclarationArrayType<'ast, T>;
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
let s0 = self.size;
@ -89,7 +89,7 @@ impl<'ast, T> IntegerInference for ArrayType<'ast, T> {
}
impl<'ast, T> IntegerInference for StructType<'ast, T> {
type Pattern = DeclarationStructType<'ast>;
type Pattern = DeclarationStructType<'ast, T>;
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
Ok(DeclarationStructType {
@ -229,7 +229,7 @@ impl<'ast, T: Field> TypedExpression<'ast, T> {
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub enum IntExpression<'ast, T> {
Value(BigUint),
Pos(Box<IntExpression<'ast, T>>),
@ -426,7 +426,7 @@ impl<'ast, T: Field> FieldElementExpression<'ast, T> {
v,
&DeclarationArrayType::new(
DeclarationType::FieldElement,
DeclarationConstant::Concrete(0),
DeclarationConstant::from(0u32),
),
)
.map_err(|(e, _)| match e {
@ -545,7 +545,7 @@ impl<'ast, T: Field> UExpression<'ast, T> {
v,
&DeclarationArrayType::new(
DeclarationType::Uint(*bitwidth),
DeclarationConstant::Concrete(0),
DeclarationConstant::from(0u32),
),
)
.map_err(|(e, _)| match e {

View file

@ -20,9 +20,9 @@ pub use self::identifier::CoreIdentifier;
pub use self::parameter::{DeclarationParameter, GParameter};
pub use self::types::{
CanonicalConstantIdentifier, ConcreteFunctionKey, ConcreteSignature, ConcreteType,
ConstantIdentifier, DeclarationArrayType, DeclarationFunctionKey, DeclarationSignature,
DeclarationStructType, DeclarationType, GArrayType, GStructType, GType, GenericIdentifier,
IntoTypes, Signature, StructType, Type, Types, UBitwidth,
ConstantIdentifier, DeclarationArrayType, DeclarationConstant, DeclarationFunctionKey,
DeclarationSignature, DeclarationStructType, DeclarationType, GArrayType, GStructType, GType,
GenericIdentifier, IntoTypes, Signature, StructType, Type, Types, UBitwidth,
};
use crate::typed_absy::types::ConcreteGenericsAssignment;
@ -35,7 +35,7 @@ pub use crate::typed_absy::uint::{bitwidth, UExpression, UExpressionInner, UMeta
use crate::embed::FlatEmbed;
use std::collections::HashMap;
use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};
use std::fmt;
@ -54,14 +54,14 @@ pub type OwnedTypedModuleId = PathBuf;
pub type TypedModuleId = Path;
/// A collection of `TypedModule`s
pub type TypedModules<'ast, T> = HashMap<OwnedTypedModuleId, TypedModule<'ast, T>>;
pub type TypedModules<'ast, T> = BTreeMap<OwnedTypedModuleId, TypedModule<'ast, T>>;
/// A collection of `TypedFunctionSymbol`s
/// # Remarks
/// * It is the role of the semantic checker to make sure there are no duplicates for a given `FunctionKey`
/// in a given `TypedModule`, hence the use of a HashMap
/// in a given `TypedModule`, hence the use of a BTreeMap
pub type TypedFunctionSymbols<'ast, T> =
HashMap<DeclarationFunctionKey<'ast>, TypedFunctionSymbol<'ast, T>>;
BTreeMap<DeclarationFunctionKey<'ast, T>, TypedFunctionSymbol<'ast, T>>;
#[derive(Clone, Debug, PartialEq)]
pub enum TypedConstantSymbol<'ast, T> {
@ -91,12 +91,11 @@ impl<'ast, T> TypedProgram<'ast, T> {
impl<'ast, T: Field> TypedProgram<'ast, T> {
pub fn abi(&self) -> Abi {
let main = self.modules[&self.main]
.functions
.iter()
.find(|(id, _)| id.id == "main")
let main = &self.modules[&self.main]
.functions_iter()
.find(|s| s.key.id == "main")
.unwrap()
.1;
.symbol;
let main = match main {
TypedFunctionSymbol::Here(main) => main,
_ => unreachable!(),
@ -109,7 +108,7 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
.map(|p| {
types::ConcreteType::try_from(
crate::typed_absy::types::try_from_g_type::<
crate::typed_absy::types::DeclarationConstant<'ast>,
DeclarationConstant<'ast, T>,
UExpression<'ast, T>,
>(p.id._type.clone())
.unwrap(),
@ -129,7 +128,7 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
.map(|ty| {
types::ConcreteType::try_from(
crate::typed_absy::types::try_from_g_type::<
crate::typed_absy::types::DeclarationConstant<'ast>,
DeclarationConstant<'ast, T>,
UExpression<'ast, T>,
>(ty.clone())
.unwrap(),
@ -163,19 +162,90 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedProgram<'ast, T> {
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct TypedFunctionSymbolDeclaration<'ast, T> {
pub key: DeclarationFunctionKey<'ast, T>,
pub symbol: TypedFunctionSymbol<'ast, T>,
}
impl<'ast, T> TypedFunctionSymbolDeclaration<'ast, T> {
pub fn new(key: DeclarationFunctionKey<'ast, T>, symbol: TypedFunctionSymbol<'ast, T>) -> Self {
TypedFunctionSymbolDeclaration { key, symbol }
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct TypedConstantSymbolDeclaration<'ast, T> {
pub id: CanonicalConstantIdentifier<'ast>,
pub symbol: TypedConstantSymbol<'ast, T>,
}
impl<'ast, T> TypedConstantSymbolDeclaration<'ast, T> {
pub fn new(
id: CanonicalConstantIdentifier<'ast>,
symbol: TypedConstantSymbol<'ast, T>,
) -> Self {
TypedConstantSymbolDeclaration { id, symbol }
}
}
#[derive(PartialEq, Debug, Clone)]
pub enum TypedSymbolDeclaration<'ast, T> {
Function(TypedFunctionSymbolDeclaration<'ast, T>),
Constant(TypedConstantSymbolDeclaration<'ast, T>),
}
impl<'ast, T> From<TypedFunctionSymbolDeclaration<'ast, T>> for TypedSymbolDeclaration<'ast, T> {
fn from(d: TypedFunctionSymbolDeclaration<'ast, T>) -> Self {
Self::Function(d)
}
}
impl<'ast, T> From<TypedConstantSymbolDeclaration<'ast, T>> for TypedSymbolDeclaration<'ast, T> {
fn from(d: TypedConstantSymbolDeclaration<'ast, T>) -> Self {
Self::Constant(d)
}
}
impl<'ast, T: fmt::Display> fmt::Display for TypedSymbolDeclaration<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TypedSymbolDeclaration::Function(fun) => write!(f, "{}", fun),
TypedSymbolDeclaration::Constant(c) => write!(f, "{}", c),
}
}
}
pub type TypedSymbolDeclarations<'ast, T> = Vec<TypedSymbolDeclaration<'ast, T>>;
/// A typed module as a collection of functions. Types have been resolved during semantic checking.
#[derive(PartialEq, Debug, Clone)]
pub struct TypedModule<'ast, T> {
/// Functions of the module
pub functions: TypedFunctionSymbols<'ast, T>,
/// Constants defined in module
pub constants: TypedConstantSymbols<'ast, T>,
pub symbols: TypedSymbolDeclarations<'ast, T>,
}
impl<'ast, T> TypedModule<'ast, T> {
pub fn functions_iter(&self) -> impl Iterator<Item = &TypedFunctionSymbolDeclaration<'ast, T>> {
self.symbols.iter().filter_map(|s| match s {
TypedSymbolDeclaration::Function(d) => Some(d),
_ => None,
})
}
pub fn into_functions_iter(
self,
) -> impl Iterator<Item = TypedFunctionSymbolDeclaration<'ast, T>> {
self.symbols.into_iter().filter_map(|s| match s {
TypedSymbolDeclaration::Function(d) => Some(d),
_ => None,
})
}
}
#[derive(Clone, PartialEq, Debug)]
pub enum TypedFunctionSymbol<'ast, T> {
Here(TypedFunction<'ast, T>),
There(DeclarationFunctionKey<'ast>),
There(DeclarationFunctionKey<'ast, T>),
Flat(FlatEmbed),
}
@ -183,17 +253,61 @@ impl<'ast, T: Field> TypedFunctionSymbol<'ast, T> {
pub fn signature<'a>(
&'a self,
modules: &'a TypedModules<'ast, T>,
) -> DeclarationSignature<'ast> {
) -> DeclarationSignature<'ast, T> {
match self {
TypedFunctionSymbol::Here(f) => f.signature.clone(),
TypedFunctionSymbol::There(key) => modules
.get(&key.module)
.unwrap()
.functions
.get(key)
.functions_iter()
.find(|d| d.key == *key)
.unwrap()
.symbol
.signature(&modules),
TypedFunctionSymbol::Flat(flat_fun) => flat_fun.signature(),
TypedFunctionSymbol::Flat(flat_fun) => flat_fun.typed_signature(),
}
}
}
impl<'ast, T: fmt::Display> fmt::Display for TypedConstantSymbolDeclaration<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.symbol {
TypedConstantSymbol::Here(ref tc) => {
write!(f, "const {} {} = {}", tc.ty, self.id, tc.expression)
}
TypedConstantSymbol::There(ref imported_id) => {
write!(
f,
"from \"{}\" import {} as {}",
imported_id.module.display(),
imported_id.id,
self.id
)
}
}
}
}
impl<'ast, T: fmt::Display> fmt::Display for TypedFunctionSymbolDeclaration<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.symbol {
TypedFunctionSymbol::Here(ref function) => write!(f, "def {}{}", self.key.id, function),
TypedFunctionSymbol::There(ref fun_key) => write!(
f,
"from \"{}\" import {} as {} // with signature {}",
fun_key.module.display(),
fun_key.id,
self.key.id,
self.key.signature
),
TypedFunctionSymbol::Flat(ref flat_fun) => {
write!(
f,
"def {}{}:\n\t// hidden",
self.key.id,
flat_fun.typed_signature::<T>()
)
}
}
}
}
@ -201,34 +315,9 @@ impl<'ast, T: Field> TypedFunctionSymbol<'ast, T> {
impl<'ast, T: fmt::Display> fmt::Display for TypedModule<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let res = self
.constants
.symbols
.iter()
.map(|(id, symbol)| match symbol {
TypedConstantSymbol::Here(ref tc) => {
format!("const {} {} = {}", id.ty, id.id, tc)
}
TypedConstantSymbol::There(ref imported_id) => {
format!(
"from \"{}\" import {} as {}",
imported_id.module.display(),
imported_id.id,
id.id
)
}
})
.chain(self.functions.iter().map(|(key, symbol)| match symbol {
TypedFunctionSymbol::Here(ref function) => format!("def {}{}", key.id, function),
TypedFunctionSymbol::There(ref fun_key) => format!(
"from \"{}\" import {} as {} // with signature {}",
fun_key.module.display(),
fun_key.id,
key.id,
key.signature
),
TypedFunctionSymbol::Flat(ref flat_fun) => {
format!("def {}{}:\n\t// hidden", key.id, flat_fun.signature())
}
}))
.map(|s| format!("{}", s))
.collect::<Vec<_>>();
write!(f, "{}", res.join("\n"))
@ -239,11 +328,11 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedModule<'ast, T> {
#[derive(Clone, PartialEq, Debug, Hash)]
pub struct TypedFunction<'ast, T> {
/// Arguments of the function
pub arguments: Vec<DeclarationParameter<'ast>>,
pub arguments: Vec<DeclarationParameter<'ast, T>>,
/// Vector of statements that are executed when running the function
pub statements: Vec<TypedStatement<'ast, T>>,
/// function signature
pub signature: DeclarationSignature<'ast>,
pub signature: DeclarationSignature<'ast, T>,
}
impl<'ast, T: fmt::Display> fmt::Display for TypedFunction<'ast, T> {
@ -312,11 +401,12 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedFunction<'ast, T> {
#[derive(Clone, PartialEq, Debug)]
pub struct TypedConstant<'ast, T> {
pub expression: TypedExpression<'ast, T>,
pub ty: DeclarationType<'ast, T>,
}
impl<'ast, T> TypedConstant<'ast, T> {
pub fn new(expression: TypedExpression<'ast, T>) -> Self {
TypedConstant { expression }
pub fn new(expression: TypedExpression<'ast, T>, ty: DeclarationType<'ast, T>) -> Self {
TypedConstant { expression, ty }
}
}
@ -333,14 +423,14 @@ impl<'ast, T: Field> Typed<'ast, T> for TypedConstant<'ast, T> {
}
/// Something we can assign to.
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum TypedAssignee<'ast, T> {
Identifier(Variable<'ast, T>),
Select(Box<TypedAssignee<'ast, T>>, Box<UExpression<'ast, T>>),
Member(Box<TypedAssignee<'ast, T>>, MemberId),
}
#[derive(Clone, PartialEq, Hash, Eq, Debug)]
#[derive(Clone, PartialEq, Hash, Eq, Debug, PartialOrd, Ord)]
pub struct TypedSpread<'ast, T> {
pub array: ArrayExpression<'ast, T>,
}
@ -357,7 +447,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedSpread<'ast, T> {
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum TypedExpressionOrSpread<'ast, T> {
Expression(TypedExpression<'ast, T>),
Spread(TypedSpread<'ast, T>),
@ -487,7 +577,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedAssignee<'ast, T> {
/// A statement in a `TypedFunction`
#[allow(clippy::large_enum_variant)]
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum TypedStatement<'ast, T> {
Return(Vec<TypedExpression<'ast, T>>),
Definition(TypedAssignee<'ast, T>, TypedExpression<'ast, T>),
@ -502,7 +592,7 @@ pub enum TypedStatement<'ast, T> {
MultipleDefinition(Vec<TypedAssignee<'ast, T>>, TypedExpressionList<'ast, T>),
// Aux
PushCallLog(
DeclarationFunctionKey<'ast>,
DeclarationFunctionKey<'ast, T>,
ConcreteGenericsAssignment<'ast>,
),
PopCallLog,
@ -575,7 +665,7 @@ pub trait Typed<'ast, T> {
/// A typed expression
#[allow(clippy::large_enum_variant)]
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum TypedExpression<'ast, T> {
Boolean(BooleanExpression<'ast, T>),
FieldElement(FieldElementExpression<'ast, T>),
@ -714,7 +804,7 @@ pub trait MultiTyped<'ast, T> {
fn get_types(&self) -> &Vec<Type<'ast, T>>;
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct TypedExpressionList<'ast, T> {
pub inner: TypedExpressionListInner<'ast, T>,
@ -727,7 +817,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedExpressionList<'ast, T> {
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum TypedExpressionListInner<'ast, T> {
FunctionCall(FunctionCallExpression<'ast, T, TypedExpressionList<'ast, T>>),
EmbedCall(FlatEmbed, Vec<u32>, Vec<TypedExpression<'ast, T>>),
@ -744,7 +834,7 @@ impl<'ast, T> TypedExpressionListInner<'ast, T> {
TypedExpressionList { inner: self, types }
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct BlockExpression<'ast, T, E> {
pub statements: Vec<TypedStatement<'ast, T>>,
pub value: Box<E>,
@ -759,7 +849,7 @@ impl<'ast, T, E> BlockExpression<'ast, T, E> {
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct MemberExpression<'ast, T, E> {
pub struc: Box<StructExpression<'ast, T>>,
pub id: MemberId,
@ -782,7 +872,7 @@ impl<'ast, T: fmt::Display, E> fmt::Display for MemberExpression<'ast, T, E> {
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct SelectExpression<'ast, T, E> {
pub array: Box<ArrayExpression<'ast, T>>,
pub index: Box<UExpression<'ast, T>>,
@ -805,13 +895,13 @@ impl<'ast, T: fmt::Display, E> fmt::Display for SelectExpression<'ast, T, E> {
}
}
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub enum ConditionalKind {
IfElse,
Ternary,
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct ConditionalExpression<'ast, T, E> {
pub condition: Box<BooleanExpression<'ast, T>>,
pub consequence: Box<E>,
@ -852,9 +942,9 @@ impl<'ast, T: fmt::Display, E: fmt::Display> fmt::Display for ConditionalExpress
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct FunctionCallExpression<'ast, T, E> {
pub function_key: DeclarationFunctionKey<'ast>,
pub function_key: DeclarationFunctionKey<'ast, T>,
pub generics: Vec<Option<UExpression<'ast, T>>>,
pub arguments: Vec<TypedExpression<'ast, T>>,
ty: PhantomData<E>,
@ -862,7 +952,7 @@ pub struct FunctionCallExpression<'ast, T, E> {
impl<'ast, T, E> FunctionCallExpression<'ast, T, E> {
pub fn new(
function_key: DeclarationFunctionKey<'ast>,
function_key: DeclarationFunctionKey<'ast, T>,
generics: Vec<Option<UExpression<'ast, T>>>,
arguments: Vec<TypedExpression<'ast, T>>,
) -> Self {
@ -905,7 +995,7 @@ impl<'ast, T: fmt::Display, E> fmt::Display for FunctionCallExpression<'ast, T,
}
/// An expression of type `field`
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum FieldElementExpression<'ast, T> {
Block(BlockExpression<'ast, T, Self>),
Number(T),
@ -982,7 +1072,7 @@ impl<'ast, T> From<T> for FieldElementExpression<'ast, T> {
}
/// An expression of type `bool`
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum BooleanExpression<'ast, T> {
Block(BlockExpression<'ast, T, Self>),
Identifier(Identifier<'ast>),
@ -1047,13 +1137,13 @@ impl<'ast, T> From<bool> for BooleanExpression<'ast, T> {
/// * Contrary to basic types which are represented as enums, we wrap an enum `ArrayExpressionInner` in a struct in order to keep track of the type (content and size)
/// of the array. Only using an enum would require generics, which would propagate up to TypedExpression which we want to keep simple, hence this "runtime"
/// type checking
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct ArrayExpression<'ast, T> {
pub ty: Box<ArrayType<'ast, T>>,
pub inner: ArrayExpressionInner<'ast, T>,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
pub struct ArrayValue<'ast, T>(pub Vec<TypedExpressionOrSpread<'ast, T>>);
impl<'ast, T> From<Vec<TypedExpressionOrSpread<'ast, T>>> for ArrayValue<'ast, T> {
@ -1131,7 +1221,7 @@ impl<'ast, T> std::iter::FromIterator<TypedExpressionOrSpread<'ast, T>> for Arra
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum ArrayExpressionInner<'ast, T> {
Block(BlockExpression<'ast, T, ArrayExpression<'ast, T>>),
Identifier(Identifier<'ast>),
@ -1171,7 +1261,7 @@ impl<'ast, T: Clone> ArrayExpression<'ast, T> {
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub struct StructExpression<'ast, T> {
ty: StructType<'ast, T>,
inner: StructExpressionInner<'ast, T>,
@ -1195,7 +1285,7 @@ impl<'ast, T> StructExpression<'ast, T> {
}
}
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
#[derive(Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)]
pub enum StructExpressionInner<'ast, T> {
Block(BlockExpression<'ast, T, StructExpression<'ast, T>>),
Identifier(Identifier<'ast>),
@ -1957,7 +2047,7 @@ impl<'ast, T: Field> Id<'ast, T> for TypedExpressionList<'ast, T> {
pub trait FunctionCall<'ast, T>: Expr<'ast, T> {
fn function_call(
key: DeclarationFunctionKey<'ast>,
key: DeclarationFunctionKey<'ast, T>,
generics: Vec<Option<UExpression<'ast, T>>>,
arguments: Vec<TypedExpression<'ast, T>>,
) -> Self::Inner;
@ -1965,7 +2055,7 @@ pub trait FunctionCall<'ast, T>: Expr<'ast, T> {
impl<'ast, T: Field> FunctionCall<'ast, T> for FieldElementExpression<'ast, T> {
fn function_call(
key: DeclarationFunctionKey<'ast>,
key: DeclarationFunctionKey<'ast, T>,
generics: Vec<Option<UExpression<'ast, T>>>,
arguments: Vec<TypedExpression<'ast, T>>,
) -> Self::Inner {
@ -1975,7 +2065,7 @@ impl<'ast, T: Field> FunctionCall<'ast, T> for FieldElementExpression<'ast, T> {
impl<'ast, T: Field> FunctionCall<'ast, T> for BooleanExpression<'ast, T> {
fn function_call(
key: DeclarationFunctionKey<'ast>,
key: DeclarationFunctionKey<'ast, T>,
generics: Vec<Option<UExpression<'ast, T>>>,
arguments: Vec<TypedExpression<'ast, T>>,
) -> Self::Inner {
@ -1985,7 +2075,7 @@ impl<'ast, T: Field> FunctionCall<'ast, T> for BooleanExpression<'ast, T> {
impl<'ast, T: Field> FunctionCall<'ast, T> for UExpression<'ast, T> {
fn function_call(
key: DeclarationFunctionKey<'ast>,
key: DeclarationFunctionKey<'ast, T>,
generics: Vec<Option<UExpression<'ast, T>>>,
arguments: Vec<TypedExpression<'ast, T>>,
) -> Self::Inner {
@ -1995,7 +2085,7 @@ impl<'ast, T: Field> FunctionCall<'ast, T> for UExpression<'ast, T> {
impl<'ast, T: Field> FunctionCall<'ast, T> for ArrayExpression<'ast, T> {
fn function_call(
key: DeclarationFunctionKey<'ast>,
key: DeclarationFunctionKey<'ast, T>,
generics: Vec<Option<UExpression<'ast, T>>>,
arguments: Vec<TypedExpression<'ast, T>>,
) -> Self::Inner {
@ -2005,7 +2095,7 @@ impl<'ast, T: Field> FunctionCall<'ast, T> for ArrayExpression<'ast, T> {
impl<'ast, T: Field> FunctionCall<'ast, T> for StructExpression<'ast, T> {
fn function_call(
key: DeclarationFunctionKey<'ast>,
key: DeclarationFunctionKey<'ast, T>,
generics: Vec<Option<UExpression<'ast, T>>>,
arguments: Vec<TypedExpression<'ast, T>>,
) -> Self::Inner {
@ -2015,7 +2105,7 @@ impl<'ast, T: Field> FunctionCall<'ast, T> for StructExpression<'ast, T> {
impl<'ast, T: Field> FunctionCall<'ast, T> for TypedExpressionList<'ast, T> {
fn function_call(
key: DeclarationFunctionKey<'ast>,
key: DeclarationFunctionKey<'ast, T>,
generics: Vec<Option<UExpression<'ast, T>>>,
arguments: Vec<TypedExpression<'ast, T>>,
) -> Self::Inner {

View file

@ -18,12 +18,12 @@ impl<'ast, S> From<GVariable<'ast, S>> for GParameter<'ast, S> {
}
}
pub type DeclarationParameter<'ast> = GParameter<'ast, DeclarationConstant<'ast>>;
pub type DeclarationParameter<'ast, T> = GParameter<'ast, DeclarationConstant<'ast, T>>;
impl<'ast, S: fmt::Display + Clone> fmt::Display for GParameter<'ast, S> {
impl<'ast, S: fmt::Display> fmt::Display for GParameter<'ast, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let visibility = if self.private { "private " } else { "" };
write!(f, "{}{} {}", visibility, self.id.get_type(), self.id.id)
write!(f, "{}{} {}", visibility, self.id._type, self.id.id)
}
}

View file

@ -55,6 +55,27 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
fold_module(self, m)
}
fn fold_symbol_declaration(
&mut self,
s: TypedSymbolDeclaration<'ast, T>,
) -> Result<TypedSymbolDeclaration<'ast, T>, Self::Error> {
fold_symbol_declaration(self, s)
}
fn fold_function_symbol_declaration(
&mut self,
s: TypedFunctionSymbolDeclaration<'ast, T>,
) -> Result<TypedFunctionSymbolDeclaration<'ast, T>, Self::Error> {
fold_function_symbol_declaration(self, s)
}
fn fold_constant_symbol_declaration(
&mut self,
s: TypedConstantSymbolDeclaration<'ast, T>,
) -> Result<TypedConstantSymbolDeclaration<'ast, T>, Self::Error> {
fold_constant_symbol_declaration(self, s)
}
fn fold_constant(
&mut self,
c: TypedConstant<'ast, T>,
@ -78,8 +99,8 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
fn fold_declaration_function_key(
&mut self,
key: DeclarationFunctionKey<'ast>,
) -> Result<DeclarationFunctionKey<'ast>, Self::Error> {
key: DeclarationFunctionKey<'ast, T>,
) -> Result<DeclarationFunctionKey<'ast, T>, Self::Error> {
fold_declaration_function_key(self, key)
}
@ -92,22 +113,22 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
fn fold_signature(
&mut self,
s: DeclarationSignature<'ast>,
) -> Result<DeclarationSignature<'ast>, Self::Error> {
s: DeclarationSignature<'ast, T>,
) -> Result<DeclarationSignature<'ast, T>, Self::Error> {
fold_signature(self, s)
}
fn fold_declaration_constant(
&mut self,
c: DeclarationConstant<'ast>,
) -> Result<DeclarationConstant<'ast>, Self::Error> {
c: DeclarationConstant<'ast, T>,
) -> Result<DeclarationConstant<'ast, T>, Self::Error> {
fold_declaration_constant(self, c)
}
fn fold_parameter(
&mut self,
p: DeclarationParameter<'ast>,
) -> Result<DeclarationParameter<'ast>, Self::Error> {
p: DeclarationParameter<'ast, T>,
) -> Result<DeclarationParameter<'ast, T>, Self::Error> {
Ok(DeclarationParameter {
id: self.fold_declaration_variable(p.id)?,
..p
@ -121,7 +142,6 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
Ok(CanonicalConstantIdentifier {
module: self.fold_module_id(i.module)?,
id: i.id,
ty: box self.fold_declaration_type(*i.ty)?,
})
}
@ -142,8 +162,8 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
fn fold_declaration_variable(
&mut self,
v: DeclarationVariable<'ast>,
) -> Result<DeclarationVariable<'ast>, Self::Error> {
v: DeclarationVariable<'ast, T>,
) -> Result<DeclarationVariable<'ast, T>, Self::Error> {
Ok(DeclarationVariable {
id: self.fold_name(v.id)?,
_type: self.fold_declaration_type(v._type)?,
@ -246,8 +266,8 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
fn fold_declaration_type(
&mut self,
t: DeclarationType<'ast>,
) -> Result<DeclarationType<'ast>, Self::Error> {
t: DeclarationType<'ast, T>,
) -> Result<DeclarationType<'ast, T>, Self::Error> {
use self::GType::*;
match t {
@ -259,8 +279,8 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
fn fold_declaration_array_type(
&mut self,
t: DeclarationArrayType<'ast>,
) -> Result<DeclarationArrayType<'ast>, Self::Error> {
t: DeclarationArrayType<'ast, T>,
) -> Result<DeclarationArrayType<'ast, T>, Self::Error> {
Ok(DeclarationArrayType {
ty: box self.fold_declaration_type(*t.ty)?,
size: self.fold_declaration_constant(t.size)?,
@ -269,8 +289,8 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
fn fold_declaration_struct_type(
&mut self,
t: DeclarationStructType<'ast>,
) -> Result<DeclarationStructType<'ast>, Self::Error> {
t: DeclarationStructType<'ast, T>,
) -> Result<DeclarationStructType<'ast, T>, Self::Error> {
Ok(DeclarationStructType {
generics: t
.generics
@ -294,16 +314,7 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
&mut self,
a: TypedAssignee<'ast, T>,
) -> Result<TypedAssignee<'ast, T>, Self::Error> {
match a {
TypedAssignee::Identifier(v) => Ok(TypedAssignee::Identifier(self.fold_variable(v)?)),
TypedAssignee::Select(box a, box index) => Ok(TypedAssignee::Select(
box self.fold_assignee(a)?,
box self.fold_uint_expression(index)?,
)),
TypedAssignee::Member(box s, m) => {
Ok(TypedAssignee::Member(box self.fold_assignee(s)?, m))
}
}
fold_assignee(self, a)
}
fn fold_statement(
@ -518,6 +529,20 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>(
Ok(e)
}
pub fn fold_assignee<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
a: TypedAssignee<'ast, T>,
) -> Result<TypedAssignee<'ast, T>, F::Error> {
match a {
TypedAssignee::Identifier(v) => Ok(TypedAssignee::Identifier(f.fold_variable(v)?)),
TypedAssignee::Select(box a, box index) => Ok(TypedAssignee::Select(
box f.fold_assignee(a)?,
box f.fold_uint_expression(index)?,
)),
TypedAssignee::Member(box s, m) => Ok(TypedAssignee::Member(box f.fold_assignee(s)?, m)),
}
}
pub fn fold_struct_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
ty: &StructType<'ast, T>,
@ -977,8 +1002,8 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>(
pub fn fold_declaration_function_key<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
key: DeclarationFunctionKey<'ast>,
) -> Result<DeclarationFunctionKey<'ast>, F::Error> {
key: DeclarationFunctionKey<'ast, T>,
) -> Result<DeclarationFunctionKey<'ast, T>, F::Error> {
Ok(DeclarationFunctionKey {
module: f.fold_module_id(key.module)?,
signature: f.fold_signature(key.signature)?,
@ -1008,12 +1033,16 @@ pub fn fold_function<'ast, T: Field, F: ResultFolder<'ast, T>>(
})
}
fn fold_signature<'ast, T: Field, F: ResultFolder<'ast, T>>(
pub fn fold_signature<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
s: DeclarationSignature<'ast>,
) -> Result<DeclarationSignature<'ast>, F::Error> {
s: DeclarationSignature<'ast, T>,
) -> Result<DeclarationSignature<'ast, T>, F::Error> {
Ok(DeclarationSignature {
generics: s.generics,
generics: s
.generics
.into_iter()
.map(|g| g.map(|g| f.fold_declaration_constant(g)).transpose())
.collect::<Result<_, _>>()?,
inputs: s
.inputs
.into_iter()
@ -1027,11 +1056,16 @@ fn fold_signature<'ast, T: Field, F: ResultFolder<'ast, T>>(
})
}
fn fold_declaration_constant<'ast, T: Field, F: ResultFolder<'ast, T>>(
_: &mut F,
c: DeclarationConstant<'ast>,
) -> Result<DeclarationConstant<'ast>, F::Error> {
Ok(c)
pub fn fold_declaration_constant<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
c: DeclarationConstant<'ast, T>,
) -> Result<DeclarationConstant<'ast, T>, F::Error> {
match c {
DeclarationConstant::Expression(e) => {
Ok(DeclarationConstant::Expression(f.fold_expression(e)?))
}
c => Ok(c),
}
}
pub fn fold_array_expression<'ast, T: Field, F: ResultFolder<'ast, T>>(
@ -1115,6 +1149,7 @@ pub fn fold_constant<'ast, T: Field, F: ResultFolder<'ast, T>>(
) -> Result<TypedConstant<'ast, T>, F::Error> {
Ok(TypedConstant {
expression: f.fold_expression(c.expression)?,
ty: f.fold_declaration_type(c.ty)?,
})
}
@ -1143,20 +1178,49 @@ pub fn fold_function_symbol<'ast, T: Field, F: ResultFolder<'ast, T>>(
}
}
pub fn fold_symbol_declaration<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
d: TypedSymbolDeclaration<'ast, T>,
) -> Result<TypedSymbolDeclaration<'ast, T>, F::Error> {
Ok(match d {
TypedSymbolDeclaration::Function(d) => {
TypedSymbolDeclaration::Function(f.fold_function_symbol_declaration(d)?)
}
TypedSymbolDeclaration::Constant(d) => {
TypedSymbolDeclaration::Constant(f.fold_constant_symbol_declaration(d)?)
}
})
}
pub fn fold_function_symbol_declaration<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
d: TypedFunctionSymbolDeclaration<'ast, T>,
) -> Result<TypedFunctionSymbolDeclaration<'ast, T>, F::Error> {
Ok(TypedFunctionSymbolDeclaration {
key: f.fold_declaration_function_key(d.key)?,
symbol: f.fold_function_symbol(d.symbol)?,
})
}
pub fn fold_constant_symbol_declaration<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
d: TypedConstantSymbolDeclaration<'ast, T>,
) -> Result<TypedConstantSymbolDeclaration<'ast, T>, F::Error> {
Ok(TypedConstantSymbolDeclaration {
id: f.fold_canonical_constant_identifier(d.id)?,
symbol: f.fold_constant_symbol(d.symbol)?,
})
}
pub fn fold_module<'ast, T: Field, F: ResultFolder<'ast, T>>(
f: &mut F,
m: TypedModule<'ast, T>,
) -> Result<TypedModule<'ast, T>, F::Error> {
Ok(TypedModule {
constants: m
.constants
symbols: m
.symbols
.into_iter()
.map(|(key, tc)| f.fold_constant_symbol(tc).map(|tc| (key, tc)))
.collect::<Result<_, _>>()?,
functions: m
.functions
.into_iter()
.map(|(key, fun)| f.fold_function_symbol(fun).map(|f| (key, f)))
.map(|s| f.fold_symbol_declaration(s))
.collect::<Result<_, _>>()?,
})
}

View file

@ -1,4 +1,6 @@
use crate::typed_absy::{Identifier, OwnedTypedModuleId, UExpression, UExpressionInner};
use crate::typed_absy::{
CoreIdentifier, Identifier, OwnedTypedModuleId, TypedExpression, UExpression, UExpressionInner,
};
use crate::typed_absy::{TryFrom, TryInto};
use serde::{de::Error, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
use std::collections::BTreeMap;
@ -46,7 +48,7 @@ impl<'ast, T> IntoTypes<'ast, T> for Types<'ast, T> {
}
}
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct Types<'ast, T> {
pub inner: Vec<Type<'ast, T>>,
}
@ -107,69 +109,77 @@ pub type ConstantIdentifier<'ast> = &'ast str;
pub struct CanonicalConstantIdentifier<'ast> {
pub module: OwnedTypedModuleId,
pub id: ConstantIdentifier<'ast>,
pub ty: Box<DeclarationType<'ast>>,
}
impl<'ast> fmt::Display for CanonicalConstantIdentifier<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}/{}", self.module.display(), self.id)
}
}
impl<'ast> CanonicalConstantIdentifier<'ast> {
pub fn new(
id: ConstantIdentifier<'ast>,
module: OwnedTypedModuleId,
ty: DeclarationType<'ast>,
) -> Self {
CanonicalConstantIdentifier {
module,
id,
ty: box ty,
}
pub fn new(id: ConstantIdentifier<'ast>, module: OwnedTypedModuleId) -> Self {
CanonicalConstantIdentifier { module, id }
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DeclarationConstant<'ast> {
pub enum DeclarationConstant<'ast, T> {
Generic(GenericIdentifier<'ast>),
Concrete(u32),
Constant(CanonicalConstantIdentifier<'ast>),
Expression(TypedExpression<'ast, T>),
}
impl<'ast, T> PartialEq<UExpression<'ast, T>> for DeclarationConstant<'ast> {
impl<'ast, T: PartialEq> PartialEq<UExpression<'ast, T>> for DeclarationConstant<'ast, T> {
fn eq(&self, other: &UExpression<'ast, T>) -> bool {
match (self, other.as_inner()) {
(DeclarationConstant::Concrete(c), UExpressionInner::Value(v)) => *c == *v as u32,
match (self, other) {
(
DeclarationConstant::Concrete(c),
UExpression {
bitwidth: UBitwidth::B32,
inner: UExpressionInner::Value(v),
..
},
) => *c == *v as u32,
(DeclarationConstant::Expression(TypedExpression::Uint(e0)), e1) => e0 == e1,
(DeclarationConstant::Expression(..), _) => false, // type error
_ => true,
}
}
}
impl<'ast, T> PartialEq<DeclarationConstant<'ast>> for UExpression<'ast, T> {
fn eq(&self, other: &DeclarationConstant<'ast>) -> bool {
impl<'ast, T: PartialEq> PartialEq<DeclarationConstant<'ast, T>> for UExpression<'ast, T> {
fn eq(&self, other: &DeclarationConstant<'ast, T>) -> bool {
other.eq(self)
}
}
impl<'ast> From<u32> for DeclarationConstant<'ast> {
impl<'ast, T> From<u32> for DeclarationConstant<'ast, T> {
fn from(e: u32) -> Self {
DeclarationConstant::Concrete(e)
}
}
impl<'ast> From<usize> for DeclarationConstant<'ast> {
impl<'ast, T> From<usize> for DeclarationConstant<'ast, T> {
fn from(e: usize) -> Self {
DeclarationConstant::Concrete(e as u32)
}
}
impl<'ast> From<GenericIdentifier<'ast>> for DeclarationConstant<'ast> {
impl<'ast, T> From<GenericIdentifier<'ast>> for DeclarationConstant<'ast, T> {
fn from(e: GenericIdentifier<'ast>) -> Self {
DeclarationConstant::Generic(e)
}
}
impl<'ast> fmt::Display for DeclarationConstant<'ast> {
impl<'ast, T: fmt::Display> fmt::Display for DeclarationConstant<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DeclarationConstant::Generic(i) => write!(f, "{}", i),
DeclarationConstant::Concrete(v) => write!(f, "{}", v),
DeclarationConstant::Constant(v) => write!(f, "{}/{}", v.module.display(), v.id),
DeclarationConstant::Expression(e) => write!(f, "{}", e),
}
}
}
@ -180,8 +190,8 @@ impl<'ast, T> From<usize> for UExpression<'ast, T> {
}
}
impl<'ast, T> From<DeclarationConstant<'ast>> for UExpression<'ast, T> {
fn from(c: DeclarationConstant<'ast>) -> Self {
impl<'ast, T> From<DeclarationConstant<'ast, T>> for UExpression<'ast, T> {
fn from(c: DeclarationConstant<'ast, T>) -> Self {
match c {
DeclarationConstant::Generic(i) => {
UExpressionInner::Identifier(i.name.into()).annotate(UBitwidth::B32)
@ -190,8 +200,10 @@ impl<'ast, T> From<DeclarationConstant<'ast>> for UExpression<'ast, T> {
UExpressionInner::Value(v as u128).annotate(UBitwidth::B32)
}
DeclarationConstant::Constant(v) => {
UExpressionInner::Identifier(Identifier::from(v.id)).annotate(UBitwidth::B32)
UExpressionInner::Identifier(CoreIdentifier::from(v).into())
.annotate(UBitwidth::B32)
}
DeclarationConstant::Expression(e) => e.try_into().unwrap(),
}
}
}
@ -209,7 +221,7 @@ impl<'ast, T> TryInto<usize> for UExpression<'ast, T> {
}
}
impl<'ast> TryInto<usize> for DeclarationConstant<'ast> {
impl<'ast, T> TryInto<usize> for DeclarationConstant<'ast, T> {
type Error = SpecializationError;
fn try_into(self) -> Result<usize, Self::Error> {
@ -230,7 +242,7 @@ pub struct GStructMember<S> {
pub ty: Box<GType<S>>,
}
pub type DeclarationStructMember<'ast> = GStructMember<DeclarationConstant<'ast>>;
pub type DeclarationStructMember<'ast, T> = GStructMember<DeclarationConstant<'ast, T>>;
pub type ConcreteStructMember = GStructMember<usize>;
pub type StructMember<'ast, T> = GStructMember<UExpression<'ast, T>>;
@ -270,7 +282,7 @@ pub struct GArrayType<S> {
pub ty: Box<GType<S>>,
}
pub type DeclarationArrayType<'ast> = GArrayType<DeclarationConstant<'ast>>;
pub type DeclarationArrayType<'ast, T> = GArrayType<DeclarationConstant<'ast, T>>;
pub type ConcreteArrayType = GArrayType<usize>;
pub type ArrayType<'ast, T> = GArrayType<UExpression<'ast, T>>;
@ -336,7 +348,7 @@ pub struct StructLocation {
pub name: String,
}
impl<'ast> From<ConcreteArrayType> for DeclarationArrayType<'ast> {
impl<'ast, T> From<ConcreteArrayType> for DeclarationArrayType<'ast, T> {
fn from(t: ConcreteArrayType) -> Self {
try_from_g_array_type(t).unwrap()
}
@ -352,7 +364,7 @@ pub struct GStructType<S> {
pub members: Vec<GStructMember<S>>,
}
pub type DeclarationStructType<'ast> = GStructType<DeclarationConstant<'ast>>;
pub type DeclarationStructType<'ast, T> = GStructType<DeclarationConstant<'ast, T>>;
pub type ConcreteStructType = GStructType<usize>;
pub type StructType<'ast, T> = GStructType<UExpression<'ast, T>>;
@ -416,7 +428,7 @@ impl<'ast, T> From<ConcreteStructType> for StructType<'ast, T> {
}
}
impl<'ast> From<ConcreteStructType> for DeclarationStructType<'ast> {
impl<'ast, T> From<ConcreteStructType> for DeclarationStructType<'ast, T> {
fn from(t: ConcreteStructType) -> Self {
try_from_g_struct_type(t).unwrap()
}
@ -609,7 +621,7 @@ impl<'de, S: Deserialize<'de>> Deserialize<'de> for GType<S> {
}
}
pub type DeclarationType<'ast> = GType<DeclarationConstant<'ast>>;
pub type DeclarationType<'ast, T> = GType<DeclarationConstant<'ast, T>>;
pub type ConcreteType = GType<usize>;
pub type Type<'ast, T> = GType<UExpression<'ast, T>>;
@ -652,7 +664,7 @@ impl<'ast, T> From<ConcreteType> for Type<'ast, T> {
}
}
impl<'ast> From<ConcreteType> for DeclarationType<'ast> {
impl<'ast, T> From<ConcreteType> for DeclarationType<'ast, T> {
fn from(t: ConcreteType) -> Self {
try_from_g_type(t).unwrap()
}
@ -738,7 +750,7 @@ impl<S> GType<S> {
}
impl<'ast, T: fmt::Display + PartialEq + fmt::Debug> Type<'ast, T> {
pub fn can_be_specialized_to(&self, other: &DeclarationType) -> bool {
pub fn can_be_specialized_to(&self, other: &DeclarationType<'ast, T>) -> bool {
use self::GType::*;
if other == self {
@ -811,14 +823,14 @@ impl ConcreteType {
pub type FunctionIdentifier<'ast> = &'ast str;
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
#[derive(PartialEq, Eq, Hash, Debug, Clone, PartialOrd, Ord)]
pub struct GFunctionKey<'ast, S> {
pub module: OwnedTypedModuleId,
pub id: FunctionIdentifier<'ast>,
pub signature: GSignature<S>,
}
pub type DeclarationFunctionKey<'ast> = GFunctionKey<'ast, DeclarationConstant<'ast>>;
pub type DeclarationFunctionKey<'ast, T> = GFunctionKey<'ast, DeclarationConstant<'ast, T>>;
pub type ConcreteFunctionKey<'ast> = GFunctionKey<'ast, usize>;
pub type FunctionKey<'ast, T> = GFunctionKey<'ast, UExpression<'ast, T>>;
@ -828,7 +840,7 @@ impl<'ast, S: fmt::Display> fmt::Display for GFunctionKey<'ast, S> {
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
pub struct GGenericsAssignment<'ast, S>(pub BTreeMap<GenericIdentifier<'ast>, S>);
pub type ConcreteGenericsAssignment<'ast> = GGenericsAssignment<'ast, usize>;
@ -854,8 +866,8 @@ impl<'ast, S: fmt::Display> fmt::Display for GGenericsAssignment<'ast, S> {
}
}
impl<'ast> PartialEq<DeclarationFunctionKey<'ast>> for ConcreteFunctionKey<'ast> {
fn eq(&self, other: &DeclarationFunctionKey<'ast>) -> bool {
impl<'ast, T> PartialEq<DeclarationFunctionKey<'ast, T>> for ConcreteFunctionKey<'ast> {
fn eq(&self, other: &DeclarationFunctionKey<'ast, T>) -> bool {
self.module == other.module && self.id == other.id && self.signature == other.signature
}
}
@ -884,7 +896,7 @@ impl<'ast, T> From<ConcreteFunctionKey<'ast>> for FunctionKey<'ast, T> {
}
}
impl<'ast> From<ConcreteFunctionKey<'ast>> for DeclarationFunctionKey<'ast> {
impl<'ast, T> From<ConcreteFunctionKey<'ast>> for DeclarationFunctionKey<'ast, T> {
fn from(k: ConcreteFunctionKey<'ast>) -> Self {
try_from_g_function_key(k).unwrap()
}
@ -931,8 +943,8 @@ impl<'ast> ConcreteFunctionKey<'ast> {
use std::collections::btree_map::Entry;
pub fn check_type<'ast, S: Clone + PartialEq + PartialEq<usize>>(
decl_ty: &DeclarationType<'ast>,
pub fn check_type<'ast, T, S: Clone + PartialEq + PartialEq<usize>>(
decl_ty: &DeclarationType<'ast, T>,
ty: &GType<S>,
constants: &mut GGenericsAssignment<'ast, S>,
) -> bool {
@ -953,9 +965,9 @@ pub fn check_type<'ast, S: Clone + PartialEq + PartialEq<usize>>(
}
},
DeclarationConstant::Concrete(s0) => s1 == *s0 as usize,
// in the case of a constant, we do not know the value yet, so we optimistically assume it's correct
// in the other cases, we do not know the value yet, so we optimistically assume it's correct
// if it does not match, it will be caught during inlining
DeclarationConstant::Constant(..) => true,
DeclarationConstant::Constant(..) | DeclarationConstant::Expression(..) => true,
}
}
(DeclarationType::FieldElement, GType::FieldElement)
@ -963,6 +975,11 @@ pub fn check_type<'ast, S: Clone + PartialEq + PartialEq<usize>>(
(DeclarationType::Uint(b0), GType::Uint(b1)) => b0 == b1,
(DeclarationType::Struct(s0), GType::Struct(s1)) => {
s0.canonical_location == s1.canonical_location
&& s0
.members
.iter()
.zip(s1.members.iter())
.all(|(m0, m1)| check_type(&*m0.ty, &*m1.ty, constants))
}
_ => false,
}
@ -970,16 +987,12 @@ pub fn check_type<'ast, S: Clone + PartialEq + PartialEq<usize>>(
impl<'ast, T> From<CanonicalConstantIdentifier<'ast>> for UExpression<'ast, T> {
fn from(c: CanonicalConstantIdentifier<'ast>) -> Self {
let bitwidth = match *c.ty {
DeclarationType::Uint(bitwidth) => bitwidth,
_ => unreachable!(),
};
UExpressionInner::Identifier(Identifier::from(c.id)).annotate(bitwidth)
UExpressionInner::Identifier(Identifier::from(CoreIdentifier::Constant(c)))
.annotate(UBitwidth::B32)
}
}
impl<'ast> From<CanonicalConstantIdentifier<'ast>> for DeclarationConstant<'ast> {
impl<'ast, T> From<CanonicalConstantIdentifier<'ast>> for DeclarationConstant<'ast, T> {
fn from(c: CanonicalConstantIdentifier<'ast>) -> Self {
DeclarationConstant::Constant(c)
}
@ -987,21 +1000,21 @@ impl<'ast> From<CanonicalConstantIdentifier<'ast>> for DeclarationConstant<'ast>
pub fn specialize_declaration_type<
'ast,
T,
S: Clone + PartialEq + From<u32> + fmt::Debug + From<CanonicalConstantIdentifier<'ast>>,
>(
decl_ty: DeclarationType<'ast>,
decl_ty: DeclarationType<'ast, T>,
generics: &GGenericsAssignment<'ast, S>,
) -> Result<GType<S>, GenericIdentifier<'ast>> {
Ok(match decl_ty {
DeclarationType::Int => unreachable!(),
DeclarationType::Array(t0) => {
// let s1 = t1.size.clone();
let ty = box specialize_declaration_type(*t0.ty, &generics)?;
let size = match t0.size {
DeclarationConstant::Generic(s) => generics.0.get(&s).cloned().ok_or(s),
DeclarationConstant::Concrete(s) => Ok(s.into()),
DeclarationConstant::Constant(c) => Ok(c.into()),
DeclarationConstant::Expression(..) => unreachable!("the semantic checker should not yield this DeclarationConstant variant")
}?;
GType::Array(GArrayType { size, ty })
@ -1028,11 +1041,8 @@ pub fn specialize_declaration_type<
generics.0.get(&s).cloned().ok_or(s).map(Some)
}
DeclarationConstant::Concrete(s) => Ok(Some(s.into())),
DeclarationConstant::Constant(..) => {
unreachable!(
"identifiers should have been removed in constant inlining"
)
}
DeclarationConstant::Constant(c) => Ok(Some(c.into())),
DeclarationConstant::Expression(..) => unreachable!("the semantic checker should not yield this DeclarationConstant variant"),
},
_ => Ok(None),
})
@ -1096,12 +1106,12 @@ pub mod signature {
}
}
pub type DeclarationSignature<'ast> = GSignature<DeclarationConstant<'ast>>;
pub type DeclarationSignature<'ast, T> = GSignature<DeclarationConstant<'ast, T>>;
pub type ConcreteSignature = GSignature<usize>;
pub type Signature<'ast, T> = GSignature<UExpression<'ast, T>>;
impl<'ast> PartialEq<DeclarationSignature<'ast>> for ConcreteSignature {
fn eq(&self, other: &DeclarationSignature<'ast>) -> bool {
impl<'ast, T> PartialEq<DeclarationSignature<'ast, T>> for ConcreteSignature {
fn eq(&self, other: &DeclarationSignature<'ast, T>) -> bool {
// we keep track of the value of constants in a map, as a given constant can only have one value
let mut constants = ConcreteGenericsAssignment::default();
@ -1110,11 +1120,11 @@ pub mod signature {
.iter()
.chain(other.outputs.iter())
.zip(self.inputs.iter().chain(self.outputs.iter()))
.all(|(decl_ty, ty)| check_type::<usize>(decl_ty, ty, &mut constants))
.all(|(decl_ty, ty)| check_type::<T, usize>(decl_ty, ty, &mut constants))
}
}
impl<'ast> DeclarationSignature<'ast> {
impl<'ast, T: Clone + PartialEq + fmt::Debug> DeclarationSignature<'ast, T> {
pub fn specialize(
&self,
values: Vec<Option<u32>>,
@ -1155,7 +1165,7 @@ pub mod signature {
}
}
pub fn get_output_types<T: Clone + PartialEq + fmt::Debug>(
pub fn get_output_types(
&self,
generics: Vec<Option<UExpression<'ast, T>>>,
inputs: Vec<Type<'ast, T>>,
@ -1234,7 +1244,7 @@ pub mod signature {
}
}
impl<'ast> From<ConcreteSignature> for DeclarationSignature<'ast> {
impl<'ast, T> From<ConcreteSignature> for DeclarationSignature<'ast, T> {
fn from(s: ConcreteSignature) -> Self {
try_from_g_signature(s).unwrap()
}
@ -1349,6 +1359,7 @@ pub mod signature {
#[cfg(test)]
mod tests {
use super::*;
use zokrates_field::Bn128Field;
#[test]
fn signature() {
@ -1365,7 +1376,7 @@ pub mod signature {
// <P>(field[P])
// <Q>(field[Q])
let generic1 = DeclarationSignature::new()
let generic1 = DeclarationSignature::<Bn128Field>::new()
.generics(vec![Some(
GenericIdentifier {
name: "P",

View file

@ -133,13 +133,13 @@ impl<'ast, T: Field> From<&'ast str> for UExpressionInner<'ast, T> {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct UMetadata {
pub bitwidth: Option<Bitwidth>,
pub should_reduce: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct UExpression<'ast, T> {
pub bitwidth: UBitwidth,
pub metadata: Option<UMetadata>,
@ -173,7 +173,7 @@ impl<'ast, T> PartialEq<usize> for UExpression<'ast, T> {
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub enum UExpressionInner<'ast, T> {
Block(BlockExpression<'ast, T, UExpression<'ast, T>>),
Identifier(Identifier<'ast>),

View file

@ -5,13 +5,13 @@ use crate::typed_absy::UExpression;
use crate::typed_absy::{TryFrom, TryInto};
use std::fmt;
#[derive(Clone, PartialEq, Hash, Eq)]
#[derive(Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct GVariable<'ast, S> {
pub id: Identifier<'ast>,
pub _type: GType<S>,
}
pub type DeclarationVariable<'ast> = GVariable<'ast, DeclarationConstant<'ast>>;
pub type DeclarationVariable<'ast, T> = GVariable<'ast, DeclarationConstant<'ast, T>>;
pub type ConcreteVariable<'ast> = GVariable<'ast, usize>;
pub type Variable<'ast, T> = GVariable<'ast, UExpression<'ast, T>>;

458
zokrates_js/Cargo.lock generated
View file

@ -17,6 +17,17 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]]
name = "ahash"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
dependencies = [
"getrandom 0.2.2",
"once_cell",
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.6.10"
@ -26,6 +37,219 @@ dependencies = [
"memchr",
]
[[package]]
name = "ark-bls12-377"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb89b97424403ec9cc22a1df0db748dd7396c9ba5fb5c71a6f0e10ae1d1a7449"
dependencies = [
"ark-ec",
"ark-ff",
"ark-r1cs-std",
"ark-std",
]
[[package]]
name = "ark-bw6-761"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ad8d74a8e083a59defc4a226a19759691337006d5c9397dbd793af9e406418"
dependencies = [
"ark-bls12-377",
"ark-ec",
"ark-ff",
"ark-std",
]
[[package]]
name = "ark-crypto-primitives"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74b83a7e125e5c611e4a997123effb2f02e3fbc66531dd77751d3016ee920741"
dependencies = [
"ark-ec",
"ark-ff",
"ark-nonnative-field",
"ark-r1cs-std",
"ark-relations",
"ark-snark",
"ark-std",
"blake2",
"derivative",
"digest 0.9.0",
"tracing",
]
[[package]]
name = "ark-ec"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c56006994f509d76fbce6f6ffe3108f7191b4f3754ecd00bbae7cac20ec05020"
dependencies = [
"ark-ff",
"ark-serialize",
"ark-std",
"derivative",
"num-traits 0.2.12",
"zeroize",
]
[[package]]
name = "ark-ff"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4d8802d40fce9212c5c09be08f75c4b3becc0c488e87f60fff787b01250ce33"
dependencies = [
"ark-ff-asm",
"ark-ff-macros",
"ark-serialize",
"ark-std",
"derivative",
"num-traits 0.2.12",
"rustc_version",
"zeroize",
]
[[package]]
name = "ark-ff-asm"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e8cb28c2137af1ef058aa59616db3f7df67dbb70bf2be4ee6920008cc30d98c"
dependencies = [
"quote 1.0.7",
"syn 1.0.34",
]
[[package]]
name = "ark-ff-macros"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9c256a93a10ed9708c16a517d6dcfaba3d215c0d7fab44d29a9affefb5eeb8"
dependencies = [
"num-bigint 0.4.2",
"num-traits 0.2.12",
"quote 1.0.7",
"syn 1.0.34",
]
[[package]]
name = "ark-gm17"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c9085a6c89aa65178aa2718b2efb62fd7c4dc23fe25285204e30b56e4cbfcac"
dependencies = [
"ark-crypto-primitives",
"ark-ec",
"ark-ff",
"ark-poly",
"ark-r1cs-std",
"ark-relations",
"ark-serialize",
"ark-std",
"derivative",
"tracing",
]
[[package]]
name = "ark-nonnative-field"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17887af156e9911d1dba5b30d49256d508f82f6a4f765a6fad8b5c637b700353"
dependencies = [
"ark-ec",
"ark-ff",
"ark-r1cs-std",
"ark-relations",
"ark-std",
"derivative",
"num-bigint 0.4.2",
"num-integer",
"num-traits 0.2.12",
"tracing",
]
[[package]]
name = "ark-poly"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72d6683d21645a2abb94034f6a14e708405e55d9597687952d54b2269922857a"
dependencies = [
"ark-ff",
"ark-serialize",
"ark-std",
"derivative",
"hashbrown",
]
[[package]]
name = "ark-r1cs-std"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a90fea2b84ae4443983d56540360ea004cab952292b7a6535798b6b9dcb7f41"
dependencies = [
"ark-ec",
"ark-ff",
"ark-relations",
"ark-std",
"derivative",
"num-bigint 0.4.2",
"num-traits 0.2.12",
"tracing",
]
[[package]]
name = "ark-relations"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a42f124f8dfff2b0561143c0c7ea48d7f7dc8d2c4c1e87eca14a27430c653c0b"
dependencies = [
"ark-ff",
"ark-std",
"tracing",
]
[[package]]
name = "ark-serialize"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e9b59329dc9b92086b3dc619f31cef4a0c802f10829b575a3666d48a48387d"
dependencies = [
"ark-serialize-derive",
"ark-std",
]
[[package]]
name = "ark-serialize-derive"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ac3d78c750b01f5df5b2e76d106ed31487a93b3868f14a7f0eb3a74f45e1d8a"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.34",
]
[[package]]
name = "ark-snark"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39da26432fe584b0010741299820145ec69180fe9ea18ddf96946932763624a1"
dependencies = [
"ark-ff",
"ark-relations",
"ark-std",
]
[[package]]
name = "ark-std"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5b856a29bea7b810858116a596beee3d20fc4c5aeb240e8e5a8bca4845a470"
dependencies = [
"rand 0.7.3",
"rand_xorshift",
]
[[package]]
name = "arrayvec"
version = "0.4.12"
@ -88,6 +312,17 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3"
[[package]]
name = "blake2"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174"
dependencies = [
"crypto-mac",
"digest 0.9.0",
"opaque-debug 0.3.0",
]
[[package]]
name = "blake2-rfc_bellman_edition"
version = "0.0.1"
@ -108,7 +343,7 @@ dependencies = [
"block-padding",
"byte-tools",
"byteorder",
"generic-array",
"generic-array 0.12.3",
]
[[package]]
@ -184,6 +419,16 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-mac"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
dependencies = [
"generic-array 0.14.4",
"subtle",
]
[[package]]
name = "csv"
version = "1.1.3"
@ -206,13 +451,33 @@ dependencies = [
"memchr",
]
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.34",
]
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array",
"generic-array 0.12.3",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
@ -278,7 +543,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50c052fa6d4c2f12305ec364bfb8ef884836f3f61ea015b202372ff996d1ac4b"
dependencies = [
"num-bigint",
"num-bigint 0.2.6",
"num-integer",
"num-traits 0.2.12",
"proc-macro2 1.0.18",
@ -391,6 +656,16 @@ dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.1.15"
@ -421,6 +696,15 @@ version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]]
name = "hermit-abi"
version = "0.1.15"
@ -532,10 +816,21 @@ dependencies = [
]
[[package]]
name = "num-integer"
version = "0.1.43"
name = "num-bigint"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535"
dependencies = [
"autocfg",
"num-integer",
"num-traits 0.2.12",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits 0.2.12",
@ -588,9 +883,9 @@ checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
[[package]]
name = "once_cell"
version = "1.4.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "opaque-debug"
@ -598,6 +893,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "pairing_ce"
version = "0.21.1"
@ -685,6 +986,12 @@ dependencies = [
"syn 1.0.34",
]
[[package]]
name = "pin-project-lite"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
[[package]]
name = "pin-utils"
version = "0.1.0"
@ -802,6 +1109,15 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_xorshift"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rdrand"
version = "0.4.0"
@ -854,6 +1170,15 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
[[package]]
name = "rustc_version"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
dependencies = [
"semver",
]
[[package]]
name = "ryu"
version = "1.0.5"
@ -869,7 +1194,7 @@ dependencies = [
"bellman_ce",
"blake2-rfc_bellman_edition",
"byteorder",
"digest",
"digest 0.8.1",
"rand 0.4.6",
"serde",
"serde_derive",
@ -877,6 +1202,24 @@ dependencies = [
"tiny-keccak",
]
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
[[package]]
name = "serde"
version = "1.0.114"
@ -915,9 +1258,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
dependencies = [
"block-buffer",
"digest",
"digest 0.8.1",
"fake-simd",
"opaque-debug",
"opaque-debug 0.2.3",
]
[[package]]
@ -927,9 +1270,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
dependencies = [
"block-buffer",
"digest",
"digest 0.8.1",
"fake-simd",
"opaque-debug",
"opaque-debug 0.2.3",
]
[[package]]
@ -947,6 +1290,12 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "0.15.44"
@ -999,6 +1348,35 @@ dependencies = [
"crunchy",
]
[[package]]
name = "tracing"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8"
dependencies = [
"cfg-if 1.0.0",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98863d0dd09fa59a1b79c6750ad80dbda6b75f4e71c437a6a1a8cb91a8bcbd77"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.34",
]
[[package]]
name = "tracing-core"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46125608c26121c81b0c6d693eab5a420e416da7e43c426d2e8f7df8da8a3acf"
[[package]]
name = "typed-arena"
version = "1.7.0"
@ -1041,6 +1419,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "void"
version = "1.0.2"
@ -1147,9 +1531,30 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zeroize"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.34",
"synstructure",
]
[[package]]
name = "zokrates_abi"
version = "0.1.4"
version = "0.1.5"
dependencies = [
"serde",
"serde_derive",
@ -1164,7 +1569,7 @@ version = "0.1.0"
[[package]]
name = "zokrates_core"
version = "0.6.4"
version = "0.6.6"
dependencies = [
"bellman_ce",
"bincode",
@ -1174,8 +1579,9 @@ dependencies = [
"getrandom 0.2.2",
"hex",
"lazy_static",
"log",
"num",
"num-bigint",
"num-bigint 0.2.6",
"pairing_ce",
"rand 0.4.6",
"rand 0.7.3",
@ -1192,10 +1598,20 @@ dependencies = [
[[package]]
name = "zokrates_embed"
version = "0.1.3"
version = "0.1.4"
dependencies = [
"ark-bls12-377",
"ark-bw6-761",
"ark-crypto-primitives",
"ark-ec",
"ark-ff",
"ark-gm17",
"ark-r1cs-std",
"ark-relations",
"ark-std",
"bellman_ce",
"sapling-crypto_ce",
"zokrates_field",
]
[[package]]
@ -1205,7 +1621,7 @@ dependencies = [
"bellman_ce",
"bincode",
"lazy_static",
"num-bigint",
"num-bigint 0.2.6",
"num-integer",
"num-traits 0.2.12",
"serde",
@ -1216,7 +1632,7 @@ dependencies = [
[[package]]
name = "zokrates_js"
version = "1.0.33"
version = "1.0.35"
dependencies = [
"console_error_panic_hook",
"js-sys",
@ -1231,7 +1647,7 @@ dependencies = [
[[package]]
name = "zokrates_parser"
version = "0.2.2"
version = "0.2.4"
dependencies = [
"pest",
"pest_derive",
@ -1239,7 +1655,7 @@ dependencies = [
[[package]]
name = "zokrates_pest_ast"
version = "0.2.2"
version = "0.2.3"
dependencies = [
"from-pest",
"lazy_static",

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_js"
version = "1.0.35"
version = "1.0.36"
authors = ["Darko Macesic"]
edition = "2018"

View file

@ -1,6 +1,6 @@
{
"name": "zokrates-js",
"version": "1.0.32",
"version": "1.0.35",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View file

@ -2,7 +2,7 @@
"name": "zokrates-js",
"main": "index.js",
"author": "Darko Macesic <darem966@gmail.com>",
"version": "1.0.35",
"version": "1.0.36",
"keywords": [
"zokrates",
"wasm-bindgen",

View file

@ -36,15 +36,11 @@ module.exports = (dep) => {
return {
compile: (source, options = {}) => {
const createConfig = (config) => ({
allow_unconstrained_variables: false,
...config
});
const { location = "main.zok", resolveCallback = () => null, config = {} } = options;
const callback = (currentLocation, importLocation) => {
return resolveFromStdlib(currentLocation, importLocation) || resolveCallback(currentLocation, importLocation);
};
const { program, abi } = zokrates.compile(source, location, callback, createConfig(config));
const { program, abi } = zokrates.compile(source, location, callback, config);
return {
program: new Uint8Array(program),
abi