From db91eb666fceb0283596babb594f2e7d9656c136 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 4 Jan 2024 20:44:29 +0100 Subject: [PATCH] Modify script --- apps/remix-ide/src/app/editor/editor.js | 4 +- .../src/templates/ecdsa/scripts/run_setup.ts | 20 +-- .../ecdsa/scripts/run_verification.ts | 136 ++++++++++-------- 3 files changed, 82 insertions(+), 78 deletions(-) diff --git a/apps/remix-ide/src/app/editor/editor.js b/apps/remix-ide/src/app/editor/editor.js index 98a027b714..e14e08869e 100644 --- a/apps/remix-ide/src/app/editor/editor.js +++ b/apps/remix-ide/src/app/editor/editor.js @@ -208,8 +208,8 @@ class Editor extends Plugin { const paths = path.split('/') paths.pop() const fromPath = paths.join('/') // get current execution context path - for (const match of content.matchAll(/import\s+.*\s+from\s+(?:"(.*?)"|'(.*?)')/g)) { - let pathDep = match[2] + for (const match of content.matchAll(/import\s+(?:(?:\{[^{}]*\}|[^'";]+)\s+from\s+)?['"](@[\w-]+\/[\w-]+)['"];?/g)) { + let pathDep = match[1] if (pathDep.startsWith('./') || pathDep.startsWith('../')) pathDep = resolve(fromPath, pathDep) if (pathDep.startsWith('/')) pathDep = pathDep.substring(1) if (!pathDep.endsWith('.ts')) pathDep = pathDep + '.ts' diff --git a/libs/remix-ws-templates/src/templates/ecdsa/scripts/run_setup.ts b/libs/remix-ws-templates/src/templates/ecdsa/scripts/run_setup.ts index 1d8505b71d..584565406b 100644 --- a/libs/remix-ws-templates/src/templates/ecdsa/scripts/run_setup.ts +++ b/libs/remix-ws-templates/src/templates/ecdsa/scripts/run_setup.ts @@ -3,30 +3,14 @@ import { ethers, BigNumber } from 'ethers' // eslint-disable-next-line @typescript-eslint/no-var-requires const snarkjs = require('snarkjs'); -const logger = { - info: (...args) => console.log(...args), - debug: (...args) => console.log(...args) -}; - -/** - * Creates a keccak256 hash of a message compatible with the SNARK scalar modulus. - * @param message The message to be hashed. - * @returns The message digest. - */ -function hash(message: any): bigint { - message = BigNumber.from(message).toTwos(256).toHexString() - message = ethers.utils.zeroPad(message, 32) - return BigInt(ethers.utils.keccak256(message)) >> BigInt(8) -} - (async () => { try { // @ts-ignore - await remix.call('circuit-compiler', 'generateR1cs', 'circuits/semaphore.circom'); + await remix.call('circuit-compiler', 'generateR1cs', 'circuits/instances/pubkey_membership.circom'); const ptau_final = "https://ipfs-cluster.ethdevops.io/ipfs/QmTiT4eiYz5KF7gQrDsgfCSTRv3wBPYJ4bRN1MmTRshpnW"; // @ts-ignore - const r1csBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/semaphore.r1cs', true); + const r1csBuffer = await remix.call('fileManager', 'readFile', 'circuits/instances/.bin/pubkey_membership.r1cs', true); // @ts-ignore const r1cs = new Uint8Array(r1csBuffer); const zkey_0 = { type: "mem" }; diff --git a/libs/remix-ws-templates/src/templates/ecdsa/scripts/run_verification.ts b/libs/remix-ws-templates/src/templates/ecdsa/scripts/run_verification.ts index e97e4074e9..4b9d4a4313 100644 --- a/libs/remix-ws-templates/src/templates/ecdsa/scripts/run_verification.ts +++ b/libs/remix-ws-templates/src/templates/ecdsa/scripts/run_verification.ts @@ -1,6 +1,7 @@ -import { ethers, BigNumber } from 'ethers' -import { IncrementalMerkleTree } from "@zk-kit/incremental-merkle-tree" -import { poseidon } from "circomlibjs" // v0.0.8 +// @ts-ignore +import { Poseidon, Tree, computeEffEcdsaPubInput } from "@personaelabs/spartan-ecdsa" +// @ts-ignore +import { privateToPublic, hashPersonalMessage, ecsign, utf8ToBytes, bytesToHex } from "@ethereumjs/util" // eslint-disable-next-line @typescript-eslint/no-var-requires const snarkjs = require('snarkjs'); @@ -11,88 +12,107 @@ const logger = { error: (...args) => console.error(...args), } -/** - * Creates a keccak256 hash of a message compatible with the SNARK scalar modulus. - * @param message The message to be hashed. - * @returns The message digest. - */ -function hash(message: any): bigint { - message = BigNumber.from(message).toTwos(256).toHexString() - message = ethers.utils.zeroPad(message, 32) - return BigInt(ethers.utils.keccak256(message)) >> BigInt(8) +function getEffEcdsaCircuitInput (privKey, msg) { + const msgHash = hashPersonalMessage(msg) + const { v, r: _r, s } = ecsign(msgHash, privKey) + const r = BigInt('0x' + _r.map(byte => byte.toString(16).padStart(2, '0')).join('')) + const circuitPubInput = computeEffEcdsaPubInput(r, v, msgHash) + + const input = { + s: BigInt('0x' + s.map(byte => byte.toString(16).padStart(2, '0')).join('')), + Tx: circuitPubInput.Tx, + Ty: circuitPubInput.Ty, + Ux: circuitPubInput.Ux, + Uy: circuitPubInput.Uy + } + + return input } (async () => { try { // @ts-ignore - const r1csBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/semaphore.r1cs', true); + const r1csBuffer = await remix.call('fileManager', 'readFile', 'circuits/instances/.bin/pubkey_membership.r1cs', true) // @ts-ignore - const r1cs = new Uint8Array(r1csBuffer); + const r1cs = new Uint8Array(r1csBuffer) // @ts-ignore - const wasmBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/semaphore.wasm', true); + const wasmBuffer = await remix.call('fileManager', 'readFile', 'circuits/instances/.bin/pubkey_membership.wasm', true) // @ts-ignore - const wasm = new Uint8Array(wasmBuffer); + const wasm = new Uint8Array(wasmBuffer) const zkey_final = { type: "mem", data: new Uint8Array(JSON.parse(await remix.call('fileManager', 'readFile', './zk/build/zk_setup.txt'))) } - const wtns = { type: "mem" }; + const wtns = { type: "mem" } const vKey = JSON.parse(await remix.call('fileManager', 'readFile', './zk/build/verification_key.json')) - - // build list of identity commitments - const secrets = [] - const identityCommitments = [] - for (let k = 0; k < 2; k++) { - const identityTrapdoor = BigInt(ethers.utils.hexlify(ethers.utils.randomBytes(32))) - const identityNullifier = BigInt(ethers.utils.hexlify(ethers.utils.randomBytes(32))) - secrets.push({identityTrapdoor, identityNullifier}) - - const secret = poseidon([identityNullifier, identityTrapdoor]) - const identityCommitment = poseidon([secret]) - identityCommitments.push(identityCommitment) - } - //console.log('incremental tree', identityCommitments.map((x) => x.toString())) + // Construct the tree + const poseidon = new Poseidon() + + await poseidon.initWasm() - let tree - - try { - tree = new IncrementalMerkleTree(poseidon, 20, BigInt(0), 2, identityCommitments) // Binary tree. - } catch (e) { - console.error(e.message) - return + const nLevels = 10 + const tree = new Tree(nLevels, poseidon) + + console.log('done') + + const privKeys = [ + utf8ToBytes("".padStart(16, "🧙")), + utf8ToBytes("".padStart(16, "🪄")), + utf8ToBytes("".padStart(16, "🔮")) + ] + + // Store public key hashes + const pubKeyHashes: bigint[] = [] + + // Compute public key hashes + for (const privKey of privKeys) { + const pubKey = privateToPublic(privKey) + const pubKeyHex = bytesToHex(pubKey) + const hexWithoutPrefix = pubKeyHex.startsWith('0x') ? pubKeyHex.slice(2) : pubKeyHex; + const pubKeyHash = poseidon.hashPubKey(hexWithoutPrefix) + + pubKeyHashes.push(pubKeyHash) + } + + // Insert the pubkey hashes into the tree + for (const pubKeyHash of pubKeyHashes) { + tree.insert(pubKeyHash) } - const index = tree.indexOf(identityCommitments[0]) - console.log(index.toString()) - - const proof1 = tree.createProof(0) + // Sign + const index = 0; // Use privKeys[0] for proving + const privKey = privKeys[index] + const msg = utf8ToBytes("hello world".padStart(16, " ")) + + // Prepare signature proof input + const effEcdsaInput = getEffEcdsaCircuitInput(privKey, msg) + + const merkleProof = tree.createProof(index) - console.log('prepare signals for id ', identityCommitments[0].toString(), tree.indexOf(identityCommitments[0]), proof1.siblings.map((x)=> x.toString())) - const signals = { - identityTrapdoor: secrets[0].identityTrapdoor, - identityNullifier: secrets[0].identityNullifier, - treePathIndices: proof1.pathIndices, - treeSiblings: proof1.siblings, - externalNullifier: hash(42), - signalHash: hash(ethers.utils.formatBytes32String("Hello World")) + ...effEcdsaInput, + siblings: merkleProof.siblings, + pathIndices: merkleProof.pathIndices, + root: tree.root() } + + console.log('signals: ', signals) console.log('calculate') - await snarkjs.wtns.calculate(signals, wasm, wtns); + await snarkjs.wtns.calculate(signals, wasm, wtns) - console.log('check') - await snarkjs.wtns.check(r1cs, wtns, logger); + // console.log('check') + // await snarkjs.wtns.check(r1cs, wtns, logger) - console.log('prove') - const { proof, publicSignals } = await snarkjs.groth16.prove(zkey_final, wtns); + // console.log('prove') + // const { proof, publicSignals } = await snarkjs.groth16.prove(zkey_final, wtns); - const verified = await snarkjs.groth16.verify(vKey, publicSignals, proof, logger); - console.log('zk proof validity', verified); - proof1.root.toString() === publicSignals[0] ? console.log('merkle proof valid') : console.log('merkle proof invalid') + // const verified = await snarkjs.groth16.verify(vKey, publicSignals, proof, logger); + // console.log('zk proof validity', verified); + // proof1.root.toString() === publicSignals[0] ? console.log('merkle proof valid') : console.log('merkle proof invalid')