feat: sha1 with ecdsa verifier

This commit is contained in:
0xvikasrushi
2024-07-28 18:22:43 +00:00
parent 85b4f3a9c5
commit 8391df73c1
3 changed files with 144 additions and 189 deletions

View File

@@ -7,154 +7,102 @@ include "../../utils/rsaPkcs1.circom";
include "dmpierre/sha1-circom/circuits/sha1.circom";
include "../../utils/circom-ecdsa/ecdsa.circom";
// n, k, max_datahashes_bytes
template PassportVerifier_ecdsaWithSHA1Encryption(n,k) {
//
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 r[k];
signal input s[k];
signal input msghash[k];
signal input pubkey[2][k];
signal input datahashes_padded_length;
signal input eContentBytes[eContentBytesLength];
// pubkey that signed the passport for ecdsa it will be qx and qy on p256 curve need use bigInt.circom
// coz p256 modulus extends 254 bit range in circom
signal input dsc_modulus[2][k];
// signal input r[6];
// signal s[6];
// signal msghash[6];
// signal pubkey[2][6];
// r[0] <== 4356595461396;
// r[1] <== 7517478021216;
// r[2] <== 461130717732;
// r[3] <== 582422961751;
// r[4] <== 4827585151075;
// r[5] <== 1832639904957;
// signature of the passport
signal input signature_r[k];
signal input signature_s[k];
// compute sha1 of formatted mrz
signal mrzSha[160] <== Sha1BytesStatic(93)(mrz);
// s[0] <== 491010621745;
// s[1] <== 1153769202424;
// s[2] <== 7481879050338;
// s[3] <== 2362326744248;
// s[4] <== 5715790716735;
// s[5] <== 1133501322735;
// 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);
// pubkey[0][0] <== 4705934152392;
// pubkey[0][1] <== 8704141833119;
// pubkey[0][2] <== 4827796658582;
// pubkey[0][3] <== 5154602932886;
// pubkey[0][4] <== 6957561507837;
// pubkey[0][5] <== 974696539144;
for (var j = 0; j < 8; j++) {
mrzSha_bytes[i].in[7 - j] <== mrzSha[i * 8 + j];
}
}
// pubkey[1][0] <== 8600645394507;
// pubkey[1][1] <== 418369241838;
// pubkey[1][2] <== 1959034348828;
// pubkey[1][3] <== 6964301761725;
// pubkey[1][4] <== 1750427296885;
// pubkey[1][5] <== 1782063459524;
// 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);
// msghash[0] <== 1234;
// msghash[1] <== 0;
// msghash[2] <== 0;
// msghash[3] <== 0;
// msghash[4] <== 0;
// msghash[5] <== 0;
// 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 <== r;
ecdsa_verify.s <== s;
ecdsa_verify.msghash <== msghash;
ecdsa_verify.pubkey <== pubkey;
ecdsa_verify.r <== signature_r;
ecdsa_verify.s <== signature_s;
ecdsa_verify.msghash <== msgHash;
ecdsa_verify.pubkey <== dsc_modulus;
// log(ecdsa_verify.valid);
log("ecdsa_verify.result", ecdsa_verify.result);
signal output result <== ecdsa_verify.result;
// 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
// // for ecdsa it will be qx and qy on p256 curve need use bigInt.circom
// // coz p256 modulus extends 254 bit range in circom
// signal input dsc_modulus[k];
// // signal input dsc_public_key_x[k];
// // signal input dsc_public_key_y[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;
// }
// ! 43 * 6 = 258 > circom field 254
// ! 64 * 4 = 256 > circom field 254 we can use any of the these
// rsa.modulus <== dsc_modulus;
// rsa.signature <== signature;
// var k = div_ceil(10 ,3 );
}
// 121, 17, 320
component main = PassportVerifier_ecdsaWithSHA1Encryption(43, 6);
component main = PassportVerifier_ecdsaWithSHA1Encryption(43, 6, 320);

View File

@@ -1,11 +1,26 @@
import { expect } from 'chai';
import { describe } from 'mocha';
import path from 'path';
import { poseidon1 } from 'poseidon-lite';
import { mockPassPortData_sha1_ecdsa } from '../../../common/src/constants/mockPassportData';
import { generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs';
import { extractRSFromSignature } from '../../../common/src/utils/utils';
import { extractRSFromSignature, hexToDecimal } from '../../../common/src/utils/utils';
const wasm_tester = require('circom_tester').wasm;
import elliptic from 'elliptic';
import * as crypto from 'crypto';
function bigint_to_array(n: number, k: number, x: bigint) {
let mod: bigint = 1n;
for (var idx = 0; idx < n; idx++) {
mod = mod * 2n;
}
let ret: bigint[] = [];
var x_temp: bigint = x;
for (var idx = 0; idx < k; idx++) {
ret.push(x_temp % mod);
x_temp = x_temp / mod;
}
return ret;
}
describe('Register - SHA1 WITH ECDSA', function () {
this.timeout(0);
@@ -14,7 +29,7 @@ describe('Register - SHA1 WITH ECDSA', function () {
let passportData = mockPassPortData_sha1_ecdsa;
let attestation_id: string;
const attestation_name = 'E-PASSPORT';
const n_dsc = 43;
const n_dsc = 43; // 43 * 6 = 258 > 254 Cirom field size
const k_dsc = 6;
const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString();
@@ -30,58 +45,52 @@ describe('Register - SHA1 WITH ECDSA', function () {
k_dsc
);
let qx = inputs.dsc_modulus[0];
let qy = inputs.dsc_modulus[1];
let signature = inputs.signature;
before(async () => {
circuit = await wasm_tester(
path.join(
__dirname,
'../../circuits/register/verifier/passport_verifier_ecdsaWithSHA1Encryption.circom'
),
{
include: [
'node_modules',
'./node_modules/@zk-kit/binary-merkle-root.circom/src',
'./node_modules/circomlib/circuits',
'./node_modules/dmpierre/sha1-circom/circuits',
],
}
);
});
const ec = new elliptic.ec('p256');
const key = ec.keyFromPublic({ x: qx, y: qy }, 'hex');
it('should compile and load the circuit', async function () {
expect(circuit).to.not.be.undefined;
});
const messageBuffer = Buffer.from(inputs.signed_attributes);
const msgHash = crypto.createHash('sha1').update(messageBuffer).digest();
it('should verify inputs with ecdsa sha256', async function () {
let qx = BigInt(hexToDecimal(inputs.dsc_modulus[0]));
let qy = BigInt(hexToDecimal(inputs.dsc_modulus[1]));
let dsc_modulus = [bigint_to_array(43, 6, qx), bigint_to_array(43, 6, qy)];
const isValid = key.verify(msgHash, signature);
let signature = inputs.signature;
let { r, s } = extractRSFromSignature(signature);
let signature_r = bigint_to_array(43, 6, BigInt(hexToDecimal(r)));
let signature_s = bigint_to_array(43, 6, BigInt(hexToDecimal(s)));
console.log('isVerified', isValid);
// console.log('dsc_modulus', dsc_modulus);
// console.log('signature_r', signature_r);
// console.log('signature_s', signature_s);
// console.log('dg1_hash', inputs.dg1_hash_offset);
// console.log('econtent', inputs.econtent);
let { r, s } = extractRSFromSignature(inputs.signature);
console.log('r', r);
console.log('s', s);
// console.log(extractRSFromSignature(inputs.signature));
// let sui = Buffer.from(inputs.signature);
// console.log(sui);
// var test_cases: Array<[bigint, bigint, bigint, bigint]> = [];
// var privkeys: Array<bigint> = [
// 88549154299169935420064281163296845505587953610183896504176354567359434168161n,
// 37706893564732085918706190942542566344879680306879183356840008504374628845468n,
// 90388020393783788847120091912026443124559466591761394939671630294477859800601n,
// 110977009687373213104962226057480551605828725303063265716157300460694423838923n,
// ];
// for (var idx = 0; idx < privkeys.length; idx++) {
// var pubkey = p256.ProjectivePoint.fromPrivateKey(privkeys[idx]);
// var msghash_bigint: bigint = 1234n;
// test_cases.push([privkeys[idx], msghash_bigint, pubkey.x, pubkey.y]);
// }
// before(async () => {
// circuit = await wasm_tester(
// path.join(
// __dirname,
// '../../circuits/register/verifier/passport_verifier_ecdsaWithSHA1Encryption.circom'
// ),
// {
// include: [
// 'node_modules',
// './node_modules/@zk-kit/binary-merkle-root.circom/src',
// './node_modules/circomlib/circuits',
// './node_modules/dmpierre/sha1-circom/circuits',
// ],
// }
// );
// });
// it('should compile and load the circuit', async function () {
// expect(circuit).to.not.be.undefined;
// });
const witness = await circuit.calculateWitness({
mrz: inputs.mrz,
dg1_hash_offset: inputs.dg1_hash_offset[0],
dataHashes: inputs.econtent,
datahashes_padded_length: inputs.datahashes_padded_length[0],
eContentBytes: inputs.signed_attributes,
dsc_modulus: dsc_modulus,
signature_r: signature_r,
signature_s: signature_s,
});
});
});