@dfinity/certificate-verification
v4.0.0
Published
Client side certificate verification for the Internet Computer
Downloads
493
Readme
Certificate Verification
Certificate verification on the Internet Computer is the process of verifying that a canister's response to a query call has gone through consensus with other replicas hosting the same canister.
This package partially encapsulates the protocol for such verification. It performs the following actions:
- Decoding of the certificate and the canister provided tree
- Verification of the certificate's root of trust
- Verification of the certificate's delegations (if any)
- Decoding of a canister provided merkle tree
- Verification that the canister provided merkle tree's root hash matches the canister's certified data
Usage
In the following example, canister is an actor created with @icp-sdk/core for a canister with the following candid:
type certified_response = record {
"data" : nat32;
"certificate" : blob;
"witness" : blob;
};
service : {
"get_data" : () -> (certified_response) query;
};Check ic-certification for details on how to create certificate and witness inside your canister.
calculateDataHash is a userland provided function that can calculate the hash of the data returned from the canister. This must be calculated in the same way on the canister and the frontend.
import {
lookup_path,
lookupResultToBuffer,
uint8Equals,
} from '@icp-sdk/core/agent';
import { Principal } from '@icp-sdk/core/principal';
const { data, certificate, witness } = await canister.get_data();
// The agent holds the built-in IC root key. Only a local replica's key has to
// be fetched, via `HttpAgent.create({ shouldFetchRootKey: true })`; fetching it
// on the IC would let a malicious gateway supply its own trust anchor.
if (!agent.rootKey) {
throw new Error('The agent is missing a root key');
}
const tree = await verifyCertification({
canisterId: Principal.fromText(canisterId),
encodedCertificate: new Uint8Array(certificate),
encodedTree: new Uint8Array(witness),
rootKey: agent.rootKey,
maxCertificateTimeOffsetMs: 50000,
});
const treeDataHash = lookupResultToBuffer(lookup_path(['count'], tree));
const responseDataHash = calculateDataHash(data);
if (!treeDataHash || !uint8Equals(treeDataHash, responseDataHash)) {
// The data returned from the canister does not match the certified data.
}Examples
See the certified counter example for a full e2e example of how to create a certification and verify it using this package.
