Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add cookbook recipe how to generate keys #223

Merged
merged 14 commits into from
Aug 1, 2023
Merged
12 changes: 6 additions & 6 deletions code_examples/sdk_examples/src/core_features/claiming/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export async function runAll(
attesterFullDid.uri,
submitterAccount,
async ({ data }) => ({
signature: attersterKeys.attestation.sign(data),
keyType: attersterKeys.attestation.type
signature: attersterKeys.assertionMethod.sign(data),
keyType: attersterKeys.assertionMethod.type
})
)
console.log('2 claiming) Fetch CType')
Expand All @@ -57,8 +57,8 @@ export async function runAll(
attesterFullDid.uri,
submitterAccount,
async ({ data }) => ({
signature: attersterKeys.attestation.sign(data),
keyType: attersterKeys.attestation.type
signature: attersterKeys.assertionMethod.sign(data),
keyType: attersterKeys.assertionMethod.type
}),
credential
)
Expand All @@ -81,8 +81,8 @@ export async function runAll(
attesterFullDid.uri,
submitterAccount,
async ({ data }) => ({
signature: attersterKeys.attestation.sign(data),
keyType: attersterKeys.attestation.type
signature: attersterKeys.assertionMethod.sign(data),
keyType: attersterKeys.assertionMethod.type
}),
credential,
false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as Kilt from '@kiltprotocol/sdk-js'

import {
blake2AsU8a,
keyExtractPath,
keyFromPath,
mnemonicGenerate,
mnemonicToMiniSecret,
sr25519PairFromSeed
} from '@polkadot/util-crypto'

// Because there is no first-class support for this class of keys,
// we need to use a workaround to generate a key we can use for encryption/decryption.
function generateKeyAgreement(mnemonic: string): Kilt.KiltEncryptionKeypair {
const secretKeyPair = sr25519PairFromSeed(mnemonicToMiniSecret(mnemonic))
const { path } = keyExtractPath('//did//keyAgreement//0')
const { secretKey } = keyFromPath(secretKeyPair, path, 'sr25519')
return Kilt.Utils.Crypto.makeEncryptionKeypairFromSeed(blake2AsU8a(secretKey))
}

export function generateKeypairs(mnemonic = mnemonicGenerate()): {
authentication: Kilt.KiltKeyringPair & {
type: 'sr25519'
}
keyAgreement: Kilt.KiltEncryptionKeypair
assertionMethod: Kilt.KiltKeyringPair
capabilityDelegation: Kilt.KiltKeyringPair
} {
const account = Kilt.Utils.Crypto.makeKeypairFromSeed(
mnemonicToMiniSecret(mnemonic),
'sr25519'
)

const authentication = {
...account.derive('//did//0'),
type: 'sr25519'
} as Kilt.KiltKeyringPair & {
type: 'sr25519'
}

const assertionMethod = {
...account.derive('//did//assertion//0'),
type: 'sr25519'
} as Kilt.KiltKeyringPair

const capabilityDelegation = {
...account.derive('//did//delegation//0'),
type: 'sr25519'
} as Kilt.KiltKeyringPair

const keyAgreement = generateKeyAgreement(mnemonic)

return {
authentication: authentication,
keyAgreement: keyAgreement,
assertionMethod: assertionMethod,
capabilityDelegation: capabilityDelegation
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import * as Kilt from '@kiltprotocol/sdk-js'

export function createCompleteLightDid({
authentication,
encryption
keyAgreement
}: {
authentication: Kilt.NewLightDidVerificationKey
encryption: Kilt.NewDidEncryptionKey
keyAgreement: Kilt.NewDidEncryptionKey
}): Kilt.DidDocument {
// Example service for the DID.
const service: Kilt.DidServiceEndpoint[] = [
Expand All @@ -19,7 +19,7 @@ export function createCompleteLightDid({
// Create the KILT light DID with the information generated.
const lightDID = Kilt.Did.createLightDidDocument({
authentication: [authentication],
keyAgreement: [encryption],
keyAgreement: [keyAgreement],
service
})
console.log(lightDID.uri)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ export async function createCompleteFullDid(
submitterAccount: Kilt.KiltKeyringPair,
{
authentication,
encryption,
attestation,
delegation
keyAgreement,
assertionMethod,
capabilityDelegation
}: {
authentication: Kilt.NewDidVerificationKey
encryption: Kilt.NewDidEncryptionKey
attestation: Kilt.NewDidVerificationKey
delegation: Kilt.NewDidVerificationKey
keyAgreement: Kilt.NewDidEncryptionKey
assertionMethod: Kilt.NewDidVerificationKey
capabilityDelegation: Kilt.NewDidVerificationKey
},
signCallback: Kilt.SignExtrinsicCallback
): Promise<Kilt.DidDocument> {
Expand All @@ -20,9 +20,9 @@ export async function createCompleteFullDid(
const fullDidCreationTx = await Kilt.Did.getStoreTx(
{
authentication: [authentication],
keyAgreement: [encryption],
assertionMethod: [attestation],
capabilityDelegation: [delegation],
keyAgreement: [keyAgreement],
assertionMethod: [assertionMethod],
capabilityDelegation: [capabilityDelegation],
// Example service.
service: [
{
Expand Down
16 changes: 8 additions & 8 deletions code_examples/sdk_examples/src/core_features/did/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ export async function runAll(
console.log('2 did) Create complete light DID')
const {
authentication: completeLightDidAuth,
encryption: completeLightDidEnc
keyAgreement: completeLightDidEnc
} = generateKeypairs()
createCompleteLightDid({
authentication: completeLightDidAuth,
encryption: completeLightDidEnc
keyAgreement: completeLightDidEnc
})
console.log('3 did) Migrate first light DID to full DID')
await migrateLightDid(simpleLightDid, submitterAccount, async ({ data }) => ({
Expand All @@ -57,17 +57,17 @@ export async function runAll(
console.log('5 did) Create complete full DID')
const {
authentication: completeFullDidAuth,
encryption: completeFullDidEnc,
attestation: completeFullDidAtt,
delegation: completeFullDidDel
keyAgreement: completeFullDidEnc,
assertionMethod: completeFullDidAtt,
capabilityDelegation: completeFullDidDel
} = generateKeypairs()
const createdCompleteFullDid = await createCompleteFullDid(
submitterAccount,
{
authentication: completeFullDidAuth,
encryption: completeFullDidEnc,
attestation: completeFullDidAtt,
delegation: completeFullDidDel
keyAgreement: completeFullDidEnc,
assertionMethod: completeFullDidAtt,
capabilityDelegation: completeFullDidDel
},
async ({ data }) => ({
signature: completeFullDidAuth.sign(data),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export async function runAll(submitterAccount: Kilt.KiltKeyringPair) {
senderFullDid.uri,
submitterAccount,
async ({ data }) => ({
signature: senderKeypairs.attestation.sign(data),
keyType: senderKeypairs.attestation.type
signature: senderKeypairs.assertionMethod.sign(data),
keyType: senderKeypairs.assertionMethod.type
})
)

Expand All @@ -59,13 +59,13 @@ export async function runAll(submitterAccount: Kilt.KiltKeyringPair) {
message,
senderFullDid.uri,
receiverFullDid.uri,
senderKeypairs.encryption
senderKeypairs.keyAgreement
)

console.log(
'6 Messaging) Decrypting the message from sender for the receiver'
)
await decryptMessage(encryptedMessage, receiverKeypairs.encryption)
await decryptMessage(encryptedMessage, receiverKeypairs.keyAgreement)

console.log('Messaging flow completed!')
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export async function runAll(
attesterDid.uri,
submitterAccount,
async ({ data }) => ({
signature: keypairs.attestation.sign(data),
keyType: keypairs.attestation.type
signature: keypairs.assertionMethod.sign(data),
keyType: keypairs.assertionMethod.type
})
)

Expand All @@ -54,8 +54,8 @@ export async function runAll(
attesterDid.uri,
submitterAccount,
async ({ data }) => ({
signature: keypairs.attestation.sign(data),
keyType: keypairs.attestation.type
signature: keypairs.assertionMethod.sign(data),
keyType: keypairs.assertionMethod.type
}),
credential
)
Expand Down Expand Up @@ -85,8 +85,8 @@ export async function runAll(
attesterDid.uri,
submitterAccount,
async ({ data }) => ({
signature: keypairs.attestation.sign(data),
keyType: keypairs.attestation.type
signature: keypairs.assertionMethod.sign(data),
keyType: keypairs.assertionMethod.type
}),
credentialId,
true
Expand All @@ -96,8 +96,8 @@ export async function runAll(
attesterDid.uri,
submitterAccount,
async ({ data }) => ({
signature: keypairs.attestation.sign(data),
keyType: keypairs.attestation.type
signature: keypairs.assertionMethod.sign(data),
keyType: keypairs.assertionMethod.type
}),
credential
)
Expand All @@ -106,8 +106,8 @@ export async function runAll(
attesterDid.uri,
submitterAccount,
async ({ data }) => ({
signature: keypairs.attestation.sign(data),
keyType: keypairs.attestation.type
signature: keypairs.assertionMethod.sign(data),
keyType: keypairs.assertionMethod.type
}),
credential
)
Expand All @@ -116,8 +116,8 @@ export async function runAll(
attesterDid.uri,
submitterAccount,
async ({ data }) => ({
signature: keypairs.attestation.sign(data),
keyType: keypairs.attestation.type
signature: keypairs.assertionMethod.sign(data),
keyType: keypairs.assertionMethod.type
}),
credential
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,60 @@
import { mnemonicGenerate, mnemonicToMiniSecret } from '@polkadot/util-crypto'

import * as Kilt from '@kiltprotocol/sdk-js'

import {
blake2AsU8a,
keyExtractPath,
keyFromPath,
mnemonicGenerate,
mnemonicToMiniSecret,
sr25519PairFromSeed
} from '@polkadot/util-crypto'

// Because there is no first-class support for this class of keys,
// we need to use a workaround to generate a key we can use for encryption/decryption.
function generateKeyAgreement(mnemonic: string): Kilt.KiltEncryptionKeypair {
const secretKeyPair = sr25519PairFromSeed(mnemonicToMiniSecret(mnemonic))
const { path } = keyExtractPath('//did//keyAgreement//0')
const { secretKey } = keyFromPath(secretKeyPair, path, 'sr25519')
return Kilt.Utils.Crypto.makeEncryptionKeypairFromSeed(blake2AsU8a(secretKey))
}

export function generateKeypairs(mnemonic = mnemonicGenerate()): {
authentication: Kilt.KiltKeyringPair & {
type: 'ed25519'
type: 'sr25519'
}
encryption: Kilt.KiltEncryptionKeypair
attestation: Kilt.KiltKeyringPair
delegation: Kilt.KiltKeyringPair
keyAgreement: Kilt.KiltEncryptionKeypair
assertionMethod: Kilt.KiltKeyringPair
capabilityDelegation: Kilt.KiltKeyringPair
} {
const authentication = Kilt.Utils.Crypto.makeKeypairFromSeed(
mnemonicToMiniSecret(mnemonic)
)
const encryption = Kilt.Utils.Crypto.makeEncryptionKeypairFromSeed(
mnemonicToMiniSecret(mnemonic)
)
const attestation = authentication.derive(
'//attestation'
) as Kilt.KiltKeyringPair
const delegation = authentication.derive(
'//delegation'
) as Kilt.KiltKeyringPair
const keyring = new Kilt.Utils.Keyring({
ss58Format: 38,
type: 'sr25519'
})
const account = keyring.addFromMnemonic(mnemonic)

const authentication = {
...account.derive('//did//0'),
type: 'sr25519'
} as Kilt.KiltKeyringPair & {
type: 'sr25519'
}

const assertionMethod = {
...account.derive('//did//assertion//0'),
type: 'sr25519'
} as Kilt.KiltKeyringPair

const capabilityDelegation = {
...account.derive('//did//delegation//0'),
type: 'sr25519'
} as Kilt.KiltKeyringPair

const keyAgreement = generateKeyAgreement(mnemonic)

return {
authentication,
encryption,
attestation,
delegation
authentication: authentication,
keyAgreement: keyAgreement,
assertionMethod: assertionMethod,
capabilityDelegation: capabilityDelegation
}
}

// Required for the raw-loader to successfully import this code snippet as text.
export default generateKeypairs
22 changes: 22 additions & 0 deletions docs/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
id: key-generation
title: Generate DID keys
---

import TsJsBlock from '@site/src/components/TsJsBlock';

import GenerateKeys from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/00_generate_did_keys.ts';

Creating a DID (like in [Light DID Creation](./01_light_did_creation.md) or [Full DID Creation](./02_full_did_creation.md)) requires the generation of some keying material for keys that are to be used for authentication and encryption.

The following is an example of how to create a a set of keypairs suitable for generating a KILT DID from it.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like this:

Suggested change
Creating a DID (like in [Light DID Creation](./01_light_did_creation.md) or [Full DID Creation](./02_full_did_creation.md)) requires the generation of some keying material for keys that are to be used for authentication and encryption.
The following is an example of how to create a a set of keypairs suitable for generating a KILT DID from it.
Creating a Decentralized Identifier (DID) in the KILT network involves generating keying material for authentication and encryption. In this guide, we'll demonstrate how to create a set of key pairs suitable for generating a KILT DID.
Before we proceed, it's important to note that this example assumes the usage of the @kiltprotocol/sdk-js library along with the @polkadot/util-crypto library for cryptographic operations. Additionally, we want to emphasize the significance of securely storing keys and the mnemonic seed phrase. For production use, ensure that private keys are encrypted and stored safely, while also creating a backup of the mnemonic seed phrase.
Below is an example code snippet illustrating the key pair generation for a KILT DID:

Also please explain the reason for the derivation paths

Maybe like that:

In the example provided, we derive different types of keys from a single account using derivation paths. This approach allows us to generate various key pairs for authentication, key agreement, assertion methods, and capability delegation from one mnemonic seed phrase. Using derivation paths simplifies key management, ensuring that a single mnemonic seed serves as the basis for multiple keys associated with a DID. This method improves efficiency while maintaining security. However, it's essential to handle and store private keys securely to prevent unauthorized access and ensure the overall integrity and privacy of the decentralized identity system.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

soooo much 🤖


<TsJsBlock>
{GenerateKeys}
</TsJsBlock>

:::info
This example doesn't show how to store the keys.
It is recommended to store the keys in a secure manner, e.g. only storing the private keys encrypted on disk.
The mnemonic seed phrase can be used to regenerate the keys, so it is recommended to also store the mnemonic in a secure manner and create a backup of it.
:::