Merge remote-tracking branch 'origin/dev' into csca

This commit is contained in:
turnoffthiscomputer
2024-06-29 22:55:01 +02:00
71 changed files with 5631 additions and 2621 deletions

View File

@@ -40,8 +40,8 @@ Proof of Passport currently supports the following sig/hash algorithms:
- [x] sha256WithRSAEncryption
- [ ] sha1WithRSAEncryption (under development)
- [ ] rsassaPss
- [x] sha1WithRSAEncryption
- [x] sha256WithRSASSAPSS
- [ ] ecdsa-with-SHA384
- [ ] ecdsa-with-SHA1
- [ ] ecdsa-with-SHA256
@@ -57,12 +57,10 @@ Proof of Passport currently supports the following sig/hash algorithms:
yarn install-circuits
```
## Build circuits (dev only)
```bash
./scripts/build_circuit.sh
./scripts/build_circuits.sh
```
## Run tests
@@ -70,8 +68,4 @@ yarn install-circuits
```bash
yarn test
```
This will run tests with sample data generated on the fly.
The
To run tests with your own passport data, extract your `passportData.json` using the app (available soon), place it in `inputs/`, then run `yarn test`
This will run tests with sample data generated on the fly.

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.5;
include "circomlib/circuits/poseidon.circom";
include "@zk-email/circuits/helpers/extract.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "./utils/isOlderThan.circom";
include "./utils/isValid.circom";
include "binary-merkle-root.circom";
@@ -32,7 +32,7 @@ template Disclose(nLevels) {
poseidon_hasher.inputs[0] <== secret;
poseidon_hasher.inputs[1] <== attestation_id;
poseidon_hasher.inputs[2] <== pubkey_leaf;
signal mrz_packed[3] <== PackBytes(93, 3, 31)(mrz);
signal mrz_packed[3] <== PackBytes(93)(mrz);
for (var i = 0; i < 3; i++) {
poseidon_hasher.inputs[i + 3] <== mrz_packed[i];
}
@@ -60,13 +60,18 @@ template Disclose(nLevels) {
older_than[0] <== isOlderThan.out * majority[0];
older_than[1] <== isOlderThan.out * majority[1];
// constrain bitmap to be 0s or 1s
for (var i = 0; i < 90; i++) {
bitmap[i] * (bitmap[i] - 1) === 0;
}
signal revealedData[90];
for (var i = 0; i < 88; i++) {
revealedData[i] <== mrz[5+i] * bitmap[i];
}
revealedData[88] <== older_than[0] * bitmap[88];
revealedData[89] <== older_than[1] * bitmap[89];
revealedData_packed <== PackBytes(90, 3, 31)(revealedData);
revealedData_packed <== PackBytes(90)(revealedData);
// Generate scope nullifier
component poseidon_nullifier = Poseidon(2);

View File

@@ -0,0 +1,96 @@
pragma circom 2.1.5;
include "./utils/rsaPkcs1.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "./utils/Sha1BytesStatic.circom";
include "./utils/Sha1Bytes.circom";
include "dmpierre/sha1-circom/circuits/sha1.circom";
template PassportVerifier_sha1WithRSAEncryption_65537(n, k, max_datahashes_bytes) {
var hashLen = 20;
var eContentBytesLength = 72 + hashLen; // 92
signal input mrz[93]; // formatted mrz (5 + 88) chars
signal input dg1_hash_offset;
signal input dataHashes[max_datahashes_bytes];
signal input datahashes_padded_length;
signal input eContentBytes[eContentBytesLength];
// pubkey that signed the passport
signal input pubkey[k];
// signature of the passport
signal input signature[k];
// compute sha1 of formatted mrz
signal mrzSha[160] <== Sha1BytesStatic(93)(mrz);
// mrzSha_bytes: list of 32 Bits2Num
component mrzSha_bytes[hashLen];
// cast the 160 bits from mrzSha into a list of 20 bytes
for (var i = 0; i < hashLen; i++) {
mrzSha_bytes[i] = Bits2Num(8);
for (var j = 0; j < 8; j++) {
mrzSha_bytes[i].in[7 - j] <== mrzSha[i * 8 + j];
}
}
// assert mrz_hash equals the one extracted from dataHashes input (bytes dg1_hash_offset to dg1_hash_offset + hashLen)
signal dg1Hash[hashLen] <== SelectSubArray(max_datahashes_bytes, hashLen)(dataHashes, dg1_hash_offset, hashLen);
for(var i = 0; i < hashLen; i++) {
dg1Hash[i] === mrzSha_bytes[i].out;
}
// hash dataHashes dynamically
signal dataHashesSha[160] <== Sha1Bytes(max_datahashes_bytes)(dataHashes, datahashes_padded_length);
// get output of dataHashes into bytes to check against eContent
component dataHashesSha_bytes[hashLen];
for (var i = 0; i < hashLen; i++) {
dataHashesSha_bytes[i] = Bits2Num(8);
for (var j = 0; j < 8; j++) {
dataHashesSha_bytes[i].in[7 - j] <== dataHashesSha[i * 8 + j];
}
}
// assert dataHashesSha is in eContentBytes in range bytes 72 to 92
for(var i = 0; i < hashLen; i++) {
eContentBytes[eContentBytesLength - hashLen + i] === dataHashesSha_bytes[i].out;
}
// hash eContentBytes
signal eContentSha[160] <== Sha1BytesStatic(eContentBytesLength)(eContentBytes);
// get output of eContentBytes sha1 into k chunks of n bits each
var msg_len = (160 + n) \ n;
//eContentHash: list of length 160/n +1 of components of n bits
component eContentHash[msg_len];
for (var i = 0; i < msg_len; i++) {
eContentHash[i] = Bits2Num(n);
}
for (var i = 0; i < 160; i++) {
eContentHash[i \ n].in[i % n] <== eContentSha[159 - i];
}
for (var i = 160; i < n * msg_len; i++) {
eContentHash[i \ n].in[i % n] <== 0;
}
// verify eContentHash signature
component rsa = RSAVerify65537(n, k);
for (var i = 0; i < msg_len; i++) {
rsa.base_message[i] <== eContentHash[i].out;
}
for (var i = msg_len; i < k; i++) {
rsa.base_message[i] <== 0;
}
rsa.modulus <== pubkey;
rsa.signature <== signature;
}

View File

@@ -1,15 +1,20 @@
pragma circom 2.1.5;
include "@zk-email/circuits/helpers/rsa.circom";
include "@zk-email/circuits/helpers/extract.circom";
include "@zk-email/circuits/helpers/sha.circom";
include "@zk-email/circuits/lib/rsa.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "@zk-email/circuits/lib/sha.circom";
include "@zk-email/circuits/utils/array.circom";
include "./utils/Sha256BytesStatic.circom";
template PassportVerifier_sha256WithRSAEncryption_65537(n, k, max_datahashes_bytes) {
var hashLen = 32;
var eContentBytesLength = 72 + hashLen; // 104
signal input mrz[93]; // formatted mrz (5 + 88) chars
signal input dg1_hash_offset;
signal input dataHashes[max_datahashes_bytes];
signal input datahashes_padded_length;
signal input eContentBytes[104];
signal input eContentBytes[eContentBytesLength];
// dsc_modulus that signed the passport
signal input dsc_modulus[k];
@@ -21,10 +26,10 @@ template PassportVerifier_sha256WithRSAEncryption_65537(n, k, max_datahashes_byt
signal mrzSha[256] <== Sha256BytesStatic(93)(mrz);
// mrzSha_bytes: list of 32 Bits2Num
component mrzSha_bytes[32];
component mrzSha_bytes[hashLen];
// cast the 256 bits from mrzSha into a list of 32 bytes
for (var i = 0; i < 32; i++) {
for (var i = 0; i < hashLen; i++) {
mrzSha_bytes[i] = Bits2Num(8);
for (var j = 0; j < 8; j++) {
@@ -32,17 +37,18 @@ template PassportVerifier_sha256WithRSAEncryption_65537(n, k, max_datahashes_byt
}
}
// assert mrz_hash equals the one extracted from dataHashes input (bytes 32 to 64)
for(var i = 0; i < 32; i++) {
dataHashes[31 + i] === mrzSha_bytes[i].out;
// assert mrz_hash equals the one extracted from dataHashes input (bytes dg1_hash_offset to dg1_hash_offset + hashLen)
signal dg1Hash[hashLen] <== SelectSubArray(max_datahashes_bytes, hashLen)(dataHashes, dg1_hash_offset, hashLen);
for(var i = 0; i < hashLen; i++) {
dg1Hash[i] === mrzSha_bytes[i].out;
}
// 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 dataHashesSha_bytes[32];
for (var i = 0; i < 32; i++) {
component dataHashesSha_bytes[hashLen];
for (var i = 0; i < hashLen; i++) {
dataHashesSha_bytes[i] = Bits2Num(8);
for (var j = 0; j < 8; j++) {
dataHashesSha_bytes[i].in[7 - j] <== dataHashesSha[i * 8 + j];
@@ -50,8 +56,8 @@ template PassportVerifier_sha256WithRSAEncryption_65537(n, k, max_datahashes_byt
}
// assert dataHashesSha is in eContentBytes in range bytes 72 to 104
for(var i = 0; i < 32; i++) {
eContentBytes[72 + i] === dataHashesSha_bytes[i].out;
for(var i = 0; i < hashLen; i++) {
eContentBytes[eContentBytesLength - hashLen + i] === dataHashesSha_bytes[i].out;
}
// hash eContentBytes
@@ -60,10 +66,9 @@ template PassportVerifier_sha256WithRSAEncryption_65537(n, k, max_datahashes_byt
// get output of eContentBytes sha256 into k chunks of n bits each
var msg_len = (256 + n) \ n;
//eContentHash: list of length 256/n +1 of components of n bits
//eContentHash: list of length 256/n +1 of components of n bits
component eContentHash[msg_len];
for (var i = 0; i < msg_len; i++) {
//instantiate each component of the list of Bits2Num of size n
eContentHash[i] = Bits2Num(n);
}
@@ -76,14 +81,14 @@ template PassportVerifier_sha256WithRSAEncryption_65537(n, k, max_datahashes_byt
}
// verify eContentHash signature
component rsa = RSAVerify65537(121, 17);
component rsa = RSAVerifier65537(n, k);
for (var i = 0; i < msg_len; i++) {
rsa.base_message[i] <== eContentHash[i].out;
rsa.message[i] <== eContentHash[i].out;
}
for (var i = msg_len; i < k; i++) {
rsa.base_message[i] <== 0;
rsa.message[i] <== 0;
}
rsa.modulus <== dsc_modulus;

View File

@@ -0,0 +1,75 @@
pragma circom 2.1.5;
// include "@zk-email/circuits/lib/rsa.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "@zk-email/circuits/lib/sha.circom";
include "@zk-email/circuits/utils/array.circom";
include "./utils/Sha256BytesStatic.circom";
include "./utils/RSASSAPSS.circom";
template PassportVerifier_sha256WithRSASSAPSS_65537(n, k, max_datahashes_bytes) {
var hashLen = 32;
var eContentBytesLength = 72 + hashLen; // 104
signal input mrz[93]; // formatted mrz (5 + 88) chars
signal input dg1_hash_offset;
signal input dataHashes[max_datahashes_bytes];
signal input datahashes_padded_length;
signal input eContentBytes[eContentBytesLength];
// pubkey that signed the passport
signal input pubkey[k];
// signature of the passport
signal input signature[k];
// compute sha256 of formatted mrz
signal mrzSha[256] <== Sha256BytesStatic(93)(mrz);
// mrzSha_bytes: list of 32 Bits2Num
component mrzSha_bytes[hashLen];
// cast the 256 bits from mrzSha into a list of 32 bytes
for (var i = 0; i < hashLen; i++) {
mrzSha_bytes[i] = Bits2Num(8);
for (var j = 0; j < 8; j++) {
mrzSha_bytes[i].in[7 - j] <== mrzSha[i * 8 + j];
}
}
// assert mrz_hash equals the one extracted from dataHashes input (bytes dg1_hash_offset to dg1_hash_offset + hashLen)
signal dg1Hash[hashLen] <== SelectSubArray(max_datahashes_bytes, hashLen)(dataHashes, dg1_hash_offset, hashLen);
for(var i = 0; i < hashLen; i++) {
dg1Hash[i] === mrzSha_bytes[i].out;
}
// 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 dataHashesSha_bytes[hashLen];
for (var i = 0; i < hashLen; i++) {
dataHashesSha_bytes[i] = Bits2Num(8);
for (var j = 0; j < 8; j++) {
dataHashesSha_bytes[i].in[7 - j] <== dataHashesSha[i * 8 + j];
}
}
// assert dataHashesSha is in eContentBytes in range bytes 72 to 104
for(var i = 0; i < hashLen; i++) {
eContentBytes[eContentBytesLength - hashLen + i] === dataHashesSha_bytes[i].out;
}
// decode signature to get encoded message
component rsaDecode = RSASSAPSS_Decode(n, k);
rsaDecode.signature <== signature;
rsaDecode.modulus <== pubkey;
signal encodedMessage[(n*k) \ 8] <== rsaDecode.eM;
// verify eContent signature
component rsaVerify = RSASSAPSSVerify_SHA256(n*k, eContentBytesLength);
rsaVerify.eM <== encodedMessage;
rsaVerify.message <== eContentBytes;
}

View File

@@ -0,0 +1,61 @@
pragma circom 2.1.5;
include "circomlib/circuits/poseidon.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "./passport_verifier_sha1WithRSAEncryption_65537.circom";
include "./utils/chunk_data.circom";
include "./utils/compute_pubkey_leaf.circom";
include "binary-merkle-root.circom";
template Register_sha1WithRSAEncryption_65537(n, k, max_datahashes_bytes, nLevels, signatureAlgorithm) {
signal input secret;
signal input mrz[93];
signal input dg1_hash_offset;
signal input econtent[max_datahashes_bytes];
signal input datahashes_padded_length;
signal input signed_attributes[92];
signal input signature[k];
signal input pubkey[k];
signal input merkle_root;
signal input path[nLevels];
signal input siblings[nLevels];
signal input attestation_id;
// Verify inclusion of the pubkey in the pubkey tree
signal leaf <== ComputePubkeyLeaf(n, k, signatureAlgorithm)(pubkey);
signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(leaf, nLevels, path, siblings);
merkle_root === computed_merkle_root;
// Verify passport validity
component PV = PassportVerifier_sha1WithRSAEncryption_65537(n, k, max_datahashes_bytes);
PV.mrz <== mrz;
PV.dg1_hash_offset <== dg1_hash_offset;
PV.dataHashes <== econtent;
PV.datahashes_padded_length <== datahashes_padded_length;
PV.eContentBytes <== signed_attributes;
PV.pubkey <== pubkey;
PV.signature <== signature;
// Generate the commitment
component poseidon_hasher = Poseidon(6);
poseidon_hasher.inputs[0] <== secret;
poseidon_hasher.inputs[1] <== attestation_id;
poseidon_hasher.inputs[2] <== leaf;
signal mrz_packed[3] <== PackBytes(93)(mrz);
for (var i = 0; i < 3; i++) {
poseidon_hasher.inputs[i + 3] <== mrz_packed[i];
}
signal output commitment <== poseidon_hasher.out;
// Generate the nullifier
var chunk_size = 11; // Since ceil(32 / 3) in integer division is 11
signal chunked_signature[chunk_size] <== ChunkData(n, k, chunk_size)(signature);
signal output nullifier <== Poseidon(chunk_size)(chunked_signature);
}
// We hardcode 3 here for sha1WithRSAEncryption_65537
component main { public [ merkle_root, attestation_id ] } = Register_sha1WithRSAEncryption_65537(64, 32, 320, 16, 3);

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.5;
include "circomlib/circuits/poseidon.circom";
include "@zk-email/circuits/helpers/extract.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "./passport_verifier_sha256WithRSAEncryption_65537.circom";
include "binary-merkle-root.circom";
include "./utils/splitSignalsToWords.circom";
@@ -10,6 +10,7 @@ template Register_sha256WithRSAEncryption_65537(n, k, max_datahashes_bytes, nLev
signal input secret;
signal input mrz[93];
signal input dg1_hash_offset;
signal input econtent[max_datahashes_bytes];
signal input datahashes_padded_length;
signal input signed_attributes[104];
@@ -40,6 +41,7 @@ template Register_sha256WithRSAEncryption_65537(n, k, max_datahashes_bytes, nLev
// Verify passport validity
component PV = PassportVerifier_sha256WithRSAEncryption_65537(n, k, max_datahashes_bytes);
PV.mrz <== mrz;
PV.dg1_hash_offset <== dg1_hash_offset;
PV.dataHashes <== econtent;
PV.datahashes_padded_length <== datahashes_padded_length;
PV.eContentBytes <== signed_attributes;
@@ -52,7 +54,7 @@ template Register_sha256WithRSAEncryption_65537(n, k, max_datahashes_bytes, nLev
poseidon_hasher.inputs[1] <== attestation_id;
poseidon_hasher.inputs[2] <== leaf_hasher.out;
signal mrz_packed[3] <== PackBytes(93, 3, 31)(mrz);
signal mrz_packed[3] <== PackBytes(93)(mrz);
for (var i = 0; i < 3; i++) {
poseidon_hasher.inputs[i + 3] <== mrz_packed[i];
}

View File

@@ -0,0 +1,61 @@
pragma circom 2.1.5;
include "circomlib/circuits/poseidon.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "./passport_verifier_sha256WithRSASSAPSS_65537.circom";
include "./utils/chunk_data.circom";
include "./utils/compute_pubkey_leaf.circom";
include "binary-merkle-root.circom";
template register_sha256WithRSASSAPSS_65537(n, k, max_datahashes_bytes, nLevels, signatureAlgorithm) {
signal input secret;
signal input mrz[93];
signal input dg1_hash_offset;
signal input econtent[max_datahashes_bytes];
signal input datahashes_padded_length;
signal input signed_attributes[104];
signal input signature[k];
signal input pubkey[k];
signal input merkle_root;
signal input path[nLevels];
signal input siblings[nLevels];
signal input attestation_id;
// Verify inclusion of the pubkey in the pubkey tree
signal leaf <== ComputePubkeyLeaf(n, k, signatureAlgorithm)(pubkey);
signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(leaf, nLevels, path, siblings);
merkle_root === computed_merkle_root;
// Verify passport validity
component PV = PassportVerifier_sha256WithRSASSAPSS_65537(n, k, max_datahashes_bytes);
PV.mrz <== mrz;
PV.dg1_hash_offset <== dg1_hash_offset;
PV.dataHashes <== econtent;
PV.datahashes_padded_length <== datahashes_padded_length;
PV.eContentBytes <== signed_attributes;
PV.pubkey <== pubkey;
PV.signature <== signature;
// Generate the commitment
component poseidon_hasher = Poseidon(6);
poseidon_hasher.inputs[0] <== secret;
poseidon_hasher.inputs[1] <== attestation_id;
poseidon_hasher.inputs[2] <== leaf;
signal mrz_packed[3] <== PackBytes(93)(mrz);
for (var i = 0; i < 3; i++) {
poseidon_hasher.inputs[i + 3] <== mrz_packed[i];
}
signal output commitment <== poseidon_hasher.out;
// Generate the nullifier
var chunk_size = 11; // Since ceil(32 / 3) in integer division is 11
signal chunked_signature[chunk_size] <== ChunkData(n, k, chunk_size)(signature);
signal output nullifier <== Poseidon(chunk_size)(chunked_signature);
}
// We hardcode 1 here for sha256WithRSAEncryption_65537
component main { public [ merkle_root, attestation_id ] } = register_sha256WithRSASSAPSS_65537(64, 32, 320, 16, 4);

View File

@@ -34,7 +34,7 @@ template Mgf1Sha256(seedLen, maskLen) { //in bytes
for (var j = 0; j < 32; j++) {
//concat seed and counter
concated[seedLenBits + j] = num2Bits[i].out[j];
concated[seedLenBits + j] = num2Bits[i].out[31-j];
}
sha256[i].in <== concated;

View File

@@ -0,0 +1,192 @@
pragma circom 2.1.5;
include "@zk-email/circuits/lib/rsa.circom";
include "@zk-email/circuits/lib/fp.circom";
include "@zk-email/circuits/lib/bigint-func.circom";
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/sha256/sha256.circom";
include "./Mgf1Sha256.circom";
include "./xor.circom";
/// @notice Returns the encoded message in 8bit chunks.
/// @param n Number of bits per chunk the modulus is split into.
/// @param k Number of chunks the modulus is split into.
template RSASSAPSS_Decode(n, k) {
signal input signature[k];
signal input modulus[k];
// signal output eM[k];
signal encoded[k];
signal eMsgInBits[n*k];
signal output eM[(n*k)\8]; //8 bit words
component bigPow = FpPow65537Mod(n, k);
for (var i = 0; i < k; i++) {
bigPow.base[i] <== signature[i];
bigPow.modulus[i] <== modulus[i];
}
encoded <== bigPow.out;
component num2Bits[k];
for (var i = 0; i < k; i++) {
num2Bits[i] = Num2Bits(n);
num2Bits[i].in <== encoded[k-1-i];
for (var j = 0; j < n; j++) {
eMsgInBits[i * n + j] <== num2Bits[i].out[n-j-1];
}
}
component bits2Num[(n*k)\8];
for (var i = 0; i < (n*k)\8; i++) {
bits2Num[i] = Bits2Num(8);
for (var j = 0; j < 8; j++) {
bits2Num[i].in[7-j] <== eMsgInBits[i*8 + j];
}
eM[(n*k)\8 - i -1] <== bits2Num[i].out;
}
}
/// @param emBits Length of the encoded message in bits.
/// @param messageLen Length of the message in bytes.
/// @param n Number of bits per chunk the modulus is split into.
/// @param k Number of chunks the modulus is split into.
template RSASSAPSSVerify_SHA256(emBits, messageLen) {
var emLen = div_ceil(emBits, 8);
signal input eM[emLen];
signal input message[messageLen];
signal mHash[256];
var hLen = 32;
var sLen = 32;
var hLenBits = 256; //sha256
var sLenBits = 256; //sha256
var emLenBits = emLen * 8;
signal messageBits[messageLen*8];
component num2BitsMessage[messageLen];
for (var i = 0; i < messageLen; i++) {
num2BitsMessage[i] = Num2Bits(8);
num2BitsMessage[i].in <== message[i];
for (var j = 0; j < 8; j++) {
messageBits[i*8 +j] <== num2BitsMessage[i].out[7-j];
}
}
//mHash
component sha256 = Sha256(832);
sha256.in <== messageBits;
for (var i = 0; i < 256; i++) {
mHash[i] <== sha256.out[i];
}
//If emLen < hLen + sLen + 2, output "inconsistent" and stop.
assert(emLen >= 32 + 32 +2);
//should end with 0xBC (188 in decimal)
assert(eM[0] == 188); //inconsistent
signal eMsgInBits[emLen * 8];
signal maskedDB[(emLen - hLen - 1) * 8];
signal hash[hLen * 8];
var dbMaskLen = emLen - hLen - 1;
signal dbMask[dbMaskLen * 8];
signal DB[dbMaskLen * 8];
signal salt[hLen * 8];
//split eM into bits
component num2Bits[emLen];
for (var i = 0; i < emLen; i++) {
num2Bits[i] = Num2Bits(8);
num2Bits[i].in <== eM[emLen-1-i];
for (var j = 0; j < 8; j++) {
eMsgInBits[i * 8 + j] <== num2Bits[i].out[8-j-1];
}
}
//extract maskedDB. leftmost emLen - hLen - 1 octets of EM
for (var i=0; i< (emLen - hLen -1) * 8; i++) {
maskedDB[i] <== eMsgInBits[i];
}
//Ref: https://github.com/directdemocracy-vote/app/blob/d0590b5515e749fa72fc50f05062273eb2465da1/httpdocs/app/js/rsa-blind.js#L183
signal mask <== 0xff00 >> (emLenBits / 8 - emBits) & 0xff;
signal maskBits[8];
component num2BitsMask = Num2Bits(8);
num2BitsMask.in <== mask;
for (var i = 0; i < 8; i++) {
maskBits[i] <== num2BitsMask.out[7-i];
}
for (var i=0; i<8; i++) {
assert(maskBits[i] & maskedDB[i] == 0);
}
//extract hash
for (var i=0; i<hLenBits; i++) {
hash[i] <== eMsgInBits[(emLenBits) - hLenBits-8 +i];
}
//DbMask MGF1
component MGF1 = Mgf1Sha256(hLen, dbMaskLen);
for (var i = 0; i < (hLenBits); i++) {
MGF1.seed[i] <== hash[i];
}
for (var i = 0; i < dbMaskLen * 8; i++) {
dbMask[i] <== MGF1.out[i];
}
//DB = maskedDB xor dbMask
component xor = Xor2(dbMaskLen * 8);
for (var i = 0; i < dbMaskLen * 8; i++) {
xor.a[i] <== maskedDB[i];
xor.b[i] <== dbMask[i];
}
// Ref: https://github.com/directdemocracy-vote/app/blob/d0590b5515e749fa72fc50f05062273eb2465da1/httpdocs/app/js/rsa-blind.js#L188-L190
for (var i = 0; i < dbMaskLen * 8; i++) {
//setting the first leftmost byte to 0
if (i==0) {
DB[i] <== 0;
} else {
DB[i] <== xor.out[i];
}
}
// If the emLen - hLen - sLen - 2 leftmost octets of DB are not
// zero, output "inconsistent" and stop.
for (var i = 0; i < (emLenBits-528); i++) { //hLenBits + sLenBits + 16 = 256 + 256 + 16 = 528
assert(DB[i] == 0);
}
// if the octet at position emLen - hLen - sLen - 1 (the
// leftmost position is "position 1") does not have hexadecimal
// value 0x01, output "inconsistent" and stop.
component bits2Num = Bits2Num(8);
for (var i = 0; i < 8; i++) {
bits2Num.in[7-i] <== DB[(emLenBits)- 528 +i]; //emLen - hLen - sLen - 1
}
assert(bits2Num.out == 1);
//extract salt
for (var i = 0; i < sLenBits; i++) {
//last sLenBits (256) bits of DB
salt[256 -1 - i] <== DB[(dbMaskLen * 8) -1 - i];
}
//M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
signal mDash[576]; // 8 + hLen + sLen = 8 + 32 + 32 = 72 bytes = 576 bits
for (var i = 0; i < 64; i++) {
mDash[i] <== 0;
}
for (var i = 0 ; i < 256; i++) {
mDash[64 + i] <== mHash[i];
}
for (var i = 0; i < 256; i++) {
mDash[320 + i] <== salt[i];
}
component hDash = Sha256(576);
hDash.in <== mDash;
for (var i = 0; i < 256; i++) {
assert(hDash.out[i] == hash[i]);
}
}

View File

@@ -0,0 +1,119 @@
pragma circom 2.1.5;
include "dmpierre/sha1-circom/circuits/sha1compression.circom";
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/mimcsponge.circom";
include "@zk-email/circuits/lib/fp.circom";
//Adapted from @zk-email/circuits/helpers/sha.circom
template Sha1Bytes(max_num_bytes) {
signal input in_padded[max_num_bytes];
signal input in_len_padded_bytes;
signal output out[160];
var num_bits = max_num_bytes * 8;
component sha = Sha1General(num_bits);
component bytes[max_num_bytes];
for (var i = 0; i < max_num_bytes; i++) {
bytes[i] = Num2Bits(8);
bytes[i].in <== in_padded[i];
for (var j = 0; j < 8; j++) {
sha.paddedIn[i*8+j] <== bytes[i].out[7-j];
}
}
sha.in_len_padded_bits <== in_len_padded_bytes * 8;
for (var i = 0; i < 160; i++) {
out[i] <== sha.out[i];
}
}
//Adapted from @zk-email/circuits/helpers/sha256general.circom
//Sha1 template from https://github.com/dmpierre/sha1-circom/blob/fe18319cf72b9f3b83d0cea8f49a1f04482c125b/circuits/sha1.circom
template Sha1General(maxBitsPadded) {
assert(maxBitsPadded % 512 == 0);
var maxBitsPaddedBits = log2Ceil(maxBitsPadded);
assert(2 ** maxBitsPaddedBits > maxBitsPadded);
signal input paddedIn[maxBitsPadded];
signal output out[160];
signal input in_len_padded_bits;
signal inBlockIndex;
var i;
var k;
var j;
var maxBlocks;
maxBlocks = (maxBitsPadded\512);
var maxBlocksBits = log2Ceil(maxBlocks);
assert(2 ** maxBlocksBits > maxBlocks);
inBlockIndex <-- (in_len_padded_bits >> 9);
in_len_padded_bits === inBlockIndex * 512;
component bitLengthVerifier = LessEqThan(maxBitsPaddedBits);
bitLengthVerifier.in[0] <== in_len_padded_bits;
bitLengthVerifier.in[1] <== maxBitsPadded;
bitLengthVerifier.out === 1;
component ha0 = H(0);
component hb0 = H(1);
component hc0 = H(2);
component hd0 = H(3);
component he0 = H(4);
component sha1compression[maxBlocks];
for (i=0; i<maxBlocks; i++) {
sha1compression[i] = Sha1compression();
if (i==0) {
for (k=0; k<32; k++) {
sha1compression[i].hin[0*32+k] <== ha0.out[k];
sha1compression[i].hin[1*32+k] <== hb0.out[k];
sha1compression[i].hin[2*32+k] <== hc0.out[k];
sha1compression[i].hin[3*32+k] <== hd0.out[k];
sha1compression[i].hin[4*32+k] <== he0.out[k];
}
} else {
for (k=0; k<32; k++) {
sha1compression[i].hin[32*0+k] <== sha1compression[i-1].out[32*0+31-k];
sha1compression[i].hin[32*1+k] <== sha1compression[i-1].out[32*1+31-k];
sha1compression[i].hin[32*2+k] <== sha1compression[i-1].out[32*2+31-k];
sha1compression[i].hin[32*3+k] <== sha1compression[i-1].out[32*3+31-k];
sha1compression[i].hin[32*4+k] <== sha1compression[i-1].out[32*4+31-k];
}
}
for (k=0; k<512; k++) {
sha1compression[i].inp[k] <== paddedIn[i*512+k];
}
}
component arraySelectors[160];
var outs[maxBlocks][160];
for (i=0; i<maxBlocks; i++) {
for (j=0; j<5; j++) {
for (k=0; k<32; k++) {
outs[i][32*j + k] = sha1compression[i].out[32*j + (31-k)];
}
}
}
for (i =0; i < 160; i++) {
arraySelectors[i] = ItemAtIndex(maxBlocks);
for (j=0; j<maxBlocks; j++) {
arraySelectors[i].in[j] <== outs[j][i];
}
arraySelectors[i].index <== inBlockIndex - 1;
out[i] <== arraySelectors[i].out;
}
}

View File

@@ -0,0 +1,35 @@
pragma circom 2.1.5;
include "circomlib/circuits/bitify.circom";
include "dmpierre/sha1-circom/circuits/sha1.circom";
// Static length sha160 bytes, adapted from zk-email
template Sha1BytesStatic(max_num_bytes) {
signal input in_padded[max_num_bytes];
signal output out[160];
// num_bits: num of bits in max_num_bytes
var num_bits = max_num_bytes * 8;
// sha: component used to hash all bits from input signal
component sha = Sha1(num_bits);
// bytes: list of component used to convert bytes from input signal to bits
component bytes[max_num_bytes];
// for each bytes iterate and set bytes from input signal inside the component
for (var i = 0; i < max_num_bytes; i++) {
bytes[i] = Num2Bits(8);
bytes[i].in <== in_padded[i];
// for each bits int bytes iterate again and set the bits from each bytes from reverse order inside sha256 component
for (var j = 0; j < 8; j++) {
sha.in[i*8+j] <== bytes[i].out[7-j];
}
}
for (var i = 0; i < 160; i++) {
out[i] <== sha.out[i];
}
}

View File

@@ -0,0 +1,157 @@
pragma circom 2.1.5;
include "@zk-email/circuits/lib/fp.circom";
// Computes base^65537 mod modulus
// Does not necessarily reduce fully mod modulus (the answer could be
// too big by a multiple of modulus)
template FpPow65537Mod(n, k) {
signal input base[k];
// Exponent is hardcoded at 65537
signal input modulus[k];
signal output out[k];
component doublers[16];
component adder = FpMul(n, k);
for (var i = 0; i < 16; i++) {
doublers[i] = FpMul(n, k);
}
for (var j = 0; j < k; j++) {
adder.p[j] <== modulus[j];
for (var i = 0; i < 16; i++) {
doublers[i].p[j] <== modulus[j];
}
}
for (var j = 0; j < k; j++) {
doublers[0].a[j] <== base[j];
doublers[0].b[j] <== base[j];
}
for (var i = 0; i + 1 < 16; i++) {
for (var j = 0; j < k; j++) {
doublers[i + 1].a[j] <== doublers[i].out[j];
doublers[i + 1].b[j] <== doublers[i].out[j];
}
}
for (var j = 0; j < k; j++) {
adder.a[j] <== base[j];
adder.b[j] <== doublers[15].out[j];
}
for (var j = 0; j < k; j++) {
out[j] <== adder.out[j];
}
}
template RSAPad(n, k) {
signal input modulus[k];
signal input base_message[k];
signal output padded_message[k];
var base_len = 280;
var msg_len = 160;
signal padded_message_bits[n*k];
component modulus_n2b[k];
component base_message_n2b[k];
signal modulus_bits[n*k];
signal base_message_bits[n*k];
for (var i = 0; i < k; i++) {
base_message_n2b[i] = Num2Bits(n);
base_message_n2b[i].in <== base_message[i];
for (var j = 0; j < n; j++) {
base_message_bits[i*n+j] <== base_message_n2b[i].out[j];
}
modulus_n2b[i] = Num2Bits(n);
modulus_n2b[i].in <== modulus[i];
for (var j = 0; j < n; j++) {
modulus_bits[i*n+j] <== modulus_n2b[i].out[j];
}
}
for (var i = msg_len; i < n*k; i++) {
base_message_bits[i] === 0;
}
for (var i = 0; i < msg_len; i++) {
padded_message_bits[i] <== base_message_bits[i];
}
for (var i = base_len; i < base_len + 8; i++) {
padded_message_bits[i] <== 0;
}
for (var i = msg_len; i < base_len; i++) {
padded_message_bits[i] <== (0x3021300906052b0e03021a05000414 >> (i - msg_len)) & 1;
}
component modulus_zero[(n*k + 7 - (base_len + 8))\8];
{
var modulus_prefix = 0;
for (var i = n*k - 1; i >= base_len + 8; i--) {
if (i+8 < n*k) {
modulus_prefix += modulus_bits[i+8];
if (i % 8 == 0) {
var idx = (i - (base_len + 8)) / 8;
modulus_zero[idx] = IsZero();
modulus_zero[idx].in <== modulus_prefix;
padded_message_bits[i] <== 1-modulus_zero[idx].out;
} else {
padded_message_bits[i] <== padded_message_bits[i+1];
}
} else {
padded_message_bits[i] <== 0;
}
}
}
// The RFC guarantees at least 8 octets of 0xff padding.
assert(base_len + 8 + 65 <= n*k);
for (var i = base_len + 8; i < base_len + 8 + 65; i++) {
padded_message_bits[i] === 1;
}
component padded_message_b2n[k];
for (var i = 0; i < k; i++) {
padded_message_b2n[i] = Bits2Num(n);
for (var j = 0; j < n; j++) {
padded_message_b2n[i].in[j] <== padded_message_bits[i*n+j];
}
padded_message[i] <== padded_message_b2n[i].out;
}
}
template RSAVerify65537(n, k) {
signal input signature[k];
signal input modulus[k];
signal input base_message[k];
component padder = RSAPad(n, k);
for (var i = 0; i < k; i++) {
padder.modulus[i] <== modulus[i];
padder.base_message[i] <== base_message[i];
}
// Check that the signature is in proper form and reduced mod modulus.
component signatureRangeCheck[k];
component bigLessThan = BigLessThan(n, k);
for (var i = 0; i < k; i++) {
signatureRangeCheck[i] = Num2Bits(n);
signatureRangeCheck[i].in <== signature[i];
bigLessThan.a[i] <== signature[i];
bigLessThan.b[i] <== modulus[i];
}
bigLessThan.out === 1;
component bigPow = FpPow65537Mod(n, k);
for (var i = 0; i < k; i++) {
bigPow.base[i] <== signature[i];
bigPow.modulus[i] <== modulus[i];
}
// By construction of the padding, the padded message is necessarily
// smaller than the modulus. Thus, we don't have to check that bigPow is fully reduced.
for (var i = 0; i < k; i++) {
bigPow.out[i] === padder.padded_message[i];
}
}

View File

@@ -0,0 +1,11 @@
pragma circom 2.1.5;
template Xor2(n) {
signal input a[n];
signal input b[n];
signal output out[n];
for (var k=0; k<n; k++) {
out[k] <== a[k] + b[k] - 2*a[k]*b[k];
}
}

View File

@@ -11,12 +11,13 @@
"@types/chai-as-promised": "^7.1.6",
"@types/node": "^20.11.19",
"@types/node-forge": "^1.3.5",
"@zk-email/circuits": "^3.2.2",
"@zk-email/helpers": "^3.1.3",
"@zk-email/circuits": "^6.1.1",
"@zk-email/helpers": "^6.1.1",
"@zk-email/zk-regex-circom": "^1.2.1",
"@zk-kit/binary-merkle-root.circom": "^1.0.0-beta",
"@zk-kit/circuits": "^1.0.0-beta",
"@zk-kit/imt": "https://gitpkg.now.sh/0xturboblitz/zk-kit/packages/imt?6d417675",
"dmpierre/sha1-circom": "https://github.com/dmpierre/sha1-circom/",
"@zk-kit/lean-imt": "^2.0.1",
"chai-as-promised": "^7.1.1",
"circom_tester": "github:Atomic-Buy/circom_tester#main",

View File

@@ -0,0 +1,36 @@
#!/bin/bash
source "scripts/download_ptau.sh"
build_circuit() {
local CIRCUIT_NAME=$1
local START_TIME=$(date +%s)
echo "compiling circuit: $CIRCUIT_NAME"
circom circuits/${CIRCUIT_NAME}.circom -l node_modules -l ./node_modules/@zk-kit/binary-merkle-root.circom/src -l ./node_modules/circomlib/circuits --r1cs --O1 --wasm -c --output build
echo "building zkey"
yarn snarkjs groth16 setup build/${CIRCUIT_NAME}.r1cs build/powersOfTau28_hez_final_20.ptau build/${CIRCUIT_NAME}.zkey
echo "building vkey"
yarn snarkjs zkey contribute build/${CIRCUIT_NAME}.zkey build/${CIRCUIT_NAME}_final.zkey -e="random text"
yarn snarkjs zkey export verificationkey build/${CIRCUIT_NAME}_final.zkey build/${CIRCUIT_NAME}_vkey.json
yarn snarkjs zkey export solidityverifier build/${CIRCUIT_NAME}_final.zkey build/Verifier_${CIRCUIT_NAME}.sol
sed -i '' "s/Groth16Verifier/Verifier_${CIRCUIT_NAME}/g" build/Verifier_${CIRCUIT_NAME}.sol
cp build/Verifier_${CIRCUIT_NAME}.sol ../contracts/contracts/Verifier_${CIRCUIT_NAME}.sol
echo "copied Verifier_${CIRCUIT_NAME}.sol to contracts"
echo "Build of $CIRCUIT_NAME completed in $(($(date +%s) - START_TIME)) seconds"
echo "Size of ${CIRCUIT_NAME}.r1cs: $(wc -c <build/${CIRCUIT_NAME}.r1cs) bytes"
echo "Size of ${CIRCUIT_NAME}.wasm: $(wc -c <build/${CIRCUIT_NAME}_js/${CIRCUIT_NAME}.wasm) bytes"
echo "Size of ${CIRCUIT_NAME}_final.zkey: $(wc -c <build/${CIRCUIT_NAME}_final.zkey) bytes"
}
declare -a CIRCUITS=("register_sha256WithRSAEncryption_65537" "register_sha1WithRSAEncryption_65537" "register_sha256WithRSAEncryption_65537" "disclose")
TOTAL_START_TIME=$(date +%s)
for CIRCUIT_NAME in "${CIRCUITS[@]}"; do
build_circuit "$CIRCUIT_NAME"
done
echo "Total completed in $(($(date +%s) - TOTAL_START_TIME)) seconds"

View File

@@ -1,44 +0,0 @@
#!/bin/bash
# Record the start time
START_TIME=$(date +%s)
mkdir -p build
cd build
if [ ! -f powersOfTau28_hez_final_20.ptau ]; then
echo "Download power of tau...."
wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_20.ptau
echo "Finished download!"
else
echo "Powers of tau file already downloaded... Skip download action!"
fi
cd ..
echo "compiling circuit"
circom circuits/disclose.circom -l node_modules -l ./node_modules/@zk-kit/binary-merkle-root.circom/src -l ./node_modules/circomlib/circuits --r1cs --O1 --wasm -c --output build
echo "building zkey"
yarn snarkjs groth16 setup build/disclose.r1cs build/powersOfTau28_hez_final_20.ptau build/disclose.zkey
if command -v openssl &> /dev/null
then
RAND_STR=$(openssl rand -hex 64)
else
RAND_STR="random text"
fi
echo "building vkey"
echo $RAND_STR | yarn snarkjs zkey contribute build/disclose.zkey build/disclose_final.zkey
yarn snarkjs zkey export verificationkey build/disclose_final.zkey build/disclose_vkey.json
yarn snarkjs zkey export solidityVerifier build/disclose_final.zkey build/Verifier_disclose.sol
sed -i '' 's/Groth16Verifier/Verifier_disclose/g' build/Verifier_disclose.sol
cp build/Verifier_disclose.sol ../contracts/contracts/Verifier_disclose.sol
echo "copied Verifier_disclose.sol to contracts"
echo "Build completed in $(($(date +%s) - $START_TIME)) seconds"
echo "file sizes:"
echo "Size of disclose.r1cs: $(wc -c <build/disclose.r1cs) bytes"
echo "Size of disclose.wasm: $(wc -c <build/disclose_js/disclose.wasm) bytes"
echo "Size of disclose_final.zkey: $(wc -c <build/disclose_final.zkey) bytes"

View File

@@ -1,44 +0,0 @@
#!/bin/bash
# Record the start time
START_TIME=$(date +%s)
mkdir -p build
cd build
if [ ! -f powersOfTau28_hez_final_20.ptau ]; then
echo "Download power of tau...."
wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_20.ptau
echo "Finished download!"
else
echo "Powers of tau file already downloaded... Skip download action!"
fi
cd ..
echo "compiling circuit"
circom circuits/register_sha256WithRSAEncryption_65537.circom -l node_modules -l ./node_modules/@zk-kit/binary-merkle-root.circom/src -l ./node_modules/circomlib/circuits --r1cs --O1 --wasm -c --output build
echo "building zkey"
yarn snarkjs groth16 setup build/register_sha256WithRSAEncryption_65537.r1cs build/powersOfTau28_hez_final_20.ptau build/register_sha256WithRSAEncryption_65537.zkey
if command -v openssl &> /dev/null
then
RAND_STR=$(openssl rand -hex 64)
else
RAND_STR="random text"
fi
echo "building vkey"
echo $RAND_STR | yarn snarkjs zkey contribute build/register_sha256WithRSAEncryption_65537.zkey build/register_sha256WithRSAEncryption_65537_final.zkey
yarn snarkjs zkey export verificationkey build/register_sha256WithRSAEncryption_65537_final.zkey build/register_sha256WithRSAEncryption_65537_vkey.json
yarn snarkjs zkey export solidityverifier build/register_sha256WithRSAEncryption_65537_final.zkey build/Verifier_register_sha256WithRSAEncryption_65537.sol
sed -i '' 's/Groth16Verifier/Verifier_register_sha256WithRSAEncryption_65537/g' build/Verifier_register_sha256WithRSAEncryption_65537.sol
cp build/Verifier_register_sha256WithRSAEncryption_65537.sol ../contracts/contracts/Verifier_register_sha256WithRSAEncryption_65537.sol
echo "copied Verifier_register_sha256WithRSAEncryption_65537.sol to contracts"
echo "Build completed in $(($(date +%s) - $START_TIME)) seconds"
echo "file sizes:"
echo "Size of register_sha256WithRSAEncryption_65537.r1cs: $(wc -c <build/register_sha256WithRSAEncryption_65537.r1cs) bytes"
echo "Size of register_sha256WithRSAEncryption_65537.wasm: $(wc -c <build/register_sha256WithRSAEncryption_65537_js/register_sha256WithRSAEncryption_65537.wasm) bytes"
echo "Size of register_sha256WithRSAEncryption_65537_final.zkey: $(wc -c <build/register_sha256WithRSAEncryption_65537_final.zkey) bytes"

View File

@@ -0,0 +1,12 @@
#!/bin/bash
mkdir -p build
cd build
if [ ! -f powersOfTau28_hez_final_20.ptau ]; then
echo "Download power of tau...."
wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_20.ptau
echo "Finished download!"
else
echo "Powers of tau file already downloaded... Skip download action!"
fi
cd ..

View File

@@ -1,6 +1,6 @@
import assert from "assert";
import { PassportData } from "../../../common/src/utils/types";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual } from "../../../common/src/utils/utils";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual, findSubarrayIndex } from "../../../common/src/utils/utils";
import * as forge from 'node-forge';
import { writeFileSync } from "fs";
import elliptic from 'elliptic';
@@ -32,16 +32,17 @@ const sampleDataHashes = [
14,
[76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38]
]
]
] as [number, number[]][]
const signatureAlgorithm = 'SHA384withECDSA'
const hashLen = 46
export function genMockPassportData_SHA384withECDSA(): PassportData {
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
sampleDataHashes.unshift([1, mrzHash]);
const concatenatedDataHashes = formatAndConcatenateDataHashes(
mrzHash,
sampleDataHashes as [number, number[]][],
[[1, mrzHash], ...sampleDataHashes],
hashLen,
33
);
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
@@ -74,11 +75,17 @@ function verify(passportData: PassportData): boolean {
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
const formattedMrz = formatMrz(mrz);
const mrzHash = hash(signatureAlgorithm, formattedMrz);
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
console.log('dg1HashOffset', dg1HashOffset);
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
console.log("mrzHash:", mrzHash);
const concatHash = hash(signatureAlgorithm, dataGroupHashes)
assert(
arraysAreEqual(mrzHash, dataGroupHashes.slice(31, 31 + mrzHash.length)),
'mrzHash is at the right place in dataGroupHashes'
arraysAreEqual(
concatHash,
eContent.slice(eContent.length - concatHash.length)
),
'concatHash is not at the right place in eContent'
);
const cleanPublicKeyQ = pubKey.publicKeyQ.replace(/[()]/g, '').split(',');

View File

@@ -1,6 +1,6 @@
import assert from "assert";
import { PassportData } from "../../../common/src/utils/types";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual } from "../../../common/src/utils/utils";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual, findSubarrayIndex } from "../../../common/src/utils/utils";
import * as forge from 'node-forge';
import crypto from 'crypto';
import { writeFileSync } from "fs";
@@ -31,10 +31,11 @@ const sampleDataHashes = [
14,
[76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38]
]
]
const signatureAlgorithm = 'rsassaPss'
] as [number, number[]][]
const signatureAlgorithm = 'sha256WithRSASSAPSS'
const hashLen = 32
export function genMockPassportData_rsassaPss_65537(): PassportData {
export function genMockPassportData_sha256WithRSASSAPSS_65537(): PassportData {
const keypair = forge.pki.rsa.generateKeyPair(2048);
const privateKeyPem = forge.pki.privateKeyToPem(keypair.privateKey);
@@ -44,10 +45,10 @@ export function genMockPassportData_rsassaPss_65537(): PassportData {
const salt = Buffer.from('dee959c7e06411361420ff80185ed57f3e6776afdee959c7e064113614201420', 'hex');
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
sampleDataHashes.unshift([1, mrzHash]);
const concatenatedDataHashes = formatAndConcatenateDataHashes(
mrzHash,
sampleDataHashes as [number, number[]][],
[[1, mrzHash], ...sampleDataHashes],
hashLen,
30
);
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
@@ -82,11 +83,17 @@ function verify(passportData: PassportData): boolean {
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
const formattedMrz = formatMrz(mrz);
const mrzHash = hash(signatureAlgorithm, formattedMrz);
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
console.log('dg1HashOffset', dg1HashOffset);
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
console.log("mrzHash", mrzHash);
const concatHash = hash(signatureAlgorithm, dataGroupHashes)
assert(
arraysAreEqual(mrzHash, dataGroupHashes.slice(31, 31 + mrzHash.length)),
'mrzHash is at the right place in dataGroupHashes'
arraysAreEqual(
concatHash,
eContent.slice(eContent.length - concatHash.length)
),
'concatHash is not at the right place in eContent'
);
const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10);
@@ -99,11 +106,6 @@ function verify(passportData: PassportData): boolean {
const signature = Buffer.from(encryptedDigest);
const hash_algorithm = "sha256";
assert(Buffer.isBuffer(rsa_public));
assert.strictEqual(typeof hash_algorithm, "string");
assert(Buffer.isBuffer(message));
assert(Buffer.isBuffer(signature));
const public_key = {
key: rsa_public,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
@@ -115,7 +117,7 @@ function verify(passportData: PassportData): boolean {
return isVerified;
}
const mockPassportData = genMockPassportData_rsassaPss_65537();
const mockPassportData = genMockPassportData_sha256WithRSASSAPSS_65537();
console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2));
console.log("Signature valid:", verify(mockPassportData));

View File

@@ -4,7 +4,7 @@
import assert from "assert";
import { PassportData } from "../../../common/src/utils/types";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual } from "../../../common/src/utils/utils";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual, findSubarrayIndex } from "../../../common/src/utils/utils";
import * as forge from 'node-forge';
import crypto from 'crypto';
import { writeFileSync } from "fs";
@@ -35,10 +35,11 @@ const sampleDataHashes = [
14,
[76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38]
]
]
const signatureAlgorithm = 'rsassaPss'
] as [number, number[]][]
const signatureAlgorithm = 'sha256WithRSASSAPSS'
const hashLen = 32
export function genMockPassportData_rsassaPss_65537(): PassportData {
export function genMockPassportData_sha256WithRSASSAPSS_65537(): PassportData {
const keypair = forge.pki.rsa.generateKeyPair(2048);
const privateKeyPem = forge.pki.privateKeyToPem(keypair.privateKey);
@@ -48,10 +49,10 @@ export function genMockPassportData_rsassaPss_65537(): PassportData {
const salt = Buffer.from('dee959c7e06411361420ff80185ed57f3e6776afdee959c7e064113614201420', 'hex');
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
sampleDataHashes.unshift([1, mrzHash]);
const concatenatedDataHashes = formatAndConcatenateDataHashes(
mrzHash,
sampleDataHashes as [number, number[]][],
[[1, mrzHash], ...sampleDataHashes],
hashLen,
30
);
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
@@ -113,11 +114,16 @@ function verify(passportData: PassportData): boolean {
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
const formattedMrz = formatMrz(mrz);
const mrzHash = hash(signatureAlgorithm, formattedMrz);
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
console.log("mrzHash", mrzHash);
const concatHash = hash(signatureAlgorithm, dataGroupHashes)
assert(
arraysAreEqual(mrzHash, dataGroupHashes.slice(31, 31 + mrzHash.length)),
'mrzHash is at the right place in dataGroupHashes'
arraysAreEqual(
concatHash,
eContent.slice(eContent.length - concatHash.length)
),
'concatHash is not at the right place in eContent'
);
const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10);
@@ -207,7 +213,7 @@ function BufferXOR(a: Buffer, b: Buffer) {
}
const mockPassportData = genMockPassportData_rsassaPss_65537();
const mockPassportData = genMockPassportData_sha256WithRSASSAPSS_65537();
console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2));
console.log("Signature valid:", verify(mockPassportData));

View File

@@ -1,6 +1,6 @@
import { writeFileSync } from "fs";
import { PassportData } from "../../../common/src/utils/types";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual } from "../../../common/src/utils/utils";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual, findSubarrayIndex } from "../../../common/src/utils/utils";
import * as forge from 'node-forge';
import { assert } from "console";
@@ -18,15 +18,16 @@ const sampleDataHashes = [
14,
[76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59]
]
]
] as [number, number[]][]
const signatureAlgorithm = 'sha1WithRSAEncryption'
const hashLen = 20
export function genMockPassportData_sha1WithRSAEncryption_65537(): PassportData {
const signatureAlgorithm = 'sha1WithRSAEncryption'
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
sampleDataHashes.unshift([1, mrzHash]);
const concatenatedDataHashes = formatAndConcatenateDataHashes(
mrzHash,
sampleDataHashes as [number, number[]][],
[[1, mrzHash], ...sampleDataHashes],
hashLen,
31 // could have been different
);
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
@@ -59,10 +60,17 @@ function verify(passportData: PassportData): boolean {
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
const formattedMrz = formatMrz(mrz);
const mrzHash = hash(signatureAlgorithm, formattedMrz);
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
console.log('dg1HashOffset', dg1HashOffset);
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
const concatHash = hash(signatureAlgorithm, dataGroupHashes)
assert(
arraysAreEqual(mrzHash, dataGroupHashes.slice(31, 31 + mrzHash.length)),
'mrzHash is at the right place in dataGroupHashes'
arraysAreEqual(
concatHash,
eContent.slice(eContent.length - concatHash.length)
),
'concatHash is not at the right place in eContent'
);
const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10);
@@ -72,8 +80,10 @@ function verify(passportData: PassportData): boolean {
const md = forge.md.sha1.create();
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
const signature = String.fromCharCode(...encryptedDigest);
const signature = Buffer.from(encryptedDigest).toString(
'binary',
);
return rsaPublicKey.verify(md.digest().bytes(), signature);
}

View File

@@ -1,6 +1,6 @@
import assert from "assert";
import { PassportData } from "../../../common/src/utils/types";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual } from "../../../common/src/utils/utils";
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual, findSubarrayIndex } from "../../../common/src/utils/utils";
import * as forge from 'node-forge';
import { writeFileSync, readFileSync } from "fs";
@@ -32,15 +32,16 @@ const sampleDataHashes = [
14,
[76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38]
]
]
] as [number, number[]][]
const signatureAlgorithm = 'sha256WithRSAEncryption'
const hashLen = 32
export function genMockPassportData_sha256WithRSAEncryption_65537(): PassportData {
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
sampleDataHashes.unshift([1, mrzHash]);
const concatenatedDataHashes = formatAndConcatenateDataHashes(
mrzHash,
sampleDataHashes as [number, number[]][],
[[1, mrzHash], ...sampleDataHashes],
hashLen,
31
);
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
@@ -74,10 +75,17 @@ function verify(passportData: PassportData): boolean {
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
const formattedMrz = formatMrz(mrz);
const mrzHash = hash(signatureAlgorithm, formattedMrz);
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
console.log('dg1HashOffset', dg1HashOffset);
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
const concatHash = hash(signatureAlgorithm, dataGroupHashes)
assert(
arraysAreEqual(mrzHash, dataGroupHashes.slice(31, 31 + mrzHash.length)),
'mrzHash is at the right place in dataGroupHashes'
arraysAreEqual(
concatHash,
eContent.slice(eContent.length - hashLen)
),
'concatHash is not at the right place in eContent'
);
const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10);
@@ -87,7 +95,9 @@ function verify(passportData: PassportData): boolean {
const md = forge.md.sha256.create();
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
const signature = String.fromCharCode(...encryptedDigest);
const signature = Buffer.from(encryptedDigest).toString(
'binary',
);
return rsaPublicKey.verify(md.digest().bytes(), signature);
}

View File

@@ -0,0 +1,132 @@
import { describe } from 'mocha'
import { assert, expect } from 'chai'
import path from "path";
const wasm_tester = require("circom_tester").wasm;
import { poseidon1, poseidon6 } from "poseidon-lite";
import { mockPassportData_sha256WithRSASSAPSS_65537 } from "../../common/src/utils/mockPassportData";
import { generateCircuitInputsRegister } from '../../common/src/utils/generateInputs';
import { getLeaf } from '../../common/src/utils/pubkeyTree';
import { packBytes } from '../../common/src/utils/utils';
describe("Proof of Passport - Circuits - RSASSAPSS", function () {
this.timeout(0);
let inputs: any;
let circuit: any;
let passportData = mockPassportData_sha256WithRSASSAPSS_65537;
let attestation_id: string;
before(async () => {
circuit = await wasm_tester(
path.join(__dirname, "../circuits/register_sha256WithRSASSAPSS_65537.circom"),
{
include: [
"node_modules",
"node_modules/@zk-email/circuits/helpers/sha.circom",
"./node_modules/@zk-kit/binary-merkle-root.circom/src",
"./node_modules/circomlib/circuits"
]
},
);
const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString();
console.log("secret", secret);
const attestation_name = "E-PASSPORT";
attestation_id = poseidon1([
BigInt(Buffer.from(attestation_name).readUIntBE(0, 6))
]).toString();
inputs = generateCircuitInputsRegister(
secret,
attestation_id,
passportData,
[passportData],
);
});
it("should compile and load the circuit", async function () {
expect(circuit).to.not.be.undefined;
});
it("should calculate the witness with correct inputs", async function () {
console.time('calculateWitness')
const w = await circuit.calculateWitness(inputs);
console.timeEnd('calculateWitness')
await circuit.checkConstraints(w);
console.log("nullifier", (await circuit.getOutput(w, ["nullifier"])).nullifier);
const commitment_circom = (await circuit.getOutput(w, ["commitment"])).commitment;
const mrz_bytes = packBytes(inputs.mrz);
const commitment_bytes = poseidon6([
inputs.secret[0],
attestation_id,
getLeaf({
signatureAlgorithm: passportData.signatureAlgorithm,
modulus: passportData.pubKey.modulus,
exponent: passportData.pubKey.exponent
}),
mrz_bytes[0],
mrz_bytes[1],
mrz_bytes[2]
]);
const commitment_js = commitment_bytes.toString();
console.log('commitment_js', commitment_js)
console.log('commitment_circom', commitment_circom)
expect(commitment_circom).to.be.equal(commitment_js);
});
it("should fail to calculate witness with invalid mrz", async function () {
try {
const invalidInputs = {
...inputs,
mrz: Array(93).fill(0).map(byte => BigInt(byte).toString())
}
await circuit.calculateWitness(invalidInputs);
expect.fail("Expected an error but none was thrown.");
} catch (error) {
expect(error.message).to.include("Assert Failed");
}
});
it("should fail to calculate witness with invalid econtent", async function () {
try {
const invalidInputs = {
...inputs,
econtent: inputs.econtent.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)),
}
await circuit.calculateWitness(invalidInputs);
expect.fail("Expected an error but none was thrown.");
} catch (error) {
expect(error.message).to.include("Assert Failed");
}
});
it("should fail to calculate witness with invalid signature", async function () {
try {
const invalidInputs = {
...inputs,
signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)),
}
await circuit.calculateWitness(invalidInputs);
expect.fail("Expected an error but none was thrown.");
} catch (error) {
expect(error.message).to.include("Assert Failed");
}
});
it("should fail to calculate witness with invalid merkle root", async function () {
try {
const invalidInputs = {
...inputs,
merkle_root: inputs.merkle_root.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)),
}
await circuit.calculateWitness(invalidInputs);
expect.fail("Expected an error but none was thrown.");
} catch (error) {
expect(error.message).to.include("Assert Failed");
}
});
});

View File

@@ -0,0 +1,129 @@
import { describe } from 'mocha'
import { assert, expect } from 'chai'
import path from "path";
const wasm_tester = require("circom_tester").wasm;
import { poseidon1, poseidon6 } from "poseidon-lite";
import { mockPassportData_sha1WithRSAEncryption_65537 } from "../../common/src/utils/mockPassportData";
import { generateCircuitInputsRegister } from '../../common/src/utils/generateInputs';
import { getLeaf } from '../../common/src/utils/pubkeyTree';
import { packBytes } from '../../common/src/utils/utils';
describe("Circuits - sha1WithRSAEncryption_65537 Register flow", function () {
this.timeout(0);
let inputs: any;
let circuit: any;
let passportData = mockPassportData_sha1WithRSAEncryption_65537;
let attestation_id: string;
before(async () => {
circuit = await wasm_tester(
path.join(__dirname, "../circuits/register_sha1WithRSAEncryption_65537.circom"),
{
include: [
"node_modules",
"./node_modules/@zk-kit/binary-merkle-root.circom/src",
"./node_modules/circomlib/circuits",
"./node_modules/dmpierre/sha1-circom/circuits",
]
},
);
const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString();
console.log("secret", secret);
const attestation_name = "E-PASSPORT";
attestation_id = poseidon1([
BigInt(Buffer.from(attestation_name).readUIntBE(0, 6))
]).toString();
inputs = generateCircuitInputsRegister(
secret,
attestation_id,
passportData,
);
});
it("should compile and load the circuit", async function () {
expect(circuit).to.not.be.undefined;
});
it("should calculate the witness with correct inputs", async function () {
const w = await circuit.calculateWitness(inputs);
await circuit.checkConstraints(w);
console.log("nullifier", (await circuit.getOutput(w, ["nullifier"])).nullifier);
const commitment_circom = (await circuit.getOutput(w, ["commitment"])).commitment;
const mrz_bytes = packBytes(inputs.mrz);
const commitment_bytes = poseidon6([
inputs.secret[0],
attestation_id,
getLeaf({
signatureAlgorithm: passportData.signatureAlgorithm,
modulus: passportData.pubKey.modulus,
exponent: passportData.pubKey.exponent
}),
mrz_bytes[0],
mrz_bytes[1],
mrz_bytes[2]
]);
const commitment_js = commitment_bytes.toString();
console.log('commitment_js', commitment_js)
console.log('commitment_circom', commitment_circom)
expect(commitment_circom).to.be.equal(commitment_js);
});
it("should fail to calculate witness with invalid mrz", async function () {
try {
const invalidInputs = {
...inputs,
mrz: Array(93).fill(0).map(byte => BigInt(byte).toString())
}
await circuit.calculateWitness(invalidInputs);
expect.fail("Expected an error but none was thrown.");
} catch (error) {
expect(error.message).to.include("Assert Failed");
}
});
it("should fail to calculate witness with invalid econtent", async function () {
try {
const invalidInputs = {
...inputs,
econtent: inputs.econtent.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)),
}
await circuit.calculateWitness(invalidInputs);
expect.fail("Expected an error but none was thrown.");
} catch (error) {
expect(error.message).to.include("Assert Failed");
}
});
it("should fail to calculate witness with invalid signature", async function () {
try {
const invalidInputs = {
...inputs,
signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)),
}
await circuit.calculateWitness(invalidInputs);
expect.fail("Expected an error but none was thrown.");
} catch (error) {
expect(error.message).to.include("Assert Failed");
}
});
it("should fail to calculate witness with invalid merkle root", async function () {
try {
const invalidInputs = {
...inputs,
merkle_root: inputs.merkle_root.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)),
}
await circuit.calculateWitness(invalidInputs);
expect.fail("Expected an error but none was thrown.");
} catch (error) {
expect(error.message).to.include("Assert Failed");
}
});
});

View File

@@ -8,7 +8,7 @@ import { generateCircuitInputsRegister } from '../../common/src/utils/generateIn
import { getLeaf } from '../../common/src/utils/pubkeyTree';
import { packBytes } from '../../common/src/utils/utils';
describe("Proof of Passport - Circuits - Register flow", function () {
describe("Circuits - sha256WithRSAEncryption_65537 Register flow", function () {
this.timeout(0);
let inputs: any;
let circuit: any;

View File

@@ -2,11 +2,6 @@
# yarn lockfile v1
"@adraffy/ens-normalize@1.10.1":
version "1.10.1"
resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069"
integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==
"@cspotcode/source-map-support@^0.8.0":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
@@ -387,18 +382,6 @@
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@noble/curves@1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35"
integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==
dependencies:
"@noble/hashes" "1.3.2"
"@noble/hashes@1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==
"@tsconfig/node10@^1.0.7":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
@@ -463,11 +446,6 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.3.tgz#5b763b321cd3b80f6b8dde7a37e1a77ff9358dd9"
integrity sha512-HksnYH4Ljr4VQgEy2lTStbCKv/P590tmPe5HqOnv9Gprffgv5WXAY+Y5Gqniu0GGqeTCUdBnzC3QSrzPkBkAMA==
"@types/node@18.15.13":
version "18.15.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469"
integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==
"@types/node@^20.11.19":
version "20.11.19"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.19.tgz#b466de054e9cb5b3831bee38938de64ac7f81195"
@@ -475,39 +453,29 @@
dependencies:
undici-types "~5.26.4"
"@zk-email/circuits@^3.2.2":
version "3.2.3"
resolved "https://registry.yarnpkg.com/@zk-email/circuits/-/circuits-3.2.3.tgz#24e16706bc1f46eab5b6e51185faf8d8afe28175"
integrity sha512-dAOaEul2iq86f69FFaXK/u3ec+Lk6B3vpbapyJ9oKGgWeINilWJQaEP1WSJyeVV52zPRVE5uDkIVhIguU7jk2g==
"@zk-email/circuits@^6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@zk-email/circuits/-/circuits-6.1.1.tgz#6eff8063fc71bf5ad38c90c552e9bfdfcd7247c6"
integrity sha512-O09UQjEY0sM8gfR6M2/KJPZfIac7xuVHvpwyTCxTpb+CZvt3qXhhRcrDm3CoHOpvtRGS3sI9SdUQZipiiSiR/w==
dependencies:
"@zk-email/zk-regex-circom" "^1.1.1"
"@zk-email/zk-regex-circom" "^2.1.0"
circomlib "^2.0.5"
"@zk-email/helpers@^3.1.3":
version "3.1.3"
resolved "https://registry.yarnpkg.com/@zk-email/helpers/-/helpers-3.1.3.tgz#c3e603955ea794b9506968e910249b990b1b536a"
integrity sha512-a6iyWugDkm5RKnXd3q0bAqXWuJ4nKtRinQD8jt5UhiDKD2OJ8SAc+tvgeHOTyZx90nKP6mDolGEy+tWAWpdVMg==
"@zk-email/helpers@^6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@zk-email/helpers/-/helpers-6.1.1.tgz#3172d07c7fd1ce56a2957dc9ff32b0bc7d1592a3"
integrity sha512-u3LYa8rLdLCvy4FpgXOfQNJPOIrj26CwxLDEYOwyDwYpdSdvEgqE/FL1h2Rwkr1TdbneWaCeSVQC4jhtQaXswg==
dependencies:
addressparser "^1.0.1"
atob "^2.1.2"
circomlibjs "^0.1.7"
ethers "^6.8.0"
libmime "^5.2.1"
localforage "^1.10.0"
lodash "^4.17.21"
node-forge "^1.3.1"
pako "^2.1.0"
pki "^1.1.0"
psl "^1.9.0"
snarkjs "https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e"
"@zk-email/zk-regex-circom@^1.1.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@zk-email/zk-regex-circom/-/zk-regex-circom-1.2.1.tgz#ea1adc832e8d855c9568abc438567a524a0ac962"
integrity sha512-+AoH5PdKZxatTWfwYWGkpuQ0xGaax6FwBHvdYXugkPDdgtJQYyxhItQtM79bo0djCmuwEK2X1rnYlFHBDClQeA==
dependencies:
commander "^11.0.0"
snarkjs "^0.7.0"
"@zk-email/zk-regex-circom@^1.2.1":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@zk-email/zk-regex-circom/-/zk-regex-circom-1.3.0.tgz#8cb2b3b4977cfe42dc7072e13795e10d92efa074"
@@ -516,6 +484,14 @@
commander "^11.0.0"
snarkjs "^0.7.0"
"@zk-email/zk-regex-circom@^2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@zk-email/zk-regex-circom/-/zk-regex-circom-2.1.0.tgz#cc2f1d93fb130a9f8ac88114d3559a296df97538"
integrity sha512-Ayq0Hk4m7w1UHPPx2c5bUWLdKUPnuK62AZFOyiIvA7x4NgRyvjxe+S4D5KFH5FIz4PgEnXVxgscSSbe5p/GCvQ==
dependencies:
commander "^11.0.0"
snarkjs "^0.7.0"
"@zk-kit/binary-merkle-root.circom@^1.0.0-beta":
version "1.0.0-beta"
resolved "https://registry.yarnpkg.com/@zk-kit/binary-merkle-root.circom/-/binary-merkle-root.circom-1.0.0-beta.tgz#1124840ff3d0af8c28ad4d9ee5004d41f6768978"
@@ -568,11 +544,6 @@ aes-js@3.0.0:
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d"
integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==
aes-js@4.0.0-beta.5:
version "4.0.0-beta.5"
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873"
integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==
ansi-colors@4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
@@ -830,6 +801,11 @@ check-types@^11.2.3:
resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.3.tgz#1ffdf68faae4e941fce252840b1787b8edc93b71"
integrity sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==
child_process@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/child_process/-/child_process-1.0.2.tgz#b1f7e7fc73d25e7fd1d455adc94e143830182b5a"
integrity sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g==
chokidar@3.5.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
@@ -859,6 +835,20 @@ circom_runtime@0.1.24:
dependencies:
ffjavascript "0.2.60"
circom_tester@^0.0.19:
version "0.0.19"
resolved "https://registry.yarnpkg.com/circom_tester/-/circom_tester-0.0.19.tgz#e8bed494d080f8186bd0ac6571755d00ccec83bd"
integrity sha512-SNHaBsGxcBH6XsVWfsRbRPA7NF8m8AMKJI9dtJJCFGUtOTT2+zsoIqAwi50z6XCnO4TtjyXq7AeXa1PLHqT0tw==
dependencies:
chai "^4.3.6"
child_process "^1.0.2"
ffjavascript "^0.2.56"
fnv-plus "^1.3.1"
r1csfile "^0.0.41"
snarkjs "0.5.0"
tmp-promise "^3.0.3"
util "^0.12.4"
"circom_tester@github:Atomic-Buy/circom_tester#main":
version "0.0.20"
resolved "https://codeload.github.com/Atomic-Buy/circom_tester/tar.gz/cf7d7a60bddcffc2388f0acaf44f38bb00d6f2f6"
@@ -970,6 +960,13 @@ diff@^4.0.1:
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
"dmpierre/sha1-circom@https://github.com/dmpierre/sha1-circom/":
version "1.0.0"
resolved "https://github.com/dmpierre/sha1-circom/#fe18319cf72b9f3b83d0cea8f49a1f04482c125b"
dependencies:
circom_tester "^0.0.19"
snarkjs "^0.5.0"
ejs@^3.1.6:
version "3.1.9"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361"
@@ -1103,19 +1100,6 @@ ethers@^5.5.1:
"@ethersproject/web" "5.7.1"
"@ethersproject/wordlists" "5.7.0"
ethers@^6.8.0:
version "6.11.1"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.11.1.tgz#96aae00b627c2e35f9b0a4d65c7ab658259ee6af"
integrity sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==
dependencies:
"@adraffy/ens-normalize" "1.10.1"
"@noble/curves" "1.2.0"
"@noble/hashes" "1.3.2"
"@types/node" "18.15.13"
aes-js "4.0.0-beta.5"
tslib "2.4.0"
ws "8.5.0"
fast-levenshtein@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
@@ -1144,7 +1128,7 @@ ffjavascript@0.2.60, ffjavascript@^0.2.48:
wasmcurves "0.2.2"
web-worker "^1.2.0"
ffjavascript@0.2.63, ffjavascript@^0.2.45, ffjavascript@^0.2.60:
ffjavascript@0.2.63, ffjavascript@^0.2.45, ffjavascript@^0.2.56, ffjavascript@^0.2.60:
version "0.2.63"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.63.tgz#0c1216a1f123dc9181df69e144473704d2f115eb"
integrity sha512-dBgdsfGks58b66JnUZeZpGxdMIDQ4QsD3VYlRJyFVrKQHb2kJy4R2gufx5oetrTxXPT+aEjg0dOvOLg1N0on4A==
@@ -1516,11 +1500,6 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-symbols@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
@@ -1708,11 +1687,6 @@ picomatch@^2.0.4, picomatch@^2.2.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pki@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/pki/-/pki-1.1.0.tgz#abd7c257816ceb2a0c0afef5642180227355d173"
integrity sha512-OzMMXAo8sI7X3+EW46eIfGfOnuM0d0Cef0iVp7UUCsh2VV7RvsUztLTc6xacBwgsz16Vp6qQuQA8Lep5bxeuOA==
poseidon-lite@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/poseidon-lite/-/poseidon-lite-0.2.0.tgz#dbc242ebd9c10c32d507a533fa497231d168fd72"
@@ -1733,7 +1707,7 @@ psl@^1.9.0:
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
r1csfile@0.0.41:
r1csfile@0.0.41, r1csfile@^0.0.41:
version "0.0.41"
resolved "https://registry.yarnpkg.com/r1csfile/-/r1csfile-0.0.41.tgz#e3d2709d36923156dd1fc2db9858987b30c92948"
integrity sha512-Q1WDF3u1vYeAwjHo4YuddkA8Aq0TulbKjmGm99+Atn13Lf5fTsMZBnBV9T741w8iSyPFG6Uh6sapQby77sREqA==
@@ -1822,6 +1796,22 @@ set-function-length@^1.2.1:
gopd "^1.0.1"
has-property-descriptors "^1.0.1"
snarkjs@0.5.0, snarkjs@^0.5.0, "snarkjs@https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e":
version "0.5.0"
resolved "https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e"
dependencies:
"@iden3/binfileutils" "0.0.11"
bfj "^7.0.2"
blake2b-wasm "^2.4.0"
circom_runtime "0.1.21"
ejs "^3.1.6"
fastfile "0.0.20"
ffjavascript "0.2.56"
js-sha3 "^0.8.0"
localforage "^1.10.0"
logplease "^1.2.15"
r1csfile "0.0.41"
snarkjs@^0.7.0, snarkjs@^0.7.1:
version "0.7.3"
resolved "https://registry.yarnpkg.com/snarkjs/-/snarkjs-0.7.3.tgz#7f703d05b810235255f2d0a70d8a9b8b3ea916e5"
@@ -1838,22 +1828,6 @@ snarkjs@^0.7.0, snarkjs@^0.7.1:
logplease "^1.2.15"
r1csfile "0.0.47"
"snarkjs@https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e":
version "0.5.0"
resolved "https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e"
dependencies:
"@iden3/binfileutils" "0.0.11"
bfj "^7.0.2"
blake2b-wasm "^2.4.0"
circom_runtime "0.1.21"
ejs "^3.1.6"
fastfile "0.0.20"
ffjavascript "0.2.56"
js-sha3 "^0.8.0"
localforage "^1.10.0"
logplease "^1.2.15"
r1csfile "0.0.41"
source-map-support@^0.5.6:
version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
@@ -1999,11 +1973,6 @@ tsconfig-paths@^3.5.0:
minimist "^1.2.6"
strip-bom "^3.0.0"
tslib@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
type-check@~0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
@@ -2036,7 +2005,7 @@ util-deprecate@^1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
util@^0.12.5:
util@^0.12.4, util@^0.12.5:
version "0.12.5"
resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc"
integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==
@@ -2116,11 +2085,6 @@ ws@7.4.6:
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
ws@8.5.0:
version "8.5.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"