Merge pull request #279 from zk-passport/feat/other-ecdsa-circuits

Add support for other ecdsa curves
This commit is contained in:
turnoffthiscomputer
2025-01-07 14:48:41 +01:00
committed by GitHub
44 changed files with 497602 additions and 4948 deletions

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(160, 160, 27, 32, 7, 320, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(256, 224, 30, 32, 7, 448, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(256, 256, 28, 32, 7, 448, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(256, 256, 21, 64, 4, 448, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(256, 256, 23, 64, 6, 448, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(384, 384, 24, 64, 4, 640, 256, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(384, 384, 22, 64, 6, 640, 256, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(384, 384, 9, 64, 6, 640, 256, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(512, 512, 25, 64, 4, 768, 256, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(512, 512, 26, 64, 6, 768, 256, 20);

View File

@@ -427,7 +427,7 @@ template BigModInvOptimised(CHUNK_SIZE, CHUNK_NUMBER) {
out[i] <-- inv[i];
}
component mult = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER);
component mult = BigMultModPNonOptimised(CHUNK_SIZE, CHUNK_NUMBER);
mult.in[0] <== in;
mult.in[1] <== out;
mult.in[2] <== modulus;
@@ -919,4 +919,4 @@ template BigIsEqual(CHUNK_SIZE, CHUNK_NUMBER) {
}
}
out <== equalResults[CHUNK_NUMBER - 1];
}
}

View File

@@ -332,7 +332,7 @@ function prod_dl(n, k, a, b) {
// p is a prime
// computes a^e mod p
function mod_exp_dl(n, k, a, p, e) {
var eBits[500];
var eBits[512];
for (var i = 0; i < k; i++) {
for (var j = 0; j < n; j++) {
eBits[j + n * i] = (e[i] >> j) & 1;

View File

@@ -3,8 +3,11 @@ pragma circom 2.1.6;
include "../bigInt/bigIntOverflow.circom";
include "../bigInt/bigIntFunc.circom";
include "./powers/secp256k1pows.circom";
include "./powers/brainpoolP224r1pows.circom";
include "./powers/brainpoolP256r1pows.circom";
include "./powers/brainpoolP384r1pows.circom";
include "./powers/brainpoolP512r1pows.circom";
include "./powers/p224pows.circom";
include "./powers/p256pows.circom";
include "./powers/p384pows.circom";
include "circomlib/circuits/bitify.circom";
@@ -46,7 +49,6 @@ include "./get.circom";
// λ = (3 * x ** 2 + a) / (2 * y)
// y3 = λ * (x - x3) - y
template TangentCheck(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
assert(CHUNK_SIZE == 64);
signal input in1[2][CHUNK_NUMBER];
@@ -202,13 +204,13 @@ template EllipticCurvePrecomputePipinger(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, WIND
for (var i = 2; i < PRECOMPUTE_NUMBER; i++){
if (i % 2 == 0){
doublers[i \ 2 - 1] = EllipticCurveDoubleOptimised(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
doublers[i \ 2 - 1] = EllipticCurveDouble(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
doublers[i \ 2 - 1].in <== out[i \ 2];
doublers[i \ 2 - 1].out ==> out[i];
}
else {
adders[i \ 2 - 1] = EllipticCurveAddOptimised(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
adders[i \ 2 - 1] = EllipticCurveAdd(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
adders[i \ 2 - 1].in1 <== out[1];
adders[i \ 2 - 1].in2 <== out[i - 1];
adders[i \ 2 - 1].out ==> out[i];
@@ -712,7 +714,7 @@ template EllipticCurvePipingerMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, WINDOW_SIZ
res[0] <== precomputed[0];
for (var i = 0; i < CHUNK_NUMBER * CHUNK_SIZE; i += WINDOW_SIZE){
adders[i \ WINDOW_SIZE] = EllipticCurveAddOptimised(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
adders[i \ WINDOW_SIZE] = EllipticCurveAdd(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
bits2Num[i \ WINDOW_SIZE] = Bits2Num(WINDOW_SIZE);
for (var j = 0; j < WINDOW_SIZE; j++){
bits2Num[i \ WINDOW_SIZE].in[j] <== scalarBits[i + (WINDOW_SIZE - 1) - j];
@@ -724,7 +726,7 @@ template EllipticCurvePipingerMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, WINDOW_SIZ
if (i != 0){
for (var j = 0; j < WINDOW_SIZE; j++){
doublers[i + j - WINDOW_SIZE] = EllipticCurveDoubleOptimised(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
doublers[i + j - WINDOW_SIZE] = EllipticCurveDouble(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
if (j == 0){
for (var axis_idx = 0; axis_idx < 2; axis_idx++){
@@ -1261,7 +1263,6 @@ template EllipticCurveAddNonOptimised(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
// This chunking will be added late
// Complexity is field \ 8 - 1 additions
template EllipicCurveScalarGeneratorMultiplicationNonOptimised(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
signal input scalar[CHUNK_NUMBER];
signal output out[2][CHUNK_NUMBER];
@@ -1279,6 +1280,19 @@ template EllipicCurveScalarGeneratorMultiplicationNonOptimised(CHUNK_SIZE, CHUNK
powers = get_g_pow_stride8_table_p384(CHUNK_SIZE, CHUNK_NUMBER);
}
}
if (CHUNK_NUMBER == 7) {
if (P[0] == 2127085823 && P[1] == 2547681781 && P[2] == 2963212119 && P[3] == 1976686471 && P[4] == 706228261 && P[5] == 641951366 && P[6] == 3619763370 ){
powers = get_g_pow_stride8_table_brainpoolP224r1(CHUNK_SIZE, CHUNK_NUMBER);
}
if (P[0] == 1 && P[1] == 0 && P[2] == 0 && P[3] == 4294967295 && P[4] == 4294967295 && P[5] == 4294967295 && P[6] == 4294967295 ){
powers = get_g_pow_stride8_table_p224(CHUNK_SIZE, CHUNK_NUMBER);
}
}
if (CHUNK_NUMBER == 8) {
if (P[0] == 2930260431521597683 && P[1] == 2918894611604883077 && P[2] == 12595900938455318758 && P[3] == 9029043254863489090 && P[4] == 15448363540090652785 && P[5] == 14641358191536493070 && P[6] == 4599554755319692295 && P[7] == 12312170373589877899 ){
powers = get_g_pow_stride8_table_brainpoolP512r1(CHUNK_SIZE, CHUNK_NUMBER);
}
}
component num2bits[CHUNK_NUMBER];
for (var i = 0; i < CHUNK_NUMBER; i++){
@@ -1612,13 +1626,6 @@ template EllipicCurveScalarPrecomputeMultiplicationNonOptimised(CHUNK_SIZE, CHUN
}
}
out <== resultingPoints[parts - 2];
for (var i = 0; i < 6; i++){
log(out[0][i]);
}
for (var i = 0; i < 6; i++){
log(out[1][i]);
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1712,4 +1719,4 @@ template EllipicCurveScalarPrecomputeMultiplication(CHUNK_SIZE, CHUNK_NUMBER, A,
out <== scalarMultNonOptimised.out;
}
}
}

View File

@@ -5,9 +5,8 @@ pragma circom 2.1.6;
// Now there is only secp256k1 \ brainpoolP256r1 generator (64 4 chunking) and brainpoolP384r1
// Other curves / chunking will be added later
template EllipticCurveGetGenerator(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
assert (CHUNK_SIZE == 64);
signal output gen[2][CHUNK_NUMBER];
if (CHUNK_NUMBER == 4){
if (P[0] == 18446744069414583343 && P[1] == 18446744073709551615 && P[2] == 18446744073709551615 && P[3] == 18446744073709551615){
gen[0] <== [6481385041966929816, 188021827762530521, 6170039885052185351, 8772561819708210092];
@@ -31,9 +30,23 @@ template EllipticCurveGetGenerator(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
gen[0] <== [17259960781858189086, 16728304380777219754, 15816583608832692456, 9819997727167172579, 11720119409086381931, 2097662510161151487];
gen[1] <== [4792396531824874261, 1028586674454626577, 16256874595948243240, 7113166411453454436, 6679378719998465362, 9997460611710698148];
}
}
if (CHUNK_NUMBER == 7) {
if (P[0] == 1 && P[1] == 0 && P[2] == 0 && P[3] == 4294967295 && P[4] == 4294967295 && P[5] == 4294967295 && P[6] == 4294967295 ){
gen[0] <== [291249441, 875725014, 1455558946, 1241760211, 840143033, 1807007615, 3071151293];
gen[1] <== [2231402036, 1154843033, 1510426468, 3443750304, 1277353958, 3052872699, 3174523784];
}
if (P[0] == 2127085823 && P[1] == 2547681781 && P[2] == 2963212119 && P[3] == 1976686471 && P[4] == 706228261 && P[5] == 641951366 && P[6] == 3619763370 ){
gen[0] <== [3994206333, 1277062909, 2655838999, 2826815116, 872948658, 746478836, 227551661];
gen[1] <== [1981022925, 3399743187, 894148249, 1322101796, 617003166, 1925214831, 1487558391];
}
}
if (CHUNK_NUMBER == 8) {
if (P[0] == 2930260431521597683 && P[1] == 2918894611604883077 && P[2] == 12595900938455318758 && P[3] == 9029043254863489090 && P[4] == 15448363540090652785 && P[5] == 14641358191536493070 && P[6] == 4599554755319692295 && P[7] == 12312170373589877899 ){
gen[0] <== [10030961170254002210, 8965910700118138472, 5823550673135435103, 18391328107359425677, 12987082728901970318, 9650544882960897729, 6494527313417104019, 9344657780867258724];
gen[1] <== [8704646705537616018, 15116942582920270854, 6614182396149851054, 12888420639989254238, 11529432042984931601, 17440742611955841818, 13901133935883592445, 9069748673103213292];
}
}
}
// We can`t "if" signal in circom, so we always need to do all opertions, even we won`t use results of them
@@ -41,8 +54,6 @@ template EllipticCurveGetGenerator(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
// We will ignore result, but we still should get it, so we need to pout something anyway
// Dummy point = G * 2**256
template EllipticCurveGetDummy(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
assert (CHUNK_SIZE == 64);
signal output dummyPoint[2][CHUNK_NUMBER];
if (CHUNK_NUMBER == 4){
if (P[0] == 18446744069414583343 && P[1] == 18446744073709551615 && P[2] == 18446744073709551615 && P[3] == 18446744073709551615){
@@ -87,15 +98,26 @@ template EllipticCurveGetDummy(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
dummyPoint[1] <== [9174881270872499347, 7148726877058227897, 1584493337432922624, 1438582915076653591, 16161625210166602047, 946254366129831718];
}
}
if (CHUNK_NUMBER == 7) {
if (P[0] == 1 && P[1] == 0 && P[2] == 0 && P[3] == 4294967295 && P[4] == 4294967295 && P[5] == 4294967295 && P[6] == 4294967295 ){
dummyPoint[0] <== [2477436510, 406882550, 2884834286, 2269163287, 3636783260, 3699382582, 912817446];
dummyPoint[1] <== [582933619, 1778719645, 3780674687, 3008581200, 3586474874, 866709652, 3566930607];
}
if (P[0] == 2127085823 && P[1] == 2547681781 && P[2] == 2963212119 && P[3] == 1976686471 && P[4] == 706228261 && P[5] == 641951366 && P[6] == 3619763370 ){
dummyPoint[0] <== [1011829107, 766339764, 2646701381, 2557417204, 2772323181, 3776113163, 1766619938];
dummyPoint[1] <== [3055119978, 1933167529, 3830194223, 368418451, 674341366, 2229791193, 2172448247];
}
}
if (CHUNK_NUMBER == 8) {
if (P[0] == 2930260431521597683 && P[1] == 2918894611604883077 && P[2] == 12595900938455318758 && P[3] == 9029043254863489090 && P[4] == 15448363540090652785 && P[5] == 14641358191536493070 && P[6] == 4599554755319692295 && P[7] == 12312170373589877899 ){
dummyPoint[0] <== [14574916302597975989, 11319969548132449701, 10903266595883857697, 1994548485485214030, 8766324413095117920, 13859543515914586224, 15359012927175766703, 8888157292894416277];
dummyPoint[1] <== [15424904851015096434, 4509353341016380105, 2660624093915944643, 18108652003744254071, 16457937165138284712, 13988121693385681648, 3974402614675683080, 4273228049790294330];
}
}
}
// Get order of eliptic curve
template EllipicCurveGetOrder(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
assert (CHUNK_SIZE == 64);
signal output order[CHUNK_NUMBER];
if (CHUNK_NUMBER == 4){
if (P[0] == 18446744069414583343 && P[1] == 18446744073709551615 && P[2] == 18446744073709551615 && P[3] == 18446744073709551615){
@@ -116,4 +138,17 @@ template EllipicCurveGetOrder(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
order <== [4289733633151100261, 14932448379039367952, 2240099277684876711, 1526563086152259251, 1107163671716839903, 10140169582434348328];
}
}
if (CHUNK_NUMBER == 7) {
if (P[0] == 1 && P[1] == 0 && P[2] == 0 && P[3] == 4294967295 && P[4] == 4294967295 && P[5] == 4294967295 && P[6] == 4294967295 ){
order <== [1549543997, 333261125, 3770216510, 4294907554, 4294967295, 4294967295, 4294967295];
}
if (P[0] == 2127085823 && P[1] == 2547681781 && P[2] == 2963212119 && P[3] == 1976686471 && P[4] == 706228261 && P[5] == 641951366 && P[6] == 3619763370 ){
order <== [2779222943, 1843313827, 3507928139, 1976630168, 706228261, 641951366, 3619763370];
}
}
if (CHUNK_NUMBER == 8) {
if (P[0] == 2930260431521597683 && P[1] == 2918894611604883077 && P[2] == 12595900938455318758 && P[3] == 9029043254863489090 && P[4] == 15448363540090652785 && P[5] == 14641358191536493070 && P[6] == 4599554755319692295 && P[7] == 12312170373589877899 ){
order <== [13080589130439131241, 2139723849122306781, 4721568021488603207, 6142448377308718617, 15448363540090652784, 14641358191536493070, 4599554755319692295, 12312170373589877899];
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,22 +3,29 @@ pragma circom 2.0.0;
include "../sha2Common.circom";
include "../sha256/sha256Schedule.circom";
include "../sha256/sha256Rounds.circom";
include "@zk-email/circuits/utils/array.circom";
include "sha224InitialValue.circom";
template Sha224HashChunks(BLOCK_NUM) {
signal input in[BLOCK_NUM * 512];
template Sha224HashChunks(MAX_BLOCKS) {
signal input in[MAX_BLOCKS * 512];
signal input paddedInLength;
signal output out[224];
signal inBlockIndex;
inBlockIndex <-- (paddedInLength >> 9);
paddedInLength === inBlockIndex * 512;
signal states[BLOCK_NUM + 1][8][32];
signal states[MAX_BLOCKS + 1][8][32];
component iv = Sha224InitialValue();
iv.out ==> states[0];
component sch[BLOCK_NUM];
component rds[BLOCK_NUM];
component sch[MAX_BLOCKS];
component rds[MAX_BLOCKS];
for (var m = 0; m < BLOCK_NUM; m++) {
for (var m = 0; m < MAX_BLOCKS; m++) {
sch[m] = Sha2_224_256Shedule();
rds[m] = Sha2_224_256Rounds(64);
@@ -35,9 +42,15 @@ template Sha224HashChunks(BLOCK_NUM) {
rds[m].outHash ==> states[m + 1];
}
component arraySelectors[224];
for (var j = 0; j < 7; j++) {
for (var i = 0; i < 32; i++){
out[j * 32 + i] <== states[BLOCK_NUM][j][31 - i];
arraySelectors[j * 32 + i] = ItemAtIndex(MAX_BLOCKS + 1);
for (var k = 0; k <= MAX_BLOCKS; k++) {
arraySelectors[j * 32 + i].in[k] <== states[k][j][31 - i];
}
arraySelectors[j * 32 + i].index <== inBlockIndex;
out[j * 32 + i] <== arraySelectors[j * 32 + i].out;
}
}
}

View File

@@ -3,24 +3,29 @@ pragma circom 2.0.0;
include "../sha2Common.circom";
include "../sha512/sha512Schedule.circom";
include "../sha512/sha512Rounds.circom";
include "@zk-email/circuits/utils/array.circom";
include "sha384InitialValue.circom";
template Sha384HashChunks(BLOCK_NUM) {
signal input in[BLOCK_NUM * 1024];
template Sha384HashChunks(MAX_BLOCKS) {
signal input in[MAX_BLOCKS * 1024];
signal input paddedInLength;
signal output out[384];
signal inBlockIndex;
inBlockIndex <-- (paddedInLength >> 10);
paddedInLength === inBlockIndex * 1024;
signal states[BLOCK_NUM + 1][8][64];
signal states[MAX_BLOCKS + 1][8][64];
component iv = Sha384InitialValues();
iv.out ==> states[0];
component sch[BLOCK_NUM];
component rds[BLOCK_NUM];
component sch[MAX_BLOCKS];
component rds[MAX_BLOCKS];
for (var m = 0; m < BLOCK_NUM; m++) {
for (var m = 0; m < MAX_BLOCKS; m++) {
sch[m] = Sha2_384_512Schedule();
rds[m] = Sha2_384_512Rounds(80);
@@ -37,9 +42,15 @@ template Sha384HashChunks(BLOCK_NUM) {
rds[m].outHash ==> states[m + 1];
}
component arraySelectors[384];
for (var j = 0; j < 6; j++) {
for (var i = 0; i < 64; i++){
out[j * 64 + i] <== states[BLOCK_NUM][j][63 - i];
arraySelectors[j * 64 + i] = ItemAtIndex(MAX_BLOCKS + 1);
for (var k = 0; k <= MAX_BLOCKS; k++) {
arraySelectors[j * 64 + i].in[k] <== states[k][j][63 - i];
}
arraySelectors[j * 64 + i].index <== inBlockIndex;
out[j * 64 + i] <== arraySelectors[j * 64 + i].out;
}
}
}

View File

@@ -3,23 +3,31 @@ pragma circom 2.0.0;
include "../sha2Common.circom";
include "sha512InitialValue.circom";
include "sha512Schedule.circom";
include "@zk-email/circuits/utils/array.circom";
include "sha512Rounds.circom";
template Sha512HashChunks(BLOCK_NUM) {
signal input in[BLOCK_NUM * 1024];
template Sha512HashChunks(MAX_BLOCKS) {
signal input in[MAX_BLOCKS * 1024];
signal input paddedInLength;
signal input dummy;
dummy * dummy === 0;
signal output out[512];
signal inBlockIndex;
inBlockIndex <-- (paddedInLength >> 10);
paddedInLength === inBlockIndex * 1024;
signal states[BLOCK_NUM + 1][8][64];
signal states[MAX_BLOCKS + 1][8][64];
component iv = Sha512InitialValue();
iv.out ==> states[0];
component sch[BLOCK_NUM];
component rds[BLOCK_NUM];
component sch[MAX_BLOCKS];
component rds[MAX_BLOCKS];
for (var m = 0; m < BLOCK_NUM; m++) {
for (var m = 0; m < MAX_BLOCKS; m++) {
sch[m] = Sha2_384_512Schedule();
rds[m] = Sha2_384_512Rounds(80);
@@ -36,9 +44,15 @@ template Sha512HashChunks(BLOCK_NUM) {
rds[m].outHash ==> states[m + 1];
}
component arraySelectors[512];
for (var j = 0; j < 8; j++) {
for (var i = 0; i < 64; i++){
out[j * 64 + i] <== states[BLOCK_NUM][j][63 - i];
arraySelectors[j * 64 + i] = ItemAtIndex(MAX_BLOCKS + 1);
for (var k = 0; k <= MAX_BLOCKS; k++) {
arraySelectors[j * 64 + i].in[k] <== states[k][j][63 - i];
}
arraySelectors[j * 64 + i].index <== inBlockIndex;
out[j * 64 + i] <== arraySelectors[j * 64 + i].out;
}
}
}

View File

@@ -0,0 +1,27 @@
pragma circom 2.1.9;
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "../../sha2/sha224/sha224HashChunks.circom";
template Sha224Bytes(maxByteLength) {
signal input paddedIn[maxByteLength];
signal input paddedInLength;
signal output out[224];
component sha = Sha224HashChunks((maxByteLength * 8) \ 512);
sha.paddedInLength <== paddedInLength * 8;
component bytes[maxByteLength];
for (var i = 0; i < maxByteLength; i++) {
bytes[i] = Num2Bits(8);
bytes[i].in <== paddedIn[i];
for (var j = 0; j < 8; j++) {
sha.in[i*8+j] <== bytes[i].out[7-j];
}
}
for (var i = 0; i < 224; i++) {
out[i] <== sha.out[i];
}
}

View File

@@ -1,18 +1,16 @@
pragma circom 2.1.9;
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/bitify.circom";
include "../../other/fp.circom";
include "../../other/array.circom";
include "../../sha2/sha384/sha384_hash_bits.circom";
include "circomlib/circuits/comparators.circom";
include "../../sha2/sha384/sha384HashChunks.circom";
template Sha384Bytes(maxByteLength) {
signal input paddedIn[maxByteLength];
signal input paddedInLength;
signal output out[384];
var maxBits = maxByteLength * 8;
component sha = Sha384Dynamic(maxBits);
component sha = Sha384HashChunks((maxByteLength * 8) \ 1024);
sha.paddedInLength <== paddedInLength * 8;
component bytes[maxByteLength];
for (var i = 0; i < maxByteLength; i++) {
@@ -22,7 +20,6 @@ template Sha384Bytes(maxByteLength) {
sha.in[i*8+j] <== bytes[i].out[7-j];
}
}
sha.paddedInLength <== paddedInLength * 8;
for (var i = 0; i < 384; i++) {
out[i] <== sha.out[i];

View File

@@ -1,18 +1,16 @@
pragma circom 2.1.9;
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/bitify.circom";
include "../../other/fp.circom";
include "../../other/array.circom";
include "../../sha2/sha512/sha512_hash_bits.circom";
include "circomlib/circuits/comparators.circom";
include "../../sha2/sha512/sha512HashChunks.circom";
template Sha512Bytes(maxByteLength) {
signal input paddedIn[maxByteLength];
signal input paddedInLength;
signal output out[512];
var maxBits = maxByteLength * 8;
component sha = Sha512Dynamic(maxBits);
component sha = Sha512HashChunks((maxByteLength * 8) \ 1024);
sha.paddedInLength <== paddedInLength * 8;
component bytes[maxByteLength];
for (var i = 0; i < maxByteLength; i++) {
@@ -22,9 +20,9 @@ template Sha512Bytes(maxByteLength) {
sha.in[i*8+j] <== bytes[i].out[7-j];
}
}
sha.paddedInLength <== paddedInLength * 8;
sha.dummy <== 0;
for (var i = 0; i < 512; i++) {
out[i] <== sha.out[i];
}
}
}

View File

@@ -1,27 +1,30 @@
pragma circom 2.1.9;
include "./dynamic/sha1Bytes.circom";
include "./dynamic/sha224Bytes.circom";
include "@zk-email/circuits/lib/sha.circom";
// include "./dynamic/sha384Bytes.circom";
// include "./dynamic/sha512Bytes.circom";
include "./dynamic/sha384Bytes.circom";
include "./dynamic/sha512Bytes.circom";
template ShaBytesDynamic(hashLen, max_num_bytes) {
signal input in_padded[max_num_bytes];
template ShaBytesDynamic(hashLen, max_num_bits) {
signal input in_padded[max_num_bits];
signal input in_len_padded_bytes;
signal output hash[hashLen];
// if (hashLen == 512) {
// hash <== Sha512Bytes(max_num_bytes)(in_padded, in_len_padded_bytes);
// }
// if (hashLen == 384) {
// hash <== Sha384Bytes(max_num_bytes)(in_padded, in_len_padded_bytes);
// }
if (hashLen == 512) {
hash <== Sha512Bytes(max_num_bits)(in_padded, in_len_padded_bytes);
}
if (hashLen == 384) {
hash <== Sha384Bytes(max_num_bits)(in_padded, in_len_padded_bytes);
}
if (hashLen == 256) {
hash <== Sha256Bytes(max_num_bytes)(in_padded, in_len_padded_bytes);
hash <== Sha256Bytes(max_num_bits)(in_padded, in_len_padded_bytes);
}
if (hashLen == 224) {
hash <== Sha224Bytes(max_num_bits)(in_padded, in_len_padded_bytes);
}
if (hashLen == 160) {
hash <== Sha1Bytes(max_num_bytes)(in_padded, in_len_padded_bytes);
hash <== Sha1Bytes(max_num_bits)(in_padded, in_len_padded_bytes);
}
}

View File

@@ -16,8 +16,6 @@ include "../bigInt/bigInt.circom";
// (x1, y1) = h * s_inv * G + r * s_inv * (x, y)
// x1 === r
template verifyECDSABits(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, ALGO){
assert(CHUNK_SIZE == 64 && CHUNK_NUMBER == 4);
signal input pubkey[2][CHUNK_NUMBER];
signal input signature[2][CHUNK_NUMBER];
signal input hashed[ALGO];
@@ -47,74 +45,13 @@ template verifyECDSABits(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, ALGO){
modInv.out ==> sinv;
// (s ^ -1 mod n) * h mod n
component mult = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER);
component mult = BigMultModPNonOptimised(CHUNK_SIZE, CHUNK_NUMBER);
mult.in[0] <== sinv;
mult.in[1] <== hashedChunked;
mult.in[2] <== order;
// (s ^ -1 mod n) * r mod n
component mult2 = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER);
mult2.in[0] <== sinv;
mult2.in[1] <== signature[0];
mult2.in[2] <== order;
// h * s_inv * G
component scalarMult1 = EllipicCurveScalarGeneratorMultiplication(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
scalarMult1.scalar <== mult.out;
// r * s_inv * (x, y)
component scalarMult2 = EllipticCurvePipingerMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, 4);
scalarMult2.scalar <== mult2.out;
scalarMult2.in <== pubkey;
// (x1, y1) = h * s_inv * G + r * s_inv * (x, y)
component add = EllipticCurveAdd(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
add.in1 <== scalarMult1.out;
add.in2 <== scalarMult2.out;
// x1 === r
for (var i = 0; i < CHUNK_NUMBER; i++){
add.out[0][i] === signature[0][i];
}
}
// Use this one if yours message is chunk bigint
// pubkey[2] = [x, y] - pubkey for signature
// signature[2] = [r, s] - signature
// hashed = h - hashed message
// n is curve order
// s_inv = s ^ -1 mod n
// (x1, y1) = h * s_inv * G + r * s_inv * (x, y)
// x1 === r
template verifyECDSABigInt(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
assert(CHUNK_SIZE == 64 && CHUNK_NUMBER == 4);
signal input pubkey[2][CHUNK_NUMBER];
signal input signature[2][CHUNK_NUMBER];
signal input hashed[CHUNK_NUMBER];
component getOrder = EllipicCurveGetOrder(CHUNK_SIZE,CHUNK_NUMBER, A, B, P);
signal order[CHUNK_NUMBER];
order <== getOrder.order;
// s_inv = s ^ -1 mod n
signal sinv[CHUNK_NUMBER];
component modInv = BigModInvOptimised(CHUNK_SIZE, CHUNK_NUMBER);
modInv.in <== signature[1];
modInv.modulus <== order;
modInv.out ==> sinv;
// (s ^ -1 mod n) * h mod n
component mult = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER);
mult.in[0] <== sinv;
mult.in[1] <== hashed;
mult.in[2] <== order;
// (s ^ -1 mod n) * r mod n
component mult2 = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER);
component mult2 = BigMultModPNonOptimised(CHUNK_SIZE, CHUNK_NUMBER);
mult2.in[0] <== sinv;
mult2.in[1] <== signature[0];
mult2.in[2] <== order;

View File

@@ -1,140 +0,0 @@
pragma circom 2.1.6;
include "../ec/curve.circom";
include "../ec/get.circom";
include "../bigInt/bigInt.circom";
// Here is ecdsa signature verification
// For now, only 256 bit curves are allowed with chunking 64 4
//--------------------------------------------------------------------------------------------------------------------------------
// Use this one if you hash message in circuit (message is bits, not chunked int)!!!
// signature[2] = [r, s] - signature
// pubkey[2] = [x, y] - pubkey for signature
// hashed[ALGO] = h - hashed message by some algo (typically sha-2 256 for 256 bit curves)
// n is curve order
// s_inv = s ^ -1 mod n
// (x1, y1) = h * s_inv * G + r * s_inv * (x, y)
// x1 === r
template verifyECDSABits(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, ALGO){
assert(CHUNK_SIZE == 64 && CHUNK_NUMBER == 4);
signal input pubkey[2][CHUNK_NUMBER];
signal input signature[2][CHUNK_NUMBER];
signal input hashed[ALGO];
signal hashedChunked[CHUNK_NUMBER];
component bits2Num[CHUNK_NUMBER];
for (var i = 0; i < CHUNK_NUMBER; i++) {
bits2Num[i] = Bits2Num(CHUNK_SIZE);
for (var j = 0; j < CHUNK_SIZE; j++) {
bits2Num[i].in[CHUNK_SIZE - 1 - j] <== hashed[i * CHUNK_SIZE + j];
}
hashedChunked[CHUNK_NUMBER - 1 - i] <== bits2Num[i].out;
}
component getOrder = EllipicCurveGetOrder(CHUNK_SIZE,CHUNK_NUMBER, A, B, P);
signal order[CHUNK_NUMBER];
order <== getOrder.order;
// s_inv = s ^ -1 mod n
signal sinv[CHUNK_NUMBER];
component modInv = BigModInvOptimised(CHUNK_SIZE, CHUNK_NUMBER);
modInv.in <== signature[1];
modInv.modulus <== order;
modInv.out ==> sinv;
// (s ^ -1 mod n) * h mod n
component mult = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER);
mult.in[0] <== sinv;
mult.in[1] <== hashedChunked;
mult.in[2] <== order;
// (s ^ -1 mod n) * r mod n
component mult2 = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER);
mult2.in[0] <== sinv;
mult2.in[1] <== signature[0];
mult2.in[2] <== order;
// h * s_inv * G
component scalarMult1 = EllipicCurveScalarGeneratorMultiplication(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
scalarMult1.scalar <== mult.out;
// r * s_inv * (x, y)
component scalarMult2 = EllipticCurvePipingerMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, 4);
scalarMult2.scalar <== mult2.out;
scalarMult2.in <== pubkey;
// (x1, y1) = h * s_inv * G + r * s_inv * (x, y)
component add = EllipticCurveAdd(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
add.in1 <== scalarMult1.out;
add.in2 <== scalarMult2.out;
// x1 === r
for (var i = 0; i < CHUNK_NUMBER; i++){
add.out[0][i] === signature[0][i];
}
}
// Use this one if yours message is chunk bigint
// pubkey[2] = [x, y] - pubkey for signature
// signature[2] = [r, s] - signature
// hashed = h - hashed message
// n is curve order
// s_inv = s ^ -1 mod n
// (x1, y1) = h * s_inv * G + r * s_inv * (x, y)
// x1 === r
template verifyECDSABigInt(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
assert(CHUNK_SIZE == 64 && CHUNK_NUMBER == 4);
signal input pubkey[2][CHUNK_NUMBER];
signal input signature[2][CHUNK_NUMBER];
signal input hashed[CHUNK_NUMBER];
component getOrder = EllipicCurveGetOrder(CHUNK_SIZE,CHUNK_NUMBER, A, B, P);
signal order[CHUNK_NUMBER];
order <== getOrder.order;
// s_inv = s ^ -1 mod n
signal sinv[CHUNK_NUMBER];
component modInv = BigModInvOptimised(CHUNK_SIZE, CHUNK_NUMBER);
modInv.in <== signature[1];
modInv.modulus <== order;
modInv.out ==> sinv;
// (s ^ -1 mod n) * h mod n
component mult = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER);
mult.in[0] <== sinv;
mult.in[1] <== hashed;
mult.in[2] <== order;
// (s ^ -1 mod n) * r mod n
component mult2 = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER);
mult2.in[0] <== sinv;
mult2.in[1] <== signature[0];
mult2.in[2] <== order;
// h * s_inv * G
component scalarMult1 = EllipicCurveScalarGeneratorMultiplication(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
scalarMult1.scalar <== mult.out;
// r * s_inv * (x, y)
component scalarMult2 = EllipticCurvePipingerMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, 4);
scalarMult2.scalar <== mult2.out;
scalarMult2.in <== pubkey;
// (x1, y1) = h * s_inv * G + r * s_inv * (x, y)
component add = EllipticCurveAdd(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
add.in1 <== scalarMult1.out;
add.in2 <== scalarMult2.out;
// x1 === r
for (var i = 0; i < CHUNK_NUMBER; i++){
add.out[0][i] === signature[0][i];
}
}

View File

@@ -0,0 +1,224 @@
pragma circom 2.1.9;
include "./signatureAlgorithm.circom";
include "../circomlib/signature/ecdsa.circom";
template EcdsaVerifier(signatureAlgorithm, n, k) {
var kLengthFactor = getKLengthFactor(signatureAlgorithm);
var kScaled = k * kLengthFactor;
var HASH_LEN_BITS = getHashLength(signatureAlgorithm);
signal input signature[kScaled];
signal input pubKey[kScaled];
signal input hashParsed[HASH_LEN_BITS];
signal hash[n * k];
if (HASH_LEN_BITS >= n * k) {
for (var i = 0; i < n * k; i++) {
hash[i] <== hashParsed[i];
}
}
if (HASH_LEN_BITS < n * k) {
for (var i = n * k - 1; i >= 0; i--) {
if (i <= n * k - 1 - HASH_LEN_BITS) {
hash[i] <== 0;
} else {
hash[i] <== hashParsed[i - n * k + HASH_LEN_BITS];
}
}
}
signal signature_r[k]; // ECDSA signature component r
signal signature_s[k]; // ECDSA signature component s
signal pubKey_x[k];
signal pubKey_y[k];
for (var i = 0; i < k; i++) {
signature_r[i] <== signature[i];
signature_s[i] <== signature[i + k];
pubKey_x[i] <== pubKey[i];
pubKey_y[i] <== pubKey[i + k];
}
signal pubkey_xy[2][k] <== [pubKey_x, pubKey_y];
// verify eContentHash signature
if (signatureAlgorithm == 7 || signatureAlgorithm == 8) {
component ecdsa_verify = verifyECDSABits(n, k, [
18446744073709551612,
4294967295,
0,
18446744069414584321
],
[
4309448131093880907,
7285987128567378166,
12964664127075681980,
6540974713487397863
],
[
18446744073709551615,
4294967295,
0,
18446744069414584321
], n * k);
ecdsa_verify.pubkey <== pubkey_xy;
ecdsa_verify.signature <== [signature_r, signature_s];
ecdsa_verify.hashed <== hash;
}
if (signatureAlgorithm == 9 || signatureAlgorithm == 23) {
component ecdsa_verify = verifyECDSABits(n, k, [
4294967292,
18446744069414584320,
18446744073709551614,
18446744073709551615,
18446744073709551615,
18446744073709551615
],
[
3064076045283764975,
14291673747578343837,
221811693264799578,
1737717031765098770,
10992729701402291481,
12912154004749740004
],
[
4294967295,
18446744069414584320,
18446744073709551614,
18446744073709551615,
18446744073709551615,
18446744073709551615
], n * k);
ecdsa_verify.pubkey <== pubkey_xy;
ecdsa_verify.signature <== [signature_r, signature_s];
ecdsa_verify.hashed <== hash;
}
if (signatureAlgorithm == 21 || signatureAlgorithm == 24 || signatureAlgorithm == 25) {
component ecdsa_verify = verifyECDSABits(n, k, [
16810331318623712729,
18122579188607900780,
17219079075415130087,
9032542404991529047
],
[
7767825457231955894,
10773760575486288334,
17523706096862592191,
2800214691157789508
],
[
2311270323689771895,
7943213001558335528,
4496292894210231666,
12248480212390422972
], n * k);
ecdsa_verify.pubkey <== pubkey_xy;
ecdsa_verify.signature <== [signature_r, signature_s];
ecdsa_verify.hashed <== hash;
}
if (signatureAlgorithm == 22 || signatureAlgorithm == 26) {
component ecdsa_verify = verifyECDSABits(n, k, [
335737924824737830,
9990533504564909291,
1410020238645393679,
14032832221039175559,
4355552632119865248,
8918115475071440140
],
[
4230998357940653073,
8985869839777909140,
3352946025465340629,
3438355245973688998,
10032249017711215740,
335737924824737830
],
[
9747760000893709395,
12453481191562877553,
1347097566612230435,
1526563086152259252,
1107163671716839903,
10140169582434348328
], n * k);
ecdsa_verify.pubkey <== pubkey_xy;
ecdsa_verify.signature <== [signature_r, signature_s];
ecdsa_verify.hashed <== hash;
}
if (signatureAlgorithm == 27 || signatureAlgorithm == 28 || signatureAlgorithm == 30) {
component ecdsa_verify = verifyECDSABits(n, k, [
3402800963,
2953063001,
1310206680,
3243445073,
697828262,
2848877596,
1755702828
],
[
946618379,
1725674354,
1042363858,
2837670371,
2265387953,
3487842616,
629208636
],
[
2127085823,
2547681781,
2963212119,
1976686471,
706228261,
641951366,
3619763370
], n * k);
ecdsa_verify.pubkey <== pubkey_xy;
ecdsa_verify.signature <== [signature_r, signature_s];
ecdsa_verify.hashed <== hash;
}
if (signatureAlgorithm == 29) {
component ecdsa_verify = verifyECDSABits(n, k, [
16699818341992010954,
9156125524185237433,
733789637240866997,
3309403945136634529,
12120384836935902140,
10721906936585459216,
16299214545461923013,
8660601516620528521
],
[
2885045271355914019,
10970857440773072349,
8645948983640342119,
3166813089265986637,
10059573399531886503,
12116154835845181897,
16904370861210688858,
4465624766311842250
],
[
2930260431521597683,
2918894611604883077,
12595900938455318758,
9029043254863489090,
15448363540090652785,
14641358191536493070,
4599554755319692295,
12312170373589877899
], n * k);
ecdsa_verify.pubkey <== pubkey_xy;
ecdsa_verify.signature <== [signature_r, signature_s];
ecdsa_verify.hashed <== hash;
}
}

View File

@@ -45,7 +45,6 @@ template PassportVerifier(DG_HASH_ALGO, ECONTENT_HASH_ALGO, signatureAlgorithm,
}
signal dg1Sha[DG_HASH_ALGO] <== ShaHashBits(93 * 8, DG_HASH_ALGO)(dg1Bits);
component dg1ShaBytes[DG_HASH_ALGO_BYTES];
for (var i = 0; i < DG_HASH_ALGO_BYTES; i++) {

View File

@@ -1,62 +0,0 @@
pragma circom 2.1.9;
include "./signatureAlgorithm.circom";
include "../circomlib/signatures/ecdsa.circom";
template Secp256r1Verifier(signatureAlgorithm, n, k) {
var kLengthFactor = getKLengthFactor(signatureAlgorithm);
var kScaled = k * kLengthFactor;
var HASH_LEN_BITS = getHashLength(signatureAlgorithm);
signal input signature[kScaled];
signal input pubKey[kScaled];
signal input hashParsed[HASH_LEN_BITS];
signal hash[n * k];
for (var i = n * k - 1; i >= 0; i--) {
if (i <= n * k - 1 - HASH_LEN_BITS) {
hash[i] <== 0;
}else {
hash[i] <== hashParsed[i - n * k + HASH_LEN_BITS];
}
}
signal signature_r[k]; // ECDSA signature component r
signal signature_s[k]; // ECDSA signature component s
signal pubKey_x[k];
signal pubKey_y[k];
for (var i = 0; i < k; i++) {
signature_r[i] <== signature[i];
signature_s[i] <== signature[i + k];
pubKey_x[i] <== pubKey[i];
pubKey_y[i] <== pubKey[i + k];
}
signal pubkey_xy[2][k] <== [pubKey_x, pubKey_y];
// verify eContentHash signature
component ecdsa_verify = verifyECDSABits(n, k, [
18446744073709551612,
4294967295,
0,
18446744069414584321
],
[
4309448131093880907,
7285987128567378166,
12964664127075681980,
6540974713487397863
],
[
18446744073709551615,
4294967295,
0,
18446744069414584321
], n * k);
ecdsa_verify.pubkey <== pubkey_xy;
ecdsa_verify.signature <== [signature_r, signature_s];
ecdsa_verify.hashed <== hash;
}

View File

@@ -18,6 +18,16 @@ pragma circom 2.1.9;
17: rsapss_sha256_3_4096
18: rsapss_sha384_65537_3072
19: rsapss_sha256_65537_3072
21: ecdsa_sha256_brainpoolP256r1_256
22: ecdsa_sha384_brainpoolP384r1_384
23: ecdsa_sha256_secp384r1_384
24: ecdsa_sha384_brainpoolP256r1_256
25: ecdsa_sha512_brainpoolP256r1_256
26: ecdsa_sha512_brainpoolP384r1_384
27: ecdsa_sha1_brainpoolP224r1_224
28: ecdsa_sha256_brainpoolP224r1_224
29: ecdsa_sha512_brainpoolP512r1_512
30: ecdsa_sha224_brainpoolP224r1_224
*/
function getHashLength(signatureAlgorithm) {
@@ -72,6 +82,36 @@ function getHashLength(signatureAlgorithm) {
if (signatureAlgorithm == 20) {
return 256;
}
if (signatureAlgorithm == 21) {
return 256;
}
if (signatureAlgorithm == 22) {
return 384;
}
if (signatureAlgorithm == 23) {
return 256;
}
if (signatureAlgorithm == 24) {
return 384;
}
if (signatureAlgorithm == 25) {
return 512;
}
if (signatureAlgorithm == 26) {
return 512;
}
if (signatureAlgorithm == 27) {
return 160;
}
if (signatureAlgorithm == 28) {
return 256;
}
if (signatureAlgorithm == 29) {
return 512;
}
if (signatureAlgorithm == 30) {
return 224;
}
return 0;
}
@@ -124,6 +164,36 @@ function getKeyLength(signatureAlgorithm) {
if (signatureAlgorithm == 19) {
return 3072;
}
if (signatureAlgorithm == 21) {
return 256;
}
if (signatureAlgorithm == 22) {
return 384;
}
if (signatureAlgorithm == 23) {
return 384;
}
if (signatureAlgorithm == 24) {
return 256;
}
if (signatureAlgorithm == 25) {
return 256;
}
if (signatureAlgorithm == 26) {
return 384;
}
if (signatureAlgorithm == 27) {
return 224;
}
if (signatureAlgorithm == 28) {
return 224;
}
if (signatureAlgorithm == 29) {
return 512;
}
if (signatureAlgorithm == 30) {
return 224;
}
return 0;
}
@@ -177,6 +247,36 @@ function getKLengthFactor(signatureAlgorithm) {
if (signatureAlgorithm == 19) {
return 1;
}
if (signatureAlgorithm == 21) {
return 2;
}
if (signatureAlgorithm == 22) {
return 2;
}
if (signatureAlgorithm == 23) {
return 2;
}
if (signatureAlgorithm == 24) {
return 2;
}
if (signatureAlgorithm == 25) {
return 2;
}
if (signatureAlgorithm == 26) {
return 2;
}
if (signatureAlgorithm == 27) {
return 2;
}
if (signatureAlgorithm == 28) {
return 2;
}
if (signatureAlgorithm == 29) {
return 2;
}
if (signatureAlgorithm == 30) {
return 2;
}
return 0;
}

View File

@@ -1,12 +1,7 @@
pragma circom 2.1.9;
// include "../rsa/rsaPkcs1.circom";
// include "secp256r1Verifier.circom";
include "../circomlib/signature/rsapss/rsapss.circom";
include "secp256r1Verifier.circom";
// include "../rsapss/rsapss.circom";
// include "../rsa/rsa.circom";
// include "../circomlib/signature/rsa/verifyLargeRsaPkcs1v1_5.circom";
include "ecdsaVerifier.circom";
include "../circomlib/signature/rsa/verifyRsa3Pkcs1v1_5.circom";
include "../circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
include "@zk-email/circuits/utils/bytes.circom";
@@ -74,13 +69,22 @@ template SignatureVerifier(signatureAlgorithm, n, k) {
rsaPssShaVerification.hashed <== hash; // send the raw hash
}
if (signatureAlgorithm == 7) {
Secp256r1Verifier (signatureAlgorithm, n, k)(signature, pubKey, hash);
}
if (signatureAlgorithm == 8) {
Secp256r1Verifier (signatureAlgorithm,n,k)(signature, pubKey, hash);
}
if (signatureAlgorithm == 9) {
if (
signatureAlgorithm == 7
|| signatureAlgorithm == 8
|| signatureAlgorithm == 9
|| signatureAlgorithm == 21
|| signatureAlgorithm == 22
|| signatureAlgorithm == 23
|| signatureAlgorithm == 24
|| signatureAlgorithm == 25
|| signatureAlgorithm == 26
|| signatureAlgorithm == 27
|| signatureAlgorithm == 28
|| signatureAlgorithm == 29
|| signatureAlgorithm == 30
) {
EcdsaVerifier (signatureAlgorithm, n, k)(signature, pubKey, hash);
}
if (signatureAlgorithm == 10) {
component rsa = VerifyRsa65537Pkcs1v1_5(n, k, 256);

View File

@@ -6,7 +6,7 @@
"scripts": {
"test": "yarn ts-mocha --max-old-space-size=8192 'tests/**/*.test.ts' 'tests/*.test.ts' --exit",
"test-dsc": "yarn ts-mocha --max-old-space-size=8192 'tests/dsc.test.ts' --exit",
"test-prove": "yarn ts-mocha --max-old-space-size=8192 'tests/prove.test.ts' --exit",
"test-prove": "yarn ts-mocha --max-old-space-size=40960 'tests/prove.test.ts' --exit",
"test-rsa": "yarn ts-mocha --max-old-space-size=8192 'tests/utils/rsaPkcs1v1_5.test.ts' --exit",
"install-circuits": "cd ../common && yarn && cd ../circuits && yarn",
"format": "prettier --write .",
@@ -35,6 +35,7 @@
"circomlibjs": "^0.1.7",
"crypto": "^1.0.1",
"elliptic": "^6.5.5",
"hash.js": "^1.1.7",
"js-sha256": "^0.10.1",
"jsrsasign": "^11.1.0",
"modpow": "^1.0.0",

View File

@@ -16,7 +16,7 @@ build_circuit() {
yarn snarkjs groth16 setup build/prove/${CIRCUIT_NAME}/${CIRCUIT_NAME}.r1cs build/powersOfTau28_hez_final_${POWEROFTAU}.ptau build/prove/${CIRCUIT_NAME}/${CIRCUIT_NAME}.zkey
echo "building vkey"
yarn snarkjs zkey contribute build/prove/${CIRCUIT_NAME}/${CIRCUIT_NAME}.zkey build/prove/${CIRCUIT_NAME}/${CIRCUIT_NAME}_final.zkey -e="random text"
# yarn snarkjs zkey contribute build/prove/${CIRCUIT_NAME}/${CIRCUIT_NAME}.zkey build/prove/${CIRCUIT_NAME}/${CIRCUIT_NAME}_final.zkey -e="random text"
yarn snarkjs zkey export verificationkey build/prove/${CIRCUIT_NAME}/${CIRCUIT_NAME}_final.zkey build/prove/${CIRCUIT_NAME}/${CIRCUIT_NAME}_vkey.json
yarn snarkjs zkey export solidityverifier build/prove/${CIRCUIT_NAME}/${CIRCUIT_NAME}_final.zkey build/prove/${CIRCUIT_NAME}/Verifier_${CIRCUIT_NAME}.sol

View File

@@ -10,7 +10,6 @@ import { poseidon2 } from 'poseidon-lite';
import { SMT } from '@openpassport/zk-kit-smt';
import namejson from '../../common/ofacdata/outputs/nameSMT.json';
import { getCircuitNameFromPassportData } from '../../common/src/utils/circuitsName';
import { parsePassportData } from '../../common/src/utils/parsePassportData';
const sigAlgs = [
{
@@ -45,6 +44,14 @@ const sigAlgs = [
domainParameter: 'secp256r1',
keyLength: '256',
},
{
dgHashAlgo: 'sha256',
eContentHashAlgo: 'sha224',
sigAlg: 'ecdsa',
hashFunction: 'sha224',
domainParameter: 'brainpoolP224r1',
keyLength: '224',
},
];
const fullSigAlgs = [
@@ -136,6 +143,86 @@ const fullSigAlgs = [
domainParameter: 'secp256r1',
keyLength: '256',
},
{
dgHashAlgo: 'sha256',
eContentHashAlgo: 'sha256',
sigAlg: 'ecdsa',
hashFunction: 'sha256',
domainParameter: 'brainpoolP256r1',
keyLength: '256',
},
{
dgHashAlgo: 'sha256',
eContentHashAlgo: 'sha256',
sigAlg: 'ecdsa',
hashFunction: 'sha256',
domainParameter: 'secp384r1',
keyLength: '384',
},
{
dgHashAlgo: 'sha384',
eContentHashAlgo: 'sha384',
sigAlg: 'ecdsa',
hashFunction: 'sha384',
domainParameter: 'brainpoolP256r1',
keyLength: '256',
},
{
dgHashAlgo: 'sha384',
eContentHashAlgo: 'sha384',
sigAlg: 'ecdsa',
hashFunction: 'sha384',
domainParameter: 'brainpoolP384r1',
keyLength: '384',
},
{
dgHashAlgo: 'sha384',
eContentHashAlgo: 'sha384',
sigAlg: 'ecdsa',
hashFunction: 'sha384',
domainParameter: 'secp384r1',
keyLength: '384',
},
{
dgHashAlgo: 'sha512',
eContentHashAlgo: 'sha512',
sigAlg: 'ecdsa',
hashFunction: 'sha512',
domainParameter: 'brainpoolP256r1',
keyLength: '256',
},
{
dgHashAlgo: 'sha256',
eContentHashAlgo: 'sha224',
sigAlg: 'ecdsa',
hashFunction: 'sha224',
domainParameter: 'brainpoolP224r1',
keyLength: '224',
},
{
dgHashAlgo: 'sha256',
eContentHashAlgo: 'sha256',
sigAlg: 'ecdsa',
hashFunction: 'sha256',
domainParameter: 'brainpoolP224r1',
keyLength: '224',
},
{
dgHashAlgo: 'sha1',
eContentHashAlgo: 'sha1',
sigAlg: 'ecdsa',
hashFunction: 'sha1',
domainParameter: 'brainpoolP224r1',
keyLength: '224',
},
{
dgHashAlgo: 'sha256',
eContentHashAlgo: 'sha256',
sigAlg: 'ecdsa',
hashFunction: 'sha256',
domainParameter: 'secp256r1',
keyLength: '256',
},
];
const testSuite = process.env.FULL_TEST_SUITE === 'true' ? fullSigAlgs : sigAlgs;

File diff suppressed because it is too large Load Diff

View File

@@ -40,19 +40,21 @@ export const DEFAULT_MAJORITY = '18';
// rsa_sha256_65537_3072: 384,
// rsa_sha256_3_2048: 384,
// };
export const hashAlgos = ['sha1', 'sha256', 'sha384', 'sha512'];
export const MAX_PADDED_ECONTENT_LEN: Partial<Record<(typeof hashAlgos)[number], number>> = {
export const hashAlgos = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512'] as const;
export const MAX_PADDED_ECONTENT_LEN: Record<(typeof hashAlgos)[number], number> = {
sha1: 320,
sha224: 384,
sha256: 448,
sha384: 576,
sha512: 704,
sha384: 640,
sha512: 768,
};
export const MAX_PADDED_SIGNED_ATTR_LEN: Partial<Record<(typeof hashAlgos)[number], number>> = {
export const MAX_PADDED_SIGNED_ATTR_LEN: Record<(typeof hashAlgos)[number], number> = {
sha1: 128,
sha224: 128,
sha256: 128,
sha384: 128,
sha512: 192,
sha384: 256,
sha512: 256,
};
export const MAX_CERT_BYTES: Partial<Record<keyof typeof SignatureAlgorithmIndex, number>> = {
@@ -95,6 +97,16 @@ export enum SignatureAlgorithmIndex {
rsapss_sha256_3_4096 = 17,
rsapss_sha384_65537_3072 = 18,
rsapss_sha256_65537_3072 = 19,
ecdsa_sha256_brainpoolP256r1_256 = 21,
ecdsa_sha384_brainpoolP384r1_384 = 22,
ecdsa_sha256_secp384r1_384 = 23,
ecdsa_sha384_brainpoolP256r1_256 = 24,
ecdsa_sha512_brainpoolP256r1_256 = 25,
ecdsa_sha512_brainpoolP384r1_384 = 26,
ecdsa_sha1_brainpoolP224r1_224 = 27,
ecdsa_sha256_brainpoolP224r1_224 = 28,
ecdsa_sha512_brainpoolP512r1_512 = 29,
ecdsa_sha224_brainpoolP224r1_224 = 30,
}
export const attributeToPosition = {

View File

@@ -1244,27 +1244,228 @@ d+9Msdsovrc=
-----END CERTIFICATE-----
`;
export const mock_dsc_key_sha256_brainpoolP256r1 = `-----BEGIN EC PRIVATE KEY-----
MHgCAQEEICM/qGkSEYZJeejSAl3to/52G9Vw+GDKdvw2BA4Hq4TRoAsGCSskAwMC
CAEBB6FEA0IABCga+ftPaAL6Bljws48myO1IDRDjaBkyFR3W/esrhP2pb3poTpqd
KDjKkI9hUU1t3cllGYBP4UzL9IUhe4J7I6s=
export const mock_dsc_key_sha1_brainpoolP224r1 = `-----BEGIN EC PRIVATE KEY-----
MGwCAQEEHEtm6OSi3EClphbb0ovVMLNX6SCQ/ZpYsFTjlnqgCwYJKyQDAwIIAQEF
oTwDOgAEb8kcLsVLjpC1RWAjA/lRTHP2HVdW1ntmtfo1g2R6E6NkgLetsRXxc8Sn
CJ71v4bL9/50ksOiv+U=
-----END EC PRIVATE KEY-----
`;
export const mock_dsc_sha1_brainpoolP224r1 = `-----BEGIN CERTIFICATE-----
MIIBzTCCAX2gAwIBAgIUL2Uxhvbe1w8fdNbH+/nFp0LvkEYwCQYHKoZIzj0EATBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTI0MTIzMDA4NDQ0MVoXDTI1MTIzMDA4
NDQ0MVowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNV
BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBSMBQGByqGSM49AgEGCSskAwMC
CAEBBQM6AARvyRwuxUuOkLVFYCMD+VFMc/YdV1bWe2a1+jWDZHoTo2SAt62xFfFz
xKcInvW/hsv3/nSSw6K/5aNTMFEwHQYDVR0OBBYEFHWg+dJpv6bTRvEWrInb/XtX
XIzPMB8GA1UdIwQYMBaAFHWg+dJpv6bTRvEWrInb/XtXXIzPMA8GA1UdEwEB/wQF
MAMBAf8wCQYHKoZIzj0EAQM/ADA8Ahx0BuqVqweU/EHvq42lTIH6ku+wPMoqvUL/
jnD0AhwDAIPS8xytmOiI0MuVj3kwdnzTLdsGslSkmj8l
-----END CERTIFICATE-----
`;
export const mock_dsc_key_sha224_braipoolP224r1 = `-----BEGIN EC PRIVATE KEY-----
MGwCAQEEHD8zMUlakQzf4dhsIN/RlRKZqRRPX+y2LJj/6OWgCwYJKyQDAwIIAQEF
oTwDOgAEVhYeSwufAC+rdeIw8skbC2bwM3g7giuR+5vl0brGHgiEIaUr33msAPHz
epGlvTkSRQz+nOWMogI=
-----END EC PRIVATE KEY-----`;
export const mock_dsc_sha224_brainpoolP224r1 = `-----BEGIN CERTIFICATE-----
MIIB0DCCAX6gAwIBAgIUKS+C9XWWr12MLB1+rcVEaYGW53UwCgYIKoZIzj0EAwEw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTAxMDcwNzUxMDJaFw0yNjAxMDcw
NzUxMDJaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwUjAUBgcqhkjOPQIBBgkrJAMD
AggBAQUDOgAEVhYeSwufAC+rdeIw8skbC2bwM3g7giuR+5vl0brGHgiEIaUr33ms
APHzepGlvTkSRQz+nOWMogKjUzBRMB0GA1UdDgQWBBS7hFp/MRDFZ//5GxYHnpM+
N8mqKTAfBgNVHSMEGDAWgBS7hFp/MRDFZ//5GxYHnpM+N8mqKTAPBgNVHRMBAf8E
BTADAQH/MAoGCCqGSM49BAMBA0AAMD0CHQCT+jX3mCRjmvdXO2HKlb9faeYgKfiX
frIJV5mBAhwEqIQRW2USNItxRt1iTO69eBj/20q67UOhDgK2
-----END CERTIFICATE-----`;
export const mock_dsc_key_sha256_brainpoolP224r1 = `-----BEGIN EC PRIVATE KEY-----
MGwCAQEEHEtm6OSi3EClphbb0ovVMLNX6SCQ/ZpYsFTjlnqgCwYJKyQDAwIIAQEF
oTwDOgAEb8kcLsVLjpC1RWAjA/lRTHP2HVdW1ntmtfo1g2R6E6NkgLetsRXxc8Sn
CJ71v4bL9/50ksOiv+U=
-----END EC PRIVATE KEY-----
`;
export const mock_dsc_sha256_brainpoolP224r1 = `-----BEGIN CERTIFICATE-----
MIIB0DCCAX6gAwIBAgIUVaUBruPv+13YqSDtb28faYlca1UwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMzAxNDA2NTZaFw0yNTEyMzAx
NDA2NTZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwUjAUBgcqhkjOPQIBBgkrJAMD
AggBAQUDOgAEb8kcLsVLjpC1RWAjA/lRTHP2HVdW1ntmtfo1g2R6E6NkgLetsRXx
c8SnCJ71v4bL9/50ksOiv+WjUzBRMB0GA1UdDgQWBBR1oPnSab+m00bxFqyJ2/17
V1yMzzAfBgNVHSMEGDAWgBR1oPnSab+m00bxFqyJ2/17V1yMzzAPBgNVHRMBAf8E
BTADAQH/MAoGCCqGSM49BAMCA0AAMD0CHQCXfviMoPED3c43XbavcZkccHVwxOYq
aUpntBqzAhwqxYeED8F9yQVTF3NWcAd1kmySSE79HoCpjdTZ
-----END CERTIFICATE-----
`;
export const mock_dsc_key_sha256_brainpoolP256r1 = `-----BEGIN EC PRIVATE KEY-----
MHgCAQEEIGJigSc0XAA6G8o5znqeZyr6vM33jfVLKjIenqGZni8poAsGCSskAwMC
CAEBB6FEA0IABDu2bqyQM7+NJRN1jSaQK0DW2a99g2U6JjGGIVMq0n2gZYOKFx9E
SguAfoUpJmMXDsyPwTHlPtn/vLMfRzgbtPQ=
-----END EC PRIVATE KEY-----
`;
export const mock_dsc_sha256_brainpoolP256r1 = `-----BEGIN CERTIFICATE-----
MIICDzCCAbagAwIBAgIUcNlflnEgBabRuI8TtmhfuXeBDxAwCgYIKoZIzj0EAwIw
ZjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRUw
EwYDVQQKDAxPcmdhbml6YXRpb24xDTALBgNVBAsMBFVuaXQxEjAQBgNVBAMMCW1v
Y2tfY3NjYTAeFw0yNDEwMDMxODE2MzFaFw0yNTEwMDMxODE2MzFaMGUxCzAJBgNV
BAYTAlVTMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEVMBMGA1UECgwM
T3JnYW5pemF0aW9uMQ0wCwYDVQQLDARVbml0MREwDwYDVQQDDAhtb2NrX2RzYzBa
MBQGByqGSM49AgEGCSskAwMCCAEBBwNCAARcehJ7rf3trDknfb3agrcH08G7q0lZ
GL6fpY3beLTxeJMFF36REb8HLnOUFGw78hfPH8etWuA9H7HVZ/vB8Cd8o0IwQDAd
BgNVHQ4EFgQUQE/6d9aMviaMEi9k91hdsVguoekwHwYDVR0jBBgwFoAUXOj0kKh6
5e3xwozKdrj0y/kxpVkwCgYIKoZIzj0EAwIDRwAwRAIgfcPQcDu6hK7ad5EM1Owf
hlAwf+ljOVwK1ZhDh5lJLicCIEJdrWnH+dUOBL+NecPbLmcFVBCelST9iNCUXTKD
CLpT
MIIB4DCCAYagAwIBAgIUbHVEhdtUOw6RyVe/hvzTuRzEuR4wCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMjcxMTU3NDNaFw0yNTEyMjcx
MTU3NDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWjAUBgcqhkjOPQIBBgkrJAMD
AggBAQcDQgAEO7ZurJAzv40lE3WNJpArQNbZr32DZTomMYYhUyrSfaBlg4oXH0RK
C4B+hSkmYxcOzI/BMeU+2f+8sx9HOBu09KNTMFEwHQYDVR0OBBYEFP1eFopMfvFG
0FAMe9ufMERzT7I7MB8GA1UdIwQYMBaAFP1eFopMfvFG0FAMe9ufMERzT7I7MA8G
A1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhAKMCAoCHlvYyR9nuUXWS
Tvkpy9dRVAEaF2QmoiMtCHKnAiAe9FkZw6iO8h4GWKyeiAsvnk/tiRcLwkOQoLNc
7hTFLQ==
-----END CERTIFICATE-----
`;
export const mock_dsc_key_sha384_brainpoolP256r1 = `-----BEGIN EC PRIVATE KEY-----
MHgCAQEEIIhHbA4GKMOiNXQcXTiFlQUX2YFKz5U/Ya+vQa/YFo6foAsGCSskAwMC
CAEBB6FEA0IABKje0Lfu0ACxcGqEJc2vF6AYckbw9LaoHIKRyM6ko91AFuNhEIsx
pUF1FV+lornr3u0I7bOxL4PlOD+nZuRXGQE=
-----END EC PRIVATE KEY-----
`;
export const mock_dsc_sha384_brainpoolP256r1 = `-----BEGIN CERTIFICATE-----
MIIB3zCCAYagAwIBAgIUNxoAJFWOPOCE9KOmtQZpg4NiEzMwCgYIKoZIzj0EAwMw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMjgwNjE0MTZaFw0yNTEyMjgw
NjE0MTZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWjAUBgcqhkjOPQIBBgkrJAMD
AggBAQcDQgAEqN7Qt+7QALFwaoQlza8XoBhyRvD0tqgcgpHIzqSj3UAW42EQizGl
QXUVX6Wiueve7Qjts7Evg+U4P6dm5FcZAaNTMFEwHQYDVR0OBBYEFHB+vSzRl9Vy
UedDOcm9V+sbVYlLMB8GA1UdIwQYMBaAFHB+vSzRl9VyUedDOcm9V+sbVYlLMA8G
A1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwMDRwAwRAIgFv62dVvKdRlqCcRfQdax
iSfNPb3k7L2E0ETWSZ0KLvICIC8csz7X6VOTuVspKl1YXlBM6hOx7gTVdaGKmTR2
WtFT
-----END CERTIFICATE-----
`;
export const mock_dsc_key_sha512_brainpoolP256r1 = `-----BEGIN EC PRIVATE KEY-----
MHgCAQEEIFuQVhd8HfMpFLdTH60+UA1HfePAQkfeaGH6V9FJe5kioAsGCSskAwMC
CAEBB6FEA0IABCAx2ey4sj3xDzMbrJyjyINrSw57z98QcllbStcRHCz2YIfUUvsh
KwkgnEMAWec4iy3jeZ8yeLcoGk0fi6iCoLk=
-----END EC PRIVATE KEY-----
`;
export const mock_dsc_sha512_brainpoolP256r1 = `-----BEGIN CERTIFICATE-----
MIIB3zCCAYagAwIBAgIUQYSjqrXJx+UTzjryNw2jl8a8bUowCgYIKoZIzj0EAwQw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMjgwODU5NDFaFw0yNTEyMjgw
ODU5NDFaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWjAUBgcqhkjOPQIBBgkrJAMD
AggBAQcDQgAEIDHZ7LiyPfEPMxusnKPIg2tLDnvP3xByWVtK1xEcLPZgh9RS+yEr
CSCcQwBZ5ziLLeN5nzJ4tygaTR+LqIKguaNTMFEwHQYDVR0OBBYEFDxCzGkoR6xw
Im2XGg/24tJ+2fgyMB8GA1UdIwQYMBaAFDxCzGkoR6xwIm2XGg/24tJ+2fgyMA8G
A1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwQDRwAwRAIgPC4h2/aUem5OMnwMy42R
9j/NhYacXZGKXZv5KVBq5o4CIE/LcOS7bs7K3uNOdFxdJDCpK56YGV4H3O1paLpt
VqPW
-----END CERTIFICATE-----
`;
export const mock_dsc_key_sha256_secp384r1 = `-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDBZthN5/vhpqE/ALHj35A/pMkfSDRxFKKweTYs2IxR0eW6RJQlZhdgk
TGP7rQ4EKF6gBwYFK4EEACKhZANiAASsl16vufqKa/qdJWIEDO5no2useouKh4Zk
AdtBf3fWjDnsT3J9ulxe0Ep+QbC8010o3dGQZL5UqwzoarLGrFentQ4wTJYzLXX2
VHrLCyDjwswia1U3+I9ZYLp1TA9+88A=
-----END EC PRIVATE KEY-----
`;
export const mock_dsc_sha256_secp384r1 = `-----BEGIN CERTIFICATE-----
MIICHDCCAaKgAwIBAgIUIxGxDq5DcnphGZhSQNaAMWC5WtcwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMjgwNTMwMzlaFw0yNTEyMjgw
NTMwMzlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQA
IgNiAASsl16vufqKa/qdJWIEDO5no2useouKh4ZkAdtBf3fWjDnsT3J9ulxe0Ep+
QbC8010o3dGQZL5UqwzoarLGrFentQ4wTJYzLXX2VHrLCyDjwswia1U3+I9ZYLp1
TA9+88CjUzBRMB0GA1UdDgQWBBQuToV7daaeM2l+EdWsqXX4NP1gFjAfBgNVHSME
GDAWgBQuToV7daaeM2l+EdWsqXX4NP1gFjAPBgNVHRMBAf8EBTADAQH/MAoGCCqG
SM49BAMCA2gAMGUCMFEUPb/G0QxEiAW0d1S7njA4UPPtgugQ44PDjWhFrwEowtEv
gmDwQUgL/nKb+7GsSQIxANABnyvZSR9heu9rqqYxeW/0eGoQoDnSiZowdf7Z6fJP
aiTuTmjxvd1KKxrCkmuSDg==
-----END CERTIFICATE-----
`;
export const mock_dsc_key_sha384_brainpoolP384r1 = `-----BEGIN EC PRIVATE KEY-----
MIGoAgEBBDAAqX21j3nsvbpheKxpL3Vbj9Q5rkMqZ1LTVOpykpFezXH8R+d9tYgl
lMBGmlszFJSgCwYJKyQDAwIIAQELoWQDYgAEf0p2YN3Lru5iZ8KRhZfUthvwBa9u
SZgsKlmeBE7epzdpJvkGL3QSHO2GiF7Nv8MYEerqpwyynlAL9YK8HAqAXOoOa+rP
RvG+mFXRYyRZTMwIH5/ULI29H+tLqsRejx4x
-----END EC PRIVATE KEY-----
`;
export const mock_dsc_sha384_brainpoolP384r1 = `-----BEGIN CERTIFICATE-----
MIICHzCCAaagAwIBAgIUIWM2gNwyhyOd0Tv2h8Hm63b/s54wCgYIKoZIzj0EAwMw
RTELMAkGA1UEBhMCSU4xEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMjcwOTQzMjBaFw0yNTEyMjcw
OTQzMjBaMEUxCzAJBgNVBAYTAklOMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwejAUBgcqhkjOPQIBBgkrJAMD
AggBAQsDYgAEf0p2YN3Lru5iZ8KRhZfUthvwBa9uSZgsKlmeBE7epzdpJvkGL3QS
HO2GiF7Nv8MYEerqpwyynlAL9YK8HAqAXOoOa+rPRvG+mFXRYyRZTMwIH5/ULI29
H+tLqsRejx4xo1MwUTAdBgNVHQ4EFgQUpCaQbwuQL/GaEmjSH4oVu8zku44wHwYD
VR0jBBgwFoAUpCaQbwuQL/GaEmjSH4oVu8zku44wDwYDVR0TAQH/BAUwAwEB/zAK
BggqhkjOPQQDAwNnADBkAjArBhymHpn9modIUw0Q/t3wxyzGYO9UpuiAxJiiRWVM
SduwTA4zUXYzfQUEn50j4lQCMHbwK7l1rwHW0FlpAMG3GDFgTNUaCU2I/m3J4A/E
bKeq3jWgsSb2o7VSgneDGG70Qw==
-----END CERTIFICATE-----
`;
export const mock_dsc_key_sha512_brainpoolP384r1 = `-----BEGIN EC PRIVATE KEY-----
MIGoAgEBBDB4JkHrXVXl2oWIH04Wh0ERPrGi+oW6Gm4Qs+QMlzMlZFz/pGn9BbFo
VwHIejJ8fuWgCwYJKyQDAwIIAQELoWQDYgAEgFY8mpSYBoiXECveGnKHO/9PW96k
WT80fBf3/tz8vytQGhLzqFS4kcxSsoO9lJXnfLk+PTqKyHGX8wPAqD9MvGcD8pj1
uvEviUV7Hp99wos7JXGGdm8koJhAvfGSt6N3
-----END EC PRIVATE KEY-----
`;
export const mock_dsc_sha512_brainpoolP384r1 = `-----BEGIN CERTIFICATE-----
MIICIDCCAaagAwIBAgIUUxZNjQROjb8L3QFE3qKEAOuGA/4wCgYIKoZIzj0EAwQw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMjgxMDA3MDdaFw0yNTEyMjgx
MDA3MDdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwejAUBgcqhkjOPQIBBgkrJAMD
AggBAQsDYgAEgFY8mpSYBoiXECveGnKHO/9PW96kWT80fBf3/tz8vytQGhLzqFS4
kcxSsoO9lJXnfLk+PTqKyHGX8wPAqD9MvGcD8pj1uvEviUV7Hp99wos7JXGGdm8k
oJhAvfGSt6N3o1MwUTAdBgNVHQ4EFgQUUgkQRw5jvunoflxxAvX5Yc+ROgswHwYD
VR0jBBgwFoAUUgkQRw5jvunoflxxAvX5Yc+ROgswDwYDVR0TAQH/BAUwAwEB/zAK
BggqhkjOPQQDBANoADBlAjEAhtyXbjYqxVBT4KonoZcYciftQkRt+0DxBnPmRZ52
d67SbyA9LP/7XDTg8qw++aPyAjAFYTG7tu/EGBqWfvSCjEo0aK9ZS/eS5HZoTfs7
dzuXqOBuBj1L+HpiiBobsDhL63c=
-----END CERTIFICATE-----
`;
export const mock_dsc_key_sha512_brainpoolP512r1 = `-----BEGIN EC PRIVATE KEY-----
MIHaAgEBBEBsh1A9ArliqvxSQg7Z4u9XszaGEJTw9qPD52QSVG9qWN7zfnl4xWmD
m7ZCM00Lc2it0orK3FjymVEPr7GOcLgPoAsGCSskAwMCCAEBDaGBhQOBggAEjJkR
N4I/rAdmNOyUfmz/xAZ8rhLQlKYk8qwdQg3XrW0r9VbXTRkdnJxZLo8m/PH9AlFL
qHdloVKLJp+JkITdYWuLbDn+Y6wGUCsFLCfJR1YRByP5L0+gT4LcFlotLDmRm46B
44q5Et+aQIimslTS9KAK6VlSSswSEaG2LqzSAD0=
-----END EC PRIVATE KEY-----
`;
export const mock_dsc_sha512_brainpoolP512r1 = `-----BEGIN CERTIFICATE-----
MIICYzCCAcigAwIBAgIUAwDW2UZPk3oy12xQCOrtAi4J8dswCgYIKoZIzj0EAwQw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMzAxNDUyMTdaFw0yNTEyMzAx
NDUyMTdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZswFAYHKoZIzj0CAQYJKyQD
AwIIAQENA4GCAASMmRE3gj+sB2Y07JR+bP/EBnyuEtCUpiTyrB1CDdetbSv1VtdN
GR2cnFkujyb88f0CUUuod2WhUosmn4mQhN1ha4tsOf5jrAZQKwUsJ8lHVhEHI/kv
T6BPgtwWWi0sOZGbjoHjirkS35pAiKayVNL0oArpWVJKzBIRobYurNIAPaNTMFEw
HQYDVR0OBBYEFGNz0nQzf/S2dvSrGKeczYkAapabMB8GA1UdIwQYMBaAFGNz0nQz
f/S2dvSrGKeczYkAapabMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwQDgYgA
MIGEAkBvgsKebJL2PQOXy3KWDvb50ygqXAXItDbbqLqxE+7h7zswDiqQz/tDtDeG
tGGbBQIiYYwa1WlqaTJA+AjUpsZCAkBW+Z7PiQJE4DNms8za0bzom7u5kaHGaOGU
fRSx8q4PN04hIQfS8Rm4/1Zg8VmHIQ4kdnYC4WLQgXOmshSS8LTi
-----END CERTIFICATE-----
`;

View File

@@ -40,12 +40,31 @@ import {
mock_dsc_sha256_rsapss_65537_3072,
mock_dsc_key_rsapss_65537_4096,
mock_dsc_sha256_rsapss_65537_4096,
mock_dsc_key_sha384_brainpoolP384r1,
mock_dsc_sha384_brainpoolP384r1,
mock_dsc_key_sha256_secp384r1,
mock_dsc_sha256_secp384r1,
mock_dsc_key_sha384_brainpoolP256r1,
mock_dsc_sha384_brainpoolP256r1,
mock_dsc_key_sha512_brainpoolP256r1,
mock_dsc_sha512_brainpoolP256r1,
mock_dsc_key_sha512_brainpoolP384r1,
mock_dsc_sha512_brainpoolP384r1,
mock_dsc_key_sha1_brainpoolP224r1,
mock_dsc_sha1_brainpoolP224r1,
mock_dsc_key_sha256_brainpoolP224r1,
mock_dsc_sha256_brainpoolP224r1,
mock_dsc_key_sha512_brainpoolP512r1,
mock_dsc_sha512_brainpoolP512r1,
mock_dsc_key_sha224_braipoolP224r1,
mock_dsc_sha224_brainpoolP224r1,
} from '../constants/mockCertificates';
import { countryCodes } from '../constants/constants';
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple';
import { SignatureAlgorithm } from './types';
import { PublicKeyDetailsECDSA, PublicKeyDetailsRSAPSS } from './certificate_parsing/dataStructure';
import { getCurveForElliptic } from './certificate_parsing/curves';
import { createHash } from 'crypto';
function generateRandomBytes(length: number): number[] {
// Generate numbers between -128 and 127 to match the existing signed byte format
@@ -159,10 +178,22 @@ export function genMockPassportData(
privateKeyPem = mock_dsc_key_sha384_ecdsa;
dsc = mock_dsc_sha384_ecdsa;
break;
case 'ecdsa_sha256_secp384r1_384':
privateKeyPem = mock_dsc_key_sha256_secp384r1;
dsc = mock_dsc_sha256_secp384r1;
break;
case 'ecdsa_sha256_brainpoolP256r1_256':
privateKeyPem = mock_dsc_key_sha256_brainpoolP256r1;
dsc = mock_dsc_sha256_brainpoolP256r1;
break;
case 'ecdsa_sha384_brainpoolP256r1_256':
privateKeyPem = mock_dsc_key_sha384_brainpoolP256r1;
dsc = mock_dsc_sha384_brainpoolP256r1;
break;
case 'ecdsa_sha512_brainpoolP256r1_256':
privateKeyPem = mock_dsc_key_sha512_brainpoolP256r1;
dsc = mock_dsc_sha512_brainpoolP256r1;
break;
case 'rsa_sha256_3_2048':
privateKeyPem = mock_dsc_key_sha256_rsa_3_2048;
dsc = mock_dsc_sha256_rsa_3_2048;
@@ -179,6 +210,30 @@ export function genMockPassportData(
privateKeyPem = mock_dsc_key_rsapss_65537_4096;
dsc = mock_dsc_sha256_rsapss_65537_4096;
break;
case 'ecdsa_sha384_brainpoolP384r1_384':
privateKeyPem = mock_dsc_key_sha384_brainpoolP384r1;
dsc = mock_dsc_sha384_brainpoolP384r1;
break;
case 'ecdsa_sha512_brainpoolP384r1_384':
privateKeyPem = mock_dsc_key_sha512_brainpoolP384r1;
dsc = mock_dsc_sha512_brainpoolP384r1;
break;
case 'ecdsa_sha1_brainpoolP224r1_224':
privateKeyPem = mock_dsc_key_sha1_brainpoolP224r1;
dsc = mock_dsc_sha1_brainpoolP224r1;
break;
case 'ecdsa_sha224_brainpoolP224r1_224':
privateKeyPem = mock_dsc_key_sha224_braipoolP224r1;
dsc = mock_dsc_sha224_brainpoolP224r1;
break;
case 'ecdsa_sha256_brainpoolP224r1_224':
privateKeyPem = mock_dsc_key_sha256_brainpoolP224r1;
dsc = mock_dsc_sha256_brainpoolP224r1;
break;
case 'ecdsa_sha512_brainpoolP512r1_512':
privateKeyPem = mock_dsc_key_sha512_brainpoolP512r1;
dsc = mock_dsc_sha512_brainpoolP512r1;
break;
}
// Generate MRZ hash first
@@ -236,22 +291,16 @@ function sign(
);
const asn1Data = asn1.fromBER(privateKeyDer);
const privateKeyBuffer = (asn1Data.result.valueBlock as any).value[1].valueBlock.valueHexView;
// console.log('sig deets');
// console.log('pk', privateKeyBuffer);
// console.log('hashFUnction', hashAlgorithm);
// console.log('message', Buffer.from(eContent).toString('hex'));
const keyPair = ec.keyFromPrivate(privateKeyBuffer);
let md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
// let md = forge.md[hashAlgorithm].create();
// md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
const hasher = createHash(hashAlgorithm);
const msgHash = hasher.update(new Uint8Array(eContent)).digest('hex');
// console.log('message to sign', md.digest().toHex());
const signature = keyPair.sign(md.digest().toHex(), 'hex');
// console.log(Buffer.from(signature.toDER(), 'hex').toString('hex'));
const signature = keyPair.sign(msgHash, 'hex');
const signatureBytes = Array.from(Buffer.from(signature.toDER(), 'hex'));
// console.log('sig', JSON.stringify(signatureBytes));
return signatureBytes;
} else {
const privKey = forge.pki.privateKeyFromPem(privateKeyPem);

View File

@@ -4,7 +4,7 @@ import {
MAX_PADDED_ECONTENT_LEN,
MAX_PADDED_SIGNED_ATTR_LEN,
} from '../constants/constants';
import { assert, shaPad } from './shaPad';
import { assert, sha384_512Pad, shaPad } from './shaPad';
import { PassportData, SignatureAlgorithm } from './types';
import {
bytesToBigDecimal,
@@ -221,13 +221,25 @@ export function generateCircuitInputsProve(
);
}
console.log('signatureAlgorithmFullName', signatureAlgorithmFullName);
const [eContentPadded, eContentLen] = shaPad(
const dg1PaddingFunction =
passportMetadata.dg1HashFunction === 'sha1' ||
passportMetadata.dg1HashFunction === 'sha224' ||
passportMetadata.dg1HashFunction === 'sha256'
? shaPad
: sha384_512Pad;
const [eContentPadded, eContentLen] = dg1PaddingFunction(
new Uint8Array(eContent),
MAX_PADDED_ECONTENT_LEN[passportMetadata.dg1HashFunction]
);
const [signedAttrPadded, signedAttrPaddedLen] = shaPad(
const eContentPaddingFunction =
passportMetadata.eContentHashFunction === 'sha1' ||
passportMetadata.eContentHashFunction === 'sha224' ||
passportMetadata.eContentHashFunction === 'sha256'
? shaPad
: sha384_512Pad;
const [signedAttrPadded, signedAttrPaddedLen] = eContentPaddingFunction(
new Uint8Array(signedAttr),
MAX_PADDED_SIGNED_ATTR_LEN[passportMetadata.eContentHashFunction]
);

View File

@@ -2,10 +2,10 @@ import { PassportData } from '../../../common/src/utils/types';
import { findSubarrayIndex, formatMrz, hash } from './utils';
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple';
import {
CertificateData,
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
PublicKeyDetailsRSAPSS,
CertificateData,
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
PublicKeyDetailsRSAPSS,
} from './certificate_parsing/dataStructure';
import { getCSCAFromSKI } from './csca';
import { hashAlgos } from '../constants/constants';
@@ -14,225 +14,227 @@ import forge from 'node-forge';
import * as asn1js from 'asn1js';
import { initElliptic } from './elliptic';
import { getCurveForElliptic } from './certificate_parsing/curves';
import { createHash } from 'crypto';
export interface PassportMetadata {
dataGroups: string;
dg1HashFunction: string;
dg1HashOffset: number;
eContentSize: number;
eContentHashFunction: string;
eContentHashOffset: number;
signedAttrSize: number;
signedAttrHashFunction: string;
signatureAlgorithm: string;
signatureAlgorithmDetails: string;
curveOrExponent: string;
signatureAlgorithmBits: number;
countryCode: string;
cscaFound: boolean;
cscaHashFunction: string;
cscaSignature: string;
cscaSignatureAlgorithmDetails: string;
cscaCurveOrExponent: string;
cscaSignatureAlgorithmBits: number;
dsc: string;
dataGroups: string;
dg1HashFunction: string;
dg1HashOffset: number;
eContentSize: number;
eContentHashFunction: string;
eContentHashOffset: number;
signedAttrSize: number;
signedAttrHashFunction: string;
signatureAlgorithm: string;
signatureAlgorithmDetails: string;
curveOrExponent: string;
signatureAlgorithmBits: number;
countryCode: string;
cscaFound: boolean;
cscaHashFunction: string;
cscaSignature: string;
cscaSignatureAlgorithmDetails: string;
cscaCurveOrExponent: string;
cscaSignatureAlgorithmBits: number;
dsc: string;
}
export function findHashSizeOfEContent(eContent: number[], signedAttr: number[]) {
for (const hashFunction of hashAlgos) {
const hashValue = hash(hashFunction, eContent);
const hashOffset = findSubarrayIndex(signedAttr, hashValue);
if (hashOffset !== -1) {
return { hashFunction, offset: hashOffset };
}
for (const hashFunction of hashAlgos) {
const hashValue = hash(hashFunction, eContent);
const hashOffset = findSubarrayIndex(signedAttr, hashValue);
if (hashOffset !== -1) {
return { hashFunction, offset: hashOffset };
}
return { hashFunction: 'unknown', offset: -1 };
}
return { hashFunction: 'unknown', offset: -1 };
}
export function findDG1HashInEContent(
mrz: string,
eContent: number[]
mrz: string,
eContent: number[]
): { hash: number[]; hashFunction: string; offset: number } | null {
const formattedMrz = formatMrz(mrz);
const formattedMrz = formatMrz(mrz);
for (const hashFunction of hashAlgos) {
const hashValue = hash(hashFunction, formattedMrz);
const normalizedHash = hashValue.map((byte) => (byte > 127 ? byte - 256 : byte));
const hashOffset = findSubarrayIndex(eContent, normalizedHash);
for (const hashFunction of hashAlgos) {
const hashValue = hash(hashFunction, formattedMrz);
const normalizedHash = hashValue.map((byte) => (byte > 127 ? byte - 256 : byte));
const hashOffset = findSubarrayIndex(eContent, normalizedHash);
if (hashOffset !== -1) {
return { hash: hashValue, hashFunction, offset: hashOffset };
}
if (hashOffset !== -1) {
return { hash: hashValue, hashFunction, offset: hashOffset };
}
return null;
}
return null;
}
export function getCountryCodeFromMrz(mrz: string): string {
return mrz.substring(2, 5);
return mrz.substring(2, 5);
}
export function getCurveOrExponent(certData: CertificateData): string {
if (certData.signatureAlgorithm === 'rsapss' || certData.signatureAlgorithm === 'rsa') {
return (certData.publicKeyDetails as PublicKeyDetailsRSA).exponent;
}
return (certData.publicKeyDetails as PublicKeyDetailsECDSA).curve;
if (certData.signatureAlgorithm === 'rsapss' || certData.signatureAlgorithm === 'rsa') {
return (certData.publicKeyDetails as PublicKeyDetailsRSA).exponent;
}
return (certData.publicKeyDetails as PublicKeyDetailsECDSA).curve;
}
export function getSimplePublicKeyDetails(certData: CertificateData): string {
interface SimplePublicKeyDetails {
exponent?: string;
curve?: string;
hashAlgorithm?: string;
saltLength?: string;
interface SimplePublicKeyDetails {
exponent?: string;
curve?: string;
hashAlgorithm?: string;
saltLength?: string;
}
const simplePublicKeyDetails: SimplePublicKeyDetails = {};
if (certData.signatureAlgorithm === 'rsapss' || certData.signatureAlgorithm === 'rsa') {
simplePublicKeyDetails.exponent = (certData.publicKeyDetails as PublicKeyDetailsRSA).exponent;
if (certData.signatureAlgorithm === 'rsapss') {
simplePublicKeyDetails.hashAlgorithm = (
certData.publicKeyDetails as PublicKeyDetailsRSAPSS
).hashAlgorithm;
simplePublicKeyDetails.saltLength = (
certData.publicKeyDetails as PublicKeyDetailsRSAPSS
).saltLength;
}
const simplePublicKeyDetails: SimplePublicKeyDetails = {};
if (certData.signatureAlgorithm === 'rsapss' || certData.signatureAlgorithm === 'rsa') {
simplePublicKeyDetails.exponent = (certData.publicKeyDetails as PublicKeyDetailsRSA).exponent;
if (certData.signatureAlgorithm === 'rsapss') {
simplePublicKeyDetails.hashAlgorithm = (
certData.publicKeyDetails as PublicKeyDetailsRSAPSS
).hashAlgorithm;
simplePublicKeyDetails.saltLength = (
certData.publicKeyDetails as PublicKeyDetailsRSAPSS
).saltLength;
}
} else if (certData.signatureAlgorithm === 'ecdsa') {
simplePublicKeyDetails.curve = (certData.publicKeyDetails as PublicKeyDetailsECDSA).curve;
}
return JSON.stringify(simplePublicKeyDetails);
} else if (certData.signatureAlgorithm === 'ecdsa') {
simplePublicKeyDetails.curve = (certData.publicKeyDetails as PublicKeyDetailsECDSA).curve;
}
return JSON.stringify(simplePublicKeyDetails);
}
export function verifySignature(passportData: PassportData, hashAlgorithm: string): boolean {
const elliptic = initElliptic();
const { dsc, signedAttr, encryptedDigest } = passportData;
const { signatureAlgorithm, publicKeyDetails } = parseCertificateSimple(dsc);
const elliptic = initElliptic();
const { dsc, signedAttr, encryptedDigest } = passportData;
const { signatureAlgorithm, publicKeyDetails } = parseCertificateSimple(dsc);
if (signatureAlgorithm === 'ecdsa') {
const certBuffer = Buffer.from(
dsc.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64'
);
const asn1Data = asn1js.fromBER(certBuffer);
const cert = new Certificate({ schema: asn1Data.result });
const publicKeyInfo = cert.subjectPublicKeyInfo;
const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const curveForElliptic = getCurveForElliptic((publicKeyDetails as PublicKeyDetailsECDSA).curve);
const ec = new elliptic.ec(curveForElliptic);
if (signatureAlgorithm === 'ecdsa') {
const certBuffer = Buffer.from(
dsc.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64'
);
const asn1Data = asn1js.fromBER(certBuffer);
const cert = new Certificate({ schema: asn1Data.result });
const publicKeyInfo = cert.subjectPublicKeyInfo;
const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const curveForElliptic = getCurveForElliptic((publicKeyDetails as PublicKeyDetailsECDSA).curve);
const ec = new elliptic.ec(curveForElliptic);
const key = ec.keyFromPublic(publicKeyBuffer);
const md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const msgHash = md.digest().toHex();
const signature_crypto = Buffer.from(encryptedDigest).toString('hex');
const key = ec.keyFromPublic(publicKeyBuffer);
const hasher = createHash(hashAlgorithm);
const msgHash = hasher.update(new Uint8Array(signedAttr)).digest('hex');
const signature_crypto = Buffer.from(encryptedDigest).toString('hex');
return key.verify(msgHash, signature_crypto);
} else {
const cert = forge.pki.certificateFromPem(dsc);
const publicKey = cert.publicKey as forge.pki.rsa.PublicKey;
return key.verify(msgHash, signature_crypto);
} else {
const cert = forge.pki.certificateFromPem(dsc);
const publicKey = cert.publicKey as forge.pki.rsa.PublicKey;
try {
const md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const signature = Buffer.from(encryptedDigest).toString('binary');
const signature = Buffer.from(encryptedDigest).toString('binary');
if (signatureAlgorithm === 'rsapss') {
try {
const pss = forge.pss.create({
md: forge.md[hashAlgorithm].create(),
mgf: forge.mgf.mgf1.create(forge.md[hashAlgorithm].create()),
saltLength: parseInt((publicKeyDetails as PublicKeyDetailsRSAPSS).saltLength),
});
return publicKey.verify(md.digest().bytes(), signature, pss);
} catch (error) {
return false;
}
} else {
return publicKey.verify(md.digest().bytes(), signature);
if (signatureAlgorithm === 'rsapss') {
try {
const pss = forge.pss.create({
md: forge.md[hashAlgorithm].create(),
mgf: forge.mgf.mgf1.create(forge.md[hashAlgorithm].create()),
saltLength: parseInt((publicKeyDetails as PublicKeyDetailsRSAPSS).saltLength),
});
return publicKey.verify(md.digest().bytes(), signature, pss);
} catch (error) {
return false;
}
} else {
return publicKey.verify(md.digest().bytes(), signature);
}
} catch (err) {
return false;
}
}
}
export function brutforceHashAlgorithm(passportData: PassportData): any {
for (const hashFunction of hashAlgos) {
if (verifySignature(passportData, hashFunction)) {
return hashFunction;
}
for (const hashFunction of hashAlgos) {
if (verifySignature(passportData, hashFunction)) {
return hashFunction;
}
return null;
}
return null;
}
export function parsePassportData(passportData: PassportData): PassportMetadata {
const dg1HashInfo = passportData.mrz
? findDG1HashInEContent(passportData.mrz, passportData.eContent)
: null;
const dg1HashInfo = passportData.mrz
? findDG1HashInEContent(passportData.mrz, passportData.eContent)
: null;
const dg1HashFunction = dg1HashInfo?.hashFunction || 'unknown';
const dg1HashOffset = dg1HashInfo?.offset || 0;
const dg1HashFunction = dg1HashInfo?.hashFunction || 'unknown';
const dg1HashOffset = dg1HashInfo?.offset || 0;
const { hashFunction: eContentHashFunction, offset: eContentHashOffset } = findHashSizeOfEContent(
passportData.eContent,
passportData.signedAttr
);
const { hashFunction: eContentHashFunction, offset: eContentHashOffset } = findHashSizeOfEContent(
passportData.eContent,
passportData.signedAttr
);
const signatureHashAlgo = brutforceHashAlgorithm(passportData);
const signatureHashAlgo = brutforceHashAlgorithm(passportData);
let parsedDsc = null;
let parsedCsca = null;
let csca = null;
let dscSignature = 'unknown';
let dscSignatureAlgorithmDetails = 'unknown';
let dscSignatureAlgorithmBits = 0;
let cscaHashFunction = 'unknown';
let cscaSignature = 'unknown';
let cscaSignatureAlgorithmDetails = 'unknown';
let cscaSignatureAlgorithmBits = 0;
let parsedDsc = null;
let parsedCsca = null;
let csca = null;
let dscSignature = 'unknown';
let dscSignatureAlgorithmDetails = 'unknown';
let dscSignatureAlgorithmBits = 0;
let cscaHashFunction = 'unknown';
let cscaSignature = 'unknown';
let cscaSignatureAlgorithmDetails = 'unknown';
let cscaSignatureAlgorithmBits = 0;
if (passportData.dsc) {
parsedDsc = parseCertificateSimple(passportData.dsc);
dscSignature = parsedDsc.signatureAlgorithm;
dscSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedDsc);
dscSignatureAlgorithmBits = parseInt(parsedDsc.publicKeyDetails?.bits || '0');
if (passportData.dsc) {
parsedDsc = parseCertificateSimple(passportData.dsc);
dscSignature = parsedDsc.signatureAlgorithm;
dscSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedDsc);
dscSignatureAlgorithmBits = parseInt(parsedDsc.publicKeyDetails?.bits || '0');
if (parsedDsc.authorityKeyIdentifier) {
try {
csca = getCSCAFromSKI(parsedDsc.authorityKeyIdentifier, true);
if (csca) {
parsedCsca = parseCertificateSimple(csca);
cscaHashFunction = parsedCsca.hashAlgorithm;
cscaSignature = parsedCsca.signatureAlgorithm;
cscaSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedCsca);
cscaSignatureAlgorithmBits = parseInt(parsedCsca.publicKeyDetails?.bits || '0');
}
} catch (error) {
}
if (parsedDsc.authorityKeyIdentifier) {
try {
csca = getCSCAFromSKI(parsedDsc.authorityKeyIdentifier, true);
if (csca) {
parsedCsca = parseCertificateSimple(csca);
cscaHashFunction = parsedCsca.hashAlgorithm;
cscaSignature = parsedCsca.signatureAlgorithm;
cscaSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedCsca);
cscaSignatureAlgorithmBits = parseInt(parsedCsca.publicKeyDetails?.bits || '0');
}
} catch (error) {}
}
}
return {
dataGroups:
passportData.dgPresents
?.toString()
.split(',')
.map((item) => item.replace('DG', ''))
.join(',') || 'None',
dg1HashFunction,
dg1HashOffset,
eContentSize: passportData.eContent?.length || 0,
eContentHashFunction,
eContentHashOffset,
signedAttrSize: passportData.signedAttr?.length || 0,
signedAttrHashFunction: signatureHashAlgo,
signatureAlgorithm: dscSignature,
signatureAlgorithmDetails: dscSignatureAlgorithmDetails,
curveOrExponent: parsedDsc ? getCurveOrExponent(parsedDsc) : 'unknown',
signatureAlgorithmBits: dscSignatureAlgorithmBits,
countryCode: passportData.mrz ? getCountryCodeFromMrz(passportData.mrz) : 'unknown',
cscaFound: !!csca,
cscaHashFunction,
cscaSignature,
cscaSignatureAlgorithmDetails,
cscaCurveOrExponent: parsedCsca ? getCurveOrExponent(parsedCsca) : 'unknown',
cscaSignatureAlgorithmBits: cscaSignatureAlgorithmBits,
dsc: passportData.dsc,
};
return {
dataGroups:
passportData.dgPresents
?.toString()
.split(',')
.map((item) => item.replace('DG', ''))
.join(',') || 'None',
dg1HashFunction,
dg1HashOffset,
eContentSize: passportData.eContent?.length || 0,
eContentHashFunction,
eContentHashOffset,
signedAttrSize: passportData.signedAttr?.length || 0,
signedAttrHashFunction: signatureHashAlgo,
signatureAlgorithm: dscSignature,
signatureAlgorithmDetails: dscSignatureAlgorithmDetails,
curveOrExponent: parsedDsc ? getCurveOrExponent(parsedDsc) : 'unknown',
signatureAlgorithmBits: dscSignatureAlgorithmBits,
countryCode: passportData.mrz ? getCountryCodeFromMrz(passportData.mrz) : 'unknown',
cscaFound: !!csca,
cscaHashFunction,
cscaSignature,
cscaSignatureAlgorithmDetails,
cscaCurveOrExponent: parsedCsca ? getCurveOrExponent(parsedCsca) : 'unknown',
cscaSignatureAlgorithmBits: cscaSignatureAlgorithmBits,
dsc: passportData.dsc,
};
}

View File

@@ -23,12 +23,21 @@ export type SignatureAlgorithm =
| 'ecdsa_sha256_secp256r1_256'
| 'ecdsa_sha1_secp256r1_256'
| 'ecdsa_sha384_secp384r1_384'
| 'ecdsa_sha256_secp384r1_384'
| 'ecdsa_sha384_brainpoolP256r1_256'
| 'ecdsa_sha512_brainpoolP256r1_256'
| 'ecdsa_sha256_brainpoolP256r1_256'
| 'rsa_sha256_3_2048'
| 'rsa_sha256_65537_3072'
| 'rsa_sha256_65537_4096'
| 'rsa_sha512_65537_4096'
| 'rsapss_sha256_65537_3072'
| 'ecdsa_sha384_brainpoolP384r1_384'
| 'ecdsa_sha512_brainpoolP384r1_384'
| 'ecdsa_sha1_brainpoolP224r1_224'
| 'ecdsa_sha224_brainpoolP224r1_224'
| 'ecdsa_sha256_brainpoolP224r1_224'
| 'ecdsa_sha512_brainpoolP512r1_512'
| 'rsapss_sha256_65537_4096';
export type Proof = {

View File

@@ -1,7 +1,7 @@
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
import { sha256 } from 'js-sha256';
import { sha224, sha256 } from 'js-sha256';
import { sha1 } from 'js-sha1';
import { sha384, sha512_256 } from 'js-sha512';
import { sha384, sha512 } from 'js-sha512';
import { SMT } from '@openpassport/zk-kit-smt';
import forge from 'node-forge';
import {
@@ -37,7 +37,19 @@ export function getNAndK(sigAlg: SignatureAlgorithm) {
}
if (sigAlg.startsWith('ecdsa_')) {
return { n: n_dsc_ecdsa, k: k_dsc_ecdsa }; // 256/32 = 8
if (sigAlg.endsWith('224')) {
return { n: 32, k: 7 };
} else if (sigAlg.endsWith('256')) {
return { n: n_dsc_ecdsa, k: 4 };
} else if (sigAlg.endsWith('384')) {
return { n: n_dsc_ecdsa, k: 6 };
} else if (sigAlg.endsWith('512')) {
return { n: n_dsc_ecdsa, k: 8 };
} else if (sigAlg.endsWith('521')) {
return { n: n_dsc_ecdsa, k: 16 };
} else {
throw new Error('invalid key size');
}
}
if (sigAlg.startsWith('rsapss_')) {
@@ -236,6 +248,9 @@ export function hash(hashFunction: string, bytesArray: number[]): number[] {
case 'sha1':
hashResult = sha1(unsignedBytesArray);
break;
case 'sha224':
hashResult = sha224(unsignedBytesArray);
break;
case 'sha256':
hashResult = sha256(unsignedBytesArray);
break;
@@ -243,7 +258,7 @@ export function hash(hashFunction: string, bytesArray: number[]): number[] {
hashResult = sha384(unsignedBytesArray);
break;
case 'sha512':
hashResult = sha512_256(unsignedBytesArray);
hashResult = sha512(unsignedBytesArray);
break;
default:
console.log('\x1b[31m%s\x1b[0m', `${hashFunction} not found in hash`); // Log in red
@@ -311,6 +326,8 @@ export function getHashLen(hashFunction: string) {
switch (hashFunction) {
case 'sha1':
return 20;
case 'sha224':
return 28;
case 'sha256':
return 32;
case 'sha384':

4
yarn.lock Normal file
View File

@@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1