mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
Merge branch 'dev' of github.com:zk-passport/proof-of-passport into dev
This commit is contained in:
17
common/.prettierrc
Normal file
17
common/.prettierrc
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"singleQuote": true,
|
||||
"quoteProps": "as-needed",
|
||||
"jsxSingleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": false,
|
||||
"arrowParens": "always",
|
||||
"proseWrap": "preserve",
|
||||
"htmlWhitespaceSensitivity": "css",
|
||||
"endOfLine": "lf",
|
||||
"embeddedLanguageFormatting": "auto",
|
||||
"singleAttributePerLine": false
|
||||
}
|
||||
136
common/scripts/passportData/sha1_ecdsa.ts
Normal file
136
common/scripts/passportData/sha1_ecdsa.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import assert from 'assert';
|
||||
import { PassportData } from '../../../common/src/utils/types';
|
||||
import {
|
||||
hash,
|
||||
assembleEContent,
|
||||
formatAndConcatenateDataHashes,
|
||||
formatMrz,
|
||||
arraysAreEqual,
|
||||
findSubarrayIndex,
|
||||
} from '../../../common/src/utils/utils';
|
||||
import * as forge from 'node-forge';
|
||||
import { writeFileSync } from 'fs';
|
||||
import elliptic from 'elliptic';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
const sampleMRZ =
|
||||
'P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02';
|
||||
const sampleDataHashes = [
|
||||
[
|
||||
2,
|
||||
[
|
||||
-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128,
|
||||
-8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38,
|
||||
],
|
||||
],
|
||||
[
|
||||
3,
|
||||
[
|
||||
0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6, 36,
|
||||
21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82,
|
||||
],
|
||||
],
|
||||
[
|
||||
11,
|
||||
[
|
||||
-120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0,
|
||||
60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124,
|
||||
],
|
||||
],
|
||||
[
|
||||
12,
|
||||
[
|
||||
41, -22, 106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42,
|
||||
53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114,
|
||||
],
|
||||
],
|
||||
[
|
||||
13,
|
||||
[
|
||||
91, -34, -46, -63, 62, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85,
|
||||
-15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18, 38,
|
||||
],
|
||||
],
|
||||
[
|
||||
14,
|
||||
[
|
||||
76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59,
|
||||
-100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
|
||||
],
|
||||
],
|
||||
] as [number, number[]][];
|
||||
const signatureAlgorithm = 'ecdsa-with-SHA1';
|
||||
const hashLen = 20;
|
||||
|
||||
export function genMockPassportData_sha1WithECDSA(): PassportData {
|
||||
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
|
||||
sampleDataHashes.unshift([1, mrzHash]);
|
||||
const concatenatedDataHashes = formatAndConcatenateDataHashes(
|
||||
[[1, mrzHash], ...sampleDataHashes],
|
||||
hashLen,
|
||||
33
|
||||
);
|
||||
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
|
||||
|
||||
const ec = new elliptic.ec('p256');
|
||||
const keyPair = ec.genKeyPair();
|
||||
const pubKey = keyPair.getPublic();
|
||||
|
||||
const md = forge.md.sha1.create();
|
||||
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
|
||||
const signature = keyPair.sign(md.digest().toHex(), 'hex');
|
||||
const signatureBytes = Array.from(Buffer.from(signature.toDER(), 'hex'));
|
||||
|
||||
const Qx = pubKey.getX().toString(16);
|
||||
const Qy = pubKey.getY().toString(16);
|
||||
|
||||
return {
|
||||
mrz: sampleMRZ,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
pubKey: {
|
||||
publicKeyQ: `(${Qx},${Qy},1,fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc)`,
|
||||
},
|
||||
dataGroupHashes: concatenatedDataHashes,
|
||||
eContent: eContent,
|
||||
encryptedDigest: signatureBytes,
|
||||
photoBase64: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3...',
|
||||
};
|
||||
}
|
||||
|
||||
function verify(passportData: PassportData): boolean {
|
||||
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } =
|
||||
passportData;
|
||||
const formattedMrz = formatMrz(mrz);
|
||||
const mrzHash = hash(signatureAlgorithm, formattedMrz);
|
||||
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash);
|
||||
console.log('dg1HashOffset', dg1HashOffset);
|
||||
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
|
||||
|
||||
const concatHash = hash(signatureAlgorithm, dataGroupHashes);
|
||||
assert(
|
||||
arraysAreEqual(concatHash, eContent.slice(eContent.length - concatHash.length)),
|
||||
'concatHash is not at the right place in eContent'
|
||||
);
|
||||
|
||||
const cleanPublicKeyQ = pubKey.publicKeyQ.replace(/[()]/g, '').split(',');
|
||||
const Qx = cleanPublicKeyQ[0];
|
||||
const Qy = cleanPublicKeyQ[1];
|
||||
|
||||
const ec = new elliptic.ec('p256');
|
||||
const key = ec.keyFromPublic({ x: Qx, y: Qy }, 'hex');
|
||||
|
||||
const messageBuffer = Buffer.from(eContent);
|
||||
const msgHash = crypto.createHash('sha1').update(messageBuffer).digest();
|
||||
|
||||
const signature = Buffer.from(encryptedDigest).toString('hex');
|
||||
|
||||
const isValid = key.verify(msgHash, signature);
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
const mockPassportData = genMockPassportData_sha1WithECDSA();
|
||||
console.log('Passport Data:', JSON.stringify(mockPassportData, null, 2));
|
||||
console.log('Signature valid:', verify(mockPassportData));
|
||||
|
||||
writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2));
|
||||
136
common/scripts/passportData/sha256_ecdsa.ts
Normal file
136
common/scripts/passportData/sha256_ecdsa.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import assert from 'assert';
|
||||
import { PassportData } from '../../../common/src/utils/types';
|
||||
import {
|
||||
hash,
|
||||
assembleEContent,
|
||||
formatAndConcatenateDataHashes,
|
||||
formatMrz,
|
||||
arraysAreEqual,
|
||||
findSubarrayIndex,
|
||||
} from '../../../common/src/utils/utils';
|
||||
import * as forge from 'node-forge';
|
||||
import { writeFileSync } from 'fs';
|
||||
import elliptic from 'elliptic';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
const sampleMRZ =
|
||||
'P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02';
|
||||
const sampleDataHashes = [
|
||||
[
|
||||
2,
|
||||
[
|
||||
-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128,
|
||||
-8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38,
|
||||
],
|
||||
],
|
||||
[
|
||||
3,
|
||||
[
|
||||
0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6, 36,
|
||||
21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82,
|
||||
],
|
||||
],
|
||||
[
|
||||
11,
|
||||
[
|
||||
-120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0,
|
||||
60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124,
|
||||
],
|
||||
],
|
||||
[
|
||||
12,
|
||||
[
|
||||
41, -22, 106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42,
|
||||
53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114,
|
||||
],
|
||||
],
|
||||
[
|
||||
13,
|
||||
[
|
||||
91, -34, -46, -63, 62, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85,
|
||||
-15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18, 38,
|
||||
],
|
||||
],
|
||||
[
|
||||
14,
|
||||
[
|
||||
76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59,
|
||||
-100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
|
||||
],
|
||||
],
|
||||
] as [number, number[]][];
|
||||
const signatureAlgorithm = 'ecdsa-with-SHA256';
|
||||
const hashLen = 32;
|
||||
|
||||
export function genMockPassportData_sha256WithECDSA(): PassportData {
|
||||
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
|
||||
sampleDataHashes.unshift([1, mrzHash]);
|
||||
const concatenatedDataHashes = formatAndConcatenateDataHashes(
|
||||
[[1, mrzHash], ...sampleDataHashes],
|
||||
hashLen,
|
||||
33
|
||||
);
|
||||
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
|
||||
|
||||
const ec = new elliptic.ec('p256');
|
||||
const keyPair = ec.genKeyPair();
|
||||
const pubKey = keyPair.getPublic();
|
||||
|
||||
const md = forge.md.sha256.create();
|
||||
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
|
||||
const signature = keyPair.sign(md.digest().toHex(), 'hex');
|
||||
const signatureBytes = Array.from(Buffer.from(signature.toDER(), 'hex'));
|
||||
|
||||
const Qx = pubKey.getX().toString(16);
|
||||
const Qy = pubKey.getY().toString(16);
|
||||
|
||||
return {
|
||||
mrz: sampleMRZ,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
pubKey: {
|
||||
publicKeyQ: `(${Qx},${Qy},1,fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc)`,
|
||||
},
|
||||
dataGroupHashes: concatenatedDataHashes,
|
||||
eContent: eContent,
|
||||
encryptedDigest: signatureBytes,
|
||||
photoBase64: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3...',
|
||||
};
|
||||
}
|
||||
|
||||
function verify(passportData: PassportData): boolean {
|
||||
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } =
|
||||
passportData;
|
||||
const formattedMrz = formatMrz(mrz);
|
||||
const mrzHash = hash(signatureAlgorithm, formattedMrz);
|
||||
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash);
|
||||
console.log('dg1HashOffset', dg1HashOffset);
|
||||
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
|
||||
|
||||
const concatHash = hash(signatureAlgorithm, dataGroupHashes);
|
||||
assert(
|
||||
arraysAreEqual(concatHash, eContent.slice(eContent.length - concatHash.length)),
|
||||
'concatHash is not at the right place in eContent'
|
||||
);
|
||||
|
||||
const cleanPublicKeyQ = pubKey.publicKeyQ.replace(/[()]/g, '').split(',');
|
||||
const Qx = cleanPublicKeyQ[0];
|
||||
const Qy = cleanPublicKeyQ[1];
|
||||
|
||||
const ec = new elliptic.ec('p256');
|
||||
const key = ec.keyFromPublic({ x: Qx, y: Qy }, 'hex');
|
||||
|
||||
const messageBuffer = Buffer.from(eContent);
|
||||
const msgHash = crypto.createHash('sha256').update(messageBuffer).digest();
|
||||
|
||||
const signature = Buffer.from(encryptedDigest).toString('hex');
|
||||
|
||||
const isValid = key.verify(msgHash, signature);
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
const mockPassportData = genMockPassportData_sha256WithECDSA();
|
||||
console.log('Passport Data:', JSON.stringify(mockPassportData, null, 2));
|
||||
console.log('Signature valid:', verify(mockPassportData));
|
||||
|
||||
writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2));
|
||||
136
common/scripts/passportData/sha512_ecdsa.ts
Normal file
136
common/scripts/passportData/sha512_ecdsa.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import assert from 'assert';
|
||||
import { PassportData } from '../../../common/src/utils/types';
|
||||
import {
|
||||
hash,
|
||||
assembleEContent,
|
||||
formatAndConcatenateDataHashes,
|
||||
formatMrz,
|
||||
arraysAreEqual,
|
||||
findSubarrayIndex,
|
||||
} from '../../../common/src/utils/utils';
|
||||
import * as forge from 'node-forge';
|
||||
import { writeFileSync } from 'fs';
|
||||
import elliptic from 'elliptic';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
const sampleMRZ =
|
||||
'P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02';
|
||||
const sampleDataHashes = [
|
||||
[
|
||||
2,
|
||||
[
|
||||
-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128,
|
||||
-8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38,
|
||||
],
|
||||
],
|
||||
[
|
||||
3,
|
||||
[
|
||||
0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6, 36,
|
||||
21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82,
|
||||
],
|
||||
],
|
||||
[
|
||||
11,
|
||||
[
|
||||
-120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0,
|
||||
60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124,
|
||||
],
|
||||
],
|
||||
[
|
||||
12,
|
||||
[
|
||||
41, -22, 106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42,
|
||||
53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114,
|
||||
],
|
||||
],
|
||||
[
|
||||
13,
|
||||
[
|
||||
91, -34, -46, -63, 62, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85,
|
||||
-15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18, 38,
|
||||
],
|
||||
],
|
||||
[
|
||||
14,
|
||||
[
|
||||
76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59,
|
||||
-100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
|
||||
],
|
||||
],
|
||||
] as [number, number[]][];
|
||||
const signatureAlgorithm = 'ecdsa-with-SHA512';
|
||||
const hashLen = 64;
|
||||
|
||||
export function genMockPassportData_sha512WithECDSA(): PassportData {
|
||||
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
|
||||
sampleDataHashes.unshift([1, mrzHash]);
|
||||
const concatenatedDataHashes = formatAndConcatenateDataHashes(
|
||||
[[1, mrzHash], ...sampleDataHashes],
|
||||
hashLen,
|
||||
33
|
||||
);
|
||||
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
|
||||
|
||||
const ec = new elliptic.ec('p256');
|
||||
const keyPair = ec.genKeyPair();
|
||||
const pubKey = keyPair.getPublic();
|
||||
|
||||
const md = forge.md.sha512.create();
|
||||
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
|
||||
const signature = keyPair.sign(md.digest().toHex(), 'hex');
|
||||
const signatureBytes = Array.from(Buffer.from(signature.toDER(), 'hex'));
|
||||
|
||||
const Qx = pubKey.getX().toString(16);
|
||||
const Qy = pubKey.getY().toString(16);
|
||||
|
||||
return {
|
||||
mrz: sampleMRZ,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
pubKey: {
|
||||
publicKeyQ: `(${Qx},${Qy},1,fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc)`,
|
||||
},
|
||||
dataGroupHashes: concatenatedDataHashes,
|
||||
eContent: eContent,
|
||||
encryptedDigest: signatureBytes,
|
||||
photoBase64: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3...',
|
||||
};
|
||||
}
|
||||
|
||||
function verify(passportData: PassportData): boolean {
|
||||
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } =
|
||||
passportData;
|
||||
const formattedMrz = formatMrz(mrz);
|
||||
const mrzHash = hash(signatureAlgorithm, formattedMrz);
|
||||
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash);
|
||||
console.log('dg1HashOffset', dg1HashOffset);
|
||||
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
|
||||
|
||||
const concatHash = hash(signatureAlgorithm, dataGroupHashes);
|
||||
assert(
|
||||
arraysAreEqual(concatHash, eContent.slice(eContent.length - concatHash.length)),
|
||||
'concatHash is not at the right place in eContent'
|
||||
);
|
||||
|
||||
const cleanPublicKeyQ = pubKey.publicKeyQ.replace(/[()]/g, '').split(',');
|
||||
const Qx = cleanPublicKeyQ[0];
|
||||
const Qy = cleanPublicKeyQ[1];
|
||||
|
||||
const ec = new elliptic.ec('p256');
|
||||
const key = ec.keyFromPublic({ x: Qx, y: Qy }, 'hex');
|
||||
|
||||
const messageBuffer = Buffer.from(eContent);
|
||||
const msgHash = crypto.createHash('sha512').update(messageBuffer).digest();
|
||||
|
||||
const signature = Buffer.from(encryptedDigest).toString('hex');
|
||||
|
||||
const isValid = key.verify(msgHash, signature);
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
const mockPassportData = genMockPassportData_sha512WithECDSA();
|
||||
console.log('Passport Data:', JSON.stringify(mockPassportData, null, 2));
|
||||
console.log('Signature valid:', verify(mockPassportData));
|
||||
|
||||
writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2));
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
||||
import { MAX_DATAHASHES_LEN, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE } from "../constants/constants";
|
||||
import { assert, shaPad } from "./shaPad";
|
||||
import { PassportData } from "./types";
|
||||
import { MAX_DATAHASHES_LEN, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE } from '../constants/constants';
|
||||
import { assert, shaPad } from './shaPad';
|
||||
import { PassportData } from './types';
|
||||
import {
|
||||
<<<<<<< HEAD
|
||||
arraysAreEqual, bytesToBigDecimal, formatMrz, hash, splitToWords,
|
||||
toUnsignedByte, getHashLen, getCurrentDateYYMMDD,
|
||||
generateMerkleProof, generateSMTProof,
|
||||
@@ -17,6 +18,26 @@ import {
|
||||
mockPassportDatas,
|
||||
} from "../constants/mockPassportData";
|
||||
import { SMT } from "@ashpect/smt"
|
||||
=======
|
||||
arraysAreEqual,
|
||||
bytesToBigDecimal,
|
||||
formatMrz,
|
||||
hash,
|
||||
splitToWords,
|
||||
toUnsignedByte,
|
||||
getHashLen,
|
||||
getCurrentDateYYMMDD,
|
||||
generateMerkleProof,
|
||||
findSubarrayIndex,
|
||||
hexToDecimal,
|
||||
} from './utils';
|
||||
import { LeanIMT } from '@zk-kit/lean-imt';
|
||||
import { getLeaf } from './pubkeyTree';
|
||||
import { poseidon6 } from 'poseidon-lite';
|
||||
import { packBytes } from '../utils/utils';
|
||||
import { getCSCAModulusMerkleTree } from './csca';
|
||||
import { mockPassportDatas } from '../constants/mockPassportData';
|
||||
>>>>>>> ce89661e8145b933ceb235af66f0c12cee7c0242
|
||||
|
||||
export function generateCircuitInputsRegister(
|
||||
secret: string,
|
||||
@@ -27,7 +48,8 @@ export function generateCircuitInputsRegister(
|
||||
k_dsc: number,
|
||||
mocks: PassportData[] = mockPassportDatas
|
||||
) {
|
||||
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
|
||||
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } =
|
||||
passportData;
|
||||
|
||||
const tree = getCSCAModulusMerkleTree();
|
||||
|
||||
@@ -37,11 +59,15 @@ export function generateCircuitInputsRegister(
|
||||
}
|
||||
}
|
||||
|
||||
if (![
|
||||
"sha256WithRSAEncryption",
|
||||
"sha1WithRSAEncryption",
|
||||
"sha256WithRSASSAPSS"
|
||||
].includes(signatureAlgorithm)) {
|
||||
if (
|
||||
![
|
||||
'sha256WithRSAEncryption',
|
||||
'sha1WithRSAEncryption',
|
||||
'sha256WithRSASSAPSS',
|
||||
'ecdsa-with-SHA1',
|
||||
'ecdsa-with-SHA256',
|
||||
].includes(signatureAlgorithm)
|
||||
) {
|
||||
console.error(`${signatureAlgorithm} has not been implemented.`);
|
||||
throw new Error(`${signatureAlgorithm} has not been implemented.`);
|
||||
}
|
||||
@@ -50,7 +76,7 @@ export function generateCircuitInputsRegister(
|
||||
const formattedMrz = formatMrz(mrz);
|
||||
const mrzHash = hash(signatureAlgorithm, formattedMrz);
|
||||
|
||||
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
|
||||
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash);
|
||||
console.log('dg1HashOffset', dg1HashOffset);
|
||||
|
||||
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
|
||||
@@ -58,30 +84,31 @@ export function generateCircuitInputsRegister(
|
||||
const concatHash = hash(signatureAlgorithm, dataGroupHashes);
|
||||
|
||||
assert(
|
||||
arraysAreEqual(
|
||||
concatHash,
|
||||
eContent.slice(eContent.length - hashLen)
|
||||
),
|
||||
arraysAreEqual(concatHash, eContent.slice(eContent.length - hashLen)),
|
||||
'concatHash is not at the right place in eContent'
|
||||
);
|
||||
|
||||
// const leaf = getLeaf({
|
||||
// signatureAlgorithm: signatureAlgorithm,
|
||||
// ...pubKey,
|
||||
// }).toString();
|
||||
const leaf = getLeaf({
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
...pubKey,
|
||||
}).toString();
|
||||
|
||||
// const index = tree.indexOf(leaf);
|
||||
// // console.log(`Index of pubkey in the registry: ${index}`);
|
||||
// if (index === -1) {
|
||||
// throw new Error("Your public key was not found in the registry");
|
||||
// }
|
||||
const index = tree.indexOf(leaf);
|
||||
// console.log(`Index of pubkey in the registry: ${index}`);
|
||||
if (index === -1) {
|
||||
throw new Error('Your public key was not found in the registry');
|
||||
}
|
||||
|
||||
// const proof = tree.createProof(index);
|
||||
// console.log("verifyProof", tree.verifyProof(proof));
|
||||
const proof = tree.createProof(index);
|
||||
console.log('verifyProof', tree.verifyProof(proof));
|
||||
|
||||
if (dataGroupHashes.length > MAX_DATAHASHES_LEN) {
|
||||
console.error(`Data hashes too long (${dataGroupHashes.length} bytes). Max length is ${MAX_DATAHASHES_LEN} bytes.`);
|
||||
throw new Error(`This length of datagroups (${dataGroupHashes.length} bytes) is currently unsupported. Please contact us so we add support!`);
|
||||
console.error(
|
||||
`Data hashes too long (${dataGroupHashes.length} bytes). Max length is ${MAX_DATAHASHES_LEN} bytes.`
|
||||
);
|
||||
throw new Error(
|
||||
`This length of datagroups (${dataGroupHashes.length} bytes) is currently unsupported. Please contact us so we add support!`
|
||||
);
|
||||
}
|
||||
|
||||
const [messagePadded, messagePaddedLen] = shaPad(
|
||||
@@ -90,25 +117,41 @@ export function generateCircuitInputsRegister(
|
||||
MAX_DATAHASHES_LEN
|
||||
);
|
||||
|
||||
return {
|
||||
secret: [secret],
|
||||
mrz: formattedMrz.map(byte => String(byte)),
|
||||
dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits
|
||||
econtent: Array.from(messagePadded).map((x) => x.toString()),
|
||||
datahashes_padded_length: [messagePaddedLen.toString()],
|
||||
signed_attributes: eContent.map(toUnsignedByte).map(byte => String(byte)),
|
||||
signature: splitToWords(
|
||||
BigInt(bytesToBigDecimal(passportData.encryptedDigest)),
|
||||
BigInt(n_dsc),
|
||||
BigInt(k_dsc)
|
||||
),
|
||||
dsc_modulus: splitToWords(
|
||||
let dsc_modulus: any;
|
||||
let signature: any;
|
||||
|
||||
if (
|
||||
signatureAlgorithm === 'ecdsa-with-SHA1' ||
|
||||
signatureAlgorithm === 'ecdsa-with-SHA256' ||
|
||||
signatureAlgorithm === 'ecdsa-with-SHA512' ||
|
||||
signatureAlgorithm === 'ecdsa-with-SHA384'
|
||||
) {
|
||||
const curve_params = pubKey.publicKeyQ.replace(/[()]/g, '').split(',');
|
||||
dsc_modulus = [curve_params[0], curve_params[1]]; // ! TODO REFACTOR SPLIT HERE WHAT IF WORKS
|
||||
signature = passportData.encryptedDigest;
|
||||
} else {
|
||||
dsc_modulus = splitToWords(
|
||||
BigInt(passportData.pubKey.modulus as string),
|
||||
BigInt(n_dsc),
|
||||
BigInt(k_dsc)
|
||||
),
|
||||
);
|
||||
signature = splitToWords(
|
||||
BigInt(bytesToBigDecimal(passportData.encryptedDigest)),
|
||||
BigInt(n_dsc),
|
||||
BigInt(k_dsc)
|
||||
);
|
||||
}
|
||||
return {
|
||||
secret: [secret],
|
||||
mrz: formattedMrz.map((byte) => String(byte)),
|
||||
dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits
|
||||
econtent: Array.from(messagePadded).map((x) => x.toString()),
|
||||
datahashes_padded_length: [messagePaddedLen.toString()],
|
||||
signed_attributes: eContent.map(toUnsignedByte).map((byte) => String(byte)),
|
||||
signature: signature,
|
||||
dsc_modulus: dsc_modulus,
|
||||
attestation_id: [attestation_id],
|
||||
dsc_secret: [dscSecret]
|
||||
dsc_secret: [dscSecret],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -120,7 +163,7 @@ export function generateCircuitInputsDisclose(
|
||||
majority: string[],
|
||||
bitmap: string[],
|
||||
scope: string,
|
||||
user_identifier: string,
|
||||
user_identifier: string
|
||||
) {
|
||||
const pubkey_leaf = getLeaf({
|
||||
signatureAlgorithm: passportData.signatureAlgorithm,
|
||||
@@ -136,27 +179,32 @@ export function generateCircuitInputsDisclose(
|
||||
pubkey_leaf,
|
||||
mrz_bytes[0],
|
||||
mrz_bytes[1],
|
||||
mrz_bytes[2]
|
||||
mrz_bytes[2],
|
||||
]);
|
||||
|
||||
//console.log('commitment', commitment.toString());
|
||||
|
||||
const index = findIndexInTree(merkletree, commitment);
|
||||
const { merkleProofSiblings, merkleProofIndices, depthForThisOne } = generateMerkleProof(merkletree, index, PUBKEY_TREE_DEPTH)
|
||||
|
||||
const { merkleProofSiblings, merkleProofIndices, depthForThisOne } = generateMerkleProof(
|
||||
merkletree,
|
||||
index,
|
||||
PUBKEY_TREE_DEPTH
|
||||
);
|
||||
|
||||
return {
|
||||
secret: [secret],
|
||||
attestation_id: [attestation_id],
|
||||
pubkey_leaf: [pubkey_leaf.toString()],
|
||||
mrz: formattedMrz.map(byte => String(byte)),
|
||||
mrz: formattedMrz.map((byte) => String(byte)),
|
||||
merkle_root: [merkletree.root.toString()],
|
||||
merkletree_size: [BigInt(depthForThisOne).toString()],
|
||||
path: merkleProofIndices.map(index => BigInt(index).toString()),
|
||||
siblings: merkleProofSiblings.map(index => BigInt(index).toString()),
|
||||
path: merkleProofIndices.map((index) => BigInt(index).toString()),
|
||||
siblings: merkleProofSiblings.map((index) => BigInt(index).toString()),
|
||||
bitmap: bitmap,
|
||||
scope: [scope],
|
||||
current_date: getCurrentDateYYMMDD().map(datePart => BigInt(datePart).toString()),
|
||||
majority: majority.map(char => BigInt(char.charCodeAt(0)).toString()),
|
||||
current_date: getCurrentDateYYMMDD().map((datePart) => BigInt(datePart).toString()),
|
||||
majority: majority.map((char) => BigInt(char.charCodeAt(0)).toString()),
|
||||
user_identifier: [user_identifier],
|
||||
};
|
||||
}
|
||||
@@ -213,9 +261,9 @@ export function findIndexInTree(tree: LeanIMT, commitment: bigint): number {
|
||||
index = tree.indexOf(commitment.toString() as unknown as bigint);
|
||||
}
|
||||
if (index === -1) {
|
||||
throw new Error("This commitment was not found in the tree");
|
||||
throw new Error('This commitment was not found in the tree');
|
||||
} else {
|
||||
// console.log(`Index of commitment in the registry: ${index}`);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,75 +1,96 @@
|
||||
import { poseidon10, poseidon2, poseidon8 } from "poseidon-lite"
|
||||
import { SignatureAlgorithm, PUBKEY_TREE_DEPTH } from "../constants/constants";
|
||||
import { IMT } from '@zk-kit/imt'
|
||||
import { splitToWords } from "./utils";
|
||||
import { formatSigAlgNameForCircuit } from "./utils";
|
||||
import { toStandardName } from "./formatNames";
|
||||
import { poseidon10, poseidon2, poseidon3, poseidon5, poseidon6, poseidon8 } from 'poseidon-lite';
|
||||
import { SignatureAlgorithm, PUBKEY_TREE_DEPTH } from '../constants/constants';
|
||||
import { IMT } from '@zk-kit/imt';
|
||||
import { BigintToArray, hexToDecimal, splitToWords } from './utils';
|
||||
import { formatSigAlgNameForCircuit } from './utils';
|
||||
import { toStandardName } from './formatNames';
|
||||
|
||||
export function buildPubkeyTree(pubkeys: any[]) {
|
||||
let leaves: bigint[] = []
|
||||
let leaves: bigint[] = [];
|
||||
let startTime = performance.now();
|
||||
|
||||
for (let i = 0; i < pubkeys.length; i++) {
|
||||
const pubkey = pubkeys[i]
|
||||
const pubkey = pubkeys[i];
|
||||
|
||||
if (i % 3000 === 0 && i !== 0) {
|
||||
console.log('Processing pubkey number', i, "over", pubkeys.length);
|
||||
console.log('Processing pubkey number', i, 'over', pubkeys.length);
|
||||
}
|
||||
|
||||
const leaf = getLeaf(pubkey, i)
|
||||
const leaf = getLeaf(pubkey, i);
|
||||
|
||||
if (!leaf) {
|
||||
// console.log('no leaf for this weird signature:', i, formatSigAlgNameForCircuit(pubkey.signatureAlgorithm, pubkey.exponent))
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
leaves.push(leaf)
|
||||
leaves.push(leaf);
|
||||
}
|
||||
|
||||
const tree = new IMT(poseidon2, PUBKEY_TREE_DEPTH, 0, 2, leaves)
|
||||
console.log('pubkey tree built in', performance.now() - startTime, 'ms')
|
||||
const tree = new IMT(poseidon2, PUBKEY_TREE_DEPTH, 0, 2, leaves);
|
||||
console.log('pubkey tree built in', performance.now() - startTime, 'ms');
|
||||
|
||||
return tree
|
||||
return tree;
|
||||
}
|
||||
|
||||
export function getLeaf(pubkey: any, i?: number): bigint {
|
||||
if (!pubkey?.modulus && pubkey?.pubKey?.modulus) {
|
||||
pubkey.modulus = pubkey.pubKey.modulus
|
||||
pubkey.exponent = pubkey.pubKey.exponent
|
||||
pubkey.modulus = pubkey.pubKey.modulus;
|
||||
pubkey.exponent = pubkey.pubKey.exponent;
|
||||
}
|
||||
if (!pubkey?.publicKeyQ && pubkey?.pubKey?.publicKeyQ) {
|
||||
pubkey.publicKeyQ = pubkey.pubKey.publicKeyQ
|
||||
pubkey.publicKeyQ = pubkey.pubKey.publicKeyQ;
|
||||
}
|
||||
const sigAlgFormatted = toStandardName(pubkey.signatureAlgorithm)
|
||||
const sigAlgFormattedForCircuit = formatSigAlgNameForCircuit(sigAlgFormatted, pubkey.exponent)
|
||||
|
||||
const sigAlgFormatted = toStandardName(pubkey.signatureAlgorithm);
|
||||
const sigAlgFormattedForCircuit = formatSigAlgNameForCircuit(sigAlgFormatted, pubkey.exponent);
|
||||
if (
|
||||
sigAlgFormattedForCircuit === "sha256WithRSAEncryption_65537"
|
||||
|| sigAlgFormattedForCircuit === "sha256WithRSAEncryption_3"
|
||||
|| sigAlgFormattedForCircuit === "sha1WithRSAEncryption_65537"
|
||||
|| sigAlgFormattedForCircuit === "sha256WithRSASSAPSS_65537"
|
||||
|| sigAlgFormattedForCircuit === "sha256WithRSASSAPSS_3"
|
||||
|| sigAlgFormattedForCircuit === "sha512WithRSAEncryption_65537"
|
||||
sigAlgFormattedForCircuit === 'sha256WithRSAEncryption_65537' ||
|
||||
sigAlgFormattedForCircuit === 'sha256WithRSAEncryption_3' ||
|
||||
sigAlgFormattedForCircuit === 'sha1WithRSAEncryption_65537' ||
|
||||
sigAlgFormattedForCircuit === 'sha256WithRSASSAPSS_65537' ||
|
||||
sigAlgFormattedForCircuit === 'sha256WithRSASSAPSS_3' ||
|
||||
sigAlgFormattedForCircuit === 'sha512WithRSAEncryption_65537'
|
||||
) {
|
||||
const pubkeyChunked = splitToWords(BigInt(pubkey.modulus), BigInt(230), BigInt(9));
|
||||
const leaf = poseidon10([SignatureAlgorithm[sigAlgFormattedForCircuit], ...pubkeyChunked])
|
||||
const leaf = poseidon10([SignatureAlgorithm[sigAlgFormattedForCircuit], ...pubkeyChunked]);
|
||||
try {
|
||||
|
||||
return leaf
|
||||
return leaf;
|
||||
} catch (err) {
|
||||
console.log('err', err, i, sigAlgFormattedForCircuit, pubkey)
|
||||
console.log('err', err, i, sigAlgFormattedForCircuit, pubkey);
|
||||
}
|
||||
} else if (
|
||||
sigAlgFormattedForCircuit === "ecdsa_with_SHA1"
|
||||
|| sigAlgFormattedForCircuit === "ecdsa_with_SHA224"
|
||||
|| sigAlgFormattedForCircuit === "ecdsa_with_SHA384"
|
||||
|| sigAlgFormattedForCircuit === "ecdsa_with_SHA256"
|
||||
|| sigAlgFormattedForCircuit === "ecdsa_with_SHA512"
|
||||
sigAlgFormattedForCircuit === 'ecdsa_with_SHA1' ||
|
||||
sigAlgFormattedForCircuit === 'ecdsa_with_SHA224' ||
|
||||
sigAlgFormattedForCircuit === 'ecdsa_with_SHA384' ||
|
||||
sigAlgFormattedForCircuit === 'ecdsa_with_SHA256' ||
|
||||
sigAlgFormattedForCircuit === 'ecdsa_with_SHA512'
|
||||
) {
|
||||
try {
|
||||
// this will be replaced by just X and Y or pubkey in publicKeyQ
|
||||
return poseidon8([SignatureAlgorithm[sigAlgFormattedForCircuit], pubkey.pub, pubkey.prime, pubkey.a, pubkey.b, pubkey.generator, pubkey.order, pubkey.cofactor])
|
||||
if (!pubkey.publicKeyQ) {
|
||||
throw new Error('publicKeyQ is undefined');
|
||||
}
|
||||
|
||||
const [x, y, a, p] = pubkey.publicKeyQ.replace(/[()]/g, '').split(',');
|
||||
|
||||
if (!x || !y) {
|
||||
throw new Error('Invalid publicKeyQ format');
|
||||
}
|
||||
|
||||
let qx = BigintToArray(43, 6, BigInt(hexToDecimal(x)));
|
||||
let qy = BigintToArray(43, 6, BigInt(hexToDecimal(y)));
|
||||
|
||||
let poseidon_hasher_dsc_modules_x = poseidon6(qx);
|
||||
let poseidon_hasher_dsc_modules_y = poseidon6(qy);
|
||||
|
||||
return poseidon3([
|
||||
SignatureAlgorithm[sigAlgFormattedForCircuit],
|
||||
poseidon_hasher_dsc_modules_x, // pub.x
|
||||
poseidon_hasher_dsc_modules_y, // pub.y
|
||||
// pubkey.b ? pubkey.b : BigInt(0), // null then 0
|
||||
// pubkey.generator ? pubkey.generator : BigInt(0), // null then 0
|
||||
// pubkey.order ? pubkey.order : BigInt(0), // null then 0
|
||||
// pubkey.cofactor ? pubkey.cofactor : BigInt(0), // null then 0
|
||||
]);
|
||||
} catch (err) {
|
||||
console.log('err', err, i, sigAlgFormattedForCircuit, pubkey)
|
||||
console.log('err', err, i, sigAlgFormattedForCircuit, pubkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@ import { sha1 } from 'js-sha1';
|
||||
import { sha384 } from 'js-sha512';
|
||||
import { SMT } from '@ashpect/smt';
|
||||
import { poseidon3 } from 'poseidon-lite';
|
||||
import forge from 'node-forge';
|
||||
|
||||
export function formatMrz(mrz: string) {
|
||||
const mrzCharcodes = [...mrz].map(char => char.charCodeAt(0));
|
||||
const mrzCharcodes = [...mrz].map((char) => char.charCodeAt(0));
|
||||
|
||||
mrzCharcodes.unshift(88); // the length of the mrz data
|
||||
mrzCharcodes.unshift(95, 31); // the MRZ_INFO_TAG
|
||||
@@ -39,9 +40,10 @@ export function formatAndConcatenateDataHashes(
|
||||
dg1HashOffset: number
|
||||
) {
|
||||
// concatenating dataHashes :
|
||||
let concat: number[] = []
|
||||
let concat: number[] = [];
|
||||
|
||||
const startingSequence = Array.from({length: dg1HashOffset},
|
||||
const startingSequence = Array.from(
|
||||
{ length: dg1HashOffset },
|
||||
() => Math.floor(Math.random() * 256) - 128
|
||||
);
|
||||
|
||||
@@ -71,7 +73,7 @@ export function formatAndConcatenateDataHashes(
|
||||
// 96, -122, 72, 1, 101, 3, 4, 2, 1,
|
||||
// // NULL tag + SEQUENCE + length (117 bytes)
|
||||
// 5, 0, 48, 117,
|
||||
|
||||
|
||||
// SHA384withECDSA (index of mrzhash is 33)
|
||||
// // SEQUENCE + long form indicator + length (313 bytes)
|
||||
// 48, -126, 1, 57,
|
||||
@@ -89,12 +91,12 @@ export function formatAndConcatenateDataHashes(
|
||||
|
||||
// console.log(`startingSequence`, startingSequence.map(byte => (byte < 0 ? byte + 256 : byte).toString(16).padStart(2, '0')).join(''));
|
||||
|
||||
concat.push(...startingSequence)
|
||||
concat.push(...startingSequence);
|
||||
|
||||
for (const dataHash of dataHashes) {
|
||||
// console.log(`dataHash ${dataHash[0]}`, dataHash[1].map(byte => (byte < 0 ? byte + 256 : byte).toString(16).padStart(2, '0')).join(''));
|
||||
|
||||
concat.push(...dataHash[1])
|
||||
concat.push(...dataHash[1]);
|
||||
// concat.push(...[48, hashLen + 5, 2, 1, dataHash[0], 4, hashLen, ...dataHash[1]])
|
||||
// 48, 37, 2, 1, 1, 4, 32,
|
||||
// 48, 53, 2, 1, 1, 4, 48,
|
||||
@@ -103,9 +105,7 @@ export function formatAndConcatenateDataHashes(
|
||||
return concat;
|
||||
}
|
||||
|
||||
export function assembleEContent(
|
||||
messageDigest: number[],
|
||||
) {
|
||||
export function assembleEContent(messageDigest: number[]) {
|
||||
const constructedEContent = [];
|
||||
|
||||
// Detailed description is in private file r&d.ts for now
|
||||
@@ -113,22 +113,16 @@ export function assembleEContent(
|
||||
constructedEContent.push(...[49, 102]);
|
||||
|
||||
// 1.2.840.113549.1.9.3 is RFC_3369_CONTENT_TYPE_OID
|
||||
constructedEContent.push(
|
||||
...[48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3],
|
||||
);
|
||||
constructedEContent.push(...[48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3]);
|
||||
// 2.23.136.1.1.1 is ldsSecurityObject
|
||||
constructedEContent.push(...[49, 8, 6, 6, 103, -127, 8, 1, 1, 1]);
|
||||
|
||||
// 1.2.840.113549.1.9.5 is signing-time
|
||||
constructedEContent.push(
|
||||
...[48, 28, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 5],
|
||||
);
|
||||
constructedEContent.push(...[48, 28, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 5]);
|
||||
// mock time of signature
|
||||
constructedEContent.push(...[49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90]);
|
||||
// 1.2.840.113549.1.9.4 is RFC_3369_MESSAGE_DIGEST_OID
|
||||
constructedEContent.push(
|
||||
...[48, 47, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 4],
|
||||
);
|
||||
constructedEContent.push(...[48, 47, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 4]);
|
||||
// TAG and length of the message digest
|
||||
constructedEContent.push(...[49, 34, 4, 32]);
|
||||
|
||||
@@ -141,10 +135,7 @@ export function toUnsigned(byte: number) {
|
||||
}
|
||||
|
||||
export function arraysAreEqual(array1: number[], array2: number[]) {
|
||||
return (
|
||||
array1.length === array2.length &&
|
||||
array1.every((value, index) => value === array2[index])
|
||||
);
|
||||
return array1.length === array2.length && array1.every((value, index) => value === array2[index]);
|
||||
}
|
||||
|
||||
export function toSigned(byte: number) {
|
||||
@@ -152,29 +143,23 @@ export function toSigned(byte: number) {
|
||||
}
|
||||
|
||||
export const toBinaryString = (byte: any) => {
|
||||
const binary = (parseInt(byte, 10) & 0xFF).toString(2).padStart(8, '0');
|
||||
const binary = (parseInt(byte, 10) & 0xff).toString(2).padStart(8, '0');
|
||||
return binary;
|
||||
};
|
||||
|
||||
export function splitToWords(
|
||||
number: bigint,
|
||||
wordsize: bigint,
|
||||
numberElement: bigint
|
||||
) {
|
||||
let t = number
|
||||
const words: string[] = []
|
||||
export function splitToWords(number: bigint, wordsize: bigint, numberElement: bigint) {
|
||||
let t = number;
|
||||
const words: string[] = [];
|
||||
for (let i = BigInt(0); i < numberElement; ++i) {
|
||||
const baseTwo = BigInt(2)
|
||||
const baseTwo = BigInt(2);
|
||||
|
||||
words.push(`${t % BigInt(Math.pow(Number(baseTwo), Number(wordsize)))}`)
|
||||
t = BigInt(t / BigInt(Math.pow(Number(BigInt(2)), Number(wordsize))))
|
||||
words.push(`${t % BigInt(Math.pow(Number(baseTwo), Number(wordsize)))}`);
|
||||
t = BigInt(t / BigInt(Math.pow(Number(BigInt(2)), Number(wordsize))));
|
||||
}
|
||||
if (!(t == BigInt(0))) {
|
||||
throw `Number ${number} does not fit in ${(
|
||||
wordsize * numberElement
|
||||
).toString()} bits`
|
||||
throw `Number ${number} does not fit in ${(wordsize * numberElement).toString()} bits`;
|
||||
}
|
||||
return words
|
||||
return words;
|
||||
}
|
||||
|
||||
export function bytesToBigDecimal(arr: number[]): string {
|
||||
@@ -190,16 +175,31 @@ export function hexToDecimal(hex: string): string {
|
||||
}
|
||||
|
||||
// hash logic here because the one in utils.ts only works with node
|
||||
export function hash(signatureAlgorithm: string, bytesArray: number[]) {
|
||||
const unsignedBytesArray = bytesArray.map(toUnsignedByte);
|
||||
const hash = (signatureAlgorithm == 'sha1WithRSAEncryption')
|
||||
? sha1(unsignedBytesArray)
|
||||
: (signatureAlgorithm == 'SHA384withECDSA')
|
||||
? sha384(unsignedBytesArray)
|
||||
: (signatureAlgorithm == 'sha256WithRSAEncryption' || signatureAlgorithm == 'sha256WithRSASSAPSS')
|
||||
? sha256(unsignedBytesArray)
|
||||
: sha256(unsignedBytesArray); // defaults to sha256
|
||||
return hexToSignedBytes(hash);
|
||||
|
||||
export function hash(signatureAlgorithm: string, bytesArray: number[]): number[] {
|
||||
const unsignedBytesArray = bytesArray.map((byte) => byte & 0xff);
|
||||
let hashResult: string;
|
||||
|
||||
switch (signatureAlgorithm) {
|
||||
case 'sha1WithRSAEncryption':
|
||||
hashResult = sha1(unsignedBytesArray);
|
||||
break;
|
||||
case 'SHA384withECDSA':
|
||||
hashResult = sha384(unsignedBytesArray);
|
||||
break;
|
||||
case 'sha256WithRSAEncryption':
|
||||
hashResult = sha256(unsignedBytesArray);
|
||||
break;
|
||||
case 'sha256WithRSASSAPSS':
|
||||
hashResult = sha256(unsignedBytesArray);
|
||||
break;
|
||||
case 'ecdsa-with-SHA1':
|
||||
hashResult = sha1(unsignedBytesArray);
|
||||
break;
|
||||
default:
|
||||
hashResult = sha256(unsignedBytesArray); // Default to sha256
|
||||
}
|
||||
return hexToSignedBytes(hashResult);
|
||||
}
|
||||
|
||||
export function hexToSignedBytes(hexString: string): number[] {
|
||||
@@ -215,19 +215,20 @@ export function toUnsignedByte(signedByte: number) {
|
||||
return signedByte < 0 ? signedByte + 256 : signedByte;
|
||||
}
|
||||
|
||||
export function formatSigAlgNameForCircuit(
|
||||
sigAlg: string,
|
||||
exponent?: string
|
||||
) {
|
||||
export function formatSigAlgNameForCircuit(sigAlg: string, exponent?: string) {
|
||||
// replace - by _, for instance for ecdsa-with-SHA256
|
||||
sigAlg = sigAlg.replace(/-/g, '_')
|
||||
sigAlg = sigAlg.replace(/-/g, '_');
|
||||
// add exponent, for instance for sha256WithRSAEncryption
|
||||
return exponent ? `${sigAlg}_${exponent}` : sigAlg
|
||||
return exponent ? `${sigAlg}_${exponent}` : sigAlg;
|
||||
}
|
||||
|
||||
export function bigIntToChunkedBytes(num: BigInt | bigint, bytesPerChunk: number, numChunks: number) {
|
||||
export function bigIntToChunkedBytes(
|
||||
num: BigInt | bigint,
|
||||
bytesPerChunk: number,
|
||||
numChunks: number
|
||||
) {
|
||||
const res: string[] = [];
|
||||
const bigintNum: bigint = typeof num == "bigint" ? num : num.valueOf();
|
||||
const bigintNum: bigint = typeof num == 'bigint' ? num : num.valueOf();
|
||||
const msk = (1n << BigInt(bytesPerChunk)) - 1n;
|
||||
for (let i = 0; i < numChunks; ++i) {
|
||||
res.push(((bigintNum >> BigInt(i * bytesPerChunk)) & msk).toString());
|
||||
@@ -242,11 +243,11 @@ export function hexStringToSignedIntArray(hexString: string) {
|
||||
result.push(byte > 127 ? byte - 256 : byte);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function formatRoot(root: string): string {
|
||||
let rootHex = BigInt(root).toString(16);
|
||||
return rootHex.length % 2 === 0 ? "0x" + rootHex : "0x0" + rootHex;
|
||||
return rootHex.length % 2 === 0 ? '0x' + rootHex : '0x0' + rootHex;
|
||||
}
|
||||
|
||||
export function getCurrentDateYYMMDD(dayDiff: number = 0): number[] {
|
||||
@@ -255,28 +256,28 @@ export function getCurrentDateYYMMDD(dayDiff: number = 0): number[] {
|
||||
const year = date.getUTCFullYear();
|
||||
const month = date.getUTCMonth() + 1;
|
||||
const day = date.getUTCDate();
|
||||
const YY = (`0${year % 100}`).slice(-2);
|
||||
const MM = (`0${month}`).slice(-2);
|
||||
const DD = (`0${day}`).slice(-2);
|
||||
const YY = `0${year % 100}`.slice(-2);
|
||||
const MM = `0${month}`.slice(-2);
|
||||
const DD = `0${day}`.slice(-2);
|
||||
|
||||
const yymmdd = `${YY}${MM}${DD}`;
|
||||
return Array.from(yymmdd).map(char => parseInt(char));
|
||||
return Array.from(yymmdd).map((char) => parseInt(char));
|
||||
}
|
||||
|
||||
export function getHashLen(signatureAlgorithm: string) {
|
||||
switch (signatureAlgorithm) {
|
||||
case "sha1WithRSAEncryption":
|
||||
case "ecdsa-with-SHA1":
|
||||
case 'sha1WithRSAEncryption':
|
||||
case 'ecdsa-with-SHA1':
|
||||
return 20;
|
||||
case "sha256WithRSAEncryption":
|
||||
case "rsassaPss":
|
||||
case "ecdsa-with-SHA256":
|
||||
case 'sha256WithRSAEncryption':
|
||||
case 'rsassaPss':
|
||||
case 'ecdsa-with-SHA256':
|
||||
return 32;
|
||||
case "sha384WithRSAEncryption":
|
||||
case "ecdsa-with-SHA384":
|
||||
case 'sha384WithRSAEncryption':
|
||||
case 'ecdsa-with-SHA384':
|
||||
return 48;
|
||||
case "sha512WithRSAEncryption":
|
||||
case "ecdsa-with-SHA512":
|
||||
case 'sha512WithRSAEncryption':
|
||||
case 'ecdsa-with-SHA512':
|
||||
return 64;
|
||||
default:
|
||||
console.log(`${signatureAlgorithm} not found in getHashLen`);
|
||||
@@ -350,28 +351,61 @@ export function generateSMTProof(smt: SMT, leaf: bigint) {
|
||||
}
|
||||
|
||||
export function generateMerkleProof(imt: LeanIMT, _index: number, maxDepth: number) {
|
||||
const { siblings: merkleProofSiblings, index } = imt.generateProof(_index)
|
||||
const depthForThisOne = merkleProofSiblings.length
|
||||
const { siblings: merkleProofSiblings, index } = imt.generateProof(_index);
|
||||
const depthForThisOne = merkleProofSiblings.length;
|
||||
// The index must be converted to a list of indices, 1 for each tree level.
|
||||
// The circuit tree depth is 20, so the number of siblings must be 20, even if
|
||||
// the tree depth is actually 3. The missing siblings can be set to 0, as they
|
||||
// won't be used to calculate the root in the circuit.
|
||||
const merkleProofIndices: number[] = []
|
||||
const merkleProofIndices: number[] = [];
|
||||
|
||||
for (let i = 0; i < maxDepth; i += 1) {
|
||||
merkleProofIndices.push((index >> i) & 1)
|
||||
merkleProofIndices.push((index >> i) & 1);
|
||||
if (merkleProofSiblings[i] === undefined) {
|
||||
merkleProofSiblings[i] = BigInt(0)
|
||||
merkleProofSiblings[i] = BigInt(0);
|
||||
}
|
||||
}
|
||||
return { merkleProofSiblings, merkleProofIndices, depthForThisOne }
|
||||
return { merkleProofSiblings, merkleProofIndices, depthForThisOne };
|
||||
}
|
||||
|
||||
export function findSubarrayIndex(arr: any[], subarray: any[]): number {
|
||||
return arr.findIndex((_, index) =>
|
||||
subarray.every((element, i) => element === arr[index + i])
|
||||
);
|
||||
return arr.findIndex((_, index) => subarray.every((element, i) => element === arr[index + i]));
|
||||
}
|
||||
|
||||
export function extractRSFromSignature(signatureBytes: number[]): { r: string; s: string } {
|
||||
const derSignature = Buffer.from(signatureBytes).toString('binary');
|
||||
const asn1 = forge.asn1.fromDer(derSignature);
|
||||
const signatureAsn1 = asn1.value;
|
||||
|
||||
if (signatureAsn1.length !== 2) {
|
||||
throw new Error('Invalid signature format');
|
||||
}
|
||||
|
||||
if (!Array.isArray(asn1.value) || asn1.value.length !== 2) {
|
||||
throw new Error('Invalid signature format');
|
||||
}
|
||||
const r = forge.util.createBuffer(asn1.value[0].value as string).toHex();
|
||||
const s = forge.util.createBuffer(asn1.value[1].value as string).toHex();
|
||||
|
||||
return { r, s };
|
||||
}
|
||||
|
||||
export function BigintToArray(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;
|
||||
}
|
||||
|
||||
|
||||
export function stringToAsciiBigIntArray(str: string): bigint[] {
|
||||
let asciiBigIntArray = [];
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
|
||||
Reference in New Issue
Block a user