commit
18ad7907d3
7 changed files with 169 additions and 143 deletions
|
@ -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`
|
||||
|
|
|
@ -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.
|
|
@ -36,4 +36,4 @@ gulp.task('metadata', (done) => {
|
|||
done();
|
||||
});
|
||||
|
||||
gulp.task('setup', gulp.series('stdlib', 'metadata'));
|
||||
gulp.task('setup', gulp.parallel('stdlib', 'metadata'));
|
14
zokrates_js/index.d.ts
vendored
14
zokrates_js/index.d.ts
vendored
|
@ -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;
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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"]);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue