From 3acd7692644e7a084bbb8492c446134cf34ef091 Mon Sep 17 00:00:00 2001 From: 0xturboblitz Date: Mon, 27 Jan 2025 19:01:08 -0800 Subject: [PATCH] Started working on DSC circuit with new architure - cleanups --- app/src/screens/ProveScreen.tsx | 4 +- circuits/circuits/dsc/dsc.circom | 108 ++++++++------- .../dsc/instances/dsc_sha1_rsa_3_4096.circom | 2 +- .../instances/dsc_sha1_rsa_65537_4096.circom | 2 +- .../instances/dsc_sha256_rsa_3_4096.circom | 2 +- .../dsc_sha256_rsa_65537_4096.circom | 3 +- .../dsc_sha256_rsapss_65537_4096.circom | 2 +- .../dsc_sha384_rsa_65537_4096.circom | 2 +- .../dsc_sha512_rsa_65537_4096.circom | 2 +- ...sha256_sha256_sha256_rsa_65537_3072.circom | 5 - circuits/circuits/register/register.circom | 102 +++++--------- .../circuits/tests/others/test_glue.circom | 37 ----- .../tests/others/test_glue_120_35.circom | 22 --- .../tests/others/test_glue_32_7.circom | 21 --- .../tests/others/test_glue_64_4.circom | 22 --- .../tests/others/test_glue_64_6.circom | 22 --- .../tests/others/test_glue_64_8.circom | 22 --- .../circuits/utils/crypto/bitify/bytes.circom | 43 +++--- .../utils/crypto/utils/WordToBytes.circom | 47 ------- .../utils/passport/checkPubkeysEqual.circom | 31 +++++ .../circuits/utils/passport/constants.circom | 27 +++- .../utils/passport/customHashers.circom | 1 + .../passport/dsc/ExtractPublicKey.circom | 34 ----- .../dsc/StandardizePubKeyTo35Words.circom | 17 --- .../utils/passport/signatureAlgorithm.circom | 75 +--------- circuits/tests/dsc/dsc.test.ts | 17 +-- common/src/constants/constants.ts | 5 +- common/src/utils/circuits/circuitsName.ts | 1 - common/src/utils/circuits/generateInputs.ts | 130 ++++++++++++------ common/src/utils/csca.ts | 6 +- common/src/utils/passports/passport.ts | 4 + prover/tests/modal.test.ts | 8 +- registry/README.md | 2 +- registry/package.json | 2 +- 34 files changed, 284 insertions(+), 546 deletions(-) delete mode 100644 circuits/circuits/register/instances/register_sha256_sha256_sha256_rsa_65537_3072.circom delete mode 100644 circuits/circuits/tests/others/test_glue.circom delete mode 100644 circuits/circuits/tests/others/test_glue_120_35.circom delete mode 100644 circuits/circuits/tests/others/test_glue_32_7.circom delete mode 100644 circuits/circuits/tests/others/test_glue_64_4.circom delete mode 100644 circuits/circuits/tests/others/test_glue_64_6.circom delete mode 100644 circuits/circuits/tests/others/test_glue_64_8.circom delete mode 100644 circuits/circuits/utils/crypto/utils/WordToBytes.circom create mode 100644 circuits/circuits/utils/passport/checkPubkeysEqual.circom delete mode 100644 circuits/circuits/utils/passport/dsc/ExtractPublicKey.circom delete mode 100644 circuits/circuits/utils/passport/dsc/StandardizePubKeyTo35Words.circom diff --git a/app/src/screens/ProveScreen.tsx b/app/src/screens/ProveScreen.tsx index f0b693e4d..167ce31a6 100644 --- a/app/src/screens/ProveScreen.tsx +++ b/app/src/screens/ProveScreen.tsx @@ -5,7 +5,7 @@ import { Progress, Spinner, Text, XStack, YStack } from 'tamagui'; import { DEVELOPMENT_MODE, - max_cert_bytes, + max_dsc_bytes, } from '../../../common/src/constants/constants'; import { DisclosureOptions, @@ -193,7 +193,7 @@ const ProveScreen: React.FC = ({ const cscaInputs = generateCircuitInputsDSC( dscSecret as string, passportData.dsc, - max_cert_bytes, + max_dsc_bytes, selectedApp.devMode, ); [dscProof, proof] = await Promise.all([ diff --git a/circuits/circuits/dsc/dsc.circom b/circuits/circuits/dsc/dsc.circom index a7d6f29b9..ef7eac817 100644 --- a/circuits/circuits/dsc/dsc.circom +++ b/circuits/circuits/dsc/dsc.circom @@ -9,70 +9,78 @@ include "@zk-kit/binary-merkle-root.circom/src/binary-merkle-root.circom"; include "../utils/passport/customHashers.circom"; include "../utils/passport/signatureAlgorithm.circom"; include "../utils/passport/signatureVerifier.circom"; -include "../utils/crypto/utils/WordToBytes.circom"; +include "../utils/passport/checkPubkeysEqual.circom"; +// include "../utils/crypto/utils/WordToBytes.circom"; include "../utils/passport/constants.circom"; -include "../utils/passport/dsc/StandardizePubKeyTo35Words.circom"; -include "../utils/passport/dsc/ExtractPublicKey.circom"; - -///@input dsc_pubKey_bytes public key of the DSC in bytes padded to 525 bytes -///@input dsc_pubKey_offset offset of the DSC public key in the certificate -///@input dsc_pubkey_length_bytes length of the DSC public key in bytes. For ECDSA, it is x+y length -template DSC(signatureAlgorithm, n_csca, k_csca, max_cert_bytes, nLevels) { - var maxPubkeyBytesLength = getMaxDscPubKeyLength(); - +include "../utils/crypto/bitify/bytes.circom"; +// include "../utils/crypto/bitify/splitWordsToBytes.circom"; + +template DSC( + signatureAlgorithm, + n_csca, + k_csca +) { + var MAX_CSCA_LENGTH = getMaxCSCALength(); + var MAX_DSC_LENGTH = getMaxDSCLength(); + var MAX_CSCA_PUBKEY_LENGTH = getMaxCSCAPubKeyLength(); + var nLevels = getMaxCSCALevels(); + // variables verification - assert(max_cert_bytes % 64 == 0); - // assert(n_csca * k_csca > max_cert_bytes); + assert(MAX_CSCA_LENGTH % 64 == 0); // it's 1664 currently + assert(MAX_DSC_LENGTH % 64 == 0); // it's 1664 currently + // assert(n_csca * k_csca > max_dsc_bytes); // not sure what this is for assert(n_csca <= (255 \ 2)); var hashLength = getHashLength(signatureAlgorithm); var kLengthFactor = getKLengthFactor(signatureAlgorithm); var kScaled = k_csca * kLengthFactor; - signal input raw_dsc_cert[max_cert_bytes]; - signal input raw_dsc_cert_padded_bytes; + var csca_pubkey_length_bytes = (getKeyLength(signatureAlgorithm) / 8) * kLengthFactor; + + signal input raw_csca[MAX_CSCA_LENGTH]; + signal input raw_csca_actual_length; + signal input csca_pubKey_offset; + + signal input raw_dsc[MAX_DSC_LENGTH]; + signal input raw_dsc_actual_length; + signal input csca_pubKey[kScaled]; signal input signature[kScaled]; - signal input dsc_pubKey_bytes[maxPubkeyBytesLength]; - signal input dsc_pubKey_offset; - signal input dsc_pubkey_length_bytes; - signal input merkle_root; - signal input path[nLevels]; - signal input siblings[nLevels]; - signal input salt; + + // signal input merkle_root; + // signal input path[nLevels]; + // signal input siblings[nLevels]; + + log("raw_csca_actual_length", raw_csca_actual_length); + log("csca_pubKey_offset", csca_pubKey_offset); + log("csca_pubkey_length_bytes", csca_pubkey_length_bytes); + + log("raw_dsc_actual_length", raw_dsc_actual_length); // check offsets refer to valid ranges - signal dscPubkeyOffsetInRange <== LessEqThan(14)([dsc_pubKey_offset + dsc_pubkey_length_bytes, raw_dsc_cert_padded_bytes]); - dscPubkeyOffsetInRange === 1; + signal csca_pubKey_offset_in_range <== LessEqThan(14)([ // TODO update this value with log2(MAX_CSCA_LENGTH) + csca_pubKey_offset + csca_pubkey_length_bytes, + raw_csca_actual_length + ]); + csca_pubKey_offset_in_range === 1; - // leaf - signal leaf <== CustomHasher(kScaled)(csca_pubKey); + // compute leaf in the CSCA Merkle tree and verify inclusion + signal csca_tree_leaf <== PackBytesAndPoseidon(MAX_CSCA_LENGTH)(raw_csca); + // signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(csca_tree_leaf, nLevels, path, siblings); + // merkle_root === computed_merkle_root; - signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(leaf, nLevels, path, siblings); - merkle_root === computed_merkle_root; - - // verify certificate signature - signal hashedCertificate[hashLength] <== ShaBytesDynamic(hashLength, max_cert_bytes)(raw_dsc_cert, raw_dsc_cert_padded_bytes); + // get CSCA public key from the certificate + signal extracted_csca_pubKey[MAX_CSCA_PUBKEY_LENGTH] <== SelectSubArray(MAX_CSCA_LENGTH, MAX_CSCA_PUBKEY_LENGTH)(raw_csca, csca_pubKey_offset, csca_pubkey_length_bytes); + + // check if the CSCA public key is the same as the one in the certificate + // If we end up adding the pubkey in the CSCA leaf, we'll be able to remove this check + CheckPubkeysEqual(n_csca, kScaled, csca_pubkey_length_bytes, MAX_CSCA_PUBKEY_LENGTH)(csca_pubKey, extracted_csca_pubKey); + + // verify DSC signature + signal hashedCertificate[hashLength] <== ShaBytesDynamic(hashLength, MAX_DSC_LENGTH)(raw_dsc, raw_dsc_actual_length); SignatureVerifier(signatureAlgorithm, n_csca, k_csca)(hashedCertificate, csca_pubKey, signature); - //Extract certificate public key from certificate - component extractPubKey = ExtractPublicKey(max_cert_bytes, maxPubkeyBytesLength); - extractPubKey.raw_dsc_cert <== raw_dsc_cert; - extractPubKey.dsc_pubKey_offset <== dsc_pubKey_offset; - extractPubKey.dsc_pubkey_length_bytes <== dsc_pubkey_length_bytes; - - //compare extracted public key with the one provided - for (var i=0; i= 8 * l){ - bits2num[i].in[j] <== 0; - } - else{ + for (var j = 0 ; j < n ; j++) { + if (i*n + j >= 8 * l) { + bits2num[i].in[j] <== 0; + } else { bits2num[i].in[j] <== num2bits[l - (( i * n + j) \ 8) - 1].out[ ((i * n + j) % 8)]; } } } - for( var i = 0 ; i< k ; i++){ - out[i] <== bits2num[i].out; + for(var i = 0 ; i < k ; i++){ + out[i] <== bits2num[i].out; } } /// NOTE: this circuit is unaudited and should not be used in production -/// @title SplitBytesToWords +/// @title SplitSignalsToWords /// @notice split an array of bytes into an array of words /// @notice useful for casting a message or modulus before RSA verification /// @param l: number of bytes in the input array @@ -72,31 +72,30 @@ template SplitBytesToWords (l,n,k) { /// @param k: number of words /// @input in: array of bytes /// @output out: array of words -template SplitSignalsToWords (t,l,n,k) { +template SplitSignalsToWords(t,l,n,k) { signal input in[l]; signal output out[k]; + component num2bits[l]; - for (var i = 0 ; i < l ; i++){ + for (var i = 0 ; i < l ; i++) { num2bits[i] = Num2Bits(t); num2bits[i].in <== in[i]; } - for (var i = 0 ; i < t ; i ++){ - } + component bits2num[k]; - for (var i = 0 ; i < k ; i++){ + for (var i = 0 ; i < k ; i++) { bits2num[i] = Bits2Num(n); for(var j = 0 ; j < n ; j++){ - if(i*n + j >= l * t){ - bits2num[i].in[j] <== 0; - } - else{ + if (i*n + j >= l * t) { + bits2num[i].in[j] <== 0; + } else { bits2num[i].in[j] <== num2bits[ (( i * n + j) \ t) ].out[ ((i * n + j) % t)]; } - } - } - for( var i = 0 ; i< k ; i++){ - out[i] <== bits2num[i].out; + } } + for(var i = 0 ; i < k ; i++) { + out[i] <== bits2num[i].out; + } } \ No newline at end of file diff --git a/circuits/circuits/utils/crypto/utils/WordToBytes.circom b/circuits/circuits/utils/crypto/utils/WordToBytes.circom deleted file mode 100644 index 12dc2a8c7..000000000 --- a/circuits/circuits/utils/crypto/utils/WordToBytes.circom +++ /dev/null @@ -1,47 +0,0 @@ -pragma circom 2.1.9; -include "circomlib/circuits/bitify.circom"; - -template WordsToBytes(n_words, k_words, maxBytesLength) { - assert(n_words * k_words == maxBytesLength * 8); - - signal input words[k_words]; - signal output bytes[maxBytesLength]; - - component num2bits[k_words]; - signal word_bits[k_words * n_words]; - - // Convert words to bits - for (var i = 0; i < k_words; i++) { - num2bits[i] = Num2Bits(n_words); - num2bits[i].in <== words[i]; - } - for (var i = 0; i < k_words; i++) { - for (var j = 0; j < n_words; j++) { - word_bits[i * n_words + j] <== num2bits[i].out[j]; - } - } - - // Convert bits back to bytes - component bits2Num[maxBytesLength]; - for (var i = 0; i < maxBytesLength; i++) { - bits2Num[i] = Bits2Num(8); - for (var j = 0; j < 8; j++) { - bits2Num[i].in[j] <== word_bits[i * 8 + j]; - } - bytes[i] <== bits2Num[i].out; - } -} - -template ByteMaskDynamic(maxLength) { - signal input in[maxLength]; - signal input maxValidByte; - signal output out[maxLength]; - - component lt[maxLength]; - for (var i=0; i< maxLength; i++) { - lt[i] = LessThan(32); - lt[i].in[0] <== i; - lt[i].in[1] <== maxValidByte; - out[i] <== in[i] * lt[i].out; - } -} diff --git a/circuits/circuits/utils/passport/checkPubkeysEqual.circom b/circuits/circuits/utils/passport/checkPubkeysEqual.circom new file mode 100644 index 000000000..f971d838b --- /dev/null +++ b/circuits/circuits/utils/passport/checkPubkeysEqual.circom @@ -0,0 +1,31 @@ +pragma circom 2.1.9; + +include "../crypto/bitify/bytes.circom"; +include "../crypto/bitify/splitWordsToBytes.circom"; + +/// @title CheckPubkeysEqual +/// @notice Checks if the CSCA public key given is the same as the one in the certificate +/// @param kScaled Number of chunks the given key is split into. +/// @param MAX_CSCA_PUBKEY_LENGTH Maximum length of the parsed CSCA public key +/// @input csca_pubKey CSCA public key given by the user, formatted for signature verification +/// @input extracted_csca_pubKey CSCA public key extracted from the certificate +template CheckPubkeysEqual(n, kScaled, csca_pubkey_length_bytes, MAX_CSCA_PUBKEY_LENGTH) { + signal input csca_pubKey[kScaled]; + signal input extracted_csca_pubKey[MAX_CSCA_PUBKEY_LENGTH]; + + signal csca_pubKey_bytes[MAX_CSCA_PUBKEY_LENGTH] <== WordsToBytes(n, kScaled, n * kScaled / 8)(csca_pubKey); + + // reverse bytes order + signal padded_csca_pubKey_bytes[MAX_CSCA_PUBKEY_LENGTH]; + for (var i = 0; i < csca_pubkey_length_bytes; i++) { + padded_csca_pubKey_bytes[i] <== csca_pubKey_bytes[csca_pubkey_length_bytes - i - 1]; + } + + for (var i = csca_pubkey_length_bytes; i < MAX_CSCA_PUBKEY_LENGTH; i++) { + padded_csca_pubKey_bytes[i] <== 0; + } + + for (var i = 0; i < MAX_CSCA_PUBKEY_LENGTH; i++) { + padded_csca_pubKey_bytes[i] === extracted_csca_pubKey[i]; + } +} \ No newline at end of file diff --git a/circuits/circuits/utils/passport/constants.circom b/circuits/circuits/utils/passport/constants.circom index 04a086b68..393d935f2 100644 --- a/circuits/circuits/utils/passport/constants.circom +++ b/circuits/circuits/utils/passport/constants.circom @@ -4,6 +4,31 @@ pragma circom 2.1.9; /// @notice Contains constants for the passport circuit /// @notice Maximum length of the DSC public key — currently 512 bytes padded to 525 -function getMaxDscPubKeyLength(){ +function getMaxDSCPubKeyLength(){ return 525; } + +/// @notice Maximum length of the CSCA public key — maybe should be 1024 bytes padded to 1056 +function getMaxCSCAPubKeyLength(){ + return 525; // TODO update with the correct value +} + +/// @notice Maximum length of DSC certificate — currently 1664 bytes +function getMaxDSCLength(){ + return 1664; +} + +/// @notice Maximum length of CSCA certificate — currently 1664 bytes +function getMaxCSCALength(){ + return 1664; // TODO update with the correct value +} + +/// @notice Maximum number of levels in the CSCA Merkle tree — currently 12 +function getMaxCSCALevels(){ + return 12; +} + +/// @notice Maximum number of levels in the DSC Merkle tree — currently 12 +function getMaxDSCLevels(){ + return 12; +} \ No newline at end of file diff --git a/circuits/circuits/utils/passport/customHashers.circom b/circuits/circuits/utils/passport/customHashers.circom index c4cea96a9..ccf543890 100644 --- a/circuits/circuits/utils/passport/customHashers.circom +++ b/circuits/circuits/utils/passport/customHashers.circom @@ -53,6 +53,7 @@ template CustomHasher(k) { /// @param out Output hash template PackBytesAndPoseidon(k) { var packed_length = computeIntChunkLength(k); + signal input in[k]; signal packed[packed_length] <== PackBytes(k)(in); signal output out <== CustomHasher(packed_length)(packed); diff --git a/circuits/circuits/utils/passport/dsc/ExtractPublicKey.circom b/circuits/circuits/utils/passport/dsc/ExtractPublicKey.circom deleted file mode 100644 index ad06fab2f..000000000 --- a/circuits/circuits/utils/passport/dsc/ExtractPublicKey.circom +++ /dev/null @@ -1,34 +0,0 @@ -pragma circom 2.1.9; -include "@openpassport/zk-email-circuits/utils/array.circom"; - -template ExtractPublicKey(max_cert_bytes, maxPubkeyBytesLength) { - signal input raw_dsc_cert[max_cert_bytes]; - signal input dsc_pubKey_offset; - signal input dsc_pubkey_length_bytes; - signal output out[maxPubkeyBytesLength]; - - //reverse the certificate - signal raw_dsc_cert_reversed[max_cert_bytes]; - for (var i=0; i { + it('should compute a valid witness', async () => { const witness = await circuit.calculateWitness(inputs.inputs, true); + await circuit.checkConstraints(witness); console.log('\x1b[34m%s\x1b[0m', 'witness generated ', sigAlg); - // const blinded_dsc_commitment = (await circuit.getOutput(witness, ['blinded_dsc_commitment'])) - // .blinded_dsc_commitment; - // console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment: ', blinded_dsc_commitment); - // const merkle_root = (await circuit.getOutput(witness, ['merkle_root'])).merkle_root; - // console.log('\x1b[34m%s\x1b[0m', 'merkle_root: ', merkle_root); - // expect(blinded_dsc_commitment).to.be.not.null; + const dsc_tree_leaf = (await circuit.getOutput(witness, ['dsc_tree_leaf'])) + .dsc_tree_leaf; + console.log('\x1b[34m%s\x1b[0m', 'dsc_tree_leaf: ', dsc_tree_leaf); }); }); }); diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index f92030fcc..000d3ce8b 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -1,5 +1,3 @@ -import { SignatureAlgorithm } from '../utils/types'; - export const RELAYER_URL = 'https://0pw5u65m3a.execute-api.eu-north-1.amazonaws.com/api-stage/mint'; //export const COMMITMENT_TREE_TRACKER_URL = "https://app.proofofpassport.com/apiv2/download-merkle-tree" export const COMMITMENT_TREE_TRACKER_URL = @@ -131,7 +129,8 @@ export const n_csca = 120; export const k_csca = 35; export const n_dsc_ecdsa = 64; export const k_dsc_ecdsa = 4; -export const max_cert_bytes = 1664; +export const max_dsc_bytes = 1664; +export const max_csca_bytes = 1664; // TODO: change this value export const countryCodes = { AFG: 'Afghanistan', ALA: 'Aland Islands', diff --git a/common/src/utils/circuits/circuitsName.ts b/common/src/utils/circuits/circuitsName.ts index 0a8868012..c78a8ad1f 100644 --- a/common/src/utils/circuits/circuitsName.ts +++ b/common/src/utils/circuits/circuitsName.ts @@ -16,7 +16,6 @@ export function getCircuitNameFromPassportData(passportData: PassportData, circu } function getDSCircuitNameFromPassportData(passportData: PassportData) { - const passportMetadata = parsePassportData(passportData); const signatureAlgorithm = passportMetadata.cscaSignatureAlgorithm; const hashFunction = passportMetadata.cscaHashFunction; diff --git a/common/src/utils/circuits/generateInputs.ts b/common/src/utils/circuits/generateInputs.ts index 8ff02a883..cc00eab37 100644 --- a/common/src/utils/circuits/generateInputs.ts +++ b/common/src/utils/circuits/generateInputs.ts @@ -3,6 +3,8 @@ import { MAX_PADDED_ECONTENT_LEN, MAX_PADDED_SIGNED_ATTR_LEN, SignatureAlgorithmIndex, + max_dsc_bytes, + max_csca_bytes, } from '../../constants/constants'; import { PassportData } from '../types'; import { LeanIMT } from '@openpassport/zk-kit-lean-imt'; @@ -18,6 +20,7 @@ import { getPassportSignatureInfos, getSignatureAlgorithmFullName, pad, + padWithZeroes, } from '../passports/passport'; import { toUnsignedByte } from '../bytes'; import { customHasher, hash, packBytesAndPoseidon } from '../hash'; @@ -33,78 +36,88 @@ import { PublicKeyDetailsECDSA, PublicKeyDetailsRSA } from '../certificate_parsi import { getLeafCSCA } from '../pubkeyTree'; export function generateCircuitInputsDSC( - dscSecret: string, dscCertificate: string, - max_cert_bytes: number, devMode: boolean = false ) { - const certificateData = parseCertificateSimple(dscCertificate); - const TbsBytes = getTBSBytes(dscCertificate); - const { - signatureAlgorithm, - hashAlgorithm, - publicKeyDetails, - authorityKeyIdentifier, - } = certificateData; - - const signatureAlgorithmFullName = getSignatureAlgorithmFullName( - certificateData, - signatureAlgorithm, - hashAlgorithm - ); + // Get CSCA that signed the DSC + const { authorityKeyIdentifier } = parseCertificateSimple(dscCertificate); + console.log('js: authorityKeyIdentifier', authorityKeyIdentifier); + const cscaPem = getCSCAFromSKI(authorityKeyIdentifier, devMode); + console.log('js: cscaPem', cscaPem); + const cscaCertData = parseCertificateSimple(cscaPem); + console.log('js: cscaCertData', cscaCertData); - const pubKey_dsc = formatCertificatePubKeyDSC( - certificateData, - signatureAlgorithm, - ); + const cscaTbsBytes = getTBSBytes(cscaPem); + console.log('js: cscaTbsBytes', cscaTbsBytes); + console.log('js: cscaTbsBytes length', cscaTbsBytes.length); + const cscaTbsBytesPadded = padWithZeroes(Array.from(cscaTbsBytes), max_csca_bytes); // TODO: change this to the actual hash algorithm + console.log('js: cscaTbsBytesPadded', cscaTbsBytesPadded); + console.log('js: cscaTbsBytesPadded length', cscaTbsBytesPadded.length); - const [raw_dsc_cert_padded, raw_dsc_cert_padded_bytes] = pad(hashAlgorithm)( - TbsBytes, - max_cert_bytes - ); + const dscTbsBytes = getTBSBytes(dscCertificate); + console.log('js: dscTbsBytes', dscTbsBytes); + console.log('js: dscTbsBytes length', dscTbsBytes.length); + // const dscTbsBytesPadded = padWithZeroes(Array.from(dscTbsBytes), max_dsc_bytes); + // console.log('js: dscTbsBytesPadded', dscTbsBytesPadded); + // console.log('js: dscTbsBytesPadded length', dscTbsBytesPadded.length); - // Get start index based on algorithm - const startIndex = findStartPubKeyIndex(certificateData, raw_dsc_cert_padded, signatureAlgorithm); - - // Get CSCA certificate and proof - const cscaPem = getCSCAFromSKI(authorityKeyIdentifier, devMode); - const leaf = getLeafCSCA(cscaPem); - const [root, proof] = getCSCAModulusProof(leaf); + const [dscTbsBytesPadded, dscTbsBytesLen] = pad(cscaCertData.hashAlgorithm)( // do we want to keep this padding for the commitment? Not sure + dscTbsBytes, + max_dsc_bytes + ); + console.log('js: dscTbsBytesPadded', dscTbsBytesPadded); + console.log('js: dscTbsBytesPadded length', dscTbsBytesPadded.length); + + // TODO: get the CSCA inclusion proof + // const leaf = getLeafCSCA(cscaPem); + // const [root, proof] = getCSCAModulusProof(leaf); // Parse CSCA certificate and get its public key - const cscaCertData = parseCertificateSimple(cscaPem); const csca_pubKey_formatted = getCertificatePubKey( cscaCertData, cscaCertData.signatureAlgorithm, cscaCertData.hashAlgorithm ); + const modulus = (cscaCertData.publicKeyDetails as PublicKeyDetailsRSA).modulus; + const modulus_bytes = Array.from(Buffer.from(modulus, 'hex')); + console.log('js: modulus_bytes', modulus_bytes); + console.log('js: modulus_bytes[modulus_bytes.length - 1]', modulus_bytes[modulus_bytes.length - 1]); + console.log('js: modulus_bytes length', modulus_bytes.length); + console.log('js: csca_pubKey_formatted', csca_pubKey_formatted); + console.log('js: csca_pubKey_formatted length', csca_pubKey_formatted.length); + + const csca_pubkey_length_bytes = Number(cscaCertData.publicKeyDetails.bits) / 8; + console.log('js: csca_pubkey_length_bytes', csca_pubkey_length_bytes); + const CSCAsignatureAlgorithmFullName = getSignatureAlgorithmFullName( cscaCertData, cscaCertData.signatureAlgorithm, cscaCertData.hashAlgorithm ); + console.log('js: CSCAsignatureAlgorithmFullName', CSCAsignatureAlgorithmFullName); const signatureRaw = extractSignatureFromDSC(dscCertificate); + // console.log('js: signatureRaw', signatureRaw); const signature = formatSignatureDSCCircuit(CSCAsignatureAlgorithmFullName, cscaPem, signatureRaw,); + // console.log('js: signature', signature); - const dsc_pubkey_length_bytes = signatureAlgorithm === 'ecdsa' - ? (Number((publicKeyDetails as PublicKeyDetailsECDSA).bits) / 8) * 2 - : Number((publicKeyDetails as PublicKeyDetailsRSA).bits) / 8; + // Get start index of CSCA pubkey based on algorithm + const startIndex = findStartPubKeyIndex(cscaCertData, cscaTbsBytesPadded, cscaCertData.signatureAlgorithm); + console.log('js: startIndex', startIndex); return { - signature_algorithm: signatureAlgorithmFullName, + signature_algorithm: CSCAsignatureAlgorithmFullName, inputs: { - raw_dsc_cert: Array.from(raw_dsc_cert_padded).map(x => x.toString()), - raw_dsc_cert_padded_bytes: [ BigInt(raw_dsc_cert_padded_bytes).toString()], - dsc_pubkey_length_bytes: [dsc_pubkey_length_bytes], + raw_csca: cscaTbsBytesPadded.map(x => x.toString()), + raw_csca_actual_length: [BigInt(cscaTbsBytes.length).toString()], + csca_pubKey_offset: [startIndex.toString()], + raw_dsc: Array.from(dscTbsBytesPadded).map(x => x.toString()), + raw_dsc_actual_length: [BigInt(dscTbsBytesLen).toString()], csca_pubKey: csca_pubKey_formatted, signature, - dsc_pubKey_bytes: pubKey_dsc, - dsc_pubKey_offset: [startIndex.toString()], - merkle_root: [BigInt(root).toString()], - path: proof.pathIndices.map(index => index.toString()), - siblings: proof.siblings.flat().map(sibling => sibling.toString()), - salt: dscSecret, + // merkle_root: [BigInt(root).toString()], + // path: proof.pathIndices.map(index => index.toString()), + // siblings: proof.siblings.flat().map(sibling => sibling.toString()), } }; } @@ -141,6 +154,33 @@ export function generateCircuitInputsRegister( MAX_PADDED_SIGNED_ATTR_LEN[passportMetadata.eContentHashFunction] ); + + // const dsc_pubkey_length_bytes = signatureAlgorithm === 'ecdsa' + // ? (Number((publicKeyDetails as PublicKeyDetailsECDSA).bits) / 8) * 2 + // : Number((publicKeyDetails as PublicKeyDetailsRSA).bits) / 8; + + // const certificateData = parseCertificateSimple(dscCertificate); + + // const signatureAlgorithmFullName = getSignatureAlgorithmFullName( + // certificateData, + // signatureAlgorithm, + // hashAlgorithm + // ); + + // const pubKey_dsc = formatCertificatePubKeyDSC( + // certificateData, + // signatureAlgorithm, + // ); + + // console.log('js: pubKey_dsc', pubKey_dsc); + + // const { + // signatureAlgorithm, + // hashAlgorithm, + // publicKeyDetails, + // authorityKeyIdentifier, + // } = certificateData; + const pubKey_csca = getCertificatePubKey( passportData.csca_parsed, passportMetadata.cscaSignatureAlgorithm, diff --git a/common/src/utils/csca.ts b/common/src/utils/csca.ts index 64fa3ae61..34da8dca4 100644 --- a/common/src/utils/csca.ts +++ b/common/src/utils/csca.ts @@ -149,7 +149,7 @@ export function findOIDPosition( export function generateCircuitInputsDSC( dscSecret: string, dscCertificate: any, - max_cert_bytes: number, + max_dsc_bytes: number, devMode: boolean = false ) { const dscCert = getCertificateFromPem(dscCertificate); @@ -172,8 +172,8 @@ export function generateCircuitInputsDSC( let dsc_messagePaddedLen; [dsc_message_padded, dsc_messagePaddedLen] = hashAlgorithm == 'sha384' || hashAlgorithm == 'sha512' - ? sha384_512Pad(dscTbsCertUint8Array, max_cert_bytes) - : shaPad(dscTbsCertUint8Array, max_cert_bytes); + ? sha384_512Pad(dscTbsCertUint8Array, max_dsc_bytes) + : shaPad(dscTbsCertUint8Array, max_dsc_bytes); // const { n, k } = getNAndK(`${signatureAlgorithm}_${hashAlgorithm}_${exponent}_${bits}` as SignatureAlgorithm); //dsc key is padded to 525 bytes diff --git a/common/src/utils/passports/passport.ts b/common/src/utils/passports/passport.ts index 0bb39bcb7..5f2f6dfbd 100644 --- a/common/src/utils/passports/passport.ts +++ b/common/src/utils/passports/passport.ts @@ -134,6 +134,10 @@ export function pad(hashFunction: (typeof hashAlgos)[number]) { : sha384_512Pad; } +export function padWithZeroes(bytes: number[], length: number) { + return bytes.concat(new Array(length - bytes.length).fill(0)); +} + function validatePassportMetadata(passportData: PassportData): void { if (!passportData.parsed) { throw new Error('Passport data is not parsed'); diff --git a/prover/tests/modal.test.ts b/prover/tests/modal.test.ts index 026d60770..2d9342d02 100644 --- a/prover/tests/modal.test.ts +++ b/prover/tests/modal.test.ts @@ -8,7 +8,7 @@ import { groth16 } from 'snarkjs' import { expect } from "chai"; import path from 'path'; -const max_cert_bytes = 1664; +const max_dsc_bytes = 1664; const vkey_sha256_rsa = JSON.parse(fs.readFileSync(path.join(__dirname, '../src/vkey/dsc_rsa_65537_sha256_4096_vkey.json'), 'utf8')); const vkey_sha256_rsapss = JSON.parse(fs.readFileSync(path.join(__dirname, '../src/vkey/dsc_rsapss_65537_sha256_4096_vkey.json'), 'utf8')); @@ -22,7 +22,7 @@ describe('MODAL PROVER', function () { const inputs = generateCircuitInputsDSC( BigInt(0).toString(), mock_dsc_sha256_rsapss_4096, - max_cert_bytes, + max_dsc_bytes, true ); console.log('\x1b[34msending request to modal server\x1b[0m'); @@ -43,7 +43,7 @@ describe('MODAL PROVER', function () { const inputs = generateCircuitInputsDSC( BigInt(0).toString(), mock_dsc_sha256_rsa_4096, - max_cert_bytes, + max_dsc_bytes, true ); //console.log(JSON.stringify(inputs)); @@ -66,7 +66,7 @@ describe('MODAL PROVER', function () { const inputs = generateCircuitInputsDSC( BigInt(0).toString(), mock_dsc_sha1_rsa_4096, - max_cert_bytes, + max_dsc_bytes, true ); diff --git a/registry/README.md b/registry/README.md index e1a3bc919..f27587e8e 100644 --- a/registry/README.md +++ b/registry/README.md @@ -32,7 +32,7 @@ run the following command to extract the masterlist from the ICAO website as a f | `all` | extract both ```bash -yarn masterlist-extract $arg +yarn extract-masterlist $arg ``` ## Prisma diff --git a/registry/package.json b/registry/package.json index 956c212e7..bf31c8376 100644 --- a/registry/package.json +++ b/registry/package.json @@ -33,4 +33,4 @@ "mapJson": "ts-node src/buildMapJson.ts" }, "license": "MIT" -} \ No newline at end of file +}