rsassapss: add verifier & register circuits

This commit is contained in:
seshanthS
2024-06-22 18:04:18 +05:30
parent b4fbe95885
commit 059626cade
3 changed files with 147 additions and 0 deletions

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_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

@@ -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];
}
}