mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
feat: sha1 with ecdsa verifier
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user