fix conflicts
This commit is contained in:
commit
2605559f4c
17 changed files with 258 additions and 188 deletions
|
@ -233,12 +233,6 @@ err() {
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
need() {
|
|
||||||
if ! command -v $1 > /dev/null 2>&1; then
|
|
||||||
err "need $1 (command not found)"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
need_cmd curl
|
need_cmd curl
|
||||||
|
|
||||||
|
@ -259,12 +253,11 @@ main() {
|
||||||
done
|
done
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
need basename
|
need_cmd curl
|
||||||
need curl
|
need_cmd install
|
||||||
need install
|
need_cmd mkdir
|
||||||
need mkdir
|
need_cmd mktemp
|
||||||
need mktemp
|
need_cmd tar
|
||||||
need tar
|
|
||||||
|
|
||||||
git="ZoKrates/ZoKrates"
|
git="ZoKrates/ZoKrates"
|
||||||
|
|
||||||
|
|
|
@ -1,51 +1,33 @@
|
||||||
# zokrates.js
|
# zokrates.js
|
||||||
|
|
||||||
You can get JavaScript bindings for ZoKrates by running
|
JavaScript bindings for [ZoKrates](https://github.com/Zokrates/ZoKrates).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install zokrates-js
|
npm install zokrates-js
|
||||||
```
|
```
|
||||||
|
|
||||||
## API
|
## Importing
|
||||||
|
|
||||||
| Function | Description |
|
##### Bundlers
|
||||||
| ------ | ------ |
|
**Note:** As this library uses a model where the wasm module itself is natively an ES module, you will need a bundler of some form.
|
||||||
| initialize | Loads binding wasm module and returns a promise with ZoKrates provider |
|
Currently the only known bundler known to be fully compatible with `zokrates-js` is [Webpack](https://webpack.js.org/).
|
||||||
| compile | Compiles source code into ZoKrates internal representation of arithmetic circuits |
|
The choice of this default was done to reflect the trends of the JS ecosystem.
|
||||||
| computeWitness | Computes a valid assignment of the variables, which include the results of the computation |
|
|
||||||
| setup | Generates a trusted setup for the compiled program |
|
|
||||||
| exportSolidityVerifier | Generates a Solidity contract which contains the generated verification key and a public function to verify a solution to the compiled program |
|
|
||||||
| generateProof | Generates a proof for a computation of the compiled program |
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Importing
|
|
||||||
|
|
||||||
Bundlers
|
|
||||||
```js
|
```js
|
||||||
import { initialize } from 'zokrates-js';
|
import { initialize } from 'zokrates-js';
|
||||||
```
|
```
|
||||||
|
|
||||||
Node
|
##### Node
|
||||||
```js
|
```js
|
||||||
const { initialize } = require('zokrates-js/node');
|
const { initialize } = require('zokrates-js/node');
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example
|
## Example
|
||||||
```js
|
```js
|
||||||
function importResolver(currentLocation, importLocation) {
|
|
||||||
// implement your resolving logic here
|
|
||||||
return {
|
|
||||||
source: "def main(): return",
|
|
||||||
location: importLocation
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize().then((zokratesProvider) => {
|
initialize().then((zokratesProvider) => {
|
||||||
const source = "def main(private field a) -> field: return a * a";
|
const source = "def main(private field a) -> field: return a * a";
|
||||||
|
|
||||||
// compilation
|
// compilation
|
||||||
const artifacts = zokratesProvider.compile(source, "main", importResolver);
|
const artifacts = zokratesProvider.compile(source);
|
||||||
|
|
||||||
// computation
|
// computation
|
||||||
const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]);
|
const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]);
|
||||||
|
@ -60,3 +42,103 @@ initialize().then((zokratesProvider) => {
|
||||||
const verifier = zokratesProvider.exportSolidityVerifier(keypair.vk, "v1");
|
const verifier = zokratesProvider.exportSolidityVerifier(keypair.vk, "v1");
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
##### initialize()
|
||||||
|
Returns an initialized `ZoKratesProvider` as a promise.
|
||||||
|
|
||||||
|
```js
|
||||||
|
initialize().then(zokratesProvider => {
|
||||||
|
// call api functions here
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns: `Promise<ZoKratesProvider>`
|
||||||
|
|
||||||
|
##### compile(source[, options])
|
||||||
|
Compiles source code into ZoKrates internal representation of arithmetic circuits.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
* `source` - Source code to compile
|
||||||
|
* `options` - Compilation options
|
||||||
|
|
||||||
|
Returns: `CompilationArtifacts`
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
|
||||||
|
Compilation:
|
||||||
|
```js
|
||||||
|
const artifacts = zokratesProvider.compile("def main() -> (): return");
|
||||||
|
```
|
||||||
|
|
||||||
|
Compilation with custom options:
|
||||||
|
```js
|
||||||
|
const source = "...";
|
||||||
|
const options = {
|
||||||
|
location: "main.zok", // location of the root module
|
||||||
|
resolveCallback: (currentLocation, importLocation) => {
|
||||||
|
console.log(currentLocation + ' is importing ' + importLocation);
|
||||||
|
return {
|
||||||
|
source: "def main() -> (): return",
|
||||||
|
location: importLocation
|
||||||
|
};
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
is_release: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const artifacts = zokratesProvider.compile(source, options);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** The `resolveCallback` function is used to resolve dependencies.
|
||||||
|
This callback receives the current module location and the import location of the module which is being imported.
|
||||||
|
The callback must synchronously return either an error, `null` or a valid `ResolverResult` object like shown in the example above.
|
||||||
|
|
||||||
|
##### computeWitness(artifacts, args)
|
||||||
|
Computes a valid assignment of the variables, which include the results of the computation.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
* `artifacts` - Compilation artifacts
|
||||||
|
* `args` - Array of arguments (eg. `["1", "2", true]`)
|
||||||
|
|
||||||
|
Returns: `ComputationResult`
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```js
|
||||||
|
const code = 'def main(private field a) -> (field): return a * a';
|
||||||
|
const artifacts = zokratesProvider.compile(code);
|
||||||
|
|
||||||
|
const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]);
|
||||||
|
|
||||||
|
console.log(witness); // Resulting witness which can be used to generate a proof
|
||||||
|
console.log(output); // Computation output: ["4"]
|
||||||
|
```
|
||||||
|
|
||||||
|
##### setup(program)
|
||||||
|
Generates a trusted setup for the compiled program.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
* `program` - Compiled program
|
||||||
|
|
||||||
|
Returns: `SetupKeypair`
|
||||||
|
|
||||||
|
##### exportSolidityVerifier(verificationKey, abi)
|
||||||
|
Generates a Solidity contract which contains the generated verification key and a public function to verify proofs of computation of the compiled program.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
* `verificationKey` - Verification key from the setup keypair
|
||||||
|
* `abi` - Abi version (`"v1"` | `"v2"`)
|
||||||
|
|
||||||
|
Returns: `string`
|
||||||
|
|
||||||
|
##### generateProof(program, witness, provingKey)
|
||||||
|
Generates a proof for a computation of the compiled program.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
* `program` - Compiled program
|
||||||
|
* `witness` - Witness (valid assignment of the variables) from the computation result
|
||||||
|
* `provingKey` - Proving key from the setup keypair
|
||||||
|
|
||||||
|
Returns: `Proof`
|
||||||
|
|
|
@ -409,23 +409,13 @@ impl<'ast, T: Field> From<pest::Spread<'ast>> for absy::SpreadNode<'ast, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, T: Field> From<pest::Range<'ast>> for absy::RangeNode<T> {
|
impl<'ast, T: Field> From<pest::Range<'ast>> for absy::RangeNode<'ast, T> {
|
||||||
fn from(range: pest::Range<'ast>) -> absy::RangeNode<T> {
|
fn from(range: pest::Range<'ast>) -> absy::RangeNode<'ast, T> {
|
||||||
use absy::NodeValue;
|
use absy::NodeValue;
|
||||||
|
|
||||||
let from = range
|
let from = range.from.map(|e| absy::ExpressionNode::from(e.0));
|
||||||
.from
|
|
||||||
.map(|e| match absy::ExpressionNode::from(e.0).value {
|
|
||||||
absy::Expression::FieldConstant(n) => n,
|
|
||||||
e => unimplemented!("Range bounds should be constants, found {}", e),
|
|
||||||
});
|
|
||||||
|
|
||||||
let to = range
|
let to = range.to.map(|e| absy::ExpressionNode::from(e.0));
|
||||||
.to
|
|
||||||
.map(|e| match absy::ExpressionNode::from(e.0).value {
|
|
||||||
absy::Expression::FieldConstant(n) => n,
|
|
||||||
e => unimplemented!("Range bounds should be constants, found {}", e),
|
|
||||||
});
|
|
||||||
|
|
||||||
absy::Range { from, to }.span(range.span)
|
absy::Range { from, to }.span(range.span)
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,7 +395,7 @@ impl<'ast, T: fmt::Debug> fmt::Debug for SpreadOrExpression<'ast, T> {
|
||||||
/// The index in an array selector. Can be a range or an expression.
|
/// The index in an array selector. Can be a range or an expression.
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum RangeOrExpression<'ast, T> {
|
pub enum RangeOrExpression<'ast, T> {
|
||||||
Range(RangeNode<T>),
|
Range(RangeNode<'ast, T>),
|
||||||
Expression(ExpressionNode<'ast, T>),
|
Expression(ExpressionNode<'ast, T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,14 +439,14 @@ pub struct Spread<'ast, T> {
|
||||||
|
|
||||||
/// A range
|
/// A range
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct Range<T> {
|
pub struct Range<'ast, T> {
|
||||||
pub from: Option<T>,
|
pub from: Option<ExpressionNode<'ast, T>>,
|
||||||
pub to: Option<T>,
|
pub to: Option<ExpressionNode<'ast, T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type RangeNode<T> = Node<Range<T>>;
|
pub type RangeNode<'ast, T> = Node<Range<'ast, T>>;
|
||||||
|
|
||||||
impl<'ast, T: fmt::Display> fmt::Display for Range<T> {
|
impl<'ast, T: fmt::Display> fmt::Display for Range<'ast, T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
|
@ -463,7 +463,7 @@ impl<'ast, T: fmt::Display> fmt::Display for Range<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, T: fmt::Debug> fmt::Debug for Range<T> {
|
impl<'ast, T: fmt::Debug> fmt::Debug for Range<'ast, T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "Range({:?}, {:?})", self.from, self.to)
|
write!(f, "Range({:?}, {:?})", self.from, self.to)
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ impl<'ast> NodeValue for Variable<'ast> {}
|
||||||
impl<'ast> NodeValue for Parameter<'ast> {}
|
impl<'ast> NodeValue for Parameter<'ast> {}
|
||||||
impl<'ast> NodeValue for Import<'ast> {}
|
impl<'ast> NodeValue for Import<'ast> {}
|
||||||
impl<'ast, T: fmt::Display + fmt::Debug + PartialEq> NodeValue for Spread<'ast, T> {}
|
impl<'ast, T: fmt::Display + fmt::Debug + PartialEq> NodeValue for Spread<'ast, T> {}
|
||||||
impl<T: fmt::Display + fmt::Debug + PartialEq> NodeValue for Range<T> {}
|
impl<'ast, T: fmt::Display + fmt::Debug + PartialEq> NodeValue for Range<'ast, T> {}
|
||||||
|
|
||||||
impl<T: PartialEq> PartialEq for Node<T> {
|
impl<T: PartialEq> PartialEq for Node<T> {
|
||||||
fn eq(&self, other: &Node<T>) -> bool {
|
fn eq(&self, other: &Node<T>) -> bool {
|
||||||
|
|
|
@ -1659,17 +1659,50 @@ impl<'ast> Checker<'ast> {
|
||||||
let array_size = array.size();
|
let array_size = array.size();
|
||||||
let inner_type = array.inner_type().clone();
|
let inner_type = array.inner_type().clone();
|
||||||
|
|
||||||
|
// check that the bounds are valid expressions
|
||||||
let from = r
|
let from = r
|
||||||
.value
|
.value
|
||||||
.from
|
.from
|
||||||
.map(|v| v.to_dec_string().parse::<usize>().unwrap())
|
.map(|e| self.check_expression(e, module_id, &types))
|
||||||
.unwrap_or(0);
|
.unwrap_or(Ok(FieldElementExpression::Number(T::from(0)).into()))?;
|
||||||
|
|
||||||
let to = r
|
let to = r
|
||||||
.value
|
.value
|
||||||
.to
|
.to
|
||||||
.map(|v| v.to_dec_string().parse::<usize>().unwrap())
|
.map(|e| self.check_expression(e, module_id, &types))
|
||||||
.unwrap_or(array_size);
|
.unwrap_or(Ok(FieldElementExpression::Number(T::from(
|
||||||
|
array_size,
|
||||||
|
))
|
||||||
|
.into()))?;
|
||||||
|
|
||||||
|
// check the bounds are field constants
|
||||||
|
// Note: it would be nice to allow any field expression, and check it's a constant after constant propagation,
|
||||||
|
// but it's tricky from a type perspective: the size of the slice changes the type of the resulting array,
|
||||||
|
// which doesn't work well with our static array approach. Enabling arrays to have unknown size introduces a lot
|
||||||
|
// of complexity in the compiler, as function selection in inlining requires knowledge of the array size, but
|
||||||
|
// determining array size potentially requires inlining and propagating. This suggests we would need semantic checking
|
||||||
|
// to happen iteratively with inlining and propagation, which we can't do now as we go from absy to typed_absy
|
||||||
|
let from = match from {
|
||||||
|
TypedExpression::FieldElement(FieldElementExpression::Number(n)) => Ok(n.to_dec_string().parse::<usize>().unwrap()),
|
||||||
|
e => Err(ErrorInner {
|
||||||
|
pos: Some(pos),
|
||||||
|
message: format!(
|
||||||
|
"Expected the lower bound of the range to be a constant field, found {}",
|
||||||
|
e
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let to = match to {
|
||||||
|
TypedExpression::FieldElement(FieldElementExpression::Number(n)) => Ok(n.to_dec_string().parse::<usize>().unwrap()),
|
||||||
|
e => Err(ErrorInner {
|
||||||
|
pos: Some(pos),
|
||||||
|
message: format!(
|
||||||
|
"Expected the higher bound of the range to be a constant field, found {}",
|
||||||
|
e
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}?;
|
||||||
|
|
||||||
match (from, to, array_size) {
|
match (from, to, array_size) {
|
||||||
(f, _, s) if f > s => Err(ErrorInner {
|
(f, _, s) if f > s => Err(ErrorInner {
|
||||||
|
|
1
zokrates_js/.gitignore
vendored
1
zokrates_js/.gitignore
vendored
|
@ -5,3 +5,4 @@ pkg
|
||||||
wasm-pack.log
|
wasm-pack.log
|
||||||
stdlib
|
stdlib
|
||||||
stdlib.json
|
stdlib.json
|
||||||
|
metadata.json
|
|
@ -6,57 +6,4 @@ JavaScript bindings for [ZoKrates](https://github.com/Zokrates/ZoKrates) project
|
||||||
npm install zokrates-js
|
npm install zokrates-js
|
||||||
```
|
```
|
||||||
|
|
||||||
## API
|
Check the offical [ZoKrates documentation](https://zokrates.github.io/zokrates_js.html) for more details.
|
||||||
|
|
||||||
| Function | Description |
|
|
||||||
| ------ | ------ |
|
|
||||||
| initialize | Loads binding wasm module and returns a promise with ZoKrates provider |
|
|
||||||
| compile | Compiles source code into ZoKrates internal representation of arithmetic circuits |
|
|
||||||
| computeWitness | Computes a valid assignment of the variables, which include the results of the computation |
|
|
||||||
| setup | Generates a trusted setup for the compiled program |
|
|
||||||
| exportSolidityVerifier | Generates a Solidity contract which contains the generated verification key and a public function to verify a solution to the compiled program |
|
|
||||||
| generateProof | Generates a proof for a computation of the compiled program |
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Importing
|
|
||||||
|
|
||||||
Bundlers
|
|
||||||
```js
|
|
||||||
import { initialize } from 'zokrates-js';
|
|
||||||
```
|
|
||||||
|
|
||||||
Node
|
|
||||||
```js
|
|
||||||
const { initialize } = require('zokrates-js/node');
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```js
|
|
||||||
function importResolver(currentLocation, importLocation) {
|
|
||||||
// implement your resolving logic here
|
|
||||||
return {
|
|
||||||
source: "def main(): return",
|
|
||||||
location: importLocation
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize().then((zokratesProvider) => {
|
|
||||||
const source = "def main(private field a) -> field: return a * a";
|
|
||||||
|
|
||||||
// compilation
|
|
||||||
const artifacts = zokratesProvider.compile(source, "main", importResolver);
|
|
||||||
|
|
||||||
// computation
|
|
||||||
const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]);
|
|
||||||
|
|
||||||
// run setup
|
|
||||||
const keypair = zokratesProvider.setup(artifacts.program);
|
|
||||||
|
|
||||||
// generate proof
|
|
||||||
const proof = zokratesProvider.generateProof(artifacts.program, witness, keypair.pk);
|
|
||||||
|
|
||||||
// export solidity verifier
|
|
||||||
const verifier = zokratesProvider.exportSolidityVerifier(keypair.vk, "v1");
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
|
@ -3,10 +3,11 @@ const gulp = require('gulp');
|
||||||
const dree = require('dree');
|
const dree = require('dree');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const toml = require('toml');
|
||||||
|
|
||||||
/** stdlib constants */
|
/** stdlib constants */
|
||||||
const stdlibRoot = '../zokrates_stdlib/stdlib';
|
const stdlibRoot = '../zokrates_stdlib/stdlib';
|
||||||
const output = 'stdlib.json';
|
const stdlibOutput = 'stdlib.json';
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
extensions: ['zok']
|
extensions: ['zok']
|
||||||
|
@ -22,6 +23,17 @@ gulp.task('stdlib', (done) => {
|
||||||
stdlib[file.relativePath] = content;
|
stdlib[file.relativePath] = content;
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.writeFileSync(path.resolve(__dirname, output), JSON.stringify(stdlib));
|
fs.writeFileSync(path.resolve(__dirname, stdlibOutput), JSON.stringify(stdlib));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task('metadata', (done) => {
|
||||||
|
const config = toml.parse(fs.readFileSync('../zokrates_cli/Cargo.toml').toString());
|
||||||
|
const metadata = JSON.stringify({
|
||||||
|
version: config.package.version
|
||||||
|
});
|
||||||
|
fs.writeFileSync(path.resolve(__dirname, 'metadata.json'), metadata);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('setup', gulp.parallel('stdlib', 'metadata'));
|
19
zokrates_js/index.d.ts
vendored
19
zokrates_js/index.d.ts
vendored
|
@ -4,10 +4,19 @@ declare module 'zokrates-js' {
|
||||||
export type G2Affine = [G1Affine, G1Affine];
|
export type G2Affine = [G1Affine, G1Affine];
|
||||||
export type ProvingKey = Uint8Array;
|
export type ProvingKey = Uint8Array;
|
||||||
|
|
||||||
|
export type SolidityAbi = "v1" | "v2";
|
||||||
|
export type ResolveCallback = (location: string, path: string) => ResolverResult;
|
||||||
|
|
||||||
export interface CompileConfig {
|
export interface CompileConfig {
|
||||||
is_release: boolean
|
is_release: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CompileOptions {
|
||||||
|
location?: string,
|
||||||
|
resolveCallback?: ResolveCallback,
|
||||||
|
config?: CompileConfig
|
||||||
|
}
|
||||||
|
|
||||||
export interface VerificationKey {
|
export interface VerificationKey {
|
||||||
alpha: G1Affine,
|
alpha: G1Affine,
|
||||||
beta: G2Affine,
|
beta: G2Affine,
|
||||||
|
@ -49,16 +58,18 @@ declare module 'zokrates-js' {
|
||||||
pk: ProvingKey,
|
pk: ProvingKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SolidityAbi = "v1" | "v2";
|
|
||||||
export type ResolveCallback = (location: string, path: string) => ResolverResult;
|
|
||||||
|
|
||||||
export interface ZoKratesProvider {
|
export interface ZoKratesProvider {
|
||||||
compile(source: string, location: string, callback: ResolveCallback, config?: CompileConfig): CompilationArtifacts;
|
compile(source: string, options?: CompileOptions): CompilationArtifacts;
|
||||||
setup(program: Uint8Array): SetupKeypair;
|
setup(program: Uint8Array): SetupKeypair;
|
||||||
computeWitness(artifacts: CompilationArtifacts, args: any[]): ComputationResult;
|
computeWitness(artifacts: CompilationArtifacts, args: any[]): ComputationResult;
|
||||||
exportSolidityVerifier(verifyingKey: VerificationKey, abi: SolidityAbi): string;
|
exportSolidityVerifier(verifyingKey: VerificationKey, abi: SolidityAbi): string;
|
||||||
generateProof(program: Uint8Array, witness: string, provingKey: Uint8Array): Proof;
|
generateProof(program: Uint8Array, witness: string, provingKey: Uint8Array): Proof;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Metadata {
|
||||||
|
version: string
|
||||||
|
}
|
||||||
|
|
||||||
export function initialize(): Promise<ZoKratesProvider>;
|
export function initialize(): Promise<ZoKratesProvider>;
|
||||||
|
export var metadata: Metadata;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import wrapper from './wrapper';
|
import wrapper from './wrapper';
|
||||||
import stdlib from './stdlib.json';
|
import stdlib from './stdlib.json';
|
||||||
|
import metadata from './metadata.json';
|
||||||
|
|
||||||
const initialize = async () => {
|
const initialize = async () => {
|
||||||
const zokrates = await import('./pkg/index.js');
|
const zokrates = await import('./pkg/index.js');
|
||||||
return wrapper({ zokrates, stdlib });
|
return wrapper({ zokrates, stdlib });
|
||||||
}
|
}
|
||||||
|
|
||||||
export { initialize };
|
export { initialize, metadata };
|
|
@ -1,5 +1,6 @@
|
||||||
const wrapper = require('../wrapper.js');
|
const wrapper = require('../wrapper.js');
|
||||||
const stdlib = require('../stdlib.json');
|
const stdlib = require('../stdlib.json');
|
||||||
|
const metadata = require('../metadata.json');
|
||||||
|
|
||||||
const initialize = async () => {
|
const initialize = async () => {
|
||||||
return wrapper({
|
return wrapper({
|
||||||
|
@ -8,4 +9,4 @@ const initialize = async () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { initialize };
|
module.exports = { initialize, metadata };
|
6
zokrates_js/package-lock.json
generated
6
zokrates_js/package-lock.json
generated
|
@ -4572,6 +4572,12 @@
|
||||||
"through2": "^2.0.3"
|
"through2": "^2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"toml": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
|
||||||
|
|
|
@ -16,12 +16,13 @@
|
||||||
"index.d.ts",
|
"index.d.ts",
|
||||||
"wrapper.js",
|
"wrapper.js",
|
||||||
"stdlib.json",
|
"stdlib.json",
|
||||||
|
"metadata.json",
|
||||||
"README.md"
|
"README.md"
|
||||||
],
|
],
|
||||||
"types": "index.d.ts",
|
"types": "index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"wasm-pack": "wasm-pack build --out-name index --release",
|
"wasm-pack": "wasm-pack build --out-name index --release",
|
||||||
"setup": "npm install && gulp stdlib",
|
"setup": "npm install && gulp setup",
|
||||||
"prebuild": "npm run setup",
|
"prebuild": "npm run setup",
|
||||||
"build": "npm run build:bundler && npm run build:node",
|
"build": "npm run build:bundler && npm run build:node",
|
||||||
"build:bundler": "rimraf pkg && npm run wasm-pack -- --target bundler && npm run clean-pkg",
|
"build:bundler": "rimraf pkg && npm run wasm-pack -- --target bundler && npm run clean-pkg",
|
||||||
|
@ -39,7 +40,8 @@
|
||||||
"mocha": "^7.1.1",
|
"mocha": "^7.1.1",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"serve": "^11.3.2",
|
"serve": "^11.3.2",
|
||||||
"text-encoding": "^0.7.0"
|
"text-encoding": "^0.7.0",
|
||||||
|
"toml": "^3.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,22 +98,13 @@ impl<'a> Resolver<Error> for JsResolver<'a> {
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
source: JsValue,
|
source: JsValue,
|
||||||
location: JsValue,
|
location: JsValue,
|
||||||
resolve: &js_sys::Function,
|
resolve_callback: &js_sys::Function,
|
||||||
config: JsValue,
|
config: JsValue,
|
||||||
) -> Result<JsValue, JsValue> {
|
) -> Result<JsValue, JsValue> {
|
||||||
|
let resolver = JsResolver::new(resolve_callback);
|
||||||
|
let config: CompileConfig = config.into_serde().unwrap_or(CompileConfig::default());
|
||||||
|
|
||||||
let fmt_error = |e: &CompileError| format!("{}:{}", e.file().display(), e.value());
|
let fmt_error = |e: &CompileError| format!("{}:{}", e.file().display(), e.value());
|
||||||
let resolver = JsResolver::new(resolve);
|
|
||||||
|
|
||||||
let config: CompileConfig = {
|
|
||||||
if config.is_object() {
|
|
||||||
config
|
|
||||||
.into_serde()
|
|
||||||
.map_err(|e| JsValue::from_str(&format!("Invalid config format: {}", e)))?
|
|
||||||
} else {
|
|
||||||
CompileConfig::default()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let artifacts: CompilationArtifacts<Bn128Field> = core_compile(
|
let artifacts: CompilationArtifacts<Bn128Field> = core_compile(
|
||||||
source.as_string().unwrap(),
|
source.as_string().unwrap(),
|
||||||
PathBuf::from(location.as_string().unwrap()),
|
PathBuf::from(location.as_string().unwrap()),
|
||||||
|
@ -208,8 +199,6 @@ pub fn generate_proof(program: JsValue, witness: JsValue, pk: JsValue) -> Result
|
||||||
|
|
||||||
#[wasm_bindgen(start)]
|
#[wasm_bindgen(start)]
|
||||||
pub fn main_js() -> Result<(), JsValue> {
|
pub fn main_js() -> Result<(), JsValue> {
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,112 +14,113 @@ describe('tests', function() {
|
||||||
describe("compilation", () => {
|
describe("compilation", () => {
|
||||||
it('should compile', function() {
|
it('should compile', function() {
|
||||||
assert.doesNotThrow(() => {
|
assert.doesNotThrow(() => {
|
||||||
const artifacts = this.zokrates.compile("def main() -> field: return 42", "main");
|
const artifacts = this.zokrates.compile("def main() -> field: return 42");
|
||||||
assert.ok(artifacts !== undefined);
|
assert.ok(artifacts !== undefined);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw on invalid code', function() {
|
it('should throw on invalid code', function() {
|
||||||
assert.throws(() => this.zokrates.compile(":-)", "main"));
|
assert.throws(() => this.zokrates.compile(":-)"));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should resolve stdlib module', function() {
|
it('should resolve stdlib module', function() {
|
||||||
|
const stdlib = require('../stdlib.json');
|
||||||
assert.doesNotThrow(() => {
|
assert.doesNotThrow(() => {
|
||||||
const code = `
|
const code = `import "${Object.keys(stdlib)[0]}" as func\ndef main(): return`;
|
||||||
def main():
|
this.zokrates.compile(code);
|
||||||
return
|
});
|
||||||
`;
|
|
||||||
this.zokrates.compile(code, "main");
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should resolve user module', function() {
|
it('should resolve user module', function() {
|
||||||
assert.doesNotThrow(() => {
|
assert.doesNotThrow(() => {
|
||||||
const code = 'import "test" as test\ndef main() -> field: return test()';
|
const code = 'import "test" as test\ndef main() -> field: return test()';
|
||||||
this.zokrates.compile(code, "main", (_, path) => {
|
const options = {
|
||||||
|
resolveCallback: (_, path) => {
|
||||||
return {
|
return {
|
||||||
source: "def main() -> field: return 1",
|
source: "def main() -> (field): return 1",
|
||||||
location: path
|
location: path
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.zokrates.compile(code, options);
|
||||||
});
|
});
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw on invalid module', function() {
|
it('should throw on unresolved module', function() {
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
const code = 'import "test" as test\ndef main() -> field: return test()';
|
const code = 'import "test" as test\ndef main() -> field: return test()';
|
||||||
this.zokrates.compile(code, "main", (_loc, _path) => null);
|
this.zokrates.compile(code);
|
||||||
})
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
|
||||||
|
|
||||||
describe("computation", () => {
|
describe("computation", () => {
|
||||||
it('should compute with valid inputs', function() {
|
it('should compute with valid inputs', function() {
|
||||||
assert.doesNotThrow(() => {
|
assert.doesNotThrow(() => {
|
||||||
const code = 'def main(private field a) -> field: return a * a';
|
const code = 'def main(private field a) -> field: return a * a';
|
||||||
const artifacts = this.zokrates.compile(code, "main", null);
|
const artifacts = this.zokrates.compile(code);
|
||||||
|
|
||||||
const result = this.zokrates.computeWitness(artifacts, ["2"])
|
const result = this.zokrates.computeWitness(artifacts, ["2"]);
|
||||||
const output = JSON.parse(result.output);
|
const output = JSON.parse(result.output);
|
||||||
|
|
||||||
assert.deepEqual(output, ["4"]);
|
assert.deepEqual(output, ["4"]);
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw on invalid input count', function() {
|
it('should throw on invalid input count', function() {
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
const code = 'def main(private field a) -> field: return a * a';
|
const code = 'def main(private field a) -> field: return a * a';
|
||||||
const artifacts = this.zokrates.compile(code, "main", null);
|
const artifacts = this.zokrates.compile(code);
|
||||||
|
|
||||||
this.zokrates.computeWitness(artifacts, ["1", "2"])
|
this.zokrates.computeWitness(artifacts, ["1", "2"]);
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw on invalid input type', function() {
|
it('should throw on invalid input type', function() {
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
const code = 'def main(private field a) -> field: return a * a';
|
const code = 'def main(private field a) -> field: return a * a';
|
||||||
const artifacts = this.zokrates.compile(code, "main", null);
|
const artifacts = this.zokrates.compile(code);
|
||||||
|
|
||||||
this.zokrates.computeWitness(artifacts, [true])
|
this.zokrates.computeWitness(artifacts, [true]);
|
||||||
})
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
|
||||||
|
|
||||||
describe("setup", () => {
|
describe("setup", () => {
|
||||||
it('should run setup', function() {
|
it('should run setup', function() {
|
||||||
assert.doesNotThrow(() => {
|
assert.doesNotThrow(() => {
|
||||||
const code = 'def main(private field a) -> field: return a * a';
|
const code = 'def main(private field a) -> field: return a * a';
|
||||||
const artifacts = this.zokrates.compile(code, "main", null);
|
const artifacts = this.zokrates.compile(code);
|
||||||
|
|
||||||
this.zokrates.setup(artifacts.program);
|
this.zokrates.setup(artifacts.program);
|
||||||
})
|
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("export-verifier", () => {
|
describe("export-verifier", () => {
|
||||||
it('should export solidity verifier', function() {
|
it('should export solidity verifier', function() {
|
||||||
assert.doesNotThrow(() => {
|
assert.doesNotThrow(() => {
|
||||||
const code = 'def main(private field a) -> field: return a * a';
|
const code = 'def main(private field a) -> field: return a * a';
|
||||||
const artifacts = this.zokrates.compile(code, "main", null);
|
const artifacts = this.zokrates.compile(code);
|
||||||
const keypair = this.zokrates.setup(artifacts.program);
|
const keypair = this.zokrates.setup(artifacts.program);
|
||||||
|
|
||||||
const verifier = this.zokrates.exportSolidityVerifier(keypair.vk, "v1");
|
const verifier = this.zokrates.exportSolidityVerifier(keypair.vk, "v1");
|
||||||
assert.ok(verifier.length > 0)
|
assert.ok(verifier.length > 0);
|
||||||
})
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
|
||||||
|
|
||||||
describe("generate-proof", () => {
|
describe("generate-proof", () => {
|
||||||
it('should generate proof', function() {
|
it('should generate proof', function() {
|
||||||
assert.doesNotThrow(() => {
|
assert.doesNotThrow(() => {
|
||||||
const code = 'def main(private field a) -> field: return a * a';
|
const code = 'def main(private field a) -> field: return a * a';
|
||||||
const artifacts = this.zokrates.compile(code, "main", null);
|
const artifacts = this.zokrates.compile(code);
|
||||||
const computationResult = this.zokrates.computeWitness(artifacts, ["2"])
|
const computationResult = this.zokrates.computeWitness(artifacts, ["2"])
|
||||||
const keypair = this.zokrates.setup(artifacts.program);
|
const keypair = this.zokrates.setup(artifacts.program);
|
||||||
const proof = this.zokrates.generateProof(artifacts.program, computationResult.witness, keypair.pk);
|
const proof = this.zokrates.generateProof(artifacts.program, computationResult.witness, keypair.pk);
|
||||||
|
|
||||||
assert.ok(proof !== undefined);
|
assert.ok(proof !== undefined);
|
||||||
assert.deepEqual(proof.inputs, ["0x0000000000000000000000000000000000000000000000000000000000000004"])
|
assert.deepEqual(proof.inputs, ["0x0000000000000000000000000000000000000000000000000000000000000004"]);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,11 +35,12 @@ module.exports = (dep) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
compile: (source, location, callback) => {
|
compile: (source, options = {}) => {
|
||||||
let importCallback = (currentLocation, importLocation) => {
|
const { location = "main.zok", resolveCallback = () => null, config } = options;
|
||||||
return resolveFromStdlib(currentLocation, importLocation) || callback(currentLocation, importLocation);
|
const callback = (currentLocation, importLocation) => {
|
||||||
|
return resolveFromStdlib(currentLocation, importLocation) || resolveCallback(currentLocation, importLocation);
|
||||||
};
|
};
|
||||||
const { program, abi } = zokrates.compile(source, location, importCallback);
|
const { program, abi } = zokrates.compile(source, location, callback, config);
|
||||||
return {
|
return {
|
||||||
program: Array.from(program),
|
program: Array.from(program),
|
||||||
abi
|
abi
|
||||||
|
|
Loading…
Reference in a new issue