Update rln scripts

pull/4717/head
ioedeveloper 8 months ago
parent 6bcb2f951c
commit f91fa145fe
  1. 2
      libs/remix-ws-templates/src/templates/rln/index.ts
  2. 2
      libs/remix-ws-templates/src/templates/rln/scripts/groth16/groth16_trusted_setup.ts
  3. 2
      libs/remix-ws-templates/src/templates/rln/scripts/groth16/groth16_zkproof.ts
  4. 3
      libs/remix-ws-templates/src/templates/rln/scripts/plonk/plonk_trusted_setup.ts
  5. 207
      libs/remix-ws-templates/src/templates/rln/scripts/plonk/plonk_zkproof.ts

@ -17,6 +17,8 @@ export default async () => {
// @ts-ignore // @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
'templates/plonk_verifier.sol.ejs': (await import('!!raw-loader!./templates/groth16_verifier.sol.ejs')).default,
// @ts-ignore
'LICENSE-APACHE': (await import('!!raw-loader!./LICENSE-APACHE')).default, 'LICENSE-APACHE': (await import('!!raw-loader!./LICENSE-APACHE')).default,
// @ts-ignore // @ts-ignore
'LICENSE-MIT': (await import('!!raw-loader!./LICENSE-MIT')).default, 'LICENSE-MIT': (await import('!!raw-loader!./LICENSE-MIT')).default,

@ -42,7 +42,7 @@ const logger = {
await remix.call('fileManager', 'writeFile', './zk/keys/groth16/verification_key.json', JSON.stringify(vKey, null, 2)) await remix.call('fileManager', 'writeFile', './zk/keys/groth16/verification_key.json', JSON.stringify(vKey, null, 2))
console.log('save zkey_final') console.log('save zkey_final')
await remix.call('fileManager', 'writeFile', './zk/keys/groth16/zkey_final.txt', JSON.stringify(Array.from(((zkey_final as any).data)))) await remix.call('fileManager', 'writeFile', './zk/keys/groth16/zkey_final.txt', (zkey_final as any).data, { encoding: null })
console.log('setup done.') console.log('setup done.')

@ -76,7 +76,7 @@ async function prove (signals, wasm, wtns, r1cs, zkey_final, vKey) {
const zkey_final = { const zkey_final = {
type: "mem", type: "mem",
data: new Uint8Array(JSON.parse(await remix.call('fileManager', 'readFile', './zk/keys/groth16/zkey_final.txt'))) data: new Uint8Array(await remix.call('fileManager', 'readFile', './zk/keys/groth16/zkey_final.txt', { encoding: null }))
} }
const wtns = { type: "mem" }; const wtns = { type: "mem" };

@ -20,7 +20,8 @@ const snarkjs = require('snarkjs');
const vKey = await snarkjs.zKey.exportVerificationKey(zkey_final) const vKey = await snarkjs.zKey.exportVerificationKey(zkey_final)
console.log('save zkey_final') console.log('save zkey_final')
await remix.call('fileManager', 'writeFile', './zk/keys/plonk/zkey_final.txt', JSON.stringify(Array.from(((zkey_final as any).data)))) // @ts-ignore
await remix.call('fileManager', 'writeFile', './zk/keys/plonk/zkey_final.txt', (zkey_final as any).data, { encoding: null })
console.log('save verification key') console.log('save verification key')
await remix.call('fileManager', 'writeFile', './zk/keys/plonk/verification_key.json', JSON.stringify(vKey, null, 2)) await remix.call('fileManager', 'writeFile', './zk/keys/plonk/verification_key.json', JSON.stringify(vKey, null, 2))

@ -1,6 +1,13 @@
import { ethers, BigNumber } from 'ethers' import { ethers, BigNumber } from 'ethers'
import { IncrementalMerkleTree } from "@zk-kit/incremental-merkle-tree"
import { poseidon } from "circomlibjs" // v0.0.8 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 // eslint-disable-next-line @typescript-eslint/no-var-requires
const snarkjs = require('snarkjs'); const snarkjs = require('snarkjs');
@ -8,86 +15,168 @@ const logger = {
info: (...args) => console.log(...args), info: (...args) => console.log(...args),
debug: (...args) => console.log(...args), debug: (...args) => console.log(...args),
error: (...args) => console.error(...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.plonk.prove(zkey_final, wtns);
const verified = await snarkjs.plonk.verify(vKey, publicSignals, proof, logger);
console.log('zk proof validity', verified);
await remix.call('fileManager', 'writeFile', `zk/build/plonk/input-${Date.now()}.json`, JSON.stringify({
_pubSignals: publicSignals,
_proof: [
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.A[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.A[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.B[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.B[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.C[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.C[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Z[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Z[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T1[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T1[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T2[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T2[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T3[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T3[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Wxi[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Wxi[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Wxiw[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Wxiw[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_a).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_b).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_c).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_s1).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_s2).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_zw).toHexString(), 32),
]
}, null, 2))
console.log('proof done.')
return {
proof,
x: publicSignals[3],
y: publicSignals[0]
}
}
(async () => { (async () => {
try { try {
// @ts-ignore // @ts-ignore
await remix.call('circuit-compiler', 'compile', 'circuits/calculate_hash.circom'); const r1csBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/rln.r1cs', { encoding: null });
// @ts-ignore
const r1cs = new Uint8Array(r1csBuffer);
// @ts-ignore
await remix.call('circuit-compiler', 'compile', 'circuits/rln.circom');
// @ts-ignore // @ts-ignore
const wasmBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/calculate_hash.wasm', { encoding: null }); const wasmBuffer = await remix.call('fileManager', 'readFile', 'circuits/.bin/rln.wasm', { encoding: null });
// @ts-ignore // @ts-ignore
const wasm = new Uint8Array(wasmBuffer); const wasm = new Uint8Array(wasmBuffer);
const zkey_final = { const zkey_final = {
type: "mem", type: "mem",
data: new Uint8Array(JSON.parse(await remix.call('fileManager', 'readFile', './zk/keys/plonk/zkey_final.txt'))) data: new Uint8Array(await remix.call('fileManager', 'readFile', './zk/keys/plonk/zkey_final.txt', { encoding: null }))
} }
const wtns = { type: "mem" };
const wtns = { type: "mem" }; const vKey = JSON.parse(await remix.call('fileManager', 'readFile', './zk/keys/plonk/verification_key.json'))
const value1 = '1234'
const value2 = '2' // build list of identity commitments
const value3 = '3' const secrets = []
const value4 = '4' 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)
}
const wrongValue = '5' // put this in the poseidon hash calculation to simulate a non matching hash. let tree
const signals = { try {
value1, tree = new IncrementalMerkleTree(poseidon, 20, BigInt(0), 2, rateCommitments) // Binary tree.
value2, } catch (e) {
value3, console.error(e.message)
value4, return
hash: poseidon([value1, value2, value3, value4])
} }
console.log('calculate') const merkleproof1 = tree.createProof(0)
await snarkjs.wtns.calculate(signals, wasm, wtns, logger);
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 { proof, publicSignals } = await snarkjs.plonk.prove(zkey_final, wtns); 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 vKey = JSON.parse(await remix.call('fileManager', 'readFile', './zk/keys/plonk/verification_key.json')) const secret = shamirRecovery(BigInt(proof1.x), BigInt(proof2.x), BigInt(proof1.y), BigInt(proof2.y))
const verified = await snarkjs.plonk.verify(vKey, publicSignals, proof);
console.log('zk proof validity', verified); console.log(secret.toString(10))
console.log(Fq.normalize(secrets[0]))
const templates = { const templates = {
plonk: await remix.call('fileManager', 'readFile', 'templates/plonk_verifier.sol.ejs') plonk: await remix.call('fileManager', 'readFile', 'templates/plonk_verifier.sol.ejs')
} }
const solidityContract = await snarkjs.zKey.exportSolidityVerifier(zkey_final, templates) const solidityContract = await snarkjs.zKey.exportSolidityVerifier(zkey_final, templates)
await remix.call('fileManager', 'writeFile', 'zk/build/plonk/zk_verifier.sol', solidityContract) await remix.call('fileManager', 'writeFile', './zk/build/plonk/zk_verifier.sol', solidityContract)
await remix.call('fileManager', 'writeFile', 'zk/build/plonk/input.json', JSON.stringify({
_pubSignals: publicSignals,
_proof: [
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.A[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.A[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.B[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.B[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.C[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.C[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Z[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Z[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T1[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T1[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T2[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T2[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T3[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.T3[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Wxi[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Wxi[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Wxiw[0]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.Wxiw[1]).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_a).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_b).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_c).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_s1).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_s2).toHexString(), 32),
ethers.utils.hexZeroPad(ethers.BigNumber.from(proof.eval_zw).toHexString(), 32),
]
}, null, 2))
console.log('proof done.')
} catch (e) { } catch (e) {
console.error(e.message) console.error(e.message)
} }
})() })()
Loading…
Cancel
Save