DID
The next step is to generate a KILT decentralized identifier (DID) using the account you created for the Attester in the previous step.
A DID may represent any entity, such as a person, an organization, or a machine.
A DID is a string uniquely identifying each KILT user. You can store information about a DID on the KILT chain, which is useful for different use cases.
One use case is messaging. You could store a public encryption key and a service on chain, and a user can query both using a DID. Other users can now encrypt messages using your public encryption key and send a message to your service.
Light and full DIDsโ
Kilt supports two DID types: light and full.
There are differences between the two types, but the most crucial is that you can use a light DID offline, but a full DID needs access to the blockchain to work. Read the DID documentation to learn more about the difference between the light and full types.
A DID supports four different key types:
- An authentication key pair, used to sign claims and present authenticated credentials
- A key-agreement key pair, used to encrypt/decrypt messages
- An assertion-method key pair, used to write CTypes and attestations on chain
- A capability-delegation key pair, used to write delegations on chain
You can replace keys over time, e.g., if a key becomes compromised.
What's the difference between a DID and an account?โ
A DID and an account sound quite similar, but there are some differences:
- You record both to chain
- You can have a DID without an account
- You can have an account without a DID
- Only an account can pay deposits and fees and attest claims
- DIDs don't hold any coins
In summary, you register a DID on the blockchain by an account submitting the DID creation transaction and paying the fees.
Create a DIDโ
As an Attester needs to interact with the chain, you must create a full DID.
Write DID to chainโ
The KILT SDK provides multiple methods to create DIDs, this workshop highlights the createFromAccount
method, that creates a DID from any pre-existing substrate-compatible account.
This workshop assumes you followed the create account step, but if you have a pre-existing account, you can use that instead.
Create and submit the extrinsic (aka transaction) that registers the DID.
- Typescript
- Javascript
import * as Kilt from '@kiltprotocol/sdk-js'
import { config as envConfig } from 'dotenv'
import { generateAccount } from './generateAccount'
export async function createFullDid(
creatorAccount: Kilt.KiltKeyringPair & {
type: 'ed25519' | 'sr25519' | 'ecdsa'
}
): Promise<{
fullDid: Kilt.DidDocument
}> {
const api = Kilt.ConfigService.get('api')
const verificationMethod = Kilt.Did.publicKeyToChain(creatorAccount)
const txs = [
api.tx.did.createFromAccount(verificationMethod),
api.tx.did.dispatchAs(
creatorAccount.address,
api.tx.did.setAttestationKey(verificationMethod)
)
]
console.log('Creating DID from accountโฆ')
await Kilt.Blockchain.signAndSubmitTx(
api.tx.utility.batch(txs),
creatorAccount
)
const didUri = Kilt.Did.getFullDidUriFromKey(creatorAccount)
const encodedFullDid = await api.call.did.query(Kilt.Did.toChain(didUri))
const { document: didDocument } = Kilt.Did.linkedInfoFromChain(encodedFullDid)
if (!didDocument) {
throw new Error('Full DID was not successfully created.')
}
return { fullDid: didDocument }
}
// Don't execute if this is imported by another file.
if (require.main === module) {
;(async () => {
envConfig()
try {
await Kilt.connect(process.env.WSS_ADDRESS as string)
// Load attester account
const accountMnemonic = process.env.ATTESTER_ACCOUNT_MNEMONIC as string
const { account } = generateAccount(accountMnemonic)
const { fullDid } = await createFullDid(account)
console.log('\nsave following to .env to continue\n')
console.error(`ATTESTER_DID_URI="${fullDid.uri}"\n`)
} catch (e) {
console.log('Error while creating attester DID')
throw e
}
})()
}
# loading code...
The publicKeyToChain
helper method returns a public key of the correct type.
The txs
array holds the two transactions containing the extrinsics needed to submit to the chain for the Attester's DID creation.
The createFromAccount
method takes the authenticated key of the account to attach the DID to, and the setAttestationKey
method takes the same parameter to set the attestation key the DID needs and uses.
An Attester account needs to have an attestation key to write CTypes and attestations on chain. Use the setAttestationKey
method to set this. For this example transaction, the Attester account uses the dispatchAs
proxy method to assign the attestation key to the same account. However, you can also use this method to assign the attestation key to another account.
The signAndSubmitTx
method then takes those transactions and submits them as a batch to the chain.
Run the codeโ
Now run the code with:
- Typescript
- Javascript
yarn ts-node ./attester/generateDid.ts
node ./attester/generateDid.js
Once you have run the script, the output should provide you with the ATTESTER_DID_URI
.
The output should look like the following, but not identical since the code creates the DIDs from your account:
ATTESTER_DID_URI="did:kilt:4ohMvUHsyeDโฆ"
Save the values in the .env
file, which should now look like the following:
WSS_ADDRESS=wss://peregrine.kilt.io
ATTESTER_ACCOUNT_MNEMONIC="warrior icon use cry...
ATTESTER_ACCOUNT_ADDRESS=4ohMvUHsyeDhMVZF...
ATTESTER_DID_URI="did:kilt:4ohMvUHsyeD..."
Well done - You've generated a full DID! The next step is to create a CType!
Generate Keysโ
Add the following code to the generateKeypairs
file.
- Typescript
- Javascript
import * as Kilt from '@kiltprotocol/sdk-js'
import { mnemonicGenerate } from '@polkadot/util-crypto'
export function generateKeypairs(mnemonic = mnemonicGenerate()): {
authentication: Kilt.KiltKeyringPair
keyAgreement: Kilt.KiltEncryptionKeypair
assertionMethod: Kilt.KiltKeyringPair
capabilityDelegation: Kilt.KiltKeyringPair
} {
const authentication = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic)
const assertionMethod = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic)
const capabilityDelegation = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic)
const keyAgreement = Kilt.Utils.Crypto.makeEncryptionKeypairFromSeed(
Kilt.Utils.Crypto.mnemonicToMiniSecret(mnemonic)
)
return {
authentication: authentication,
keyAgreement: keyAgreement,
assertionMethod: assertionMethod,
capabilityDelegation: capabilityDelegation
}
}
# loading code...