-
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 #159 from zk-passport/sha1-with-ecdsa
ECDSA With SHA1 & SHA256 Support
- Loading branch information
Showing
28 changed files
with
115,679 additions
and
1,946 deletions.
There are no files selected for viewing
86 changes: 86 additions & 0 deletions
86
circuits/circuits/register/register_ecdsaWithSHA1Encryption.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,86 @@ | ||
pragma circom 2.1.5; | ||
|
||
include "circomlib/circuits/poseidon.circom"; | ||
include "@zk-email/circuits/utils/bytes.circom"; | ||
include "./verifier/passport_verifier_ecdsaWithSHA1Encryption.circom"; | ||
include "binary-merkle-root.circom"; | ||
include "../utils/splitSignalsToWords.circom"; | ||
|
||
template Register_ecdsaWithSHA1Encryption(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_r[k]; // ECDSA signature component r | ||
signal input signature_s[k]; // ECDSA signature component s | ||
signal input dsc_modulus[2][k]; // Public Key (split into Qx and Qy) | ||
|
||
signal input dsc_secret; | ||
signal input attestation_id; | ||
|
||
// Hash DSC modulus and signature components | ||
// Poseidon(dsc_modulus[0][0], dsc_modulus[0][1], ..., dsc_modulus[0][5]) | ||
component poseidon_hasher_dsc_modules_x = Poseidon(6); | ||
component poseidon_hasher_dsc_modules_y = Poseidon(6); | ||
|
||
// Poseidon(signature_r[0], signature_r[1], ..., signature_r[5]) | ||
component poseidon_hasher_signature_r = Poseidon(6); | ||
component poseidon_hasher_signature_s = Poseidon(6); | ||
|
||
for (var i = 0; i < k; i++) { | ||
poseidon_hasher_dsc_modules_x.inputs[i] <== dsc_modulus[0][i]; | ||
poseidon_hasher_dsc_modules_y.inputs[i] <== dsc_modulus[1][i]; | ||
poseidon_hasher_signature_r.inputs[i] <== signature_r[i]; | ||
poseidon_hasher_signature_s.inputs[i] <== signature_s[i]; | ||
} | ||
|
||
component dsc_commitment_hasher = Poseidon(3); | ||
component nullifier_hasher = Poseidon(3); | ||
component leaf_hasher = Poseidon(3); | ||
|
||
dsc_commitment_hasher.inputs[0] <== dsc_secret; | ||
dsc_commitment_hasher.inputs[1] <== poseidon_hasher_dsc_modules_x.out; | ||
dsc_commitment_hasher.inputs[2] <== poseidon_hasher_dsc_modules_y.out; | ||
|
||
nullifier_hasher.inputs[0] <== secret; | ||
nullifier_hasher.inputs[1] <== poseidon_hasher_signature_r.out; | ||
nullifier_hasher.inputs[2] <== poseidon_hasher_signature_s.out; | ||
|
||
leaf_hasher.inputs[0] <== signatureAlgorithm; | ||
leaf_hasher.inputs[1] <== poseidon_hasher_dsc_modules_x.out; | ||
leaf_hasher.inputs[2] <== poseidon_hasher_dsc_modules_y.out; | ||
|
||
signal output blinded_dsc_commitment <== dsc_commitment_hasher.out; | ||
signal output nullifier <== nullifier_hasher.out; | ||
|
||
// Verify passport validity | ||
component PV = PassportVerifier_ecdsaWithSHA1Encryption(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.dsc_modulus <== dsc_modulus; | ||
PV.signature_r <== signature_r; | ||
PV.signature_s <== signature_s; | ||
|
||
// signature is valid | ||
PV.result === 1; | ||
|
||
// Generate the commitment | ||
component poseidon_hasher = Poseidon(6); | ||
poseidon_hasher.inputs[0] <== secret; | ||
poseidon_hasher.inputs[1] <== attestation_id; | ||
poseidon_hasher.inputs[2] <== leaf_hasher.out; | ||
|
||
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; | ||
} | ||
|
||
component main { public [ attestation_id ] } = Register_ecdsaWithSHA1Encryption(43, 6, 320, 16, 7); |
86 changes: 86 additions & 0 deletions
86
circuits/circuits/register/register_ecdsaWithSHA256Encryption.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,86 @@ | ||
pragma circom 2.1.5; | ||
|
||
include "circomlib/circuits/poseidon.circom"; | ||
include "@zk-email/circuits/utils/bytes.circom"; | ||
include "./verifier/passport_verifier_ecdsaWithSHA256Encryption.circom"; | ||
include "binary-merkle-root.circom"; | ||
include "../utils/splitSignalsToWords.circom"; | ||
|
||
template Register_ecdsaWithSHA256Encryption(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_r[k]; // ECDSA signature component r | ||
signal input signature_s[k]; // ECDSA signature component s | ||
signal input dsc_modulus[2][k]; // Public Key (split into Qx and Qy) | ||
|
||
signal input dsc_secret; | ||
signal input attestation_id; | ||
|
||
// Hash DSC modulus and signature components | ||
// Poseidon(dsc_modulus[0][0], dsc_modulus[0][1], ..., dsc_modulus[0][5]) | ||
component poseidon_hasher_dsc_modules_x = Poseidon(6); | ||
component poseidon_hasher_dsc_modules_y = Poseidon(6); | ||
|
||
// Poseidon(signature_r[0], signature_r[1], ..., signature_r[5]) | ||
component poseidon_hasher_signature_r = Poseidon(6); | ||
component poseidon_hasher_signature_s = Poseidon(6); | ||
|
||
for (var i = 0; i < k; i++) { | ||
poseidon_hasher_dsc_modules_x.inputs[i] <== dsc_modulus[0][i]; | ||
poseidon_hasher_dsc_modules_y.inputs[i] <== dsc_modulus[1][i]; | ||
poseidon_hasher_signature_r.inputs[i] <== signature_r[i]; | ||
poseidon_hasher_signature_s.inputs[i] <== signature_s[i]; | ||
} | ||
|
||
component dsc_commitment_hasher = Poseidon(3); | ||
component nullifier_hasher = Poseidon(3); | ||
component leaf_hasher = Poseidon(3); | ||
|
||
dsc_commitment_hasher.inputs[0] <== dsc_secret; | ||
dsc_commitment_hasher.inputs[1] <== poseidon_hasher_dsc_modules_x.out; | ||
dsc_commitment_hasher.inputs[2] <== poseidon_hasher_dsc_modules_y.out; | ||
|
||
nullifier_hasher.inputs[0] <== secret; | ||
nullifier_hasher.inputs[1] <== poseidon_hasher_signature_r.out; | ||
nullifier_hasher.inputs[2] <== poseidon_hasher_signature_s.out; | ||
|
||
leaf_hasher.inputs[0] <== signatureAlgorithm; | ||
leaf_hasher.inputs[1] <== poseidon_hasher_dsc_modules_x.out; | ||
leaf_hasher.inputs[2] <== poseidon_hasher_dsc_modules_y.out; | ||
|
||
signal output blinded_dsc_commitment <== dsc_commitment_hasher.out; | ||
signal output nullifier <== nullifier_hasher.out; | ||
|
||
// Verify passport validity | ||
component PV = PassportVerifier_ecdsaWithSHA256Encryption(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.dsc_modulus <== dsc_modulus; | ||
PV.signature_r <== signature_r; | ||
PV.signature_s <== signature_s; | ||
|
||
// signature is valid | ||
PV.result === 1; | ||
|
||
// Generate the commitment | ||
component poseidon_hasher = Poseidon(6); | ||
poseidon_hasher.inputs[0] <== secret; | ||
poseidon_hasher.inputs[1] <== attestation_id; | ||
poseidon_hasher.inputs[2] <== leaf_hasher.out; | ||
|
||
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; | ||
} | ||
|
||
component main { public [ attestation_id ] } = Register_ecdsaWithSHA256Encryption(43, 6, 320, 16, 8); |
102 changes: 102 additions & 0 deletions
102
circuits/circuits/register/verifier/passport_verifier_ecdsaWithSHA1Encryption.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,102 @@ | ||
pragma circom 2.1.5; | ||
|
||
include "@zk-email/circuits/utils/bytes.circom"; | ||
include "../../utils/Sha1BytesStatic.circom"; | ||
include "../../utils/Sha1Bytes.circom"; | ||
include "../../utils/rsaPkcs1.circom"; | ||
include "dmpierre/sha1-circom/circuits/sha1.circom"; | ||
include "../../utils/circom-ecdsa/ecdsa.circom"; | ||
|
||
template PassportVerifier_ecdsaWithSHA1Encryption(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]; | ||
|
||
signal input dsc_modulus[2][k]; // Public Key (split into Qx and Qy) | ||
|
||
signal input signature_r[k]; // ECDSA signature component r | ||
signal input signature_s[k]; // ECDSA signature component s | ||
|
||
// 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; | ||
} | ||
|
||
// 43 * 6 = 258; | ||
signal msgHash[6]; | ||
for(var i = 0; i < 4; i++) { | ||
msgHash[i] <== eContentHash[i].out; | ||
} | ||
msgHash[4] <== 0; | ||
msgHash[5] <== 0; | ||
|
||
// verify eContentHash signature | ||
component ecdsa_verify = ECDSAVerifyNoPubkeyCheck(n,k); | ||
|
||
ecdsa_verify.r <== signature_r; | ||
ecdsa_verify.s <== signature_s; | ||
ecdsa_verify.msghash <== msgHash; | ||
ecdsa_verify.pubkey <== dsc_modulus; | ||
|
||
signal output result <== ecdsa_verify.result; | ||
} | ||
|
99 changes: 99 additions & 0 deletions
99
circuits/circuits/register/verifier/passport_verifier_ecdsaWithSHA256Encryption.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,99 @@ | ||
pragma circom 2.1.5; | ||
|
||
include "@zk-email/circuits/utils/bytes.circom"; | ||
include "../../utils/circom-ecdsa/ecdsa.circom"; | ||
include "../../utils/Sha256BytesStatic.circom"; | ||
include "@zk-email/circuits/lib/sha.circom"; | ||
|
||
template PassportVerifier_ecdsaWithSHA256Encryption(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]; | ||
|
||
signal input dsc_modulus[2][k]; // Public Key (split into Qx and Qy) | ||
|
||
signal input signature_r[k]; // ECDSA signature component r | ||
signal input signature_s[k]; // ECDSA signature component s | ||
|
||
// 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 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[256] <== Sha256BytesStatic(104)(eContentBytes); | ||
|
||
// 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 | ||
component eContentHash[msg_len]; | ||
for (var i = 0; i < msg_len; i++) { | ||
eContentHash[i] = Bits2Num(n); | ||
} | ||
|
||
for (var i = 0; i < 256; i++) { | ||
eContentHash[i \ n].in[i % n] <== eContentSha[255 - i]; | ||
} | ||
|
||
for (var i = 256; i < n * msg_len; i++) { | ||
eContentHash[i \ n].in[i % n] <== 0; | ||
} | ||
|
||
|
||
// 43 * 6 = 258; | ||
signal msgHash[6]; | ||
for(var i = 0; i < msg_len; i++) { | ||
msgHash[i] <== eContentHash[i].out; | ||
} | ||
|
||
// verify eContentHash signature | ||
component ecdsa_verify = ECDSAVerifyNoPubkeyCheck(n,k); | ||
|
||
ecdsa_verify.r <== signature_r; | ||
ecdsa_verify.s <== signature_s; | ||
ecdsa_verify.msghash <== msgHash; | ||
ecdsa_verify.pubkey <== dsc_modulus; | ||
|
||
signal output result <== ecdsa_verify.result; | ||
} | ||
|
Oops, something went wrong.