![License](https://img.shields.io/npm/l/@kiltprotocol/portablegabi)
Portablegabi
This TypeScript module of Portable Gabi enables the use of Idemix attribute based anonymous credentials via NPM. It is based on the Gabi Go implementation by the Privacy By Design Foundation but does not use the same API.
A user (in the following referred to as claimer) claiming something in JSON format (e.g. citizenship in a specific country, ownership of a valid driver's license) can request an attestation from a trusted entity (attester) and present these claims to multiple verifiers without revealing their identity or sensitive information (multi-show unlinkability).
The claimer can chose which attributes of the claim to disclose to a verifier (selective disclosure).
Tutorial
We recommend visiting our Portablegabi tutorial to better understand how to use our anonymous credentials and the API.
Portablegabi also provides a generated API reference.
Revocation and Substrate
This module can be used with and without a Substrate-based blockchain.
However, it was designed to be used with a chain acting as a decentralised storage of each attester's accumulator versions to enable revocation.
All processes tied to chain activity can be found in files with chain
suffix. In order to use them, you are required to have an active Substrate blockchain implementing our portablegabi-pallet
.
We also provide a blockchain template which includes our pallet and can be used to store accumulators.
In order to use that, just clone and set up the portablegabi-node
or use the template to create your own project. Please see our tutorial for more information.
Installing
npm
npm i @kiltprotocol/portablegabi
yarn
yarn add @kiltprotocol/portablegabi
Building + Testing
If you want to help develop portablegabi, we would be glad to merge your pull request.
But first, you need to set up a development environment for our project.
See our tutorial for more information.
Run in the browser
It is also possible to use the Portablegabi API in the browser, see here for more details.
Example
Please see the example files for a showcase of on- and off-chain usage with single or combined credentials.
const portablegabi = require('@kiltprotocol/portablegabi')
async function exec() {
const claim = {
contents: {
name: 'Jasper',
age: '42',
city: 'Berlin',
id: 'ed638ndke92902n29',
},
}
const claimer = await portablegabi.Claimer.create()
const attester = await portablegabi.Attester.create()
console.log('Public key:\n\t', attester.privateKey.toString())
console.log('Private key:\n\t', attester.privateKey.toString())
const accumulator = await attester.createAccumulator()
const {
message: startAttestationMsg,
session: attestationSession,
} = await attester.startAttestation()
const {
message: attestationRequest,
session: claimerSession,
} = await claimer.requestAttestation({
startAttestationMsg,
claim,
attesterPubKey: attester.publicKey,
})
console.log('Claimer requests attestation:\n\t', attestationRequest)
const checkClaim = attestationRequest.getClaim()
console.log('Attester checks claim :\n\t', checkClaim)
const { attestation, witness } = await attester.issueAttestation({
attestationSession,
attestationRequest,
accumulator,
})
console.log('Attester issues attestion:\n\t', attestation)
const credential = await claimer.buildCredential({
claimerSession,
attestation,
})
console.log('Claimer builds credential:\n\t', credential)
const {
session: verifierSession,
message: presentationReq,
} = await portablegabi.Verifier.requestPresentation({
requestedAttributes: ['contents.age', 'contents.city'],
reqUpdatedAfter: new Date(),
})
console.log('Verifier starts verification session:\n\t', presentationReq)
const proof = await claimer.buildPresentation({
credential,
presentationReq,
attesterPubKey: attester.publicKey,
})
console.log('Claimer builds zk-proof on requested attributes:\n\t', proof)
const {
verified,
claim: verifiedClaim,
} = await portablegabi.Verifier.verifyPresentation({
proof,
verifierSession,
attesterPubKey: attester.publicKey,
latestAccumulator: accumulator,
})
console.log('Verifier verifiers proof:\n\t', verified, verifiedClaim)
const accumulatorAfterRevocation = await attester.revokeAttestation({
accumulator,
witnesses: [witness],
})
await credential
.updateSingle({
attesterPubKey: attester.publicKey,
accumulator: accumulatorAfterRevocation,
})
.catch((e) => {
if (e.message.includes('revoked')) {
console.log('Credential was revoked and cannot be updated')
} else throw e
})
}
exec()
Troubleshooting
Node process did not exit automatically
Note that due to the usage of a Go WASM via callbacks, all functions are asynchronous. It can happen that NodeJS does not exit automatically since we keep the WASM instance open. We recommend calling goWasmClose()
from wasm_exec_wrapper at the end of your process.
Go version below 1.14.1
[LinkError: WebAssembly Instantiation: Import
(node:6909) UnhandledPromiseRejectionWarning: Error: Function genKey missing in WASM
Please check your Go version, it should be at least 1.14.1
. If this is the case for you, and you still encounter this problem without having modified our code, please open a ticket.
Limitations
- all numbers inside a claim are handled as
float64
- arrays are handled as a single attribute. Disclosing a value inside an array is only possible if the whole array is disclosed.
![](https://github.com/KILTprotocol/portablegabi/raw/HEAD/./web3_foundation_grants_badge_black.svg)