mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 14:48:06 -05:00
Move self app store to mobile sdk (#1040)
This commit is contained in:
@@ -55,10 +55,14 @@ export {
|
||||
SelfAppBuilder,
|
||||
bigIntToString,
|
||||
brutforceSignatureAlgorithmDsc,
|
||||
buildSMT,
|
||||
calculateUserIdentifierHash,
|
||||
findStartPubKeyIndex,
|
||||
formatEndpoint,
|
||||
formatMrz,
|
||||
genAndInitMockPassportData,
|
||||
genMockIdDoc,
|
||||
genMockIdDocAndInitDataParsing,
|
||||
generateCircuitInputsDSC,
|
||||
generateCircuitInputsRegister,
|
||||
generateCircuitInputsVCandDisclose,
|
||||
@@ -69,28 +73,17 @@ export {
|
||||
getLeafCscaTree,
|
||||
getLeafDscTree,
|
||||
getSKIPEM,
|
||||
getSolidityPackedUserContextData,
|
||||
getUniversalLink,
|
||||
hashEndpointWithScope,
|
||||
initElliptic,
|
||||
initPassportDataParsing,
|
||||
parseCertificateSimple,
|
||||
parseDscCertificateData,
|
||||
genMockIdDoc,
|
||||
genMockIdDocAndInitDataParsing,
|
||||
buildSMT,
|
||||
calculateUserIdentifierHash,
|
||||
getSolidityPackedUserContextData,
|
||||
stringToBigInt,
|
||||
} from './src/utils/index.js';
|
||||
|
||||
export {
|
||||
prepareAadhaarRegisterTestData,
|
||||
prepareAadhaarDiscloseTestData,
|
||||
prepareAadhaarRegisterData,
|
||||
} from './src/utils/aadhaar/mockData.js';
|
||||
export { generateTestData, testCustomData } from './src/utils/aadhaar/utils.js';
|
||||
export { createSelector } from './src/utils/aadhaar/constants.js';
|
||||
|
||||
// Hash utilities
|
||||
export {
|
||||
customHasher,
|
||||
@@ -99,3 +92,11 @@ export {
|
||||
hash,
|
||||
packBytesAndPoseidon,
|
||||
} from './src/utils/hash.js';
|
||||
|
||||
export { generateTestData, testCustomData } from './src/utils/aadhaar/utils.js';
|
||||
|
||||
export {
|
||||
prepareAadhaarDiscloseTestData,
|
||||
prepareAadhaarRegisterData,
|
||||
prepareAadhaarRegisterTestData,
|
||||
} from './src/utils/aadhaar/mockData.js';
|
||||
|
||||
@@ -647,8 +647,8 @@
|
||||
"build:watch": "tsup --watch",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check .",
|
||||
"lint:imports": "eslint . --fix",
|
||||
"lint:imports:check": "eslint .",
|
||||
"lint:imports": "yarn eslint --fix .",
|
||||
"lint:imports:check": "yarn eslint .",
|
||||
"nice": "yarn format && yarn lint:imports",
|
||||
"nice:check": "yarn lint && yarn lint:imports:check",
|
||||
"prepublishOnly": "yarn build",
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
export type Country3LetterCode = keyof typeof countryCodes;
|
||||
export type document_type = 'passport' | 'id_card';
|
||||
export type hashAlgosTypes = 'sha512' | 'sha384' | 'sha256' | 'sha224' | 'sha1';
|
||||
export const AADHAAR_ATTESTATION_ID = '3';
|
||||
export const API_URL = 'https://api.self.xyz';
|
||||
|
||||
export const API_URL_STAGING = 'https://api.staging.self.xyz';
|
||||
|
||||
export const CHAIN_NAME = 'celo';
|
||||
@@ -42,8 +44,6 @@ export const CSCA_TREE_URL_STAGING = 'https://tree.staging.self.xyz/csca';
|
||||
|
||||
export const CSCA_TREE_URL_STAGING_ID_CARD = 'https://tree.staging.self.xyz/csca-id';
|
||||
|
||||
export const AADHAAR_ATTESTATION_ID = '3';
|
||||
|
||||
// we make it global here because passing it to generateCircuitInputsRegister caused trouble
|
||||
export const DEFAULT_MAJORITY = '18';
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { buildAadhaarSMT } from '../trees.js';
|
||||
|
||||
async function build_aadhaar_ofac_smt() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable sort-exports/sort-exports */
|
||||
export const MAX_FIELD_BYTE_SIZE = 31;
|
||||
export const NAME_MAX_LENGTH = 2 * MAX_FIELD_BYTE_SIZE; // 62 bytes
|
||||
export const TOTAL_REVEAL_DATA_LENGTH = 119;
|
||||
|
||||
@@ -1,29 +1,34 @@
|
||||
import { calculateAge, generateTestData, testCustomData } from './utils.js';
|
||||
import {
|
||||
convertBigIntToByteArray,
|
||||
decompressByteArray,
|
||||
splitToWords,
|
||||
extractPhoto,
|
||||
} from '@anon-aadhaar/core';
|
||||
import { bufferToHex, Uint8ArrayToCharArray } from '@zk-email/helpers/dist/binary-format.js';
|
||||
import { sha256Pad } from '@zk-email/helpers/dist/sha-utils.js';
|
||||
import { testQRData } from './assets/dataInput.js';
|
||||
import { stringToAsciiArray } from './utils.js';
|
||||
import { packBytesAndPoseidon } from '../hash.js';
|
||||
import { poseidon5 } from 'poseidon-lite';
|
||||
import forge from 'node-forge';
|
||||
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
|
||||
import { SMT } from '@openpassport/zk-kit-smt';
|
||||
import { poseidon5 } from 'poseidon-lite';
|
||||
|
||||
import { COMMITMENT_TREE_DEPTH } from '../../constants/constants.js';
|
||||
import { findIndexInTree, formatInput } from '../circuits/generateInputs.js';
|
||||
import { packBytesAndPoseidon } from '../hash.js';
|
||||
import {
|
||||
generateMerkleProof,
|
||||
generateSMTProof,
|
||||
getNameDobLeafAadhaar,
|
||||
getNameYobLeafAahaar,
|
||||
} from '../trees.js';
|
||||
import { testQRData } from './assets/dataInput.js';
|
||||
import {
|
||||
calculateAge,
|
||||
extractQRDataFields,
|
||||
generateTestData,
|
||||
stringToAsciiArray,
|
||||
testCustomData,
|
||||
} from './utils.js';
|
||||
|
||||
import { COMMITMENT_TREE_DEPTH } from '../../constants/constants.js';
|
||||
import { extractQRDataFields } from './utils.js';
|
||||
import {
|
||||
convertBigIntToByteArray,
|
||||
decompressByteArray,
|
||||
extractPhoto,
|
||||
splitToWords,
|
||||
} from '@anon-aadhaar/core';
|
||||
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
|
||||
import { SMT } from '@openpassport/zk-kit-smt';
|
||||
import { bufferToHex, Uint8ArrayToCharArray } from '@zk-email/helpers/dist/binary-format.js';
|
||||
import { sha256Pad } from '@zk-email/helpers/dist/sha-utils.js';
|
||||
|
||||
// Helper function to compute padded name
|
||||
function computePaddedName(name: string): number[] {
|
||||
@@ -163,166 +168,6 @@ function processQRDataSimple(qrData: string) {
|
||||
};
|
||||
}
|
||||
|
||||
export function prepareAadhaarRegisterTestData(
|
||||
privKeyPem: string,
|
||||
pubkeyPem: string,
|
||||
secret: string,
|
||||
name?: string,
|
||||
dateOfBirth?: string,
|
||||
gender?: string,
|
||||
pincode?: string,
|
||||
state?: string,
|
||||
timestamp?: string
|
||||
) {
|
||||
const sharedData = processQRData(
|
||||
privKeyPem,
|
||||
name,
|
||||
dateOfBirth,
|
||||
gender,
|
||||
pincode,
|
||||
state,
|
||||
timestamp
|
||||
);
|
||||
|
||||
const delimiterIndices: number[] = [];
|
||||
for (let i = 0; i < sharedData.qrDataPadded.length; i++) {
|
||||
if (sharedData.qrDataPadded[i] === 255) {
|
||||
delimiterIndices.push(i);
|
||||
}
|
||||
if (delimiterIndices.length === 18) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let photoEOI = 0;
|
||||
for (let i = delimiterIndices[17]; i < sharedData.qrDataPadded.length - 1; i++) {
|
||||
if (sharedData.qrDataPadded[i + 1] === 217 && sharedData.qrDataPadded[i] === 255) {
|
||||
photoEOI = i + 1;
|
||||
}
|
||||
}
|
||||
if (photoEOI === 0) {
|
||||
throw new Error('Photo EOI not found');
|
||||
}
|
||||
|
||||
const signatureBytes = sharedData.decodedData.slice(
|
||||
sharedData.decodedData.length - 256,
|
||||
sharedData.decodedData.length
|
||||
);
|
||||
const signature = BigInt('0x' + bufferToHex(Buffer.from(signatureBytes)).toString());
|
||||
|
||||
const publicKey = forge.pki.publicKeyFromPem(pubkeyPem);
|
||||
|
||||
const modulusHex = publicKey.n.toString(16);
|
||||
const pubKey = BigInt('0x' + modulusHex);
|
||||
|
||||
const nullifier = nullifierHash(sharedData.extractedFields);
|
||||
const packedCommitment = computePackedCommitment(sharedData.extractedFields);
|
||||
const commitment = computeCommitment(
|
||||
BigInt(secret),
|
||||
BigInt(sharedData.qrHash),
|
||||
nullifier,
|
||||
packedCommitment,
|
||||
BigInt(sharedData.photoHash)
|
||||
);
|
||||
|
||||
const inputs = {
|
||||
qrDataPadded: Uint8ArrayToCharArray(sharedData.qrDataPadded),
|
||||
qrDataPaddedLength: sharedData.qrDataPaddedLen,
|
||||
delimiterIndices: delimiterIndices,
|
||||
signature: splitToWords(signature, BigInt(121), BigInt(17)),
|
||||
pubKey: splitToWords(pubKey, BigInt(121), BigInt(17)),
|
||||
secret: secret,
|
||||
photoEOI: photoEOI,
|
||||
};
|
||||
|
||||
return {
|
||||
inputs,
|
||||
nullifier,
|
||||
commitment,
|
||||
};
|
||||
}
|
||||
|
||||
export async function prepareAadhaarRegisterData(qrData: string, secret: string, certs: string[]) {
|
||||
const sharedData = processQRDataSimple(qrData);
|
||||
const delimiterIndices: number[] = [];
|
||||
for (let i = 0; i < sharedData.qrDataPadded.length; i++) {
|
||||
if (sharedData.qrDataPadded[i] === 255) {
|
||||
delimiterIndices.push(i);
|
||||
}
|
||||
if (delimiterIndices.length === 18) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let photoEOI = 0;
|
||||
for (let i = delimiterIndices[17]; i < sharedData.qrDataPadded.length - 1; i++) {
|
||||
if (sharedData.qrDataPadded[i + 1] === 217 && sharedData.qrDataPadded[i] === 255) {
|
||||
photoEOI = i + 1;
|
||||
}
|
||||
}
|
||||
if (photoEOI === 0) {
|
||||
throw new Error('Photo EOI not found');
|
||||
}
|
||||
|
||||
const signatureBytes = sharedData.decodedData.slice(
|
||||
sharedData.decodedData.length - 256,
|
||||
sharedData.decodedData.length
|
||||
);
|
||||
const signature = BigInt('0x' + bufferToHex(Buffer.from(signatureBytes)).toString());
|
||||
|
||||
//do promise.all for all certs and pick the one that is valid
|
||||
const certificates = await Promise.all(
|
||||
certs.map(async (cert) => {
|
||||
const certificate = forge.pki.certificateFromPem(cert);
|
||||
const publicKey = certificate.publicKey as forge.pki.rsa.PublicKey;
|
||||
|
||||
try {
|
||||
const md = forge.md.sha256.create();
|
||||
md.update(forge.util.binary.raw.encode(sharedData.signedData));
|
||||
|
||||
const isValid = publicKey.verify(md.digest().getBytes(), signatureBytes);
|
||||
return isValid;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
//find the valid cert
|
||||
const validCert = certificates.indexOf(true);
|
||||
if (validCert === -1) {
|
||||
throw new Error('No valid certificate found');
|
||||
}
|
||||
const certPem = certs[validCert];
|
||||
const cert = forge.pki.certificateFromPem(certPem);
|
||||
const modulusHex = (cert.publicKey as forge.pki.rsa.PublicKey).n.toString(16);
|
||||
const pubKey = BigInt('0x' + modulusHex);
|
||||
|
||||
const nullifier = nullifierHash(sharedData.extractedFields);
|
||||
const packedCommitment = computePackedCommitment(sharedData.extractedFields);
|
||||
const commitment = computeCommitment(
|
||||
BigInt(secret),
|
||||
BigInt(sharedData.qrHash),
|
||||
nullifier,
|
||||
packedCommitment,
|
||||
BigInt(sharedData.photoHash)
|
||||
);
|
||||
|
||||
const inputs = {
|
||||
qrDataPadded: Uint8ArrayToCharArray(sharedData.qrDataPadded),
|
||||
qrDataPaddedLength: sharedData.qrDataPaddedLen,
|
||||
delimiterIndices: delimiterIndices,
|
||||
signature: splitToWords(signature, BigInt(121), BigInt(17)),
|
||||
pubKey: splitToWords(pubKey, BigInt(121), BigInt(17)),
|
||||
secret: secret,
|
||||
photoEOI: photoEOI,
|
||||
};
|
||||
|
||||
return {
|
||||
inputs,
|
||||
nullifier,
|
||||
commitment,
|
||||
};
|
||||
}
|
||||
|
||||
export function prepareAadhaarDiscloseTestData(
|
||||
privateKeyPem: string,
|
||||
merkletree: LeanIMT,
|
||||
@@ -444,3 +289,163 @@ export function prepareAadhaarDiscloseTestData(
|
||||
commitment,
|
||||
};
|
||||
}
|
||||
|
||||
export async function prepareAadhaarRegisterData(qrData: string, secret: string, certs: string[]) {
|
||||
const sharedData = processQRDataSimple(qrData);
|
||||
const delimiterIndices: number[] = [];
|
||||
for (let i = 0; i < sharedData.qrDataPadded.length; i++) {
|
||||
if (sharedData.qrDataPadded[i] === 255) {
|
||||
delimiterIndices.push(i);
|
||||
}
|
||||
if (delimiterIndices.length === 18) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let photoEOI = 0;
|
||||
for (let i = delimiterIndices[17]; i < sharedData.qrDataPadded.length - 1; i++) {
|
||||
if (sharedData.qrDataPadded[i + 1] === 217 && sharedData.qrDataPadded[i] === 255) {
|
||||
photoEOI = i + 1;
|
||||
}
|
||||
}
|
||||
if (photoEOI === 0) {
|
||||
throw new Error('Photo EOI not found');
|
||||
}
|
||||
|
||||
const signatureBytes = sharedData.decodedData.slice(
|
||||
sharedData.decodedData.length - 256,
|
||||
sharedData.decodedData.length
|
||||
);
|
||||
const signature = BigInt('0x' + bufferToHex(Buffer.from(signatureBytes)).toString());
|
||||
|
||||
//do promise.all for all certs and pick the one that is valid
|
||||
const certificates = await Promise.all(
|
||||
certs.map(async (cert) => {
|
||||
const certificate = forge.pki.certificateFromPem(cert);
|
||||
const publicKey = certificate.publicKey as forge.pki.rsa.PublicKey;
|
||||
|
||||
try {
|
||||
const md = forge.md.sha256.create();
|
||||
md.update(forge.util.binary.raw.encode(sharedData.signedData));
|
||||
|
||||
const isValid = publicKey.verify(md.digest().getBytes(), signatureBytes);
|
||||
return isValid;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
//find the valid cert
|
||||
const validCert = certificates.indexOf(true);
|
||||
if (validCert === -1) {
|
||||
throw new Error('No valid certificate found');
|
||||
}
|
||||
const certPem = certs[validCert];
|
||||
const cert = forge.pki.certificateFromPem(certPem);
|
||||
const modulusHex = (cert.publicKey as forge.pki.rsa.PublicKey).n.toString(16);
|
||||
const pubKey = BigInt('0x' + modulusHex);
|
||||
|
||||
const nullifier = nullifierHash(sharedData.extractedFields);
|
||||
const packedCommitment = computePackedCommitment(sharedData.extractedFields);
|
||||
const commitment = computeCommitment(
|
||||
BigInt(secret),
|
||||
BigInt(sharedData.qrHash),
|
||||
nullifier,
|
||||
packedCommitment,
|
||||
BigInt(sharedData.photoHash)
|
||||
);
|
||||
|
||||
const inputs = {
|
||||
qrDataPadded: Uint8ArrayToCharArray(sharedData.qrDataPadded),
|
||||
qrDataPaddedLength: sharedData.qrDataPaddedLen,
|
||||
delimiterIndices: delimiterIndices,
|
||||
signature: splitToWords(signature, BigInt(121), BigInt(17)),
|
||||
pubKey: splitToWords(pubKey, BigInt(121), BigInt(17)),
|
||||
secret: secret,
|
||||
photoEOI: photoEOI,
|
||||
};
|
||||
|
||||
return {
|
||||
inputs,
|
||||
nullifier,
|
||||
commitment,
|
||||
};
|
||||
}
|
||||
|
||||
export function prepareAadhaarRegisterTestData(
|
||||
privKeyPem: string,
|
||||
pubkeyPem: string,
|
||||
secret: string,
|
||||
name?: string,
|
||||
dateOfBirth?: string,
|
||||
gender?: string,
|
||||
pincode?: string,
|
||||
state?: string,
|
||||
timestamp?: string
|
||||
) {
|
||||
const sharedData = processQRData(
|
||||
privKeyPem,
|
||||
name,
|
||||
dateOfBirth,
|
||||
gender,
|
||||
pincode,
|
||||
state,
|
||||
timestamp
|
||||
);
|
||||
|
||||
const delimiterIndices: number[] = [];
|
||||
for (let i = 0; i < sharedData.qrDataPadded.length; i++) {
|
||||
if (sharedData.qrDataPadded[i] === 255) {
|
||||
delimiterIndices.push(i);
|
||||
}
|
||||
if (delimiterIndices.length === 18) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let photoEOI = 0;
|
||||
for (let i = delimiterIndices[17]; i < sharedData.qrDataPadded.length - 1; i++) {
|
||||
if (sharedData.qrDataPadded[i + 1] === 217 && sharedData.qrDataPadded[i] === 255) {
|
||||
photoEOI = i + 1;
|
||||
}
|
||||
}
|
||||
if (photoEOI === 0) {
|
||||
throw new Error('Photo EOI not found');
|
||||
}
|
||||
|
||||
const signatureBytes = sharedData.decodedData.slice(
|
||||
sharedData.decodedData.length - 256,
|
||||
sharedData.decodedData.length
|
||||
);
|
||||
const signature = BigInt('0x' + bufferToHex(Buffer.from(signatureBytes)).toString());
|
||||
|
||||
const publicKey = forge.pki.publicKeyFromPem(pubkeyPem);
|
||||
|
||||
const modulusHex = publicKey.n.toString(16);
|
||||
const pubKey = BigInt('0x' + modulusHex);
|
||||
|
||||
const nullifier = nullifierHash(sharedData.extractedFields);
|
||||
const packedCommitment = computePackedCommitment(sharedData.extractedFields);
|
||||
const commitment = computeCommitment(
|
||||
BigInt(secret),
|
||||
BigInt(sharedData.qrHash),
|
||||
nullifier,
|
||||
packedCommitment,
|
||||
BigInt(sharedData.photoHash)
|
||||
);
|
||||
|
||||
const inputs = {
|
||||
qrDataPadded: Uint8ArrayToCharArray(sharedData.qrDataPadded),
|
||||
qrDataPaddedLength: sharedData.qrDataPaddedLen,
|
||||
delimiterIndices: delimiterIndices,
|
||||
signature: splitToWords(signature, BigInt(121), BigInt(17)),
|
||||
pubKey: splitToWords(pubKey, BigInt(121), BigInt(17)),
|
||||
secret: secret,
|
||||
photoEOI: photoEOI,
|
||||
};
|
||||
|
||||
return {
|
||||
inputs,
|
||||
nullifier,
|
||||
commitment,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,27 +1,40 @@
|
||||
import forge from 'node-forge';
|
||||
|
||||
import {
|
||||
convertBigIntToByteArray,
|
||||
decompressByteArray,
|
||||
returnFullId,
|
||||
extractPhoto,
|
||||
getEndIndex,
|
||||
getRandomBytes,
|
||||
IdFields,
|
||||
rawDataToCompressedQR,
|
||||
replaceBytesBetween,
|
||||
IdFields,
|
||||
extractPhoto,
|
||||
getRandomBytes,
|
||||
getEndIndex,
|
||||
returnFullId,
|
||||
} from '@anon-aadhaar/core';
|
||||
import forge from 'node-forge';
|
||||
|
||||
export function stringToAsciiArray(str: string) {
|
||||
return str.split('').map((char) => char.charCodeAt(0));
|
||||
export interface ExtractedQRData {
|
||||
name: string;
|
||||
yob: string;
|
||||
mob: string;
|
||||
dob: string;
|
||||
gender: string;
|
||||
pincode: string;
|
||||
state: string;
|
||||
aadhaarLast4Digits: string;
|
||||
phoneNoLast4Digits: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
// This is the official test data issued by the UIDAI
|
||||
// In this script we'll change the signed data to emulate the specs of the Aadhaar QR V2
|
||||
// and sign the data again with our own certificates.
|
||||
// data on https://uidai.gov.in/en/ecosystem/authentication-devices-documents/qr-code-reader.html
|
||||
// This data is copied from https://github.dev/anon-aadhaar/anon-aadhaar/blob/main/packages/circuits/src/helpers/extractor.circom
|
||||
export const testCustomData =
|
||||
'2374971804270526477833002468783965837992554564899874087591661303561346432389832047870524302186901344489362368642972767716416349990805756094923115719687656090691368051627957878187788907419297818953295185555346288172578594637886352753543271000481717080003254556962148594350559820352806251787713278744047402230989238559317351232114240089849934148895256488140236015024800731753594740948640957680138566468247224859669467819596919398964809164399637893729212452791889199675715949918925838319591794702333094022248132120531152523331442741730158840977243402215102904932650832502847295644794421419704633765033761284508863534321317394686768650111457751139630853448637215423705157211510636160227953566227527799608082928846103264491539001327407775670834868948113753614112563650255058316849200536533335903554984254814901522086937767458409075617572843449110393213525925388131214952874629655799772119820372255291052673056372346072235458198199995637720424196884145247220163810790179386390283738429482893152518286247124911446073389185062482901364671389605727763080854673156754021728522287806275420847159574631844674460263574901590412679291518508010087116598357407343835408554094619585212373168435612645646129147973594416508676872819776522537778717985070402222824965034768103900739105784663244748432502180989441389718131079445941981681118258324511923246198334046020123727749408128519721102477302359413240175102907322619462289965085963377744024233678337951462006962521823224880199210318367946130004264196899778609815012001799773327514133268825910089483612283510244566484854597156100473055413090101948456959122378865704840756793122956663218517626099291311352417342899623681483097817511136427210593032393600010728324905512596767095096153856032112835755780472808814199620390836980020899858288860556611564167406292139646289142056168261133256777093245980048335918156712295254776487472431445495668303900536289283098315798552328294391152828182614909451410115516297083658174657554955228963550255866282688308751041517464999930825273776417639569977754844191402927594739069037851707477839207593911886893016618794870530622356073909077832279869798641545167528509966656120623184120128052588408742941658045827255866966100249857968956536613250770326334844204927432961924987891433020671754710428050564671868464658436926086493709176888821257183419013229795869757265111599482263223604228286513011751601176504567030118257385997460972803240338899836840030438830725520798480181575861397469056536579877274090338750406459700907704031830137890544492015701251066934352867527112361743047684237105216779177819594030160887368311805926405114938744235859610328064947158936962470654636736991567663705830950312548447653861922078087824048793236971354828540758657075837209006713701763902429652486225300535997260665898927924843608750347193892239342462507130025307878412116604096773706728162016134101751551184021079984480254041743057914746472840768175369369852937574401874295943063507273467384747124843744395375119899278823903202010381949145094804675442110869084589592876721655764753871572233276245590041302887094585204427900634246823674277680009401177473636685542700515621164233992970974893989913447733956146698563285998205950467321954304';
|
||||
export const FIELD_POSITIONS = {
|
||||
REFERENCE_ID: 2,
|
||||
NAME: 3,
|
||||
DOB: 4,
|
||||
GENDER: 5,
|
||||
PINCODE: 11,
|
||||
STATE: 13,
|
||||
PHONE_NO: 17,
|
||||
PHOTO: 18,
|
||||
} as const;
|
||||
|
||||
// Will sign the data with the keys generated for test
|
||||
const signNewTestData = (newSignedData: Uint8Array, privKeyPem: string) => {
|
||||
@@ -45,65 +58,33 @@ const signNewTestData = (newSignedData: Uint8Array, privKeyPem: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const generateTestData = ({
|
||||
privKeyPem,
|
||||
data,
|
||||
dob,
|
||||
gender,
|
||||
pincode,
|
||||
state,
|
||||
photo,
|
||||
name,
|
||||
timestamp,
|
||||
}: {
|
||||
privKeyPem: string;
|
||||
data: string;
|
||||
dob?: string;
|
||||
gender?: string;
|
||||
pincode?: string;
|
||||
state?: string;
|
||||
photo?: boolean;
|
||||
name?: string;
|
||||
timestamp?: string;
|
||||
}) => {
|
||||
const qrDataBytes = convertBigIntToByteArray(BigInt(data));
|
||||
const decodedData = decompressByteArray(qrDataBytes);
|
||||
export function calculateAge(
|
||||
dob: string,
|
||||
mob: string,
|
||||
yob: string
|
||||
): { age: number; currentYear: number; currentMonth: number; currentDay: number } {
|
||||
const currentDate = new Date();
|
||||
const currentYear = currentDate.getFullYear();
|
||||
const currentMonth = currentDate.getMonth() + 1; // getMonth() returns 0-11
|
||||
const currentDay = currentDate.getDate();
|
||||
|
||||
// Turning test data V1 into V2
|
||||
// Adding the version specifier prefix,
|
||||
// the last 4 digits of phone number and timestamp to now
|
||||
const dataToSign = createCustomV2TestData({
|
||||
signedData: decodedData.slice(0, decodedData.length - 256),
|
||||
dob,
|
||||
pincode,
|
||||
gender,
|
||||
state,
|
||||
photo,
|
||||
name,
|
||||
timestamp,
|
||||
});
|
||||
const birthYear = parseInt(yob);
|
||||
const birthMonth = parseInt(mob);
|
||||
const birthDay = parseInt(dob);
|
||||
|
||||
// Signing the newly generated testData
|
||||
const signature = signNewTestData(dataToSign, privKeyPem);
|
||||
let age = currentYear - birthYear;
|
||||
|
||||
// Reconstructing the whole QR data
|
||||
const tempData = Buffer.concat([dataToSign, signature]);
|
||||
|
||||
// Compressing the data to have it in the same format as the QR code
|
||||
const newCompressedData = rawDataToCompressedQR(tempData);
|
||||
const newQrData = {
|
||||
testQRData: newCompressedData.toString(),
|
||||
...returnFullId(dataToSign),
|
||||
if (currentMonth < birthMonth || (currentMonth === birthMonth && currentDay < birthDay)) {
|
||||
age--;
|
||||
}
|
||||
return {
|
||||
age,
|
||||
currentYear,
|
||||
currentMonth,
|
||||
currentDay,
|
||||
};
|
||||
}
|
||||
|
||||
return newQrData;
|
||||
};
|
||||
|
||||
// This modify the test data to make it compliant with the secure Aadhaar QR V2 2022
|
||||
// - Adds the version specifier at the beginning 'V2'
|
||||
// - Mocks last 4 digits of phone number '1234' after VTC
|
||||
// - Refresh timestamp data to now
|
||||
// - Optionally it can take parameters to change the test data fields (dob, pinCode, gender, state)
|
||||
export const createCustomV2TestData = ({
|
||||
signedData,
|
||||
dob,
|
||||
@@ -238,99 +219,6 @@ export const createCustomV2TestData = ({
|
||||
return newData;
|
||||
};
|
||||
|
||||
export function calculateAge(
|
||||
dob: string,
|
||||
mob: string,
|
||||
yob: string
|
||||
): { age: number; currentYear: number; currentMonth: number; currentDay: number } {
|
||||
const currentDate = new Date();
|
||||
const currentYear = currentDate.getFullYear();
|
||||
const currentMonth = currentDate.getMonth() + 1; // getMonth() returns 0-11
|
||||
const currentDay = currentDate.getDate();
|
||||
|
||||
const birthYear = parseInt(yob);
|
||||
const birthMonth = parseInt(mob);
|
||||
const birthDay = parseInt(dob);
|
||||
|
||||
let age = currentYear - birthYear;
|
||||
|
||||
if (currentMonth < birthMonth || (currentMonth === birthMonth && currentDay < birthDay)) {
|
||||
age--;
|
||||
}
|
||||
return {
|
||||
age,
|
||||
currentYear,
|
||||
currentMonth,
|
||||
currentDay,
|
||||
};
|
||||
}
|
||||
|
||||
export function returnNewDateString(timestamp?: string): string {
|
||||
const newDate = timestamp ? new Date(+timestamp) : new Date();
|
||||
|
||||
// Convert the UTC date to IST by adding 5 hours and 30 minutes
|
||||
const offsetHours = 5;
|
||||
const offsetMinutes = 30;
|
||||
newDate.setUTCHours(newDate.getUTCHours() + offsetHours);
|
||||
newDate.setUTCMinutes(newDate.getUTCMinutes() + offsetMinutes);
|
||||
|
||||
return (
|
||||
newDate.getUTCFullYear().toString() +
|
||||
(newDate.getUTCMonth() + 1).toString().padStart(2, '0') +
|
||||
newDate.getUTCDate().toString().padStart(2, '0') +
|
||||
newDate.getUTCHours().toString().padStart(2, '0') +
|
||||
newDate.getUTCMinutes().toString().padStart(2, '0') +
|
||||
newDate.getUTCSeconds().toString().padStart(2, '0') +
|
||||
newDate.getUTCMilliseconds().toString().padStart(3, '0')
|
||||
);
|
||||
}
|
||||
export const FIELD_POSITIONS = {
|
||||
REFERENCE_ID: 2,
|
||||
NAME: 3,
|
||||
DOB: 4,
|
||||
GENDER: 5,
|
||||
PINCODE: 11,
|
||||
STATE: 13,
|
||||
PHONE_NO: 17,
|
||||
PHOTO: 18,
|
||||
} as const;
|
||||
|
||||
function asciiArrayToString(asciiArray: number[]): string {
|
||||
return asciiArray
|
||||
.filter((byte) => byte !== 0)
|
||||
.map((byte) => String.fromCharCode(byte))
|
||||
.join('');
|
||||
}
|
||||
|
||||
function extractFieldData(
|
||||
data: Uint8Array,
|
||||
delimiterIndices: number[],
|
||||
position: number
|
||||
): number[] {
|
||||
const startIndex = delimiterIndices[position - 1] + 1;
|
||||
const endIndex = delimiterIndices[position];
|
||||
|
||||
const fieldData: number[] = [];
|
||||
for (let i = startIndex; i < endIndex; i++) {
|
||||
fieldData.push(data[i]);
|
||||
}
|
||||
|
||||
return fieldData;
|
||||
}
|
||||
|
||||
export interface ExtractedQRData {
|
||||
name: string;
|
||||
yob: string;
|
||||
mob: string;
|
||||
dob: string;
|
||||
gender: string;
|
||||
pincode: string;
|
||||
state: string;
|
||||
aadhaarLast4Digits: string;
|
||||
phoneNoLast4Digits: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export function extractQRDataFields(qrData: string | Uint8Array): ExtractedQRData {
|
||||
let qrDataBytes: Uint8Array;
|
||||
|
||||
@@ -428,3 +316,117 @@ export function extractQRDataFields(qrData: string | Uint8Array): ExtractedQRDat
|
||||
timestamp,
|
||||
};
|
||||
}
|
||||
|
||||
export const generateTestData = ({
|
||||
privKeyPem,
|
||||
data,
|
||||
dob,
|
||||
gender,
|
||||
pincode,
|
||||
state,
|
||||
photo,
|
||||
name,
|
||||
timestamp,
|
||||
}: {
|
||||
privKeyPem: string;
|
||||
data: string;
|
||||
dob?: string;
|
||||
gender?: string;
|
||||
pincode?: string;
|
||||
state?: string;
|
||||
photo?: boolean;
|
||||
name?: string;
|
||||
timestamp?: string;
|
||||
}) => {
|
||||
const qrDataBytes = convertBigIntToByteArray(BigInt(data));
|
||||
const decodedData = decompressByteArray(qrDataBytes);
|
||||
|
||||
// Turning test data V1 into V2
|
||||
// Adding the version specifier prefix,
|
||||
// the last 4 digits of phone number and timestamp to now
|
||||
const dataToSign = createCustomV2TestData({
|
||||
signedData: decodedData.slice(0, decodedData.length - 256),
|
||||
dob,
|
||||
pincode,
|
||||
gender,
|
||||
state,
|
||||
photo,
|
||||
name,
|
||||
timestamp,
|
||||
});
|
||||
|
||||
// Signing the newly generated testData
|
||||
const signature = signNewTestData(dataToSign, privKeyPem);
|
||||
|
||||
// Reconstructing the whole QR data
|
||||
const tempData = Buffer.concat([dataToSign, signature]);
|
||||
|
||||
// Compressing the data to have it in the same format as the QR code
|
||||
const newCompressedData = rawDataToCompressedQR(tempData);
|
||||
const newQrData = {
|
||||
testQRData: newCompressedData.toString(),
|
||||
...returnFullId(dataToSign),
|
||||
};
|
||||
|
||||
return newQrData;
|
||||
};
|
||||
|
||||
export function returnNewDateString(timestamp?: string): string {
|
||||
const newDate = timestamp ? new Date(+timestamp) : new Date();
|
||||
|
||||
// Convert the UTC date to IST by adding 5 hours and 30 minutes
|
||||
const offsetHours = 5;
|
||||
const offsetMinutes = 30;
|
||||
newDate.setUTCHours(newDate.getUTCHours() + offsetHours);
|
||||
newDate.setUTCMinutes(newDate.getUTCMinutes() + offsetMinutes);
|
||||
|
||||
return (
|
||||
newDate.getUTCFullYear().toString() +
|
||||
(newDate.getUTCMonth() + 1).toString().padStart(2, '0') +
|
||||
newDate.getUTCDate().toString().padStart(2, '0') +
|
||||
newDate.getUTCHours().toString().padStart(2, '0') +
|
||||
newDate.getUTCMinutes().toString().padStart(2, '0') +
|
||||
newDate.getUTCSeconds().toString().padStart(2, '0') +
|
||||
newDate.getUTCMilliseconds().toString().padStart(3, '0')
|
||||
);
|
||||
}
|
||||
|
||||
function asciiArrayToString(asciiArray: number[]): string {
|
||||
return asciiArray
|
||||
.filter((byte) => byte !== 0)
|
||||
.map((byte) => String.fromCharCode(byte))
|
||||
.join('');
|
||||
}
|
||||
|
||||
function extractFieldData(
|
||||
data: Uint8Array,
|
||||
delimiterIndices: number[],
|
||||
position: number
|
||||
): number[] {
|
||||
const startIndex = delimiterIndices[position - 1] + 1;
|
||||
const endIndex = delimiterIndices[position];
|
||||
|
||||
const fieldData: number[] = [];
|
||||
for (let i = startIndex; i < endIndex; i++) {
|
||||
fieldData.push(data[i]);
|
||||
}
|
||||
|
||||
return fieldData;
|
||||
}
|
||||
|
||||
// This is the official test data issued by the UIDAI
|
||||
// In this script we'll change the signed data to emulate the specs of the Aadhaar QR V2
|
||||
// and sign the data again with our own certificates.
|
||||
// data on https://uidai.gov.in/en/ecosystem/authentication-devices-documents/qr-code-reader.html
|
||||
// This data is copied from https://github.dev/anon-aadhaar/anon-aadhaar/blob/main/packages/circuits/src/helpers/extractor.circom
|
||||
export function stringToAsciiArray(str: string) {
|
||||
return str.split('').map((char) => char.charCodeAt(0));
|
||||
}
|
||||
|
||||
// This modify the test data to make it compliant with the secure Aadhaar QR V2 2022
|
||||
// - Adds the version specifier at the beginning 'V2'
|
||||
// - Mocks last 4 digits of phone number '1234' after VTC
|
||||
// - Refresh timestamp data to now
|
||||
// - Optionally it can take parameters to change the test data fields (dob, pinCode, gender, state)
|
||||
export const testCustomData =
|
||||
'2374971804270526477833002468783965837992554564899874087591661303561346432389832047870524302186901344489362368642972767716416349990805756094923115719687656090691368051627957878187788907419297818953295185555346288172578594637886352753543271000481717080003254556962148594350559820352806251787713278744047402230989238559317351232114240089849934148895256488140236015024800731753594740948640957680138566468247224859669467819596919398964809164399637893729212452791889199675715949918925838319591794702333094022248132120531152523331442741730158840977243402215102904932650832502847295644794421419704633765033761284508863534321317394686768650111457751139630853448637215423705157211510636160227953566227527799608082928846103264491539001327407775670834868948113753614112563650255058316849200536533335903554984254814901522086937767458409075617572843449110393213525925388131214952874629655799772119820372255291052673056372346072235458198199995637720424196884145247220163810790179386390283738429482893152518286247124911446073389185062482901364671389605727763080854673156754021728522287806275420847159574631844674460263574901590412679291518508010087116598357407343835408554094619585212373168435612645646129147973594416508676872819776522537778717985070402222824965034768103900739105784663244748432502180989441389718131079445941981681118258324511923246198334046020123727749408128519721102477302359413240175102907322619462289965085963377744024233678337951462006962521823224880199210318367946130004264196899778609815012001799773327514133268825910089483612283510244566484854597156100473055413090101948456959122378865704840756793122956663218517626099291311352417342899623681483097817511136427210593032393600010728324905512596767095096153856032112835755780472808814199620390836980020899858288860556611564167406292139646289142056168261133256777093245980048335918156712295254776487472431445495668303900536289283098315798552328294391152828182614909451410115516297083658174657554955228963550255866282688308751041517464999930825273776417639569977754844191402927594739069037851707477839207593911886893016618794870530622356073909077832279869798641545167528509966656120623184120128052588408742941658045827255866966100249857968956536613250770326334844204927432961924987891433020671754710428050564671868464658436926086493709176888821257183419013229795869757265111599482263223604228286513011751601176504567030118257385997460972803240338899836840030438830725520798480181575861397469056536579877274090338750406459700907704031830137890544492015701251066934352867527112361743047684237105216779177819594030160887368311805926405114938744235859610328064947158936962470654636736991567663705830950312548447653861922078087824048793236971354828540758657075837209006713701763902429652486225300535997260665898927924843608750347193892239342462507130025307878412116604096773706728162016134101751551184021079984480254041743057914746472840768175369369852937574401874295943063507273467384747124843744395375119899278823903202010381949145094804675442110869084589592876721655764753871572233276245590041302887094585204427900634246823674277680009401177473636685542700515621164233992970974893989913447733956146698563285998205950467321954304';
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { MAX_BYTES_IN_FIELD } from '../constants/constants.js';
|
||||
|
||||
export function bigIntToChunkedBytes(
|
||||
num: BigInt | bigint,
|
||||
num: bigint | bigint,
|
||||
bytesPerChunk: number,
|
||||
numChunks: number
|
||||
) {
|
||||
const res: string[] = [];
|
||||
const bigintNum: bigint = typeof num == 'bigint' ? num : num.valueOf();
|
||||
const bigintNum: bigint = typeof num == 'bigint' ? num : BigInt(num);
|
||||
const msk = (1n << BigInt(bytesPerChunk)) - 1n;
|
||||
for (let i = 0; i < numChunks; ++i) {
|
||||
res.push(((bigintNum >> BigInt(i * bytesPerChunk)) & msk).toString());
|
||||
|
||||
45
common/src/utils/hash.test.ts
Normal file
45
common/src/utils/hash.test.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { calculateUserIdentifierHash } from './hash';
|
||||
|
||||
describe('calculateUserIdentifierHash', () => {
|
||||
it('should return a bigint', () => {
|
||||
const result = calculateUserIdentifierHash(
|
||||
1,
|
||||
'550e8400-e29b-41d4-a716-446655440000',
|
||||
'some data'
|
||||
);
|
||||
expect(typeof result).toBe('bigint');
|
||||
});
|
||||
|
||||
it('should return the same hash for identical inputs', () => {
|
||||
const destChainID = 42;
|
||||
const userID = 'abcdef12-3456-7890-abcd-ef1234567890';
|
||||
const userDefinedData = 'Test data';
|
||||
const hash1 = calculateUserIdentifierHash(destChainID, userID, userDefinedData);
|
||||
const hash2 = calculateUserIdentifierHash(destChainID, userID, userDefinedData);
|
||||
expect(hash1).toBe(hash2);
|
||||
expect(hash1).toMatchInlineSnapshot(`525133570835708563534412370019423387022853755228n`);
|
||||
});
|
||||
|
||||
it('should return different hash for different inputs', () => {
|
||||
const hash1 = calculateUserIdentifierHash(
|
||||
42,
|
||||
'abcdef12-3456-7890-abcd-ef1234567890',
|
||||
'Test data'
|
||||
);
|
||||
const hash2 = calculateUserIdentifierHash(
|
||||
42,
|
||||
'abcdef12-3456-7890-abcd-ef1234567890',
|
||||
'Different data'
|
||||
);
|
||||
expect(hash1).not.toBe(hash2);
|
||||
expect(hash1).toMatchInlineSnapshot(`525133570835708563534412370019423387022853755228n`);
|
||||
});
|
||||
it('should handle user ids starting with 0x', () => {
|
||||
const hash1 = calculateUserIdentifierHash(42, '0xabcdef1234567890', 'Test data');
|
||||
const hash2 = calculateUserIdentifierHash(42, 'abcdef1234567890', 'Test data');
|
||||
expect(hash1).toBe(hash2);
|
||||
expect(hash1).toMatchInlineSnapshot(`830654111289877969679298811043657652615780822337n`);
|
||||
});
|
||||
});
|
||||
@@ -29,7 +29,7 @@ export function calculateUserIdentifierHash(
|
||||
destChainID: number,
|
||||
userID: string,
|
||||
userDefinedData: string
|
||||
): BigInt {
|
||||
): bigint {
|
||||
const solidityPackedUserContextData = getSolidityPackedUserContextData(
|
||||
destChainID,
|
||||
userID,
|
||||
@@ -133,7 +133,8 @@ export function getSolidityPackedUserContextData(
|
||||
['bytes32', 'bytes32', 'bytes'],
|
||||
[
|
||||
ethers.zeroPadValue(ethers.toBeHex(destChainID), 32),
|
||||
ethers.zeroPadValue('0x' + userIdHex, 32),
|
||||
|
||||
ethers.zeroPadValue(userIdHex.startsWith('0x') ? userIdHex : '0x' + userIdHex, 32),
|
||||
ethers.toUtf8Bytes(userDefinedData),
|
||||
]
|
||||
);
|
||||
|
||||
@@ -2,14 +2,15 @@ import countries from 'i18n-iso-countries';
|
||||
// @ts-ignore
|
||||
import en from 'i18n-iso-countries/langs/en.json' with { type: 'json' };
|
||||
import {
|
||||
poseidon12,
|
||||
poseidon13,
|
||||
poseidon2,
|
||||
poseidon3,
|
||||
poseidon5,
|
||||
poseidon6,
|
||||
poseidon10,
|
||||
poseidon12,
|
||||
poseidon13,
|
||||
} from 'poseidon-lite';
|
||||
|
||||
import {
|
||||
CSCA_TREE_DEPTH,
|
||||
DSC_TREE_DEPTH,
|
||||
@@ -17,6 +18,7 @@ import {
|
||||
max_dsc_bytes,
|
||||
OFAC_TREE_LEVELS,
|
||||
} from '../constants/constants.js';
|
||||
import { packBytes } from './bytes.js';
|
||||
import type { CertificateData } from './certificate_parsing/dataStructure.js';
|
||||
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple.js';
|
||||
import { stringToAsciiBigIntArray } from './circuits/uuid.js';
|
||||
@@ -26,7 +28,6 @@ import {
|
||||
DscCertificateMetaData,
|
||||
parseDscCertificateData,
|
||||
} from './passports/passport_parsing/parseDscCertificateData.js';
|
||||
import { packBytes } from './bytes.js';
|
||||
|
||||
import { IMT } from '@openpassport/zk-kit-imt';
|
||||
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
|
||||
@@ -36,6 +37,52 @@ import { SMT } from '@openpassport/zk-kit-smt';
|
||||
// SideEffect here
|
||||
countries.registerLocale(en);
|
||||
|
||||
//---------------------------
|
||||
// AADHAAR
|
||||
//---------------------------
|
||||
export function buildAadhaarSMT(field: any[], treetype: string): [number, number, SMT] {
|
||||
let count = 0;
|
||||
let startTime = performance.now();
|
||||
|
||||
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];
|
||||
|
||||
if (i !== 0) {
|
||||
console.log('Processing', treetype, 'number', i, 'out of', field.length);
|
||||
}
|
||||
|
||||
let leaf = BigInt(0);
|
||||
let reverse_leaf = BigInt(0);
|
||||
if (treetype == 'name_and_dob') {
|
||||
leaf = processNameAndDobAadhaar(entry, i);
|
||||
reverse_leaf = processNameAndDobAadhaar(entry, i, true);
|
||||
} else if (treetype == 'name_and_yob') {
|
||||
leaf = processNameAndYobAadhaar(entry, i);
|
||||
reverse_leaf = processNameAndYobAadhaar(entry, i, true);
|
||||
}
|
||||
|
||||
if (leaf == BigInt(0) || tree.createProof(leaf).membership) {
|
||||
console.log('This entry already exists in the tree, skipping...');
|
||||
continue;
|
||||
}
|
||||
|
||||
count += 1;
|
||||
tree.add(leaf, BigInt(1));
|
||||
if (reverse_leaf == BigInt(0) || tree.createProof(reverse_leaf).membership) {
|
||||
console.log('This entry already exists in the tree, skipping...');
|
||||
continue;
|
||||
}
|
||||
tree.add(reverse_leaf, BigInt(1));
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return [count, performance.now() - startTime, tree];
|
||||
}
|
||||
|
||||
// SMT trees for 3 levels of matching :
|
||||
// 1. Passport Number and Nationality tree : level 3 (Absolute Match)
|
||||
// 2. Name and date of birth combo tree : level 2 (High Probability Match)
|
||||
@@ -266,12 +313,6 @@ export function getLeafCscaTree(csca_parsed: CertificateData): string {
|
||||
return getLeaf(csca_parsed, 'csca');
|
||||
}
|
||||
|
||||
export function getLeafDscTree(dsc_parsed: CertificateData, csca_parsed: CertificateData): string {
|
||||
const dscLeaf = getLeaf(dsc_parsed, 'dsc');
|
||||
const cscaLeaf = getLeaf(csca_parsed, 'csca');
|
||||
return poseidon2([dscLeaf, cscaLeaf]).toString();
|
||||
}
|
||||
|
||||
function processPassportNoAndNationality(
|
||||
passno: string,
|
||||
nationality: string,
|
||||
@@ -480,6 +521,12 @@ function processCountry(country1: string, country2: string, i: number) {
|
||||
return leaf;
|
||||
}
|
||||
|
||||
export function getLeafDscTree(dsc_parsed: CertificateData, csca_parsed: CertificateData): string {
|
||||
const dscLeaf = getLeaf(dsc_parsed, 'dsc');
|
||||
const cscaLeaf = getLeaf(csca_parsed, 'csca');
|
||||
return poseidon2([dscLeaf, cscaLeaf]).toString();
|
||||
}
|
||||
|
||||
export function getLeafDscTreeFromDscCertificateMetadata(
|
||||
dscParsed: CertificateData,
|
||||
dscMetaData: DscCertificateMetaData
|
||||
@@ -501,6 +548,18 @@ export function getNameDobLeaf(
|
||||
return generateSmallKey(poseidon2([getDobLeaf(dobMrz), getNameLeaf(nameMrz)]));
|
||||
}
|
||||
|
||||
export const getNameDobLeafAadhaar = (name: string, year: string, month: string, day: string) => {
|
||||
const paddedName = name
|
||||
.toUpperCase()
|
||||
.padEnd(62, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0));
|
||||
const namePacked = packBytes(paddedName);
|
||||
return generateSmallKey(
|
||||
poseidon5([namePacked[0], namePacked[1], BigInt(year), BigInt(month), BigInt(day)])
|
||||
);
|
||||
};
|
||||
|
||||
export function getNameLeaf(nameMrz: (bigint | number)[], i?: number): bigint {
|
||||
const middleChunks: bigint[] = [];
|
||||
const chunks: (number | bigint)[][] = [];
|
||||
@@ -544,76 +603,6 @@ export function getNameYobLeaf(
|
||||
return generateSmallKey(poseidon2([getYearLeaf(yobMrz), getNameLeaf(nameMrz)]));
|
||||
}
|
||||
|
||||
export function getPassportNumberAndNationalityLeaf(
|
||||
passport: (bigint | number)[],
|
||||
nationality: (bigint | number)[],
|
||||
i?: number
|
||||
): bigint {
|
||||
if (passport.length !== 9) {
|
||||
console.log('parsed passport length is not 9:', i, passport);
|
||||
return;
|
||||
}
|
||||
if (nationality.length !== 3) {
|
||||
console.log('parsed nationality length is not 3:', i, nationality);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const fullHash = poseidon12(passport.concat(nationality));
|
||||
return generateSmallKey(fullHash);
|
||||
} catch (err) {
|
||||
console.log('err : passport', err, i, passport);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------
|
||||
|
||||
// AADHAAR
|
||||
|
||||
//---------------------------
|
||||
|
||||
export function buildAadhaarSMT(field: any[], treetype: string): [number, number, SMT] {
|
||||
let count = 0;
|
||||
let startTime = performance.now();
|
||||
|
||||
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];
|
||||
|
||||
if (i !== 0) {
|
||||
console.log('Processing', treetype, 'number', i, 'out of', field.length);
|
||||
}
|
||||
|
||||
let leaf = BigInt(0);
|
||||
let reverse_leaf = BigInt(0);
|
||||
if (treetype == 'name_and_dob') {
|
||||
leaf = processNameAndDobAadhaar(entry, i);
|
||||
reverse_leaf = processNameAndDobAadhaar(entry, i, true);
|
||||
} else if (treetype == 'name_and_yob') {
|
||||
leaf = processNameAndYobAadhaar(entry, i);
|
||||
reverse_leaf = processNameAndYobAadhaar(entry, i, true);
|
||||
}
|
||||
|
||||
if (leaf == BigInt(0) || tree.createProof(leaf).membership) {
|
||||
console.log('This entry already exists in the tree, skipping...');
|
||||
continue;
|
||||
}
|
||||
|
||||
count += 1;
|
||||
tree.add(leaf, BigInt(1));
|
||||
if (reverse_leaf == BigInt(0) || tree.createProof(reverse_leaf).membership) {
|
||||
console.log('This entry already exists in the tree, skipping...');
|
||||
continue;
|
||||
}
|
||||
tree.add(reverse_leaf, BigInt(1));
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return [count, performance.now() - startTime, tree];
|
||||
}
|
||||
|
||||
const processNameAndDobAadhaar = (entry: any, i: number, reverse: boolean = false): bigint => {
|
||||
let firstName = entry.First_Name;
|
||||
let lastName = entry.Last_Name;
|
||||
@@ -684,18 +673,6 @@ const processDobAadhaar = (year: string, month: string, day: string): bigint[] =
|
||||
return [year, month, day].map(BigInt);
|
||||
};
|
||||
|
||||
export const getNameDobLeafAadhaar = (name: string, year: string, month: string, day: string) => {
|
||||
const paddedName = name
|
||||
.toUpperCase()
|
||||
.padEnd(62, '\0')
|
||||
.split('')
|
||||
.map((char) => char.charCodeAt(0));
|
||||
const namePacked = packBytes(paddedName);
|
||||
return generateSmallKey(
|
||||
poseidon5([namePacked[0], namePacked[1], BigInt(year), BigInt(month), BigInt(day)])
|
||||
);
|
||||
};
|
||||
|
||||
export const getNameYobLeafAahaar = (name: string, year: string) => {
|
||||
const paddedName = name
|
||||
.toUpperCase()
|
||||
@@ -706,3 +683,24 @@ export const getNameYobLeafAahaar = (name: string, year: string) => {
|
||||
|
||||
return generateSmallKey(poseidon3([namePacked[0], namePacked[1], BigInt(year)]));
|
||||
};
|
||||
|
||||
export function getPassportNumberAndNationalityLeaf(
|
||||
passport: (bigint | number)[],
|
||||
nationality: (bigint | number)[],
|
||||
i?: number
|
||||
): bigint {
|
||||
if (passport.length !== 9) {
|
||||
console.log('parsed passport length is not 9:', i, passport);
|
||||
return;
|
||||
}
|
||||
if (nationality.length !== 3) {
|
||||
console.log('parsed nationality length is not 3:', i, nationality);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const fullHash = poseidon12(passport.concat(nationality));
|
||||
return generateSmallKey(fullHash);
|
||||
} catch (err) {
|
||||
console.log('err : passport', err, i, passport);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user