Attestation and notary framework for any document types on the blockchain.
OpenAttestation allows any entity to proof the existence of a document or a batch of documents. It makes use of smart contracts on the Ethereum blockchain to store cryptographic proofs of individual documents.
The Open Attestation repository allows you to batch the documents to obtain the merkle root of the batch to be committed to the blockchain. It also allows you to verify the signature of the document wrapped using the OpenAttestation framework.
npm i @govtechsg/open-attestation
wrapDocuments
takes in an array of document and returns the batched documents. Each document must be valid regarding the version of the schema used (see below) It computes the merkle root of the batch and appends the signature to each document. This merkle root can be published on the blockchain and queried against to prove the provenance of the document issued this way.
This function accept a second optional parameter to specify the version of open-attestation you want to use. By default, open-attestation will use schema 2.0.
The wrapDocument
function is identical but accept only one document.
import { wrapDocuments } from "@govtechsg/open-attestation";
const document = {
id: "SERIAL_NUMBER_123",
$template: {
name: "CUSTOM_TEMPLATE",
type: "EMBEDDED_RENDERER",
url: "https://localhost:3000/renderer",
},
issuers: [
{
name: "DEMO STORE",
tokenRegistry: "0x9178F546D3FF57D7A6352bD61B80cCCD46199C2d",
identityProof: {
type: "DNS-TXT",
location: "tradetrust.io",
},
},
],
recipient: {
name: "Recipient Name",
},
unknownKey: "unknownValue",
attachments: [
{
filename: "sample.pdf",
type: "application/pdf",
data: "BASE64_ENCODED_FILE",
},
],
};
wrappedDocuments = wrapDocuments([document, { ...document, id: "different id" }]); // will ensure document is valid regarding open-attestation 2.0 schema
console.log(wrappedDocuments);
wrappedDocuments = wrapDocuments([document, { ...document, id: "different id" }], { version: "open-attestation/3.0" }); // will ensure document is valid regarding open-attestation 3.0 schema
console.log(wrappedDocuments);
Note: Though
wrapDocument
andwrapDocuments
are both identical but there is a slight difference.wrapDocuments:
- returns an array and not an object.
- Each element in the array is a wrapped document corresponding to the one provided as input.
- Each element will share the same unique
merkleRoot
value in every batch wrap instance.- Each element has an unique
targetHash
value.- Similar to wrapDocument, every time you run wrapDocuments, it will create unique hashes (in front of every fields in the data object).
signDocument
takes a wrapped document, as well as a public/private key pair or an Ethers.js Signer. The method will sign the merkle root from the wrapped document, happened the signature to the document and return it. Currently, it supports the following sign algorithm:
Secp256k1VerificationKey2018
import { signDocument, SUPPORTED_SIGNING_ALGORITHM } from "@govtechsg/open-attestation";
await signDocument(wrappedV2Document, SUPPORTED_SIGNING_ALGORITHM.Secp256k1VerificationKey2018, {
public: "did:ethr:0xE712878f6E8d5d4F9e87E10DA604F9cB564C9a89#controller",
private: "0x497c85ed89f1874ba37532d1e33519aba15bd533cdcb90774cc497bfe3cde655",
});
import { signDocument, SUPPORTED_SIGNING_ALGORITHM } from "@govtechsg/open-attestation";
import { Wallet } from "ethers";
const wallet = Wallet.fromMnemonic("tourist quality multiply denial diary height funny calm disease buddy speed gold");
const { proof } = await signDocument(
wrappedDocumentV2,
SUPPORTED_SIGNING_ALGORITHM.Secp256k1VerificationKey2018,
wallet
);
validateSchema
checks that the document conforms to open attestation data structure.
import { validateSchema } from "@govtechsg/open-attestation";
const validatedSchema = validateSchema(wrappedDocument);
console.log(validatedSchema);
verifysignature
checks that the signature of the document corresponds to the actual content in the document. In addition, it checks that the target hash (hash of the document content), is part of the set of documents wrapped in the batch using the proofs.
Note that this method does not check against the blockchain or any registry if this document has been published. The merkle root of this document need to be checked against a publicly accessible document store (can be a smart contract on the blockchain).
import { verifySignature } from "@govtechsg/open-attestation";
const verified = verifySignature(wrappedDocument);
console.log(verified);
getData
returns the original data stored in the document, in a readable format.
import { getData } from "@govtechsg/open-attestation";
const data = getData(wrappedDocument);
console.log(data);
import { utils } from "@govtechsg/open-attestation";
utils.isWrappedV3Document(document);
isWrappedV2Document
type guard for wrapped v2 documentisSignedWrappedV2Document
type guard for signed v2 documentisSignedWrappedV3Document
type guard for signed v3 documentisWrappedV3Document
type guard for wrapped v3 documentdiagnose
tool to find out why a document is not a valid open attestation file (wrapped or signed document)
obfuscateDocument
removes a key-value pair from the document's data section, without causing the file hash to change. This can be used to generate a new document containing a subset of the original data, yet allow the recipient to proof the provenance of the document.
const newData = obfuscateDocument(wrappedDocument, "key1");
console.log(newData);
To run tests
npm run test
You can run the vc-test-suite against open-attestation
by running npm run test:vc
. This command will:
- clone https://github.com/w3c/vc-test-suite.git
- copy the local configuration (
vc-test-suite-config.json
) into the cloned repository - install the latest version of
@govtechsg/open-attestation-cli
- monkey patch
open-attestation
in@govtechsg/open-attestation-cli
. That means that the current version of the project will be built and replace the one installed with@govtechsg/open-attestation-cli
.
In the event you face a problem with one test and want to debug locally:
- Ensure the folder
vc-test-suite
is available from the root of the project. If that's not the case, runnpm run test:vc
first. - Open
runVcTest.sh
and updateinstall_vc_test_suite=true
toinstall_vc_test_suite=false
. This line will help to preserve thevc-test-suite
folder untouched.
You can now debug from the vc-test-suite
folder the way you need it.
- Found a bug? Have a question? Want to share an idea? Reach us at our Github repository.
- We are currently building a new version of the schema, compatible with W3C VC. This is very experimental and whatever is available for v2 documents are also available for v3 documents:
- OA schema v3
- Typings:
import {v3} from "@govtechsg/open-attestation"
. - Type guard:
utils.isWrappedV3Document
. - Wrapping:
wrapDocument(document, {version: "open-attestation/3.0"})
- There are extra utilities available:
- Refer to the utils component for the full list of utilities.