Skip to content

Commit

Permalink
add prettierrc to sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
remicolin committed Aug 27, 2024
1 parent 66f0858 commit 5fc4348
Show file tree
Hide file tree
Showing 13 changed files with 1,487 additions and 923 deletions.
18 changes: 18 additions & 0 deletions sdk/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always",
"proseWrap": "preserve",
"htmlWhitespaceSensitivity": "css",
"endOfLine": "lf",
"embeddedLanguageFormatting": "auto",
"singleAttributePerLine": false
}
28 changes: 16 additions & 12 deletions sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,43 @@ yarn add @openpassport/sdk

To use the `OpenPassport1StepVerifier`, import and initialize it as follows:


```typescript
import { OpenPassport1StepVerifier } from '@openpassport/sdk';
const verifier = new OpenPassport1StepVerifier({
scope: "yourScope",
requirements: [["older_than", "18"], ["nationality", "France"]]
scope: 'yourScope',
requirements: [
['older_than', '18'],
['nationality', 'France'],
],
});
```

### parameters for `OpenPassport1StepVerifier`

| Parameter | Optional | Description |
|---------------|----------|-------------|
| `scope` | No | The scope of your application, is unique for each application. |
| `attestationId` | Yes | The ID of the attestation, defaults to `PASSPORT_ATTESTATION_ID`. |
| `requirements` | Yes | An array of requirements, each an array with an attribute and its expected value. |
| `rpcUrl` | Yes | The RPC URL to connect to the blockchain, defaults to `DEFAULT_RPC_URL`. |
| Parameter | Optional | Description |
| --------------- | -------- | --------------------------------------------------------------------------------- |
| `scope` | No | The scope of your application, is unique for each application. |
| `attestationId` | Yes | The ID of the attestation, defaults to `PASSPORT_ATTESTATION_ID`. |
| `requirements` | Yes | An array of requirements, each an array with an attribute and its expected value. |
| `rpcUrl` | Yes | The RPC URL to connect to the blockchain, defaults to `DEFAULT_RPC_URL`. |

Finally, verify the proof:
The function fired from the OpenPassport app will send a `OpenPassportWeb2Inputs` object.

```typescript

const result = await verifier.verify(openPassportWeb2Inputs); // OpenPassportWeb2Inputs : OpenPassportWeb2Inputs
```
## 2 Steps flow

## 2 Steps flow

### 🚧 Work in progress 🚧

# Development

```bash
yarn install-sdk
```

## Tests

To run the tests, you need to download the circuits and the zkey files from the AWS s3 bucket.
Expand All @@ -54,7 +58,7 @@ yarn download-circuits
```

Then run the tests with the following command:

```bash
yarn test
```

9 changes: 6 additions & 3 deletions sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,21 @@
"mocha": "^10.3.0",
"ts-mocha": "^10.0.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
"typescript": "^5.4.5",
"prettier": "^3.3.3"
},
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build",
"test": "yarn ts-mocha -p ./tsconfig.json tests/openPassport1Step.test.ts --exit",
"install-sdk": "cd ../common && yarn && cd ../sdk && yarn",
"download-circuits": "cd ../circuits && ./scripts/download_circuits_from_aws.sh && cd ../sdk"
"download-circuits": "cd ../circuits && ./scripts/download_circuits_from_aws.sh && cd ../sdk",
"format": "prettier --write .",
"lint": "prettier --check ."
},
"files": [
"dist",
"common",
"circuits/**/*.json"
]
}
}
244 changes: 131 additions & 113 deletions sdk/src/OpenPassport1Step.ts
Original file line number Diff line number Diff line change
@@ -1,140 +1,158 @@
import { groth16 } from 'snarkjs';
import { attributeToPosition, countryCodes, DEFAULT_RPC_URL, PASSPORT_ATTESTATION_ID } from '../../common/src/constants/constants';
import {
attributeToPosition,
countryCodes,
DEFAULT_RPC_URL,
PASSPORT_ATTESTATION_ID,
} from '../../common/src/constants/constants';
import { getCurrentDateFormatted, verifyDSCValidity } from '../utils/utils';
import { unpackReveal } from '../../common/src/utils/revealBitmap';
import { OpenPassportVerifierReport } from './OpenPassportVerifierReport';
import { vkey_prove_rsa_65537_sha1, vkey_prove_rsa_65537_sha256, vkey_prove_rsapss_65537_sha256 } from '../../common/src/constants/vkey';
import forge from 'node-forge'
import {
vkey_prove_rsa_65537_sha1,
vkey_prove_rsa_65537_sha256,
vkey_prove_rsapss_65537_sha256,
} from '../../common/src/constants/vkey';
import forge from 'node-forge';
import { splitToWords } from '../../common/src/utils/utils';
import { getSignatureAlgorithm } from '../../common/src/utils/handleCertificate';

export class OpenPassport1StepVerifier {
scope: string;
attestationId: string;
requirements: string[][];
rpcUrl: string;
report: OpenPassportVerifierReport;
dev_mode: boolean;

constructor(options: {
scope: string;
attestationId: string;
requirements: string[][];
rpcUrl: string;
report: OpenPassportVerifierReport;
dev_mode: boolean;

constructor(options: { scope: string, attestationId?: string, requirements?: string[][], rpcUrl?: string, dev_mode?: boolean }) {
this.scope = options.scope;
this.attestationId = options.attestationId || PASSPORT_ATTESTATION_ID;
this.requirements = options.requirements || [];
this.rpcUrl = options.rpcUrl || DEFAULT_RPC_URL;
this.report = new OpenPassportVerifierReport();
this.dev_mode = options.dev_mode || false;
attestationId?: string;
requirements?: string[][];
rpcUrl?: string;
dev_mode?: boolean;
}) {
this.scope = options.scope;
this.attestationId = options.attestationId || PASSPORT_ATTESTATION_ID;
this.requirements = options.requirements || [];
this.rpcUrl = options.rpcUrl || DEFAULT_RPC_URL;
this.report = new OpenPassportVerifierReport();
this.dev_mode = options.dev_mode || false;
}

getVkey(signatureAlgorithm: string, hashFunction: string) {
switch (signatureAlgorithm + ' ' + hashFunction) {
case 'rsa sha256':
return vkey_prove_rsa_65537_sha256;
case 'rsa sha1':
return vkey_prove_rsa_65537_sha1;
case 'rsapss sha256':
return vkey_prove_rsapss_65537_sha256;
default:
throw new Error('Invalid signature algorithm or hash function');
}

getVkey(signatureAlgorithm: string, hashFunction: string) {
switch (signatureAlgorithm + " " + hashFunction) {
case "rsa sha256":
return vkey_prove_rsa_65537_sha256;
case "rsa sha1":
return vkey_prove_rsa_65537_sha1;
case "rsapss sha256":
return vkey_prove_rsapss_65537_sha256;
default:
throw new Error("Invalid signature algorithm or hash function");
}
}

async verify(
openPassport1StepInputs: OpenPassport1StepInputs
): Promise<OpenPassportVerifierReport> {
const { signatureAlgorithm, hashFunction } = getSignatureAlgorithm(openPassport1StepInputs.dsc);
console.log('signatureAlgorithm', signatureAlgorithm);
console.log('hashFunction', hashFunction);
const vkey = this.getVkey(signatureAlgorithm, hashFunction);
const parsedPublicSignals = parsePublicSignals1Step(openPassport1StepInputs.publicSignals);
//1. Verify the scope
if (parsedPublicSignals.scope !== this.scope) {
this.report.exposeAttribute('scope', parsedPublicSignals.scope, this.scope);
}

async verify(openPassport1StepInputs: OpenPassport1StepInputs): Promise<OpenPassportVerifierReport> {
const { signatureAlgorithm, hashFunction } = getSignatureAlgorithm(openPassport1StepInputs.dsc);
console.log("signatureAlgorithm", signatureAlgorithm);
console.log("hashFunction", hashFunction);
const vkey = this.getVkey(signatureAlgorithm, hashFunction);
const parsedPublicSignals = parsePublicSignals1Step(openPassport1StepInputs.publicSignals);
//1. Verify the scope
if (parsedPublicSignals.scope !== this.scope) {
this.report.exposeAttribute('scope', parsedPublicSignals.scope, this.scope);
}
console.log('\x1b[32m%s\x1b[0m', `- scope verified`);

//4. Verify the current_date
if (parsedPublicSignals.current_date.toString() !== getCurrentDateFormatted().toString()) {
this.report.exposeAttribute('current_date', parsedPublicSignals.current_date, getCurrentDateFormatted());
console.log('\x1b[32m%s\x1b[0m', `- scope verified`);

//4. Verify the current_date
if (parsedPublicSignals.current_date.toString() !== getCurrentDateFormatted().toString()) {
this.report.exposeAttribute(
'current_date',
parsedPublicSignals.current_date,
getCurrentDateFormatted()
);
}
console.log('\x1b[32m%s\x1b[0m', `- current_date verified`);

//5. Verify requirements
const unpackedReveal = unpackReveal(parsedPublicSignals.revealedData_packed);
for (const requirement of this.requirements) {
const attribute = requirement[0];
const value = requirement[1];
const position = attributeToPosition[attribute];
let attributeValue = '';
for (let i = position[0]; i <= position[1]; i++) {
attributeValue += unpackedReveal[i];
}
if (requirement[0] === 'nationality' || requirement[0] === 'issuing_state') {
if (!countryCodes[attributeValue] || countryCodes[attributeValue] !== value) {
this.report.exposeAttribute(attribute as keyof OpenPassportVerifierReport);
}
console.log('\x1b[32m%s\x1b[0m', `- current_date verified`);

//5. Verify requirements
const unpackedReveal = unpackReveal(parsedPublicSignals.revealedData_packed);
for (const requirement of this.requirements) {
const attribute = requirement[0];
const value = requirement[1];
const position = attributeToPosition[attribute];
let attributeValue = '';
for (let i = position[0]; i <= position[1]; i++) {
attributeValue += unpackedReveal[i];
}
if (requirement[0] === "nationality" || requirement[0] === "issuing_state") {
if (!countryCodes[attributeValue] || countryCodes[attributeValue] !== value) {
this.report.exposeAttribute(attribute as keyof OpenPassportVerifierReport);
}
}
else {
if (attributeValue !== value) {
this.report.exposeAttribute(attribute as keyof OpenPassportVerifierReport);
}
}
console.log('\x1b[32m%s\x1b[0m', `- requirement ${requirement[0]} verified`);

} else {
if (attributeValue !== value) {
this.report.exposeAttribute(attribute as keyof OpenPassportVerifierReport);
}
}
console.log('\x1b[32m%s\x1b[0m', `- requirement ${requirement[0]} verified`);
}

//6. Verify the proof
//6. Verify the proof

const verified_prove = await groth16.verify(
vkey,
openPassport1StepInputs.publicSignals,
openPassport1StepInputs.proof as any
)
if (!verified_prove) {
this.report.exposeAttribute('proof');
}
console.log('\x1b[32m%s\x1b[0m', `- proof verified`);
const verified_prove = await groth16.verify(
vkey,
openPassport1StepInputs.publicSignals,
openPassport1StepInputs.proof as any
);
if (!verified_prove) {
this.report.exposeAttribute('proof');
}
console.log('\x1b[32m%s\x1b[0m', `- proof verified`);

this.report.nullifier = parsedPublicSignals.nullifier;
this.report.user_identifier = parsedPublicSignals.user_identifier;
this.report.nullifier = parsedPublicSignals.nullifier;
this.report.user_identifier = parsedPublicSignals.user_identifier;

//7 Verify the dsc
const dscCertificate = forge.pki.certificateFromPem(openPassport1StepInputs.dsc);
const verified_certificate = verifyDSCValidity(dscCertificate, this.dev_mode);
console.log("certificate verified:" + verified_certificate);
//7 Verify the dsc
const dscCertificate = forge.pki.certificateFromPem(openPassport1StepInputs.dsc);
const verified_certificate = verifyDSCValidity(dscCertificate, this.dev_mode);
console.log('certificate verified:' + verified_certificate);

// @ts-ignore
const dsc_modulus = BigInt(dscCertificate.publicKey.n);
const dsc_modulus_words = splitToWords(dsc_modulus, BigInt(64), BigInt(32));
const modulus_from_proof = parsedPublicSignals.pubKey;
// @ts-ignore
const dsc_modulus = BigInt(dscCertificate.publicKey.n);
const dsc_modulus_words = splitToWords(dsc_modulus, BigInt(64), BigInt(32));
const modulus_from_proof = parsedPublicSignals.pubKey;

const areArraysEqual = (arr1: string[], arr2: string[]) =>
arr1.length === arr2.length &&
arr1.every((value, index) => value === arr2[index]);
const areArraysEqual = (arr1: string[], arr2: string[]) =>
arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]);

const verified_modulus = areArraysEqual(dsc_modulus_words, modulus_from_proof);
console.log("modulus verified:" + verified_modulus);
return this.report;
}
const verified_modulus = areArraysEqual(dsc_modulus_words, modulus_from_proof);
console.log('modulus verified:' + verified_modulus);
return this.report;
}
}

export class OpenPassport1StepInputs {
publicSignals: string[];
proof: string[];
dsc: string;

constructor(publicSignals: string[], proof: string[], dsc: string) {
this.publicSignals = publicSignals;
this.proof = proof;
this.dsc = dsc;
}
publicSignals: string[];
proof: string[];
dsc: string;

constructor(publicSignals: string[], proof: string[], dsc: string) {
this.publicSignals = publicSignals;
this.proof = proof;
this.dsc = dsc;
}
}

export function parsePublicSignals1Step(publicSignals) {
return {
signature_algorithm: publicSignals[0],
revealedData_packed: [publicSignals[1], publicSignals[2], publicSignals[3]],
nullifier: publicSignals[4],
pubKey: publicSignals.slice(5, 37),
scope: publicSignals[37],
current_date: publicSignals.slice(38, 44),
user_identifier: publicSignals[44],
}
return {
signature_algorithm: publicSignals[0],
revealedData_packed: [publicSignals[1], publicSignals[2], publicSignals[3]],
nullifier: publicSignals[4],
pubKey: publicSignals.slice(5, 37),
scope: publicSignals[37],
current_date: publicSignals.slice(38, 44),
user_identifier: publicSignals[44],
};
}
Loading

0 comments on commit 5fc4348

Please sign in to comment.