Skip to content
This repository has been archived by the owner on Feb 4, 2025. It is now read-only.

Commit

Permalink
fix: change the way of converting blank node ids
Browse files Browse the repository at this point in the history
This fix improves the way of converting blank node ids before signing and verification, just using regexp-based string replacement. It enables us to make `credentialSubject.id` to be blank node identifier, which would be useful in privacy-preserving applications of BBS+.

fixes mattrglobal#128
  • Loading branch information
yamdan committed May 21, 2021
1 parent 0f20641 commit c9c30c2
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 26 deletions.
119 changes: 119 additions & 0 deletions __tests__/AnonymousVC.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Copyright 2020 - MATTR Limited
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {
exampleBls12381KeyPair,
customLoader,
testAnonymousVcDocument,
testRevealAnonymousVcDocument,
testNestedRevealDocument,
testNestedRevealFullDocument,
testNestedAnonymousVcDocument
} from "./__fixtures__";

import jsigs from "jsonld-signatures";
import {
Bls12381G2KeyPair,
BbsBlsSignatureProof2020,
BbsBlsSignature2020,
deriveProof
} from "../src/index";
import { getProofs } from "../src/utilities";

const key = new Bls12381G2KeyPair(exampleBls12381KeyPair);

const signDeriveVerify = async (vc: any, reveal: any, subject: any) => {
// Issuer issues VC
const signedVc = await jsigs.sign(vc, {
suite: new BbsBlsSignature2020({ key }),
purpose: new jsigs.purposes.AssertionProofPurpose(),
documentLoader: customLoader
});
expect(signedVc).toBeDefined();

// Holder verifies VC
const verifiedVc = await jsigs.verify(signedVc, {
suite: new BbsBlsSignature2020(),
purpose: new jsigs.purposes.AssertionProofPurpose(),
documentLoader: customLoader
});
expect(verifiedVc.verified).toBeTruthy();

// Holder derives Proof
const derivedProof = await deriveProof(signedVc, reveal, {
suite: new BbsBlsSignatureProof2020(),
documentLoader: customLoader
});
expect(derivedProof.credentialSubject).toEqual(subject);

// Verifier verifies proof
const { document, proofs } = await getProofs({
document: derivedProof,
proofType: BbsBlsSignatureProof2020.proofType,
documentLoader: customLoader
});
const suite = new BbsBlsSignatureProof2020();
const result = await suite.verifyProof({
document,
proof: proofs[0],
documentLoader: customLoader,
purpose: new jsigs.purposes.AssertionProofPurpose()
});
expect(result.verified).toBeTruthy();
};

describe("anonymous verifiable credentials with blank node identifiers", () => {
it("should sign, derive proof, and verify proof on anonymous verifiable credential", async () => {
await signDeriveVerify(
testAnonymousVcDocument,
testRevealAnonymousVcDocument,
{
id: "urn:bnid:_:c14n1",
type: ["Person", "PermanentResident"],
commuterClassification: "C1"
}
);
});

it("should sign, derive proof, and verify proof on anonymous nested and partially revealed verifiable credential", async () => {
await signDeriveVerify(
testNestedAnonymousVcDocument,
testNestedRevealDocument,
{
id: "urn:bnid:_:c14n2",
degree: {
id: "urn:bnid:_:c14n1",
type: "BachelorDegree",
name: "Bachelor of Science and Arts"
}
}
);
});

it("should sign, derive proof, and verify proof on anonymous nested and fully revealed verifiable credential", async () => {
await signDeriveVerify(
testNestedAnonymousVcDocument,
testNestedRevealFullDocument,
{
id: "urn:bnid:_:c14n2",
degree: {
id: "urn:bnid:_:c14n1",
type: "BachelorDegree",
name: "Bachelor of Science and Arts",
degreeType: "Underwater Basket Weaving"
},
college: "Contoso University"
}
);
});
});
27 changes: 27 additions & 0 deletions __tests__/__fixtures__/data/test_anonymous_vc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/citizenship/v1",
"https://w3id.org/security/v3-unstable"
],
"type": ["VerifiableCredential", "PermanentResidentCard"],
"issuer": "did:example:489398593",
"identifier": "83627465",
"name": "Permanent Resident Card",
"description": "Government of Example Permanent Resident Card.",
"issuanceDate": "2019-12-03T12:19:52Z",
"expirationDate": "2029-12-03T12:19:52Z",
"credentialSubject": {
"type": ["PermanentResident", "Person"],
"givenName": "JOHN",
"familyName": "SMITH",
"gender": "Male",
"image": "data:image/png;base64,iVBORw0KGgokJggg==",
"residentSince": "2015-01-01",
"lprCategory": "C09",
"lprNumber": "999-999-999",
"commuterClassification": "C1",
"birthCountry": "Bahamas",
"birthDate": "1958-07-17"
}
}
17 changes: 17 additions & 0 deletions __tests__/__fixtures__/data/test_anonymous_vc_reveal_document.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/citizenship/v1",
"https://w3id.org/security/v3-unstable"
],
"type": ["VerifiableCredential", "PermanentResidentCard"],
"@explicit": true,
"issuer": {},
"name": {},
"description": {},
"credentialSubject": {
"type": ["PermanentResident", "Person"],
"@explicit": true,
"commuterClassification": {}
}
}
18 changes: 18 additions & 0 deletions __tests__/__fixtures__/data/test_nested_anonymous_vc_document.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1",
"https://www.w3id.org/security/v3-unstable"
],
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
"issuer": "did:example:489398593",
"issuanceDate": "2020-03-10T04:24:12.164Z",
"credentialSubject": {
"degree": {
"type": "BachelorDegree",
"name": "Bachelor of Science and Arts",
"degreeType": "Underwater Basket Weaving"
},
"college": "Contoso University"
}
}
8 changes: 7 additions & 1 deletion __tests__/__fixtures__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ import testNestedVcDocument from "./data/test_nested_vc_document.json";
import testSignedNestedVcDocument from "./data/test_signed_nested_vc_document.json";
import testProofNestedVcDocument from "./data/test_proof_nested_vc_document.json";
import testPartialProofNestedVcDocument from "./data/test_partial_proof_nested_vc_document.json";
import testAnonymousVcDocument from "./data/test_anonymous_vc.json";
import testRevealAnonymousVcDocument from "./data/test_anonymous_vc_reveal_document.json";
import testNestedAnonymousVcDocument from "./data/test_nested_anonymous_vc_document.json";

export {
exampleBls12381KeyPair,
Expand All @@ -61,5 +64,8 @@ export {
testSignedNestedVcDocument,
testProofNestedVcDocument,
testPartialProofNestedVcDocument,
customLoader
customLoader,
testAnonymousVcDocument,
testRevealAnonymousVcDocument,
testNestedAnonymousVcDocument
};
30 changes: 5 additions & 25 deletions src/BbsBlsSignatureProof2020.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,19 +126,8 @@ export class BbsBlsSignatureProof2020 extends suites.LinkedDataProof {
// Transform any blank node identifiers for the input
// document statements into actual node identifiers
// e.g _:c14n0 => urn:bnid:_:c14n0
const transformedInputDocumentStatements = documentStatements.map(
element => {
if (element.includes("_:c14n")) {
const prefixIndex = element.indexOf("_:c14n");
const spaceIndex = element.indexOf(" ", prefixIndex);
return element.replace(
element.substring(prefixIndex, spaceIndex),
`<urn:bnid:${element.substring(prefixIndex, spaceIndex)}>`
);
}

return element;
}
const transformedInputDocumentStatements = documentStatements.map(element =>
element.replace(/(_:c14n[0-9]+)/g, "<urn:bnid:$1>")
);

//Transform the resulting RDF statements back into JSON-LD
Expand Down Expand Up @@ -263,18 +252,9 @@ export class BbsBlsSignatureProof2020 extends suites.LinkedDataProof {

// Transform the blank node identifier placeholders for the document statements
// back into actual blank node identifiers
const transformedDocumentStatements = documentStatements.map(element => {
const prefixString = "<urn:bnid:";
if (element.includes("<urn:bnid:_:c14n")) {
const prefixIndex = element.indexOf(prefixString);
const closingIndex = element.indexOf(">", prefixIndex);
return element.replace(
element.substring(prefixIndex, closingIndex + 1),
element.substring(prefixIndex + prefixString.length, closingIndex)
);
}
return element;
});
const transformedDocumentStatements = documentStatements.map(element =>
element.replace(/<urn:bnid:(_:c14n[0-9]+)>/g, "$1")
);

// Combine all the statements to be verified
const statementsToVerify: Uint8Array[] = proofStatements
Expand Down

0 comments on commit c9c30c2

Please sign in to comment.