-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #121 from seshanthS/feat/sha1WithRSAEncryption
Feat: sha1 with rsa encryption
- Loading branch information
Showing
28 changed files
with
1,105 additions
and
335 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
circuits/circuits/passport_verifier_sha1WithRSAEncryption_65537.circom
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
pragma circom 2.1.5; | ||
|
||
include "./utils/rsaPkcs1.circom"; | ||
include "@zk-email/circuits/helpers/extract.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) { | ||
signal input mrz[93]; // formatted mrz (5 + 88) chars | ||
signal input dataHashes[max_datahashes_bytes]; | ||
signal input datahashes_padded_length; | ||
signal input eContentBytes[92]; | ||
|
||
// 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[20]; | ||
|
||
// cast the 160 bits from mrzSha into a list of 32 bytes | ||
for (var i = 0; i < 20; 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 32 to 52) | ||
for(var i = 0; i < 20; i++) { | ||
dataHashes[31 + i] === mrzSha_bytes[i].out; | ||
} | ||
|
||
// hash dataHashes dynamically | ||
signal dataHashesSha[160] <== Sha1Bytes(max_datahashes_bytes)(dataHashes, datahashes_padded_length); | ||
|
||
// get output of dataHashes 160 into bytes to check against eContent | ||
component dataHashesSha_bytes[20]; | ||
for (var i = 0; i < 20; 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 < 20; i++) { | ||
// log(dataHashesSha_bytes[i].out); | ||
|
||
eContentBytes[72 + i] === dataHashesSha_bytes[i].out; | ||
} | ||
|
||
// hash eContentBytes | ||
signal eContentSha[160] <== Sha1BytesStatic(92)(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++) { | ||
//instantiate each component of the list of Bits2Num of size n | ||
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(64, 32); | ||
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; | ||
} |
59 changes: 59 additions & 0 deletions
59
circuits/circuits/register_sha1WithRSAEncryption_65537.circom
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
pragma circom 2.1.5; | ||
|
||
include "circomlib/circuits/poseidon.circom"; | ||
include "@zk-email/circuits/helpers/extract.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 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.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, 3, 31)(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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
pragma circom 2.1.5; | ||
|
||
include "@zk-email/circuits/helpers/utils.circom"; | ||
include "dmpierre/sha1-circom/circuits/sha1compression.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 = log2_ceil(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 = log2_ceil(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] = QuinSelector(maxBlocks, maxBlocksBits); | ||
for (j=0; j<maxBlocks; j++) { | ||
arraySelectors[i].in[j] <== outs[j][i]; | ||
} | ||
arraySelectors[i].index <== inBlockIndex - 1; | ||
out[i] <== arraySelectors[i].out; | ||
} | ||
} |
Oops, something went wrong.