├── index.js ├── .gitignore ├── tests ├── witness.wtns ├── multiplier.r1cs ├── setup_2^10.key ├── multiplier.circom ├── read_file.js ├── single.test.js ├── prove_and_verify.rs └── secret.test.js ├── README.md ├── .github └── workflows │ ├── commitlint.yml │ └── test.yml ├── .eslintrc ├── package.json ├── src ├── lib.rs └── api.rs ├── Cargo.toml └── .commitlintrc.js /index.js: -------------------------------------------------------------------------------- 1 | exports.prover = require("./pkg"); 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | yarn-error.log 3 | yarn.lock 4 | node_modules 5 | Cargo.lock 6 | -------------------------------------------------------------------------------- /tests/witness.wtns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xEigenLabs/plonkjs/HEAD/tests/witness.wtns -------------------------------------------------------------------------------- /tests/multiplier.r1cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xEigenLabs/plonkjs/HEAD/tests/multiplier.r1cs -------------------------------------------------------------------------------- /tests/setup_2^10.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xEigenLabs/plonkjs/HEAD/tests/setup_2^10.key -------------------------------------------------------------------------------- /tests/multiplier.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | template Multiplier2() { 4 | signal input a; 5 | signal input b; 6 | signal output c; 7 | c <== a*b; 8 | } 9 | 10 | component main = Multiplier2(); 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PlonkJS 2 | 3 | Javascript/NodeJS Plonk library on [eigen-plonky](https://github.com/0xEigenLabs/eigen-zkvm/tree/main/plonky) and [bellman](https://github.com/matter-labs/bellman). 4 | 5 | # Usage 6 | 7 | ## test 8 | ``` 9 | npm run build_node 10 | npm run test 11 | cargo flamegraph --test prove_and_verify #perf 12 | ``` 13 | 14 | ## compile 15 | ``` 16 | npm run build_node #node 17 | npm run build #web 18 | ``` 19 | -------------------------------------------------------------------------------- /.github/workflows/commitlint.yml: -------------------------------------------------------------------------------- 1 | name: Eigen Lint Commit Messages 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ main ] 7 | 8 | jobs: 9 | commitlint: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | - uses: wagoid/commitlint-github-action@v4 16 | with: 17 | configFile: .commitlintrc.js 18 | firstParent: true -------------------------------------------------------------------------------- /tests/read_file.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const path = require("path"); 3 | module.exports.read_file = function read_file(name) { 4 | let filename = "./tests"; 5 | if (name == "circuit") { 6 | filename = path.join(filename, "multiplier.r1cs"); 7 | } else if (name == "wtns") { 8 | filename = path.join(filename, "./witness.wtns"); 9 | } else if (name == "key") { 10 | filename = path.join(filename, "./setup_2^10.key"); 11 | } else { 12 | throw new Error("Invalid filename") 13 | } 14 | 15 | console.log(filename); 16 | const content = fs.readFileSync(filename); 17 | return content.toJSON().data; 18 | } 19 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "node": true, 6 | "mocha": true, 7 | "es2021": true 8 | }, 9 | "extends": [ 10 | "google", 11 | "eslint:recommended" 12 | ], 13 | "parserOptions": { 14 | "ecmaVersion": 2021, 15 | "sourceType": "module" 16 | }, 17 | "plugins": ["unused-imports"], 18 | "parser": "@typescript-eslint/parser", 19 | "rules": { 20 | "@typescript-eslint/no-var-requires": 0, 21 | "quotes": ["error", "double", { "avoidEscape": true }], 22 | "object-curly-spacing": ["error", "always"], 23 | "require-jsdoc": 0, 24 | "semi": 0, 25 | "unused-imports/no-unused-imports": "error", 26 | "unused-imports/no-unused-vars": [ 27 | "error", 28 | { "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" } 29 | ], 30 | "indent": "off", 31 | "no-unused-vars": "off", 32 | "comma-dangle": ["error", "never"], 33 | "camelcase": "off", 34 | "prefer-const": "off", 35 | "max-len": ["error", { "code": 180 }] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ieigen/plonkjs-node", 3 | "version": "0.0.2", 4 | "description": "Eigen Javascript/NodeJS prover", 5 | "keywords": [ 6 | "zkp", 7 | "plonk", 8 | "privacy", 9 | "blockchain" 10 | ], 11 | "scripts": { 12 | "build": "wasm-pack build --target web --release", 13 | "build_node": "wasm-pack build --target nodejs --release", 14 | "lint": "cargo fmt && ./node_modules/.bin/eslint --fix --ext .js tests", 15 | "test": "wasm-pack test --node && ./node_modules/.bin/mocha tests" 16 | }, 17 | "devDependencies": { 18 | "@wasm-tool/wasm-pack-plugin": "1.5.0", 19 | "chai": "^4.3.0", 20 | "html-webpack-plugin": "^5.3.2", 21 | "mocha": "^3.2.0", 22 | "text-encoding": "^0.7.0", 23 | "webpack": "^5.49.0", 24 | "webpack-cli": "^4.7.2", 25 | "webpack-dev-server": "^3.11.2", 26 | "eslint": "^8.17.0", 27 | "eslint-config-google": "^0.14.0", 28 | "eslint-plugin-unused-imports": "^2.0.0", 29 | "@typescript-eslint/eslint-plugin": "^5.12.0", 30 | "@typescript-eslint/parser": "^5.12.0" 31 | }, 32 | "author": "EigenLabs", 33 | "main": "index.js", 34 | "files": [ 35 | "pkg/*", 36 | "index.js" 37 | ], 38 | "dependencies": { 39 | "circomlib": "^2.0.2", 40 | "circomlibjs": "^0.1.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/single.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const path = require("path"); 3 | const fs = require("fs"); 4 | 5 | const { prover } = require("../"); 6 | 7 | describe("Plonk verifier test", function() { 8 | // this.timeout(5000000); 9 | it("Should return true when proof is correct", async function() { 10 | let basePath = __dirname; 11 | let circuit_file = path.join(basePath, "multiplier.r1cs"); 12 | let circuit_file_content = fs.readFileSync(circuit_file); 13 | let wtns = path.join(basePath, "witness.wtns"); 14 | let wtns_content = fs.readFileSync(wtns); 15 | let srs_monomial_form = path.join(__dirname, "setup_2^10.key"); 16 | let srs_monomial_form_content = fs.readFileSync(srs_monomial_form); 17 | let proof = prover.prove( 18 | circuit_file_content.toJSON().data, 19 | wtns_content.toJSON().data, 20 | srs_monomial_form_content.toJSON().data, 21 | "keccak" 22 | ); 23 | 24 | // generate verify key 25 | let vk = prover.export_verification_key( 26 | srs_monomial_form_content.toJSON().data, 27 | circuit_file_content.toJSON().data 28 | ); 29 | 30 | // verify 31 | let verify_ok = prover.verify( 32 | Array.from(vk.vk_bin), 33 | Array.from(proof.proof_bin), 34 | "keccak" 35 | ) 36 | console.log(verify_ok); 37 | expect(verify_ok).eq(true) 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg(target_arch = "wasm32")] 2 | pub use bellman_ce; 3 | 4 | pub use franklin_crypto; 5 | pub use plonky::*; 6 | 7 | mod api; 8 | pub use api::*; 9 | 10 | #[macro_use] 11 | extern crate hex_literal; 12 | 13 | #[macro_use] 14 | extern crate serde; 15 | 16 | #[cfg(target_arch = "wasm32")] 17 | extern crate wasm_bindgen; 18 | 19 | #[cfg(all(test, target_arch = "wasm32"))] 20 | extern crate wasm_bindgen_test; 21 | 22 | #[cfg(target_arch = "wasm32")] 23 | use wasm_bindgen::prelude::*; 24 | 25 | #[cfg(target_arch = "wasm32")] 26 | #[wasm_bindgen] 27 | extern "C" { 28 | // Use `js_namespace` here to bind `console.log(..)` instead of just 29 | // `log(..)` 30 | #[wasm_bindgen(js_namespace = console)] 31 | pub fn log(s: &str); 32 | 33 | // The `console.log` is quite polymorphic, so we can bind it with multiple 34 | // signatures. Note that we need to use `js_name` to ensure we always call 35 | // `log` in JS. 36 | #[wasm_bindgen(js_namespace = console, js_name = log)] 37 | fn log_u32(a: u32); 38 | 39 | // Multiple arguments too! 40 | #[wasm_bindgen(js_namespace = console, js_name = log)] 41 | fn log_many(a: &str, b: &str); 42 | } 43 | 44 | #[cfg(target_arch = "wasm32")] 45 | #[macro_export] 46 | macro_rules! console_log { 47 | // Note that this is using the `log` function imported above during 48 | // `bare_bones` 49 | ($($t:tt)*) => (log(&format_args!($($t)*).to_string())) 50 | } 51 | -------------------------------------------------------------------------------- /tests/prove_and_verify.rs: -------------------------------------------------------------------------------- 1 | #![cfg(target_arch = "wasm32")] 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[cfg(all(test, target_arch = "wasm32"))] 5 | extern crate wasm_bindgen_test; 6 | 7 | #[cfg(all(test, target_arch = "wasm32"))] 8 | use wasm_bindgen_test::*; 9 | 10 | #[macro_use] 11 | use plonkjs; 12 | use plonkjs::log; 13 | 14 | #[wasm_bindgen] 15 | extern "C" { 16 | type Buffer; 17 | } 18 | #[wasm_bindgen(module = "/tests/read_file.js")] 19 | extern "C" { 20 | #[wasm_bindgen(catch)] 21 | fn read_file(path: &str) -> Result; 22 | } 23 | 24 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 25 | #[test] 26 | fn test_prove_and_verify() { 27 | let circuit_file = read_file("circuit").unwrap(); 28 | 29 | let wtns = read_file("wtns").unwrap(); 30 | let srs_monomial_form = read_file("key").unwrap(); 31 | 32 | let proof = plonkjs::prove( 33 | JsValue::from(circuit_file.clone()), 34 | JsValue::from(wtns), 35 | JsValue::from(srs_monomial_form.clone()), 36 | String::from("keccak"), 37 | ) 38 | .unwrap(); 39 | 40 | let vk = plonkjs::export_verification_key( 41 | JsValue::from(srs_monomial_form), 42 | JsValue::from(circuit_file), 43 | ) 44 | .unwrap(); 45 | 46 | let verified_ok = plonkjs::verify( 47 | JsValue::from_serde(&vk.vk_bin).unwrap(), 48 | JsValue::from_serde(&proof.proof_bin).unwrap(), 49 | String::from("keccak"), 50 | ) 51 | .unwrap(); 52 | assert!(verified_ok); 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Eigen PlonkJS CI 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | build-test: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [18.x] 20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | - uses: actions-rs/toolchain@v1 25 | with: 26 | profile: minimal 27 | toolchain: stable 28 | override: true 29 | - name: Use Node.js ${{ matrix.node-version }} 30 | uses: actions/setup-node@v2 31 | with: 32 | node-version: ${{ matrix.node-version }} 33 | - name: Cache Node Dependencies 34 | id: cache 35 | uses: actions/cache@v2 36 | with: 37 | path: node_modules 38 | key: ${{runner.OS}}-npm-caches-${{ hashFiles('package-lock.json') }} 39 | - name: Install Dependencies 40 | run: npm install --legacy-peer-deps 41 | - name: Install wasm-pack 42 | run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 43 | - name: Start test 44 | run: npm run build_node && npm run test 45 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "plonkjs" 3 | version = "0.0.1" 4 | edition = "2021" 5 | 6 | description = "A Javascript/NodeJS prover for eigen-zkit" 7 | repository = "https://github.com/0xEigenLabs/plonkjs" 8 | license = "Apache-2.0" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | [lib] 12 | crate-type = ["cdylib", "rlib"] 13 | 14 | [target.'cfg(target_arch = "wasm32")'.dependencies] 15 | wasm-bindgen = { version = "0.2.51", features = ["serde-serialize"] } 16 | wasm-bindgen-futures = "0.4.1" 17 | rand = { version="0.6.5", features = ["wasm-bindgen"] } 18 | 19 | [target.'cfg(target_arch = "wasm32")'.dev-dependencies] 20 | wasm-bindgen-test = "0.3" 21 | 22 | [dependencies] 23 | bellman_ce = { git = "https://github.com/matter-labs/bellman", default_features = false, branch = "beta", features = ["wasm", "plonk"] } 24 | franklin-crypto = { git = "https://github.com/matter-labs/franklin-crypto", branch = "beta", features = [ "plonk" ], version = "0.0.5"} 25 | hex-literal = "0.2.1" 26 | num-bigint = "0.3.3" 27 | num-traits = "0.2.8" 28 | serde = { version = "1.0.101", features = ["derive"] } 29 | serde_derive = "1.0" 30 | serde_json = "1.0" 31 | 32 | bellman_vk_codegen = { git = "https://github.com/0xEigenLabs/solidity_plonk_verifier", version = "0.2.0", features = ["wasm"]} 33 | 34 | plonky = { git = "https://github.com/0xEigenLabs/eigen-zkvm", default_features = false, branch = "wasm_dev", features = ["wasm"] } 35 | 36 | [[bench]] 37 | name = "prove_and_verify" 38 | path = "tests/prove_and_verify.rs" 39 | harness = false 40 | -------------------------------------------------------------------------------- /tests/secret.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const path = require("path"); 3 | const fs = require("fs"); 4 | 5 | const { prover } = require("../"); 6 | 7 | describe.skip("Secret prove and verify test", function() { 8 | this.timeout(5000000); 9 | it("Should return true when proof is correct", async function() { 10 | // let basePath = __dirname; 11 | let basePath = "/tmp/secret"; 12 | let circuit_file = path.join(basePath, "main_update_state.r1cs"); 13 | let circuit_file_content = fs.readFileSync(circuit_file); 14 | let wtns = path.join(basePath, "witness.wtns"); 15 | let wtns_content = fs.readFileSync(wtns); 16 | let srs_monomial_form = path.join(basePath, "setup_2^18.key"); 17 | let srs_monomial_form_content = fs.readFileSync(srs_monomial_form); 18 | 19 | let start = new Date().getTime(); 20 | console.log(start); 21 | 22 | let proof = prover.prove( 23 | circuit_file_content.toJSON().data, 24 | wtns_content.toJSON().data, 25 | srs_monomial_form_content.toJSON().data, 26 | "keccak" 27 | ); 28 | 29 | let end = new Date().getTime(); 30 | console.log(`prove cost: ${(end - start)/1000} s`); 31 | // generate verify key 32 | let vk = prover.export_verification_key( 33 | srs_monomial_form_content.toJSON().data, 34 | circuit_file_content.toJSON().data 35 | ); 36 | 37 | let end2 = new Date().getTime(); 38 | console.log(`export vk cost: ${(end2 - end)/1000} s`); 39 | 40 | // verify 41 | let verify_ok = prover.verify( 42 | Array.from(vk.vk_bin), 43 | Array.from(proof.proof_bin), 44 | "keccak" 45 | ) 46 | let end3 = new Date().getTime(); 47 | console.log(`verify cost: ${(end3 - end2)/1000} s`); 48 | expect(verify_ok).eq(true) 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /.commitlintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parserPreset: 'conventional-changelog-conventionalcommits', 3 | rules: { 4 | 'body-leading-blank': [1, 'always'], 5 | 'body-max-line-length': [2, 'always', 100], 6 | 'footer-leading-blank': [1, 'always'], 7 | 'footer-max-line-length': [2, 'always', 100], 8 | 'header-max-length': [2, 'always', 100], 9 | 'subject-full-stop': [2, 'never', '.'], 10 | 'type-case': [2, 'always', 'lower-case'], 11 | 'type-empty': [2, 'never'], 12 | 'type-enum': [ 13 | 2, 14 | 'always', 15 | [ 16 | 'build', 17 | 'chore', 18 | 'ci', 19 | 'docs', 20 | 'feat', 21 | 'fix', 22 | 'perf', 23 | 'refactor', 24 | 'revert', 25 | 'style', 26 | 'test', 27 | ], 28 | ], 29 | }, 30 | prompt: { 31 | questions: { 32 | type: { 33 | description: "Select the type of change that you're committing", 34 | enum: { 35 | feat: { 36 | description: 'A new feature', 37 | title: 'Features', 38 | emoji: '✨', 39 | }, 40 | fix: { 41 | description: 'A bug fix', 42 | title: 'Bug Fixes', 43 | emoji: '🐛', 44 | }, 45 | docs: { 46 | description: 'Documentation only changes', 47 | title: 'Documentation', 48 | emoji: '📚', 49 | }, 50 | style: { 51 | description: 52 | 'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)', 53 | title: 'Styles', 54 | emoji: '💎', 55 | }, 56 | refactor: { 57 | description: 58 | 'A code change that neither fixes a bug nor adds a feature', 59 | title: 'Code Refactoring', 60 | emoji: '📦', 61 | }, 62 | perf: { 63 | description: 'A code change that improves performance', 64 | title: 'Performance Improvements', 65 | emoji: '🚀', 66 | }, 67 | test: { 68 | description: 'Adding missing tests or correcting existing tests', 69 | title: 'Tests', 70 | emoji: '🚨', 71 | }, 72 | build: { 73 | description: 74 | 'Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)', 75 | title: 'Builds', 76 | emoji: '🛠', 77 | }, 78 | ci: { 79 | description: 80 | 'Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)', 81 | title: 'Continuous Integrations', 82 | emoji: '⚙️', 83 | }, 84 | chore: { 85 | description: "Other changes that don't modify src or test files", 86 | title: 'Chores', 87 | emoji: '♻️', 88 | }, 89 | revert: { 90 | description: 'Reverts a previous commit', 91 | title: 'Reverts', 92 | emoji: '🗑', 93 | }, 94 | }, 95 | }, 96 | scope: { 97 | description: 98 | 'What is the scope of this change (e.g. component or filename)', 99 | }, 100 | subject: { 101 | description: 102 | 'Write a short, imperative tense description of the change', 103 | }, 104 | body: { 105 | description: 'Provide a longer description of the change', 106 | }, 107 | isBreaking: { 108 | description: 'Are there any breaking changes?', 109 | }, 110 | breakingBody: { 111 | description: 112 | 'A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself', 113 | }, 114 | breaking: { 115 | description: 'Describe the breaking changes', 116 | }, 117 | isIssueAffected: { 118 | description: 'Does this change affect any open issues?', 119 | }, 120 | issuesBody: { 121 | description: 122 | 'If issues are closed, the commit requires a body. Please enter a longer description of the commit itself', 123 | }, 124 | issues: { 125 | description: 'Add issue references (e.g. "fix #123", "re #123".)', 126 | }, 127 | }, 128 | }, 129 | } 130 | 131 | -------------------------------------------------------------------------------- /src/api.rs: -------------------------------------------------------------------------------- 1 | #![cfg(target_arch = "wasm32")] 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::circom_circuit::CircomCircuit; 5 | use crate::console_log; 6 | use crate::log; 7 | use crate::plonk; 8 | use crate::reader; 9 | use std::io::{BufReader, BufWriter, Cursor}; 10 | 11 | use crate::bellman_ce::{ 12 | kate_commitment::{Crs, CrsForMonomialForm}, 13 | pairing::bn256::Bn256, 14 | plonk::{ 15 | better_cs::cs::PlonkCsWidth4WithNextStepParams, 16 | better_cs::keys::{Proof, VerificationKey}, 17 | }, 18 | Field, PrimeFieldRepr, 19 | }; 20 | 21 | #[wasm_bindgen(getter_with_clone)] 22 | pub struct ProofJS { 23 | pub proof_bin: Vec, 24 | pub proof_json: String, 25 | pub public_json: String, 26 | } 27 | 28 | #[wasm_bindgen(getter_with_clone)] 29 | pub struct VKJS { 30 | pub vk_bin: Vec, 31 | } 32 | 33 | #[wasm_bindgen] 34 | pub fn prove( 35 | circuit_js_objs: JsValue, 36 | witness_js_objs: JsValue, 37 | srs_monomial_form_js_objs: JsValue, 38 | transcript: String, 39 | ) -> Result { 40 | let circuit_value: Vec = circuit_js_objs 41 | .into_serde() 42 | .map_err(|e| JsValue::from(e.to_string()))?; 43 | let r1cs_reader = BufReader::new(Cursor::new(circuit_value)); 44 | let (r1cs, _) = reader::load_r1cs_from_bin(r1cs_reader); 45 | 46 | let witness_value: Vec = witness_js_objs 47 | .into_serde() 48 | .map_err(|e| JsValue::from(e.to_string()))?; 49 | let witness_reader = BufReader::new(Cursor::new(witness_value)); 50 | let witness = 51 | reader::load_witness_from_bin_reader::>>>(witness_reader) 52 | .map_err(|e| JsValue::from(e.to_string()))?; 53 | 54 | let circuit = CircomCircuit { 55 | r1cs: r1cs, 56 | witness: Some(witness), 57 | wire_mapping: None, 58 | aux_offset: plonk::AUX_OFFSET, 59 | }; 60 | let srs_monomial_form_value: Vec = srs_monomial_form_js_objs 61 | .into_serde() 62 | .map_err(|e| JsValue::from(e.to_string()))?; 63 | let mut srs_monomial_form_reader = BufReader::new(Cursor::new(srs_monomial_form_value)); 64 | let srs_monomial_form = Crs::::read(&mut srs_monomial_form_reader) 65 | .map_err(|e| JsValue::from(e.to_string()))?; 66 | 67 | let setup = crate::plonk::SetupForProver::prepare_setup_for_prover( 68 | circuit.clone(), 69 | srs_monomial_form, 70 | None, 71 | ) 72 | .map_err(|e| JsValue::from(e.to_string()))?; 73 | 74 | let proof = setup 75 | .prove(circuit, &transcript) 76 | .map_err(|e| JsValue::from(e.to_string()))?; 77 | let mut contents = BufWriter::new(Vec::new()); 78 | proof 79 | .write(&mut contents) 80 | .map_err(|e| JsValue::from(e.to_string()))?; 81 | 82 | let (inputs, serialized_proof) = bellman_vk_codegen::serialize_proof(&proof); 83 | let ser_proof_str = serde_json::to_string_pretty(&serialized_proof) 84 | .map_err(|e| JsValue::from(e.to_string()))?; 85 | let ser_inputs_str = 86 | serde_json::to_string_pretty(&inputs).map_err(|e| JsValue::from(e.to_string()))?; 87 | 88 | Ok(ProofJS { 89 | proof_bin: contents.into_inner().unwrap(), 90 | proof_json: ser_proof_str, 91 | public_json: ser_inputs_str, 92 | }) 93 | } 94 | 95 | #[wasm_bindgen] 96 | pub fn export_verification_key( 97 | srs_monomial_form_js_objs: JsValue, 98 | circuit_js_objs: JsValue, 99 | ) -> Result { 100 | let circuit_value: Vec = circuit_js_objs 101 | .into_serde() 102 | .map_err(|e| JsValue::from(e.to_string()))?; 103 | 104 | let r1cs_reader = BufReader::new(Cursor::new(circuit_value)); 105 | let (r1cs, _) = reader::load_r1cs_from_bin(r1cs_reader); 106 | 107 | let circuit = CircomCircuit { 108 | r1cs: r1cs, 109 | witness: None, 110 | wire_mapping: None, 111 | aux_offset: plonk::AUX_OFFSET, 112 | }; 113 | 114 | let srs_monomial_form_value: Vec = srs_monomial_form_js_objs 115 | .into_serde() 116 | .map_err(|e| JsValue::from(e.to_string()))?; 117 | 118 | let mut srs_monomial_form_reader = BufReader::new(Cursor::new(srs_monomial_form_value)); 119 | let srs_monomial_form = Crs::::read(&mut srs_monomial_form_reader) 120 | .map_err(|e| JsValue::from(e.to_string()))?; 121 | 122 | let setup = plonk::SetupForProver::prepare_setup_for_prover( 123 | circuit, 124 | //reader::load_key_monomial_form(srs_monomial_form), 125 | srs_monomial_form, 126 | None, 127 | ) 128 | .map_err(|e| JsValue::from(e.to_string()))?; 129 | let vk = setup 130 | .make_verification_key() 131 | .map_err(|e| JsValue::from(e.to_string()))?; 132 | 133 | let mut contents = BufWriter::new(Vec::new()); 134 | vk.write(&mut contents) 135 | .map_err(|e| JsValue::from(e.to_string()))?; 136 | 137 | Ok(VKJS { 138 | vk_bin: contents.into_inner().unwrap(), 139 | }) 140 | } 141 | 142 | #[wasm_bindgen] 143 | pub fn verify( 144 | vk_file_js_objs: JsValue, 145 | proof_bin_js_objs: JsValue, 146 | transcript: String, 147 | ) -> Result { 148 | let vk_file_value: Vec = vk_file_js_objs 149 | .into_serde() 150 | .map_err(|e| JsValue::from(e.to_string()))?; 151 | let mut reader = BufReader::new(Cursor::new(vk_file_value)); 152 | let vk = VerificationKey::::read(&mut reader) 153 | .map_err(|e| JsValue::from(e.to_string()))?; 154 | 155 | let proof_value: Vec = proof_bin_js_objs 156 | .into_serde() 157 | .map_err(|e| JsValue::from(e.to_string()))?; 158 | let proof_reader = BufReader::new(Cursor::new(proof_value)); 159 | let proof = Proof::::read(proof_reader) 160 | .map_err(|e| JsValue::from(e.to_string()))?; 161 | 162 | let ok = plonk::verify(&vk, &proof, &transcript).map_err(|e| JsValue::from(e.to_string()))?; 163 | Ok(ok) 164 | } 165 | --------------------------------------------------------------------------------