mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
Merge remote-tracking branch 'origin/dev' into csca
This commit is contained in:
@@ -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.
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
61
circuits/circuits/register_sha256WithRSASSAPSS_65537.circom
Normal file
61
circuits/circuits/register_sha256WithRSASSAPSS_65537.circom
Normal 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);
|
||||
@@ -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;
|
||||
|
||||
192
circuits/circuits/utils/RSASSAPSS.circom
Normal file
192
circuits/circuits/utils/RSASSAPSS.circom
Normal 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]);
|
||||
}
|
||||
}
|
||||
119
circuits/circuits/utils/Sha1Bytes.circom
Normal file
119
circuits/circuits/utils/Sha1Bytes.circom
Normal 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;
|
||||
}
|
||||
}
|
||||
35
circuits/circuits/utils/Sha1BytesStatic.circom
Normal file
35
circuits/circuits/utils/Sha1BytesStatic.circom
Normal 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];
|
||||
}
|
||||
}
|
||||
157
circuits/circuits/utils/rsaPkcs1.circom
Normal file
157
circuits/circuits/utils/rsaPkcs1.circom
Normal 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];
|
||||
}
|
||||
}
|
||||
11
circuits/circuits/utils/xor.circom
Normal file
11
circuits/circuits/utils/xor.circom
Normal 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];
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
36
circuits/scripts/build_circuits.sh
Executable file
36
circuits/scripts/build_circuits.sh
Executable 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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
12
circuits/scripts/download_ptau.sh
Normal file
12
circuits/scripts/download_ptau.sh
Normal 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 ..
|
||||
@@ -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(',');
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
132
circuits/test/RSSSSAPSS.test.ts
Normal file
132
circuits/test/RSSSSAPSS.test.ts
Normal 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");
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
129
circuits/test/register_sha1.test.ts
Normal file
129
circuits/test/register_sha1.test.ts
Normal 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");
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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;
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user