mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 06:38:09 -05:00
fix common test
This commit is contained in:
@@ -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
@@ -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
@@ -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}"
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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-----`;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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()];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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],
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "node"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user