From 8522682f2afb4e1060ec226d56f69d6d3a214e94 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 01:29:04 +0900 Subject: [PATCH 01/18] refactor mockPassportData generation - Now using only genMockPassportData.ts - Tests in `/common` verify them - Mock DSCs for ecdsa - Factor tests into unique files - Broke register ecdsa sig verif, will fix --- app/src/screens/MockDataScreen.tsx | 1 + circuits/tests/prove/prove.test.ts | 104 +++ .../tests/prove/prove_rsa_65537_sha1.test.ts | 95 --- .../prove/prove_rsa_65537_sha256.test.ts | 95 --- .../prove/prove_rsapss_65537_sha256.test.ts | 96 --- circuits/tests/register/register.test.ts | 127 ++++ .../register/register_rsa_65537_sha1.test.ts | 115 ---- .../register_rsa_65537_sha256.test.ts | 113 ---- .../register_rsapss_65537_sha256.test.ts | 118 ---- common/package.json | 10 + common/scripts/passportData/README.md | 9 - common/scripts/passportData/passportData.json | 629 ----------------- common/scripts/passportData/sha1_ecdsa.ts | 93 --- common/scripts/passportData/sha1_rsa_65537.ts | 81 --- common/scripts/passportData/sha256_ecdsa.ts | 88 --- .../scripts/passportData/sha256_rsa_65537.ts | 81 --- .../passportData/sha256_rsapss_65537.ts | 103 --- common/scripts/passportData/sha384_ecdsa.ts | 88 --- common/scripts/passportData/sha512_ecdsa.ts | 93 --- common/src/constants/constants.ts | 2 + common/src/constants/mockCertificates.ts | 47 ++ .../sha1_ecdsa_secpk256r1/mock_dsc.key | 8 + .../sha1_ecdsa_secpk256r1/mock_dsc.pem | 13 + .../mock_dsc.key | 0 .../mock_dsc.pem | 0 .../sha384_ecdsa_secpk384r1/mock_dsc.key | 9 + .../sha384_ecdsa_secpk384r1/mock_dsc.pem | 15 + common/src/utils/genMockPassportData.ts | 220 +++--- common/src/utils/generateInputs.ts | 64 +- common/src/utils/handleCertificate.ts | 40 +- common/src/utils/types.ts | 2 +- common/src/utils/utils.ts | 41 +- common/tests/genMockPassportData.test.ts | 85 +++ common/yarn-error.log | 150 ---- common/yarn.lock | 640 +++++++++++++++++- 35 files changed, 1283 insertions(+), 2192 deletions(-) create mode 100644 circuits/tests/prove/prove.test.ts delete mode 100644 circuits/tests/prove/prove_rsa_65537_sha1.test.ts delete mode 100644 circuits/tests/prove/prove_rsa_65537_sha256.test.ts delete mode 100644 circuits/tests/prove/prove_rsapss_65537_sha256.test.ts create mode 100644 circuits/tests/register/register.test.ts delete mode 100644 circuits/tests/register/register_rsa_65537_sha1.test.ts delete mode 100644 circuits/tests/register/register_rsa_65537_sha256.test.ts delete mode 100644 circuits/tests/register/register_rsapss_65537_sha256.test.ts delete mode 100644 common/scripts/passportData/README.md delete mode 100644 common/scripts/passportData/passportData.json delete mode 100644 common/scripts/passportData/sha1_ecdsa.ts delete mode 100644 common/scripts/passportData/sha1_rsa_65537.ts delete mode 100644 common/scripts/passportData/sha256_ecdsa.ts delete mode 100644 common/scripts/passportData/sha256_rsa_65537.ts delete mode 100644 common/scripts/passportData/sha256_rsapss_65537.ts delete mode 100644 common/scripts/passportData/sha384_ecdsa.ts delete mode 100644 common/scripts/passportData/sha512_ecdsa.ts create mode 100644 common/src/mock_certificates/sha1_ecdsa_secpk256r1/mock_dsc.key create mode 100644 common/src/mock_certificates/sha1_ecdsa_secpk256r1/mock_dsc.pem rename common/src/mock_certificates/{sha256_ecdsa => sha256_ecdsa_secpk256r1}/mock_dsc.key (100%) rename common/src/mock_certificates/{sha256_ecdsa => sha256_ecdsa_secpk256r1}/mock_dsc.pem (100%) create mode 100644 common/src/mock_certificates/sha384_ecdsa_secpk384r1/mock_dsc.key create mode 100644 common/src/mock_certificates/sha384_ecdsa_secpk384r1/mock_dsc.pem create mode 100644 common/tests/genMockPassportData.test.ts delete mode 100644 common/yarn-error.log diff --git a/app/src/screens/MockDataScreen.tsx b/app/src/screens/MockDataScreen.tsx index aa1ce1f0..6449bb7f 100644 --- a/app/src/screens/MockDataScreen.tsx +++ b/app/src/screens/MockDataScreen.tsx @@ -12,6 +12,7 @@ import getCountryISO2 from "country-iso-3-to-2"; import { flag } from 'country-emoji'; import { getSignatureAlgorithm, getCircuitName } from '../../../common/src/utils/handleCertificate'; import { downloadZkey } from '../utils/zkeyDownload'; + const MockDataScreen: React.FC = () => { const [signatureAlgorithm, setSignatureAlgorithm] = useState("rsa_sha256"); const listOfSignatureAlgorithms = ["rsa_sha1", "rsa_sha256", "rsapss_sha256"]; diff --git a/circuits/tests/prove/prove.test.ts b/circuits/tests/prove/prove.test.ts new file mode 100644 index 00000000..722fbbf7 --- /dev/null +++ b/circuits/tests/prove/prove.test.ts @@ -0,0 +1,104 @@ +import { describe } from 'mocha'; +import { expect } from 'chai'; +import path from 'path'; +import { wasm as wasm_tester } from 'circom_tester'; +import { generateCircuitInputsProve } from '../../../common/src/utils/generateInputs'; +import { n_dsc, k_dsc } from '../../../common/src/constants/constants'; +import { genMockPassportData } from '../../../common/src/utils/genMockPassportData'; +import { getCircuitName } from '../../../common/src/utils/handleCertificate'; +import { SignatureAlgorithm } from '../../../common/tests/genMockPassportData.test'; + +const sigAlgs = [ + { sigAlg: 'rsa', hashFunction: 'sha1' }, + { sigAlg: 'rsa', hashFunction: 'sha256' }, + { sigAlg: 'rsapss', hashFunction: 'sha256' }, +]; + +sigAlgs.forEach(({ sigAlg, hashFunction }) => { + describe(`Prove - ${hashFunction.toUpperCase()} ${sigAlg.toUpperCase()}`, function () { + this.timeout(0); + let circuit: any; + + const passportData = genMockPassportData(`${sigAlg}_${hashFunction}` as SignatureAlgorithm, 'FRA', '000101', '300101'); + const majority = '18'; + const user_identifier = crypto.randomUUID(); + const scope = '@coboyApp'; + const bitmap = Array(90).fill('1'); + + const inputs = generateCircuitInputsProve( + passportData, + n_dsc, + k_dsc, + scope, + bitmap, + majority, + user_identifier + ); + + before(async () => { + circuit = await wasm_tester( + path.join(__dirname, `../../circuits/prove/${getCircuitName('prove', sigAlg, hashFunction)}.circom`), + { + include: [ + 'node_modules', + './node_modules/@zk-kit/binary-merkle-root.circom/src', + './node_modules/circomlib/circuits', + ], + } + ); + }); + + it('should compile and load the circuit', async function () { + expect(circuit).to.not.be.undefined; + }); + + it('should calculate the witness with correct inputs', async function () { + const w = await circuit.calculateWitness(inputs); + await circuit.checkConstraints(w); + + const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; + expect(nullifier).to.be.not.null; + }); + + it('should fail to calculate witness with invalid mrz', async function () { + try { + const invalidInputs = { + ...inputs, + mrz: Array(93) + .fill(0) + .map((byte) => BigInt(byte).toString()), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail('Expected an error but none was thrown.'); + } catch (error) { + expect(error.message).to.include('Assert Failed'); + } + }); + + it('should fail to calculate witness with invalid dataHashes', async function () { + try { + const invalidInputs = { + ...inputs, + dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail('Expected an error but none was thrown.'); + } catch (error) { + expect(error.message).to.include('Assert Failed'); + } + }); + + it('should fail to calculate witness with invalid signature', async function () { + try { + const invalidInputs = { + ...inputs, + signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail('Expected an error but none was thrown.'); + } catch (error) { + expect(error.message).to.include('Assert Failed'); + } + }); + }); +}); diff --git a/circuits/tests/prove/prove_rsa_65537_sha1.test.ts b/circuits/tests/prove/prove_rsa_65537_sha1.test.ts deleted file mode 100644 index 4b46fcef..00000000 --- a/circuits/tests/prove/prove_rsa_65537_sha1.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { describe } from 'mocha'; -import { assert, expect } from 'chai'; -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import { mockPassportData_sha1_rsa_65537 } from '../../../common/src/constants/mockPassportData'; -import { generateCircuitInputsProve } from '../../../common/src/utils/generateInputs'; -import crypto from 'crypto'; -import { DEFAULT_MAJORITY, k_dsc, n_dsc } from '../../../common/src/constants/constants'; - -describe('PROVE - RSA SHA1', function () { - this.timeout(0); - let circuit: any; - - const passportData = mockPassportData_sha1_rsa_65537; - const majority = DEFAULT_MAJORITY; - const user_identifier = crypto.randomUUID(); - const scope = '@coboyApp'; - const bitmap = Array(90).fill('1'); - - const inputs = generateCircuitInputsProve( - passportData, - n_dsc, - k_dsc, - scope, - bitmap, - majority, - user_identifier - ); - - before(async () => { - circuit = await wasm_tester( - path.join(__dirname, '../../circuits/prove/prove_rsa_65537_sha1.circom'), - { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - } - ); - }); - - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); - - it('should calculate the witness with correct inputs', async function () { - const w = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(w); - - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - expect(nullifier).to.be.not.null; - }); - - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - mrz: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid dataHashes', async function () { - try { - const invalidInputs = { - ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid signature', async function () { - try { - const invalidInputs = { - ...inputs, - signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); -}); diff --git a/circuits/tests/prove/prove_rsa_65537_sha256.test.ts b/circuits/tests/prove/prove_rsa_65537_sha256.test.ts deleted file mode 100644 index 592d133a..00000000 --- a/circuits/tests/prove/prove_rsa_65537_sha256.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { describe } from 'mocha'; -import { assert, expect } from 'chai'; -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import { mockPassportData_sha256_rsa_65537 } from '../../../common/src/constants/mockPassportData'; -import { generateCircuitInputsProve } from '../../../common/src/utils/generateInputs'; -import crypto from 'crypto'; -import { k_dsc, n_dsc } from '../../../common/src/constants/constants'; - -describe('PROVE - RSA SHA256', function () { - this.timeout(0); - let circuit: any; - - const passportData = mockPassportData_sha256_rsa_65537; - const majority = '18'; - const user_identifier = crypto.randomUUID(); - const scope = '@coboyApp'; - const bitmap = Array(90).fill('1'); - - const inputs = generateCircuitInputsProve( - passportData, - n_dsc, - k_dsc, - scope, - bitmap, - majority, - user_identifier - ); - - before(async () => { - circuit = await wasm_tester( - path.join(__dirname, '../../circuits/prove/prove_rsa_65537_sha256.circom'), - { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - } - ); - }); - - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); - - it('should calculate the witness with correct inputs', async function () { - const w = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(w); - - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - expect(nullifier).to.be.not.null; - }); - - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - mrz: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid dataHashes', async function () { - try { - const invalidInputs = { - ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid signature', async function () { - try { - const invalidInputs = { - ...inputs, - signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); -}); diff --git a/circuits/tests/prove/prove_rsapss_65537_sha256.test.ts b/circuits/tests/prove/prove_rsapss_65537_sha256.test.ts deleted file mode 100644 index 274c53e8..00000000 --- a/circuits/tests/prove/prove_rsapss_65537_sha256.test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { describe } from 'mocha'; -import { assert, expect } from 'chai'; -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import { mockPassportData_sha256_rsapss_65537 } from '../../../common/src/constants/mockPassportData'; -import { generateCircuitInputsProve } from '../../../common/src/utils/generateInputs'; -import crypto from 'crypto'; - -describe('PROVE - RSAPSS SHA256', function () { - this.timeout(0); - let circuit: any; - - const passportData = mockPassportData_sha256_rsapss_65537; - const n_dsc = 64; - const k_dsc = 32; - const majority = '18'; - const user_identifier = crypto.randomUUID(); - const scope = '@coboyApp'; - const bitmap = Array(90).fill('1'); - - const inputs = generateCircuitInputsProve( - passportData, - n_dsc, - k_dsc, - scope, - bitmap, - majority, - user_identifier - ); - - before(async () => { - circuit = await wasm_tester( - path.join(__dirname, '../../circuits/prove/prove_rsapss_65537_sha256.circom'), - { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - } - ); - }); - - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); - - it('should calculate the witness with correct inputs', async function () { - const w = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(w); - - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - expect(nullifier).to.be.not.null; - }); - - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - mrz: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid dataHashes', async function () { - try { - const invalidInputs = { - ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid signature', async function () { - try { - const invalidInputs = { - ...inputs, - signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); -}); diff --git a/circuits/tests/register/register.test.ts b/circuits/tests/register/register.test.ts new file mode 100644 index 00000000..1d346363 --- /dev/null +++ b/circuits/tests/register/register.test.ts @@ -0,0 +1,127 @@ +import { describe } from 'mocha'; +import { assert, expect } from 'chai'; +import path from 'path'; +import { wasm as wasm_tester } from 'circom_tester'; +import { poseidon6 } from 'poseidon-lite'; +import { generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs'; +import { hexToDecimal, packBytes } from '../../../common/src/utils/utils'; +import { computeLeafFromModulusBigInt } from '../../../common/src/utils/csca'; +import { n_dsc, k_dsc, n_dsc_ecdsa, k_dsc_ecdsa, PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; +import { genMockPassportData } from '../../../common/src/utils/genMockPassportData'; +import { getCircuitName, getSignatureAlgorithm } from '../../../common/src/utils/handleCertificate'; +import { SignatureAlgorithm } from '../../../common/tests/genMockPassportData.test'; + +const sigAlgs = [ + // { sigAlg: 'rsa', hashFunction: 'sha1' }, + // { sigAlg: 'rsa', hashFunction: 'sha256' }, + // { sigAlg: 'rsapss', hashFunction: 'sha256' }, + { sigAlg: 'ecdsa', hashFunction: 'sha256' }, + // { sigAlg: 'ecdsa', hashFunction: 'sha1' }, +]; + +sigAlgs.forEach(({ sigAlg, hashFunction }) => { + describe(`Register - ${hashFunction.toUpperCase()} ${sigAlg.toUpperCase()}`, function () { + this.timeout(0); + let circuit: any; + + const passportData = genMockPassportData(`${sigAlg}_${hashFunction}` as SignatureAlgorithm, 'FRA', '000101', '300101'); + const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); + const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); + + const { modulus, x, y } = getSignatureAlgorithm(passportData.dsc as string); + + const inputs = generateCircuitInputsRegister( + secret, + dscSecret, + PASSPORT_ATTESTATION_ID, + passportData, + sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc, + sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc + ); + + before(async () => { + circuit = await wasm_tester( + path.join(__dirname, `../../circuits/register/${getCircuitName('register', sigAlg, hashFunction)}.circom`), + { + include: [ + 'node_modules', + './node_modules/@zk-kit/binary-merkle-root.circom/src', + './node_modules/circomlib/circuits', + ], + } + ); + }); + + it('should compile and load the circuit', async function () { + expect(circuit).to.not.be.undefined; + }); + + it('should calculate the witness with correct inputs', async function () { + const w = await circuit.calculateWitness(inputs); + await circuit.checkConstraints(w); + + const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; + console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); + const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; + console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); + const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) + .blinded_dsc_commitment; + console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); + + // const mrz_bytes = packBytes(inputs.mrz); + // const commitment_bytes = poseidon6([ + // inputs.secret[0], + // PASSPORT_ATTESTATION_ID, + // computeLeafFromModulusBigInt(BigInt(hexToDecimal(modulus as string))), + // mrz_bytes[0], + // mrz_bytes[1], + // mrz_bytes[2], + // ]); + // const commitment_js = commitment_bytes.toString(); + // //console.log('commitment_js', commitment_js) + // //console.log('commitment_circom', commitment_circom) + // expect(commitment_circom).to.be.equal(commitment_js); + }); + + it('should fail to calculate witness with invalid mrz', async function () { + try { + const invalidInputs = { + ...inputs, + mrz: Array(93) + .fill(0) + .map((byte) => BigInt(byte).toString()), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail('Expected an error but none was thrown.'); + } catch (error) { + expect(error.message).to.include('Assert Failed'); + } + }); + + it('should fail to calculate witness with invalid dataHashes', async function () { + try { + const invalidInputs = { + ...inputs, + dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail('Expected an error but none was thrown.'); + } catch (error) { + expect(error.message).to.include('Assert Failed'); + } + }); + + it('should fail to calculate witness with invalid signature', async function () { + try { + const invalidInputs = { + ...inputs, + signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail('Expected an error but none was thrown.'); + } catch (error) { + expect(error.message).to.include('Assert Failed'); + } + }); + }); +}); diff --git a/circuits/tests/register/register_rsa_65537_sha1.test.ts b/circuits/tests/register/register_rsa_65537_sha1.test.ts deleted file mode 100644 index 8a62e641..00000000 --- a/circuits/tests/register/register_rsa_65537_sha1.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { describe } from 'mocha'; -import { assert, expect } from 'chai'; -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import { poseidon6 } from 'poseidon-lite'; -import { mockPassportData_sha1_rsa_65537 } from '../../../common/src/constants/mockPassportData'; -import { generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs'; -import { packBytes } from '../../../common/src/utils/utils'; -import { computeLeafFromModulusBigInt } from '../../../common/src/utils/csca'; -import { k_dsc, n_dsc, PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; - -describe('Register - SHA1 RSA', function () { - this.timeout(0); - let circuit: any; - - const passportData = mockPassportData_sha1_rsa_65537; - const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - - const inputs = generateCircuitInputsRegister( - secret, - dscSecret, - PASSPORT_ATTESTATION_ID, - passportData, - n_dsc, - k_dsc - ); - - before(async () => { - circuit = await wasm_tester( - path.join(__dirname, '../../circuits/register/register_rsa_65537_sha1.circom'), - { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - './node_modules/dmpierre/sha1-circom/circuits', - './node_modules/@zk-email/circuits', - ], - } - ); - }); - - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); - - it('should calculate the witness with correct inputs', async function () { - const w = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(w); - - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); - const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; - console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); - const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) - .blinded_dsc_commitment; - console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); - - const mrz_bytes = packBytes(inputs.mrz); - const commitment_bytes = poseidon6([ - inputs.secret[0], - PASSPORT_ATTESTATION_ID, - computeLeafFromModulusBigInt(BigInt(passportData.pubKey.modulus)), - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2], - ]); - const commitment_js = commitment_bytes.toString(); - //console.log('commitment_js', commitment_js) - //console.log('commitment_circom', commitment_circom) - expect(commitment_circom).to.be.equal(commitment_js); - }); - - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - mrz: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid dataHashes', async function () { - try { - const invalidInputs = { - ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid signature', async function () { - try { - const invalidInputs = { - ...inputs, - signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); -}); diff --git a/circuits/tests/register/register_rsa_65537_sha256.test.ts b/circuits/tests/register/register_rsa_65537_sha256.test.ts deleted file mode 100644 index 0bb8222a..00000000 --- a/circuits/tests/register/register_rsa_65537_sha256.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { describe } from 'mocha'; -import { assert, expect } from 'chai'; -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import { poseidon6 } from 'poseidon-lite'; -import { mockPassportData_sha256_rsa_65537 } from '../../../common/src/constants/mockPassportData'; -import { generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs'; -import { packBytes } from '../../../common/src/utils/utils'; -import { computeLeafFromModulusBigInt } from '../../../common/src/utils/csca'; -import { k_dsc, n_dsc, PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; - -describe('Register - SHA256 RSA', function () { - this.timeout(0); - let circuit: any; - - const passportData = mockPassportData_sha256_rsa_65537; - const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - - const inputs = generateCircuitInputsRegister( - secret, - dscSecret, - PASSPORT_ATTESTATION_ID, - passportData, - n_dsc, - k_dsc - ); - - before(async () => { - circuit = await wasm_tester( - path.join(__dirname, '../../circuits/register/register_rsa_65537_sha256.circom'), - { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - } - ); - }); - - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); - - it('should calculate the witness with correct inputs', async function () { - const w = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(w); - - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); - const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; - console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); - const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) - .blinded_dsc_commitment; - console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); - - const mrz_bytes = packBytes(inputs.mrz); - const commitment_bytes = poseidon6([ - inputs.secret[0], - PASSPORT_ATTESTATION_ID, - computeLeafFromModulusBigInt(BigInt(passportData.pubKey.modulus)), - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2], - ]); - const commitment_js = commitment_bytes.toString(); - //console.log('commitment_js', commitment_js) - //console.log('commitment_circom', commitment_circom) - expect(commitment_circom).to.be.equal(commitment_js); - }); - - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - mrz: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid dataHashes', async function () { - try { - const invalidInputs = { - ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid signature', async function () { - try { - const invalidInputs = { - ...inputs, - signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); -}); diff --git a/circuits/tests/register/register_rsapss_65537_sha256.test.ts b/circuits/tests/register/register_rsapss_65537_sha256.test.ts deleted file mode 100644 index 0d0b5824..00000000 --- a/circuits/tests/register/register_rsapss_65537_sha256.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { describe } from 'mocha'; -import { assert, expect } from 'chai'; -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import { poseidon6 } from 'poseidon-lite'; -import { mockPassportData_sha256_rsapss_65537 } from '../../../common/src/constants/mockPassportData'; -import { generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs'; -import { packBytes } from '../../../common/src/utils/utils'; -import { computeLeafFromModulusBigInt } from '../../../common/src/utils/csca'; -import { PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; - -describe('Register - SHA256 RSASSAPSS', function () { - this.timeout(0); - let circuit: any; - - const passportData = mockPassportData_sha256_rsapss_65537; - const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const n_dsc = 64; - const k_dsc = 32; - - const inputs = generateCircuitInputsRegister( - secret, - dscSecret, - PASSPORT_ATTESTATION_ID, - passportData, - n_dsc, - k_dsc - ); - - before(async () => { - circuit = await wasm_tester( - path.join(__dirname, '../../circuits/register/register_rsapss_65537_sha256.circom'), - { - include: [ - 'node_modules', - 'node_modules/@zk-email/circuits/helpers/sha.circom', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - } - ); - }); - - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); - - it('should calculate the witness with correct inputs', async function () { - console.time('calculateWitness'); - const w = await circuit.calculateWitness(inputs); - console.timeEnd('calculateWitness'); - await circuit.checkConstraints(w); - - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); - const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; - console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); - const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) - .blinded_dsc_commitment; - console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); - - const mrz_bytes = packBytes(inputs.mrz); - const commitment_bytes = poseidon6([ - inputs.secret[0], - PASSPORT_ATTESTATION_ID, - computeLeafFromModulusBigInt(BigInt(passportData.pubKey.modulus)), - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2], - ]); - const commitment_js = commitment_bytes.toString(); - //console.log('commitment_js', commitment_js) - //console.log('commitment_circom', commitment_circom) - expect(commitment_circom).to.be.equal(commitment_js); - }); - - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - mrz: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid dataHashes', async function () { - try { - const invalidInputs = { - ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid signature', async function () { - try { - const invalidInputs = { - ...inputs, - signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); -}); diff --git a/common/package.json b/common/package.json index d4344993..311a3716 100644 --- a/common/package.json +++ b/common/package.json @@ -1,4 +1,11 @@ { + "name": "openpassport-common", + "version": "0.0.1", + "author": "", +"license": "MIT", + "scripts": { + "test": "yarn ts-mocha tests/**/*.test.ts --exit" + }, "dependencies": { "@ashpect/smt": "https://github.com/ashpect/smt#main", "@babel/runtime": "^7.23.4", @@ -8,6 +15,7 @@ "asn1.js": "^5.4.1", "asn1js": "^3.0.5", "axios": "^1.7.2", + "chai": "^4.3.8", "elliptic": "^6.5.5", "fs": "^0.0.1-security", "js-sha1": "^0.7.0", @@ -15,10 +23,12 @@ "js-sha512": "^0.9.0", "json-to-ts": "^2.1.0", "jsrsasign": "^11.1.0", + "mocha": "^10.7.3", "node-forge": "https://github.com/remicolin/forge", "path": "^0.12.7", "pkijs": "^3.2.4", "poseidon-lite": "^0.2.0", + "ts-mocha": "^10.0.0", "typescript-parser": "^2.6.1" }, "devDependencies": { diff --git a/common/scripts/passportData/README.md b/common/scripts/passportData/README.md deleted file mode 100644 index 79b6c752..00000000 --- a/common/scripts/passportData/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# How to generate mock passport data based on your real data? - -- Build the app and scan your passport to log your passport data. -- Copy one of the files of this folder and paste your passport data. -- Adapt the `verify` function to verify it. Once this is done, adapt the `genMockPassportData` to generate a mock one. -- Once the mock passport data generated is verified correctly by the same `verify` function that verifies yours, you're all set! -- Run the script to generate a mock passport data and add it to `common/src/utils/mockPassportData.ts` -- Do a PR -- DM us to collect your bounty! \ No newline at end of file diff --git a/common/scripts/passportData/passportData.json b/common/scripts/passportData/passportData.json deleted file mode 100644 index 0ebd3b53..00000000 --- a/common/scripts/passportData/passportData.json +++ /dev/null @@ -1,629 +0,0 @@ -{ - "mrz": "P c.charCodeAt(0)); - - return { - mrz: sampleMRZ, - signatureAlgorithm: signatureAlgorithm, - pubKey: { - modulus: hexToDecimal(modulus), - exponent: '65537', - }, - 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 modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10); - const exponent = new forge.jsbn.BigInteger(pubKey.exponent, 10); - const rsaPublicKey = forge.pki.rsa.setPublicKey(modulus, exponent); - - const md = forge.md.sha1.create(); - md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); - - const signature = Buffer.from(encryptedDigest).toString( - 'binary', - ); - - return rsaPublicKey.verify(md.digest().bytes(), signature); -} - -const mockPassportData = genMockPassportData_sha1WithRSAEncryption_65537(); -console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2)); -console.log("Signature valid:", verify(mockPassportData)); - -writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2)); \ No newline at end of file diff --git a/common/scripts/passportData/sha256_ecdsa.ts b/common/scripts/passportData/sha256_ecdsa.ts deleted file mode 100644 index c3410ee2..00000000 --- a/common/scripts/passportData/sha256_ecdsa.ts +++ /dev/null @@ -1,88 +0,0 @@ -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 asn1 from 'asn1js'; -import { Certificate } from 'pkijs'; -import { writeFileSync } from 'fs'; -import elliptic from 'elliptic'; -import { sampleDataHashes_large } from '../../src/constants/sampleDataHashes'; -import { mock_dsc_key_sha256_ecdsa, mock_dsc_sha256_ecdsa } from "../../src/constants/mockCertificates"; - -const sampleMRZ = - 'P c.charCodeAt(0)); - - return { - mrz: sampleMRZ, - signatureAlgorithm: signatureAlgorithm, - pubKey: { - modulus: hexToDecimal(modulus), - exponent: '65537', - }, - 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 - hashLen) - ), - 'concatHash is not at the right place in eContent' - ); - - const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10); - const exponent = new forge.jsbn.BigInteger(pubKey.exponent, 10); - const rsaPublicKey = forge.pki.rsa.setPublicKey(modulus, exponent); - - const md = forge.md.sha256.create(); - md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); - - const signature = Buffer.from(encryptedDigest).toString( - 'binary', - ); - - return rsaPublicKey.verify(md.digest().bytes(), signature); -} - -const mockPassportData = genMockPassportData_sha256WithRSAEncryption_65537(); -console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2)); -console.log("Signature valid:", verify(mockPassportData)); - -writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2)); \ No newline at end of file diff --git a/common/scripts/passportData/sha256_rsapss_65537.ts b/common/scripts/passportData/sha256_rsapss_65537.ts deleted file mode 100644 index 03e0ad3e..00000000 --- a/common/scripts/passportData/sha256_rsapss_65537.ts +++ /dev/null @@ -1,103 +0,0 @@ -import assert from "assert"; -import { PassportData } from "../../src/utils/types"; -import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual, findSubarrayIndex } from "../../src/utils/utils"; -import * as forge from 'node-forge'; -import crypto from 'crypto'; -import { readFileSync, writeFileSync } from "fs"; -import { mock_dsc_key_sha256_rsapss_2048 } from "../../src/constants/mockCertificates"; -import { mock_dsc_sha256_rsapss_2048 } from "../../src/constants/mockCertificates"; -import { sampleDataHashes_large } from "../../src/constants/sampleDataHashes"; - -const sampleMRZ = "P byte < 128 ? byte : byte - 256); - - return { - mrz: sampleMRZ, - signatureAlgorithm: signatureAlgorithm, - pubKey: { - modulus: modulus, - exponent: exponent, - }, - dataGroupHashes: concatenatedDataHashes, - eContent: eContent, - encryptedDigest: signatureArray, - 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 modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10); - const exponent = new forge.jsbn.BigInteger(pubKey.exponent, 10); - const publicKey = forge.pki.setRsaPublicKey(modulus, exponent); - const pem = forge.pki.publicKeyToPem(publicKey); - const rsa_public = Buffer.from(pem); - - const message = Buffer.from(eContent); - const signature = Buffer.from(encryptedDigest); - const hash_algorithm = "sha256"; - - const public_key = { - key: rsa_public, - padding: crypto.constants.RSA_PKCS1_PSS_PADDING, - saltLength: 32, - }; - - const isVerified = crypto.verify(hash_algorithm, message, public_key, signature); - - return isVerified; -} - -const mockPassportData = genMockPassportData_sha256WithRSASSAPSS_65537(); -console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2)); -console.log("Signature valid:", verify(mockPassportData)); - -writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2)); \ No newline at end of file diff --git a/common/scripts/passportData/sha384_ecdsa.ts b/common/scripts/passportData/sha384_ecdsa.ts deleted file mode 100644 index 37a9a6c9..00000000 --- a/common/scripts/passportData/sha384_ecdsa.ts +++ /dev/null @@ -1,88 +0,0 @@ -import assert from "assert"; -import { PassportData } from "../../src/utils/types"; -import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual, findSubarrayIndex } from "../../src/utils/utils"; -import * as forge from 'node-forge'; -import { writeFileSync } from "fs"; -import elliptic from 'elliptic'; -import * as crypto from 'crypto'; -import { sampleDataHashes_large } from "../../src/constants/sampleDataHashes"; - -const sampleMRZ = "P 254 Cirom field size +export const k_dsc_ecdsa = 6; export const n_csca = 121; export const k_csca = 34; export const max_cert_bytes = 1664; diff --git a/common/src/constants/mockCertificates.ts b/common/src/constants/mockCertificates.ts index a18d90eb..0dab4862 100644 --- a/common/src/constants/mockCertificates.ts +++ b/common/src/constants/mockCertificates.ts @@ -470,4 +470,51 @@ xncatW0Ixvl73iXA6WG45093oyEwHzAdBgNVHQ4EFgQUUa6p5iCBqbhslwC79LHX EyYTiP0wCgYIKoZIzj0EAwIDSAAwRQIhAP6XA1AWr8v6f7EJz3u5GuudyCKqiuBY mDhB0W8OhhR2AiAMTm++57YJkbQNxzL75nypXSdZmBfiQXSNM0NFpHEuIQ== -----END CERTIFICATE----- +` + +export const mock_dsc_key_sha1_ecdsa = `-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIK2wRGm6xnmTnHhOtyUxp/PFPTySoaD+f2JNXy9JAmRVoAoGCCqGSM49 +AwEHoUQDQgAEzqM5vQEv7vhD7ZXecfkSvC/vfDffjuEyUK3DLlvjbxUIXeaJ+dUg +zb8+rYwVh+Ai/DDxCLuSy2wn4gbOFwzOGA== +-----END EC PRIVATE KEY----- +` + +export const mock_dsc_sha1_ecdsa = `-----BEGIN CERTIFICATE----- +MIICBDCCAaygAwIBAgIULaL4N+BRrqV1D8UeefZegXfkWogwCQYHKoZIzj0EATBy +MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFU3RhdGUxDTALBgNVBAcMBENpdHkxFTAT +BgNVBAoMDE9yZ2FuaXphdGlvbjETMBEGA1UECwwKRGVwYXJ0bWVudDEYMBYGA1UE +AwwPd3d3LmV4YW1wbGUuY29tMB4XDTI0MDkxMzEyNTgzNVoXDTI1MDkxMzEyNTgz +NVowcjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5 +MRUwEwYDVQQKDAxPcmdhbml6YXRpb24xEzARBgNVBAsMCkRlcGFydG1lbnQxGDAW +BgNVBAMMD3d3dy5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA +BM6jOb0BL+74Q+2V3nH5Erwv73w3347hMlCtwy5b428VCF3mifnVIM2/Pq2MFYfg +Ivww8Qi7kstsJ+IGzhcMzhijITAfMB0GA1UdDgQWBBTRmLBSAQr3AAI4didYznX/ +mEvuzDAJBgcqhkjOPQQBA0cAMEQCIB25iNcA7Y3D3E0fv8GIaV0Ei8Ydu4AVuTJW +C8tZvjhWAiBqAuBYm104bRLWaT2uSZexQJgvTPB6j6SdUi0SmR0acw== +-----END CERTIFICATE----- +` + +export const mock_dsc_key_sha384_ecdsa = `-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDAw/8AnnGTU8TWWt+SDVr2Gi3TEruQ5tkZ9PObCFtW1nQZaId/f/UFk +nJgnT7zm72qgBwYFK4EEACKhZANiAARBQCmC0UscKfL8KkVMtO69SU17NIrpLsw5 +ibVLxHqcnKMm0FLy0gwU3DFqFF9gPD64EmyoxyE+mo+I3l5rEZPWMqVZOoxCRSww +f6GeHkgco/zGFxnEaklZL7g6gwyUNp8= +-----END EC PRIVATE KEY----- +` + +export const mock_dsc_sha384_ecdsa = `-----BEGIN CERTIFICATE----- +MIICRDCCAcqgAwIBAgIUDWqj4BMk0L+D4RpvoSSyc6Lz3mswCgYIKoZIzj0EAwMw +cjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRUw +EwYDVQQKDAxPcmdhbml6YXRpb24xEzARBgNVBAsMCkRlcGFydG1lbnQxGDAWBgNV +BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0yNDA5MTMxMzA4MTdaFw0yNTA5MTMxMzA4 +MTdaMHIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0 +eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRMwEQYDVQQLDApEZXBhcnRtZW50MRgw +FgYDVQQDDA93d3cuZXhhbXBsZS5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARB +QCmC0UscKfL8KkVMtO69SU17NIrpLsw5ibVLxHqcnKMm0FLy0gwU3DFqFF9gPD64 +EmyoxyE+mo+I3l5rEZPWMqVZOoxCRSwwf6GeHkgco/zGFxnEaklZL7g6gwyUNp+j +ITAfMB0GA1UdDgQWBBTalDCeljqgJiT5+YCzAq1vS0zaFDAKBggqhkjOPQQDAwNo +ADBlAjAu9tM+LZ8PB90F3Wd+mg//Eia6oTM9APo2+E9isiV/sgRwy3HFfAbYnH7c +xy29Ef4CMQCiGvLgkcYMSx3J1bWcq8nuxPBywf440ruiFf95wzm/erjDRFG3u7Dh +d+9Msdsovrc= +-----END CERTIFICATE----- ` \ No newline at end of file diff --git a/common/src/mock_certificates/sha1_ecdsa_secpk256r1/mock_dsc.key b/common/src/mock_certificates/sha1_ecdsa_secpk256r1/mock_dsc.key new file mode 100644 index 00000000..fbae8ec5 --- /dev/null +++ b/common/src/mock_certificates/sha1_ecdsa_secpk256r1/mock_dsc.key @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIK2wRGm6xnmTnHhOtyUxp/PFPTySoaD+f2JNXy9JAmRVoAoGCCqGSM49 +AwEHoUQDQgAEzqM5vQEv7vhD7ZXecfkSvC/vfDffjuEyUK3DLlvjbxUIXeaJ+dUg +zb8+rYwVh+Ai/DDxCLuSy2wn4gbOFwzOGA== +-----END EC PRIVATE KEY----- diff --git a/common/src/mock_certificates/sha1_ecdsa_secpk256r1/mock_dsc.pem b/common/src/mock_certificates/sha1_ecdsa_secpk256r1/mock_dsc.pem new file mode 100644 index 00000000..6b004ef1 --- /dev/null +++ b/common/src/mock_certificates/sha1_ecdsa_secpk256r1/mock_dsc.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICBDCCAaygAwIBAgIULaL4N+BRrqV1D8UeefZegXfkWogwCQYHKoZIzj0EATBy +MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFU3RhdGUxDTALBgNVBAcMBENpdHkxFTAT +BgNVBAoMDE9yZ2FuaXphdGlvbjETMBEGA1UECwwKRGVwYXJ0bWVudDEYMBYGA1UE +AwwPd3d3LmV4YW1wbGUuY29tMB4XDTI0MDkxMzEyNTgzNVoXDTI1MDkxMzEyNTgz +NVowcjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5 +MRUwEwYDVQQKDAxPcmdhbml6YXRpb24xEzARBgNVBAsMCkRlcGFydG1lbnQxGDAW +BgNVBAMMD3d3dy5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA +BM6jOb0BL+74Q+2V3nH5Erwv73w3347hMlCtwy5b428VCF3mifnVIM2/Pq2MFYfg +Ivww8Qi7kstsJ+IGzhcMzhijITAfMB0GA1UdDgQWBBTRmLBSAQr3AAI4didYznX/ +mEvuzDAJBgcqhkjOPQQBA0cAMEQCIB25iNcA7Y3D3E0fv8GIaV0Ei8Ydu4AVuTJW +C8tZvjhWAiBqAuBYm104bRLWaT2uSZexQJgvTPB6j6SdUi0SmR0acw== +-----END CERTIFICATE----- diff --git a/common/src/mock_certificates/sha256_ecdsa/mock_dsc.key b/common/src/mock_certificates/sha256_ecdsa_secpk256r1/mock_dsc.key similarity index 100% rename from common/src/mock_certificates/sha256_ecdsa/mock_dsc.key rename to common/src/mock_certificates/sha256_ecdsa_secpk256r1/mock_dsc.key diff --git a/common/src/mock_certificates/sha256_ecdsa/mock_dsc.pem b/common/src/mock_certificates/sha256_ecdsa_secpk256r1/mock_dsc.pem similarity index 100% rename from common/src/mock_certificates/sha256_ecdsa/mock_dsc.pem rename to common/src/mock_certificates/sha256_ecdsa_secpk256r1/mock_dsc.pem diff --git a/common/src/mock_certificates/sha384_ecdsa_secpk384r1/mock_dsc.key b/common/src/mock_certificates/sha384_ecdsa_secpk384r1/mock_dsc.key new file mode 100644 index 00000000..61cc1780 --- /dev/null +++ b/common/src/mock_certificates/sha384_ecdsa_secpk384r1/mock_dsc.key @@ -0,0 +1,9 @@ +-----BEGIN EC PARAMETERS----- +BgUrgQQAIg== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDAw/8AnnGTU8TWWt+SDVr2Gi3TEruQ5tkZ9PObCFtW1nQZaId/f/UFk +nJgnT7zm72qgBwYFK4EEACKhZANiAARBQCmC0UscKfL8KkVMtO69SU17NIrpLsw5 +ibVLxHqcnKMm0FLy0gwU3DFqFF9gPD64EmyoxyE+mo+I3l5rEZPWMqVZOoxCRSww +f6GeHkgco/zGFxnEaklZL7g6gwyUNp8= +-----END EC PRIVATE KEY----- diff --git a/common/src/mock_certificates/sha384_ecdsa_secpk384r1/mock_dsc.pem b/common/src/mock_certificates/sha384_ecdsa_secpk384r1/mock_dsc.pem new file mode 100644 index 00000000..42780c41 --- /dev/null +++ b/common/src/mock_certificates/sha384_ecdsa_secpk384r1/mock_dsc.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICRDCCAcqgAwIBAgIUDWqj4BMk0L+D4RpvoSSyc6Lz3mswCgYIKoZIzj0EAwMw +cjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRUw +EwYDVQQKDAxPcmdhbml6YXRpb24xEzARBgNVBAsMCkRlcGFydG1lbnQxGDAWBgNV +BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0yNDA5MTMxMzA4MTdaFw0yNTA5MTMxMzA4 +MTdaMHIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0 +eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRMwEQYDVQQLDApEZXBhcnRtZW50MRgw +FgYDVQQDDA93d3cuZXhhbXBsZS5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARB +QCmC0UscKfL8KkVMtO69SU17NIrpLsw5ibVLxHqcnKMm0FLy0gwU3DFqFF9gPD64 +EmyoxyE+mo+I3l5rEZPWMqVZOoxCRSwwf6GeHkgco/zGFxnEaklZL7g6gwyUNp+j +ITAfMB0GA1UdDgQWBBTalDCeljqgJiT5+YCzAq1vS0zaFDAKBggqhkjOPQQDAwNo +ADBlAjAu9tM+LZ8PB90F3Wd+mg//Eia6oTM9APo2+E9isiV/sgRwy3HFfAbYnH7c +xy29Ef4CMQCiGvLgkcYMSx3J1bWcq8nuxPBywf440ruiFf95wzm/erjDRFG3u7Dh +d+9Msdsovrc= +-----END CERTIFICATE----- diff --git a/common/src/utils/genMockPassportData.ts b/common/src/utils/genMockPassportData.ts index 709c371d..837ff196 100644 --- a/common/src/utils/genMockPassportData.ts +++ b/common/src/utils/genMockPassportData.ts @@ -1,96 +1,150 @@ -import { PassportData } from "./types"; -import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal } from "./utils"; +import { PassportData } from './types'; +import { + hash, + assembleEContent, + formatAndConcatenateDataHashes, + formatMrz, +} from './utils'; import * as forge from 'node-forge'; -import { mock_dsc_key_sha1_rsa_4096, mock_dsc_key_sha256_rsa_4096, mock_dsc_key_sha256_rsapss_2048, mock_dsc_key_sha256_rsapss_4096, mock_dsc_sha1_rsa_4096, mock_dsc_sha256_rsa_4096, mock_dsc_sha256_rsapss_2048, mock_dsc_sha256_rsapss_4096 } from "../constants/mockCertificates"; -import { sampleDataHashes_small, sampleDataHashes_large } from "../constants/sampleDataHashes"; -import { countryCodes } from "../constants/constants"; +import * as asn1 from 'asn1js'; +import elliptic from 'elliptic'; +import { + mock_dsc_key_sha1_rsa_4096, + mock_dsc_key_sha256_ecdsa, + mock_dsc_key_sha256_rsa_4096, + mock_dsc_key_sha256_rsapss_2048, + mock_dsc_key_sha256_rsapss_4096, + mock_dsc_sha1_rsa_4096, + mock_dsc_sha256_ecdsa, + mock_dsc_sha256_rsa_4096, + mock_dsc_sha256_rsapss_2048, + mock_dsc_sha256_rsapss_4096, + mock_dsc_key_sha1_ecdsa, + mock_dsc_sha1_ecdsa, + mock_dsc_key_sha384_ecdsa, + mock_dsc_sha384_ecdsa, +} from '../constants/mockCertificates'; +import { sampleDataHashes_small, sampleDataHashes_large } from '../constants/sampleDataHashes'; +import { countryCodes } from '../constants/constants'; +import { getSignatureAlgorithm } from './handleCertificate'; + export function genMockPassportData( - signatureType: 'rsa_sha1' | 'rsa_sha256' | 'rsapss_sha256', - nationality: keyof typeof countryCodes, - birthDate: string, - expiryDate: string, + signatureType: 'rsa_sha1' | 'rsa_sha256' | 'rsapss_sha256' | 'ecdsa_sha256' | 'ecdsa_sha1' | 'ecdsa_sha384', + nationality: keyof typeof countryCodes, + birthDate: string, + expiryDate: string ): PassportData { - if (birthDate.length !== 6 || expiryDate.length !== 6) { - throw new Error("birthdate and expiry date have to be in the \"YYMMDD\" format"); - } + if (birthDate.length !== 6 || expiryDate.length !== 6) { + throw new Error('birthdate and expiry date have to be in the "YYMMDD" format'); + } - const mrz = `P<${nationality}DUPONT< c.charCodeAt(0)); - } else { - const md = signatureType === 'rsa_sha1' ? forge.md.sha1.create() : forge.md.sha256.create(); - md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); - const forgeSignature = privKey.sign(md); - signature = Array.from(forgeSignature, (c: string) => c.charCodeAt(0)); - } + const eContent = assembleEContent(hash(hashFunction, concatenatedDataHashes)); - const signatureBytes = Array.from(signature, byte => byte < 128 ? byte : byte - 256); + const signature = sign(privateKeyPem, dsc, eContent); + const signatureBytes = Array.from(signature, (byte) => (byte < 128 ? byte : byte - 256)); - return { - dsc: dsc, - mrz: mrz, - signatureAlgorithm: signatureAlgorithm, - pubKey: { - modulus: hexToDecimal(modulus), - exponent: '65537', - }, - dataGroupHashes: concatenatedDataHashes, - eContent: eContent, - encryptedDigest: signatureBytes, - photoBase64: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIy3...", - mockUser: true - }; + return { + dsc: dsc, + mrz: mrz, + dataGroupHashes: concatenatedDataHashes, + eContent: eContent, + encryptedDigest: signatureBytes, + photoBase64: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIy3...', + mockUser: true, + }; } +function sign( + privateKeyPem: string, + dsc: string, + eContent: number[] +): number[] { + const { signatureAlgorithm, hashFunction, curve } = getSignatureAlgorithm(dsc); + + if (signatureAlgorithm === 'rsapss') { + const privateKey = forge.pki.privateKeyFromPem(privateKeyPem); + const md = forge.md.sha256.create(); + md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); + const pss = forge.pss.create({ + md: forge.md.sha256.create(), + mgf: forge.mgf.mgf1.create(forge.md.sha256.create()), + saltLength: 32, + }); + const signatureBytes = privateKey.sign(md, pss); + return Array.from(signatureBytes, (c: string) => c.charCodeAt(0)); + } else if (signatureAlgorithm === 'ecdsa') { + const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384'; + const ec = new elliptic.ec(curveForElliptic); + + const privateKeyDer = Buffer.from( + privateKeyPem.replace(/-----BEGIN EC PRIVATE KEY-----|\n|-----END EC PRIVATE KEY-----/g, ''), + 'base64' + ); + const asn1Data = asn1.fromBER(privateKeyDer); + const privateKeyBuffer = (asn1Data.result.valueBlock as any).value[1].valueBlock.valueHexView; + + const keyPair = ec.keyFromPrivate(privateKeyBuffer); + + console.log('privateKeyBuffer', privateKeyBuffer); + + const eContentHash = hash(hashFunction, eContent); + const signature = keyPair.sign(eContentHash); + const signatureBytes = signature.toDER(); + + return signatureBytes; + } else { + const privKey = forge.pki.privateKeyFromPem(privateKeyPem); + const md = hashFunction === 'sha1' ? forge.md.sha1.create() : forge.md.sha256.create(); + md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); + const forgeSignature = privKey.sign(md); + return Array.from(forgeSignature, (c: string) => c.charCodeAt(0)); + } +} diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 48ed440d..b2410f4f 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -30,6 +30,7 @@ import { mockPassportDatas, } from "../constants/mockPassportData"; import { SMT } from "@ashpect/smt" +import { getSignatureAlgorithm } from './handleCertificate'; export function generateCircuitInputsRegister( secret: string, @@ -40,8 +41,11 @@ export function generateCircuitInputsRegister( k_dsc: number, mocks: PassportData[] = mockPassportDatas ) { - const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = - passportData; + const { mrz, dsc, dataGroupHashes, eContent, encryptedDigest } = + passportData; + + const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus } = getSignatureAlgorithm(dsc); + // const tree = getCSCAModulusMerkleTree(); @@ -51,39 +55,40 @@ export function generateCircuitInputsRegister( // } // } - 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.`); + + const supportedAlgorithms = [ + { signatureAlgorithm: 'rsa', hashFunction: 'sha1' }, + { signatureAlgorithm: 'rsa', hashFunction: 'sha256' }, + { signatureAlgorithm: 'rsapss', hashFunction: 'sha256' }, + { signatureAlgorithm: 'ecdsa', hashFunction: 'sha1' }, + { signatureAlgorithm: 'ecdsa', hashFunction: 'sha256' }, + ]; + + const isSupported = supportedAlgorithms.some( + (alg) => alg.signatureAlgorithm === signatureAlgorithm && alg.hashFunction === hashFunction + ); + + if (!isSupported) { + throw new Error(`Verification of ${signatureAlgorithm} with ${hashFunction} has not been implemented.`); } - const hashLen = getHashLen(signatureAlgorithm); const formattedMrz = formatMrz(mrz); - const mrzHash = hash(signatureAlgorithm, formattedMrz); + const mrzHash = hash(hashFunction, 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); + const concatHash = hash(hashFunction, dataGroupHashes); assert( 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}`); @@ -109,9 +114,8 @@ export function generateCircuitInputsRegister( let signatureComponents: any; let dscModulusComponents: any; - if (signatureAlgorithm.startsWith('ecdsa-with-')) { - const curve_params = pubKey.publicKeyQ.replace(/[()]/g, '').split(','); - const { r, s } = extractRSFromSignature(passportData.encryptedDigest); + if (signatureAlgorithm === 'ecdsa') { + const { r, s } = extractRSFromSignature(encryptedDigest); signatureComponents = { signature_r: BigintToArray(n_dsc, k_dsc, BigInt(hexToDecimal(r))), @@ -119,13 +123,13 @@ export function generateCircuitInputsRegister( }; dscModulusComponents = { - dsc_modulus_x: BigintToArray(n_dsc, k_dsc, BigInt(hexToDecimal(curve_params[0]))), - dsc_modulus_y: BigintToArray(n_dsc, k_dsc, BigInt(hexToDecimal(curve_params[1]))) + dsc_modulus_x: BigintToArray(n_dsc, k_dsc, BigInt(hexToDecimal(x))), + dsc_modulus_y: BigintToArray(n_dsc, k_dsc, BigInt(hexToDecimal(y))) }; } else { signatureComponents = { signature: splitToWords( - BigInt(bytesToBigDecimal(passportData.encryptedDigest)), + BigInt(bytesToBigDecimal(encryptedDigest)), BigInt(n_dsc), BigInt(k_dsc) ) @@ -133,13 +137,15 @@ export function generateCircuitInputsRegister( dscModulusComponents = { dsc_modulus: splitToWords( - BigInt(passportData.pubKey.modulus as string), + BigInt(hexToDecimal(modulus as string)), BigInt(n_dsc), BigInt(k_dsc) ) }; } + console.log(signatureComponents); + console.log(dscModulusComponents); return { secret: [secret], mrz: formattedMrz.map((byte) => String(byte)), diff --git a/common/src/utils/handleCertificate.ts b/common/src/utils/handleCertificate.ts index e88d3d62..68898c27 100644 --- a/common/src/utils/handleCertificate.ts +++ b/common/src/utils/handleCertificate.ts @@ -1,6 +1,8 @@ import * as asn1 from 'asn1js'; import { Certificate } from 'pkijs'; -import { vkey_prove_rsa_65537_sha256 } from '../constants/vkey'; +import { getHashLen } from './utils'; +import { getNamedCurve } from '../../../registry/src/utils/curves'; +import elliptic from 'elliptic'; export const getSignatureAlgorithm = (pemContent: string) => { const certBuffer = Buffer.from(pemContent.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''), 'base64'); @@ -8,7 +10,41 @@ export const getSignatureAlgorithm = (pemContent: string) => { const cert = new Certificate({ schema: asn1Data.result }); const signatureAlgorithmOid = cert.signatureAlgorithm.algorithmId; const { signatureAlgorithm, hashFunction } = getSignatureAlgorithmDetails(signatureAlgorithmOid); - return { signatureAlgorithm, hashFunction }; + const hashLen = getHashLen(hashFunction); + + let publicKeyDetails; + if (signatureAlgorithm === 'ecdsa') { + const subjectPublicKeyInfo = cert.subjectPublicKeyInfo; + const algorithmParams = subjectPublicKeyInfo.algorithm.algorithmParams; + const curveOid = asn1.fromBER(algorithmParams.valueBeforeDecode).result.valueBlock.toString(); + const curve = getNamedCurve(curveOid); + + // const publicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex; + // console.log("publicKeyBuffer", publicKeyBuffer); + // const x = publicKeyBuffer.slice(2, 34); // Adjusted to slice correctly for x + // const y = publicKeyBuffer.slice(34, 66); // Adjusted to slice correctly for y + // publicKeyDetails = { curve, x: Buffer.from(x).toString('hex'), y: Buffer.from(y).toString('hex') }; + + const publicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView; + const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384'; + const ec = new elliptic.ec(curveForElliptic); + const key = ec.keyFromPublic(publicKeyBuffer); + console.log(key); + const x = key.getPublic().getX().toString('hex'); + const y = key.getPublic().getY().toString('hex'); + console.log(`Size of x: ${Buffer.byteLength(x, 'hex')} bytes`); + console.log(`Size of y: ${Buffer.byteLength(y, 'hex')} bytes`); + publicKeyDetails = { curve, x, y }; + } else { + const publicKey = cert.subjectPublicKeyInfo.subjectPublicKey; + const asn1PublicKey = asn1.fromBER(publicKey.valueBlock.valueHexView); + const rsaPublicKey = asn1PublicKey.result.valueBlock; + const modulus = Buffer.from((rsaPublicKey as any).value[0].valueBlock.valueHexView).toString('hex'); + const exponent = Buffer.from((rsaPublicKey as any).value[1].valueBlock.valueHexView).toString('hex'); + publicKeyDetails = { modulus, exponent }; + } + console.log(publicKeyDetails); + return { signatureAlgorithm, hashFunction, hashLen, ...publicKeyDetails }; } export const getCircuitName = (circuitType: string, signatureAlgorithm: string, hashFunction: string) => { diff --git a/common/src/utils/types.ts b/common/src/utils/types.ts index 0fceefb9..e765061e 100644 --- a/common/src/utils/types.ts +++ b/common/src/utils/types.ts @@ -1,6 +1,6 @@ export type PassportData = { mrz: string; - signatureAlgorithm: string; + signatureAlgorithm?: string; dsc?: string; pubKey?: { modulus?: string, exponent?: string, curveName?: string, publicKeyQ?: string }; dataGroupHashes: number[]; diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts index acd80e7a..a642487b 100644 --- a/common/src/utils/utils.ts +++ b/common/src/utils/utils.ts @@ -1,7 +1,7 @@ import { LeanIMT } from '@zk-kit/lean-imt'; import { sha256 } from 'js-sha256'; import { sha1 } from 'js-sha1'; -import { sha384 } from 'js-sha512'; +import { sha384, sha512_256 } from 'js-sha512'; import { SMT } from '@ashpect/smt'; import forge from 'node-forge'; @@ -184,26 +184,22 @@ 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[]): number[] { +export function hash(hasFunction: string, bytesArray: number[]): number[] { const unsignedBytesArray = bytesArray.map((byte) => byte & 0xff); let hashResult: string; - switch (signatureAlgorithm) { - case 'sha1WithRSAEncryption': + switch (hasFunction) { + case 'sha1': hashResult = sha1(unsignedBytesArray); break; - case 'SHA384withECDSA': - hashResult = sha384(unsignedBytesArray); - break; - case 'sha256WithRSAEncryption': + case 'sha256': hashResult = sha256(unsignedBytesArray); break; - case 'sha256WithRSASSAPSS': - hashResult = sha256(unsignedBytesArray); + case 'sha384': + hashResult = sha384(unsignedBytesArray); break; - case 'ecdsa-with-SHA1': - hashResult = sha1(unsignedBytesArray); + case 'sha512': + hashResult = sha512_256(unsignedBytesArray); break; default: hashResult = sha256(unsignedBytesArray); // Default to sha256 @@ -273,23 +269,18 @@ export function getCurrentDateYYMMDD(dayDiff: number = 0): number[] { return Array.from(yymmdd).map((char) => parseInt(char)); } -export function getHashLen(signatureAlgorithm: string) { - switch (signatureAlgorithm) { - case 'sha1WithRSAEncryption': - case 'ecdsa-with-SHA1': +export function getHashLen(hashFunction: string) { + switch (hashFunction) { + case 'sha1': return 20; - case 'sha256WithRSAEncryption': - case 'rsassaPss': - case 'ecdsa-with-SHA256': + case 'sha256': return 32; - case 'sha384WithRSAEncryption': - case 'ecdsa-with-SHA384': + case 'sha384': return 48; - case 'sha512WithRSAEncryption': - case 'ecdsa-with-SHA512': + case 'sha512': return 64; default: - console.log(`${signatureAlgorithm} not found in getHashLen`); + console.log(`${hashFunction} not found in getHashLen`); return 32; } } diff --git a/common/tests/genMockPassportData.test.ts b/common/tests/genMockPassportData.test.ts new file mode 100644 index 00000000..818d3624 --- /dev/null +++ b/common/tests/genMockPassportData.test.ts @@ -0,0 +1,85 @@ +import { assert, expect } from 'chai'; +import { describe, it } from 'mocha'; +import { genMockPassportData } from '../src/utils/genMockPassportData'; +import * as forge from 'node-forge'; +import { PassportData } from '../src/utils/types'; +import { formatMrz, hash, arraysAreEqual, findSubarrayIndex } from '../src/utils/utils'; +import { getSignatureAlgorithm } from '../src/utils/handleCertificate'; +import * as asn1 from 'asn1js'; +import { Certificate } from 'pkijs'; +import elliptic from 'elliptic'; + +export type SignatureAlgorithm = 'rsa_sha1' | 'rsa_sha256' | 'rsapss_sha256' | 'ecdsa_sha256' | 'ecdsa_sha1' | 'ecdsa_sha384'; + +const sigAlgs: SignatureAlgorithm[] = [ + 'rsa_sha1', + 'rsa_sha256', + 'rsapss_sha256', + 'ecdsa_sha256', + 'ecdsa_sha1', + 'ecdsa_sha384', +]; + +describe('Mock Passport Data Generator', function () { + this.timeout(0); + + sigAlgs.forEach(sigAlg => { + it(`should generate valid passport data for ${sigAlg}`, () => { + const passportData = genMockPassportData(sigAlg, 'FRA', '000101', '300101'); + expect(passportData).to.exist; + expect(verify(passportData)).to.be.true; + }); + }); +}); + +function verify(passportData: PassportData): boolean { + const { mrz, dsc, dataGroupHashes, eContent, encryptedDigest } = passportData; + const { signatureAlgorithm, hashFunction, hashLen, curve } = getSignatureAlgorithm(dsc); + const formattedMrz = formatMrz(mrz); + const mrzHash = hash(hashFunction, formattedMrz); + const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash) + assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes'); + + const concatHash = hash(hashFunction, dataGroupHashes) + assert( + arraysAreEqual( + concatHash, + eContent.slice(eContent.length - hashLen) + ), + 'concatHash is not at the right place in eContent' + ); + + if (signatureAlgorithm === 'ecdsa') { + const certBuffer = Buffer.from(dsc.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''), 'base64'); + const asn1Data = asn1.fromBER(certBuffer); + const cert = new Certificate({ schema: asn1Data.result }); + const publicKeyInfo = cert.subjectPublicKeyInfo; + const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView; + const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384'; + const ec = new elliptic.ec(curveForElliptic); + + const key = ec.keyFromPublic(publicKeyBuffer); + const eContentHash = hash(hashFunction, eContent); + const signature = Buffer.from(encryptedDigest).toString('hex'); + return key.verify(eContentHash, signature); + } else { + const cert = forge.pki.certificateFromPem(dsc); + const publicKey = cert.publicKey as forge.pki.rsa.PublicKey; + + const md = forge.md[hashFunction].create(); + md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); + + const signature = Buffer.from(encryptedDigest).toString('binary'); + + if (signatureAlgorithm === 'rsapss') { + const pss = forge.pss.create({ + md: forge.md[hashFunction].create(), + mgf: forge.mgf.mgf1.create(forge.md[hashFunction].create()), + saltLength: hashLen + }); + return publicKey.verify(md.digest().bytes(), signature, pss); + } else { + return publicKey.verify(md.digest().bytes(), signature); + } + } +} diff --git a/common/yarn-error.log b/common/yarn-error.log deleted file mode 100644 index 845c0307..00000000 --- a/common/yarn-error.log +++ /dev/null @@ -1,150 +0,0 @@ -Arguments: - /Users/remicolin/.nvm/versions/node/v20.11.1/bin/node /opt/homebrew/Cellar/yarn/1.22.19/libexec/bin/yarn.js add path jrrsasign asn1.js - -PATH: - /Users/remicolin/.nvm/versions/node/v20.11.1/bin:/Users/remicolin/.gem/ruby/3.1.3/bin:/Users/remicolin/.rubies/ruby-3.1.3/lib/ruby/gems/3.1.0/bin:/Users/remicolin/.rubies/ruby-3.1.3/bin:/Users/remicolin/.jenv/shims:/Users/remicolin/.jenv/bin:/Users/remicolin/.cairo/target/release:/Library/Frameworks/Python.framework/Versions/3.9/bin:/Library/Frameworks/Python.framework/Versions/3.11/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Library/Apple/usr/bin:/Users/remicolin/.nvm/versions/node/v20.11.1/bin:/Users/remicolin/.jenv/shims:/Users/remicolin/.jenv/bin:/Users/remicolin/.cairo/target/release:/Library/Frameworks/Python.framework/Versions/3.9/bin:/Library/Frameworks/Python.framework/Versions/3.11/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/Users/remicolin/.cargo/bin:/Users/remicolin/.foundry/bin:/Users/remicolin/Library/Android/sdk/platform-tools:/Users/remicolin/.foundry/bin:/Users/remicolin/Library/Android/sdk/platform-tools - -Yarn version: - 1.22.19 - -Node version: - 20.11.1 - -Platform: - darwin arm64 - -Trace: - Error: https://registry.yarnpkg.com/jrrsasign: Not found - at params.callback [as _callback] (/opt/homebrew/Cellar/yarn/1.22.19/libexec/lib/cli.js:66145:18) - at self.callback (/opt/homebrew/Cellar/yarn/1.22.19/libexec/lib/cli.js:140890:22) - at Request.emit (node:events:518:28) - at Request. (/opt/homebrew/Cellar/yarn/1.22.19/libexec/lib/cli.js:141862:10) - at Request.emit (node:events:518:28) - at IncomingMessage. (/opt/homebrew/Cellar/yarn/1.22.19/libexec/lib/cli.js:141784:12) - at Object.onceWrapper (node:events:632:28) - at IncomingMessage.emit (node:events:530:35) - at endReadableNT (node:internal/streams/readable:1696:12) - at process.processTicksAndRejections (node:internal/process/task_queues:82:21) - -npm manifest: - { - "dependencies": { - "@babel/runtime": "^7.23.4", - "@zk-kit/imt": "https://gitpkg.now.sh/0xturboblitz/zk-kit/packages/imt?6d417675", - "@zk-kit/lean-imt": "^2.0.1", - "fs": "^0.0.1-security", - "js-sha1": "^0.7.0", - "js-sha256": "^0.10.1", - "js-sha512": "^0.9.0", - "node-forge": "^1.3.1", - "poseidon-lite": "^0.2.0" - }, - "devDependencies": { - "@types/node-forge": "^1.3.10" - } - } - -yarn manifest: - No manifest - -Lockfile: - # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. - # yarn lockfile v1 - - - "@babel/runtime@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.4.tgz#36fa1d2b36db873d25ec631dcc4923fdc1cf2e2e" - integrity sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg== - dependencies: - regenerator-runtime "^0.14.0" - - "@types/node-forge@^1.3.10": - version "1.3.10" - resolved "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.10.tgz" - integrity sha512-y6PJDYN4xYBxwd22l+OVH35N+1fCYWiuC3aiP2SlXVE6Lo7SS+rSx9r89hLxrP4pn6n1lBGhHJ12pj3F3Mpttw== - dependencies: - "@types/node" "*" - - "@types/node@*": - version "20.10.0" - resolved "https://registry.npmjs.org/@types/node/-/node-20.10.0.tgz" - integrity sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ== - dependencies: - undici-types "~5.26.4" - - "@zk-kit/imt@https://gitpkg.now.sh/0xturboblitz/zk-kit/packages/imt?6d417675": - version "2.0.0-beta.1" - resolved "https://gitpkg.now.sh/0xturboblitz/zk-kit/packages/imt?6d417675#38244ea6eef75dc1ad7fff3ff2a22dd5f1a2593a" - - "@zk-kit/lean-imt@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@zk-kit/lean-imt/-/lean-imt-2.0.1.tgz#78af48b384b083e4a3f003036a40a4ea3cb102c0" - integrity sha512-yc0rh9BCY6VvvKrZUNejfucuWscy1iRb9JrppuJktsiA9HcEukB3oX9CB7N/CUmCtqzmdwybet6N2aglGL/SUQ== - dependencies: - "@zk-kit/utils" "1.0.0" - - "@zk-kit/utils@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@zk-kit/utils/-/utils-1.0.0.tgz#db1af01a4e60f5290734a26c2fd9e863bff049e3" - integrity sha512-v5UjrZiaRNAN2UJmTFHvlMktaA2Efc2qN1Mwd4060ExX12yRhY8ZhzdlDODhnuHkvW5zPukuBHgQhHMScNP3Pg== - dependencies: - buffer "^6.0.3" - - base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - - buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - - fs@^0.0.1-security: - version "0.0.1-security" - resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" - integrity sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w== - - ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - - js-sha1@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/js-sha1/-/js-sha1-0.7.0.tgz#fecaf5f36bb09a51b01da46b43a207c8452c9c1e" - integrity sha512-oQZ1Mo7440BfLSv9TX87VNEyU52pXPVG19F9PL3gTgNt0tVxlZ8F4O6yze3CLuLx28TxotxvlyepCNaaV0ZjMw== - - js-sha256@^0.10.1: - version "0.10.1" - resolved "https://registry.npmjs.org/js-sha256/-/js-sha256-0.10.1.tgz" - integrity sha512-5obBtsz9301ULlsgggLg542s/jqtddfOpV5KJc4hajc9JV8GeY2gZHSVpYBn4nWqAUTJ9v+xwtbJ1mIBgIH5Vw== - - js-sha512@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/js-sha512/-/js-sha512-0.9.0.tgz#ed569aa1e4bdaf0b83363c29db1ab87b1192d9ae" - integrity sha512-mirki9WS/SUahm+1TbAPkqvbCiCfOAAsyXeHxK1UkullnJVVqoJG2pL9ObvT05CN+tM7fxhfYm0NbXn+1hWoZg== - - node-forge@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== - - poseidon-lite@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/poseidon-lite/-/poseidon-lite-0.2.0.tgz#dbc242ebd9c10c32d507a533fa497231d168fd72" - integrity sha512-vivDZnGmz8W4G/GzVA72PXkfYStjilu83rjjUfpL4PueKcC8nfX6hCPh2XhoC5FBgC6y0TA3YuUeUo5YCcNoig== - - regenerator-runtime@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" - integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== - - undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== diff --git a/common/yarn.lock b/common/yarn.lock index f4006359..a2c29ebd 100644 --- a/common/yarn.lock +++ b/common/yarn.lock @@ -18,6 +18,11 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + "@types/node-forge@^1.3.10": version "1.3.10" resolved "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.10.tgz" @@ -57,6 +62,36 @@ dependencies: buffer "^6.0.3" +ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + array-buffer-byte-length@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" @@ -104,6 +139,11 @@ arraybuffer.prototype.slice@^1.0.3: is-array-buffer "^3.0.4" is-shared-array-buffer "^1.0.2" +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== + asn1.js@^5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" @@ -123,6 +163,11 @@ asn1js@^3.0.5: pvutils "^1.1.3" tslib "^2.4.0" +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -144,21 +189,55 @@ axios@^1.7.2: form-data "^4.0.0" proxy-from-env "^1.1.0" +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + bn.js@^4.0.0, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== +browser-stdout@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +buffer-from@^1.0.0, buffer-from@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -183,6 +262,75 @@ call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bin get-intrinsic "^1.2.4" set-function-length "^1.2.1" +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +chai@^4.3.8: + version "4.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" + integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.1.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -217,6 +365,25 @@ data-view-byte-offset@^1.0.0: es-errors "^1.3.0" is-data-view "^1.0.1" +debug@^4.3.5: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +deep-eql@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" + integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== + dependencies: + type-detect "^4.0.0" + define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" @@ -240,6 +407,16 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +diff@^3.1.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +diff@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + elliptic@^6.5.5: version "6.5.5" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded" @@ -253,6 +430,11 @@ elliptic@^6.5.5: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + es-abstract@^1.17.0-next.1, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: version "1.23.3" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" @@ -362,6 +544,36 @@ es7-shim@^6.0.0: string.prototype.trimleft "^2.0.0" string.prototype.trimright "^2.0.0" +escalade@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + follow-redirects@^1.15.6: version "1.15.6" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" @@ -383,11 +595,21 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + fs@^0.0.1-security: version "0.0.1-security" resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" integrity sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w== +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" @@ -408,6 +630,16 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" @@ -428,6 +660,24 @@ get-symbol-description@^1.0.2: es-errors "^1.3.0" get-intrinsic "^1.2.4" +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + globalthis@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" @@ -448,6 +698,11 @@ has-bigints@^1.0.1, has-bigints@^1.0.2: resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" @@ -487,6 +742,11 @@ hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: dependencies: function-bind "^1.1.2" +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -501,16 +761,24 @@ ieee754@^1.2.1: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" -inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + internal-slot@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" @@ -535,6 +803,13 @@ is-bigint@^1.0.1: dependencies: has-bigints "^1.0.1" +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-boolean-object@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" @@ -562,6 +837,23 @@ is-date-object@^1.0.1: dependencies: has-tostringtag "^1.0.0" +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-negative-zero@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" @@ -574,6 +866,16 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -610,6 +912,11 @@ is-typed-array@^1.1.13: dependencies: which-typed-array "^1.1.14" +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -637,6 +944,13 @@ js-sha512@^0.9.0: resolved "https://registry.yarnpkg.com/js-sha512/-/js-sha512-0.9.0.tgz#ed569aa1e4bdaf0b83363c29db1ab87b1192d9ae" integrity sha512-mirki9WS/SUahm+1TbAPkqvbCiCfOAAsyXeHxK1UkullnJVVqoJG2pL9ObvT05CN+tM7fxhfYm0NbXn+1hWoZg== +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + json-to-ts@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/json-to-ts/-/json-to-ts-2.1.0.tgz#c68c0b210a811e8dccbe2752e68efbc0ca62bfc5" @@ -646,11 +960,25 @@ json-to-ts@^2.1.0: hash.js "^1.0.3" pluralize "^3.1.0" +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + jsrsasign@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/jsrsasign/-/jsrsasign-11.1.0.tgz#195e788102731102fbf3e36b33fde28936f4bf57" integrity sha512-Ov74K9GihaK9/9WncTe1mPmvrO7Py665TUfUKvraXBpu+xcTWitrtuOwcjf4KMU9maPaYn0OuaWy0HOzy/GBXg== +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash-es@^4.17.10: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" @@ -661,6 +989,26 @@ lodash@^4.17.10: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -683,10 +1031,65 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== +minimatch@^5.0.1, minimatch@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mocha@^10.7.3: + version "10.7.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.7.3.tgz#ae32003cabbd52b59aece17846056a68eb4b0752" + integrity sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + "node-forge@https://github.com/remicolin/forge": version "1.3.2-0" resolved "https://github.com/remicolin/forge#17a11a632dd0e50343b3b8393245a2696f78afbb" +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + object-inspect@^1.13.1: version "1.13.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" @@ -738,6 +1141,32 @@ object.values@^1.0.3: define-properties "^1.2.1" es-object-atoms "^1.0.0" +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path@^0.12.7: version "0.12.7" resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" @@ -746,6 +1175,16 @@ path@^0.12.7: process "^0.11.1" util "^0.10.3" +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + pkijs@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/pkijs/-/pkijs-3.2.4.tgz#55ed72b363a20fbd42b139ee3b72e54483635171" @@ -795,6 +1234,20 @@ pvutils@^1.1.3: resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + regenerator-runtime@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" @@ -810,6 +1263,11 @@ regexp.prototype.flags@^1.5.2: es-errors "^1.3.0" set-function-name "^2.0.1" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + safe-array-concat@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" @@ -820,6 +1278,11 @@ safe-array-concat@^1.1.2: has-symbols "^1.0.3" isarray "^2.0.5" +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex-test@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" @@ -834,6 +1297,13 @@ safer-buffer@^2.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + set-function-length@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" @@ -866,6 +1336,19 @@ side-channel@^1.0.4: get-intrinsic "^1.2.4" object-inspect "^1.13.1" +source-map-support@^0.5.6: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + string-at@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/string-at/-/string-at-1.1.0.tgz#332e090c5724418266a27a09394924b9fad41275" @@ -874,6 +1357,15 @@ string-at@^1.0.1: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string.prototype.padend@^3.0.0: version "3.1.6" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz#ba79cf8992609a91c872daa47c6bb144ee7f62a5" @@ -940,6 +1432,77 @@ string.prototype.trimstart@^1.0.3, string.prototype.trimstart@^1.0.8: define-properties "^1.2.1" es-object-atoms "^1.0.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-mocha@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-10.0.0.tgz#41a8d099ac90dbbc64b06976c5025ffaebc53cb9" + integrity sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw== + dependencies: + ts-node "7.0.1" + optionalDependencies: + tsconfig-paths "^3.5.0" + +ts-node@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" + integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== + dependencies: + arrify "^1.0.0" + buffer-from "^1.1.0" + diff "^3.1.0" + make-error "^1.1.1" + minimist "^1.2.0" + mkdirp "^0.5.1" + source-map-support "^0.5.6" + yn "^2.0.0" + +tsconfig-paths@^3.5.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -950,6 +1513,11 @@ tslib@^2.4.0, tslib@^2.6.1, tslib@^2.6.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== +type-detect@^4.0.0, type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== + typed-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" @@ -1052,3 +1620,65 @@ which-typed-array@^1.1.14, which-typed-array@^1.1.15: for-each "^0.3.3" gopd "^1.0.1" has-tostringtag "^1.0.2" + +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@^20.2.2, yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + integrity sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From 7e5c337a50c1c8bf504a1a5cd0ad7e503fa5a98f Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 11:37:44 +0900 Subject: [PATCH 02/18] fix ecdsa --- common/src/utils/genMockPassportData.ts | 9 ++++----- common/src/utils/handleCertificate.ts | 9 --------- common/tests/genMockPassportData.test.ts | 9 ++++++--- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/common/src/utils/genMockPassportData.ts b/common/src/utils/genMockPassportData.ts index 837ff196..7764e8e0 100644 --- a/common/src/utils/genMockPassportData.ts +++ b/common/src/utils/genMockPassportData.ts @@ -133,11 +133,10 @@ function sign( const keyPair = ec.keyFromPrivate(privateKeyBuffer); - console.log('privateKeyBuffer', privateKeyBuffer); - - const eContentHash = hash(hashFunction, eContent); - const signature = keyPair.sign(eContentHash); - const signatureBytes = signature.toDER(); + 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')); return signatureBytes; } else { diff --git a/common/src/utils/handleCertificate.ts b/common/src/utils/handleCertificate.ts index 68898c27..72497bc1 100644 --- a/common/src/utils/handleCertificate.ts +++ b/common/src/utils/handleCertificate.ts @@ -19,21 +19,12 @@ export const getSignatureAlgorithm = (pemContent: string) => { const curveOid = asn1.fromBER(algorithmParams.valueBeforeDecode).result.valueBlock.toString(); const curve = getNamedCurve(curveOid); - // const publicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex; - // console.log("publicKeyBuffer", publicKeyBuffer); - // const x = publicKeyBuffer.slice(2, 34); // Adjusted to slice correctly for x - // const y = publicKeyBuffer.slice(34, 66); // Adjusted to slice correctly for y - // publicKeyDetails = { curve, x: Buffer.from(x).toString('hex'), y: Buffer.from(y).toString('hex') }; - const publicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView; const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384'; const ec = new elliptic.ec(curveForElliptic); const key = ec.keyFromPublic(publicKeyBuffer); - console.log(key); const x = key.getPublic().getX().toString('hex'); const y = key.getPublic().getY().toString('hex'); - console.log(`Size of x: ${Buffer.byteLength(x, 'hex')} bytes`); - console.log(`Size of y: ${Buffer.byteLength(y, 'hex')} bytes`); publicKeyDetails = { curve, x, y }; } else { const publicKey = cert.subjectPublicKeyInfo.subjectPublicKey; diff --git a/common/tests/genMockPassportData.test.ts b/common/tests/genMockPassportData.test.ts index 818d3624..66476085 100644 --- a/common/tests/genMockPassportData.test.ts +++ b/common/tests/genMockPassportData.test.ts @@ -8,6 +8,7 @@ import { getSignatureAlgorithm } from '../src/utils/handleCertificate'; import * as asn1 from 'asn1js'; import { Certificate } from 'pkijs'; import elliptic from 'elliptic'; +import * as crypto from 'crypto'; export type SignatureAlgorithm = 'rsa_sha1' | 'rsa_sha256' | 'rsapss_sha256' | 'ecdsa_sha256' | 'ecdsa_sha1' | 'ecdsa_sha384'; @@ -59,9 +60,11 @@ function verify(passportData: PassportData): boolean { const ec = new elliptic.ec(curveForElliptic); const key = ec.keyFromPublic(publicKeyBuffer); - const eContentHash = hash(hashFunction, eContent); - const signature = Buffer.from(encryptedDigest).toString('hex'); - return key.verify(eContentHash, signature); + const messageBuffer = Buffer.from(eContent); + const msgHash = crypto.createHash('sha256').update(messageBuffer).digest(); + 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; From f99f54e35bccd14aee75d2287af1a4af2d535a03 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 11:55:21 +0900 Subject: [PATCH 03/18] factor register tests --- circuits/tests/register/register.test.ts | 19 ++- .../register/register_ecdsa_sha1.test.ts | 120 ------------------ .../register/register_ecdsa_sha256.test.ts | 119 ----------------- common/src/utils/genMockPassportData.ts | 2 +- common/src/utils/generateInputs.ts | 2 - common/src/utils/handleCertificate.ts | 1 - common/tests/genMockPassportData.test.ts | 5 +- 7 files changed, 18 insertions(+), 250 deletions(-) delete mode 100644 circuits/tests/register/register_ecdsa_sha1.test.ts delete mode 100644 circuits/tests/register/register_ecdsa_sha256.test.ts diff --git a/circuits/tests/register/register.test.ts b/circuits/tests/register/register.test.ts index 1d346363..975abc75 100644 --- a/circuits/tests/register/register.test.ts +++ b/circuits/tests/register/register.test.ts @@ -12,11 +12,11 @@ import { getCircuitName, getSignatureAlgorithm } from '../../../common/src/utils import { SignatureAlgorithm } from '../../../common/tests/genMockPassportData.test'; const sigAlgs = [ - // { sigAlg: 'rsa', hashFunction: 'sha1' }, - // { sigAlg: 'rsa', hashFunction: 'sha256' }, - // { sigAlg: 'rsapss', hashFunction: 'sha256' }, + { sigAlg: 'rsa', hashFunction: 'sha1' }, + { sigAlg: 'rsa', hashFunction: 'sha256' }, + { sigAlg: 'rsapss', hashFunction: 'sha256' }, { sigAlg: 'ecdsa', hashFunction: 'sha256' }, - // { sigAlg: 'ecdsa', hashFunction: 'sha1' }, + { sigAlg: 'ecdsa', hashFunction: 'sha1' }, ]; sigAlgs.forEach(({ sigAlg, hashFunction }) => { @@ -69,6 +69,14 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); // const mrz_bytes = packBytes(inputs.mrz); + + // for ecdsa: + + // const leaf = getLeaf({ + // signatureAlgorithm: passportData.signatureAlgorithm, + // publicKeyQ: passportData.pubKey.publicKeyQ, + // }).toString(); + // const commitment_bytes = poseidon6([ // inputs.secret[0], // PASSPORT_ATTESTATION_ID, @@ -115,7 +123,8 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { try { const invalidInputs = { ...inputs, - signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), + signature: inputs.signature ? inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) : undefined, + signature_s: inputs.signature_s ? inputs.signature_s.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) : undefined, }; await circuit.calculateWitness(invalidInputs); expect.fail('Expected an error but none was thrown.'); diff --git a/circuits/tests/register/register_ecdsa_sha1.test.ts b/circuits/tests/register/register_ecdsa_sha1.test.ts deleted file mode 100644 index 17bbb0c0..00000000 --- a/circuits/tests/register/register_ecdsa_sha1.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { describe } from 'mocha'; -import path from 'path'; -import { poseidon6 } from 'poseidon-lite'; -import { mockPassportData_sha1_ecdsa } from '../../../common/src/constants/mockPassportData'; -import { generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs'; -import { BigintToArray, hexToDecimal, packBytes } from '../../../common/src/utils/utils'; -import { expect } from 'chai'; -import { getLeaf } from '../../../common/src/utils/pubkeyTree'; -import { wasm as wasm_tester } from 'circom_tester'; -import { PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; - -describe('Register - SHA1 WITH ECDSA', function () { - this.timeout(0); - let circuit: any; - - const passportData = mockPassportData_sha1_ecdsa; - const n_dsc = 43; // 43 * 6 = 258 > 254 Cirom field size - const k_dsc = 6; - const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - - const inputs = generateCircuitInputsRegister( - secret, - dscSecret, - PASSPORT_ATTESTATION_ID, - passportData, - n_dsc, - k_dsc - ); - - before(async () => { - circuit = await wasm_tester( - path.join(__dirname, '../../circuits/register/register_ecdsa_sha1.circom'), - { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - './node_modules/dmpierre/sha1-circom/circuits', - ], - } - ); - }); - - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); - - it('should calculate the witness with correct inputs', async function () { - const w = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(w); - - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); - const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; - console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); - const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) - .blinded_dsc_commitment; - console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); - - const mrz_bytes = packBytes(inputs.mrz); - const leaf = getLeaf({ - signatureAlgorithm: passportData.signatureAlgorithm, - publicKeyQ: passportData.pubKey.publicKeyQ, - }).toString(); - - const commitment_bytes = poseidon6([ - inputs.secret[0], - PASSPORT_ATTESTATION_ID, - leaf, - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2], - ]); - const commitment_js = commitment_bytes.toString(); - expect(commitment_circom).to.be.equal(commitment_js); - }); - - it('should fail to calculate witness with invalid dataHashes', async function () { - try { - const invalidInputs = { - ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - mrz: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid signature', async function () { - let wrong_signature_s = BigintToArray(43, 6, BigInt(hexToDecimal('10') + 1)); - try { - const invalidInputs = { - ...inputs, - signature_s: wrong_signature_s, - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); -}); diff --git a/circuits/tests/register/register_ecdsa_sha256.test.ts b/circuits/tests/register/register_ecdsa_sha256.test.ts deleted file mode 100644 index 09e1b487..00000000 --- a/circuits/tests/register/register_ecdsa_sha256.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { describe } from 'mocha'; -import path from 'path'; -import { poseidon6 } from 'poseidon-lite'; -import { mockPassportData_sha256_ecdsa } from '../../../common/src/constants/mockPassportData'; -import { generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs'; -import { BigintToArray, hexToDecimal, packBytes } from '../../../common/src/utils/utils'; -import { expect } from 'chai'; -import { getLeaf } from '../../../common/src/utils/pubkeyTree'; -import { wasm as wasm_tester } from 'circom_tester'; -import { PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; - -describe('Register - SHA256 WITH ECDSA', function () { - this.timeout(0); - let circuit: any; - - const passportData = mockPassportData_sha256_ecdsa; - const n_dsc = 43; // 43 * 6 = 258 > 254 Cirom field size - const k_dsc = 6; - const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - - const inputs = generateCircuitInputsRegister( - secret, - dscSecret, - PASSPORT_ATTESTATION_ID, - passportData, - n_dsc, - k_dsc - ); - - before(async () => { - circuit = await wasm_tester( - path.join(__dirname, '../../circuits/register/register_ecdsa_sha256.circom'), - { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - } - ); - }); - - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); - - it('should calculate the witness with correct inputs', async function () { - const w = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(w); - - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); - const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; - console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); - const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) - .blinded_dsc_commitment; - console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); - - const mrz_bytes = packBytes(inputs.mrz); - const leaf = getLeaf({ - signatureAlgorithm: passportData.signatureAlgorithm, - publicKeyQ: passportData.pubKey.publicKeyQ, - }).toString(); - - const commitment_bytes = poseidon6([ - inputs.secret[0], - PASSPORT_ATTESTATION_ID, - leaf, - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2], - ]); - const commitment_js = commitment_bytes.toString(); - expect(commitment_circom).to.be.equal(commitment_js); - }); - - it('should fail to calculate witness with invalid dataHashes', async function () { - try { - const invalidInputs = { - ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - mrz: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid signature', async function () { - let wrong_signature_s = BigintToArray(43, 6, BigInt(hexToDecimal('10') + 1)); - try { - const invalidInputs = { - ...inputs, - signature_s: wrong_signature_s, - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); -}); diff --git a/common/src/utils/genMockPassportData.ts b/common/src/utils/genMockPassportData.ts index 7764e8e0..5e52a7aa 100644 --- a/common/src/utils/genMockPassportData.ts +++ b/common/src/utils/genMockPassportData.ts @@ -133,7 +133,7 @@ function sign( const keyPair = ec.keyFromPrivate(privateKeyBuffer); - const md = forge.md.sha256.create(); + const md = hashFunction === 'sha1' ? forge.md.sha1.create() : 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')); diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index b2410f4f..ed35bdd2 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -144,8 +144,6 @@ export function generateCircuitInputsRegister( }; } - console.log(signatureComponents); - console.log(dscModulusComponents); return { secret: [secret], mrz: formattedMrz.map((byte) => String(byte)), diff --git a/common/src/utils/handleCertificate.ts b/common/src/utils/handleCertificate.ts index 72497bc1..ea4abd33 100644 --- a/common/src/utils/handleCertificate.ts +++ b/common/src/utils/handleCertificate.ts @@ -34,7 +34,6 @@ export const getSignatureAlgorithm = (pemContent: string) => { const exponent = Buffer.from((rsaPublicKey as any).value[1].valueBlock.valueHexView).toString('hex'); publicKeyDetails = { modulus, exponent }; } - console.log(publicKeyDetails); return { signatureAlgorithm, hashFunction, hashLen, ...publicKeyDetails }; } diff --git a/common/tests/genMockPassportData.test.ts b/common/tests/genMockPassportData.test.ts index 66476085..802341a6 100644 --- a/common/tests/genMockPassportData.test.ts +++ b/common/tests/genMockPassportData.test.ts @@ -60,8 +60,9 @@ function verify(passportData: PassportData): boolean { const ec = new elliptic.ec(curveForElliptic); const key = ec.keyFromPublic(publicKeyBuffer); - const messageBuffer = Buffer.from(eContent); - const msgHash = crypto.createHash('sha256').update(messageBuffer).digest(); + const md = hashFunction === 'sha1' ? forge.md.sha1.create() : forge.md.sha256.create(); + md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); + const msgHash = md.digest().toHex() const signature_crypto = Buffer.from(encryptedDigest).toString('hex'); return key.verify(msgHash, signature_crypto); From 7288bab5263c385692e85b65c2123e9e5e78d707 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 12:05:25 +0900 Subject: [PATCH 04/18] simplify splitToWords, remove BigintToArray --- common/src/utils/csca.ts | 12 ++++++------ common/src/utils/generateInputs.ts | 18 ++++++++---------- common/src/utils/pubkeyTree.ts | 8 ++++---- common/src/utils/utils.ts | 23 ++++------------------- sdk/src/OpenPassport1Step.ts | 2 +- 5 files changed, 23 insertions(+), 40 deletions(-) diff --git a/common/src/utils/csca.ts b/common/src/utils/csca.ts index 7bd50473..d82fdc76 100644 --- a/common/src/utils/csca.ts +++ b/common/src/utils/csca.ts @@ -53,7 +53,7 @@ export function getCSCAInputs(dscSecret: string, dscCertificate: any, cscaCertif const csca_modulus = rsaPublicKey.n.toString(16).toLowerCase(); //console.log('csca_modulus', csca_modulus); csca_modulus_bigint = BigInt(`0x${csca_modulus}`); - csca_modulus_formatted = splitToWords(csca_modulus_bigint, BigInt(n_csca), BigInt(k_csca)); + csca_modulus_formatted = splitToWords(csca_modulus_bigint, n_csca, k_csca); //console.log('csca_modulus_formatted', csca_modulus_formatted); @@ -75,7 +75,7 @@ export function getCSCAInputs(dscSecret: string, dscCertificate: any, cscaCertif const csca_modulus = CSCA_AKI_MODULUS[formattedValueAdjusted as keyof typeof CSCA_AKI_MODULUS]; const csca_modulus_cleaned = csca_modulus.replace(/:/g, ''); csca_modulus_bigint = BigInt(`0x${csca_modulus_cleaned}`); - csca_modulus_formatted = splitToWords(csca_modulus_bigint, BigInt(n_csca), BigInt(k_csca)); + csca_modulus_formatted = splitToWords(csca_modulus_bigint, n_csca, k_csca); //console.log('CSCA modulus as bigint:', csca_modulus_bigint); //console.log('CSCA modulus extracted from json:', csca_modulus_formatted); } @@ -90,12 +90,12 @@ export function getCSCAInputs(dscSecret: string, dscCertificate: any, cscaCertif //console.log('dsc_modulus_bytes_array', dsc_modulus_bytes_array); const dsc_modulus_bytes_array_formatted = dsc_modulus_bytes_array.map(byte => byte.toString()); const dsc_modulus_number = BigInt(`0x${dsc_modulus}`); - const dsc_modulus_formatted = splitToWords(dsc_modulus_number, BigInt(n_dsc), BigInt(k_dsc)); + const dsc_modulus_formatted = splitToWords(dsc_modulus_number, n_dsc, k_dsc); const dsc_signature = dscCertificate.signature; const dsc_signature_hex = Buffer.from(dsc_signature, 'binary').toString('hex'); const dsc_signature_bigint = BigInt('0x' + dsc_signature_hex); - const dsc_signature_formatted = splitToWords(dsc_signature_bigint, BigInt(n_csca), BigInt(k_csca)); + const dsc_signature_formatted = splitToWords(dsc_signature_bigint, n_csca, k_csca); //const formatted_dsc_signature = dsc_signature.map(byte => byte.toString(16).padStart(2, '0').toUpperCase()).join(':'); @@ -188,7 +188,7 @@ export function computeLeafFromModulusFormatted(modulus_formatted: string[]) { } export function computeLeafFromModulusBigInt(modulus_bigint: bigint) { if (modulus_bigint <= BigInt(2n ** 4096n - 1n)) { - const modulus_formatted = splitToWords(modulus_bigint, BigInt(64), BigInt(64)); + const modulus_formatted = splitToWords(modulus_bigint, 64, 64); const hashInputs = new Array(4); for (let i = 0; i < 4; i++) { hashInputs[i] = new Array(16).fill(BigInt(0)); @@ -232,7 +232,7 @@ export function getTBSHash(cert: forge.pki.Certificate, hashAlgorithm: 'sha1' | const tbsCertificateHashHex = Buffer.from(tbsCertificateHashString, 'binary').toString('hex'); const tbsCertificateHashBigint = BigInt(`0x${tbsCertificateHashHex}`); console.log('tbsCertificateHashBigint', tbsCertificateHashBigint); - return splitToWords(tbsCertificateHashBigint, BigInt(n), BigInt(k)); + return splitToWords(tbsCertificateHashBigint, n, k); } diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index ed35bdd2..505fb6f6 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -8,13 +8,11 @@ import { hash, splitToWords, toUnsignedByte, - getHashLen, getCurrentDateYYMMDD, generateMerkleProof, generateSMTProof, findSubarrayIndex, hexToDecimal, - BigintToArray, extractRSFromSignature, castFromUUID, castFromScope, @@ -118,28 +116,28 @@ export function generateCircuitInputsRegister( const { r, s } = extractRSFromSignature(encryptedDigest); signatureComponents = { - signature_r: BigintToArray(n_dsc, k_dsc, BigInt(hexToDecimal(r))), - signature_s: BigintToArray(n_dsc, k_dsc, BigInt(hexToDecimal(s))) + signature_r: splitToWords(BigInt(hexToDecimal(r)), n_dsc, k_dsc), + signature_s: splitToWords(BigInt(hexToDecimal(s)), n_dsc, k_dsc) }; dscModulusComponents = { - dsc_modulus_x: BigintToArray(n_dsc, k_dsc, BigInt(hexToDecimal(x))), - dsc_modulus_y: BigintToArray(n_dsc, k_dsc, BigInt(hexToDecimal(y))) + dsc_modulus_x: splitToWords(BigInt(hexToDecimal(x)), n_dsc, k_dsc), + dsc_modulus_y: splitToWords(BigInt(hexToDecimal(y)), n_dsc, k_dsc) }; } else { signatureComponents = { signature: splitToWords( BigInt(bytesToBigDecimal(encryptedDigest)), - BigInt(n_dsc), - BigInt(k_dsc) + n_dsc, + k_dsc ) }; dscModulusComponents = { dsc_modulus: splitToWords( BigInt(hexToDecimal(modulus as string)), - BigInt(n_dsc), - BigInt(k_dsc) + n_dsc, + k_dsc ) }; } diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index f4f2a2fb..4485a107 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -4,7 +4,7 @@ import { formatSigAlgNameForCircuit } from "./utils"; import { toStandardName } from "./formatNames"; import axios from "axios"; import { poseidon10, poseidon2, poseidon3, poseidon5, poseidon6, poseidon8 } from 'poseidon-lite'; -import { BigintToArray, hexToDecimal, splitToWords } from './utils'; +import { hexToDecimal, splitToWords } from './utils'; export function buildPubkeyTree(pubkeys: any[]) { let leaves: bigint[] = []; @@ -50,7 +50,7 @@ export function getLeaf(pubkey: any, i?: number): bigint { sigAlgFormattedForCircuit === 'sha256WithRSASSAPSS_3' || sigAlgFormattedForCircuit === 'sha512WithRSAEncryption_65537' ) { - const pubkeyChunked = splitToWords(BigInt(pubkey.modulus), BigInt(230), BigInt(9)); + const pubkeyChunked = splitToWords(BigInt(pubkey.modulus), 230, 9); const leaf = poseidon10([SignatureAlgorithm[sigAlgFormattedForCircuit], ...pubkeyChunked]); try { return leaf; @@ -75,8 +75,8 @@ export function getLeaf(pubkey: any, i?: number): bigint { throw new Error('Invalid publicKeyQ format'); } - let qx = BigintToArray(43, 6, BigInt(hexToDecimal(x))); - let qy = BigintToArray(43, 6, BigInt(hexToDecimal(y))); + let qx = splitToWords(BigInt(hexToDecimal(x)), 43, 6); + let qy = splitToWords(BigInt(hexToDecimal(y)), 43, 6); let poseidon_hasher_dsc_modules_x = poseidon6(qx); let poseidon_hasher_dsc_modules_y = poseidon6(qy); diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts index a642487b..030fa0b4 100644 --- a/common/src/utils/utils.ts +++ b/common/src/utils/utils.ts @@ -156,14 +156,14 @@ export const toBinaryString = (byte: any) => { return binary; }; -export function splitToWords(number: bigint, wordsize: bigint, numberElement: bigint) { +export function splitToWords(number: bigint, wordsize: number, numberElement: number) { let t = number; const words: string[] = []; - for (let i = BigInt(0); i < numberElement; ++i) { + for (let i = 0; i < numberElement; ++i) { 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), wordsize))}`); + t = BigInt(t / BigInt(Math.pow(Number(BigInt(2)), wordsize))); } if (!(t == BigInt(0))) { throw `Number ${number} does not fit in ${(wordsize * numberElement).toString()} bits`; @@ -391,21 +391,6 @@ export function extractRSFromSignature(signatureBytes: number[]): { r: string; s 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; -} - /// UUID function stringToHex(str: string): string { diff --git a/sdk/src/OpenPassport1Step.ts b/sdk/src/OpenPassport1Step.ts index 498a6f31..2a238de9 100644 --- a/sdk/src/OpenPassport1Step.ts +++ b/sdk/src/OpenPassport1Step.ts @@ -130,7 +130,7 @@ export class OpenPassport1StepVerifier { // @ts-ignore const dsc_modulus = BigInt(dscCertificate.publicKey.n); - const dsc_modulus_words = splitToWords(dsc_modulus, BigInt(64), BigInt(32)); + const dsc_modulus_words = splitToWords(dsc_modulus, 64, 32); const modulus_from_proof = parsedPublicSignals.pubKey; const areArraysEqual = (arr1: string[], arr2: string[]) => From fb15c9427c55ac301cf8c13958f8f18658edf3fc Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 12:39:51 +0900 Subject: [PATCH 05/18] update getLeaf to use DSC and SignatureAlgorithmIndex to use new names --- app/src/screens/MainScreen.tsx | 4 +- app/src/utils/registration.ts | 6 +- app/src/utils/transactions.ts | 4 +- circuits/tests/disclose/disclose.test.ts | 6 +- circuits/tests/ofac/ofac.test.ts | 18 ++- circuits/tests/{prove => }/prove.test.ts | 10 +- .../tests/{register => }/register.test.ts | 19 ++- common/src/constants/constants.ts | 18 ++- common/src/utils/generateInputs.ts | 11 +- common/src/utils/pubkeyTree.ts | 119 ++++-------------- contracts/test/RegisterAndDisclose.ts | 12 +- registry/src/dsc/build_dsc_merkle_tree.ts | 19 --- 12 files changed, 67 insertions(+), 179 deletions(-) rename circuits/tests/{prove => }/prove.test.ts (88%) rename circuits/tests/{register => }/register.test.ts (86%) delete mode 100644 registry/src/dsc/build_dsc_merkle_tree.ts diff --git a/app/src/screens/MainScreen.tsx b/app/src/screens/MainScreen.tsx index a9d784ca..b12de32b 100644 --- a/app/src/screens/MainScreen.tsx +++ b/app/src/screens/MainScreen.tsx @@ -28,7 +28,7 @@ import NextScreen from './NextScreen'; import RegisterScreen from './RegisterScreen'; import AppScreen from './AppScreen'; // import constants -import { RPC_URL, SignatureAlgorithm } from '../../../common/src/constants/constants'; +import { RPC_URL, SignatureAlgorithmIndex } from '../../../common/src/constants/constants'; import { mock_csca_sha256_rsa_4096, mock_dsc_sha256_rsa_4096 } from '../../../common/src/constants/mockCertificates'; import DatePicker from 'react-native-date-picker' import StartScreen from './StartScreen'; @@ -144,7 +144,7 @@ const MainScreen: React.FC = () => { // if ((cscaProof !== null) && (localProof !== null)) { // const sendTransaction = async () => { // const sigAlgFormatted = formatSigAlgNameForCircuit(passportData.signatureAlgorithm, passportData.pubKey.exponent); - // const sigAlgIndex = SignatureAlgorithm[sigAlgFormatted as keyof typeof SignatureAlgorithm] + // const sigAlgIndex = SignatureAlgorithmIndex[sigAlgFormatted as keyof typeof SignatureAlgorithmIndex] // console.log("local proof already generated, sending transaction"); // const provider = new ethers.JsonRpcProvider(RPC_URL); // const serverResponse = await sendRegisterTransaction(localProof, cscaProof, sigAlgIndex) diff --git a/app/src/utils/registration.ts b/app/src/utils/registration.ts index ecbf070b..0c6a4d80 100644 --- a/app/src/utils/registration.ts +++ b/app/src/utils/registration.ts @@ -27,11 +27,7 @@ export async function isCommitmentRegistered(secret: string, passportData: Passp imt.import(response.data); - const pubkey_leaf = getLeaf({ - signatureAlgorithm: passportData.signatureAlgorithm, - modulus: passportData.pubKey!.modulus, - exponent: passportData.pubKey!.exponent, - }); + const pubkey_leaf = getLeaf(passportData); const formattedMrz = formatMrz(passportData.mrz); const mrz_bytes = packBytes(formattedMrz); diff --git a/app/src/utils/transactions.ts b/app/src/utils/transactions.ts index db6d0dd0..89df05b4 100644 --- a/app/src/utils/transactions.ts +++ b/app/src/utils/transactions.ts @@ -4,14 +4,14 @@ import groth16ExportSolidityCallData from './snarkjs'; import contractAddresses from "../../deployments/deployed_addresses.json"; import registerArtefacts from "../../deployments/artifacts/Deploy_Registry#OpenPassportRegister.json"; import sbtArtefacts from "../../deployments/artifacts/Deploy_Registry#SBT.json"; -import { CHAIN_NAME, RELAYER_URL, RPC_URL, SignatureAlgorithm } from '../../../common/src/constants/constants'; +import { CHAIN_NAME, RELAYER_URL, RPC_URL, SignatureAlgorithmIndex } from '../../../common/src/constants/constants'; import { Proof } from "../../../common/src/utils/types"; import { formatCallData_disclose, formatCallData_dsc, formatCallData_register } from "../../../common/src/utils/formatCallData"; export const sendRegisterTransaction = async ( proof: Proof, cscaProof: Proof, - sigAlgIndex: SignatureAlgorithm + sigAlgIndex: SignatureAlgorithmIndex ) => { const provider = new ethers.JsonRpcProvider(RPC_URL); diff --git a/circuits/tests/disclose/disclose.test.ts b/circuits/tests/disclose/disclose.test.ts index 2ba98e59..a7e1c3d6 100644 --- a/circuits/tests/disclose/disclose.test.ts +++ b/circuits/tests/disclose/disclose.test.ts @@ -43,11 +43,7 @@ describe('Disclose', function () { const scope = '@coboyApp'; // compute the commitment and insert it in the tree - const pubkey_leaf = getLeaf({ - signatureAlgorithm: passportData.signatureAlgorithm, - modulus: passportData.pubKey.modulus, - exponent: passportData.pubKey.exponent, - }).toString(); + const pubkey_leaf = getLeaf(passportData).toString(); const mrz_bytes = packBytes(formatMrz(passportData.mrz)); const commitment = poseidon6([ secret, diff --git a/circuits/tests/ofac/ofac.test.ts b/circuits/tests/ofac/ofac.test.ts index e2d83f2d..8375d3a8 100644 --- a/circuits/tests/ofac/ofac.test.ts +++ b/circuits/tests/ofac/ofac.test.ts @@ -1,10 +1,6 @@ import { expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; -import { - mockPassportData_sha256_rsa_65537, - mockPassportData2_sha256_rsa_65537, -} from '../../../common/src/constants/mockPassportData'; import { generateCircuitInputsOfac } from '../../../common/src/utils/generateInputs'; import { getLeaf } from '../../../common/src/utils/pubkeyTree'; import { SMT } from '@ashpect/smt'; @@ -17,10 +13,14 @@ import namejson from '../../../common/ofacdata/outputs/nameSMT.json'; import { PassportData } from '../../../common/src/utils/types'; import { PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; import crypto from 'crypto'; +import { genMockPassportData } from '../../../common/src/utils/genMockPassportData'; let circuit: any; -const passportData = mockPassportData_sha256_rsa_65537; // Mock passport ADDED in ofac list to test circuits -const passportData2 = mockPassportData2_sha256_rsa_65537; // Mock passport not added in ofac list to test circuits + +// Mock passport added in ofac list to test circuits +const passportData = genMockPassportData('rsa_sha256', 'FRA', '000101', '300101'); +// Mock passport not added in ofac list to test circuits +const passportData2 = genMockPassportData('rsa_sha256', 'FRA', '000101', '300101'); // Calculating common validity inputs for all 3 circuits function getPassportInputs(passportData: PassportData) { @@ -31,11 +31,7 @@ function getPassportInputs(passportData: PassportData) { const bitmap = Array(90).fill('1'); const scope = '@coboyApp'; - const pubkey_leaf = getLeaf({ - signatureAlgorithm: passportData.signatureAlgorithm, - modulus: passportData.pubKey.modulus, - exponent: passportData.pubKey.exponent, - }).toString(); + const pubkey_leaf = getLeaf(passportData).toString(); const mrz_bytes = packBytes(formatMrz(passportData.mrz)); const commitment = poseidon6([ secret, diff --git a/circuits/tests/prove/prove.test.ts b/circuits/tests/prove.test.ts similarity index 88% rename from circuits/tests/prove/prove.test.ts rename to circuits/tests/prove.test.ts index 722fbbf7..f189de5e 100644 --- a/circuits/tests/prove/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -2,11 +2,11 @@ import { describe } from 'mocha'; import { expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; -import { generateCircuitInputsProve } from '../../../common/src/utils/generateInputs'; -import { n_dsc, k_dsc } from '../../../common/src/constants/constants'; -import { genMockPassportData } from '../../../common/src/utils/genMockPassportData'; -import { getCircuitName } from '../../../common/src/utils/handleCertificate'; -import { SignatureAlgorithm } from '../../../common/tests/genMockPassportData.test'; +import { generateCircuitInputsProve } from '../../common/src/utils/generateInputs'; +import { n_dsc, k_dsc } from '../../common/src/constants/constants'; +import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; +import { getCircuitName } from '../../common/src/utils/handleCertificate'; +import { SignatureAlgorithm } from '../../common/tests/genMockPassportData.test'; const sigAlgs = [ { sigAlg: 'rsa', hashFunction: 'sha1' }, diff --git a/circuits/tests/register/register.test.ts b/circuits/tests/register.test.ts similarity index 86% rename from circuits/tests/register/register.test.ts rename to circuits/tests/register.test.ts index 975abc75..6f942e66 100644 --- a/circuits/tests/register/register.test.ts +++ b/circuits/tests/register.test.ts @@ -3,13 +3,13 @@ import { assert, expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; import { poseidon6 } from 'poseidon-lite'; -import { generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs'; -import { hexToDecimal, packBytes } from '../../../common/src/utils/utils'; -import { computeLeafFromModulusBigInt } from '../../../common/src/utils/csca'; -import { n_dsc, k_dsc, n_dsc_ecdsa, k_dsc_ecdsa, PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; -import { genMockPassportData } from '../../../common/src/utils/genMockPassportData'; -import { getCircuitName, getSignatureAlgorithm } from '../../../common/src/utils/handleCertificate'; -import { SignatureAlgorithm } from '../../../common/tests/genMockPassportData.test'; +import { generateCircuitInputsRegister } from '../../common/src/utils/generateInputs'; +import { hexToDecimal, packBytes } from '../../common/src/utils/utils'; +import { computeLeafFromModulusBigInt } from '../../common/src/utils/csca'; +import { n_dsc, k_dsc, n_dsc_ecdsa, k_dsc_ecdsa, PASSPORT_ATTESTATION_ID } from '../../common/src/constants/constants'; +import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; +import { getCircuitName, getSignatureAlgorithm } from '../../common/src/utils/handleCertificate'; +import { SignatureAlgorithm } from '../../common/tests/genMockPassportData.test'; const sigAlgs = [ { sigAlg: 'rsa', hashFunction: 'sha1' }, @@ -72,10 +72,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { // for ecdsa: - // const leaf = getLeaf({ - // signatureAlgorithm: passportData.signatureAlgorithm, - // publicKeyQ: passportData.pubKey.publicKeyQ, - // }).toString(); + // const leaf = getLeaf(passportData).toString(); // const commitment_bytes = poseidon6([ // inputs.secret[0], diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index 582e8d94..dc045d2d 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -20,17 +20,13 @@ export const RPC_URL = "https://opt-mainnet.g.alchemy.com/v2/Mjj_SdklUaCdR6EPfVK export const DEVELOPMENT_MODE = true export const DEFAULT_MAJORITY = "18" -export enum SignatureAlgorithm { - sha256WithRSAEncryption_65537 = 1, - sha256WithRSAEncryption_3 = 2, - sha1WithRSAEncryption_65537 = 3, - sha256WithRSASSAPSS_65537 = 4, - sha256WithRSASSAPSS_3 = 5, - ecdsa_with_SHA384 = 6, - ecdsa_with_SHA1 = 7, - ecdsa_with_SHA256 = 8, - ecdsa_with_SHA512 = 9, - sha512WithRSAEncryption_65537 = 10 +export enum SignatureAlgorithmIndex { + rsa_sha1 = 1, + rsa_sha256 = 2, + rsapss_sha256 = 3, + ecdsa_sha256 = 4, + ecdsa_sha1 = 5, + ecdsa_sha384 = 6, } export const signatureOidToName = { diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 505fb6f6..24fd98a3 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -83,10 +83,7 @@ export function generateCircuitInputsRegister( 'concatHash is not at the right place in eContent' ); - // const leaf = getLeaf({ - // signatureAlgorithm: signatureAlgorithm, - // ...pubKey, - // }).toString(); + // const leaf = getLeaf(passportData).toString(); // const index = tree.indexOf(leaf); // console.log(`Index of pubkey in the registry: ${index}`); @@ -166,11 +163,7 @@ export function generateCircuitInputsDisclose( scope: string, user_identifier: string ) { - const pubkey_leaf = getLeaf({ - signatureAlgorithm: passportData.signatureAlgorithm, - modulus: passportData.pubKey.modulus, - exponent: passportData.pubKey.exponent, - }); + const pubkey_leaf = getLeaf(passportData); const formattedMrz = formatMrz(passportData.mrz); const mrz_bytes = packBytes(formattedMrz); diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index 4485a107..802abf39 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -1,98 +1,31 @@ -import { SignatureAlgorithm, PUBKEY_TREE_DEPTH, COMMITMENT_TREE_TRACKER_URL } from "../constants/constants"; -import { IMT, LeanIMT } from '@zk-kit/imt' -import { formatSigAlgNameForCircuit } from "./utils"; -import { toStandardName } from "./formatNames"; +import { PUBKEY_TREE_DEPTH, COMMITMENT_TREE_TRACKER_URL, SignatureAlgorithmIndex } from "../constants/constants"; +import { LeanIMT } from '@zk-kit/imt' import axios from "axios"; -import { poseidon10, poseidon2, poseidon3, poseidon5, poseidon6, poseidon8 } from 'poseidon-lite'; +import { poseidon10, poseidon2, poseidon3, poseidon6 } from 'poseidon-lite'; import { hexToDecimal, splitToWords } from './utils'; - -export function buildPubkeyTree(pubkeys: any[]) { - let leaves: bigint[] = []; - let startTime = performance.now(); - - for (let i = 0; i < pubkeys.length; i++) { - const pubkey = pubkeys[i]; - - if (i % 3000 === 0 && i !== 0) { - console.log('Processing pubkey number', i, 'over', pubkeys.length); - } - - const leaf = getLeaf(pubkey, i); - - if (!leaf) { - // console.log('no leaf for this weird signature:', i, formatSigAlgNameForCircuit(pubkey.signatureAlgorithm, pubkey.exponent)) - continue; - } - leaves.push(leaf); - } - - const tree = new IMT(poseidon2, PUBKEY_TREE_DEPTH, 0, 2, leaves); - console.log('pubkey tree built in', performance.now() - startTime, 'ms'); - - 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; - } - if (!pubkey?.publicKeyQ && pubkey?.pubKey?.publicKeyQ) { - pubkey.publicKeyQ = pubkey.pubKey.publicKeyQ; - } - 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' - ) { - const pubkeyChunked = splitToWords(BigInt(pubkey.modulus), 230, 9); - const leaf = poseidon10([SignatureAlgorithm[sigAlgFormattedForCircuit], ...pubkeyChunked]); - try { - return leaf; - } catch (err) { - 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' - ) { - try { - 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 = splitToWords(BigInt(hexToDecimal(x)), 43, 6); - let qy = splitToWords(BigInt(hexToDecimal(y)), 43, 6); - - 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); - } +import { PassportData } from "./types"; +import { getSignatureAlgorithm } from "./handleCertificate"; + +export function getLeaf(passportData: PassportData): bigint { + const { signatureAlgorithm, modulus, x, y } = getSignatureAlgorithm(passportData.dsc); + + if (signatureAlgorithm === 'ecdsa') { + let qx = splitToWords(BigInt(hexToDecimal(x)), 43, 6); + let qy = splitToWords(BigInt(hexToDecimal(y)), 43, 6); + + let x_hash = poseidon6(qx); + let y_hash = poseidon6(qy); + + return poseidon3([ + SignatureAlgorithmIndex[signatureAlgorithm], + x_hash, + y_hash, + ]); + } else { + const pubkeyChunked = splitToWords(BigInt(modulus), 230, 9); + return poseidon10( + [SignatureAlgorithmIndex[signatureAlgorithm], ...pubkeyChunked] + ); } } diff --git a/contracts/test/RegisterAndDisclose.ts b/contracts/test/RegisterAndDisclose.ts index f23b96c1..25de48a3 100644 --- a/contracts/test/RegisterAndDisclose.ts +++ b/contracts/test/RegisterAndDisclose.ts @@ -2,7 +2,7 @@ import { expect, assert } from "chai"; import { ethers } from "hardhat"; // import { describe } from "mocha"; import { mockPassportData_sha256_rsa_65537, mockPassportData_sha1_rsa_65537, } from "../../common/src/constants/mockPassportData"; -import { countryCodes, PASSPORT_ATTESTATION_ID, SignatureAlgorithm } from "../../common/src/constants/constants"; +import { countryCodes, PASSPORT_ATTESTATION_ID, SignatureAlgorithmIndex } from "../../common/src/constants/constants"; import { formatRoot } from "../../common/src/utils/utils"; import { groth16 } from 'snarkjs' import { time } from "@nomicfoundation/hardhat-toolbox/network-helpers"; @@ -211,10 +211,10 @@ describe("OpenPassport - Contracts - Register & Disclose flow", function () { await verifier_disclose.waitForDeployment(); console.log('\x1b[34m%s\x1b[0m', `Verifier_disclose deployed to ${verifier_disclose.target}`); - await register.addSignatureAlgorithm(SignatureAlgorithm["sha256WithRSAEncryption_65537"], verifier_register_sha256WithRSAEncryption_65537.target); - await register.addCSCAVerifier(SignatureAlgorithm["sha256WithRSAEncryption_65537"], verifier_dsc_sha256_rsa_4096.target); - await register.addSignatureAlgorithm(SignatureAlgorithm["sha1WithRSAEncryption_65537"], verifier_register_sha1WithRSAEncryption_65537.target); - await register.addCSCAVerifier(SignatureAlgorithm["sha1WithRSAEncryption_65537"], verifier_dsc_sha1_rsa_4096.target); + await register.addSignatureAlgorithm(SignatureAlgorithmIndex.rsa_sha256, verifier_register_sha256WithRSAEncryption_65537.target); + await register.addCSCAVerifier(SignatureAlgorithmIndex.rsa_sha256, verifier_dsc_sha256_rsa_4096.target); + await register.addSignatureAlgorithm(SignatureAlgorithmIndex.rsa_sha1, verifier_register_sha1WithRSAEncryption_65537.target); + await register.addCSCAVerifier(SignatureAlgorithmIndex.rsa_sha1, verifier_dsc_sha1_rsa_4096.target); const SBT = await ethers.getContractFactory("SBT"); sbt = await SBT.deploy( @@ -311,7 +311,7 @@ describe("OpenPassport - Contracts - Register & Disclose flow", function () { for (const sigAlgName of sigAlgNames) { const sigAlgArtifacts_register = register_circuits[sigAlgName]; const sigAlgArtifacts_dsc = dsc_circuits[sigAlgName]; - const sigAlgIndex = SignatureAlgorithm[sigAlgName as keyof typeof SignatureAlgorithm] + const sigAlgIndex = SignatureAlgorithmIndex[sigAlgName as keyof typeof SignatureAlgorithmIndex] it(`Verifier contract verifies a correct proof - Register - ${sigAlgName}`, async function () { expect( diff --git a/registry/src/dsc/build_dsc_merkle_tree.ts b/registry/src/dsc/build_dsc_merkle_tree.ts deleted file mode 100644 index ce4a66ad..00000000 --- a/registry/src/dsc/build_dsc_merkle_tree.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as fs from 'fs'; -import { buildPubkeyTree } from '../../../common/src/utils/pubkeyTree' -import { computeLeafFromModulus, getCSCAModulusMerkleTree } from '../../../common/src/utils/csca' -import { CSCA_AKI_MODULUS, CSCA_TREE_DEPTH, k_csca, n_csca } from '../../../common/src/constants/constants'; -import { IMT } from '@zk-kit/imt'; -import { poseidon1, poseidon2 } from 'poseidon-lite'; -import { splitToWords } from '../../../common/src/utils/utils'; - -async function serialize_old_dsc_modulus_tree() { - const pubkeys = JSON.parse(fs.readFileSync("../common/pubkeys/public_keys_parsed.json") as unknown as string) - const tree = buildPubkeyTree(pubkeys); - const serializedTree = tree.nodes.map(layer => layer.map(node => node.toString())); - fs.writeFileSync("outputs/serialized_tree.json", JSON.stringify(serializedTree)); - fs.copyFileSync("outputs/serialized_tree.json", "../common/pubkeys/serialized_tree.json"); - console.log("serialized_tree.json written and copied in common/pubkeys!") -} - - -serialize_old_dsc_modulus_tree() \ No newline at end of file From 5a95fa9f51d632e9030aed963ffe71804db2b132 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 12:52:22 +0900 Subject: [PATCH 06/18] fix disclose test --- circuits/tests/disclose/disclose.test.ts | 5 ++--- common/src/utils/generateInputs.ts | 2 +- common/src/utils/pubkeyTree.ts | 17 ++++++++++------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/circuits/tests/disclose/disclose.test.ts b/circuits/tests/disclose/disclose.test.ts index a7e1c3d6..b6900ecd 100644 --- a/circuits/tests/disclose/disclose.test.ts +++ b/circuits/tests/disclose/disclose.test.ts @@ -1,11 +1,9 @@ import { assert, expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; -import { mockPassportData_sha256_rsa_65537 } from '../../../common/src/constants/mockPassportData'; import { formatMrz, packBytes } from '../../../common/src/utils/utils'; import { attributeToPosition, - COMMITMENT_TREE_DEPTH, PASSPORT_ATTESTATION_ID, } from '../../../common/src/constants/constants'; import { poseidon1, poseidon2, poseidon6 } from 'poseidon-lite'; @@ -14,13 +12,14 @@ import { getLeaf } from '../../../common/src/utils/pubkeyTree'; import { generateCircuitInputsDisclose } from '../../../common/src/utils/generateInputs'; import { formatAndUnpackReveal } from '../../../common/src/utils/revealBitmap'; import crypto from 'crypto'; +import { genMockPassportData } from '../../../common/src/utils/genMockPassportData'; describe('Disclose', function () { this.timeout(0); let inputs: any; let circuit: any; let w: any; - let passportData = mockPassportData_sha256_rsa_65537; + const passportData = genMockPassportData('rsa_sha256', 'FRA', '000101', '300101'); let tree: any; before(async () => { diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 24fd98a3..25cb4852 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -132,7 +132,7 @@ export function generateCircuitInputsRegister( dscModulusComponents = { dsc_modulus: splitToWords( - BigInt(hexToDecimal(modulus as string)), + BigInt(hexToDecimal(modulus)), n_dsc, k_dsc ) diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index 802abf39..545d9cac 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -7,8 +7,9 @@ import { PassportData } from "./types"; import { getSignatureAlgorithm } from "./handleCertificate"; export function getLeaf(passportData: PassportData): bigint { - const { signatureAlgorithm, modulus, x, y } = getSignatureAlgorithm(passportData.dsc); - + const { signatureAlgorithm, hashFunction, modulus, x, y } = getSignatureAlgorithm(passportData.dsc); + const sigAlgIndex = SignatureAlgorithmIndex[`${signatureAlgorithm}_${hashFunction}`] + if (signatureAlgorithm === 'ecdsa') { let qx = splitToWords(BigInt(hexToDecimal(x)), 43, 6); let qy = splitToWords(BigInt(hexToDecimal(y)), 43, 6); @@ -17,15 +18,17 @@ export function getLeaf(passportData: PassportData): bigint { let y_hash = poseidon6(qy); return poseidon3([ - SignatureAlgorithmIndex[signatureAlgorithm], + sigAlgIndex, x_hash, y_hash, ]); } else { - const pubkeyChunked = splitToWords(BigInt(modulus), 230, 9); - return poseidon10( - [SignatureAlgorithmIndex[signatureAlgorithm], ...pubkeyChunked] - ); + const pubkeyChunked = splitToWords(BigInt(hexToDecimal(modulus)), 230, 9); + + return poseidon10([ + sigAlgIndex, + ...pubkeyChunked + ]); } } From 82cd1005d8363bc28d7326730ed306ce73be9c1d Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 12:59:40 +0900 Subject: [PATCH 07/18] remove signatureOidToName --- common/src/constants/constants.ts | 5 ----- common/src/utils/csca.ts | 9 ++++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index dc045d2d..1eb70737 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -29,11 +29,6 @@ export enum SignatureAlgorithmIndex { ecdsa_sha384 = 6, } -export const signatureOidToName = { - "1.2.840.113549.1.1.11": "sha256_rsa", - "1.2.840.113549.1.1.5": "sha1_rsa" -} - export const attributeToPosition = { issuing_state: [2, 4], name: [5, 43], diff --git a/common/src/utils/csca.ts b/common/src/utils/csca.ts index d82fdc76..6b67ff78 100644 --- a/common/src/utils/csca.ts +++ b/common/src/utils/csca.ts @@ -1,12 +1,13 @@ import { sha1Pad, sha256Pad } from "./shaPad"; import * as forge from "node-forge"; import { splitToWords } from "./utils"; -import { CSCA_AKI_MODULUS, CSCA_TREE_DEPTH, MODAL_SERVER_ADDRESS, signatureOidToName } from "../constants/constants"; +import { CSCA_AKI_MODULUS, CSCA_TREE_DEPTH, MODAL_SERVER_ADDRESS } from "../constants/constants"; import { poseidon16, poseidon2, poseidon4 } from "poseidon-lite"; import { IMT } from "@zk-kit/imt"; import serialized_csca_tree from "../../pubkeys/serialized_csca_tree.json" import { createHash } from "crypto"; import axios from "axios"; +import { getSignatureAlgorithmDetails } from "./handleCertificate"; export function findStartIndex(modulus: string, messagePadded: Uint8Array): number { const modulusNumArray = []; @@ -126,12 +127,10 @@ export function getCSCAInputs(dscSecret: string, dscCertificate: any, cscaCertif // merkle tree saga const leaf = computeLeafFromModulusBigInt(csca_modulus_bigint); const [root, proof] = getCSCAModulusProof(leaf, n_csca, k_csca); - - - + const { signatureAlgorithm: signatureAlgorithmName, hashFunction } = getSignatureAlgorithmDetails(signatureAlgorithm); return { - "signature_algorithm": signatureOidToName[signatureAlgorithm], + "signature_algorithm": `${hashFunction}_${signatureAlgorithmName}`, // this is the opposite order as in the other files? "inputs": { "raw_dsc_cert": dsc_message_padded_formatted, From 4bc2afcfa78367fd07cfb37a662cbc8ecb734df9 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 13:11:58 +0900 Subject: [PATCH 08/18] remove signatureAlgorithm and pubKey from PassportData --- app/src/screens/MainScreen.tsx | 2 +- app/src/screens/ProveScreen.tsx | 2 +- app/src/stores/userStore.ts | 3 +- app/src/utils/nfcScanner.ts | 42 +--------- app/src/utils/qrCode.ts | 2 +- circuits/tests/ofac/ofac.test.ts | 3 - circuits/tests/register.test.ts | 2 +- .../passportData/sha256_sha1mrz_rsa_65537.ts | 81 ------------------ common/src/utils/formatNames.ts | 84 ------------------- common/src/utils/generateInputs.ts | 3 +- common/src/utils/types.ts | 4 +- common/src/utils/utils.ts | 24 ------ 12 files changed, 13 insertions(+), 239 deletions(-) delete mode 100644 common/scripts/passportData/sha256_sha1mrz_rsa_65537.ts delete mode 100644 common/src/utils/formatNames.ts diff --git a/app/src/screens/MainScreen.tsx b/app/src/screens/MainScreen.tsx index b12de32b..c060525a 100644 --- a/app/src/screens/MainScreen.tsx +++ b/app/src/screens/MainScreen.tsx @@ -143,7 +143,7 @@ const MainScreen: React.FC = () => { // console.log('CSCA Proof received:', cscaProof); // if ((cscaProof !== null) && (localProof !== null)) { // const sendTransaction = async () => { - // const sigAlgFormatted = formatSigAlgNameForCircuit(passportData.signatureAlgorithm, passportData.pubKey.exponent); + // const sigAlgFormatted = formatSigAlgNameForCircuit(passportData.signatureAlgorithm, passportData.pubKey.exponent); // this is old formatting // const sigAlgIndex = SignatureAlgorithmIndex[sigAlgFormatted as keyof typeof SignatureAlgorithmIndex] // console.log("local proof already generated, sending transaction"); // const provider = new ethers.JsonRpcProvider(RPC_URL); diff --git a/app/src/screens/ProveScreen.tsx b/app/src/screens/ProveScreen.tsx index a41312be..ad27ff2d 100644 --- a/app/src/screens/ProveScreen.tsx +++ b/app/src/screens/ProveScreen.tsx @@ -37,7 +37,7 @@ const ProveScreen: React.FC = ({ setSheetRegisterIsOpen }) => const [socket, setSocket] = useState(null); const [isConnecting, setIsConnecting] = useState(false); - const { signatureAlgorithm, hashFunction } = getSignatureAlgorithm(passportData.dsc as string); + const { signatureAlgorithm, hashFunction } = getSignatureAlgorithm(passportData.dsc); const circuitName = getCircuitName(selectedApp.circuit, signatureAlgorithm, hashFunction); const waitForSocketConnection = (socket: Socket): Promise => { diff --git a/app/src/stores/userStore.ts b/app/src/stores/userStore.ts index 359163d5..e31eb7a8 100644 --- a/app/src/stores/userStore.ts +++ b/app/src/stores/userStore.ts @@ -10,6 +10,7 @@ import * as Keychain from 'react-native-keychain'; import * as amplitude from '@amplitude/analytics-react-native'; import { loadPassportData, loadSecret, loadSecretOrCreateIt, storePassportData } from '../utils/keychain'; import { generateDscSecret } from '../../../common/src/utils/csca'; +import { genMockPassportData } from '../../../common/src/utils/genMockPassportData'; interface UserState { passportNumber: string @@ -43,7 +44,7 @@ const useUserStore = create((set, get) => ({ dateOfExpiry: DEFAULT_DOE ?? "", dscSecret: null, registered: false, - passportData: mockPassportData_sha256_rsa_65537, + passportData: genMockPassportData("rsa_sha256", "FRA", "19900101", "20300101"), secret: "", cscaProof: null, localProof: null, diff --git a/app/src/utils/nfcScanner.ts b/app/src/utils/nfcScanner.ts index d416032d..056e6b15 100644 --- a/app/src/utils/nfcScanner.ts +++ b/app/src/utils/nfcScanner.ts @@ -1,7 +1,6 @@ import { NativeModules, Platform } from 'react-native'; // @ts-ignore import PassportReader from 'react-native-passport-reader'; -import { toStandardName } from '../../../common/src/utils/formatNames'; import { checkInputs } from '../utils/utils'; import { PassportData } from '../../../common/src/utils/types'; import forge from 'node-forge'; @@ -121,7 +120,6 @@ const handleResponseIOS = async ( const eContentBase64 = parsed.eContentBase64; // this is what we call concatenatedDataHashes in android world const signedAttributes = parsed.signedAttributes; // this is what we call eContent in android world - const signatureAlgorithm = parsed.signatureAlgorithm; const mrz = parsed.passportMRZ; const signatureBase64 = parsed.signatureBase64; console.log('dataGroupsPresent', parsed.dataGroupsPresent) @@ -131,19 +129,12 @@ const handleResponseIOS = async ( console.log('isChipAuthenticationSupported', parsed.isChipAuthenticationSupported) console.log('residenceAddress', parsed.residenceAddress) console.log('passportPhoto', parsed.passportPhoto.substring(0, 100) + '...') - console.log('signatureAlgorithm', signatureAlgorithm) console.log('encapsulatedContentDigestAlgorithm', parsed.encapsulatedContentDigestAlgorithm) console.log('parsed.documentSigningCertificate', parsed.documentSigningCertificate) const pem = JSON.parse(parsed.documentSigningCertificate).PEM.replace(/\n/g, ''); - const certificate = forge.pki.certificateFromPem(pem); console.log('pem', pem) try { - const publicKey = certificate.publicKey; - //console.log('publicKey', publicKey); - - const modulus = (publicKey as any).n.toString(10); - const eContentArray = Array.from(Buffer.from(signedAttributes, 'base64')); const signedEContentArray = eContentArray.map(byte => byte > 127 ? byte - 256 : byte); @@ -153,15 +144,9 @@ const handleResponseIOS = async ( const encryptedDigestArray = Array.from(Buffer.from(signatureBase64, 'base64')).map(byte => byte > 127 ? byte - 256 : byte); //amplitude.track('Sig alg before conversion: ' + signatureAlgorithm); - console.log('signatureAlgorithm before conversion', signatureAlgorithm); const passportData = { mrz, - signatureAlgorithm: toStandardName(signatureAlgorithm), dsc: pem, - pubKey: { - modulus: modulus, - exponent: (publicKey as any).e.toString(10), - }, dataGroupHashes: concatenatedDataHashesArraySigned, eContent: signedEContentArray, encryptedDigest: encryptedDigestArray, @@ -169,8 +154,8 @@ const handleResponseIOS = async ( mockUser: false }; useUserStore.getState().registerPassportData(passportData) - const sigAlgName = getSignatureAlgorithm(pem); - const circuitName = getCircuitName("prove", sigAlgName.signatureAlgorithm, sigAlgName.hashFunction); + const { signatureAlgorithm, hashFunction } = getSignatureAlgorithm(pem); + const circuitName = getCircuitName("prove", signatureAlgorithm, hashFunction); downloadZkey(circuitName as any); useNavigationStore.getState().setSelectedTab("next"); } catch (e: any) { @@ -191,10 +176,6 @@ const handleResponseAndroid = async ( ) => { const { mrz, - signatureAlgorithm, - modulus, - curveName, - publicKeyQ, eContent, encryptedDigest, photo, @@ -210,22 +191,9 @@ const handleResponseAndroid = async ( //amplitude.track('Sig alg before conversion: ' + signatureAlgorithm); const pem = "-----BEGIN CERTIFICATE-----" + documentSigningCertificate + "-----END CERTIFICATE-----" - - const cert = forge.pki.certificateFromPem(pem); - console.log('cert', cert); - const publicKey = cert.publicKey; - console.log('publicKey', publicKey); - const passportData: PassportData = { mrz: mrz.replace(/\n/g, ''), - signatureAlgorithm: toStandardName(signatureAlgorithm), dsc: pem, - pubKey: { - modulus: modulus, - exponent: (publicKey as any).e.toString(10), - curveName: curveName, - publicKeyQ: publicKeyQ, - }, dataGroupHashes: JSON.parse(encapContent), eContent: JSON.parse(eContent), encryptedDigest: JSON.parse(encryptedDigest), @@ -240,8 +208,6 @@ const handleResponseAndroid = async ( }, null, 2)); console.log('mrz', passportData.mrz); - console.log('signatureAlgorithm', passportData.signatureAlgorithm); - console.log('pubKey', passportData.pubKey); console.log('dataGroupHashes', passportData.dataGroupHashes); console.log('eContent', passportData.eContent); console.log('encryptedDigest', passportData.encryptedDigest); @@ -255,8 +221,8 @@ const handleResponseAndroid = async ( console.log("documentSigningCertificate", documentSigningCertificate) useUserStore.getState().registerPassportData(passportData) - const sigAlgName = getSignatureAlgorithm(pem); - const circuitName = getCircuitName("prove", sigAlgName.signatureAlgorithm, sigAlgName.hashFunction); + const { signatureAlgorithm, hashFunction } = getSignatureAlgorithm(pem); + const circuitName = getCircuitName("prove", signatureAlgorithm, hashFunction); downloadZkey(circuitName as any); useNavigationStore.getState().setSelectedTab("next"); }; diff --git a/app/src/utils/qrCode.ts b/app/src/utils/qrCode.ts index 61fc3f5a..a4920bc7 100644 --- a/app/src/utils/qrCode.ts +++ b/app/src/utils/qrCode.ts @@ -56,7 +56,7 @@ const handleQRCodeScan = (result: string, toast: any, setSelectedApp: any, setSe console.log(result); const parsedJson = JSON.parse(result); const app: AppType = reconstructAppType(parsedJson); - const dsc = useUserStore.getState().passportData?.dsc; + const dsc = useUserStore.getState().passportData.dsc; const sigAlgName = getSignatureAlgorithm(dsc!); const circuitName = getCircuitName(app.circuit, sigAlgName.signatureAlgorithm, sigAlgName.hashFunction); downloadZkey(circuitName as any); diff --git a/circuits/tests/ofac/ofac.test.ts b/circuits/tests/ofac/ofac.test.ts index 8375d3a8..e1bf9a47 100644 --- a/circuits/tests/ofac/ofac.test.ts +++ b/circuits/tests/ofac/ofac.test.ts @@ -137,7 +137,6 @@ describe('OFAC - Passport number match', function () { expect.fail('Expected an error but none was thrown.'); } catch (error) { expect(error.message).to.include('Assert Failed'); - expect(error.message).to.include('line: 43'); expect(error.message).to.not.include('SMTVerify'); } }); @@ -225,7 +224,6 @@ describe('OFAC - Name and DOB match', function () { expect.fail('Expected an error but none was thrown.'); } catch (error) { expect(error.message).to.include('Assert Failed'); - expect(error.message).to.include('line: 54'); expect(error.message).to.not.include('SMTVerify'); } }); @@ -313,7 +311,6 @@ describe('OFAC - Name match', function () { expect.fail('Expected an error but none was thrown.'); } catch (error) { expect(error.message).to.include('Assert Failed'); - expect(error.message).to.include('line: 46'); expect(error.message).to.not.include('SMTVerify'); } }); diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index 6f942e66..d1d08178 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -28,7 +28,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const { modulus, x, y } = getSignatureAlgorithm(passportData.dsc as string); + const { modulus, x, y } = getSignatureAlgorithm(passportData.dsc); const inputs = generateCircuitInputsRegister( secret, diff --git a/common/scripts/passportData/sha256_sha1mrz_rsa_65537.ts b/common/scripts/passportData/sha256_sha1mrz_rsa_65537.ts deleted file mode 100644 index 3cfaa530..00000000 --- a/common/scripts/passportData/sha256_sha1mrz_rsa_65537.ts +++ /dev/null @@ -1,81 +0,0 @@ -import assert from "assert"; -import { PassportData } from "../../src/utils/types"; -import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual, findSubarrayIndex } from "../../src/utils/utils"; -import * as forge from 'node-forge'; -import { writeFileSync, readFileSync } from "fs"; -import { mock_dsc_key_sha256_rsa_4096 } from "../../src/constants/mockCertificates"; -import { sampleDataHashes_large } from "../../src/constants/sampleDataHashes"; - -const sampleMRZ = "P c.charCodeAt(0)); - - return { - mrz: sampleMRZ, - signatureAlgorithm: signatureAlgorithm, - pubKey: { - modulus: hexToDecimal(modulus), - exponent: '65537', - }, - 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("sha1WithRSAEncryption", 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 - hashLen) - ), - 'concatHash is not at the right place in eContent' - ); - - const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10); - const exponent = new forge.jsbn.BigInteger(pubKey.exponent, 10); - const rsaPublicKey = forge.pki.rsa.setPublicKey(modulus, exponent); - - const md = forge.md.sha256.create(); - md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); - - const signature = Buffer.from(encryptedDigest).toString( - 'binary', - ); - - return rsaPublicKey.verify(md.digest().bytes(), signature); -} - -const mockPassportData = genMockPassportData_sha256WithRSAEncryption_sha1MRZ_65537(); -console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2)); -console.log("Signature valid:", verify(mockPassportData)); - -writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2)); \ No newline at end of file diff --git a/common/src/utils/formatNames.ts b/common/src/utils/formatNames.ts deleted file mode 100644 index 0f69bab0..00000000 --- a/common/src/utils/formatNames.ts +++ /dev/null @@ -1,84 +0,0 @@ -// we use the sig alg / hash function names returned in modulus extractor and the OID reference -// Example for https://oidref.com/1.2.840.113549.1.1.11: sha256WithRSAEncryption -// the jmrtd lib returns other names (ex: SHA256withRSA), see this page: https://github.com/E3V3A/JMRTD/blob/master/jmrtd/src/org/jmrtd/lds/SODFile.java -// Sometimesm, iOS module too (ex rsaEncryption instead of sha256WithRSAEncryption) -// So we translate here - -export function toStandardName(jmrtdName: string): string { - switch (jmrtdName) { - - // hash functions - case "SHA-1": - case "SHA1": - return "sha1"; - case "SHA-224": - case "SHA224": - return "sha224"; - case "SHA-256": - case "SHA256": - return "sha256"; - case "SHA-384": - case "SHA384": - return "sha384"; - case "SHA-512": - case "SHA512": - return "sha512"; - - // sig algs - case "SHA1withECDSA": - return "ecdsa-with-SHA1"; - case "SHA224withECDSA": - return "ecdsa-with-SHA224"; - case "SHA256withECDSA": - return "ecdsa-with-SHA256"; - case "SHA384withECDSA": - return "ecdsa-with-SHA384"; - case "SHA512withECDSA": - return "ecdsa-with-SHA512"; - case "MD2withRSA": - return "md2WithRSAEncryption"; - case "MD4withRSA": - return "md4WithRSAEncryption"; - case "MD5withRSA": - return "md5WithRSAEncryption"; - case "SHA1withRSA": - return "sha1WithRSAEncryption"; - case "SHA224withRSA": - return "sha224WithRSAEncryption"; - case "SHA256withRSA": - return "sha256WithRSAEncryption"; - case "SHA384withRSA": - return "sha384WithRSAEncryption"; - case "SHA512withRSA": - return "sha512WithRSAEncryption"; - - case "SAwithRSA/PSS": - case "SSAwithRSA/PSS": - case "RSASSA-PSS": - case "rsassa-pss": - case "rsassaPss": - case "rsassapss": - case "rsapss": - case "SHA256withRSAandMGF1": - case "id-mgf1": - return "sha256WithRSASSAPSS"; - // we call it sha256WithRSASSAPSS even if specs says rsassaPss because there are multiple hash functions used - // e.g. Italy uses sha512 with it - - - // added this one for iOS - case "RSA": - case "rsaEncryption": - // for security - case "SHA256WITHRSA": - case "SHA256withRSA": - case "sha256withRSA": - case "sha256withrsa": - case "sha256WithRSAEncryption": - case "SHA256WITHRSAENCRYPTION": - return "sha256WithRSAEncryption"; - default: - console.log(`JMRTD sig alg or hash function ${jmrtdName} not found in mapping, returning it as it is`); - return jmrtdName; - } -} \ No newline at end of file diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 25cb4852..47588021 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -37,7 +37,8 @@ export function generateCircuitInputsRegister( passportData: PassportData, n_dsc: number, k_dsc: number, - mocks: PassportData[] = mockPassportDatas + // mocks: PassportData[] = mockPassportDatas + mocks?: PassportData[] ) { const { mrz, dsc, dataGroupHashes, eContent, encryptedDigest } = passportData; diff --git a/common/src/utils/types.ts b/common/src/utils/types.ts index e765061e..42366fc6 100644 --- a/common/src/utils/types.ts +++ b/common/src/utils/types.ts @@ -1,8 +1,6 @@ export type PassportData = { mrz: string; - signatureAlgorithm?: string; - dsc?: string; - pubKey?: { modulus?: string, exponent?: string, curveName?: string, publicKeyQ?: string }; + dsc: string; dataGroupHashes: number[]; eContent: number[]; encryptedDigest: number[]; diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts index 030fa0b4..b2b6d6f9 100644 --- a/common/src/utils/utils.ts +++ b/common/src/utils/utils.ts @@ -16,23 +16,6 @@ export function formatMrz(mrz: string) { return mrzCharcodes; } -export function parsePubKeyString(pubKeyString: string) { - const modulusMatch = pubKeyString.match(/modulus: ([\w\d]+)\s*public/); - const publicExponentMatch = pubKeyString.match(/public exponent: (\w+)/); - - const modulus = modulusMatch ? modulusMatch[1] : null; - const exponent = publicExponentMatch ? publicExponentMatch[1] : null; - - if (!modulus || !exponent) { - throw new Error('Could not parse public key string'); - } - - return { - modulus, - exponent, - }; -} - export function formatAndConcatenateDataHashes( dataHashes: [number, number[]][], hashLen: number, @@ -220,13 +203,6 @@ export function toUnsignedByte(signedByte: number) { return signedByte < 0 ? signedByte + 256 : signedByte; } -export function formatSigAlgNameForCircuit(sigAlg: string, exponent?: string) { - // replace - by _, for instance for ecdsa-with-SHA256 - sigAlg = sigAlg.replace(/-/g, '_'); - // add exponent, for instance for sha256WithRSAEncryption - return exponent ? `${sigAlg}_${exponent}` : sigAlg; -} - export function bigIntToChunkedBytes( num: BigInt | bigint, bytesPerChunk: number, From aa01c8e85cf8b318a0f6cb2f3923f9824e8c3ac3 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 13:25:00 +0900 Subject: [PATCH 09/18] rename getSignatureAlgorithm to parseDSC --- app/src/screens/MockDataScreen.tsx | 6 +++--- app/src/screens/ProveScreen.tsx | 4 ++-- app/src/utils/nfcScanner.ts | 6 +++--- app/src/utils/qrCode.ts | 4 ++-- circuits/tests/prove.test.ts | 2 +- circuits/tests/register.test.ts | 6 +++--- common/src/utils/genMockPassportData.ts | 6 +++--- common/src/utils/generateInputs.ts | 4 ++-- common/src/utils/handleCertificate.ts | 2 +- common/src/utils/pubkeyTree.ts | 4 ++-- common/tests/genMockPassportData.test.ts | 4 ++-- sdk/src/OpenPassport1Step.ts | 4 ++-- 12 files changed, 26 insertions(+), 26 deletions(-) diff --git a/app/src/screens/MockDataScreen.tsx b/app/src/screens/MockDataScreen.tsx index 6449bb7f..bd403c98 100644 --- a/app/src/screens/MockDataScreen.tsx +++ b/app/src/screens/MockDataScreen.tsx @@ -10,7 +10,7 @@ import { genMockPassportData } from '../../../common/src/utils/genMockPassportDa import { countryCodes } from '../../../common/src/constants/constants'; import getCountryISO2 from "country-iso-3-to-2"; import { flag } from 'country-emoji'; -import { getSignatureAlgorithm, getCircuitName } from '../../../common/src/utils/handleCertificate'; +import { parseDSC, getCircuitName } from '../../../common/src/utils/handleCertificate'; import { downloadZkey } from '../utils/zkeyDownload'; const MockDataScreen: React.FC = () => { @@ -36,8 +36,8 @@ const MockDataScreen: React.FC = () => { const mockPassportData = genMockPassportData(signatureAlgorithm as "rsa_sha256" | "rsa_sha1" | "rsapss_sha256", nationality as keyof typeof countryCodes, castDate(dateOfBirthDatePicker), castDate(dateOfExpiryDatePicker)); useUserStore.getState().registerPassportData(mockPassportData); useUserStore.getState().setRegistered(true); - const sigAlgName = getSignatureAlgorithm(mockPassportData.dsc as string); - const circuitName = getCircuitName("prove", sigAlgName.signatureAlgorithm, sigAlgName.hashFunction); + const { signatureAlgorithm: sigAlg, hashFunction } = parseDSC(mockPassportData.dsc); + const circuitName = getCircuitName("prove", sigAlg, hashFunction); downloadZkey(circuitName as any); resolve(null); }, 0)); diff --git a/app/src/screens/ProveScreen.tsx b/app/src/screens/ProveScreen.tsx index ad27ff2d..138c12f5 100644 --- a/app/src/screens/ProveScreen.tsx +++ b/app/src/screens/ProveScreen.tsx @@ -11,7 +11,7 @@ import { generateCircuitInputsProve } from '../../../common/src/utils/generateIn import { revealBitmapFromAttributes } from '../../../common/src/utils/revealBitmap'; import { formatProof, generateProof } from '../utils/prover'; import io, { Socket } from 'socket.io-client'; -import { getCircuitName, getSignatureAlgorithm } from '../../../common/src/utils/handleCertificate'; +import { getCircuitName, parseDSC } from '../../../common/src/utils/handleCertificate'; import { CircuitName } from '../utils/zkeyDownload'; import { generateCircuitInputsInApp } from '../utils/generateInputsInApp'; interface ProveScreenProps { @@ -37,7 +37,7 @@ const ProveScreen: React.FC = ({ setSheetRegisterIsOpen }) => const [socket, setSocket] = useState(null); const [isConnecting, setIsConnecting] = useState(false); - const { signatureAlgorithm, hashFunction } = getSignatureAlgorithm(passportData.dsc); + const { signatureAlgorithm, hashFunction } = parseDSC(passportData.dsc); const circuitName = getCircuitName(selectedApp.circuit, signatureAlgorithm, hashFunction); const waitForSocketConnection = (socket: Socket): Promise => { diff --git a/app/src/utils/nfcScanner.ts b/app/src/utils/nfcScanner.ts index 056e6b15..195f0dd2 100644 --- a/app/src/utils/nfcScanner.ts +++ b/app/src/utils/nfcScanner.ts @@ -8,7 +8,7 @@ import { Buffer } from 'buffer'; import * as amplitude from '@amplitude/analytics-react-native'; import useUserStore from '../stores/userStore'; import useNavigationStore from '../stores/navigationStore'; -import { getSignatureAlgorithm, getCircuitName } from '../../../common/src/utils/handleCertificate'; +import { parseDSC, getCircuitName } from '../../../common/src/utils/handleCertificate'; import { downloadZkey } from './zkeyDownload'; export const scan = async (setModalProofStep: (modalProofStep: number) => void) => { @@ -154,7 +154,7 @@ const handleResponseIOS = async ( mockUser: false }; useUserStore.getState().registerPassportData(passportData) - const { signatureAlgorithm, hashFunction } = getSignatureAlgorithm(pem); + const { signatureAlgorithm, hashFunction } = parseDSC(pem); const circuitName = getCircuitName("prove", signatureAlgorithm, hashFunction); downloadZkey(circuitName as any); useNavigationStore.getState().setSelectedTab("next"); @@ -221,7 +221,7 @@ const handleResponseAndroid = async ( console.log("documentSigningCertificate", documentSigningCertificate) useUserStore.getState().registerPassportData(passportData) - const { signatureAlgorithm, hashFunction } = getSignatureAlgorithm(pem); + const { signatureAlgorithm, hashFunction } = parseDSC(pem); const circuitName = getCircuitName("prove", signatureAlgorithm, hashFunction); downloadZkey(circuitName as any); useNavigationStore.getState().setSelectedTab("next"); diff --git a/app/src/utils/qrCode.ts b/app/src/utils/qrCode.ts index a4920bc7..0bdc566b 100644 --- a/app/src/utils/qrCode.ts +++ b/app/src/utils/qrCode.ts @@ -1,7 +1,7 @@ import { NativeModules, Platform } from "react-native"; import { AppType, reconstructAppType } from "../../../common/src/utils/appType"; import useNavigationStore from '../stores/navigationStore'; -import { getCircuitName, getSignatureAlgorithm } from "../../../common/src/utils/handleCertificate"; +import { getCircuitName, parseDSC } from "../../../common/src/utils/handleCertificate"; import useUserStore from "../stores/userStore"; import { downloadZkey } from "./zkeyDownload"; @@ -57,7 +57,7 @@ const handleQRCodeScan = (result: string, toast: any, setSelectedApp: any, setSe const parsedJson = JSON.parse(result); const app: AppType = reconstructAppType(parsedJson); const dsc = useUserStore.getState().passportData.dsc; - const sigAlgName = getSignatureAlgorithm(dsc!); + const sigAlgName = parseDSC(dsc!); const circuitName = getCircuitName(app.circuit, sigAlgName.signatureAlgorithm, sigAlgName.hashFunction); downloadZkey(circuitName as any); setSelectedApp(app); diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index f189de5e..6529ad65 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -37,7 +37,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { before(async () => { circuit = await wasm_tester( - path.join(__dirname, `../../circuits/prove/${getCircuitName('prove', sigAlg, hashFunction)}.circom`), + path.join(__dirname, `../circuits/prove/${getCircuitName('prove', sigAlg, hashFunction)}.circom`), { include: [ 'node_modules', diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index d1d08178..817c3cdf 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -8,7 +8,7 @@ import { hexToDecimal, packBytes } from '../../common/src/utils/utils'; import { computeLeafFromModulusBigInt } from '../../common/src/utils/csca'; import { n_dsc, k_dsc, n_dsc_ecdsa, k_dsc_ecdsa, PASSPORT_ATTESTATION_ID } from '../../common/src/constants/constants'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; -import { getCircuitName, getSignatureAlgorithm } from '../../common/src/utils/handleCertificate'; +import { getCircuitName, parseDSC } from '../../common/src/utils/handleCertificate'; import { SignatureAlgorithm } from '../../common/tests/genMockPassportData.test'; const sigAlgs = [ @@ -28,7 +28,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const { modulus, x, y } = getSignatureAlgorithm(passportData.dsc); + const { modulus, x, y } = parseDSC(passportData.dsc); const inputs = generateCircuitInputsRegister( secret, @@ -41,7 +41,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { before(async () => { circuit = await wasm_tester( - path.join(__dirname, `../../circuits/register/${getCircuitName('register', sigAlg, hashFunction)}.circom`), + path.join(__dirname, `../circuits/register/${getCircuitName('register', sigAlg, hashFunction)}.circom`), { include: [ 'node_modules', diff --git a/common/src/utils/genMockPassportData.ts b/common/src/utils/genMockPassportData.ts index 5e52a7aa..d17e349d 100644 --- a/common/src/utils/genMockPassportData.ts +++ b/common/src/utils/genMockPassportData.ts @@ -26,7 +26,7 @@ import { } from '../constants/mockCertificates'; import { sampleDataHashes_small, sampleDataHashes_large } from '../constants/sampleDataHashes'; import { countryCodes } from '../constants/constants'; -import { getSignatureAlgorithm } from './handleCertificate'; +import { parseDSC } from './handleCertificate'; export function genMockPassportData( signatureType: 'rsa_sha1' | 'rsa_sha256' | 'rsapss_sha256' | 'ecdsa_sha256' | 'ecdsa_sha1' | 'ecdsa_sha384', @@ -77,7 +77,7 @@ export function genMockPassportData( break; } - const { hashFunction, hashLen } = getSignatureAlgorithm(dsc); + const { hashFunction, hashLen } = parseDSC(dsc); const mrzHash = hash(hashFunction, formatMrz(mrz)); const concatenatedDataHashes = formatAndConcatenateDataHashes( @@ -107,7 +107,7 @@ function sign( dsc: string, eContent: number[] ): number[] { - const { signatureAlgorithm, hashFunction, curve } = getSignatureAlgorithm(dsc); + const { signatureAlgorithm, hashFunction, curve } = parseDSC(dsc); if (signatureAlgorithm === 'rsapss') { const privateKey = forge.pki.privateKeyFromPem(privateKeyPem); diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 47588021..dff8b04e 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -28,7 +28,7 @@ import { mockPassportDatas, } from "../constants/mockPassportData"; import { SMT } from "@ashpect/smt" -import { getSignatureAlgorithm } from './handleCertificate'; +import { parseDSC } from './handleCertificate'; export function generateCircuitInputsRegister( secret: string, @@ -43,7 +43,7 @@ export function generateCircuitInputsRegister( const { mrz, dsc, dataGroupHashes, eContent, encryptedDigest } = passportData; - const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus } = getSignatureAlgorithm(dsc); + const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus } = parseDSC(dsc); // const tree = getCSCAModulusMerkleTree(); diff --git a/common/src/utils/handleCertificate.ts b/common/src/utils/handleCertificate.ts index ea4abd33..27426afb 100644 --- a/common/src/utils/handleCertificate.ts +++ b/common/src/utils/handleCertificate.ts @@ -4,7 +4,7 @@ import { getHashLen } from './utils'; import { getNamedCurve } from '../../../registry/src/utils/curves'; import elliptic from 'elliptic'; -export const getSignatureAlgorithm = (pemContent: string) => { +export const parseDSC = (pemContent: string) => { const certBuffer = Buffer.from(pemContent.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''), 'base64'); const asn1Data = asn1.fromBER(certBuffer); const cert = new Certificate({ schema: asn1Data.result }); diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index 545d9cac..95642bd7 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -4,10 +4,10 @@ import axios from "axios"; import { poseidon10, poseidon2, poseidon3, poseidon6 } from 'poseidon-lite'; import { hexToDecimal, splitToWords } from './utils'; import { PassportData } from "./types"; -import { getSignatureAlgorithm } from "./handleCertificate"; +import { parseDSC } from "./handleCertificate"; export function getLeaf(passportData: PassportData): bigint { - const { signatureAlgorithm, hashFunction, modulus, x, y } = getSignatureAlgorithm(passportData.dsc); + const { signatureAlgorithm, hashFunction, modulus, x, y } = parseDSC(passportData.dsc); const sigAlgIndex = SignatureAlgorithmIndex[`${signatureAlgorithm}_${hashFunction}`] if (signatureAlgorithm === 'ecdsa') { diff --git a/common/tests/genMockPassportData.test.ts b/common/tests/genMockPassportData.test.ts index 802341a6..e2a95833 100644 --- a/common/tests/genMockPassportData.test.ts +++ b/common/tests/genMockPassportData.test.ts @@ -4,7 +4,7 @@ import { genMockPassportData } from '../src/utils/genMockPassportData'; import * as forge from 'node-forge'; import { PassportData } from '../src/utils/types'; import { formatMrz, hash, arraysAreEqual, findSubarrayIndex } from '../src/utils/utils'; -import { getSignatureAlgorithm } from '../src/utils/handleCertificate'; +import { parseDSC } from '../src/utils/handleCertificate'; import * as asn1 from 'asn1js'; import { Certificate } from 'pkijs'; import elliptic from 'elliptic'; @@ -35,7 +35,7 @@ describe('Mock Passport Data Generator', function () { function verify(passportData: PassportData): boolean { const { mrz, dsc, dataGroupHashes, eContent, encryptedDigest } = passportData; - const { signatureAlgorithm, hashFunction, hashLen, curve } = getSignatureAlgorithm(dsc); + const { signatureAlgorithm, hashFunction, hashLen, curve } = parseDSC(dsc); const formattedMrz = formatMrz(mrz); const mrzHash = hash(hashFunction, formattedMrz); const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash) diff --git a/sdk/src/OpenPassport1Step.ts b/sdk/src/OpenPassport1Step.ts index 2a238de9..d0dfeb70 100644 --- a/sdk/src/OpenPassport1Step.ts +++ b/sdk/src/OpenPassport1Step.ts @@ -19,7 +19,7 @@ import { splitToWords, UserIdType, } from '../../common/src/utils/utils'; -import { getSignatureAlgorithm } from '../../common/src/utils/handleCertificate'; +import { parseDSC } from '../../common/src/utils/handleCertificate'; export class OpenPassport1StepVerifier { scope: string; @@ -49,7 +49,7 @@ export class OpenPassport1StepVerifier { async verify( openPassport1StepInputs: OpenPassport1StepInputs ): Promise { - const { signatureAlgorithm, hashFunction } = getSignatureAlgorithm(openPassport1StepInputs.dsc); + const { signatureAlgorithm, hashFunction } = parseDSC(openPassport1StepInputs.dsc); const vkey = getVkey(openPassport1StepInputs.circuit, signatureAlgorithm, hashFunction); const parsedPublicSignals = parsePublicSignals1Step( openPassport1StepInputs.dscProof.publicSignals From 8e2dd945542f447440bb04ea285467da95196b23 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 13:33:35 +0900 Subject: [PATCH 10/18] get SignatureAlgorithmIndex back in accordance with circuits --- circuits/tests/register.test.ts | 31 +++++++++++++++---------------- common/src/constants/constants.ts | 12 ++++++------ 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index 817c3cdf..7494d349 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -10,6 +10,7 @@ import { n_dsc, k_dsc, n_dsc_ecdsa, k_dsc_ecdsa, PASSPORT_ATTESTATION_ID } from import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; import { getCircuitName, parseDSC } from '../../common/src/utils/handleCertificate'; import { SignatureAlgorithm } from '../../common/tests/genMockPassportData.test'; +import { getLeaf } from '../../common/src/utils/pubkeyTree'; const sigAlgs = [ { sigAlg: 'rsa', hashFunction: 'sha1' }, @@ -68,23 +69,21 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { .blinded_dsc_commitment; console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); - // const mrz_bytes = packBytes(inputs.mrz); - - // for ecdsa: - - // const leaf = getLeaf(passportData).toString(); + const mrz_bytes = packBytes(inputs.mrz); + const leaf = getLeaf(passportData).toString(); - // const commitment_bytes = poseidon6([ - // inputs.secret[0], - // PASSPORT_ATTESTATION_ID, - // computeLeafFromModulusBigInt(BigInt(hexToDecimal(modulus as string))), - // mrz_bytes[0], - // mrz_bytes[1], - // mrz_bytes[2], - // ]); - // const commitment_js = commitment_bytes.toString(); - // //console.log('commitment_js', commitment_js) - // //console.log('commitment_circom', commitment_circom) + const commitment_bytes = poseidon6([ + inputs.secret[0], + PASSPORT_ATTESTATION_ID, + leaf, + mrz_bytes[0], + mrz_bytes[1], + mrz_bytes[2], + ]); + const commitment_js = commitment_bytes.toString(); + console.log('commitment_js', commitment_js) + console.log('commitment_circom', commitment_circom) + // TODO: fix with new leaf hasher // expect(commitment_circom).to.be.equal(commitment_js); }); diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index 1eb70737..220c40c5 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -21,12 +21,12 @@ export const DEVELOPMENT_MODE = true export const DEFAULT_MAJORITY = "18" export enum SignatureAlgorithmIndex { - rsa_sha1 = 1, - rsa_sha256 = 2, - rsapss_sha256 = 3, - ecdsa_sha256 = 4, - ecdsa_sha1 = 5, - ecdsa_sha384 = 6, + rsa_sha256 = 1, + rsa_sha1 = 3, + rsapss_sha256 = 4, + ecdsa_sha1 = 7, + ecdsa_sha256 = 8, + ecdsa_sha384 = 9, } export const attributeToPosition = { From 6c40783d5d1b419ffb820085c69d89e6af7897ac Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 13:38:42 +0900 Subject: [PATCH 11/18] move SignatureAlgorithm to `types.ts` --- circuits/tests/prove.test.ts | 2 +- circuits/tests/register.test.ts | 2 +- common/src/utils/types.ts | 2 ++ common/src/utils/utils.ts | 6 ------ common/tests/genMockPassportData.test.ts | 5 +---- 5 files changed, 5 insertions(+), 12 deletions(-) diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index 6529ad65..d659a155 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -6,7 +6,7 @@ import { generateCircuitInputsProve } from '../../common/src/utils/generateInput import { n_dsc, k_dsc } from '../../common/src/constants/constants'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; import { getCircuitName } from '../../common/src/utils/handleCertificate'; -import { SignatureAlgorithm } from '../../common/tests/genMockPassportData.test'; +import { SignatureAlgorithm } from '../../common/src/utils/types'; const sigAlgs = [ { sigAlg: 'rsa', hashFunction: 'sha1' }, diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index 7494d349..3b33e251 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -9,8 +9,8 @@ import { computeLeafFromModulusBigInt } from '../../common/src/utils/csca'; import { n_dsc, k_dsc, n_dsc_ecdsa, k_dsc_ecdsa, PASSPORT_ATTESTATION_ID } from '../../common/src/constants/constants'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; import { getCircuitName, parseDSC } from '../../common/src/utils/handleCertificate'; -import { SignatureAlgorithm } from '../../common/tests/genMockPassportData.test'; import { getLeaf } from '../../common/src/utils/pubkeyTree'; +import { SignatureAlgorithm } from '../../common/src/utils/types'; const sigAlgs = [ { sigAlg: 'rsa', hashFunction: 'sha1' }, diff --git a/common/src/utils/types.ts b/common/src/utils/types.ts index 42366fc6..51968d8f 100644 --- a/common/src/utils/types.ts +++ b/common/src/utils/types.ts @@ -8,6 +8,8 @@ export type PassportData = { mockUser?: boolean; }; +export type SignatureAlgorithm = 'rsa_sha1' | 'rsa_sha256' | 'rsapss_sha256' | 'ecdsa_sha256' | 'ecdsa_sha1' | 'ecdsa_sha384'; + export type Proof = { proof: { a: [string, string], diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts index b2b6d6f9..efcd32f6 100644 --- a/common/src/utils/utils.ts +++ b/common/src/utils/utils.ts @@ -369,11 +369,6 @@ export function extractRSFromSignature(signatureBytes: number[]): { r: string; s /// UUID -function stringToHex(str: string): string { - return Buffer.from(str).toString('hex'); -} - - function hexToBigInt(hex: string): bigint { return BigInt(`0x${hex}`); } @@ -499,7 +494,6 @@ const getMaxLenght = (idType: UserIdType) => { } export const parseUIDToBigInt = (user_identifier: string, user_identifier_type: UserIdType): string => { - if (!validateUserId(user_identifier, user_identifier_type)) { throw new Error(`User identifier of type ${user_identifier_type} is not valid`); } diff --git a/common/tests/genMockPassportData.test.ts b/common/tests/genMockPassportData.test.ts index e2a95833..5f5c5a91 100644 --- a/common/tests/genMockPassportData.test.ts +++ b/common/tests/genMockPassportData.test.ts @@ -2,15 +2,12 @@ import { assert, expect } from 'chai'; import { describe, it } from 'mocha'; import { genMockPassportData } from '../src/utils/genMockPassportData'; import * as forge from 'node-forge'; -import { PassportData } from '../src/utils/types'; +import { PassportData, SignatureAlgorithm } from '../src/utils/types'; import { formatMrz, hash, arraysAreEqual, findSubarrayIndex } from '../src/utils/utils'; import { parseDSC } from '../src/utils/handleCertificate'; import * as asn1 from 'asn1js'; import { Certificate } from 'pkijs'; import elliptic from 'elliptic'; -import * as crypto from 'crypto'; - -export type SignatureAlgorithm = 'rsa_sha1' | 'rsa_sha256' | 'rsapss_sha256' | 'ecdsa_sha256' | 'ecdsa_sha1' | 'ecdsa_sha384'; const sigAlgs: SignatureAlgorithm[] = [ 'rsa_sha1', From 544aa78d12f55b9eaaa753c12735b9a5e0145cb0 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 13:44:03 +0900 Subject: [PATCH 12/18] add `/common` tests to github workflow --- .github/workflows/action.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index be22b567..36deda31 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -37,7 +37,6 @@ jobs: uses: actions/setup-node@v3 with: node-version: 18 - - name: Setup Rust uses: dtolnay/rust-toolchain@stable @@ -58,6 +57,10 @@ jobs: working-directory: ./circuits run: yarn lint - - name: Run Tests + - name: Run Tests (Circuits) working-directory: ./circuits + run: yarn test + + - name: Run Tests (Common) + working-directory: ./common run: yarn test \ No newline at end of file From cc0a0ea4a2e06d348b140ca7ec98c2876cfd6e44 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 13:50:23 +0900 Subject: [PATCH 13/18] use n_dsc_ecdsa everywhere when ecdsa --- app/src/utils/generateInputsInApp.ts | 13 +++++++++++-- circuits/tests/prove.test.ts | 6 +++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/src/utils/generateInputsInApp.ts b/app/src/utils/generateInputsInApp.ts index 2adfe923..1c6ba798 100644 --- a/app/src/utils/generateInputsInApp.ts +++ b/app/src/utils/generateInputsInApp.ts @@ -2,10 +2,11 @@ import { AppType } from '../../../common/src/utils/appType'; import { PassportData } from '../../../common/src/utils/types'; import { generateCircuitInputsProve, generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs'; -import { DEFAULT_MAJORITY, k_dsc, n_dsc, PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; +import { DEFAULT_MAJORITY, k_dsc, k_dsc_ecdsa, n_dsc, n_dsc_ecdsa, PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; import { revealBitmapFromAttributes } from '../../../common/src/utils/revealBitmap'; import useUserStore from '../stores/userStore'; import { ArgumentsProve } from '../../../common/src/utils/appType' +import { parseDSC } from '../../../common/src/utils/handleCertificate'; export const generateCircuitInputsInApp = ( passportData: PassportData, @@ -14,7 +15,15 @@ export const generateCircuitInputsInApp = ( switch (app.circuit) { case 'register': { const { secret, dscSecret } = useUserStore.getState(); - return generateCircuitInputsRegister(secret, dscSecret as string, PASSPORT_ATTESTATION_ID, passportData, n_dsc, k_dsc); + const { signatureAlgorithm } = parseDSC(passportData.dsc); + return generateCircuitInputsRegister( + secret, + dscSecret as string, + PASSPORT_ATTESTATION_ID, + passportData, + signatureAlgorithm === 'ecdsa' ? n_dsc_ecdsa : n_dsc, + signatureAlgorithm === 'ecdsa' ? k_dsc_ecdsa : k_dsc, + ); } case 'prove': { const disclosureOptions = (app.arguments as ArgumentsProve).disclosureOptions || {}; diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index d659a155..41b3f048 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -3,7 +3,7 @@ import { expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; import { generateCircuitInputsProve } from '../../common/src/utils/generateInputs'; -import { n_dsc, k_dsc } from '../../common/src/constants/constants'; +import { n_dsc, k_dsc, k_dsc_ecdsa, n_dsc_ecdsa } from '../../common/src/constants/constants'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; import { getCircuitName } from '../../common/src/utils/handleCertificate'; import { SignatureAlgorithm } from '../../common/src/utils/types'; @@ -27,8 +27,8 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { const inputs = generateCircuitInputsProve( passportData, - n_dsc, - k_dsc, + sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc, + sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc, scope, bitmap, majority, From de8cacb48d163c89da70843ab476b0235c594681 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 14:03:27 +0900 Subject: [PATCH 14/18] remove comments --- common/src/utils/generateInputs.ts | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index dff8b04e..c52c2326 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -24,9 +24,6 @@ import { getNameLeaf, getNameDobLeaf, getPassportNumberLeaf } from "./ofacTree"; import { poseidon6 } from "poseidon-lite"; import { packBytes } from "../utils/utils"; import { getCSCAModulusMerkleTree } from "./csca"; -import { - mockPassportDatas, -} from "../constants/mockPassportData"; import { SMT } from "@ashpect/smt" import { parseDSC } from './handleCertificate'; @@ -45,15 +42,7 @@ export function generateCircuitInputsRegister( const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus } = parseDSC(dsc); - - // const tree = getCSCAModulusMerkleTree(); - - // if (DEVELOPMENT_MODE) { - // for (const mockPassportData of mocks) { - // tree.insert(getLeaf(mockPassportData).toString()); - // } - // } - + // const tree = getCSCAModulusMerkleTree(DEVELOPMENT_MODE); const supportedAlgorithms = [ { signatureAlgorithm: 'rsa', hashFunction: 'sha1' }, @@ -84,17 +73,6 @@ export function generateCircuitInputsRegister( 'concatHash is not at the right place in eContent' ); - // const leaf = getLeaf(passportData).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 proof = tree.createProof(index); - // console.log('verifyProof', tree.verifyProof(proof)); - if (dataGroupHashes.length > MAX_DATAHASHES_LEN) { throw new Error( `This length of datagroups (${dataGroupHashes.length} bytes) is currently unsupported. Please contact us so we add support!` From 9d33ae84a3de6bbdbd41ff5f1856f7d35c90f223 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 14:05:38 +0900 Subject: [PATCH 15/18] remove static mockPassportData - can add them back if necessary, have to regenerate them so they have dscs --- app/src/stores/userStore.ts | 1 - common/src/constants/mockPassportData.ts | 985 ----------------------- 2 files changed, 986 deletions(-) delete mode 100644 common/src/constants/mockPassportData.ts diff --git a/app/src/stores/userStore.ts b/app/src/stores/userStore.ts index e31eb7a8..5ead014d 100644 --- a/app/src/stores/userStore.ts +++ b/app/src/stores/userStore.ts @@ -4,7 +4,6 @@ import { DEFAULT_DOB, DEFAULT_DOE, } from '@env'; -import { mockPassportData_sha256_rsa_65537 } from '../../../common/src/constants/mockPassportData'; import { PassportData, Proof } from '../../../common/src/utils/types'; import * as Keychain from 'react-native-keychain'; import * as amplitude from '@amplitude/analytics-react-native'; diff --git a/common/src/constants/mockPassportData.ts b/common/src/constants/mockPassportData.ts deleted file mode 100644 index ed5ae19f..00000000 --- a/common/src/constants/mockPassportData.ts +++ /dev/null @@ -1,985 +0,0 @@ -// Sample passport data used for testing - -export const mockPassportData_sha256_rsa_65537 = { - mrz: 'P Date: Sat, 14 Sep 2024 15:04:37 +0900 Subject: [PATCH 16/18] fix ofac tests --- circuits/tests/ofac/ofac.test.ts | 6 +++--- common/ofacdata/ReadMe.md | 2 +- common/src/utils/genMockPassportData.ts | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/circuits/tests/ofac/ofac.test.ts b/circuits/tests/ofac/ofac.test.ts index e1bf9a47..e08d51bc 100644 --- a/circuits/tests/ofac/ofac.test.ts +++ b/circuits/tests/ofac/ofac.test.ts @@ -18,9 +18,9 @@ import { genMockPassportData } from '../../../common/src/utils/genMockPassportDa let circuit: any; // Mock passport added in ofac list to test circuits -const passportData = genMockPassportData('rsa_sha256', 'FRA', '000101', '300101'); +const passportData = genMockPassportData('rsa_sha256', 'FRA', '040211', '300101'); // Mock passport not added in ofac list to test circuits -const passportData2 = genMockPassportData('rsa_sha256', 'FRA', '000101', '300101'); +const passportData2 = genMockPassportData('rsa_sha256', 'FRA', '000102', '300101', "24HB81833", "CLAQUE"); // Calculating common validity inputs for all 3 circuits function getPassportInputs(passportData: PassportData) { @@ -31,7 +31,7 @@ function getPassportInputs(passportData: PassportData) { const bitmap = Array(90).fill('1'); const scope = '@coboyApp'; - const pubkey_leaf = getLeaf(passportData).toString(); + const pubkey_leaf = getLeaf(passportData); const mrz_bytes = packBytes(formatMrz(passportData.mrz)); const commitment = poseidon6([ secret, diff --git a/common/ofacdata/ReadMe.md b/common/ofacdata/ReadMe.md index 65e0d6ff..3432b6de 100644 --- a/common/ofacdata/ReadMe.md +++ b/common/ofacdata/ReadMe.md @@ -18,7 +18,7 @@ A ballpark number of 6917 individuals (at the time of writing this document) ent - For individuals, we parse: - full name (first name, last name), dob(day, month, year) in names.json - passports and passport issuing country in passport.json -- The jsons are stored at ofacdata/inputes to be used by SMT's. +- The jsons are stored at ofacdata/inputs to be used by SMT's. ## Data Usage These jsons are later used to create sparse merkle trees for non-membership proofs. We provide 3 levels of proofs. diff --git a/common/src/utils/genMockPassportData.ts b/common/src/utils/genMockPassportData.ts index d17e349d..02f49cc7 100644 --- a/common/src/utils/genMockPassportData.ts +++ b/common/src/utils/genMockPassportData.ts @@ -32,13 +32,15 @@ export function genMockPassportData( signatureType: 'rsa_sha1' | 'rsa_sha256' | 'rsapss_sha256' | 'ecdsa_sha256' | 'ecdsa_sha1' | 'ecdsa_sha384', nationality: keyof typeof countryCodes, birthDate: string, - expiryDate: string + expiryDate: string, + passportNumber: string = "24HB81832", + lastName: string = "DUPONT" ): PassportData { if (birthDate.length !== 6 || expiryDate.length !== 6) { throw new Error('birthdate and expiry date have to be in the "YYMMDD" format'); } - const mrz = `P<${nationality}DUPONT< Date: Sat, 14 Sep 2024 15:08:47 +0900 Subject: [PATCH 17/18] yarn format --- circuits/tests/ofac/ofac.test.ts | 9 +++++++- circuits/tests/prove.test.ts | 18 +++++++++++---- circuits/tests/register.test.ts | 38 ++++++++++++++++++++++++-------- 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/circuits/tests/ofac/ofac.test.ts b/circuits/tests/ofac/ofac.test.ts index e08d51bc..8a7e168a 100644 --- a/circuits/tests/ofac/ofac.test.ts +++ b/circuits/tests/ofac/ofac.test.ts @@ -20,7 +20,14 @@ let circuit: any; // Mock passport added in ofac list to test circuits const passportData = genMockPassportData('rsa_sha256', 'FRA', '040211', '300101'); // Mock passport not added in ofac list to test circuits -const passportData2 = genMockPassportData('rsa_sha256', 'FRA', '000102', '300101', "24HB81833", "CLAQUE"); +const passportData2 = genMockPassportData( + 'rsa_sha256', + 'FRA', + '000102', + '300101', + '24HB81833', + 'CLAQUE' +); // Calculating common validity inputs for all 3 circuits function getPassportInputs(passportData: PassportData) { diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index 41b3f048..f88eba90 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -19,7 +19,12 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { this.timeout(0); let circuit: any; - const passportData = genMockPassportData(`${sigAlg}_${hashFunction}` as SignatureAlgorithm, 'FRA', '000101', '300101'); + const passportData = genMockPassportData( + `${sigAlg}_${hashFunction}` as SignatureAlgorithm, + 'FRA', + '000101', + '300101' + ); const majority = '18'; const user_identifier = crypto.randomUUID(); const scope = '@coboyApp'; @@ -37,7 +42,10 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { before(async () => { circuit = await wasm_tester( - path.join(__dirname, `../circuits/prove/${getCircuitName('prove', sigAlg, hashFunction)}.circom`), + path.join( + __dirname, + `../circuits/prove/${getCircuitName('prove', sigAlg, hashFunction)}.circom` + ), { include: [ 'node_modules', @@ -55,7 +63,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { it('should calculate the witness with correct inputs', async function () { const w = await circuit.calculateWitness(inputs); await circuit.checkConstraints(w); - + const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; expect(nullifier).to.be.not.null; }); @@ -79,7 +87,9 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { try { const invalidInputs = { ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), + dataHashes: inputs.dataHashes.map((byte: string) => + String((parseInt(byte, 10) + 1) % 256) + ), }; await circuit.calculateWitness(invalidInputs); expect.fail('Expected an error but none was thrown.'); diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index 3b33e251..60dd5cc7 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -6,7 +6,13 @@ import { poseidon6 } from 'poseidon-lite'; import { generateCircuitInputsRegister } from '../../common/src/utils/generateInputs'; import { hexToDecimal, packBytes } from '../../common/src/utils/utils'; import { computeLeafFromModulusBigInt } from '../../common/src/utils/csca'; -import { n_dsc, k_dsc, n_dsc_ecdsa, k_dsc_ecdsa, PASSPORT_ATTESTATION_ID } from '../../common/src/constants/constants'; +import { + n_dsc, + k_dsc, + n_dsc_ecdsa, + k_dsc_ecdsa, + PASSPORT_ATTESTATION_ID, +} from '../../common/src/constants/constants'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; import { getCircuitName, parseDSC } from '../../common/src/utils/handleCertificate'; import { getLeaf } from '../../common/src/utils/pubkeyTree'; @@ -25,7 +31,12 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { this.timeout(0); let circuit: any; - const passportData = genMockPassportData(`${sigAlg}_${hashFunction}` as SignatureAlgorithm, 'FRA', '000101', '300101'); + const passportData = genMockPassportData( + `${sigAlg}_${hashFunction}` as SignatureAlgorithm, + 'FRA', + '000101', + '300101' + ); const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); @@ -42,7 +53,10 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { before(async () => { circuit = await wasm_tester( - path.join(__dirname, `../circuits/register/${getCircuitName('register', sigAlg, hashFunction)}.circom`), + path.join( + __dirname, + `../circuits/register/${getCircuitName('register', sigAlg, hashFunction)}.circom` + ), { include: [ 'node_modules', @@ -71,7 +85,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { const mrz_bytes = packBytes(inputs.mrz); const leaf = getLeaf(passportData).toString(); - + const commitment_bytes = poseidon6([ inputs.secret[0], PASSPORT_ATTESTATION_ID, @@ -81,8 +95,8 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { mrz_bytes[2], ]); const commitment_js = commitment_bytes.toString(); - console.log('commitment_js', commitment_js) - console.log('commitment_circom', commitment_circom) + console.log('commitment_js', commitment_js); + console.log('commitment_circom', commitment_circom); // TODO: fix with new leaf hasher // expect(commitment_circom).to.be.equal(commitment_js); }); @@ -106,7 +120,9 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { try { const invalidInputs = { ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), + dataHashes: inputs.dataHashes.map((byte: string) => + String((parseInt(byte, 10) + 1) % 256) + ), }; await circuit.calculateWitness(invalidInputs); expect.fail('Expected an error but none was thrown.'); @@ -119,8 +135,12 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { try { const invalidInputs = { ...inputs, - signature: inputs.signature ? inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) : undefined, - signature_s: inputs.signature_s ? inputs.signature_s.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) : undefined, + signature: inputs.signature + ? inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) + : undefined, + signature_s: inputs.signature_s + ? inputs.signature_s.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) + : undefined, }; await circuit.calculateWitness(invalidInputs); expect.fail('Expected an error but none was thrown.'); From 29929d818acc6c267e066a5686a2e256a2d87a23 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Sat, 14 Sep 2024 15:11:47 +0900 Subject: [PATCH 18/18] add prettier to common, not running it to avoid bad merge --- common/package.json | 9 ++++++--- common/yarn.lock | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/common/package.json b/common/package.json index 311a3716..0aaafe1b 100644 --- a/common/package.json +++ b/common/package.json @@ -2,9 +2,11 @@ "name": "openpassport-common", "version": "0.0.1", "author": "", -"license": "MIT", + "license": "MIT", "scripts": { - "test": "yarn ts-mocha tests/**/*.test.ts --exit" + "test": "yarn ts-mocha tests/**/*.test.ts --exit", + "format": "prettier --write .", + "lint": "prettier --check ." }, "dependencies": { "@ashpect/smt": "https://github.com/ashpect/smt#main", @@ -32,6 +34,7 @@ "typescript-parser": "^2.6.1" }, "devDependencies": { - "@types/node-forge": "^1.3.10" + "@types/node-forge": "^1.3.10", + "prettier": "^3.3.3" } } diff --git a/common/yarn.lock b/common/yarn.lock index a2c29ebd..a48c2e13 100644 --- a/common/yarn.lock +++ b/common/yarn.lock @@ -1212,6 +1212,11 @@ possible-typed-array-names@^1.0.0: resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== +prettier@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + process@^0.11.1: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"