Skip to content

Commit

Permalink
chore(add test artifacts & fix Rule bug)
Browse files Browse the repository at this point in the history
  • Loading branch information
teddyjfpender committed Aug 16, 2023
1 parent cd393e4 commit fcc6222
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 5 deletions.
3 changes: 3 additions & 0 deletions apps/docs/pages/why.mdx
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
# Why Herald ?


While existing libraries also replicate the general SSI model, Herald can generate proofs that can be used as one of several arguments to other `ZkProgram`s or smart contracts; this is were the powers of recursive proofs come alive. This is a critical feature to reduce the amount of interaction necessary with smart contracts and off-chain `ZkProgram`s that are identity aware.
2 changes: 1 addition & 1 deletion packages/credentials/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('Credential CLI', () => {

it('should create a new credential', async () => {
// Execute the CLI command
const result = await execa('pnpm', ['run', 'cli', 'create', '--claims', JSON.stringify(claims), '--issuerPrvKey', issuerPrvKeyBase58, '--save', './artifacts']);
const result = await execa('pnpm', ['run', 'cli', 'create', '--claims', JSON.stringify(claims), '--issuerPrvKey', issuerPrvKeyBase58, '--save', './test/test_artifacts']);

// Assert that the command executed successfully (non-zero exit code indicates failure)
expect(result.exitCode).toBe(0);
Expand Down
10 changes: 8 additions & 2 deletions packages/credentials/test/credentials.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,15 @@ describe('Credential', () => {
const issuerPubKey = issuerPrvKey.toPublicKey();
const subjectPubKey = subjectPrvKey.toPublicKey();
const challenge: PublicInputArgs = {issuerPubKey, subjectPubKey, provingRule: rule};

const zkPrgDetails = ZkProgramsDetails["AttestSingleCredentialProperty"];
if (!zkPrgDetails) {
throw new Error("ZkProgram not found");
}

const proofResponse = await credential.prove("age", challenge, subjectPrvKey, "AttestSingleCredentialProperty");
console.log("attestationProof Verification: ", await verify(proofResponse.toJSON(), ZkProgramsDetails["AttestSingleCredentialProperty"].verificationKey));
expect(verify(proofResponse.toJSON(), ZkProgramsDetails["AttestSingleCredentialProperty"].verificationKey)).toBeTruthy();
console.log("attestationProof Verification: ", await verify(proofResponse.toJSON(), zkPrgDetails.verificationKey));
//fs.writeFileSync(path.join('./test/test_proofs', 'attestationProof.json'), JSON.stringify(attestationProof, null, 2));
expect(verify(proofResponse.toJSON(), zkPrgDetails.verificationKey)).toBeTruthy();
});
});
100 changes: 100 additions & 0 deletions packages/credentials/test/credentialsKYC.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { PrivateKey, verify } from "snarkyjs";
import { ClaimType, Rule } from "@herald-sdk/data-model";
import { Credential } from "../src";
import { describe, it } from '@jest/globals';
import { PublicInputArgs, ZkProgramsDetails } from "@herald-sdk/provable-programs";
import fs from 'fs';
import path from 'path';

describe('Credential', () => {
it('can construct a credential', () => {
const subjectPrvKey = PrivateKey.random();
const issuerPrvKey = PrivateKey.random();
const claims: {[key: string]: ClaimType} = {
over18: "true",
kyc: "passed",
subject: subjectPrvKey.toPublicKey()
};

const credential = Credential.create(claims, issuerPrvKey);
expect(credential).toBeTruthy();
});

it('can validate the signature', () => {
const subjectPrvKey = PrivateKey.random();
const issuerPrvKey = PrivateKey.random();
const claims: {[key: string]: ClaimType} = {
over18: "true",
kyc: "passed",
subject: subjectPrvKey.toPublicKey()
};

const credential = Credential.create(claims, issuerPrvKey);
const isValid = credential.verify(issuerPrvKey.toPublicKey(), subjectPrvKey.toPublicKey());
expect(isValid).toBe(true);
});

it('does not validate the signature with wrong public key', () => {
const subjectPrvKey = PrivateKey.random();
const issuerPrvKey = PrivateKey.random();
const wrongIssuerPubKey = PrivateKey.random().toPublicKey();
const claims: {[key: string]: ClaimType} = {
over18: "true",
kyc: "passed",
subject: subjectPrvKey.toPublicKey()
};

const credential = Credential.create(claims, issuerPrvKey);
const isValid = credential.verify(wrongIssuerPubKey, subjectPrvKey.toPublicKey());
expect(isValid).toBe(false);
});

it('verify claim is made about the correct subject', () => {
const subjectPrvKey = PrivateKey.random();
const issuerPrvKey = PrivateKey.random();
const claims: {[key: string]: ClaimType} = {
over18: "true",
kyc: "passed",
subject: subjectPrvKey.toPublicKey()
};

const credential = Credential.create(claims, issuerPrvKey);
const isValid = credential.verify(issuerPrvKey.toPublicKey(), subjectPrvKey.toPublicKey());
expect(isValid).toBe(true);
});
it('can prove a claim', async () => {
/**
* Issuer must make a claim about a subject AND prove the claim
*/
const subjectPrvKey = PrivateKey.random();
const issuerPrvKey = PrivateKey.random();
const issuerPubKey = issuerPrvKey.toPublicKey();
const subjectPubKey = subjectPrvKey.toPublicKey();
const claims: {[key: string]: ClaimType} = {
over18: "true",
kyc: "passed",
subject: subjectPubKey,
issuerPubKey: issuerPubKey
};
// issue credentials to subject
const credential = Credential.create(claims, issuerPrvKey);
// create rule to prove
const property = "kyc";
const operation = "eq";
const value = "passed";
const rule = new Rule(property, operation, value);
console.log("rule: ", rule);
// create challenge - this challenge must be signed by the issuer
const challenge: PublicInputArgs = {issuerPubKey: issuerPubKey, subjectPubKey: issuerPubKey, provingRule: rule};

const zkPrgDetails = ZkProgramsDetails["AttestSingleCredentialProperty"];
if (!zkPrgDetails) {
throw new Error("ZkProgram not found");
}
// issuer must sign the proof themselves
const proofResponse = await credential.prove("age", challenge, issuerPrvKey, "AttestSingleCredentialProperty");
console.log("attestationProof Verification: ", await verify(proofResponse.toJSON(), zkPrgDetails.verificationKey));
fs.writeFileSync(path.join('./test/test_proofs', 'attestationProof.json'), JSON.stringify(proofResponse, null, 2));
expect(verify(proofResponse.toJSON(), zkPrgDetails.verificationKey)).toBeTruthy();
});
});
20 changes: 20 additions & 0 deletions packages/credentials/test/test_artifacts/credential.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"id": "http://example.edu/credentials/3732",
"type": [
"VerifiableCredential",
"UniversityDegreeCredential"
],
"issuer": "https://example.edu/issuers/565049",
"issuanceDate": "2023-08-15T12:08:34.310Z",
"credentialSubject": {
"id": "did:mina:B62qoE8VJc7y9d2T97tD42qtrkxcEMQ2zjQVhnMaVJTixFXcwHpjWne",
"degree": {
"type": "BachelorDegree",
"name": "Bachelor of Science and Arts"
}
}
}
12 changes: 12 additions & 0 deletions packages/credentials/test/test_artifacts/flatCredentials.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"@context.0": "https://www.w3.org/2018/credentials/v1",
"@context.1": "https://www.w3.org/2018/credentials/examples/v1",
"id": "http://example.edu/credentials/3732",
"type.0": "VerifiableCredential",
"type.1": "UniversityDegreeCredential",
"issuer": "https://example.edu/issuers/565049",
"issuanceDate": "2023-08-15T12:08:34.310Z",
"credentialSubject.id": "did:mina:B62qoE8VJc7y9d2T97tD42qtrkxcEMQ2zjQVhnMaVJTixFXcwHpjWne",
"credentialSubject.degree.type": "BachelorDegree",
"credentialSubject.degree.name": "Bachelor of Science and Arts"
}
7 changes: 7 additions & 0 deletions packages/credentials/test/test_artifacts/signedClaim.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"claimRoot": "27788048405497487489781779262110636931710622819733473477391203108519940503595",
"signatureIssuer": {
"r": "13191013697533051278907946322593179062589185418402494564530949561445294222232",
"s": "4380502652403126031342073393707984995858675269401757059447354475365191845001"
}
}
14 changes: 14 additions & 0 deletions packages/credentials/test/test_proofs/attestationProof.json

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions packages/data-model/src/dataModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ export class Rule extends Struct({
operation: Field, // lt, lte, eq, gte, gt
value: Field, // the value to compare the field to
}) {
constructor(field: string, operation: string, value: number) {
super({field: stringToField(field), operation: stringToField(operation), value: numberToField(value)});
constructor(field: string, operation: string, value: number | string | Field) {
if (typeof value === "string") {
value = stringToField(value);
super({field: stringToField(field), operation: stringToField(operation), value: typeof value === "number" ? numberToField(value) : value});
}
}
}
13 changes: 13 additions & 0 deletions packages/provable-programs/src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import fs from 'fs';
import path from 'path';
import { AttestationProof } from '../AttestSingleCredentialProperty';

// TODO: create generic utils for loading a proof from a file and converting it to a proof object
export function loadProofJSON(): string {
const proofJSON = JSON.parse(fs.readFileSync(path.join('test', 'test_proofs', 'attestationProof.json'), 'utf8'));
return JSON.stringify(proofJSON);
}
export function convertProof(proofJSON: string): AttestationProof {
const proof = AttestationProof.fromJSON(JSON.parse(proofJSON));
return proof;
}

0 comments on commit fcc6222

Please sign in to comment.