fix common test

This commit is contained in:
motemotech
2024-12-03 00:23:35 +09:00
parent 194b367f80
commit 3a43dc372a
38 changed files with 47151 additions and 4489 deletions

View File

@@ -1,30 +1,35 @@
# How we process OFAC lists
## Data Collection
- We collect the data from the official website of the U.S. Department of the Treasury's Office of Foreign Assets Control (OFAC) and download the data in the form of a CSV file from [here](https://sanctionslist.ofac.treas.gov/Home/SdnList)
- The SDN list contains the names of individuals, entities and groups designated by OFAC as well as the listing of maritime vessels and aircraft that are blocked by OFAC.
### ofacdata/original
- The data is stored in the form of 2 CSV files named `sdn.csv` and `add.csv`. `dataspec.txt` explains the data specification for the CSV data files.
- The data is cleaned to obtain the required information for individuals from sdn.csv file.
A ballpark number of 6917 individuals (at the time of writing this document) entries are present in sdn.csv. Remaining entries are entities, vessels, and aircrafts.
A ballpark number of 6917 individuals (at the time of writing this document) entries are present in sdn.csv. Remaining entries are entities, vessels, and aircrafts.
## Data Processing
### ofacdata/scripts
- The `ofac.ipynb` script extracts the data from both the csv's and parses them in json format.
- We parse all ethereum addresses, regardless of individual or entity in eth_addresses.json.
- 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
- 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/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.
- Match through Passport Number: level 3 (Absolute Match)
- Match through Names and Dob combo tree: level 2 (High Probability Match)
- Match only through Names: level 1 (Partial Match)
The merkle tree is also exported as json in ofacdata/outputs for time constrained export and import.
The merkle tree is also exported as json in ofacdata/outputs for time constrained export and import.
Check out src/utils/smtTree.ts for more details.<br>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -139391,4 +139391,4 @@
"modulus": "27570890475572156639097623287856775344836252466001838829939036352542925065165961866608001981694334142427166393850202303938965031539138349041940985451272192932917255129033750171058334284262340405798716036258332598943701848757768379165108213023999908375628463308133920742714647194743125516607759412642152196479626108859508107615878099330811114979410920063060013012747400383086275611823457511174768910702059255959955529987050986423961804377001771564313140288755521128325084208639079990434512210328105642000081984169212229143792608985168528834146678403600894638087975271020445992778399449890220397957143415388052709250927",
"exponent": "3"
}
]
]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
"{\n \"root\": [\n \"3723637226454477754871887669092418649720258478086593147152748419758535491072\"\n ],\n \"15584704709027935251733542063227384620511214043307855217534257467792961762417\": [\n \"19105920019330168892048899546191661354446505464368653727052939891020020275805\",\n \"1\",\n \"1\"\n ],\n \"18660127412526139205442115732162973083822266226117299577691589365706228334840\": [\n \"9448785635477331140743014311625361873815551652589535216017416724761959711291\",\n \"1\",\n \"1\"\n ],\n \"6456797921795517597175320242797568338817508339820025997566327150812886169644\": [\n \"14982919419908718594292521020497589548367376867145867222119625916862338523919\",\n \"1\",\n \"1\"\n ],\n \"21448462431008449284508867604706680324695645797406411405909844675752621808583\": [\n \"19703102596598777350706899773704131970636100221024882112358056973375460525180\",\n \"1\",\n \"1\"\n ],\n \"5024298347975147207679629214514067739258346797557077798207564337243614431430\": [\n \"19108373860471292952366838274441500593871822896624734072180780733162956119803\",\n \"1\",\n \"1\"\n ],\n \"11013395557703037597623586619744322870431075171468871030732965621931984693994\": [\n \"18660127412526139205442115732162973083822266226117299577691589365706228334840\",\n \"5024298347975147207679629214514067739258346797557077798207564337243614431430\"\n ],\n \"1729831065139275692261226127032356110526626871751953239635881482684604271822\": [\n \"0\",\n \"11013395557703037597623586619744322870431075171468871030732965621931984693994\"\n ],\n \"1060322943212037380481743131272466461955448453252154411090793429054484697732\": [\n \"0\",\n \"1729831065139275692261226127032356110526626871751953239635881482684604271822\"\n ],\n \"4523419834360633541482415417662748375261328391821173313737837007860212171539\": [\n \"0\",\n \"1060322943212037380481743131272466461955448453252154411090793429054484697732\"\n ],\n \"19887871187824837566992234296328341457952969870292718848038094811162715245761\": [\n \"4523419834360633541482415417662748375261328391821173313737837007860212171539\",\n \"6456797921795517597175320242797568338817508339820025997566327150812886169644\"\n ],\n \"9542848240727884374847323764079677465913066007318782214708529655666364212993\": [\n \"6650657343958618931288105236526996870436425613563673941121571293984874538981\",\n \"1\",\n \"1\"\n ],\n \"9835458972075797025360226408971611448813740733903931664856327566250151778594\": [\n \"9542848240727884374847323764079677465913066007318782214708529655666364212993\",\n \"15584704709027935251733542063227384620511214043307855217534257467792961762417\"\n ],\n \"616896535221117079626842921265491818591744884527738215520950956841510794832\": [\n \"0\",\n \"9835458972075797025360226408971611448813740733903931664856327566250151778594\"\n ],\n \"11054445757535822137133873921702131557138890133764722473542676008237036974196\": [\n \"616896535221117079626842921265491818591744884527738215520950956841510794832\",\n \"19887871187824837566992234296328341457952969870292718848038094811162715245761\"\n ],\n \"3723637226454477754871887669092418649720258478086593147152748419758535491072\": [\n \"21448462431008449284508867604706680324695645797406411405909844675752621808583\",\n \"11054445757535822137133873921702131557138890133764722473542676008237036974196\"\n ]\n}"
"{\n \"root\": [\n \"3723637226454477754871887669092418649720258478086593147152748419758535491072\"\n ],\n \"15584704709027935251733542063227384620511214043307855217534257467792961762417\": [\n \"19105920019330168892048899546191661354446505464368653727052939891020020275805\",\n \"1\",\n \"1\"\n ],\n \"18660127412526139205442115732162973083822266226117299577691589365706228334840\": [\n \"9448785635477331140743014311625361873815551652589535216017416724761959711291\",\n \"1\",\n \"1\"\n ],\n \"6456797921795517597175320242797568338817508339820025997566327150812886169644\": [\n \"14982919419908718594292521020497589548367376867145867222119625916862338523919\",\n \"1\",\n \"1\"\n ],\n \"21448462431008449284508867604706680324695645797406411405909844675752621808583\": [\n \"19703102596598777350706899773704131970636100221024882112358056973375460525180\",\n \"1\",\n \"1\"\n ],\n \"5024298347975147207679629214514067739258346797557077798207564337243614431430\": [\n \"19108373860471292952366838274441500593871822896624734072180780733162956119803\",\n \"1\",\n \"1\"\n ],\n \"11013395557703037597623586619744322870431075171468871030732965621931984693994\": [\n \"18660127412526139205442115732162973083822266226117299577691589365706228334840\",\n \"5024298347975147207679629214514067739258346797557077798207564337243614431430\"\n ],\n \"1729831065139275692261226127032356110526626871751953239635881482684604271822\": [\n \"0\",\n \"11013395557703037597623586619744322870431075171468871030732965621931984693994\"\n ],\n \"1060322943212037380481743131272466461955448453252154411090793429054484697732\": [\n \"0\",\n \"1729831065139275692261226127032356110526626871751953239635881482684604271822\"\n ],\n \"4523419834360633541482415417662748375261328391821173313737837007860212171539\": [\n \"0\",\n \"1060322943212037380481743131272466461955448453252154411090793429054484697732\"\n ],\n \"19887871187824837566992234296328341457952969870292718848038094811162715245761\": [\n \"4523419834360633541482415417662748375261328391821173313737837007860212171539\",\n \"6456797921795517597175320242797568338817508339820025997566327150812886169644\"\n ],\n \"9542848240727884374847323764079677465913066007318782214708529655666364212993\": [\n \"6650657343958618931288105236526996870436425613563673941121571293984874538981\",\n \"1\",\n \"1\"\n ],\n \"9835458972075797025360226408971611448813740733903931664856327566250151778594\": [\n \"9542848240727884374847323764079677465913066007318782214708529655666364212993\",\n \"15584704709027935251733542063227384620511214043307855217534257467792961762417\"\n ],\n \"616896535221117079626842921265491818591744884527738215520950956841510794832\": [\n \"0\",\n \"9835458972075797025360226408971611448813740733903931664856327566250151778594\"\n ],\n \"11054445757535822137133873921702131557138890133764722473542676008237036974196\": [\n \"616896535221117079626842921265491818591744884527738215520950956841510794832\",\n \"19887871187824837566992234296328341457952969870292718848038094811162715245761\"\n ],\n \"3723637226454477754871887669092418649720258478086593147152748419758535491072\": [\n \"21448462431008449284508867604706680324695645797406411405909844675752621808583\",\n \"11054445757535822137133873921702131557138890133764722473542676008237036974196\"\n ]\n}"

View File

@@ -5,43 +5,43 @@ const srcDir = path.join(__dirname, '..', '..', 'src', 'mock_certificates');
const outputFile = path.join(__dirname, '..', '..', 'src', 'constants', 'mockCertificates.ts');
const algorithms = [
'sha1_rsa_2048',
'sha1_rsa_4096',
'sha256_rsa_2048',
'sha256_rsa_4096',
'sha256_rsapss_2048',
'sha256_rsapss_4096',
'sha1_rsa_2048',
'sha1_rsa_4096',
'sha256_rsa_2048',
'sha256_rsa_4096',
'sha256_rsapss_2048',
'sha256_rsapss_4096',
];
function readFile(dir: string, filename: string): string | null {
const filePath = path.join(dir, filename);
if (fs.existsSync(filePath)) {
return fs.readFileSync(filePath, 'utf-8').trim();
}
return null;
const filePath = path.join(dir, filename);
if (fs.existsSync(filePath)) {
return fs.readFileSync(filePath, 'utf-8').trim();
}
return null;
}
let output = '';
algorithms.forEach((algo) => {
const algoDir = path.join(srcDir, algo);
const algoDir = path.join(srcDir, algo);
const cscaCert = readFile(algoDir, 'mock_csca.crt') || readFile(algoDir, 'mock_csca.pem');
const dscCert = readFile(algoDir, 'mock_dsc.crt') || readFile(algoDir, 'mock_dsc.pem');
const dscKey = readFile(algoDir, 'mock_dsc.key');
const cscaCert = readFile(algoDir, 'mock_csca.crt') || readFile(algoDir, 'mock_csca.pem');
const dscCert = readFile(algoDir, 'mock_dsc.crt') || readFile(algoDir, 'mock_dsc.pem');
const dscKey = readFile(algoDir, 'mock_dsc.key');
if (cscaCert) {
output += `export const mock_csca_${algo} = \`${cscaCert}\`\n\n`;
}
if (cscaCert) {
output += `export const mock_csca_${algo} = \`${cscaCert}\`\n\n`;
}
if (dscCert) {
output += `export const mock_dsc_${algo} = \`${dscCert}\`\n\n`;
}
if (dscCert) {
output += `export const mock_dsc_${algo} = \`${dscCert}\`\n\n`;
}
if (dscKey) {
output += `export const mock_dsc_key_${algo} = \`${dscKey}\`\n\n`;
}
if (dscKey) {
output += `export const mock_dsc_key_${algo} = \`${dscKey}\`\n\n`;
}
});
fs.writeFileSync(outputFile, output);
console.log(`Certificates and keys have been written to ${outputFile}`);
console.log(`Certificates and keys have been written to ${outputFile}`);

File diff suppressed because it is too large Load Diff

View File

@@ -24,4 +24,4 @@ export const DSC_BLINDED_DSC_COMMITMENT_INDEX = 0;
// Enum in VerifiersManager.sol
export const VERIFICATION_TYPE_ENUM_PROVE = 0;
export const VERIFICATION_TYPE_ENUM_DSC = 1;
export const VERIFICATION_TYPE_ENUM_DSC = 1;

View File

@@ -15,7 +15,7 @@ Tg9gkA98zvV1jbokPL23UXRWufv7L44HIFr3bLeikdOmpf6Lvp1ORiUXjbMi9o+c
ty+gWrxsV+825W3LGD/71DFSD4yS8wK9M9KLZb/21bt6tq4D/E3njnYbXID+1dTL
WC/4nCtzhd5n6cq1wKl6VnZ6bcyYb8MSQ6Kd6vbew1UnRae8KmFsjr2tJ50ESTj4
jQwzIZELkOP+EAE=
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_sha1_rsa_2048 = `-----BEGIN CERTIFICATE-----
MIIC9zCCAd+gAwIBAgIUTwHaCSG0zF1Qc7zH9crP0SpqSIMwDQYJKoZIhvcNAQEF
@@ -34,7 +34,7 @@ ZOL+iNt1vNugU2Ur8FbdpbaMrNDkabWSnOiXVKJ6exXYTvdghaF3P4LkZoiutMXz
/VJ+tmeWZzhVhTQnrN0FBxvh0wfdbbdbosVaJsyB0xTD6C3aBlUTVtxdLdf3B2CA
N0/RDh6kwOOv9mcyF9u/z/YxiZB23csSJyLMmUl9WV2xPCgSZi3A1sZqOU5IIqO3
U4o97Nxcwj51Bm6x5Km/6/CbnXXRo+x+nHgAgYwMn42r4BrLFoDLUn9YRw==
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_key_sha1_rsa_2048 = `-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNAbRAvBrCOUcQ
@@ -63,7 +63,7 @@ Mt8oOSrL/umhcLnBzjQnWBeRe7frD4+a7COxmW71AoGBAO0yhYXOeHpGTnHzDzTs
qu3rNhvQKy/8f25wvqn/xR5NfbcQv/Z63PgmDoq9VLrmeektwY4zTE9wO+n7WPQU
D2BiW2DQjX4OJsOPNs63+wCE71xj08ZxipFuxFWhbjtO/A82h6QMXYwfj9do1WGD
oouEG7wJwn8++cuiivyeTWf1
-----END PRIVATE KEY-----`
-----END PRIVATE KEY-----`;
export const mock_csca_sha1_rsa_4096 = `-----BEGIN CERTIFICATE-----
MIIFCTCCAvGgAwIBAgIUPfIaBL/H++x5cwbWjRnVae1VV3owDQYJKoZIhvcNAQEF
@@ -93,7 +93,7 @@ uMGxRcwP+pPD0lApldU1uEq317cE1gtnZVjNRiZRuVTzaOA0PH98ExjZrmNgbf5o
iIUrC81FHCcvGJmzJdHosAOLRkFZMZS+7ZQ6+dTE4sQwrmSdSVWxNQTRMDjlHgXR
Nqlr+Uj3X+gds1fa0UO6QvCQUmEnRZxXv57HPKobdPJxGtHBUS+2s/3CdFy0KSHB
DeNeFcCggkhoeQqG9D3EXjGz4gre+XjGaH1wPVW0oQoV5BvKsBsMBz2oaZEX
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_sha1_rsa_4096 = `-----BEGIN CERTIFICATE-----
MIID9zCCAd+gAwIBAgIUOUB6xleW+ZGTlubYVAXbnjcaBWkwDQYJKoZIhvcNAQEF
@@ -118,7 +118,7 @@ hi2vmJ/bxS/Ka3mTbaM/3N3T1pLJnSn3vX4IrRH+wb6iQXzGu0Kc7zdYhWBJsv1e
vK/Cc6gkv9LGCBE4m3qfuK0FTuTUTjq2cZgJObDii3oK36Is9MdOPlGhWU1mamlI
wneTF59va2XHfVHmfEv9nPCDBD7YIOxYiQADJ+CJlbq/oe/l0vXvNq+5ikbUus2E
VeMUAwXpTAUekrk=
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_key_sha1_rsa_4096 = `-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCyFWWOPc09c5/t
@@ -147,7 +147,7 @@ fhKFSY14PT560FMvl2GTnolAtzyl3h5xnCks3iAzAoGBAO432byCx+qpdPST9/Vc
T6d6bpNA4Ozcs0nFSfuBbHyUXP2M7j26QrEVOlPqdnp7oHRUIqJTNEiQK2avSSgl
kA4pOhZnWoSso9huxc2ookVVvuWWSZeOhqheOVL4cxTwTjLXQzUa+cjVuVaE1+iD
hxoG8r16SNNAZudx/NDpx1hO
-----END PRIVATE KEY-----`
-----END PRIVATE KEY-----`;
export const mock_csca_sha256_rsa_2048 = `-----BEGIN CERTIFICATE-----
MIID2TCCAsGgAwIBAgIUZJXTESdl0B2qGCUUzv50dNl4VwEwDQYJKoZIhvcNAQEL
@@ -171,7 +171,7 @@ em+yZOTcNKaebx7h6Zokw7+dFKcDV5TjbkB7WYNoejp1bbCo0kNcd6C5N+WmTJkI
0rcRlUErjhIhL3DweERauQnkIltElAwV7Hiwei2cpVl6tLiWO4GydliwxxFod8AW
h88UCDvQ5BjuDnIEW1pER9MbEa5TcQa97D1ads0Unt16E86QIelLxAgdBFvd+4ip
BgA3N9B0gIhmwTvjrGT3WSG+GpQmmokIx+1bRNI=
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_sha256_rsa_2048 = `-----BEGIN CERTIFICATE-----
MIIDzzCCAregAwIBAgIURN604AIW+1RhbYMsyVJsuzSSrqkwDQYJKoZIhvcNAQEL
@@ -195,7 +195,7 @@ LkYTkJCu1UhFWM08NS/JCyjoNEN7JUHD46MzV1Q8yf8UB55jlvRpfqXM+0wUkWtO
Fv00AEvS6Tdui1MbZ/HJAkFsV83ZkYb+wOZAqmh0+Ea46dzMlwuYweKl596fwozo
ZFFNG/h2wwkcakWW1fW980jyvj+Gm6k45YworZ+bT8uoWZTloo1MUFMjdsVRI8FL
M68d6u5tbDtdO8mMPeMIRMq/ug==
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_csca_sha256_rsa_4096 = `-----BEGIN CERTIFICATE-----
MIIFpzCCA4+gAwIBAgIUVGoAk38qsh7YYIE2eANMIeZkr+IwDQYJKoZIhvcNAQEL
@@ -229,7 +229,7 @@ v9tNSlP4Tyzr2b1VoQcgmpQ987afINJG39lq2OsSrlK87p9bB4yoFSZwOfqok0nM
IICRxBuTUHLqP3Nhvo+tAl+iK848LDJVf87ZVQHl72JX4lkVvOo5LCXnOQPyowaP
D++J2c6tUj6gs9HAKVX7fH06m/2T5fJHae/OYx36O242yBXPQdHx6qloF/DNvGyM
EHC3NCCjLG5m6G0=
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_sha256_rsa_4096 = `-----BEGIN CERTIFICATE-----
MIIEkDCCAnigAwIBAgIUVWuy5jJJ5sj+QZfD5gWs3rESlFswDQYJKoZIhvcNAQEL
@@ -257,7 +257,7 @@ WatGH8+eROdlpTfF/xaAUbCJ2UYjRUupGkrpU5KkS9FxrJSVS44PO3xuJwQJN1fC
x2clYiqOEhyESrTp6c5XAGK78S0dwBP2R9o7GqY5xNI+kXBJakqyVpwIPRDq4HVo
y9QRS1jM1G/2Y1XAE9pMdMjdhfYCCp/lO48swOQDty137gzfffo0Bn0039VKzhgi
nUCb8Z7CclWppvFAVjnJruJbGp4=
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_key_sha256_rsa_4096 = `-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDbmfvDt6mQHKcW
@@ -286,7 +286,7 @@ GudUJ9vK1QUulK21It6mF68mysnvifLmAqFm3FhW+QKBgQDVSCw1x3QAtkSswJRX
NFGvIdBSeGBqPpyn4XVU8eQav/uZcjcrB77AemaCG/BwGDQA/nU0eUam0cJn3MP2
NDxMDWR56waCH8Ug/iC0ickLaev1lwj9FvwRpmDLxbmJM4aQgbQw/I1KkSP4ZOAO
2+/QeO6/dvQ2u8OvYn6l0Ls41g==
-----END PRIVATE KEY-----`
-----END PRIVATE KEY-----`;
export const mock_csca_sha256_rsapss_2048 = `-----BEGIN CERTIFICATE-----
MIIDbzCCAiOgAwIBAgIUOXPStXBBfo+yy5ooXC8RB8EeoXMwQQYJKoZIhvcNAQEK
@@ -308,7 +308,7 @@ Mh6+zaJVfiWJoaW/G43j6b4Iarzhiu+hl4WXiQJFQ6Ya3o/MwEQmBV/RnmKHcEq4
tmmZDfBnFxY3RfSPliR81niP0EWD0pxIDI6CzuuqmI+vXnRRob3MAa8mfefof34T
rA0kQqEcklmJFh95bOODC7UjOZlDDTEt7Mxg8CGKwrBxaEN79XCfpDH6kPnNqnfl
W3IkvjmEJJY6dZOOrjyYZ+2ReA==
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_sha256_rsapss_2048 = `-----BEGIN CERTIFICATE-----
MIIDXTCCAhGgAwIBAgIUbOJrpiPFgnwWkNUmues/B8JMbf8wQQYJKoZIhvcNAQEK
@@ -330,7 +330,7 @@ CgJQjLO9n2Ek7IWj1yy0BBTl5UWCsCBdv8CSDorBI+UlOyzbFMvl2wxp8MMOw8oZ
Z3WWH5U/MDtSFDQFTJLRTIlPHl5wtoqCLgZC+fqqmnY1oHPj7KCv2lIFHuTdCbrD
QVmOLpEmz/j8CpSgXpMqBp9A5KTjfZaW5FvBw4O3I7JapyZold9gt50G33ky35S0
gQ==
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_key_sha256_rsapss_2048 = `-----BEGIN PRIVATE KEY-----
MIIEvAIBADALBgkqhkiG9w0BAQoEggSoMIIEpAIBAAKCAQEAwcchJBbCnUPAeMSu
@@ -359,7 +359,7 @@ nUT+0WKQYT6ie+WMN+ryiRjyTzIKCzQHPGBlcQKBgQDFP00AGgLW8yQYj5rxNdif
ok4FOnU5hQHaDwDGqc51Xpl1SqTUc8sNYDqauMIupoq9c37lCzljUakLpFra1DK1
i4UYRl1inWp3BqGVE5V0GN/NYAtQiKUNM5iXf+10UUNrlsJujD6DQL0tttnAFsWl
gR8ctVfp/DLstUdwl54qiQ==
-----END PRIVATE KEY-----`
-----END PRIVATE KEY-----`;
export const mock_csca_sha256_rsapss_4096 = `-----BEGIN CERTIFICATE-----
MIIFbzCCAyOgAwIBAgIUcPyz9NNu9cv8bmvhreKdo5w6JhcwQQYJKoZIhvcNAQEK
@@ -392,7 +392,7 @@ JrurbPjiZ+f+ie/WAI730Mo3OOKnv6z+6qIPr4KqM9MOpECp9u8J0VcWhIDCrYhe
ZOhjTvvbwLrq4Smh8iH6C20IZFK5Je//SOkolBvsRh6ToQoJerR1lWGVlX4ljN8o
9g5hp1KC7Fe25/7Ga14YFAjrXIeRp59zpNCkX4swvUQiSYM4BQTsaNmBEvQQnlT+
9OCw
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_sha256_rsapss_4096 = `-----BEGIN CERTIFICATE-----
MIIEXTCCAhGgAwIBAgIUdS5K/Y5Ty0C8hDFibjmvBeQr4SgwQQYJKoZIhvcNAQEK
@@ -419,7 +419,7 @@ pCrZG4WfUY8ifggReHLoLWSFF8S4JqBKykRu67fbkXLe52VgnYSv6GVxvf1N7mhD
O50iFYNDXId0SgL+adTylqIsr5l5BQw84vf2m+PO8xX2PPFTO6kUsivr9d5cUgVh
duDfJWPas4d3FKdmuSqnUUh7tGWZctzXnA0kBVXa1j5OtU5w+1qp9pbtv/kci2OH
FnvLWs1nzkj58FcjpVG0+ZM=
-----END CERTIFICATE-----`
-----END CERTIFICATE-----`;
export const mock_dsc_key_sha256_rsapss_4096 = `-----BEGIN PRIVATE KEY-----
MIIEvAIBADALBgkqhkiG9w0BAQoEggSoMIIEpAIBAAKCAQEA8De9Voa/OjiMqyxU
@@ -448,14 +448,14 @@ auVZ0ifaBx68dHXkVr6TUNpGnoZ6C4TtLqvPaQKBgQDm66dlLxat1KDfEMXmpOMq
MNaFmxLFgtNngCKgGxHcjOtaMYonPGXVO1uBn+aM4Bcj3Kx21zm8DJBLQmUyIzjc
bUTICRnwWI2dWQz/K5VQuMdEDhxpzDw4uhBun97HlwEZnQnMxrf4whDby1yEnMrk
jXtnkq7Exo0bOsVwH7VNkw==
-----END PRIVATE KEY-----`
-----END PRIVATE KEY-----`;
export const mock_dsc_key_sha256_ecdsa = `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEILM+tyrOADmGjsoNiF/MBuvIscs80M4i1QjVnDy/VBJkoAoGCCqGSM49
AwEHoUQDQgAEQGjDJAD3r/b7oRH2TrgidhLtX+ThLntgul4cdoSEb1fmFcrTgXr4
utAT4/K3aMZ3GrVtCMb5e94lwOlhuOdPdw==
-----END EC PRIVATE KEY-----
`
`;
export const mock_dsc_sha256_ecdsa = `-----BEGIN CERTIFICATE-----
MIICBzCCAa2gAwIBAgIUepk5fECPtH8DJL55fJcGsPCHHowwCgYIKoZIzj0EAwIw
@@ -470,14 +470,14 @@ 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
@@ -492,7 +492,7 @@ Ivww8Qi7kstsJ+IGzhcMzhijITAfMB0GA1UdDgQWBBTRmLBSAQr3AAI4didYznX/
mEvuzDAJBgcqhkjOPQQBA0cAMEQCIB25iNcA7Y3D3E0fv8GIaV0Ei8Ydu4AVuTJW
C8tZvjhWAiBqAuBYm104bRLWaT2uSZexQJgvTPB6j6SdUi0SmR0acw==
-----END CERTIFICATE-----
`
`;
export const mock_dsc_key_sha384_ecdsa = `-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDAw/8AnnGTU8TWWt+SDVr2Gi3TEruQ5tkZ9PObCFtW1nQZaId/f/UFk
@@ -500,7 +500,7 @@ nJgnT7zm72qgBwYFK4EEACKhZANiAARBQCmC0UscKfL8KkVMtO69SU17NIrpLsw5
ibVLxHqcnKMm0FLy0gwU3DFqFF9gPD64EmyoxyE+mo+I3l5rEZPWMqVZOoxCRSww
f6GeHkgco/zGFxnEaklZL7g6gwyUNp8=
-----END EC PRIVATE KEY-----
`
`;
export const mock_dsc_sha384_ecdsa = `-----BEGIN CERTIFICATE-----
MIICRDCCAcqgAwIBAgIUDWqj4BMk0L+D4RpvoSSyc6Lz3mswCgYIKoZIzj0EAwMw
@@ -517,7 +517,7 @@ ADBlAjAu9tM+LZ8PB90F3Wd+mg//Eia6oTM9APo2+E9isiV/sgRwy3HFfAbYnH7c
xy29Ef4CMQCiGvLgkcYMSx3J1bWcq8nuxPBywf440ruiFf95wzm/erjDRFG3u7Dh
d+9Msdsovrc=
-----END CERTIFICATE-----
`
`;
export const mock_dsc_key_sha256_brainpoolP256r1 = `-----BEGIN EC PRIVATE KEY-----
MHgCAQEEICM/qGkSEYZJeejSAl3to/52G9Vw+GDKdvw2BA4Hq4TRoAsGCSskAwMC
@@ -525,7 +525,7 @@ CAEBB6FEA0IABCga+ftPaAL6Bljws48myO1IDRDjaBkyFR3W/esrhP2pb3poTpqd
KDjKkI9hUU1t3cllGYBP4UzL9IUhe4J7I6s=
-----END EC PRIVATE KEY-----
`
`;
export const mock_dsc_sha256_brainpoolP256r1 = `-----BEGIN CERTIFICATE-----
MIICDzCCAbagAwIBAgIUcNlflnEgBabRuI8TtmhfuXeBDxAwCgYIKoZIzj0EAwIw
@@ -541,7 +541,7 @@ BgNVHQ4EFgQUQE/6d9aMviaMEi9k91hdsVguoekwHwYDVR0jBBgwFoAUXOj0kKh6
hlAwf+ljOVwK1ZhDh5lJLicCIEJdrWnH+dUOBL+NecPbLmcFVBCelST9iNCUXTKD
CLpT
-----END CERTIFICATE-----
`
`;
export const mock_dsc_key_sha256_rsa_65537_3072 = `-----BEGIN PRIVATE KEY-----
MIIG/AIBADANBgkqhkiG9w0BAQEFAASCBuYwggbiAgEAAoIBgQCxoTQRUOf0mU86
@@ -675,4 +675,4 @@ cIlCXtLAlhwxvkvq6fXlDHODihiBrcmRBxz08o+IXvjgBYlfHWP5iDS4RO0lzId4
JYSWvyeHGutMDlIMuw5KEE1kVxR2XXcZypc9dWHGaI6MrYwpmmvTB6oZg11FEZzm
S8w23130L6pAB1EjCC8lUQubEkgDZ0bfy4UxpkOiqctzYdakvgo+zOwpORhN/Wxp
Vnmv
-----END CERTIFICATE-----`;
-----END CERTIFICATE-----`;

View File

@@ -1,41 +1,59 @@
export const sampleDataHashes_small = [
[
2,
[
2,
[-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -8]
-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128,
-8,
],
[
3,
[0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6]
],
[
14,
[76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59]
]
] as [number, number[]][]
],
[3, [0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6]],
[
14,
[76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59],
],
] as [number, number[]][];
export const sampleDataHashes_large = [
[
2,
[
2,
[-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38]
-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128,
-8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38,
],
],
[
3,
[
3,
[0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82]
0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6, 36,
21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82,
],
],
[
11,
[
11,
[-120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124]
-120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0,
60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124,
],
],
[
12,
[
12,
[41, -22, 106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114]
41, -22, 106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42,
53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114,
],
],
[
13,
[
13,
[91, -34, -46, -63, 62, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85, -15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18, 38]
91, -34, -46, -63, 62, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85,
-15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18, 38,
],
],
[
14,
[
14,
[76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38]
]
] as [number, number[]][]
76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59,
-100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
],
],
] as [number, number[]][];

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +1,24 @@
import { countryCodes } from '../constants/constants';
import getCountryISO2 from "country-iso-3-to-2";
import getCountryISO2 from 'country-iso-3-to-2';
import { flag } from 'country-emoji';
import fs from 'fs';
import path from 'path';
try {
console.log('Generating country options...');
console.log('Generating country options...');
const countryOptions = Object.keys(countryCodes).map((countryCode, index) => ({
countryCode,
countryName: countryCodes[countryCode as keyof typeof countryCodes],
flagEmoji: flag(getCountryISO2(countryCode)),
index,
}));
const countryOptions = Object.keys(countryCodes).map((countryCode, index) => ({
countryCode,
countryName: countryCodes[countryCode as keyof typeof countryCodes],
flagEmoji: flag(getCountryISO2(countryCode)),
index,
}));
const outputPath = path.join(__dirname, './countryOptions.json');
fs.writeFileSync(outputPath, JSON.stringify(countryOptions, null, 2));
const outputPath = path.join(__dirname, './countryOptions.json');
fs.writeFileSync(outputPath, JSON.stringify(countryOptions, null, 2));
console.log(`Generated country options at ${outputPath}`);
console.log(`Generated country options at ${outputPath}`);
} catch (error) {
console.error('Error generating country options:', error);
process.exit(1);
console.error('Error generating country options:', error);
process.exit(1);
}

View File

@@ -1,9 +1,9 @@
import { DEFAULT_USER_ID_TYPE, WEBSOCKET_URL } from "../constants/constants";
import { UserIdType } from "./utils";
import { DEFAULT_USER_ID_TYPE, WEBSOCKET_URL } from '../constants/constants';
import { UserIdType } from './utils';
export type CircuitName = "prove" | "disclose";
export type CircuitMode = "prove_onchain" | "register" | 'prove_offchain';
export type Mode = "prove_offchain" | "prove_onchain" | "register" | "vc_and_disclose";
export type CircuitName = 'prove' | 'disclose';
export type CircuitMode = 'prove_onchain' | 'register' | 'prove_offchain';
export type Mode = 'prove_offchain' | 'prove_onchain' | 'register' | 'vc_and_disclose';
// OpenPassportAppType
export interface OpenPassportAppPartial {
@@ -18,35 +18,33 @@ export interface OpenPassportAppPartial {
}
export interface OpenPassportApp extends OpenPassportAppPartial {
args: ArgumentsProveOffChain | ArgumentsProveOnChain | ArgumentsRegister | ArgumentsDisclose
args: ArgumentsProveOffChain | ArgumentsProveOnChain | ArgumentsRegister | ArgumentsDisclose;
}
export interface ArgumentsProveOffChain {
disclosureOptions: DisclosureOptions,
disclosureOptions: DisclosureOptions;
}
export interface ArgumentsProveOnChain {
disclosureOptions: DisclosureOptions,
modalServerUrl: string,
merkleTreeUrl: string,
disclosureOptions: DisclosureOptions;
modalServerUrl: string;
merkleTreeUrl: string;
}
export interface ArgumentsRegister {
cscaMerkleTreeUrl: string,
commitmentMerkleTreeUrl: string,
modalServerUrl: string,
cscaMerkleTreeUrl: string;
commitmentMerkleTreeUrl: string;
modalServerUrl: string;
}
export interface ArgumentsDisclose {
disclosureOptions: DisclosureOptions,
commitmentMerkleTreeUrl: string,
disclosureOptions: DisclosureOptions;
commitmentMerkleTreeUrl: string;
}
export interface DisclosureOptions {
minimumAge: { enabled: boolean; value: string }
nationality: { enabled: boolean; value: string }
excludedCountries: { enabled: boolean; value: string[] }
ofac: boolean
minimumAge: { enabled: boolean; value: string };
nationality: { enabled: boolean; value: string };
excludedCountries: { enabled: boolean; value: string[] };
ofac: boolean;
}

View File

@@ -3,114 +3,109 @@ import jsrsasign from 'jsrsasign';
import * as asn1 from 'asn1.js';
import fs from 'fs';
export const RSAPublicKey = asn1.define('RSAPublicKey', function () {
this.seq().obj(
this.key('n').int(),
this.key('e').int()
);
this.seq().obj(this.key('n').int(), this.key('e').int());
});
export function isRsaPublicKey(key) {
return key.type === 'RSA' || key.type === 'RSA-PSS';
return key.type === 'RSA' || key.type === 'RSA-PSS';
}
export function getPublicKey(certificate) {
const publicKeyInfo = certificate.getPublicKeyHex();
const publicKeyInfo = certificate.getPublicKeyHex();
try {
// Try to parse the public key as ASN.1
const publicKeyAsn1 = asn1.define('PublicKey', function () {
this.seq().obj(
this.key('algorithm').seq().obj(
this.key('algorithmId').objid(),
this.key('parameters').optional().any()
),
this.key('publicKey').bitstr()
);
});
try {
// Try to parse the public key as ASN.1
const publicKeyAsn1 = asn1.define('PublicKey', function () {
this.seq().obj(
this.key('algorithm')
.seq()
.obj(this.key('algorithmId').objid(), this.key('parameters').optional().any()),
this.key('publicKey').bitstr()
);
});
const parsed = publicKeyAsn1.decode(Buffer.from(publicKeyInfo, 'hex'), 'der');
const publicKeyBuffer = parsed.publicKey.data;
const parsed = publicKeyAsn1.decode(Buffer.from(publicKeyInfo, 'hex'), 'der');
const publicKeyBuffer = parsed.publicKey.data;
// Parse the RSA public key
const rsaPublicKey = RSAPublicKey.decode(publicKeyBuffer, 'der');
// Parse the RSA public key
const rsaPublicKey = RSAPublicKey.decode(publicKeyBuffer, 'der');
return {
n: new jsrsasign.BigInteger(rsaPublicKey.n.toString('hex'), 16),
e: new jsrsasign.BigInteger(rsaPublicKey.e.toString('hex'), 16),
type: 'RSA'
};
} catch (e) {
console.error("Error parsing public key:", e);
}
return {
n: new jsrsasign.BigInteger(rsaPublicKey.n.toString('hex'), 16),
e: new jsrsasign.BigInteger(rsaPublicKey.e.toString('hex'), 16),
type: 'RSA',
};
} catch (e) {
console.error('Error parsing public key:', e);
}
// If parsing fails, fall back to manual extraction
const modulus = extractModulus(publicKeyInfo);
if (modulus) {
return { n: new jsrsasign.BigInteger(modulus, 16), type: 'RSA' };
}
// If parsing fails, fall back to manual extraction
const modulus = extractModulus(publicKeyInfo);
if (modulus) {
return { n: new jsrsasign.BigInteger(modulus, 16), type: 'RSA' };
}
throw new Error("Unable to extract public key");
throw new Error('Unable to extract public key');
}
function extractModulus(publicKeyInfo: string): string | null {
// RSA OID
const rsaOid = '2a864886f70d010101';
// RSA-PSS OID
const rsaPssOid = '2a864886f70d01010a';
// RSA OID
const rsaOid = '2a864886f70d010101';
// RSA-PSS OID
const rsaPssOid = '2a864886f70d01010a';
let offset = publicKeyInfo.indexOf(rsaOid);
if (offset === -1) {
offset = publicKeyInfo.indexOf(rsaPssOid);
}
let offset = publicKeyInfo.indexOf(rsaOid);
if (offset === -1) {
offset = publicKeyInfo.indexOf(rsaPssOid);
}
if (offset === -1) {
return null;
}
if (offset === -1) {
return null;
}
// Skip OID and move to the bit string
offset = publicKeyInfo.indexOf('03', offset);
if (offset === -1) {
return null;
}
// Skip OID and move to the bit string
offset = publicKeyInfo.indexOf('03', offset);
if (offset === -1) {
return null;
}
// Skip bit string tag and length
offset += 4;
// Skip bit string tag and length
offset += 4;
// Extract modulus
const modulusStart = publicKeyInfo.indexOf('02', offset) + 2;
const modulusLength = parseInt(publicKeyInfo.substr(modulusStart, 2), 16) * 2;
const modulus = publicKeyInfo.substr(modulusStart + 2, modulusLength);
// Extract modulus
const modulusStart = publicKeyInfo.indexOf('02', offset) + 2;
const modulusLength = parseInt(publicKeyInfo.substr(modulusStart, 2), 16) * 2;
const modulus = publicKeyInfo.substr(modulusStart + 2, modulusLength);
return modulus;
return modulus;
}
export function readCertificate(filePath: string): jsrsasign.X509 {
const certPem = fs.readFileSync(filePath, 'utf8');
const certificate = new jsrsasign.X509();
certificate.readCertPEM(certPem);
return certificate;
const certPem = fs.readFileSync(filePath, 'utf8');
const certificate = new jsrsasign.X509();
certificate.readCertPEM(certPem);
return certificate;
}
export function getTBSCertificate(certificate: jsrsasign.X509): Buffer {
// console.log("Certificate:", certificate);
// console.log("Certificate:", certificate);
const certASN1 = certificate.getParam();
// console.log("certASN1:", certASN1);
const certASN1 = certificate.getParam();
// console.log("certASN1:", certASN1);
if (!certASN1) {
console.error("Failed to get certificate parameters");
throw new Error("Invalid certificate structure");
}
if (!certASN1) {
console.error('Failed to get certificate parameters');
throw new Error('Invalid certificate structure');
}
// Extract the TBS part directly from the certificate's hex representation
const certHex = certificate.hex;
const tbsStartIndex = certHex.indexOf('30') + 2; // Start after the first sequence tag
const tbsLength = parseInt(certHex.substr(tbsStartIndex, 2), 16) * 2 + 2; // Length in bytes * 2 for hex + 2 for length field
const tbsHex = certHex.substr(tbsStartIndex - 2, tbsLength); // Include the sequence tag
// Extract the TBS part directly from the certificate's hex representation
const certHex = certificate.hex;
const tbsStartIndex = certHex.indexOf('30') + 2; // Start after the first sequence tag
const tbsLength = parseInt(certHex.substr(tbsStartIndex, 2), 16) * 2 + 2; // Length in bytes * 2 for hex + 2 for length field
const tbsHex = certHex.substr(tbsStartIndex - 2, tbsLength); // Include the sequence tag
// console.log("TBS Hex:", tbsHex);
// console.log("TBS Hex:", tbsHex);
return Buffer.from(tbsHex, 'hex');
}
return Buffer.from(tbsHex, 'hex');
}

View File

@@ -1,127 +1,123 @@
export interface StandardCurve {
name: string;
p: string;
a: string;
b: string;
G: string;
n: string;
h: string;
name: string;
p: string;
a: string;
b: string;
G: string;
n: string;
h: string;
}
export const standardCurves: StandardCurve[] = [
{
name: "secp256r1",
p: "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
a: "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
b: "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
G: "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
n: "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
h: "01"
},
{
name: "secp384r1",
p: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
a: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
b: "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
G: "04AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB73617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
n: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
h: "01"
},
{
name: "secp521r1",
p: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
a: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
b: "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
G: "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
n: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
h: "01"
}
,
{
name: "brainpoolP256r1",
p: "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377",
a: "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9",
b: "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6",
G: "048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997",
n: "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7",
h: "01"
},
{
name: "brainpoolP384r1",
p: "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53",
a: "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826",
b: "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11",
G: "041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315",
n: "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565",
h: "01"
},
{
name: "brainpoolP512r1",
p: "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3",
a: "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA",
b: "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723",
G: "0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892",
n: "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069",
h: "01"
}
{
name: 'secp256r1',
p: 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF',
a: 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC',
b: '5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B',
G: '046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5',
n: 'FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551',
h: '01',
},
{
name: 'secp384r1',
p: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF',
a: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC',
b: 'B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF',
G: '04AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB73617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F',
n: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973',
h: '01',
},
{
name: 'secp521r1',
p: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
a: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC',
b: '0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00',
G: '0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650',
n: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409',
h: '01',
},
{
name: 'brainpoolP256r1',
p: 'A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377',
a: '7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9',
b: '26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6',
G: '048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997',
n: 'A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7',
h: '01',
},
{
name: 'brainpoolP384r1',
p: '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53',
a: '7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826',
b: '04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11',
G: '041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315',
n: '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565',
h: '01',
},
{
name: 'brainpoolP512r1',
p: 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3',
a: '7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA',
b: '3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723',
G: '0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892',
n: 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069',
h: '01',
},
];
export function normalizeHex(hex: string): string {
return hex.toLowerCase().replace(/^0x/, '').replace(/^00/, '');
return hex.toLowerCase().replace(/^0x/, '').replace(/^00/, '');
}
export function identifyCurve(params: any): string {
const normalizedParams = {
p: normalizeHex(params.p),
a: normalizeHex(params.a),
b: normalizeHex(params.b),
G: normalizeHex(params.G),
n: normalizeHex(params.n),
h: normalizeHex(params.h)
};
const normalizedParams = {
p: normalizeHex(params.p),
a: normalizeHex(params.a),
b: normalizeHex(params.b),
G: normalizeHex(params.G),
n: normalizeHex(params.n),
h: normalizeHex(params.h),
};
for (const curve of standardCurves) {
if (
normalizedParams.p === normalizeHex(curve.p) &&
normalizedParams.a === normalizeHex(curve.a) &&
normalizedParams.b === normalizeHex(curve.b) &&
normalizedParams.G === normalizeHex(curve.G) &&
normalizedParams.n === normalizeHex(curve.n) &&
normalizedParams.h === normalizeHex(curve.h)
) {
return curve.name;
}
for (const curve of standardCurves) {
if (
normalizedParams.p === normalizeHex(curve.p) &&
normalizedParams.a === normalizeHex(curve.a) &&
normalizedParams.b === normalizeHex(curve.b) &&
normalizedParams.G === normalizeHex(curve.G) &&
normalizedParams.n === normalizeHex(curve.n) &&
normalizedParams.h === normalizeHex(curve.h)
) {
return curve.name;
}
return "Unknown curve";
}
return 'Unknown curve';
}
export function getNamedCurve(oid: string): string {
const curves = {
'1.2.840.10045.3.1.7': 'secp256r1',
'1.3.132.0.34': 'secp384r1',
'1.3.132.0.35': 'secp521r1',
// Add more curve OIDs as needed
};
return curves[oid] || `Unknown (${oid})`;
const curves = {
'1.2.840.10045.3.1.7': 'secp256r1',
'1.3.132.0.34': 'secp384r1',
'1.3.132.0.35': 'secp521r1',
// Add more curve OIDs as needed
};
return curves[oid] || `Unknown (${oid})`;
}
export function getECDSACurveBits(curveName: string): string {
const curveBits: { [key: string]: number } = {
'secp256r1': 256,
'secp384r1': 384,
'secp521r1': 521,
'brainpoolP256r1': 256,
'brainpoolP384r1': 384,
'brainpoolP512r1': 512,
'secp256r1 (NIST P-256)': 256,
'secp384r1 (NIST P-384)': 384,
'secp521r1 (NIST P-521)': 521,
};
if (curveName in curveBits) {
return curveBits[curveName].toString();
}
console.log('\x1b[31m%s\x1b[0m', `curve name ${curveName} not found in curveBits`);
return "unknown";
}
const curveBits: { [key: string]: number } = {
secp256r1: 256,
secp384r1: 384,
secp521r1: 521,
brainpoolP256r1: 256,
brainpoolP384r1: 384,
brainpoolP512r1: 512,
'secp256r1 (NIST P-256)': 256,
'secp384r1 (NIST P-384)': 384,
'secp521r1 (NIST P-521)': 521,
};
if (curveName in curveBits) {
return curveBits[curveName].toString();
}
console.log('\x1b[31m%s\x1b[0m', `curve name ${curveName} not found in curveBits`);
return 'unknown';
}

View File

@@ -1,36 +1,40 @@
import { StandardCurve } from "./curves";
import { StandardCurve } from './curves';
export interface CertificateData {
id: string;
issuer: string;
validity: {
notBefore: string;
notAfter: string;
};
subjectKeyIdentifier: string;
signatureAlgorithm: string;
hashFunction: string;
publicKeyDetails: PublicKeyDetailsRSA | PublicKeyDetailsECDSA | PublicKeyDetailsRSAPSS | undefined;
rawPem: string;
rawTxt: string;
id: string;
issuer: string;
validity: {
notBefore: string;
notAfter: string;
};
subjectKeyIdentifier: string;
signatureAlgorithm: string;
hashFunction: string;
publicKeyDetails:
| PublicKeyDetailsRSA
| PublicKeyDetailsECDSA
| PublicKeyDetailsRSAPSS
| undefined;
rawPem: string;
rawTxt: string;
}
export interface PublicKeyDetailsRSA {
modulus: string;
exponent: string;
bits: string;
modulus: string;
exponent: string;
bits: string;
}
export interface PublicKeyDetailsRSAPSS extends PublicKeyDetailsRSA {
hashFunction: string;
mgf: string;
saltLength: string;
hashFunction: string;
mgf: string;
saltLength: string;
}
export interface PublicKeyDetailsECDSA {
curve: string;
params: StandardCurve;
bits: string;
x: string;
y: string;
}
curve: string;
params: StandardCurve;
bits: string;
x: string;
y: string;
}

View File

@@ -9,170 +9,269 @@ import { circuitNameFromMode } from '../../constants/constants';
import { Mode } from '../appType';
if (typeof global.Buffer === 'undefined') {
global.Buffer = require('buffer').Buffer;
global.Buffer = require('buffer').Buffer;
}
export function parseCertificate(pem: string) {
const cert = getCertificateFromPem(pem);
let { signatureAlgorithm, hashFunction } = getSignatureAlgorithmDetails(cert.signatureAlgorithm.algorithmId);
const subjectPublicKeyInfo = cert.subjectPublicKeyInfo;
const subjectKeyIdentifier = getSubjectKeyIdentifier(cert);
const authorityKeyIdentifier = getAuthorityKeyIdentifier(cert);
let publicKeyDetails: any;
switch (signatureAlgorithm) {
case 'rsa':
publicKeyDetails = parseRsaPublicKey(subjectPublicKeyInfo);
if (!publicKeyDetails) {
console.log('\x1b[33mRSA public key not found, probably ECDSA certificate\x1b[0m');
}
break;
case 'rsapss':
const rsaPssParams = cert.signatureAlgorithm.algorithmParams;
publicKeyDetails = parseRsaPssPublicKey(subjectPublicKeyInfo, rsaPssParams);
if (publicKeyDetails) {
hashFunction = (publicKeyDetails as PublicKeyDetailsRSAPSS).hashFunction;
}
if (!publicKeyDetails) {
console.log('\x1b[33mRSA-PSS public key not found\x1b[0m');
}
break;
case 'ecdsa':
publicKeyDetails = parseECParameters(subjectPublicKeyInfo);
if (!publicKeyDetails) {
console.log('\x1b[33mECDSA public key not found\x1b[0m');
}
break;
default:
console.log('\x1b[33mUnknown signature algorithm: \x1b[0m', signatureAlgorithm);
}
const hashLen = getHashLen(hashFunction);
return { signatureAlgorithm, hashFunction, hashLen, subjectKeyIdentifier, authorityKeyIdentifier, ...publicKeyDetails };
const cert = getCertificateFromPem(pem);
let { signatureAlgorithm, hashFunction } = getSignatureAlgorithmDetails(
cert.signatureAlgorithm.algorithmId
);
const subjectPublicKeyInfo = cert.subjectPublicKeyInfo;
const subjectKeyIdentifier = getSubjectKeyIdentifier(cert);
const authorityKeyIdentifier = getAuthorityKeyIdentifier(cert);
let publicKeyDetails: any;
switch (signatureAlgorithm) {
case 'rsa':
publicKeyDetails = parseRsaPublicKey(subjectPublicKeyInfo);
if (!publicKeyDetails) {
console.log('\x1b[33mRSA public key not found, probably ECDSA certificate\x1b[0m');
}
break;
case 'rsapss':
const rsaPssParams = cert.signatureAlgorithm.algorithmParams;
publicKeyDetails = parseRsaPssPublicKey(subjectPublicKeyInfo, rsaPssParams);
if (publicKeyDetails) {
hashFunction = (publicKeyDetails as PublicKeyDetailsRSAPSS).hashFunction;
}
if (!publicKeyDetails) {
console.log('\x1b[33mRSA-PSS public key not found\x1b[0m');
}
break;
case 'ecdsa':
publicKeyDetails = parseECParameters(subjectPublicKeyInfo);
if (!publicKeyDetails) {
console.log('\x1b[33mECDSA public key not found\x1b[0m');
}
break;
default:
console.log('\x1b[33mUnknown signature algorithm: \x1b[0m', signatureAlgorithm);
}
const hashLen = getHashLen(hashFunction);
return {
signatureAlgorithm,
hashFunction,
hashLen,
subjectKeyIdentifier,
authorityKeyIdentifier,
...publicKeyDetails,
};
}
export const getCircuitName = (circuitMode: Mode, signatureAlgorithm: string, hashFunction: string, domainParameter: string, keyLength: string) => {
const circuit = circuitNameFromMode[circuitMode];
if (circuit == 'vc_and_disclose') {
return 'vc_and_disclose';
}
if (circuit == 'dsc') {
return circuit + "_" + signatureAlgorithm + "_" + hashFunction + "_" + domainParameter + "_" + keyLength;
}
return circuit + "_" + signatureAlgorithm + "_" + hashFunction + "_" + domainParameter + "_" + keyLength;
}
export const getCircuitName = (
circuitMode: Mode,
signatureAlgorithm: string,
hashFunction: string,
domainParameter: string,
keyLength: string
) => {
const circuit = circuitNameFromMode[circuitMode];
if (circuit == 'vc_and_disclose') {
return 'vc_and_disclose';
}
if (circuit == 'dsc') {
return (
circuit +
'_' +
signatureAlgorithm +
'_' +
hashFunction +
'_' +
domainParameter +
'_' +
keyLength
);
}
return (
circuit +
'_' +
signatureAlgorithm +
'_' +
hashFunction +
'_' +
domainParameter +
'_' +
keyLength
);
};
export function getSignatureAlgorithmDetails(oid: string): { signatureAlgorithm: string, hashFunction: string } {
const details = {
'1.2.840.113549.1.1.5': { signatureAlgorithm: 'rsa', hashFunction: 'sha1', domainParameter: '65537', keyLength: '2048' },
'1.2.840.113549.1.1.11': { signatureAlgorithm: 'rsa', hashFunction: 'sha256', domainParameter: '65537', keyLength: '2048' },
'1.2.840.113549.1.1.12': { signatureAlgorithm: 'rsa', hashFunction: 'sha384', domainParameter: '65537', keyLength: '2048' },
'1.2.840.113549.1.1.13': { signatureAlgorithm: 'rsa', hashFunction: 'sha512', domainParameter: '65537', keyLength: '2048' },
// rsapss
'1.2.840.113549.1.1.10': { signatureAlgorithm: 'rsapss', hashFunction: 'sha256', domainParameter: '65537', keyLength: '2048' }, // TODO: detect which hash function is used (not always sha256)
// ecdsa
'1.2.840.10045.4.1': { signatureAlgorithm: 'ecdsa', hashFunction: 'sha1', domainParameter: 'secp256r1', keyLength: '256' },
'1.2.840.10045.4.3.1': { signatureAlgorithm: 'ecdsa', hashFunction: 'sha224', domainParameter: 'secp256r1', keyLength: '256' },
'1.2.840.10045.4.3.2': { signatureAlgorithm: 'ecdsa', hashFunction: 'sha256', domainParameter: 'secp256r1', keyLength: '256' },
'1.2.840.10045.4.3.3': { signatureAlgorithm: 'ecdsa', hashFunction: 'sha384', domainParameter: 'secp384r1', keyLength: '384' },
'1.2.840.10045.4.3.4': { signatureAlgorithm: 'ecdsa', hashFunction: 'sha512', domainParameter: 'secp521r1', keyLength: '521' },
};
return details[oid] || { signatureAlgorithm: `Unknown (${oid})`, hashFunction: 'Unknown' };
export function getSignatureAlgorithmDetails(oid: string): {
signatureAlgorithm: string;
hashFunction: string;
} {
const details = {
'1.2.840.113549.1.1.5': {
signatureAlgorithm: 'rsa',
hashFunction: 'sha1',
domainParameter: '65537',
keyLength: '2048',
},
'1.2.840.113549.1.1.11': {
signatureAlgorithm: 'rsa',
hashFunction: 'sha256',
domainParameter: '65537',
keyLength: '2048',
},
'1.2.840.113549.1.1.12': {
signatureAlgorithm: 'rsa',
hashFunction: 'sha384',
domainParameter: '65537',
keyLength: '2048',
},
'1.2.840.113549.1.1.13': {
signatureAlgorithm: 'rsa',
hashFunction: 'sha512',
domainParameter: '65537',
keyLength: '2048',
},
// rsapss
'1.2.840.113549.1.1.10': {
signatureAlgorithm: 'rsapss',
hashFunction: 'sha256',
domainParameter: '65537',
keyLength: '2048',
}, // TODO: detect which hash function is used (not always sha256)
// ecdsa
'1.2.840.10045.4.1': {
signatureAlgorithm: 'ecdsa',
hashFunction: 'sha1',
domainParameter: 'secp256r1',
keyLength: '256',
},
'1.2.840.10045.4.3.1': {
signatureAlgorithm: 'ecdsa',
hashFunction: 'sha224',
domainParameter: 'secp256r1',
keyLength: '256',
},
'1.2.840.10045.4.3.2': {
signatureAlgorithm: 'ecdsa',
hashFunction: 'sha256',
domainParameter: 'secp256r1',
keyLength: '256',
},
'1.2.840.10045.4.3.3': {
signatureAlgorithm: 'ecdsa',
hashFunction: 'sha384',
domainParameter: 'secp384r1',
keyLength: '384',
},
'1.2.840.10045.4.3.4': {
signatureAlgorithm: 'ecdsa',
hashFunction: 'sha512',
domainParameter: 'secp521r1',
keyLength: '521',
},
};
return details[oid] || { signatureAlgorithm: `Unknown (${oid})`, hashFunction: 'Unknown' };
}
export function gethashFunctionName(oid: string): string {
const hashFunctions = {
'1.3.14.3.2.26': 'sha1',
'2.16.840.1.101.3.4.2.1': 'sha256',
'2.16.840.1.101.3.4.2.2': 'sha384',
'2.16.840.1.101.3.4.2.3': 'sha512',
};
return hashFunctions[oid] || `Unknown (${oid})`;
const hashFunctions = {
'1.3.14.3.2.26': 'sha1',
'2.16.840.1.101.3.4.2.1': 'sha256',
'2.16.840.1.101.3.4.2.2': 'sha384',
'2.16.840.1.101.3.4.2.3': 'sha512',
};
return hashFunctions[oid] || `Unknown (${oid})`;
}
export function getCertificateFromPem(pemContent: string): Certificate {
const certBuffer = Buffer.from(pemContent.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''), 'base64');
const asn1Data = asn1.fromBER(certBuffer);
return new Certificate({ schema: asn1Data.result });
const certBuffer = Buffer.from(
pemContent.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64'
);
const asn1Data = asn1.fromBER(certBuffer);
return new Certificate({ schema: asn1Data.result });
}
export const getSubjectKeyIdentifier = (cert: Certificate): string => {
const subjectKeyIdentifier = cert.extensions.find(
(ext) => ext.extnID === '2.5.29.14' // OID for Subject Key Identifier
const subjectKeyIdentifier = cert.extensions.find(
(ext) => ext.extnID === '2.5.29.14' // OID for Subject Key Identifier
);
if (subjectKeyIdentifier) {
let skiValue = Buffer.from(subjectKeyIdentifier.extnValue.valueBlock.valueHexView).toString(
'hex'
);
if (subjectKeyIdentifier) {
let skiValue = Buffer.from(subjectKeyIdentifier.extnValue.valueBlock.valueHexView).toString('hex');
skiValue = skiValue.replace(/^(?:3016)?(?:0414)?/, '');
return skiValue
} else {
return null;
}
}
skiValue = skiValue.replace(/^(?:3016)?(?:0414)?/, '');
return skiValue;
} else {
return null;
}
};
export const getAuthorityKeyIdentifier = (cert: Certificate): string => {
const authorityKeyIdentifier = cert.extensions.find(
(ext) => ext.extnID === '2.5.29.35'
const authorityKeyIdentifier = cert.extensions.find((ext) => ext.extnID === '2.5.29.35');
if (authorityKeyIdentifier) {
let akiValue = Buffer.from(authorityKeyIdentifier.extnValue.valueBlock.valueHexView).toString(
'hex'
);
if (authorityKeyIdentifier) {
let akiValue = Buffer.from(authorityKeyIdentifier.extnValue.valueBlock.valueHexView).toString('hex');
akiValue = akiValue.replace(/^(?:3016)?(?:0414)?/, '');
// cur off the first 2 bytes
akiValue = akiValue.slice(4);
return akiValue
}
return null;
}
akiValue = akiValue.replace(/^(?:3016)?(?:0414)?/, '');
// cur off the first 2 bytes
akiValue = akiValue.slice(4);
return akiValue;
}
return null;
};
export function getIssuerCountryCode(cert: Certificate): string {
const issuerRDN = cert.issuer.typesAndValues;
let issuerCountryCode = '';
for (const rdn of issuerRDN) {
if (rdn.type === '2.5.4.6') { // OID for Country Name
issuerCountryCode = rdn.value.valueBlock.value;
break;
}
const issuerRDN = cert.issuer.typesAndValues;
let issuerCountryCode = '';
for (const rdn of issuerRDN) {
if (rdn.type === '2.5.4.6') {
// OID for Country Name
issuerCountryCode = rdn.value.valueBlock.value;
break;
}
return issuerCountryCode.toUpperCase();
}
return issuerCountryCode.toUpperCase();
}
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 });
const signatureAlgorithmOid = cert.signatureAlgorithm.algorithmId;
const { signatureAlgorithm, hashFunction } = getSignatureAlgorithmDetails(signatureAlgorithmOid);
const hashLen = getHashLen(hashFunction);
const certBuffer = Buffer.from(
pemContent.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64'
);
const asn1Data = asn1.fromBER(certBuffer);
const cert = new Certificate({ schema: asn1Data.result });
const signatureAlgorithmOid = cert.signatureAlgorithm.algorithmId;
const { signatureAlgorithm, hashFunction } = getSignatureAlgorithmDetails(signatureAlgorithmOid);
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);
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.valueHexView;
const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384';
const ec = new elliptic.ec(curveForElliptic);
const key = ec.keyFromPublic(publicKeyBuffer);
const x = key.getPublic().getX().toString('hex');
const y = key.getPublic().getY().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);
const x = key.getPublic().getX().toString('hex');
const y = key.getPublic().getY().toString('hex');
const fieldSizeMap: { [key: string]: number } = {
'secp256r1': 256,
'secp384r1': 384,
};
const bits = fieldSizeMap[curve]
const fieldSizeMap: { [key: string]: number } = {
secp256r1: 256,
secp384r1: 384,
};
const bits = fieldSizeMap[curve];
publicKeyDetails = { curve, x, y, bits };
} 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');
const bits = Buffer.from(modulus, 'hex').length * 8;
publicKeyDetails = { modulus, exponent, bits };
}
return { signatureAlgorithm, hashFunction, hashLen, ...publicKeyDetails };
}
publicKeyDetails = { curve, x, y, bits };
} 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'
);
const bits = Buffer.from(modulus, 'hex').length * 8;
publicKeyDetails = { modulus, exponent, bits };
}
return { signatureAlgorithm, hashFunction, hashLen, ...publicKeyDetails };
};

View File

@@ -1,230 +1,252 @@
import { fromBER, BitString } from 'asn1js';
import * as asn1 from 'asn1js';
import * as forge from 'node-forge';
import { PublicKeyDetailsECDSA, PublicKeyDetailsRSA, PublicKeyDetailsRSAPSS } from './dataStructure';
import {
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
PublicKeyDetailsRSAPSS,
} from './dataStructure';
import { identifyCurve, StandardCurve, getNamedCurve, getECDSACurveBits } from './curves';
import { gethashFunctionName } from './handleCertificate';
import elliptic from 'elliptic';
export function parseRsaPublicKey(subjectPublicKeyInfo: any): PublicKeyDetailsRSA {
const publicKey = subjectPublicKeyInfo.subjectPublicKey;
const asn1PublicKey = fromBER(publicKey.valueBlock.valueHexView);
const rsaPublicKey = asn1PublicKey.result.valueBlock;
const publicKey = subjectPublicKeyInfo.subjectPublicKey;
const asn1PublicKey = fromBER(publicKey.valueBlock.valueHexView);
const rsaPublicKey = asn1PublicKey.result.valueBlock;
if (rsaPublicKey && (rsaPublicKey as any).value && (rsaPublicKey as any).value[0] && (rsaPublicKey as any).value[1]) {
const modulusAsn1 = (rsaPublicKey as any).value[0];
const exponentAsn1 = (rsaPublicKey as any).value[1];
const modulusHex = Buffer.from(modulusAsn1.valueBlock.valueHexView).toString('hex');
const exponentHex = Buffer.from(exponentAsn1.valueBlock.valueHexView).toString('hex');
if (
rsaPublicKey &&
(rsaPublicKey as any).value &&
(rsaPublicKey as any).value[0] &&
(rsaPublicKey as any).value[1]
) {
const modulusAsn1 = (rsaPublicKey as any).value[0];
const exponentAsn1 = (rsaPublicKey as any).value[1];
const modulusHex = Buffer.from(modulusAsn1.valueBlock.valueHexView).toString('hex');
const exponentHex = Buffer.from(exponentAsn1.valueBlock.valueHexView).toString('hex');
const publicKeyForge = forge.pki.rsa.setPublicKey(
new forge.jsbn.BigInteger(modulusHex, 16),
new forge.jsbn.BigInteger(exponentHex, 16)
);
const publicKeyDetailsRSA: PublicKeyDetailsRSA = {
modulus: publicKeyForge.n.toString(16),
exponent: publicKeyForge.e.toString(10),
bits: publicKeyForge.n.bitLength().toString()
};
return publicKeyDetailsRSA;
}
else {
return null;
}
const publicKeyForge = forge.pki.rsa.setPublicKey(
new forge.jsbn.BigInteger(modulusHex, 16),
new forge.jsbn.BigInteger(exponentHex, 16)
);
const publicKeyDetailsRSA: PublicKeyDetailsRSA = {
modulus: publicKeyForge.n.toString(16),
exponent: publicKeyForge.e.toString(10),
bits: publicKeyForge.n.bitLength().toString(),
};
return publicKeyDetailsRSA;
} else {
return null;
}
}
export function parseECParameters(publicKeyInfo: any): PublicKeyDetailsECDSA {
try {
const algorithmParams = publicKeyInfo.algorithm.algorithmParams;
if (!algorithmParams) {
console.error('\x1b[31mNo algorithm params found\x1b[0m');
return null;
}
// get x and y;
const curveOid = asn1.fromBER(algorithmParams.valueBeforeDecode).result.valueBlock.toString();
const curve = getNamedCurve(curveOid);
const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384';
const ec = new elliptic.ec(curveForElliptic);
const key = ec.keyFromPublic(publicKeyBuffer);
const x = key.getPublic().getX().toString('hex');
const y = key.getPublic().getY().toString('hex');
const fieldSizeMap: { [key: string]: number } = {
'secp256r1': 256,
'secp384r1': 384,
};
const bits = fieldSizeMap[curve]
const params = asn1.fromBER(algorithmParams.valueBeforeDecodeView).result;
const valueBlock: any = params.valueBlock;
let curveParams: StandardCurve = {} as StandardCurve;
// if (valueBlock.value && valueBlock.value.length >= 6) {
// // Field ID (index 1)
// const curveParams = {} as StandardCurve;
// const fieldId = valueBlock.value[1];
// if (fieldId && fieldId.valueBlock && fieldId.valueBlock.value) {
// const fieldType = fieldId.valueBlock.value[0];
// const prime = fieldId.valueBlock.value[1];
// //curveParams.fieldType = fieldType.valueBlock.toString();
// curveParams.p = Buffer.from(prime.valueBlock.valueHexView).toString('hex');
// }
// // Curve Coefficients (index 2)
// const curveCoefficients = valueBlock.value[2];
// if (curveCoefficients && curveCoefficients.valueBlock && curveCoefficients.valueBlock.value) {
// const a = curveCoefficients.valueBlock.value[0];
// const b = curveCoefficients.valueBlock.value[1];
// curveParams.a = Buffer.from(a.valueBlock.valueHexView).toString('hex');
// curveParams.b = Buffer.from(b.valueBlock.valueHexView).toString('hex');
// }
// // Base Point G (index 3)
// const basePoint = valueBlock.value[3];
// if (basePoint && basePoint.valueBlock) {
// curveParams.G = Buffer.from(basePoint.valueBlock.valueHexView).toString('hex');
// }
// // Order n (index 4)
// const order = valueBlock.value[4];
// if (order && order.valueBlock) {
// curveParams.n = Buffer.from(order.valueBlock.valueHexView).toString('hex');
// }
// // Cofactor h (index 5)
// const cofactor = valueBlock.value[5];
// if (cofactor && cofactor.valueBlock) {
// curveParams.h = Buffer.from(cofactor.valueBlock.valueHexView).toString('hex');
// }
// if (curveParams.p && curveParams.a && curveParams.b && curveParams.G && curveParams.n && curveParams.h) {
// const identifiedCurve = identifyCurve(curveParams);
// }
// } else {
// if (valueBlock.value) {
// if (algorithmParams.idBlock.tagNumber === 6) {
// console.log('\x1b[33malgorithmParams.idBlock.tagNumber === 6, looking for algorithmParams.valueBlock\x1b[0m');
// const curveOid = algorithmParams.valueBlock.toString();
// const curveName = getNamedCurve(curveOid);
// // console.error('\x1b[33mCurve OID:', curveName, '\x1b[0m');
// return { curve: curveName, params: {} as StandardCurve, bits: getECDSACurveBits(curveName) };
// }
// else {
// console.log('\x1b[31malgorithmParams.idBlock.tagNumber !== 6\x1b[0m');
// }
// }
// else {
// console.log('\x1b[31mvalue block is not defined\x1b[0m');
// }
// }
const publicKeyDetailsECDSA: PublicKeyDetailsECDSA = {
curve: curve,
params: curveParams,
bits: bits.toString(),
x: x,
y: y
};
return publicKeyDetailsECDSA;
} catch (error) {
console.error('Error parsing EC parameters:', error);
try {
const algorithmParams = publicKeyInfo.algorithm.algorithmParams;
if (!algorithmParams) {
console.error('\x1b[31mNo algorithm params found\x1b[0m');
return null;
}
// get x and y;
const curveOid = asn1.fromBER(algorithmParams.valueBeforeDecode).result.valueBlock.toString();
const curve = getNamedCurve(curveOid);
const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384';
const ec = new elliptic.ec(curveForElliptic);
const key = ec.keyFromPublic(publicKeyBuffer);
const x = key.getPublic().getX().toString('hex');
const y = key.getPublic().getY().toString('hex');
const fieldSizeMap: { [key: string]: number } = {
secp256r1: 256,
secp384r1: 384,
};
const bits = fieldSizeMap[curve];
const params = asn1.fromBER(algorithmParams.valueBeforeDecodeView).result;
const valueBlock: any = params.valueBlock;
let curveParams: StandardCurve = {} as StandardCurve;
// if (valueBlock.value && valueBlock.value.length >= 6) {
// // Field ID (index 1)
// const curveParams = {} as StandardCurve;
// const fieldId = valueBlock.value[1];
// if (fieldId && fieldId.valueBlock && fieldId.valueBlock.value) {
// const fieldType = fieldId.valueBlock.value[0];
// const prime = fieldId.valueBlock.value[1];
// //curveParams.fieldType = fieldType.valueBlock.toString();
// curveParams.p = Buffer.from(prime.valueBlock.valueHexView).toString('hex');
// }
// // Curve Coefficients (index 2)
// const curveCoefficients = valueBlock.value[2];
// if (curveCoefficients && curveCoefficients.valueBlock && curveCoefficients.valueBlock.value) {
// const a = curveCoefficients.valueBlock.value[0];
// const b = curveCoefficients.valueBlock.value[1];
// curveParams.a = Buffer.from(a.valueBlock.valueHexView).toString('hex');
// curveParams.b = Buffer.from(b.valueBlock.valueHexView).toString('hex');
// }
// // Base Point G (index 3)
// const basePoint = valueBlock.value[3];
// if (basePoint && basePoint.valueBlock) {
// curveParams.G = Buffer.from(basePoint.valueBlock.valueHexView).toString('hex');
// }
// // Order n (index 4)
// const order = valueBlock.value[4];
// if (order && order.valueBlock) {
// curveParams.n = Buffer.from(order.valueBlock.valueHexView).toString('hex');
// }
// // Cofactor h (index 5)
// const cofactor = valueBlock.value[5];
// if (cofactor && cofactor.valueBlock) {
// curveParams.h = Buffer.from(cofactor.valueBlock.valueHexView).toString('hex');
// }
// if (curveParams.p && curveParams.a && curveParams.b && curveParams.G && curveParams.n && curveParams.h) {
// const identifiedCurve = identifyCurve(curveParams);
// }
// } else {
// if (valueBlock.value) {
// if (algorithmParams.idBlock.tagNumber === 6) {
// console.log('\x1b[33malgorithmParams.idBlock.tagNumber === 6, looking for algorithmParams.valueBlock\x1b[0m');
// const curveOid = algorithmParams.valueBlock.toString();
// const curveName = getNamedCurve(curveOid);
// // console.error('\x1b[33mCurve OID:', curveName, '\x1b[0m');
// return { curve: curveName, params: {} as StandardCurve, bits: getECDSACurveBits(curveName) };
// }
// else {
// console.log('\x1b[31malgorithmParams.idBlock.tagNumber !== 6\x1b[0m');
// }
// }
// else {
// console.log('\x1b[31mvalue block is not defined\x1b[0m');
// }
// }
const publicKeyDetailsECDSA: PublicKeyDetailsECDSA = {
curve: curve,
params: curveParams,
bits: bits.toString(),
x: x,
y: y,
};
return publicKeyDetailsECDSA;
} catch (error) {
console.error('Error parsing EC parameters:', error);
}
}
export function parseRsaPssParams(params: any): { hashFunction: string, mgf: string, saltLength: string } {
try {
const algorithmParams = asn1.fromBER(params.valueBeforeDecodeView);
const sequence = algorithmParams.result;
export function parseRsaPssParams(params: any): {
hashFunction: string;
mgf: string;
saltLength: string;
} {
try {
const algorithmParams = asn1.fromBER(params.valueBeforeDecodeView);
const sequence = algorithmParams.result;
let hashFunction = 'Unknown';
let mgf = 'Unknown';
let saltLength = "Unknown";
// Parse hash algorithm
if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[0]) {
const hashFunctionSequence = (sequence.valueBlock as any).value[0].valueBlock.value[0];
const hashFunctionOid = hashFunctionSequence.valueBlock.value[0].valueBlock.toString();
hashFunction = gethashFunctionName(hashFunctionOid);
}
// Parse MGF
if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[1]) {
const mgfSequence = (sequence.valueBlock as any).value[1].valueBlock.value[0];
const mgfOid = mgfSequence.valueBlock.value[0].valueBlock.toString();
mgf = mgfOid === '1.2.840.113549.1.1.8' ? 'MGF1' : `Unknown (${mgfOid})`;
}
// console.log((sequence.valueBlock as any).value[0].valueBlock);
// console.log((sequence.valueBlock as any).value[1].valueBlock);
// console.log((sequence.valueBlock as any).value[2].valueBlock);
// Parse salt length
if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[2]) {
const saltLengthContainer = (sequence.valueBlock as any).value[2];
if (saltLengthContainer.valueBlock && saltLengthContainer.valueBlock.value) {
const rawSaltLength = saltLengthContainer.valueBlock.value[0];
if (typeof rawSaltLength === 'number') {
saltLength = rawSaltLength.toString();
} else if (rawSaltLength && rawSaltLength.valueBlock && rawSaltLength.valueBlock.valueHexView) {
const saltLengthValue = rawSaltLength.valueBlock.valueHexView[0];
saltLength = saltLengthValue.toString();
} else {
console.error('\x1b[31mUnable to parse salt length\x1b[0m');
}
} else {
console.log("\x1b[31mSalt length not found\x1b[0m");
}
}
return { hashFunction, mgf, saltLength };
} catch (error) {
console.error('Error parsing RSA-PSS parameters:', error);
return { hashFunction: 'Unknown', mgf: 'Unknown', saltLength: "Unknown" };
}
}
export function parseRsaPssPublicKey(subjectPublicKeyInfo: any, rsaPssParams: any): PublicKeyDetailsRSAPSS {
let hashFunction = 'Unknown';
let mgf = 'Unknown';
let saltLength = "Unknown";
let saltLength = 'Unknown';
if (rsaPssParams) {
const parsedParams = parseRsaPssParams(rsaPssParams);
hashFunction = parsedParams.hashFunction;
mgf = parsedParams.mgf;
saltLength = parsedParams.saltLength;
} else {
console.log('\x1b[31mRSA-PSS parameters not found\x1b[0m');
// Parse hash algorithm
if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[0]) {
const hashFunctionSequence = (sequence.valueBlock as any).value[0].valueBlock.value[0];
const hashFunctionOid = hashFunctionSequence.valueBlock.value[0].valueBlock.toString();
hashFunction = gethashFunctionName(hashFunctionOid);
}
// Add PublicKeyDetails for RSA-PSS
const publicKey = subjectPublicKeyInfo.subjectPublicKey;
const asn1PublicKey = fromBER(publicKey.valueBlock.valueHexView);
const rsaPublicKey = asn1PublicKey.result.valueBlock;
if (rsaPublicKey && (rsaPublicKey as any).value && (rsaPublicKey as any).value[0] && (rsaPublicKey as any).value[1]) {
const modulusAsn1 = (rsaPublicKey as any).value[0];
const exponentAsn1 = (rsaPublicKey as any).value[1];
const modulusHex = Buffer.from(modulusAsn1.valueBlock.valueHexView).toString('hex');
const exponentHex = Buffer.from(exponentAsn1.valueBlock.valueHexView).toString('hex');
const publicKeyForge = forge.pki.rsa.setPublicKey(
new forge.jsbn.BigInteger(modulusHex, 16),
new forge.jsbn.BigInteger(exponentHex, 16)
);
const PublicKeyDetailsRSAPSS: PublicKeyDetailsRSAPSS = {
modulus: publicKeyForge.n.toString(16),
exponent: publicKeyForge.e.toString(10),
bits: publicKeyForge.n.bitLength().toString(),
hashFunction,
mgf,
saltLength
};
return PublicKeyDetailsRSAPSS;
// Parse MGF
if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[1]) {
const mgfSequence = (sequence.valueBlock as any).value[1].valueBlock.value[0];
const mgfOid = mgfSequence.valueBlock.value[0].valueBlock.toString();
mgf = mgfOid === '1.2.840.113549.1.1.8' ? 'MGF1' : `Unknown (${mgfOid})`;
}
else {
return null;
// console.log((sequence.valueBlock as any).value[0].valueBlock);
// console.log((sequence.valueBlock as any).value[1].valueBlock);
// console.log((sequence.valueBlock as any).value[2].valueBlock);
// Parse salt length
if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[2]) {
const saltLengthContainer = (sequence.valueBlock as any).value[2];
if (saltLengthContainer.valueBlock && saltLengthContainer.valueBlock.value) {
const rawSaltLength = saltLengthContainer.valueBlock.value[0];
if (typeof rawSaltLength === 'number') {
saltLength = rawSaltLength.toString();
} else if (
rawSaltLength &&
rawSaltLength.valueBlock &&
rawSaltLength.valueBlock.valueHexView
) {
const saltLengthValue = rawSaltLength.valueBlock.valueHexView[0];
saltLength = saltLengthValue.toString();
} else {
console.error('\x1b[31mUnable to parse salt length\x1b[0m');
}
} else {
console.log('\x1b[31mSalt length not found\x1b[0m');
}
}
return { hashFunction, mgf, saltLength };
} catch (error) {
console.error('Error parsing RSA-PSS parameters:', error);
return { hashFunction: 'Unknown', mgf: 'Unknown', saltLength: 'Unknown' };
}
}
export function parseRsaPssPublicKey(
subjectPublicKeyInfo: any,
rsaPssParams: any
): PublicKeyDetailsRSAPSS {
let hashFunction = 'Unknown';
let mgf = 'Unknown';
let saltLength = 'Unknown';
if (rsaPssParams) {
const parsedParams = parseRsaPssParams(rsaPssParams);
hashFunction = parsedParams.hashFunction;
mgf = parsedParams.mgf;
saltLength = parsedParams.saltLength;
} else {
console.log('\x1b[31mRSA-PSS parameters not found\x1b[0m');
}
// Add PublicKeyDetails for RSA-PSS
const publicKey = subjectPublicKeyInfo.subjectPublicKey;
const asn1PublicKey = fromBER(publicKey.valueBlock.valueHexView);
const rsaPublicKey = asn1PublicKey.result.valueBlock;
if (
rsaPublicKey &&
(rsaPublicKey as any).value &&
(rsaPublicKey as any).value[0] &&
(rsaPublicKey as any).value[1]
) {
const modulusAsn1 = (rsaPublicKey as any).value[0];
const exponentAsn1 = (rsaPublicKey as any).value[1];
const modulusHex = Buffer.from(modulusAsn1.valueBlock.valueHexView).toString('hex');
const exponentHex = Buffer.from(exponentAsn1.valueBlock.valueHexView).toString('hex');
const publicKeyForge = forge.pki.rsa.setPublicKey(
new forge.jsbn.BigInteger(modulusHex, 16),
new forge.jsbn.BigInteger(exponentHex, 16)
);
const PublicKeyDetailsRSAPSS: PublicKeyDetailsRSAPSS = {
modulus: publicKeyForge.n.toString(16),
exponent: publicKeyForge.e.toString(10),
bits: publicKeyForge.n.bitLength().toString(),
hashFunction,
mgf,
saltLength,
};
return PublicKeyDetailsRSAPSS;
} else {
return null;
}
}

View File

@@ -1,215 +1,234 @@
import { shaPad } from "./shaPad";
import * as forge from "node-forge";
import { bytesToBigDecimal, extractRSFromSignature, getNAndK, getNAndKCSCA, hexToDecimal, splitToWords } from "./utils";
import { CSCA_TREE_DEPTH, MODAL_SERVER_ADDRESS } from "../constants/constants";
import { poseidon2 } from "poseidon-lite";
import { IMT } from "@openpassport/zk-kit-imt";
import serialized_csca_tree from "../../pubkeys/serialized_csca_tree.json"
import axios from "axios";
import { parseCertificate } from "./certificates/handleCertificate";
import { getLeafCSCA } from "./pubkeyTree";
import { SKI_PEM, SKI_PEM_DEV } from "../constants/skiPem";
import { shaPad } from './shaPad';
import * as forge from 'node-forge';
import {
bytesToBigDecimal,
extractRSFromSignature,
getNAndK,
getNAndKCSCA,
hexToDecimal,
splitToWords,
} from './utils';
import { CSCA_TREE_DEPTH, MODAL_SERVER_ADDRESS } from '../constants/constants';
import { poseidon2 } from 'poseidon-lite';
import { IMT } from '@openpassport/zk-kit-imt';
import serialized_csca_tree from '../../pubkeys/serialized_csca_tree.json';
import axios from 'axios';
import { parseCertificate } from './certificates/handleCertificate';
import { getLeafCSCA } from './pubkeyTree';
import { SKI_PEM, SKI_PEM_DEV } from '../constants/skiPem';
export function findStartIndex(modulus: string, messagePadded: Uint8Array): number {
console.log('messagePadded', messagePadded);
const modulusNumArray = [];
for (let i = 0; i < modulus.length; i += 2) {
const hexPair = modulus.slice(i, i + 2);
const number = parseInt(hexPair, 16);
modulusNumArray.push(number);
}
console.log('modulusNumArray', modulusNumArray);
const messagePaddedNumber = [];
for (let i = 0; i < messagePadded.length; i += 1) {
const number = Number(messagePadded[i]);
messagePaddedNumber.push(number);
}
let startIndex = -1;
for (let i = 0; i <= messagePaddedNumber.length; i++) {
if (modulusNumArray[0] === messagePaddedNumber[i]) {
for (let j = 0; j < modulusNumArray.length; j++) {
if (modulusNumArray[j] !== messagePaddedNumber[i + j]) {
break;
}
else if (j === modulusNumArray.length - 1) {
startIndex = i;
}
}
break;
console.log('messagePadded', messagePadded);
const modulusNumArray = [];
for (let i = 0; i < modulus.length; i += 2) {
const hexPair = modulus.slice(i, i + 2);
const number = parseInt(hexPair, 16);
modulusNumArray.push(number);
}
console.log('modulusNumArray', modulusNumArray);
const messagePaddedNumber = [];
for (let i = 0; i < messagePadded.length; i += 1) {
const number = Number(messagePadded[i]);
messagePaddedNumber.push(number);
}
let startIndex = -1;
for (let i = 0; i <= messagePaddedNumber.length; i++) {
if (modulusNumArray[0] === messagePaddedNumber[i]) {
for (let j = 0; j < modulusNumArray.length; j++) {
if (modulusNumArray[j] !== messagePaddedNumber[i + j]) {
break;
} else if (j === modulusNumArray.length - 1) {
startIndex = i;
}
}
break;
}
if (startIndex === -1) {
throw new Error('DSC Pubkey not found in CSCA certificate');
}
return startIndex;
}
if (startIndex === -1) {
throw new Error('DSC Pubkey not found in CSCA certificate');
}
return startIndex;
}
export function generateCircuitInputsDSC(
dscSecret: string,
dscCertificate: any,
max_cert_bytes: number,
devMode: boolean = false
) {
const dscCert = forge.pki.certificateFromPem(dscCertificate);
const dscTbs = dscCert.tbsCertificate;
const dscTbsCertDer = forge.asn1.toDer(dscTbs).getBytes();
const dscTbsCertBytes = derToBytes(dscTbsCertDer);
const dscTbsCertUint8Array = Uint8Array.from(
dscTbsCertBytes.map((byte) => parseInt(byte.toString(16), 16))
);
export function generateCircuitInputsDSC(dscSecret: string, dscCertificate: any, max_cert_bytes: number, devMode: boolean = false) {
const {
signatureAlgorithm,
hashFunction,
publicKeyDetails,
x,
y,
modulus,
curve,
exponent,
bits,
subjectKeyIdentifier,
authorityKeyIdentifier,
} = parseCertificate(dscCertificate);
let dsc_message_padded;
let dsc_messagePaddedLen;
[dsc_message_padded, dsc_messagePaddedLen] = shaPad(dscTbsCertUint8Array, max_cert_bytes);
const dscCert = forge.pki.certificateFromPem(dscCertificate);
const dscTbs = dscCert.tbsCertificate;
const dscTbsCertDer = forge.asn1.toDer(dscTbs).getBytes();
const dscTbsCertBytes = derToBytes(dscTbsCertDer);
const dscTbsCertUint8Array = Uint8Array.from(dscTbsCertBytes.map(byte => parseInt(byte.toString(16), 16)));
const { n, k } = getNAndK(signatureAlgorithm);
// Extract the signature from the DSC certificate
const dscSignature = dscCert.signature;
const encryptedDigest = Array.from(forge.util.createBuffer(dscSignature).getBytes(), (char) =>
char.charCodeAt(0)
);
const { signatureAlgorithm, hashFunction, publicKeyDetails, x, y, modulus, curve, exponent, bits, subjectKeyIdentifier, authorityKeyIdentifier } = parseCertificate(dscCertificate);
let dsc_message_padded;
let dsc_messagePaddedLen;
[dsc_message_padded, dsc_messagePaddedLen] = shaPad(dscTbsCertUint8Array, max_cert_bytes);
let pubKey, signature;
const { n, k } = getNAndK(signatureAlgorithm);
// Extract the signature from the DSC certificate
const dscSignature = dscCert.signature;
const encryptedDigest = Array.from(forge.util.createBuffer(dscSignature).getBytes(), char => char.charCodeAt(0));
const startIndex = findStartIndex(modulus, dsc_message_padded);
const startIndex_formatted = startIndex.toString();
const dsc_message_padded_formatted = Array.from(dsc_message_padded).map((x) => x.toString());
const dsc_messagePaddedLen_formatted = BigInt(dsc_messagePaddedLen).toString();
let pubKey, signature;
const cscaPem = getCSCAFromSKI(authorityKeyIdentifier, devMode);
console.log('cscaPem', cscaPem);
const startIndex = findStartIndex(modulus, dsc_message_padded);
const startIndex_formatted = startIndex.toString();
const dsc_message_padded_formatted = Array.from(dsc_message_padded).map((x) => x.toString())
const dsc_messagePaddedLen_formatted = BigInt(dsc_messagePaddedLen).toString()
const {
x: csca_x,
y: csca_y,
modulus: csca_modulus,
signature_algorithm: csca_signature_algorithm,
} = parseCertificate(cscaPem);
const { n: n_csca, k: k_csca } = getNAndKCSCA(csca_signature_algorithm);
const cscaPem = getCSCAFromSKI(authorityKeyIdentifier, devMode);
console.log('cscaPem', cscaPem);
const leaf = getLeafCSCA(cscaPem);
const [root, proof] = getCSCAModulusProof(leaf);
const { x: csca_x, y: csca_y, modulus: csca_modulus, signature_algorithm: csca_signature_algorithm } = parseCertificate(cscaPem);
const { n: n_csca, k: k_csca } = getNAndKCSCA(csca_signature_algorithm);
if (signatureAlgorithm === 'ecdsa') {
const { r, s } = extractRSFromSignature(encryptedDigest);
const signature_r = splitToWords(BigInt(hexToDecimal(r)), n_csca, k_csca);
const signature_s = splitToWords(BigInt(hexToDecimal(s)), n_csca, k_csca);
signature = [...signature_r, ...signature_s];
const dsc_x_formatted = splitToWords(BigInt(hexToDecimal(x)), n, k);
const dsc_y_formatted = splitToWords(BigInt(hexToDecimal(y)), n, k);
pubKey = [...dsc_x_formatted, ...dsc_y_formatted];
} else {
signature = splitToWords(BigInt(bytesToBigDecimal(encryptedDigest)), n_csca, k_csca);
const leaf = getLeafCSCA(cscaPem);
const [root, proof] = getCSCAModulusProof(leaf);
pubKey = splitToWords(BigInt(hexToDecimal(modulus)), n, k);
}
if (signatureAlgorithm === 'ecdsa') {
const { r, s } = extractRSFromSignature(encryptedDigest);
const signature_r = splitToWords(BigInt(hexToDecimal(r)), n_csca, k_csca)
const signature_s = splitToWords(BigInt(hexToDecimal(s)), n_csca, k_csca)
signature = [...signature_r, ...signature_s]
const dsc_x_formatted = splitToWords(BigInt(hexToDecimal(x)), n, k)
const dsc_y_formatted = splitToWords(BigInt(hexToDecimal(y)), n, k)
pubKey = [...dsc_x_formatted, ...dsc_y_formatted]
} else {
signature = splitToWords(
BigInt(bytesToBigDecimal(encryptedDigest)),
n_csca,
k_csca
)
pubKey = splitToWords(
BigInt(hexToDecimal(modulus)),
n,
k
)
}
let csca_pubKey_formatted;
if (csca_signature_algorithm === 'ecdsa') {
const csca_x_formatted = splitToWords(BigInt(hexToDecimal(csca_x)), n_csca, k_csca);
const csca_y_formatted = splitToWords(BigInt(hexToDecimal(csca_y)), n_csca, k_csca);
csca_pubKey_formatted = [...csca_x_formatted, ...csca_y_formatted];
}
else {
csca_pubKey_formatted = splitToWords(BigInt(hexToDecimal(csca_modulus)), n_csca, k_csca);
}
return {
"signature_algorithm": `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${4096}`,
"inputs":
{
"raw_dsc_cert": dsc_message_padded_formatted,
"raw_dsc_cert_padded_bytes": [dsc_messagePaddedLen_formatted],
"csca_pubKey": csca_pubKey_formatted,
"signature": signature,
"dsc_pubKey": pubKey,
"dsc_pubKey_offset": [startIndex_formatted],
"secret": [dscSecret],
"merkle_root": [BigInt(root).toString()],
"path": proof.pathIndices.map(index => index.toString()),
"siblings": proof.siblings.flat().map(sibling => sibling.toString())
}
}
let csca_pubKey_formatted;
if (csca_signature_algorithm === 'ecdsa') {
const csca_x_formatted = splitToWords(BigInt(hexToDecimal(csca_x)), n_csca, k_csca);
const csca_y_formatted = splitToWords(BigInt(hexToDecimal(csca_y)), n_csca, k_csca);
csca_pubKey_formatted = [...csca_x_formatted, ...csca_y_formatted];
} else {
csca_pubKey_formatted = splitToWords(BigInt(hexToDecimal(csca_modulus)), n_csca, k_csca);
}
return {
signature_algorithm: `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${4096}`,
inputs: {
raw_dsc_cert: dsc_message_padded_formatted,
raw_dsc_cert_padded_bytes: [dsc_messagePaddedLen_formatted],
csca_pubKey: csca_pubKey_formatted,
signature: signature,
dsc_pubKey: pubKey,
dsc_pubKey_offset: [startIndex_formatted],
secret: [dscSecret],
merkle_root: [BigInt(root).toString()],
path: proof.pathIndices.map((index) => index.toString()),
siblings: proof.siblings.flat().map((sibling) => sibling.toString()),
},
};
}
export function getCSCAFromSKI(ski: string, devMode: boolean): string {
const cscaPemPROD = (SKI_PEM as any)[ski];
const cscaPemDEV = (SKI_PEM_DEV as any)[ski];
const cscaPem = devMode ? cscaPemDEV || cscaPemPROD : cscaPemPROD;
if (!cscaPem) {
console.log('\x1b[31m%s\x1b[0m', `CSCA with SKI ${ski} not found`, 'devMode: ', devMode);
throw new Error(`CSCA not found, authorityKeyIdentifier: ${ski}, areMockPassportsAllowed: ${devMode},`);
}
return cscaPem;
const cscaPemPROD = (SKI_PEM as any)[ski];
const cscaPemDEV = (SKI_PEM_DEV as any)[ski];
const cscaPem = devMode ? cscaPemDEV || cscaPemPROD : cscaPemPROD;
if (!cscaPem) {
console.log('\x1b[31m%s\x1b[0m', `CSCA with SKI ${ski} not found`, 'devMode: ', devMode);
throw new Error(
`CSCA not found, authorityKeyIdentifier: ${ski}, areMockPassportsAllowed: ${devMode},`
);
}
return cscaPem;
}
export function derToBytes(derValue: string) {
const bytes = [];
for (let i = 0; i < derValue.length; i++) {
bytes.push(derValue.charCodeAt(i));
}
return bytes;
const bytes = [];
for (let i = 0; i < derValue.length; i++) {
bytes.push(derValue.charCodeAt(i));
}
return bytes;
}
export function getCSCAModulusMerkleTree() {
const tree = new IMT(poseidon2, CSCA_TREE_DEPTH, 0, 2);
tree.setNodes(serialized_csca_tree);
return tree;
const tree = new IMT(poseidon2, CSCA_TREE_DEPTH, 0, 2);
tree.setNodes(serialized_csca_tree);
return tree;
}
export function getCSCAModulusProof(leaf) {
console.log('leaf', leaf);
let tree = new IMT(poseidon2, CSCA_TREE_DEPTH, 0, 2);
tree.setNodes(serialized_csca_tree);
const index = tree.indexOf(leaf);
if (index === -1) {
throw new Error("Your public key was not found in the registry");
}
const proof = tree.createProof(index);
return [tree.root, proof];
console.log('leaf', leaf);
let tree = new IMT(poseidon2, CSCA_TREE_DEPTH, 0, 2);
tree.setNodes(serialized_csca_tree);
const index = tree.indexOf(leaf);
if (index === -1) {
throw new Error('Your public key was not found in the registry');
}
const proof = tree.createProof(index);
return [tree.root, proof];
}
export function getTBSHash(cert: forge.pki.Certificate, hashFunction: 'sha1' | 'sha256', n: number, k: number): string[] {
const tbsCertAsn1 = forge.pki.certificateToAsn1(cert).value[0];
const tbsCertDer = forge.asn1.toDer(tbsCertAsn1 as any).getBytes();
const md = hashFunction === 'sha256' ? forge.md.sha256.create() : forge.md.sha1.create();
md.update(tbsCertDer);
const tbsCertificateHash = md.digest();
const tbsCertificateHashString = tbsCertificateHash.data;
const tbsCertificateHashHex = Buffer.from(tbsCertificateHashString, 'binary').toString('hex');
const tbsCertificateHashBigint = BigInt(`0x${tbsCertificateHashHex}`);
console.log('tbsCertificateHashBigint', tbsCertificateHashBigint);
return splitToWords(tbsCertificateHashBigint, n, k);
export function getTBSHash(
cert: forge.pki.Certificate,
hashFunction: 'sha1' | 'sha256',
n: number,
k: number
): string[] {
const tbsCertAsn1 = forge.pki.certificateToAsn1(cert).value[0];
const tbsCertDer = forge.asn1.toDer(tbsCertAsn1 as any).getBytes();
const md = hashFunction === 'sha256' ? forge.md.sha256.create() : forge.md.sha1.create();
md.update(tbsCertDer);
const tbsCertificateHash = md.digest();
const tbsCertificateHashString = tbsCertificateHash.data;
const tbsCertificateHashHex = Buffer.from(tbsCertificateHashString, 'binary').toString('hex');
const tbsCertificateHashBigint = BigInt(`0x${tbsCertificateHashHex}`);
console.log('tbsCertificateHashBigint', tbsCertificateHashBigint);
return splitToWords(tbsCertificateHashBigint, n, k);
}
export const sendCSCARequest = async (inputs_csca: any): Promise<any> => {
try {
const response = await axios.post(MODAL_SERVER_ADDRESS, inputs_csca, {
headers: {
'Content-Type': 'application/json'
}
});
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
console.error('Axios error:', error.message);
if (error.response) {
console.error('Response data:', error.response.data);
console.error('Response status:', error.response.status);
}
} else {
console.error('Unexpected error:', error);
}
throw error;
try {
const response = await axios.post(MODAL_SERVER_ADDRESS, inputs_csca, {
headers: {
'Content-Type': 'application/json',
},
});
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
console.error('Axios error:', error.message);
if (error.response) {
console.error('Response data:', error.response.data);
console.error('Response status:', error.response.status);
}
} else {
console.error('Unexpected error:', error);
}
throw error;
}
};
export const generateDscSecret = () => {
const secretBytes = forge.random.getBytesSync(31);
return BigInt(`0x${forge.util.bytesToHex(secretBytes)}`).toString();
}
const secretBytes = forge.random.getBytesSync(31);
return BigInt(`0x${forge.util.bytesToHex(secretBytes)}`).toString();
};

View File

@@ -7,7 +7,7 @@ export function formatCallData_register(parsedCallData: any[]) {
a: parsedCallData[0],
b: [parsedCallData[1][0], parsedCallData[1][1]],
c: parsedCallData[2],
};;
};
}
export function formatCallData_dsc(parsedCallData: any[]) {
return {
@@ -16,7 +16,7 @@ export function formatCallData_dsc(parsedCallData: any[]) {
a: parsedCallData[0],
b: [parsedCallData[1][0], parsedCallData[1][1]],
c: parsedCallData[2],
};;
};
}
export function formatCallData_disclose(parsedCallData: any[]) {
@@ -26,10 +26,17 @@ export function formatCallData_disclose(parsedCallData: any[]) {
attestation_id: parsedCallData[3][4],
merkle_root: parsedCallData[3][5],
scope: parsedCallData[3][6],
current_date: [parsedCallData[3][7], parsedCallData[3][8], parsedCallData[3][9], parsedCallData[3][10], parsedCallData[3][11], parsedCallData[3][12]],
current_date: [
parsedCallData[3][7],
parsedCallData[3][8],
parsedCallData[3][9],
parsedCallData[3][10],
parsedCallData[3][11],
parsedCallData[3][12],
],
user_identifier: parsedCallData[3][13],
a: parsedCallData[0],
b: [parsedCallData[1][0], parsedCallData[1][1]],
c: parsedCallData[2],
};
}
}

View File

@@ -1,10 +1,5 @@
import { PassportData } from './types';
import {
hash,
assembleEContent,
formatAndConcatenateDataHashes,
formatMrz,
} from './utils';
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz } from './utils';
import * as forge from 'node-forge';
import * as asn1 from 'asn1js';
import elliptic from 'elliptic';
@@ -39,20 +34,26 @@ export function genMockPassportData(
nationality: keyof typeof countryCodes,
birthDate: string,
expiryDate: string,
passportNumber: string = "15AA81234",
lastName: string = "DUPONT",
firstName: string = "ALPHONSE HUGHUES ALBERT"
passportNumber: string = '15AA81234',
lastName: string = 'DUPONT',
firstName: string = 'ALPHONSE HUGHUES ALBERT'
): PassportData {
if (birthDate.length !== 6 || expiryDate.length !== 6) {
throw new Error('birthdate and expiry date have to be in the "YYMMDD" format');
}
// Prepare last name: Convert to uppercase, remove invalid characters, split by spaces, and join with '<'
const lastNameParts = lastName.toUpperCase().replace(/[^A-Z< ]/g, '').split(' ');
const lastNameParts = lastName
.toUpperCase()
.replace(/[^A-Z< ]/g, '')
.split(' ');
const formattedLastName = lastNameParts.join('<');
// Prepare first name: Convert to uppercase, remove invalid characters, split by spaces, and join with '<'
const firstNameParts = firstName.toUpperCase().replace(/[^A-Z< ]/g, '').split(' ');
const firstNameParts = firstName
.toUpperCase()
.replace(/[^A-Z< ]/g, '')
.split(' ');
const formattedFirstName = firstNameParts.join('<');
// Build the first line of MRZ
@@ -154,11 +155,7 @@ export function genMockPassportData(
};
}
function sign(
privateKeyPem: string,
dsc: string,
eContent: number[]
): number[] {
function sign(privateKeyPem: string, dsc: string, eContent: number[]): number[] {
const { signatureAlgorithm, hashFunction, curve } = parseCertificate(dsc);
if (signatureAlgorithm === 'rsapss') {

View File

@@ -1,4 +1,9 @@
import { PUBKEY_TREE_DEPTH, DEFAULT_USER_ID_TYPE, MAX_PADDED_ECONTENT_LEN, MAX_PADDED_SIGNED_ATTR_LEN } from '../constants/constants';
import {
PUBKEY_TREE_DEPTH,
DEFAULT_USER_ID_TYPE,
MAX_PADDED_ECONTENT_LEN,
MAX_PADDED_SIGNED_ATTR_LEN,
} from '../constants/constants';
import { assert, shaPad } from './shaPad';
import { PassportData } from './types';
import {
@@ -20,11 +25,11 @@ import {
stringToAsciiBigIntArray,
formatCountriesList,
} from './utils';
import { generateCommitment, getLeaf } from "./pubkeyTree";
import { LeanIMT } from "@openpassport/zk-kit-lean-imt";
import { getCountryLeaf, getNameLeaf, getNameDobLeaf, getPassportNumberLeaf } from "./smtTree";
import { packBytes } from "../utils/utils";
import { SMT } from "@openpassport/zk-kit-smt"
import { generateCommitment, getLeaf } from './pubkeyTree';
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
import { getCountryLeaf, getNameLeaf, getNameDobLeaf, getPassportNumberLeaf } from './smtTree';
import { packBytes } from '../utils/utils';
import { SMT } from '@openpassport/zk-kit-smt';
import { parseCertificate } from './certificates/handleCertificate';
export function generateCircuitInputsDisclose(
@@ -41,13 +46,18 @@ export function generateCircuitInputsDisclose(
forbidden_countries_list: string[],
user_identifier: string
) {
const pubkey_leaf = getLeaf(passportData.dsc);
const formattedMrz = formatMrz(passportData.mrz);
const mrz_bytes_packed = packBytes(formattedMrz);
const commitment = generateCommitment(BigInt(secret).toString(), BigInt(attestation_id).toString(), BigInt(pubkey_leaf).toString(), mrz_bytes_packed, formatDg2Hash(passportData.dg2Hash));
console.log("\x1b[90mcommitment:\x1b[0m", commitment);
const commitment = generateCommitment(
BigInt(secret).toString(),
BigInt(attestation_id).toString(),
BigInt(pubkey_leaf).toString(),
mrz_bytes_packed,
formatDg2Hash(passportData.dg2Hash)
);
console.log('\x1b[90mcommitment:\x1b[0m', commitment);
const index = findIndexInTree(merkletree, commitment);
@@ -57,12 +67,16 @@ export function generateCircuitInputsDisclose(
PUBKEY_TREE_DEPTH
);
const formattedMajority = majority.length === 1 ? `0${majority}` : majority;
const majority_ascii = formattedMajority.split('').map(char => char.charCodeAt(0));
const majority_ascii = formattedMajority.split('').map((char) => char.charCodeAt(0));
// SMT - OFAC
const name_leaf = getNameLeaf(formattedMrz.slice(10, 49)) // [6-44] + 5 shift
const { root: smt_root, closestleaf: smt_leaf_value, siblings: smt_siblings } = generateSMTProof(name_smt, name_leaf);
const name_leaf = getNameLeaf(formattedMrz.slice(10, 49)); // [6-44] + 5 shift
const {
root: smt_root,
closestleaf: smt_leaf_value,
siblings: smt_siblings,
} = generateSMTProof(name_smt, name_leaf);
return {
secret: formatInput(secret),
@@ -84,20 +98,19 @@ export function generateCircuitInputsDisclose(
smt_leaf_value: formatInput(smt_leaf_value),
smt_siblings: formatInput(smt_siblings),
selector_ofac: formatInput(selector_ofac),
forbidden_countries_list: formatInput(formatCountriesList(forbidden_countries_list))
forbidden_countries_list: formatInput(formatCountriesList(forbidden_countries_list)),
};
}
export function generateCircuitInputsOfac(
passportData: PassportData,
sparsemerkletree: SMT,
proofLevel: number,
proofLevel: number
) {
const mrz_bytes = formatMrz(passportData.mrz);
const passport_leaf = getPassportNumberLeaf(mrz_bytes.slice(49, 58))
const namedob_leaf = getNameDobLeaf(mrz_bytes.slice(10, 49), mrz_bytes.slice(62, 68)) // [57-62] + 5 shift
const name_leaf = getNameLeaf(mrz_bytes.slice(10, 49)) // [6-44] + 5 shift
const passport_leaf = getPassportNumberLeaf(mrz_bytes.slice(49, 58));
const namedob_leaf = getNameDobLeaf(mrz_bytes.slice(10, 49), mrz_bytes.slice(62, 68)); // [57-62] + 5 shift
const name_leaf = getNameLeaf(mrz_bytes.slice(10, 49)); // [6-44] + 5 shift
let root, closestleaf, siblings;
if (proofLevel == 3) {
@@ -107,7 +120,7 @@ export function generateCircuitInputsOfac(
} else if (proofLevel == 1) {
({ root, closestleaf, siblings } = generateSMTProof(sparsemerkletree, name_leaf));
} else {
throw new Error("Invalid proof level")
throw new Error('Invalid proof level');
}
return {
@@ -120,11 +133,11 @@ export function generateCircuitInputsOfac(
export function generateCircuitInputsCountryVerifier(
passportData: PassportData,
sparsemerkletree: SMT,
sparsemerkletree: SMT
) {
const mrz_bytes = formatMrz(passportData.mrz);
const usa_ascii = stringToAsciiBigIntArray("USA")
const country_leaf = getCountryLeaf(usa_ascii, mrz_bytes.slice(7, 10))
const usa_ascii = stringToAsciiBigIntArray('USA');
const country_leaf = getCountryLeaf(usa_ascii, mrz_bytes.slice(7, 10));
const { root, closestleaf, siblings } = generateSMTProof(sparsemerkletree, country_leaf);
return {
@@ -152,7 +165,6 @@ export function findIndexInTree(tree: LeanIMT, commitment: bigint): number {
return index;
}
export function generateCircuitInputsProve(
selector_mode: number[] | string[],
secret: number | string,
@@ -168,9 +180,9 @@ export function generateCircuitInputsProve(
user_identifier: string,
user_identifier_type: 'uuid' | 'hex' | 'ascii' = DEFAULT_USER_ID_TYPE
) {
const { mrz, eContent, signedAttr, encryptedDigest, dsc, dg2Hash } = passportData;
const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus, curve, exponent, bits } = parseCertificate(passportData.dsc);
const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus, curve, exponent, bits } =
parseCertificate(passportData.dsc);
const signatureAlgorithmFullName = `${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`;
let pubKey: any;
@@ -180,40 +192,36 @@ export function generateCircuitInputsProve(
if (signatureAlgorithm === 'ecdsa') {
const { r, s } = extractRSFromSignature(encryptedDigest);
const signature_r = splitToWords(BigInt(hexToDecimal(r)), n, k)
const signature_s = splitToWords(BigInt(hexToDecimal(s)), n, k)
signature = [...signature_r, ...signature_s]
const dsc_modulus_x = splitToWords(BigInt(hexToDecimal(x)), n, k)
const dsc_modulus_y = splitToWords(BigInt(hexToDecimal(y)), n, k)
pubKey = [...dsc_modulus_x, ...dsc_modulus_y]
const signature_r = splitToWords(BigInt(hexToDecimal(r)), n, k);
const signature_s = splitToWords(BigInt(hexToDecimal(s)), n, k);
signature = [...signature_r, ...signature_s];
const dsc_modulus_x = splitToWords(BigInt(hexToDecimal(x)), n, k);
const dsc_modulus_y = splitToWords(BigInt(hexToDecimal(y)), n, k);
pubKey = [...dsc_modulus_x, ...dsc_modulus_y];
} else {
signature = splitToWords(
BigInt(bytesToBigDecimal(encryptedDigest)),
n,
k
)
signature = splitToWords(BigInt(bytesToBigDecimal(encryptedDigest)), n, k);
pubKey = splitToWords(
BigInt(hexToDecimal(modulus)),
n,
k
)
pubKey = splitToWords(BigInt(hexToDecimal(modulus)), n, k);
}
const formattedMrz = formatMrz(mrz);
const dg1Hash = hash(hashFunction, formattedMrz);
const dg1HashOffset = findSubarrayIndex(eContent, dg1Hash)
const dg1HashOffset = findSubarrayIndex(eContent, dg1Hash);
console.log('\x1b[90m%s\x1b[0m', 'dg1HashOffset', dg1HashOffset);
assert(dg1HashOffset !== -1, `DG1 hash ${dg1Hash} not found in eContent`);
const eContentHash = hash(hashFunction, eContent);
const eContentHashOffset = findSubarrayIndex(signedAttr, eContentHash)
const eContentHashOffset = findSubarrayIndex(signedAttr, eContentHash);
console.log('\x1b[90m%s\x1b[0m', 'eContentHashOffset', eContentHashOffset);
assert(eContentHashOffset !== -1, `eContent hash ${eContentHash} not found in signedAttr`);
if (eContent.length > MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]) {
console.error(`Data hashes too long (${eContent.length} bytes). Max length is ${MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]} bytes.`);
throw new Error(`This length of datagroups (${eContent.length} bytes) is currently unsupported. Please contact us so we add support!`);
console.error(
`Data hashes too long (${eContent.length} bytes). Max length is ${MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]} bytes.`
);
throw new Error(
`This length of datagroups (${eContent.length} bytes) is currently unsupported. Please contact us so we add support!`
);
}
const [eContentPadded, eContentLen] = shaPad(
@@ -227,12 +235,16 @@ export function generateCircuitInputsProve(
);
const formattedMajority = majority.length === 1 ? `0${majority}` : majority;
const majority_ascii = formattedMajority.split('').map(char => char.charCodeAt(0))
const majority_ascii = formattedMajority.split('').map((char) => char.charCodeAt(0));
// SMT - OFAC
const mrz_bytes = formatMrz(passportData.mrz);
const name_leaf = getNameLeaf(mrz_bytes.slice(10, 49)) // [6-44] + 5 shift
const { root: smt_root, closestleaf: smt_leaf_value, siblings: smt_siblings } = generateSMTProof(name_smt, name_leaf);
const name_leaf = getNameLeaf(mrz_bytes.slice(10, 49)); // [6-44] + 5 shift
const {
root: smt_root,
closestleaf: smt_leaf_value,
siblings: smt_siblings,
} = generateSMTProof(name_smt, name_leaf);
return {
selector_mode: formatInput(selector_mode),
dg1: formatInput(formattedMrz),
@@ -257,14 +269,13 @@ export function generateCircuitInputsProve(
smt_leaf_value: formatInput(smt_leaf_value),
smt_siblings: formatInput(smt_siblings),
selector_ofac: formatInput(selector_ofac),
forbidden_countries_list: formatInput(formatCountriesList(forbidden_countries_list))
forbidden_countries_list: formatInput(formatCountriesList(forbidden_countries_list)),
};
}
export function formatInput(input: any) {
if (Array.isArray(input)) {
return input.map(item => BigInt(item).toString());
return input.map((item) => BigInt(item).toString());
} else {
return [BigInt(input).toString()];
}

View File

@@ -1,92 +1,89 @@
export function getAdjustedTimestampBytes(y: number = 0, m: number = 0, d: number = 0): number[] {
// Get the current date/time
let currentDate: Date = new Date();
// Get the current date/time
let currentDate: Date = new Date();
// Optionally adjust the date
if (y !== 0) currentDate.setFullYear(currentDate.getFullYear() + y);
if (m !== 0) currentDate.setMonth(currentDate.getMonth() + m);
if (d !== 0) currentDate.setDate(currentDate.getDate() + d);
// Optionally adjust the date
if (y !== 0) currentDate.setFullYear(currentDate.getFullYear() + y);
if (m !== 0) currentDate.setMonth(currentDate.getMonth() + m);
if (d !== 0) currentDate.setDate(currentDate.getDate() + d);
// Get the Unix timestamp (in seconds)
const timestamp: number = Math.floor(currentDate.getTime() / 1000);
// Get the Unix timestamp (in seconds)
const timestamp: number = Math.floor(currentDate.getTime() / 1000);
// Convert the timestamp to 4 bytes
const bytes: number[] = [
(timestamp >> 24) & 0xFF,
(timestamp >> 16) & 0xFF,
(timestamp >> 8) & 0xFF,
timestamp & 0xFF,
];
// Convert the timestamp to 4 bytes
const bytes: number[] = [
(timestamp >> 24) & 0xff,
(timestamp >> 16) & 0xff,
(timestamp >> 8) & 0xff,
timestamp & 0xff,
];
return bytes;
return bytes;
}
export function getTimestampBytesFromYearFraction(yearFraction: number): number[] {
// Separate the year and the fractional part
const year = Math.floor(yearFraction);
const fraction = yearFraction - year;
// Separate the year and the fractional part
const year = Math.floor(yearFraction);
const fraction = yearFraction - year;
// Convert the fractional part into months (0-11)
const monthsFromFraction = Math.floor(fraction * 12);
// Convert the fractional part into months (0-11)
const monthsFromFraction = Math.floor(fraction * 12);
// Create a date object from the year and the calculated month
// Assuming the first day of the month for simplicity
const date = new Date(year, monthsFromFraction, 1);
// Create a date object from the year and the calculated month
// Assuming the first day of the month for simplicity
const date = new Date(year, monthsFromFraction, 1);
// Get the Unix timestamp (in seconds)
const timestamp: number = Math.floor(date.getTime() / 1000);
// Get the Unix timestamp (in seconds)
const timestamp: number = Math.floor(date.getTime() / 1000);
// Convert the timestamp to 4 bytes
const bytes: number[] = [
// Convert the timestamp to 4 bytes
const bytes: number[] = [
(timestamp >> 24) & 0xff,
(timestamp >> 16) & 0xff,
(timestamp >> 8) & 0xff,
timestamp & 0xff,
];
(timestamp >> 24) & 0xFF,
(timestamp >> 16) & 0xFF,
(timestamp >> 8) & 0xFF,
timestamp & 0xFF,
];
return bytes;
return bytes;
}
export function unixTimestampToYYMMDD(timestamp: number): string {
console.log("timestamp: " + timestamp);
const date = new Date(timestamp * 1000);
console.log("date: " + date);
const year = date.getUTCFullYear();
console.log("year: " + year);
const month = date.getUTCMonth() + 1;
const day = date.getUTCDate();
console.log('timestamp: ' + timestamp);
const date = new Date(timestamp * 1000);
console.log('date: ' + date);
const year = date.getUTCFullYear();
console.log('year: ' + year);
const month = date.getUTCMonth() + 1;
const day = date.getUTCDate();
// Ensure the year is correctly formatted as two digits
const YY = (`0${year % 100}`).slice(-2);
const MM = (`0${month}`).slice(-2);
const DD = (`0${day}`).slice(-2);
// Ensure the year is correctly formatted as two digits
const YY = `0${year % 100}`.slice(-2);
const MM = `0${month}`.slice(-2);
const DD = `0${day}`.slice(-2);
return `${YY}${MM}${DD}`;
return `${YY}${MM}${DD}`;
}
export function yearFractionToYYMMDD(yearFraction: number): string {
// Separate the year and the fractional part
const year = yearFraction;
const fraction = yearFraction - Math.floor(yearFraction);
// Separate the year and the fractional part
const year = yearFraction;
const fraction = yearFraction - Math.floor(yearFraction);
// Convert the fractional part into months (0-11)
const monthsFromFraction = Math.floor(fraction * 12);
// Convert the fractional part into months (0-11)
const monthsFromFraction = Math.floor(fraction * 12);
// Assuming the first day of the month for simplicity
const day = 1;
// Assuming the first day of the month for simplicity
const day = 1;
// Format year, month, and day into YYMMDD string
const YY = (`0${Math.floor(year) % 100}`).slice(-2);
const MM = (`0${monthsFromFraction + 1}`).slice(-2); // +1 because months are 1-indexed in this format
const DD = (`0${day}`).slice(-2);
// Format year, month, and day into YYMMDD string
const YY = `0${Math.floor(year) % 100}`.slice(-2);
const MM = `0${monthsFromFraction + 1}`.slice(-2); // +1 because months are 1-indexed in this format
const DD = `0${day}`.slice(-2);
return `${YY}${MM}${DD}`;
return `${YY}${MM}${DD}`;
}
export function yymmddToByteArray(yymmdd: string): number[] {
// Convert each character in the string to its ASCII value
const byteArray = Array.from(yymmdd).map(char => char.charCodeAt(0));
return byteArray;
// Convert each character in the string to its ASCII value
const byteArray = Array.from(yymmdd).map((char) => char.charCodeAt(0));
return byteArray;
}

View File

@@ -1,8 +1,4 @@
import {
ECDSA_K_LENGTH_FACTOR,
k_dsc,
k_dsc_ecdsa,
} from '../constants/constants';
import { ECDSA_K_LENGTH_FACTOR, k_dsc, k_dsc_ecdsa } from '../constants/constants';
import { parseDSC } from './certificates/handleCertificate';
import {
bigIntToHex,
@@ -12,7 +8,7 @@ import {
UserIdType,
} from './utils';
import { unpackReveal } from './revealBitmap';
import { getAttributeFromUnpackedReveal } from './utils'
import { getAttributeFromUnpackedReveal } from './utils';
import { Mode } from 'fs';
export interface OpenPassportAttestation {
@@ -135,9 +131,7 @@ export function buildAttestation(options: {
const scope = castToScope(BigInt(parsedPublicSignals.scope));
// Unpack the revealed data
const unpackedReveal = unpackReveal(
parsedPublicSignals.revealedData_packed
);
const unpackedReveal = unpackReveal(parsedPublicSignals.revealedData_packed);
const attributeNames = [
'issuing_state',
@@ -149,7 +143,9 @@ export function buildAttestation(options: {
'expiry_date',
'older_than',
];
const formattedCountryList = formatForbiddenCountriesListFromCircuitOutput(parsedPublicSignals.forbidden_countries_list_packed_disclosed);
const formattedCountryList = formatForbiddenCountriesListFromCircuitOutput(
parsedPublicSignals.forbidden_countries_list_packed_disclosed
);
const credentialSubject: any = {
userId: userId,
application: scope,
@@ -161,7 +157,6 @@ export function buildAttestation(options: {
not_in_countries: formattedCountryList,
};
attributeNames.forEach((attrName) => {
const value = getAttributeFromUnpackedReveal(unpackedReveal, attrName);
if (value !== undefined && value !== null) {
@@ -172,10 +167,7 @@ export function buildAttestation(options: {
credentialSubject.pubKey = parsedPublicSignals.pubKey_disclosed ?? [];
const attestation: OpenPassportAttestation = {
'@context': [
'https://www.w3.org/2018/credentials/v1',
'https://openpassport.app',
],
'@context': ['https://www.w3.org/2018/credentials/v1', 'https://openpassport.app'],
type: ['OpenPassportAttestation', 'PassportCredential'],
issuer: 'https://openpassport.app',
issuanceDate: new Date().toISOString(),
@@ -185,8 +177,7 @@ export function buildAttestation(options: {
signatureAlgorithm: signatureAlgorithm,
hashFunction: hashFunction,
type: 'ZeroKnowledgeProof',
verificationMethod:
'https://github.com/zk-passport/openpassport',
verificationMethod: 'https://github.com/zk-passport/openpassport',
value: {
proof: proof,
publicSignals: publicSignals,
@@ -197,8 +188,7 @@ export function buildAttestation(options: {
signatureAlgorithm: signatureAlgorithmDsc,
hashFunction: hashFunctionDsc,
type: 'ZeroKnowledgeProof',
verificationMethod:
'https://github.com/zk-passport/openpassport',
verificationMethod: 'https://github.com/zk-passport/openpassport',
value: {
proof: dscProof || [],
publicSignals: dscPublicSignals || [],
@@ -288,8 +278,7 @@ export class OpenPassportDynamicAttestation implements OpenPassportAttestation {
private parsePublicSignals() {
if (this.proof.mode === 'vc_and_disclose') {
return parsePublicSignalsDisclose(this.proof.value.publicSignals);
}
else {
} else {
let kScaled: number;
switch (this.proof.signatureAlgorithm) {
case 'ecdsa':
@@ -301,7 +290,6 @@ export class OpenPassportDynamicAttestation implements OpenPassportAttestation {
return parsePublicSignalsProve(this.proof.value.publicSignals, kScaled);
}
// Parse the public signals
}
@@ -329,8 +317,7 @@ export class OpenPassportDynamicAttestation implements OpenPassportAttestation {
const parsedPublicSignals = this.parsePublicSignals();
if (this.proof.mode === 'vc_and_disclose') {
return '';
}
else {
} else {
return (parsedPublicSignals as any).commitment;
}
}
@@ -346,8 +333,7 @@ export class OpenPassportDynamicAttestation implements OpenPassportAttestation {
if (this.dscProof.value.publicSignals) {
const parsedPublicSignalsDsc = parsePublicSignalsDsc(this.dscProof.value.publicSignals);
return parsedPublicSignalsDsc.merkle_root;
}
else {
} else {
throw new Error('No DSC proof found');
}
}
@@ -373,7 +359,7 @@ export function parsePublicSignalsDsc(publicSignals) {
return {
blinded_dsc_commitment: publicSignals[0],
merkle_root: publicSignals[1],
}
};
}
export function parsePublicSignalsDisclose(publicSignals) {
@@ -389,6 +375,5 @@ export function parsePublicSignalsDisclose(publicSignals) {
current_date: publicSignals.slice(12, 18),
user_identifier: publicSignals[18],
smt_root: publicSignals[19],
}
};
}

View File

@@ -1,12 +1,12 @@
import { PassportData } from "./types";
import { PassportData } from './types';
const fs = require('fs');
const path = require('path');
export function getLocalPassportData(): PassportData {
const passportDataPath = path.join(__dirname, '../../inputs/passportData.json');
if ( fs.existsSync(passportDataPath)) {
if (fs.existsSync(passportDataPath)) {
return require(passportDataPath);
} else {
throw new Error('Passport data not found at inputs/passportData.json');
}
}
}

View File

@@ -1,27 +1,57 @@
import {
poseidon1, poseidon2, poseidon3, poseidon4, poseidon5, poseidon6, poseidon7, poseidon8,
poseidon9, poseidon10, poseidon11, poseidon12, poseidon13, poseidon14, poseidon15, poseidon16
poseidon1,
poseidon2,
poseidon3,
poseidon4,
poseidon5,
poseidon6,
poseidon7,
poseidon8,
poseidon9,
poseidon10,
poseidon11,
poseidon12,
poseidon13,
poseidon14,
poseidon15,
poseidon16,
} from 'poseidon-lite';
export function flexiblePoseidon(inputs: bigint[]): bigint {
switch (inputs.length) {
case 1: return poseidon1(inputs);
case 2: return poseidon2(inputs);
case 3: return poseidon3(inputs);
case 4: return poseidon4(inputs);
case 5: return poseidon5(inputs);
case 6: return poseidon6(inputs);
case 7: return poseidon7(inputs);
case 8: return poseidon8(inputs);
case 9: return poseidon9(inputs);
case 10: return poseidon10(inputs);
case 11: return poseidon11(inputs);
case 12: return poseidon12(inputs);
case 13: return poseidon13(inputs);
case 14: return poseidon14(inputs);
case 15: return poseidon15(inputs);
case 16: return poseidon16(inputs);
default:
throw new Error(`Unsupported number of inputs: ${inputs.length}`);
}
switch (inputs.length) {
case 1:
return poseidon1(inputs);
case 2:
return poseidon2(inputs);
case 3:
return poseidon3(inputs);
case 4:
return poseidon4(inputs);
case 5:
return poseidon5(inputs);
case 6:
return poseidon6(inputs);
case 7:
return poseidon7(inputs);
case 8:
return poseidon8(inputs);
case 9:
return poseidon9(inputs);
case 10:
return poseidon10(inputs);
case 11:
return poseidon11(inputs);
case 12:
return poseidon12(inputs);
case 13:
return poseidon13(inputs);
case 14:
return poseidon14(inputs);
case 15:
return poseidon15(inputs);
case 16:
return poseidon16(inputs);
default:
throw new Error(`Unsupported number of inputs: ${inputs.length}`);
}
}

View File

@@ -1,10 +1,14 @@
import { PUBKEY_TREE_DEPTH, COMMITMENT_TREE_TRACKER_URL, SignatureAlgorithmIndex } from "../constants/constants";
import { LeanIMT } from '@openpassport/zk-kit-lean-imt'
import axios from "axios";
import {
PUBKEY_TREE_DEPTH,
COMMITMENT_TREE_TRACKER_URL,
SignatureAlgorithmIndex,
} from '../constants/constants';
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
import axios from 'axios';
import { poseidon16, poseidon2, poseidon6, poseidon7 } from 'poseidon-lite';
import { formatDg2Hash, getNAndK, getNAndKCSCA, hexToDecimal, splitToWords } from './utils';
import { parseCertificate } from "./certificates/handleCertificate";
import { flexiblePoseidon } from "./poseidon";
import { parseCertificate } from './certificates/handleCertificate';
import { flexiblePoseidon } from './poseidon';
export function customHasher(pubKeyFormatted: string[]) {
const rounds = Math.ceil(pubKeyFormatted.length / 16);
@@ -19,12 +23,13 @@ export function customHasher(pubKeyFormatted: string[]) {
}
}
}
const finalHash = flexiblePoseidon(hash.map(h => poseidon16(h.inputs)));
const finalHash = flexiblePoseidon(hash.map((h) => poseidon16(h.inputs)));
return finalHash.toString();
}
export function getLeaf(dsc: string): string {
const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } = parseCertificate(dsc);
const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } =
parseCertificate(dsc);
const { n, k } = getNAndK(signatureAlgorithm);
console.log(`${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`);
const sigAlgKey = `${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`;
@@ -37,17 +42,17 @@ export function getLeaf(dsc: string): string {
if (signatureAlgorithm === 'ecdsa') {
let qx = splitToWords(BigInt(hexToDecimal(x)), n, k);
let qy = splitToWords(BigInt(hexToDecimal(y)), n, k);
return customHasher([sigAlgIndex, ...qx, ...qy])
return customHasher([sigAlgIndex, ...qx, ...qy]);
} else {
const pubkeyChunked = splitToWords(BigInt(hexToDecimal(modulus)), n, k);
return customHasher([sigAlgIndex, ...pubkeyChunked]);
}
}
export function getLeafCSCA(dsc: string): string {
const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } = parseCertificate(dsc);
const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } =
parseCertificate(dsc);
const { n, k } = getNAndKCSCA(signatureAlgorithm);
console.log(`${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`)
console.log(`${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`);
const sigAlgKey = `${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`;
console.log('sigAlgKey', sigAlgKey);
const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey];
@@ -60,16 +65,21 @@ export function getLeafCSCA(dsc: string): string {
if (signatureAlgorithm === 'ecdsa') {
let qx = splitToWords(BigInt(hexToDecimal(x)), n, k);
let qy = splitToWords(BigInt(hexToDecimal(y)), n, k);
return customHasher([sigAlgIndex, ...qx, ...qy])
return customHasher([sigAlgIndex, ...qx, ...qy]);
} else {
const pubkeyChunked = splitToWords(BigInt(hexToDecimal(modulus)), n, k);
return customHasher([sigAlgIndex, ...pubkeyChunked]);
}
}
export function generateCommitment(secret: string, attestation_id: string, pubkey_leaf: string, mrz_bytes: any[], dg2Hash: any[]) {
const dg2Hash2 = customHasher(formatDg2Hash(dg2Hash).map(x => x.toString()));
export function generateCommitment(
secret: string,
attestation_id: string,
pubkey_leaf: string,
mrz_bytes: any[],
dg2Hash: any[]
) {
const dg2Hash2 = customHasher(formatDg2Hash(dg2Hash).map((x) => x.toString()));
const commitment = poseidon7([
secret,
attestation_id,
@@ -77,19 +87,18 @@ export function generateCommitment(secret: string, attestation_id: string, pubke
mrz_bytes[0],
mrz_bytes[1],
mrz_bytes[2],
dg2Hash2
dg2Hash2,
]);
return commitment;
}
export async function fetchTreeFromUrl(url: string): Promise<LeanIMT> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const commitmentMerkleTree = await response.json();
console.log("\x1b[90m%s\x1b[0m", "commitment merkle tree: ", commitmentMerkleTree);
console.log('\x1b[90m%s\x1b[0m', 'commitment merkle tree: ', commitmentMerkleTree);
const tree = LeanIMT.import((a, b) => poseidon2([a, b]), commitmentMerkleTree);
return tree;
}

View File

@@ -1,11 +1,11 @@
import { attributeToPosition } from "../constants/constants";
import { DisclosureOptions } from "./appType";
import { attributeToPosition } from '../constants/constants';
import { DisclosureOptions } from './appType';
export function revealBitmapFromMapping(attributeToReveal: { [key: string]: string }): string[] {
const reveal_bitmap = Array(90).fill('0');
Object.entries(attributeToReveal).forEach(([attribute, reveal]) => {
if (reveal !== "") {
if (reveal !== '') {
const [start, end] = attributeToPosition[attribute as keyof typeof attributeToPosition];
reveal_bitmap.fill('1', start, end + 1);
}
@@ -26,10 +26,11 @@ export function revealBitmapFromAttributes(disclosureOptions: DisclosureOptions)
return reveal_bitmap;
}
export function unpackReveal(revealedData_packed: string | string[]): string[] {
// If revealedData_packed is not an array, convert it to an array
const packedArray = Array.isArray(revealedData_packed) ? revealedData_packed : [revealedData_packed];
const packedArray = Array.isArray(revealedData_packed)
? revealedData_packed
: [revealedData_packed];
const bytesCount = [31, 31, 28]; // nb of bytes in each of the first three field elements
const bytesArray = packedArray.flatMap((element: string, index: number) => {
@@ -45,20 +46,21 @@ export function unpackReveal(revealedData_packed: string | string[]): string[] {
return bytesArray.map((byte: bigint) => String.fromCharCode(Number(byte)));
}
export function formatAndUnpackReveal(revealedData_packed: string[]): string[] {
const revealedData_packed_formatted = [
revealedData_packed["revealedData_packed[0]"],
revealedData_packed["revealedData_packed[1]"],
revealedData_packed["revealedData_packed[2]"],
revealedData_packed['revealedData_packed[0]'],
revealedData_packed['revealedData_packed[1]'],
revealedData_packed['revealedData_packed[2]'],
];
return unpackReveal(revealedData_packed_formatted);
}
export function formatAndUnpackForbiddenCountriesList(forbiddenCountriesList_packed: string[]): string[] {
export function formatAndUnpackForbiddenCountriesList(
forbiddenCountriesList_packed: string[]
): string[] {
const forbiddenCountriesList_packed_formatted = [
forbiddenCountriesList_packed["forbidden_countries_list_packed[0]"],
forbiddenCountriesList_packed["forbidden_countries_list_packed[1]"],
forbiddenCountriesList_packed['forbidden_countries_list_packed[0]'],
forbiddenCountriesList_packed['forbidden_countries_list_packed[1]'],
];
return unpackReveal(forbiddenCountriesList_packed_formatted);
}

View File

@@ -9,7 +9,7 @@ export function shaPad(prehash_prepad_m: Uint8Array, maxShaBytes: number): [Uint
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, int8toBytes(0));
}
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, length_in_bytes);
assert((prehash_prepad_m.length * 8) % 512 === 0, "Padding did not complete properly!");
assert((prehash_prepad_m.length * 8) % 512 === 0, 'Padding did not complete properly!');
let messageLen = prehash_prepad_m.length;
while (prehash_prepad_m.length < maxShaBytes) {
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, int64toBytes(0));
@@ -49,4 +49,4 @@ export function assert(cond: boolean, errorMessage: string) {
if (!cond) {
throw new Error(errorMessage);
}
}
}

View File

@@ -1,6 +1,6 @@
import { poseidon9, poseidon3, poseidon2, poseidon6, poseidon13 } from "poseidon-lite"
import { stringToAsciiBigIntArray } from "./utils";
import { ChildNodes, SMT } from "@openpassport/zk-kit-smt"
import { poseidon9, poseidon3, poseidon2, poseidon6, poseidon13 } from 'poseidon-lite';
import { stringToAsciiBigIntArray } from './utils';
import { ChildNodes, SMT } from '@openpassport/zk-kit-smt';
// SMT trees for 3 levels :
// 1. Passport tree : level 3 (Absolute Match)
@@ -8,76 +8,77 @@ import { ChildNodes, SMT } from "@openpassport/zk-kit-smt"
// 3. Names tree : level 1 (Partial Match)
export function buildSMT(field: any[], treetype: string): [number, number, SMT] {
let count = 0
let count = 0;
let startTime = performance.now();
const hash2 = (childNodes: ChildNodes) => (childNodes.length === 2 ? poseidon2(childNodes) : poseidon3(childNodes))
const tree = new SMT(hash2, true)
const hash2 = (childNodes: ChildNodes) =>
childNodes.length === 2 ? poseidon2(childNodes) : poseidon3(childNodes);
const tree = new SMT(hash2, true);
for (let i = 0; i < field.length; i++) {
const entry = field[i]
const entry = field[i];
if (i !== 0) {
console.log('Processing', treetype, 'number', i, "out of", field.length);
console.log('Processing', treetype, 'number', i, 'out of', field.length);
}
let leaf = BigInt(0)
if (treetype == "passport") {
leaf = processPassport(entry.Pass_No, i)
} else if (treetype == "name_dob") {
leaf = processNameDob(entry, i)
} else if (treetype == "name") {
leaf = processName(entry.First_Name, entry.Last_Name, i)
} else if (treetype == "country") {
let leaf = BigInt(0);
if (treetype == 'passport') {
leaf = processPassport(entry.Pass_No, i);
} else if (treetype == 'name_dob') {
leaf = processNameDob(entry, i);
} else if (treetype == 'name') {
leaf = processName(entry.First_Name, entry.Last_Name, i);
} else if (treetype == 'country') {
const keys = Object.keys(entry);
leaf = processCountry(keys[0], entry[keys[0]], i)
leaf = processCountry(keys[0], entry[keys[0]], i);
}
if (leaf == BigInt(0) || tree.createProof(leaf).membership) {
console.log("This entry already exists in the tree, skipping...")
continue
console.log('This entry already exists in the tree, skipping...');
continue;
}
count += 1
tree.add(leaf, BigInt(1))
count += 1;
tree.add(leaf, BigInt(1));
}
console.log("Total", treetype, "paresed are : ", count, " over ", field.length)
console.log(treetype, 'tree built in', performance.now() - startTime, 'ms')
return [count, performance.now() - startTime, tree]
console.log('Total', treetype, 'paresed are : ', count, ' over ', field.length);
console.log(treetype, 'tree built in', performance.now() - startTime, 'ms');
return [count, performance.now() - startTime, tree];
}
function processPassport(passno: string, index: number): bigint {
if (passno.length > 9) {
console.log('passport length is greater than 9:', index, passno)
console.log('passport length is greater than 9:', index, passno);
} else if (passno.length < 9) {
while (passno.length != 9) {
passno += '<'
passno += '<';
}
}
const leaf = getPassportNumberLeaf(stringToAsciiBigIntArray(passno))
const leaf = getPassportNumberLeaf(stringToAsciiBigIntArray(passno));
if (!leaf) {
console.log('Error creating leaf value', index, passno)
return BigInt(0)
console.log('Error creating leaf value', index, passno);
return BigInt(0);
}
return leaf
return leaf;
}
function processNameDob(entry: any, i: number): bigint {
const firstName = entry.First_Name
const lastName = entry.Last_Name
const day = entry.day
const month = entry.month
const year = entry.year
const firstName = entry.First_Name;
const lastName = entry.Last_Name;
const day = entry.day;
const month = entry.month;
const year = entry.year;
if (day == null || month == null || year == null) {
console.log('dob is null', i, entry)
return BigInt(0)
console.log('dob is null', i, entry);
return BigInt(0);
}
const nameHash = processName(firstName, lastName, i)
const dobHash = processDob(day, month, year, i)
const leaf = poseidon2([dobHash, nameHash])
return leaf
const nameHash = processName(firstName, lastName, i);
const dobHash = processDob(day, month, year, i);
const leaf = poseidon2([dobHash, nameHash]);
return leaf;
}
function processName(firstName: string, lastName: string, i: number): bigint {
@@ -93,81 +94,89 @@ function processName(firstName: string, lastName: string, i: number): bigint {
// TODO : Handle special cases like malaysia : no two filler characters like << for surname and givenname
// TODO : Verify rules for . in names. eg : J. Doe (Done same as apostrophe for now)
let arr = lastName + '<<' + firstName
let arr = lastName + '<<' + firstName;
if (arr.length > 39) {
arr = arr.substring(0, 39)
arr = arr.substring(0, 39);
} else {
while (arr.length < 39) {
arr += '<'
arr += '<';
}
}
let nameArr = stringToAsciiBigIntArray(arr)
return getNameLeaf(nameArr, i)
let nameArr = stringToAsciiBigIntArray(arr);
return getNameLeaf(nameArr, i);
}
function processDob(day: string, month: string, year: string, i: number): bigint {
// YYMMDD
const monthMap: { [key: string]: string } = {
jan: "01",
feb: "02",
mar: "03",
apr: "04",
may: "05",
jun: "06",
jul: "07",
aug: "08",
sep: "09",
oct: "10",
nov: "11",
dec: "12"
jan: '01',
feb: '02',
mar: '03',
apr: '04',
may: '05',
jun: '06',
jul: '07',
aug: '08',
sep: '09',
oct: '10',
nov: '11',
dec: '12',
};
month = monthMap[month.toLowerCase()];
year = year.slice(-2);
const dob = year + month + day;
let arr = stringToAsciiBigIntArray(dob);
return getDobLeaf(arr, i)
return getDobLeaf(arr, i);
}
function processCountry(country1: string, country2: string, i: number) {
let arr = stringToAsciiBigIntArray(country1)
let arr2 = stringToAsciiBigIntArray(country2)
let arr = stringToAsciiBigIntArray(country1);
let arr2 = stringToAsciiBigIntArray(country2);
const leaf = getCountryLeaf(arr, arr2, i)
const leaf = getCountryLeaf(arr, arr2, i);
if (!leaf) {
console.log('Error creating leaf value', i, country1, country2)
return BigInt(0)
console.log('Error creating leaf value', i, country1, country2);
return BigInt(0);
}
return leaf
return leaf;
}
export function getCountryLeaf(country_by: (bigint | number)[], country_to: (bigint | number)[], i?: number): bigint {
export function getCountryLeaf(
country_by: (bigint | number)[],
country_to: (bigint | number)[],
i?: number
): bigint {
if (country_by.length !== 3 || country_to.length !== 3) {
console.log('parsed passport length is not 3:', i, country_to, country_by)
return
console.log('parsed passport length is not 3:', i, country_to, country_by);
return;
}
try {
const country = country_by.concat(country_to)
return poseidon6(country)
const country = country_by.concat(country_to);
return poseidon6(country);
} catch (err) {
console.log('err : sanc_country hash', err, i, country_by, country_to)
console.log('err : sanc_country hash', err, i, country_by, country_to);
}
}
export function getPassportNumberLeaf(passport: (bigint | number)[], i?: number): bigint {
if (passport.length !== 9) {
console.log('parsed passport length is not 9:', i, passport)
return
console.log('parsed passport length is not 9:', i, passport);
return;
}
try {
return poseidon9(passport)
return poseidon9(passport);
} catch (err) {
console.log('err : passport', err, i, passport)
console.log('err : passport', err, i, passport);
}
}
export function getNameDobLeaf(nameMrz: (bigint | number)[], dobMrz: (bigint | number)[], i?: number): bigint {
return poseidon2([getDobLeaf(dobMrz), getNameLeaf(nameMrz)])
export function getNameDobLeaf(
nameMrz: (bigint | number)[],
dobMrz: (bigint | number)[],
i?: number
): bigint {
return poseidon2([getDobLeaf(dobMrz), getNameLeaf(nameMrz)]);
}
export function getNameLeaf(nameMrz: (bigint | number)[], i?: number): bigint {
@@ -177,24 +186,24 @@ export function getNameLeaf(nameMrz: (bigint | number)[], i?: number): bigint {
chunks.push(nameMrz.slice(0, 13), nameMrz.slice(13, 26), nameMrz.slice(26, 39)); // 39/3 for posedion to digest
for (const chunk of chunks) {
middleChunks.push(poseidon13(chunk))
middleChunks.push(poseidon13(chunk));
}
try {
return poseidon3(middleChunks)
return poseidon3(middleChunks);
} catch (err) {
console.log('err : Name', err, i, nameMrz)
console.log('err : Name', err, i, nameMrz);
}
}
export function getDobLeaf(dobMrz: (bigint | number)[], i?: number): bigint {
if (dobMrz.length !== 6) {
console.log('parsed dob length is not 9:', i, dobMrz)
return
console.log('parsed dob length is not 9:', i, dobMrz);
return;
}
try {
return poseidon6(dobMrz)
return poseidon6(dobMrz);
} catch (err) {
console.log('err : Dob', err, i, dobMrz)
console.log('err : Dob', err, i, dobMrz);
}
}

View File

@@ -1,120 +1,154 @@
import {
PROVE_RSA_NULLIFIER_INDEX,
PROVE_RSA_REVEALED_DATA_PACKED_INDEX,
PROVE_RSA_OLDER_THAN_INDEX,
PROVE_RSA_PUBKEY_DISCLOSED_INDEX,
PROVE_RSA_FORBIDDEN_COUNTRIES_LIST_PACKED_DISCLOSED_INDEX,
PROVE_RSA_OFAC_RESULT_INDEX,
PROVE_RSA_COMMITMENT_INDEX,
PROVE_RSA_BLINDED_DSC_COMMITMENT_INDEX,
PROVE_RSA_CURRENT_DATE_INDEX,
PROVE_RSA_USER_IDENTIFIER_INDEX,
PROVE_RSA_SCOPE_INDEX,
DSC_BLINDED_DSC_COMMITMENT_INDEX
} from "../../constants/contractConstants";
import { Proof } from "../types";
PROVE_RSA_NULLIFIER_INDEX,
PROVE_RSA_REVEALED_DATA_PACKED_INDEX,
PROVE_RSA_OLDER_THAN_INDEX,
PROVE_RSA_PUBKEY_DISCLOSED_INDEX,
PROVE_RSA_FORBIDDEN_COUNTRIES_LIST_PACKED_DISCLOSED_INDEX,
PROVE_RSA_OFAC_RESULT_INDEX,
PROVE_RSA_COMMITMENT_INDEX,
PROVE_RSA_BLINDED_DSC_COMMITMENT_INDEX,
PROVE_RSA_CURRENT_DATE_INDEX,
PROVE_RSA_USER_IDENTIFIER_INDEX,
PROVE_RSA_SCOPE_INDEX,
DSC_BLINDED_DSC_COMMITMENT_INDEX,
} from '../../constants/contractConstants';
import { Proof } from '../types';
export function generateMockRSAProveVerifierInputs({
nullifier = "1",
revealedData_packed = ["2", "3", "4"],
older_than = ["49", "56"],
pubkey_disclosed = ["0", "0", "0", "0","0", "0", "0", "0","0", "0", "0", "0","0", "0", "0", "0","0", "0", "0", "0","0", "0", "0", "0","0", "0", "0", "0","0", "0", "0", "0"],
forbidden_contries_list_packed_disclose = ["8", "9"],
ofac_result = "10",
commitment = "11",
blinded_dsc_commitment = "12",
current_date = new Date(),
user_identifier = "13",
scope = "14",
nullifier = '1',
revealedData_packed = ['2', '3', '4'],
older_than = ['49', '56'],
pubkey_disclosed = [
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
'0',
],
forbidden_contries_list_packed_disclose = ['8', '9'],
ofac_result = '10',
commitment = '11',
blinded_dsc_commitment = '12',
current_date = new Date(),
user_identifier = '13',
scope = '14',
}: {
nullifier?: string,
revealedData_packed?: string[],
older_than?: string[],
pubkey_disclosed?: string[],
forbidden_contries_list_packed_disclose?: string[],
ofac_result?: string,
commitment?: string,
blinded_dsc_commitment?: string,
current_date?: Date,
user_identifier?: string,
scope?: string,
nullifier?: string;
revealedData_packed?: string[];
older_than?: string[];
pubkey_disclosed?: string[];
forbidden_contries_list_packed_disclose?: string[];
ofac_result?: string;
commitment?: string;
blinded_dsc_commitment?: string;
current_date?: Date;
user_identifier?: string;
scope?: string;
}): Proof {
let pub_signals: string[] = [];
let pub_signals: string[] = [];
pub_signals[PROVE_RSA_NULLIFIER_INDEX] = nullifier;
pub_signals.splice(PROVE_RSA_REVEALED_DATA_PACKED_INDEX, 0, ...revealedData_packed);
pub_signals.splice(PROVE_RSA_OLDER_THAN_INDEX, 0, ...older_than);
pub_signals.splice(PROVE_RSA_PUBKEY_DISCLOSED_INDEX, 0, ...pubkey_disclosed);
pub_signals.splice(PROVE_RSA_FORBIDDEN_COUNTRIES_LIST_PACKED_DISCLOSED_INDEX, 0, ...forbidden_contries_list_packed_disclose);
pub_signals[PROVE_RSA_OFAC_RESULT_INDEX] = ofac_result;
pub_signals[PROVE_RSA_COMMITMENT_INDEX] = commitment;
pub_signals[PROVE_RSA_BLINDED_DSC_COMMITMENT_INDEX] = blinded_dsc_commitment;
pub_signals.splice(PROVE_RSA_CURRENT_DATE_INDEX, 0, ...getDateNum(current_date));
pub_signals[PROVE_RSA_USER_IDENTIFIER_INDEX] = user_identifier;
pub_signals[PROVE_RSA_SCOPE_INDEX] = scope;
pub_signals[PROVE_RSA_NULLIFIER_INDEX] = nullifier;
pub_signals.splice(PROVE_RSA_REVEALED_DATA_PACKED_INDEX, 0, ...revealedData_packed);
pub_signals.splice(PROVE_RSA_OLDER_THAN_INDEX, 0, ...older_than);
pub_signals.splice(PROVE_RSA_PUBKEY_DISCLOSED_INDEX, 0, ...pubkey_disclosed);
pub_signals.splice(
PROVE_RSA_FORBIDDEN_COUNTRIES_LIST_PACKED_DISCLOSED_INDEX,
0,
...forbidden_contries_list_packed_disclose
);
pub_signals[PROVE_RSA_OFAC_RESULT_INDEX] = ofac_result;
pub_signals[PROVE_RSA_COMMITMENT_INDEX] = commitment;
pub_signals[PROVE_RSA_BLINDED_DSC_COMMITMENT_INDEX] = blinded_dsc_commitment;
pub_signals.splice(PROVE_RSA_CURRENT_DATE_INDEX, 0, ...getDateNum(current_date));
pub_signals[PROVE_RSA_USER_IDENTIFIER_INDEX] = user_identifier;
pub_signals[PROVE_RSA_SCOPE_INDEX] = scope;
let proof: Proof = {
proof: {
a: ["1", "1"],
b: [
["1", "2"],
["3", "4"]
],
c: ["5", "6"]
},
pub_signals: pub_signals
};
return proof;
let proof: Proof = {
proof: {
a: ['1', '1'],
b: [
['1', '2'],
['3', '4'],
],
c: ['5', '6'],
},
pub_signals: pub_signals,
};
return proof;
}
export function generateMockDSCVerifierInputs({
blinded_dsc_commitment = "12",
blinded_dsc_commitment = '12',
}: {
blinded_dsc_commitment?: string,
blinded_dsc_commitment?: string;
}): Proof {
let pub_signals: string[] = [];
let pub_signals: string[] = [];
pub_signals[DSC_BLINDED_DSC_COMMITMENT_INDEX] = blinded_dsc_commitment;
pub_signals[DSC_BLINDED_DSC_COMMITMENT_INDEX] = blinded_dsc_commitment;
let proof: Proof = {
proof: {
a: ["1", "1"],
b: [
["1", "2"],
["3", "4"]
],
c: ["5", "6"]
},
pub_signals: pub_signals
};
return proof;
let proof: Proof = {
proof: {
a: ['1', '1'],
b: [
['1', '2'],
['3', '4'],
],
c: ['5', '6'],
},
pub_signals: pub_signals,
};
return proof;
}
function getDateNum(date: Date = new Date()): string[] {
const year = date.getUTCFullYear() % 100;
const month = date.getUTCMonth() + 1;
const day = date.getUTCDate();
const year = date.getUTCFullYear() % 100;
const month = date.getUTCMonth() + 1;
const day = date.getUTCDate();
const dateNum = [
Math.floor(year / 10),
year % 10,
Math.floor(month / 10),
month % 10,
Math.floor(day / 10),
day % 10,
];
const dateNum = [
Math.floor(year / 10),
(year % 10),
(Math.floor(month / 10)),
(month % 10),
(Math.floor(day / 10)),
(day % 10),
];
return dateNum.map(num => num.toString());
return dateNum.map((num) => num.toString());
}
export function convertProofTypeIntoInput(proof: Proof) {
return {
a: proof.proof.a,
b: proof.proof.b,
c: proof.proof.c,
pubSignals: proof.pub_signals
}
}
return {
a: proof.proof.a,
b: proof.proof.b,
c: proof.proof.c,
pubSignals: proof.pub_signals,
};
}

View File

@@ -10,25 +10,33 @@ export type PassportData = {
};
// Define the signature algorithm in "algorithm_hashfunction_domainPapameter_keyLength"
export type SignatureAlgorithm = 'rsa_sha1_65537_2048' | 'rsa_sha256_65537_2048' | 'rsapss_sha256_65537_2048' | 'ecdsa_sha256_secp256r1_256' | 'ecdsa_sha1_secp256r1_256' | 'ecdsa_sha384_secp384r1_384' | 'ecdsa_sha256_brainpoolP256r1_256' | 'rsa_sha256_3_2048' | 'rsa_sha256_65537_3072';
export type SignatureAlgorithm =
| 'rsa_sha1_65537_2048'
| 'rsa_sha256_65537_2048'
| 'rsapss_sha256_65537_2048'
| 'ecdsa_sha256_secp256r1_256'
| 'ecdsa_sha1_secp256r1_256'
| 'ecdsa_sha384_secp384r1_384'
| 'ecdsa_sha256_brainpoolP256r1_256'
| 'rsa_sha256_3_2048'
| 'rsa_sha256_65537_3072';
export type Proof = {
proof: {
a: [string, string],
b: [[string, string], [string, string]],
c: [string, string]
a: [string, string];
b: [[string, string], [string, string]];
c: [string, string];
};
pub_signals: string[];
}
};
export function castCSCAProof(proof: any): Proof {
return {
proof: {
a: proof.proof.pi_a.slice(0, 2),
b: [proof.proof.pi_b[0].slice(0, 2), proof.proof.pi_b[1].slice(0, 2)],
c: proof.proof.pi_c.slice(0, 2)
c: proof.proof.pi_c.slice(0, 2),
},
pub_signals: proof.pub_signals
}
pub_signals: proof.pub_signals,
};
}

View File

@@ -4,7 +4,16 @@ import { sha1 } from 'js-sha1';
import { sha384, sha512_256 } from 'js-sha512';
import { SMT } from '@openpassport/zk-kit-smt';
import forge from 'node-forge';
import { n_dsc, k_dsc, k_dsc_3072, n_dsc_ecdsa, k_dsc_ecdsa, n_csca, k_csca, attributeToPosition } from '../constants/constants';
import {
n_dsc,
k_dsc,
k_dsc_3072,
n_dsc_ecdsa,
k_dsc_ecdsa,
n_csca,
k_csca,
attributeToPosition,
} from '../constants/constants';
import { unpackReveal } from './revealBitmap';
import { SignatureAlgorithm } from './types';
@@ -21,18 +30,18 @@ export function formatMrz(mrz: string) {
export function getNAndK(sigAlg: SignatureAlgorithm) {
if (sigAlg === 'rsa_sha256_65537_3072') {
return { n: n_dsc, k: k_dsc_3072 }; // 3072/32 = 96
return { n: n_dsc, k: k_dsc_3072 }; // 3072/32 = 96
}
if (sigAlg.startsWith('ecdsa_')) {
return { n: n_dsc_ecdsa, k: k_dsc_ecdsa }; // 256/32 = 8
return { n: n_dsc_ecdsa, k: k_dsc_ecdsa }; // 256/32 = 8
}
if (sigAlg.startsWith('rsapss_')) {
return { n: n_dsc, k: k_dsc }; // 2048/32 = 64
return { n: n_dsc, k: k_dsc }; // 2048/32 = 64
}
return { n: n_dsc, k: k_dsc }; // 2048/32 = 64
return { n: n_dsc, k: k_dsc }; // 2048/32 = 64
}
export function getNAndKCSCA(sigAlg: 'rsa' | 'ecdsa' | 'rsapss') {
@@ -43,7 +52,8 @@ export function getNAndKCSCA(sigAlg: 'rsa' | 'ecdsa' | 'rsapss') {
export function formatDg2Hash(dg2Hash: number[]) {
const unsignedBytesDg2Hash = dg2Hash.map((x) => toUnsignedByte(x));
while (unsignedBytesDg2Hash.length < 64) { // pad it to 64 bytes to correspond to the hash length of sha512 and avoid multiplying circuits
while (unsignedBytesDg2Hash.length < 64) {
// pad it to 64 bytes to correspond to the hash length of sha512 and avoid multiplying circuits
unsignedBytesDg2Hash.push(0);
}
return unsignedBytesDg2Hash;
@@ -102,13 +112,13 @@ export function formatAndConcatenateDataHashes(
// spain
// 48, -127, -79,
// 2, 1,
// 0,
// 48, 7, 6, 5,
// 2, 1,
// 0,
// 48, 7, 6, 5,
// 1.3.14.3.2.26 is sha1
// 43, 14, 3, 2, 26,
// SEQUENCE + ...
// 48, -127, -94,
// 48, -127, -94,
// => current conclusion is we should be able to just hardcode indexes
// => as they shouldn't change must for same sig alg.
@@ -316,34 +326,35 @@ export function packBytes(unpacked) {
export function generateSMTProof(smt: SMT, leaf: bigint) {
const { entry, matchingEntry, siblings, root, membership } = smt.createProof(leaf);
const depth = siblings.length
const depth = siblings.length;
let closestleaf;
if (!matchingEntry) { // we got the 0 leaf or membership
if (!matchingEntry) {
// we got the 0 leaf or membership
// then check if entry[1] exists
if (!entry[1]) {
// non membership proof
closestleaf = BigInt(0); // 0 leaf
} else {
closestleaf = BigInt(entry[0]); // leaf itself (memb proof)
closestleaf = BigInt(entry[0]); // leaf itself (memb proof)
}
} else {
// non membership proof
closestleaf = BigInt(matchingEntry[0]); // actual closest
}
// PATH, SIBLINGS manipulation as per binary tree in the circuit
siblings.reverse()
// PATH, SIBLINGS manipulation as per binary tree in the circuit
siblings.reverse();
while (siblings.length < 256) siblings.push(BigInt(0));
// ----- Useful for debugging hence leaving as comments -----
// const binary = entry[0].toString(2)
// const bits = binary.slice(-depth);
// let indices = bits.padEnd(256, "0").split("").map(Number)
// const pathToMatch = num2Bits(256,BigInt(entry[0]))
// const pathToMatch = num2Bits(256,BigInt(entry[0]))
// while(indices.length < 256) indices.push(0);
// // CALCULATED ROOT FOR TESTING
// // closestleaf, depth, siblings, indices, root : needed
// // CALCULATED ROOT FOR TESTING
// // closestleaf, depth, siblings, indices, root : needed
// let calculatedNode = poseidon3([closestleaf,1,1]);
// console.log("Initial node while calculating",calculatedNode)
// console.log(smt.verifyProof(smt.createProof(leaf)))
@@ -413,7 +424,7 @@ function hexToBigInt(hex: string): bigint {
function checkBigInt(bigInt: bigint) {
const max253BitValue = BigInt(2n ** 253n - 1n);
if (bigInt > max253BitValue) {
throw new Error("Input should be < 2^253 - 1");
throw new Error('Input should be < 2^253 - 1');
}
}
@@ -445,14 +456,17 @@ export function castToUUID(bigInt: bigint): string {
/// scope
function checkStringLength(str: string) {
if (str.length > 25) {
throw new Error("Input string must not exceed 25 characters");
throw new Error('Input string must not exceed 25 characters');
}
}
function stringToBigInt(str: string): bigint {
return BigInt('1' + Array.from(str)
.map(char => char.charCodeAt(0).toString().padStart(3, '0'))
.join(''));
return BigInt(
'1' +
Array.from(str)
.map((char) => char.charCodeAt(0).toString().padStart(3, '0'))
.join('')
);
}
export function castFromScope(scope: string): string {
@@ -463,7 +477,7 @@ export function castFromScope(scope: string): string {
export function castToScope(num: bigint): string {
const str = num.toString().slice(1); // Remove leading '1'
const charCodes = str.match(/.{1,3}/g) || [];
return String.fromCharCode(...charCodes.map(code => parseInt(code, 10)));
return String.fromCharCode(...charCodes.map((code) => parseInt(code, 10)));
}
export function stringToAsciiBigIntArray(str: string): bigint[] {
@@ -475,11 +489,11 @@ export function stringToAsciiBigIntArray(str: string): bigint[] {
}
export function hexToBin(n: string): string {
let bin = Number(`0x${n[0]}`).toString(2)
let bin = Number(`0x${n[0]}`).toString(2);
for (let i = 1; i < n.length; i += 1) {
bin += Number(`0x${n[i]}`).toString(2).padStart(4, "0")
bin += Number(`0x${n[i]}`).toString(2).padStart(4, '0');
}
return bin
return bin;
}
export function num2Bits(n: number, inValue: bigint): bigint[] {
@@ -491,7 +505,7 @@ export function num2Bits(n: number, inValue: bigint): bigint[] {
out[i] = (inValue >> BigInt(i)) & BigInt(1);
if (out[i] !== BigInt(0) && out[i] !== BigInt(1)) {
throw new Error("Bit value is not binary.");
throw new Error('Bit value is not binary.');
}
lc1 += out[i] * e2;
@@ -499,7 +513,7 @@ export function num2Bits(n: number, inValue: bigint): bigint[] {
}
if (lc1 !== inValue) {
throw new Error("Reconstructed value does not match the input.");
throw new Error('Reconstructed value does not match the input.');
}
return out;
}
@@ -515,11 +529,13 @@ const validateUserId = (userId: string, type: UserIdType): boolean => {
case 'hex':
return /^[0-9A-Fa-f]+$/.test(userId);
case 'uuid':
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(userId);
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
userId
);
default:
return false;
}
}
};
const getMaxLenght = (idType: UserIdType) => {
switch (idType) {
@@ -528,16 +544,21 @@ const getMaxLenght = (idType: UserIdType) => {
default:
return 63;
}
}
};
export const parseUIDToBigInt = (user_identifier: string, user_identifier_type: UserIdType): string => {
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`);
}
const maxLength = getMaxLenght(user_identifier_type);
if (user_identifier.length > maxLength) {
throw new Error(`User identifier of type ${user_identifier_type} exceeds maximum length of ${maxLength} characters`);
throw new Error(
`User identifier of type ${user_identifier_type} exceeds maximum length of ${maxLength} characters`
);
}
switch (user_identifier_type) {
@@ -548,21 +569,23 @@ export const parseUIDToBigInt = (user_identifier: string, user_identifier_type:
case 'uuid':
return uuidToBigInt(user_identifier).toString();
}
}
};
export function formatCountriesList(countries: string[]) {
if (countries.length > 20) {
throw new Error("Countries list must be inferior or equals to 20");
throw new Error('Countries list must be inferior or equals to 20');
}
const paddedCountries = countries.concat(Array(20 - countries.length).fill(''));
const result = paddedCountries.flatMap(country => {
const chars = country.padEnd(3, '\0').split('').map(char => char.charCodeAt(0));
const result = paddedCountries.flatMap((country) => {
const chars = country
.padEnd(3, '\0')
.split('')
.map((char) => char.charCodeAt(0));
return chars;
});
return result;
}
export function getAttributeFromUnpackedReveal(unpackedReveal: string[], attribute: string) {
const position = attributeToPosition[attribute];
let attributeValue = '';
@@ -574,12 +597,14 @@ export function getAttributeFromUnpackedReveal(unpackedReveal: string[], attribu
return attributeValue;
}
export function formatForbiddenCountriesListFromCircuitOutput(forbiddenCountriesList: string[]): string[] {
export function formatForbiddenCountriesListFromCircuitOutput(
forbiddenCountriesList: string[]
): string[] {
const countryList1 = unpackReveal(forbiddenCountriesList[0]);
const countryList2 = unpackReveal(forbiddenCountriesList[1]);
const concatenatedCountryList = countryList1.concat(countryList2);
// dump every '\x00' value from the list
const cleanedCountryList = concatenatedCountryList.filter(value => value !== '\x00');
const cleanedCountryList = concatenatedCountryList.filter((value) => value !== '\x00');
// Concatenate every 3 elements to form country codes
const formattedCountryList = [];
for (let i = 0; i < cleanedCountryList.length; i += 3) {
@@ -592,7 +617,7 @@ export function formatForbiddenCountriesListFromCircuitOutput(forbiddenCountries
}
export function getOlderThanFromCircuitOutput(olderThan: string[]): number {
const ageString = olderThan.map(code => String.fromCharCode(parseInt(code))).join('');
const ageString = olderThan.map((code) => String.fromCharCode(parseInt(code))).join('');
const age = parseInt(ageString, 10);
return isNaN(age) ? 0 : age;
}

View File

@@ -10,18 +10,18 @@ import { Certificate } from 'pkijs';
import elliptic from 'elliptic';
const sigAlgs: SignatureAlgorithm[] = [
'rsa_sha1',
'rsa_sha256',
'rsapss_sha256',
'ecdsa_sha256',
'ecdsa_sha1',
'ecdsa_sha384',
'rsa_sha1_65537_2048',
'rsa_sha256_65537_2048',
'rsapss_sha256_65537_2048',
'ecdsa_sha256_secp256r1_256',
'ecdsa_sha1_secp256r1_256',
// 'ecdsa_sha384_secp384r1_384',
];
describe('Mock Passport Data Generator', function () {
this.timeout(0);
sigAlgs.forEach(sigAlg => {
sigAlgs.forEach((sigAlg) => {
it(`should generate valid passport data for ${sigAlg}`, () => {
const passportData = genMockPassportData(sigAlg, 'FRA', '000101', '300101');
expect(passportData).to.exist;
@@ -35,20 +35,31 @@ function verify(passportData: PassportData): boolean {
const { signatureAlgorithm, hashFunction, hashLen, curve } = parseCertificate(dsc);
const formattedMrz = formatMrz(mrz);
const mrzHash = hash(hashFunction, formattedMrz);
const dg1HashOffset = findSubarrayIndex(eContent, mrzHash)
const dg1HashOffset = findSubarrayIndex(eContent, mrzHash);
assert(dg1HashOffset !== -1, 'MRZ hash index not found in eContent');
console.error("\x1b[32m", "signatureAlgorithm", signatureAlgorithm, " hashFunction", hashFunction, "eContent size", eContent.length, "signedAttr size", signedAttr.length, "\x1b[0m");
const concatHash = hash(hashFunction, eContent)
console.error(
'\x1b[32m',
'signatureAlgorithm',
signatureAlgorithm,
' hashFunction',
hashFunction,
'eContent size',
eContent.length,
'signedAttr size',
signedAttr.length,
'\x1b[0m'
);
const concatHash = hash(hashFunction, eContent);
assert(
arraysAreEqual(
concatHash,
signedAttr.slice(signedAttr.length - hashLen)
),
arraysAreEqual(concatHash, signedAttr.slice(signedAttr.length - hashLen)),
'concatHash is not at the right place in signedAttr'
);
if (signatureAlgorithm === 'ecdsa') {
const certBuffer = Buffer.from(dsc.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''), 'base64');
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;
@@ -59,7 +70,7 @@ function verify(passportData: PassportData): boolean {
const key = ec.keyFromPublic(publicKeyBuffer);
const md = hashFunction === 'sha1' ? forge.md.sha1.create() : forge.md.sha256.create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const msgHash = md.digest().toHex()
const msgHash = md.digest().toHex();
const signature_crypto = Buffer.from(encryptedDigest).toString('hex');
return key.verify(msgHash, signature_crypto);
@@ -76,7 +87,7 @@ function verify(passportData: PassportData): boolean {
const pss = forge.pss.create({
md: forge.md[hashFunction].create(),
mgf: forge.mgf.mgf1.create(forge.md[hashFunction].create()),
saltLength: hashLen
saltLength: hashLen,
});
return publicKey.verify(md.digest().bytes(), signature, pss);
} else {

View File

@@ -5,4 +5,4 @@
"target": "ES2020",
"moduleResolution": "node"
}
}
}