support for variable number of datagroups in circuit

This commit is contained in:
0xturboblitz
2024-02-20 17:48:32 -07:00
parent 8829d8ce08
commit 8a95e938f2
12 changed files with 1100 additions and 74 deletions

View File

@@ -3,9 +3,9 @@ pragma circom 2.1.5;
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/sha256/sha256.circom";
template Sha256Bytes(max_num_bytes) {
// Static length sha256 bytes, adapted from zk-email
template Sha256BytesStatic(max_num_bytes) {
signal input in_padded[max_num_bytes];
// signal input in_len_padded_bytes;
signal output out[256];
var num_bits = max_num_bytes * 8;
@@ -19,7 +19,6 @@ template Sha256Bytes(max_num_bytes) {
sha.in[i*8+j] <== bytes[i].out[7-j];
}
}
// sha.in_len_padded_bits <== in_len_padded_bytes * 8;
for (var i = 0; i < 256; i++) {
out[i] <== sha.out[i];

View File

@@ -2,18 +2,20 @@ pragma circom 2.1.5;
include "@zk-email/circuits/helpers/rsa.circom";
include "@zk-email/circuits/helpers/extract.circom";
include "./sha256Bytes.circom";
include "@zk-email/circuits/helpers/sha.circom";
include "./Sha256BytesStatic.circom";
template PassportVerifier(n, k) {
template PassportVerifier(n, k, max_datahashes_bytes) {
signal input mrz[93]; // formatted mrz (5 + 88) chars
signal input dataHashes[297];
signal input dataHashes[max_datahashes_bytes];
signal input datahashes_padded_length;
signal input eContentBytes[104];
signal input pubkey[k];
signal input signature[k];
// compute sha256 of formatted mrz
signal mrzSha[256] <== Sha256Bytes(93)(mrz);
signal mrzSha[256] <== Sha256BytesStatic(93)(mrz);
// get output of sha256 into bytes to check against dataHashes
component sha256_bytes[32];
@@ -29,8 +31,8 @@ template PassportVerifier(n, k) {
dataHashes[31 + i] === sha256_bytes[i].out;
}
// hash dataHashes
signal dataHashesSha[256] <== Sha256Bytes(297)(dataHashes);
// hash dataHashes dynamically
signal dataHashesSha[256] <== Sha256Bytes(max_datahashes_bytes)(dataHashes, datahashes_padded_length);
// get output of dataHashes sha256 into bytes to check against eContent
component dataHashes_sha256_bytes[32];
@@ -47,7 +49,7 @@ template PassportVerifier(n, k) {
}
// hash eContentBytes
signal eContentSha[256] <== Sha256Bytes(104)(eContentBytes);
signal eContentSha[256] <== Sha256BytesStatic(104)(eContentBytes);
// get output of eContentBytes sha256 into k chunks of n bits each
var msg_len = (256 + n) \ n;

View File

@@ -4,9 +4,10 @@ include "circomlib/circuits/poseidon.circom";
include "@zk-email/circuits/helpers/extract.circom";
include "./passport_verifier.circom";
template ProofOfPassport(n, k) {
template ProofOfPassport(n, k, max_datahashes_bytes) {
signal input mrz[93]; // formatted mrz (5 + 88) chars
signal input dataHashes[297];
signal input dataHashes[max_datahashes_bytes];
signal input datahashes_padded_length;
signal input eContentBytes[104];
signal input pubkey[k];
signal input signature[k];
@@ -15,9 +16,10 @@ template ProofOfPassport(n, k) {
signal input address;
// Verify passport
component PV = PassportVerifier(n, k);
component PV = PassportVerifier(n, k, max_datahashes_bytes);
PV.mrz <== mrz;
PV.dataHashes <== dataHashes;
PV.datahashes_padded_length <== datahashes_padded_length;
PV.eContentBytes <== eContentBytes;
PV.pubkey <== pubkey;
PV.signature <== signature;
@@ -45,7 +47,7 @@ template ProofOfPassport(n, k) {
}
}
component main { public [ address ] } = ProofOfPassport(64, 32);
component main { public [ address ] } = ProofOfPassport(64, 32, 320);
// Us:
// 11 + 1 + 3 + 1

View File

@@ -11,7 +11,9 @@
"@types/node": "^20.6.3",
"@types/node-forge": "^1.3.5",
"@zk-email/circuits": "^3.2.2",
"@zk-email/helpers": "^3.1.3",
"chai-as-promised": "^7.1.1",
"circom_tester": "^0.0.20",
"circomlib": "^2.0.5",
"js-sha256": "^0.10.1",
"node-forge": "^1.3.1",

View File

@@ -1,5 +1,8 @@
#!/bin/bash
# Record the start time
START_TIME=$(date +%s)
# Check if the first argument is "app-only"
if [ "$1" == "app-only" ]; then
echo "Building only for the app"
@@ -39,4 +42,9 @@ yarn snarkjs zkey export verificationkey build/proof_of_passport_final.zkey buil
yarn snarkjs zkey export solidityverifier build/proof_of_passport_final.zkey build/Verifier.sol
cp build/Verifier.sol ../contracts/contracts/Verifier.sol
echo "copied Verifier.sol to contracts"
echo "copied Verifier.sol to contracts"
# Calculate and print the time taken by the whole script
END_TIME=$(date +%s)
ELAPSED_TIME=$(($END_TIME - $START_TIME))
echo "Build completed in $ELAPSED_TIME seconds"

View File

@@ -1,12 +1,14 @@
import { describe } from 'mocha'
import chai, { assert, expect } from 'chai'
import chaiAsPromised from 'chai-as-promised'
import { hash, toUnsignedByte, arraysAreEqual, bytesToBigDecimal, formatAndConcatenateDataHashes, formatMrz, splitToWords } from '../../common/src/utils/utils'
import { hash, toUnsignedByte, arraysAreEqual, bytesToBigDecimal, formatMrz, splitToWords } from '../../common/src/utils/utils'
import { groth16 } from 'snarkjs'
import { DataHash } from '../../common/src/utils/types'
import { getPassportData } from '../../common/src/utils/passportData'
import { attributeToPosition } from '../../common/src/constants/constants'
import { MAX_DATAHASHES_LEN, attributeToPosition } from '../../common/src/constants/constants'
import { sha256Pad } from '@zk-email/helpers'
import path from "path";
const fs = require('fs');
const wasm_tester = require("circom_tester").wasm;
chai.use(chaiAsPromised)
@@ -21,13 +23,9 @@ describe('Circuit tests', function () {
const passportData = getPassportData();
const formattedMrz = formatMrz(passportData.mrz);
const mrzHash = hash(formatMrz(passportData.mrz));
const concatenatedDataHashes = formatAndConcatenateDataHashes(
mrzHash,
passportData.dataGroupHashes as DataHash[],
);
const concatenatedDataHashesHashDigest = hash(concatenatedDataHashes);
const concatenatedDataHashesHashDigest = hash(passportData.dataGroupHashes);
console.log('concatenatedDataHashesHashDigest', concatenatedDataHashesHashDigest);
assert(
arraysAreEqual(passportData.eContent.slice(72, 72 + 32), concatenatedDataHashesHashDigest),
@@ -36,10 +34,16 @@ describe('Circuit tests', function () {
const reveal_bitmap = Array(88).fill('1');
const [messagePadded, messagePaddedLen] = sha256Pad(
new Uint8Array(passportData.dataGroupHashes),
MAX_DATAHASHES_LEN
);
inputs = {
mrz: formattedMrz.map(byte => String(byte)),
reveal_bitmap: reveal_bitmap.map(byte => String(byte)),
dataHashes: concatenatedDataHashes.map(toUnsignedByte).map(byte => String(byte)),
dataHashes: Array.from(messagePadded).map((x) => x.toString()),
datahashes_padded_length: messagePaddedLen.toString(),
eContentBytes: passportData.eContent.map(toUnsignedByte).map(byte => String(byte)),
pubkey: splitToWords(
BigInt(passportData.pubKey.modulus),
@@ -53,7 +57,8 @@ describe('Circuit tests', function () {
),
address: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", // sample address
}
console.log('inputs', inputs);
})
describe('Proof', function() {
@@ -210,6 +215,19 @@ describe('Circuit tests', function () {
})
// use these tests with .only to check changes without rebuilding the zkey
describe('Circom tester tests', function() {
it('should prove and verify with valid inputs', async function () {
const circuit = await wasm_tester(
path.join(__dirname, `../circuits/proof_of_passport.circom`),
{ include: ["node_modules"] },
);
const w = await circuit.calculateWitness(inputs);
await circuit.checkConstraints(w);
})
})
})

File diff suppressed because it is too large Load Diff