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

Merge pull request #655 from dark64/develop

Update zokrates.js book
This commit is contained in:
Thibaut Schaeffer 2020-08-04 16:50:49 +02:00 committed by GitHub
commit 18ad7907d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 169 additions and 143 deletions

View file

@ -1,51 +1,33 @@
# zokrates.js
You can get JavaScript bindings for ZoKrates by running
JavaScript bindings for [ZoKrates](https://github.com/Zokrates/ZoKrates).
```bash
npm install zokrates-js
```
## API
## Importing
| 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
##### 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.
Currently the only known bundler known to be fully compatible with `zokrates-js` is [Webpack](https://webpack.js.org/).
The choice of this default was done to reflect the trends of the JS ecosystem.
```js
import { initialize } from 'zokrates-js';
```
Node
##### Node
```js
const { initialize } = require('zokrates-js/node');
```
### Example
## 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);
const artifacts = zokratesProvider.compile(source);
// computation
const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]);
@ -60,3 +42,103 @@ initialize().then((zokratesProvider) => {
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`

View file

@ -1,62 +1,9 @@
# zokrates.js
JavaScript bindings for [ZoKrates](https://github.com/Zokrates/ZoKrates) project.
JavaScript bindings for [ZoKrates](https://github.com/Zokrates/ZoKrates) project.
```bash
npm install zokrates-js
```
## API
| 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");
});
```
Check the offical [ZoKrates documentation](https://zokrates.github.io/zokrates_js.html) for more details.

View file

@ -36,4 +36,4 @@ gulp.task('metadata', (done) => {
done();
});
gulp.task('setup', gulp.series('stdlib', 'metadata'));
gulp.task('setup', gulp.parallel('stdlib', 'metadata'));

View file

@ -4,10 +4,19 @@ declare module 'zokrates-js' {
export type G2Affine = [G1Affine, G1Affine];
export type ProvingKey = Uint8Array;
export type SolidityAbi = "v1" | "v2";
export type ResolveCallback = (location: string, path: string) => ResolverResult;
export interface CompileConfig {
is_release: boolean
}
export interface CompileOptions {
location?: string,
resolveCallback?: ResolveCallback,
config?: CompileConfig
}
export interface VerificationKey {
alpha: G1Affine,
beta: G2Affine,
@ -49,11 +58,8 @@ declare module 'zokrates-js' {
pk: ProvingKey,
}
export type SolidityAbi = "v1" | "v2";
export type ResolveCallback = (location: string, path: string) => ResolverResult;
export interface ZoKratesProvider {
compile(source: string, location: string, callback: ResolveCallback, config?: CompileConfig): CompilationArtifacts;
compile(source: string, options?: CompileOptions): CompilationArtifacts;
setup(program: Uint8Array): SetupKeypair;
computeWitness(artifacts: CompilationArtifacts, args: any[]): ComputationResult;
exportSolidityVerifier(verifyingKey: VerificationKey, abi: SolidityAbi): string;

View file

@ -98,22 +98,13 @@ impl<'a> Resolver<Error> for JsResolver<'a> {
pub fn compile(
source: JsValue,
location: JsValue,
resolve: &js_sys::Function,
resolve_callback: &js_sys::Function,
config: 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 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(
source.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)]
pub fn main_js() -> Result<(), JsValue> {
#[cfg(debug_assertions)]
console_error_panic_hook::set_once();
Ok(())
}

View file

@ -14,112 +14,113 @@ describe('tests', function() {
describe("compilation", () => {
it('should compile', function() {
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);
})
});
it('should throw on invalid code', function() {
assert.throws(() => this.zokrates.compile(":-)", "main"));
assert.throws(() => this.zokrates.compile(":-)"));
});
it('should resolve stdlib module', function() {
const stdlib = require('../stdlib.json');
assert.doesNotThrow(() => {
const code = `
def main() -> ():
return
`;
this.zokrates.compile(code, "main");
})
const code = `import "${Object.keys(stdlib)[0]}" as func\ndef main() -> (): return`;
this.zokrates.compile(code);
});
});
it('should resolve user module', function() {
assert.doesNotThrow(() => {
const code = 'import "test" as test\ndef main() -> (field): return test()';
this.zokrates.compile(code, "main", (_, path) => {
return {
source: "def main() -> (field): return 1",
location: path
const options = {
resolveCallback: (_, path) => {
return {
source: "def main() -> (field): return 1",
location: path
}
}
});
})
};
this.zokrates.compile(code, options);
});
});
it('should throw on invalid module', function() {
it('should throw on unresolved module', function() {
assert.throws(() => {
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", () => {
it('should compute with valid inputs', function() {
assert.doesNotThrow(() => {
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);
assert.deepEqual(output, ["4"]);
})
});
});
it('should throw on invalid input count', function() {
assert.throws(() => {
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() {
assert.throws(() => {
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", () => {
it('should run setup', function() {
assert.doesNotThrow(() => {
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);
})
});
});
})
});
describe("export-verifier", () => {
it('should export solidity verifier', function() {
assert.doesNotThrow(() => {
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 verifier = this.zokrates.exportSolidityVerifier(keypair.vk, "v1");
assert.ok(verifier.length > 0)
})
assert.ok(verifier.length > 0);
});
});
})
});
describe("generate-proof", () => {
it('should generate proof', function() {
assert.doesNotThrow(() => {
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 keypair = this.zokrates.setup(artifacts.program);
const proof = this.zokrates.generateProof(artifacts.program, computationResult.witness, keypair.pk);
assert.ok(proof !== undefined);
assert.deepEqual(proof.inputs, ["0x0000000000000000000000000000000000000000000000000000000000000004"])
assert.deepEqual(proof.inputs, ["0x0000000000000000000000000000000000000000000000000000000000000004"]);
})
});
});

View file

@ -35,11 +35,12 @@ module.exports = (dep) => {
}
return {
compile: (source, location, callback) => {
let importCallback = (currentLocation, importLocation) => {
return resolveFromStdlib(currentLocation, importLocation) || callback(currentLocation, importLocation);
compile: (source, options = {}) => {
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, importCallback);
const { program, abi } = zokrates.compile(source, location, callback, config);
return {
program: Array.from(program),
abi