Merge pull request #4249 from ethereum/rln-verification

Add run_verificatiion
pull/5370/head
yann300 1 year ago committed by GitHub
commit 2bb7059c4c
  1. 2
      libs/remix-ws-templates/src/templates/rln/index.ts
  2. 141
      libs/remix-ws-templates/src/templates/rln/scripts/run_verification.ts

@ -9,6 +9,8 @@ export default async () => {
// @ts-ignore // @ts-ignore
'scripts/run_setup.ts': (await import('!!raw-loader!./scripts/run_setup.ts')).default, 'scripts/run_setup.ts': (await import('!!raw-loader!./scripts/run_setup.ts')).default,
// @ts-ignore // @ts-ignore
'scripts/run_verification.ts': (await import('!!raw-loader!./scripts/run_verification.ts')).default,
// @ts-ignore
'templates/groth16_verifier.sol.ejs': (await import('!!raw-loader!./templates/groth16_verifier.sol.ejs')).default, 'templates/groth16_verifier.sol.ejs': (await import('!!raw-loader!./templates/groth16_verifier.sol.ejs')).default,
// @ts-ignore // @ts-ignore
'LICENSE-APACHE': (await import('!!raw-loader!./LICENSE-APACHE')).default, 'LICENSE-APACHE': (await import('!!raw-loader!./LICENSE-APACHE')).default,

@ -0,0 +1,141 @@
import { ethers, BigNumber } from 'ethers'
import { IncrementalMerkleTree } from "@zk-kit/incremental-merkle-tree"
import { poseidon } from "circomlibjs" // v0.0.8
import { ZqField } from 'ffjavascript'
const SNARK_FIELD_SIZE = BigInt('21888242871839275222246405745257275088548364400416034343698204186575808495617')
// Creates the finite field
const Fq = new ZqField(SNARK_FIELD_SIZE)
// 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),
error: (...args) => console.error(...args),
}
/**
* Recovers secret from two shares
* @param x1 signal hash of first message
* @param x2 signal hash of second message
* @param y1 yshare of first message
* @param y2 yshare of second message
* @returns identity secret
*/
function shamirRecovery(x1: bigint, x2: bigint, y1: bigint, y2: bigint): bigint {
const slope = Fq.div(Fq.sub(y2, y1), Fq.sub(x2, x1))
const privateKey = Fq.sub(y1, Fq.mul(slope, x1))
return Fq.normalize(privateKey)
}
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 hashNullifier(message: any): bigint {
return BigInt(ethers.utils.keccak256(message)) >> BigInt(8)
}
async function prove (signals, wasm, wtns, r1cs, zkey_final, vKey) {
console.log('calculate')
await snarkjs.wtns.calculate(signals, wasm, wtns);
console.log('check')
await snarkjs.wtns.check(r1cs, wtns, logger);
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);
return {
proof,
x: publicSignals[3],
y: publicSignals[0]
}
}
(async () => {
try {
// @ts-ignore
const r1csBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/rln.r1cs', true);
// @ts-ignore
const r1cs = new Uint8Array(r1csBuffer);
// @ts-ignore
const wasmBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/rln.wasm', true);
// @ts-ignore
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 vKey = JSON.parse(await remix.call('fileManager', 'readFile', './zk/build/verification_key.json'))
// build list of identity commitments
const secrets = []
const identityCommitments = []
const rateCommitments = []
const userMessageLimit = 0x2
for (let k = 0; k < 2; k++) {
const identitySecret = BigInt(ethers.utils.hexlify(ethers.utils.randomBytes(32)))
secrets.push(identitySecret)
const identityCommitment = poseidon([identitySecret])
const rateCommitment = poseidon([identityCommitment, userMessageLimit])
identityCommitments.push(identityCommitment)
rateCommitments.push(rateCommitment)
}
let tree
try {
tree = new IncrementalMerkleTree(poseidon, 20, BigInt(0), 2, rateCommitments) // Binary tree.
} catch (e) {
console.error(e.message)
return
}
const merkleproof1 = tree.createProof(0)
const appId = 0xa
const epoch = 0x1
const signals1 = {
identitySecret: secrets[0],
userMessageLimit,
messageId: 0x0,
pathElements: merkleproof1.siblings,
identityPathIndex: merkleproof1.pathIndices,
x: 0xabcd, // hash(message)
externalNullifier: 0xa // hash(epoch, appId)
}
const proof1 = await prove(signals1, wasm, wtns, r1cs, zkey_final, vKey)
const signals2 = {
identitySecret: secrets[0],
userMessageLimit,
messageId: 0x0,
pathElements: merkleproof1.siblings,
identityPathIndex: merkleproof1.pathIndices,
x: 0xabce, // hash(message)
externalNullifier: 0xa // hash(epoch, appId)
}
const proof2 = await prove(signals2, wasm, wtns, r1cs, zkey_final, vKey)
const secret = shamirRecovery(BigInt(proof1.x), BigInt(proof2.x), BigInt(proof1.y), BigInt(proof2.y))
console.log(secret.toString(10))
console.log(Fq.normalize(secrets[0]))
} catch (e) {
console.error(e.message)
}
})()
Loading…
Cancel
Save