-
Infra DID Method Spec
-
Infra DID Resolver (DIF ts universal resolver compatible)
-
Infra DID Substrate Node
Feature provided by infra-did-js/infra-ss58
library
Note: The Infra DID resolver provides three types of verification methods in its DID document: 'Ed25519VerificationKey2018', 'Ed25519VerificationKey2020', and 'JsonWebKey2020'. However, as of 2023-07-21, we are using the w3c standard for VC/VP verification, so only 'Ed25519VerificationKey2018' is available.
- Infra SS58 DID Creation
- DID Module
- Register/Unregister DID on chain
- Update/Remove DID attributes (Service Endpoint, Controller DID, Public Key)
- Set Attestations Claim
- Get Documents of DID(Resolve)
- BBS+ Module
- BBS+ Key Pair & Public Key Creation
- Add/Get/Remove BBS+ Params
- Add/Get/Remove BBS+ Public Key
- Trusted Entity Module
- Register/Get/Unregister Authorizer on chain
- Add/Get/Remove Trusted Entity(Issuer, Verifier)
- Registry Module
- Register/Get/Unregister Registry on chain
- Verifiable Classes
- Create/Register/Get Schema
- Create/Issue/Verify Verifiable Credential
- Revoke/Unrevoke/Check Verifiable Credential
- Create/Sign/Verify VerifiablePresentation
- Issue/Verify BBSPlusCredential and BBSPlusPresentation
- Crypto Helper
- convert Ed25519 to X25519
- convert key type (u8a to jwk, keyobject)
- create ECDH-ES Key(diffieHellman) using X25519
- ED25519 derived key SLIP-10
import {InfraSS58, CRYPTO_INFO} from 'infra-did-js';
const txfeePaterAccountKeyPair = await InfraSS58.getKeyPairFromUri('//Alice', 'sr25519');
const confBlockchainNetwork = {
networkId: 'space',
address: 'wss://infra2.infrablockchain.com',
// seed or keyPair required
txfeePayerAccountKeyPair,
// or txfeePayerAccountSeed: 'TX_FEE_PAYER_ACCOUNT_SEED'
};
const conf = {
...confBlockchainNetwork,
did: 'did:infra:space:5CRV5zBdAhBALnXiBSWZWjca3rSREBg87GJ6UY9i2A7y1rCs',
// seed or keyPair required
seed: 'DID_SEED',
// keyPair: keyPair,
controllerDID: 'did:infra:space:5HdJprb8NhaJsGASLBKGQ1bkKkvaZDaK1FxTbJRXNShFuqgY'
controllerSeed: 'DID_CONTROLLER_SEED',
// or controllerKeyPair: controllerKeyPair
};
const infraApi = await InfraSS58.createAsync(conf);
DIDSet = await InfraSS58.createNewSS58DIDSet(networkId)
console.log({ DIDSet })
{
DIDSet: {
did: 'did:infra:space:5Cq2Za1Z4HJx5eTvxT5iFyXZLM1XTwVZSafQsEuK4ujNKJEF',
didKey: DidKey_SS58 {
publicKey: PublicKey_SS58 {
value: '0x21cdc3dc94f8cccd889759fbc282f4272f89c8d974aea4d3051e8efa85e738b7',
sigType: 'Ed25519'
},
verRels: VerificationRelationship { _value: 0 }
},
keyPair: {
address: [Getter],
addressRaw: [Getter],
isLocked: [Getter],
meta: [Getter],
publicKey: [Getter],
type: [Getter],
// -- snip --
},
publicKey: PublicKey_SS58 {
value: '0x21cdc3dc94f8cccd889759fbc282f4272f89c8d974aea4d3051e8efa85e738b7',
sigType: 'Ed25519'
},
verRels: VerificationRelationship { _value: 0 },
cryptoInfo: {
CRYPTO_TYPE: 'ed25519',
KEY_NAME: 'Ed25519VerificationKey2018',
SIG_TYPE: 'Ed25519',
SIG_NAME: 'Ed25519Signature2018',
SIG_CLS: [class Ed25519Signature2018 extends CustomLinkedDataSignature],
LDKeyClass: [class Ed25519VerificationKey2018]
},
seed: '0x8c9971953c5c82a51e3ab0ec9a16ced7054585081483e2489241b5b059f5f3cf',
keyPairJWK: {
publicJwk: {
alg: 'EdDSA',
kty: 'OKP',
crv: 'Ed25519',
x: 'Ic3D3JT4zM2Il1n7woL0Jy-JyNl0rqTTBR6O-oXnOLc'
},
privateJwk: {
alg: 'EdDSA',
kty: 'OKP',
crv: 'Ed25519',
x: 'Ic3D3JT4zM2Il1n7woL0Jy-JyNl0rqTTBR6O-oXnOLc',
d: 'jJlxlTxcgqUeOrDsmhbO1wVFhQgUg-JIkkG1sFn1888'
}
}
}
}
InfraSS58.validateInfraSS58(SOME_DID_STRING).result
// Register DID
await infraApi.didModule.registerOnchain()
// Unregister DID
await infraApi.didModule.unregisterOnChain()
// Add keys
await infraApi.didModule.addKeys(SOME_DID_KEY)
// Remove Keys
await infraApi.didModule.removeKeys(DID_KEY_IDS)
// Add Controller DID
await infraApi.didModule.addControllers(CONTROLLER_DIDS)
// Remove Controller DID
await infraApi.didModule.removeControllers(CONTROLLER_DIDS)
// Add Service Endpoint
await infraApi.didModule.addServiceEndpoint(SOME_SERVICE_ENDPOINT_URLS)
// Get Service Endpoint
await infraApi.didModule.getServiceEndpoint()
// Remove Service Endpoint
await infraApi.didModule.removeServiceEndpoint()
await infraApi.didModule.setClaim(PRIORITY_NUMBER, CLAIM_IRI)
const didDocuments = await infraDID.didModule.getDocument() // get self.document
// or
const didDocuments2 = await infraDID.getDocument(SOME_DID)
console.log({ didDocuments })
{
"didDocuments": {
"@context": [
"https://www.w3.org/ns/did/v1"
],
"id": "did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX",
"controller": [
"did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX"
],
"verificationMethod": [
{
"id": "did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-1",
"type": "Ed25519VerificationKey2018",
"controller": "did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX",
"publicKeyBase58": "FXvzvY3jcmtXNK48azNRund96FBFtVK62MMPHZeE1v7T"
},
{
"id": "did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-2",
"type": "Ed25519VerificationKey2020",
"controller": "did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX",
"publicKeyMultibase": "zFXvzvY3jcmtXNK48azNRund96FBFtVK62MMPHZeE1v7T"
},
{
"id": "did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-3",
"type": "JsonWebKey2020",
"controller": "did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX",
"publicKeyJwk": {
"alg": "EdDSA",
"kty": "OKP",
"crv": "Ed25519",
"kid": "keys-3",
"x": "1_AZBSwM9m5V0JvdNHro1FzkHi38m50V6N_fR_DaGdo"
}
}
],
"authentication": [
"did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-1",
"did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-2",
"did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-3"
],
"assertionMethod": [
"did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-1",
"did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-2",
"did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-3"
],
"keyAgreement": [],
"capabilityInvocation": [
"did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-1",
"did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-2",
"did:infra:space:5GwqUaWxLMqZeC5bK7XgEQ1ZNL8y9YnxxvtVFSnoFtzRWfiX#keys-3"
],
"ATTESTS_IRI": null,
"service": []
}
};
const newSigSet = await InfraSS58.BBSPlus_createNewSigSet(did)
console.log({ newSigSet })
{
newSigSet: {
{
sigSet: {
sigParam: SignatureParamsG1 { value: [Object], label: undefined },
keyPair: KeypairG2 { sk: [BBSPlusSecretKey], pk: [BBSPlusPublicKeyG2] },
publicKey: {
bytes: '0xe9f99021d89e072454bd13eeb8bf08343282d2a25a842be02315c342ede11019cdfc9c3dd97408595b56cda4abaf980014355d7de9da92122619c320618d1fd932b4a2219c087e7783beec0517261716c5a5fa10999f621ef308dc017656e598',
paramsRef: undefined,
curveType: 'Bls12381'
},
messageCounter: 10,
label: undefined
}
};
// Create Sig Param
const sigParam = InfraSS58.BBSPlus_createSigParamsWithLabel(
MESSAGE_COUNTER_NUMBER,
'some-param-label'
)
// Add BBS+ Params
await infraSS58.bbsModule.addParams(sigParam)
// Get BBS+ Params
const param = await infraDID.bbsModule.getParams(PARAM_COUNTER_NUMBER)
// Get BBS+ Last Params
const lastParam = await infraDID.bbsModule.getLastParamsWritten()
// Remove BBS+ {arams
await infraDID.bbsModule.removeParams(PARAM_COUNTER_NUMBER)
// Add BBS+ Public Key
await infraDID.bbsModule.addPublicKey(SigSet.publicKey)
// Get BBS+ Public Key
const publicKey = await infraDID.bbsModule.getPublicKey(KEY_ID_NUMBER)
console.log({ publicKey })
// Remove BBS+ Public Key
await infraDID.bbsModule.removePublicKey(KEY_ID_NUMBER)
{
"publicKey": {
"bytes": "0xe9f99021d89e072454bd13eeb8bf08343282d2a25a842be02315c342ede11019cdfc9c3dd97408595b56cda4abaf980014355d7de9da92122619c320618d1fd932b4a2219c087e7783beec0517261716c5a5fa10999f621ef308dc017656e598",
"paramsRef": undefined,
"curveType": "Bls12381"
}
}
// Create Authorizer id
const authorizerId = infraSS58.trustModule.createNewAuthorizerId()
// Add Owner DID if want
infraSS58.trustModule.addPolicyOwner('some did')
// Add new Authorizer
await infraSS58.trustModule.registerAuthorizer(authorizerId)
// Get Authorizer
await infraSS58.trustModule.getAuthorizer(authorizerId)
// Remove Authorizer
await infraSS58.trustModule.unregisterAuthorizer(authorizerId)
// Add Issuer
await infraSS58.trustModule.addIssuer(authorizerId, issuerDID)
// Get Issuer
await infraSS58.trustModule.getIssuers(authorizerId, issuerDID)
// Remove Issuer
await infraSS58.trustModule.removeIssuer(authorizerId, issuerDID)
// Add Issuer
await infraSS58.trustModule.addVerifier(authorizerId, verifierDID)
// Get Issuer
await infraSS58.trustModule.getVerifiers(authorizerId, verifierDID)
// Remove Issuer
await infraSS58.trustModule.removeVerifier(authorizerId, verifierDID)
let schema = new Schema(newtworkId)
const someJSONSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
description: 'Schema Example',
type: 'object',
properties: {
id: { type: 'string' },
email: { type: 'string', format: 'email' },
alumniOf: { type: 'string' }
},
required: ['email', 'alumniOf'],
additionalProperties: false
}
schema = await schema.setJSONSchema(someJSONSchema)
console.log(schema.toJSON())
{
"id": "blob:infra:space:5EEmkHUNgMxL6435o7hfURpfNWtCdsVsvm5SD2y5oXmeUagM",
"schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Schema Example",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"alumniOf": {
"type": "string"
}
},
"required": ["email", "alumniOf"],
"additionalProperties": false
}
}
// Register Schema
await infraApi.blobModule.writeSchemaOnChainByBlob(schema.toBlob())
// or
await schema.writeToChain(infraApi)
// Get Schema
await infraApi.blobModule.getSchema(schemaId)
// or
await Schema.get(schemaId, infraApi)
const validationResult = await Schema.validateSchema(schema.schema)
console.log(validationResult)
{
"instance": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Schema Example",
"type": "object",
"properties": {
"id": ["Object"],
"email": ["Object"],
"alumniOf": ["Object"]
},
"required": ["email", "alumniOf"],
"additionalProperties": false
},
"schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://json-schema.org/draft-07/schema#",
"title": "Core schema meta-schema",
"definitions": {
"schemaArray": ["Object"],
"nonNegativeInteger": ["Object"],
"nonNegativeIntegerDefault0": ["Object"],
"simpleTypes": ["Object"],
"stringArray": ["Object"]
},
"type": ["object", "boolean"],
"properties": {
// -- snip --
},
"default": true
},
"options": {
"throwError": true,
"throwAll": "undefined"
},
"path": [],
"propertyPath": "instance",
"errors": [],
"throwError": true,
"throwFirst": "undefined",
"throwAll": "undefined",
"disableFormat": false
}
// Create new Registry id
const registryId = issuerApi.registryModule.createNewRegistryId()
// Register Registry
await issuerApi.registryModule.registerRegistry(registryId)
// Get Registry
await issuerApi.registryModule.getRegistry(registryId)
// Unregister Registry
await issuerApi.registryModule.unregisterRegistry(registryId)
vc = new VerifiableCredential(VC_ID)
vc.addContext('https://www.w3.org/2018/credentials/examples/v1')
vc.addContext('https://www.w3.org/2018/credentials/v1')
vc.addContext('https://schema.org')
vc.addType('VerifiableCredential')
vc.addType('VaccinationCredential')
vc.setSchema(schemaId)
vc.addSubject({
id: HOLDER_DID,
alumniOf: 'Example University',
email: 'test@test.com'
})
vc.setIssuanceDate('2021-04-02T10:11:41.000Z')
console.log(vc.toJSON())
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1",
"https://schema.org"
],
"id": "http://example.vc/credentials/123532",
"type": ["VerifiableCredential", "VaccinationCredential"],
"credentialSubject": [
{
"id": "did:infra:space:5DYKafDzPZSfJ5jmcAQK5X1TAShwbAPJJPzetUKv2XQuBBL3",
"alumniOf": "Example University",
"email": "test@test.com"
}
],
"issuanceDate": "2021-04-02T10:11:41.000Z",
"credentialSchema": {
"id": "blob:infra:space:5EEmkHUNgMxL6435o7hfURpfNWtCdsVsvm5SD2y5oXmeUagM",
"type": "JsonSchemaValidator2018"
}
}
const signedVC = await vc.sign(issuerInfraApi.didModule.getKeyDoc())
console.log(signedVC.toJSON())
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1",
"https://schema.org"
],
"id": "http://example.vc/credentials/123532",
"type": ["VerifiableCredential", "VaccinationCredential"],
"credentialSubject": [
{
"id": "did:infra:space:5DYKafDzPZSfJ5jmcAQK5X1TAShwbAPJJPzetUKv2XQuBBL3",
"alumniOf": "Example University",
"email": "test@test.com"
}
],
"issuanceDate": "2021-04-02T10:11:41.000Z",
"credentialSchema": {
"id": "blob:infra:space:5EEmkHUNgMxL6435o7hfURpfNWtCdsVsvm5SD2y5oXmeUagM",
"type": "JsonSchemaValidator2018"
},
"proof": {
"type": "EcdsaSecp256k1Signature2019",
"created": "2023-03-08T05:06:06Z",
"verificationMethod": "did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs#keys-1",
"proofPurpose": "assertionMethod",
"proofValue": "zAN1rKvtTouag9xApsQx1meZYG6bsDbMBN3dPiuBrsYJLKDzskZeZmRunwCjFGANBAsv7PfzbGuL7Ye9XPiDgWJbBXkSiRRAgs"
},
"issuer": "did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs"
}
const result: boolean = await signedVC.validateSchema(schema)
const verifyResult = await signedVC.verify(issuerApi)
console.log(verifyResult)
{
"verified": true,
"results": [
{
"proof": {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1",
"https://schema.org"
],
"type": "EcdsaSecp256k1Signature2019",
"created": "2023-03-08T05:06:06Z",
"verificationMethod": "did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs#keys-1",
"proofPurpose": "assertionMethod",
"proofValue": "zAN1rKvtTouag9xApsQx1meZYG6bsDbMBN3dPiuBrsYJLKDzskZeZmRunwCjFGANBAsv7PfzbGuL7Ye9XPiDgWJbBXkSiRRAgs"
},
"verified": true,
"verificationMethod": {
"@context": "https://w3id.org/security/v2",
"id": "did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs#keys-1",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": {
"id": "did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs",
"assertionMethod": [
"did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs#keys-1"
],
"authentication": [
"did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs#keys-1"
],
"capabilityInvocation": [
"did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs#keys-1"
],
"controller": "did:infra:space5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs",
"verificationMethod": "did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs#keys-1"
},
"publicKeyBase58": "rmwTxfjnpCM5wncDQ8k7RmCbzkY34BfTiKdw5QVNfRda"
},
"purposeResult": {
"valid": true,
"error": null
}
}
]
}
const revokeId = issuerApi.registryModule.getRevokeId(VC_ID)
// Revoke VC
await issuerApi.registryModule.revokeCredential(registryId, revokeId)
// Unrevoke VC
await issuerApi.registryModule.unrevokeCredential(registryId, revokeId)
// Check Revoke state
const isRevoked: boolean = await issuerApi.registryModule.getIsRevoked(
registryId,
revokeId
)
vp = new VerifiablePresentation(VP_ID)
vp.addContext('https://www.w3.org/2018/credentials/examples/v1')
vp.addType('CredentialManagerPresentation')
vp.setHolder(HOLDER_DID)
vp.addCredential(vc)
console.log(vp.toJSON())
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"verifiableCredential": [
{
"@context": ["Array"],
"id": "http://example.vc/credentials/123532",
"type": ["Array"],
"credentialSubject": ["Array"],
"issuanceDate": "2021-04-02T10:11:41.000Z",
"credentialSchema": ["Object"],
"proof": ["Object"],
"issuer": "did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs"
}
],
"id": "http://example.edu/credentials/2803",
"type": ["VerifiablePresentation", "CredentialManagerPresentation"],
"proof": null,
"holder": "did:infra:space:5DYKafDzPZSfJ5jmcAQK5X1TAShwbAPJJPzetUKv2XQuBBL3"
}
const signedVP = await vp.sign(holderInfraApi, DOMAIN_URL)
console.log(signedVP)
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"verifiableCredential": [
{
"@context": ["Array"],
"id": "http://example.vc/credentials/123532",
"type": ["Array"],
"credentialSubject": ["Array"],
"issuanceDate": "2021-04-02T10:11:41.000Z",
"credentialSchema": ["Object"],
"proof": ["Object"],
"issuer": "did:infra:space:5C8VZ28vrCbjsYeJrfNiy2TDSUDpCrRvya2RDy2KtbD6RFvs"
}
],
"id": "http://example.edu/credentials/2803",
"type": ["VerifiablePresentation", "CredentialManagerPresentation"],
"proof": {
"type": "Ed25519Signature2018",
"created": "2023-03-08T05:06:12Z",
"verificationMethod": "did:infra:space:5DYKafDzPZSfJ5jmcAQK5X1TAShwbAPJJPzetUKv2XQuBBL3#keys-1",
"proofPurpose": "authentication",
"challenge": "0xf805d8827cce9d4a49e1c30efd5f96a34dc726b7e50908d07e92f525be8bd068",
"domain": "example domain",
"proofValue": "zkt1MCJ6uZMHUS67uuAYzXJKtvymYh7oiFmzyXbPA2BCQME5T8NqqR6cw3vwu2dy2ZY82tSfJ45Hh8a5YjXmB766"
},
"holder": "did:infra:space:5DYKafDzPZSfJ5jmcAQK5X1TAShwbAPJJPzetUKv2XQuBBL3"
}
const verifyResult = await signedVP.verify(verifierInfraApi, DOMAIN_URL)
console.log(verifyResult)
{
"presentationResult": {
"verified": true,
"results": [
{
"proof": {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"type": "Ed25519Signature2018",
"created": "2023-07-20T23:47:06Z",
"verificationMethod": "did:infra:space:5CBKkEYcZ23fgmmhPbz2D7M1jZnLmHQJuJUrGqYKX7gbZoVU#keys-1",
"proofPurpose": "authentication",
"challenge": "0xdfb67fc9b7c2fb7e672c6590d16ef38a88eb66aad4e6403806ad664494d6d203",
"domain": "example domain",
"proofValue": "z2aTjMYC5SeWNnwunzEtTw89Q9BYRcx78jqsXcCoLMeEgE3FpTKHZtuXiGjGQbeDEDaBNkdQjymhcSiWht6atJiYC"
},
"verified": true,
"verificationMethod": {
"@context": "https://w3id.org/security/v2",
"id": "did:infra:space:5CBKkEYcZ23fgmmhPbz2D7M1jZnLmHQJuJUrGqYKX7gbZoVU#keys-1",
"type": "Ed25519VerificationKey2018",
"controller": {
/* snip */
},
"publicKeyBase58": "LhuSNWqUPB6ykSKN7QYZFZupTdG1eAQrtaW3VumvuUs"
},
"purposeResult": {
/* snip */
}
}
]
},
"credentialResults": [
{
"verified": true,
"results": [
{
"proof": {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://schema.org"
],
"type": "Ed25519Signature2018",
"created": "2023-07-20T23:46:54Z",
"verificationMethod": "did:infra:space:5FXBmypmPrqsp9pSrcJB3En2bdVYmA6T2C3aRXqjEMmLGBcR#keys-1",
"proofPurpose": "assertionMethod",
"proofValue": "z2TZV4YPEymjXp7CbpUtJD29ABXKRCRXhCyWfcZcg2foBkrab2h417tANL5DDEBumKC77hJsMkUKNL5KQZAe6KfAd"
},
"verified": true,
"verificationMethod": {
"@context": "https://w3id.org/security/v2",
"id": "did:infra:space:5FXBmypmPrqsp9pSrcJB3En2bdVYmA6T2C3aRXqjEMmLGBcR#keys-1",
"type": "Ed25519VerificationKey2018",
"controller": {
"id": "did:infra:space:5FXBmypmPrqsp9pSrcJB3En2bdVYmA6T2C3aRXqjEMmLGBcR",
"assertionMethod": [
/* snip */
],
"authentication": [
/* snip */
],
"capabilityInvocation": [
/* snip */
],
"controller": "did:infra:space5FXBmypmPrqsp9pSrcJB3En2bdVYmA6T2C3aRXqjEMmLGBcR",
"verificationMethod": [
"did:infra:space:5FXBmypmPrqsp9pSrcJB3En2bdVYmA6T2C3aRXqjEMmLGBcR#keys-1",
{
"id": "did:infra:space:5FXBmypmPrqsp9pSrcJB3En2bdVYmA6T2C3aRXqjEMmLGBcR#keys-2",
"type": "did:Ed25519VerificationKey2020",
"controller": "did:infra:space:5FXBmypmPrqsp9pSrcJB3En2bdVYmA6T2C3aRXqjEMmLGBcR"
},
{
"id": "did:infra:space:5FXBmypmPrqsp9pSrcJB3En2bdVYmA6T2C3aRXqjEMmLGBcR#keys-3",
"type": "did:JsonWebKey2020",
"controller": "did:infra:space:5FXBmypmPrqsp9pSrcJB3En2bdVYmA6T2C3aRXqjEMmLGBcR"
}
]
},
"publicKeyBase58": "BHsKsCtp9uovx1PefquegpVJtJJEEaR8A7agjeMRuSCs"
},
"purposeResult": {
"valid": true,
"error": null
}
}
],
"credentialId": "did:infra:space:5FDseiC76zPek2YYkuyenu4ZgxZ7PUWXt9d19HNB5CaQXt5U"
}
],
"verified": true
}
// Add BBS+ Public Key and Key Pair ID
issuerBBSSigSet = await InfraSS58.BBSPlus_createNewSigSet(issuer.did)
await issuerApi.bbsModule.addPublicKey(issuerBBSSigSet.publicKey)
await issuerApi.didModule.getDocument().then((doc) => {
issuerBBSSigSet.keyPair.id = doc.verificationMethod[1].id
})
// Create Verifiable Credential
vc = new VerifiableCredential(vcId)
vc.addContext('https://www.w3.org/2018/credentials/examples/v1')
vc.addContext('https://www.w3.org/2018/credentials/v1')
vc.addContext('https://schema.org')
vc.addType('VerifiableCredential')
vc.addType('VaccinationCredential')
// Different parts than normal Verifiable Credential
vc.setSchema(schema.toBBSSchema()) // Use toBBSSchema for schema,
// Use setSubject because BBSPlusPresentation does not allow arrays.
vc.setSubject({
id: holder.did,
alumniOf: 'Example University',
email: 'test@test.com'
})
vc.setIssuer(issuer.did)
bbsPlusPresentation = new BBSPlusPresentation()
// Sign / Issue BBSPlusCredential
const { id, type } = issuerBBSSigSet.keyPair
const issuerKeyDoc = issuerApi.getKeyDoc(
id,
issuer.did,
type,
issuerBBSSigSet.keyPair //use BBS+ keypair
)
const bbsPlusCredential = await bbsPlusPresentation.issueCredential(
issuerKeyDoc,
vc.toJSON()
)
// Add Presentation and reveal Attribute
const idx = await bbsPlusPresentation.addCredentialToPresent(
bbsPlusCredential,
{
resolver: issuerApi.Resolver
}
)
await bbsPlusPresentation.addCredentialSubjectAttributeToReveal(idx, [
'alumniOf'
])
const presentation = await bbsPlusPresentation.createPresentation()
console.log({ presentation })
{
"version": "0.0.1",
"nonce": null,
"spec": {
"credentials": [
{
"version": "0.1.0",
"schema": "{\"id\":\"data:application/json;charset=utf-8,%7B%22properties%22%3A%7B%22credentialSubject%22%3A%7B%22properties%22%3A%7B%22id%22%3A%7B%22type%22%3A%22string%22%7D%2C%22email%22%3A%7B%22type%22%3A%22string%22%2C%22format%22%3A%22email%22%7D%2C%22alumniOf%22%3A%7B%22type%22%3A%22string%22%7D%7D%2C%22type%22%3A%22object%22%7D%2C%22cryptoVersion%22%3A%7B%22type%22%3A%22string%22%7D%2C%22credentialSchema%22%3A%7B%22type%22%3A%22string%22%7D%2C%22%40context%22%3A%7B%22type%22%3A%22string%22%7D%2C%22id%22%3A%7B%22type%22%3A%22string%22%7D%2C%22issuanceDate%22%3A%7B%22type%22%3A%22string%22%7D%2C%22issuer%22%3A%7B%22type%22%3A%22string%22%7D%2C%22proof%22%3A%7B%22type%22%3A%22object%22%2C%22properties%22%3A%7B%22%40context%22%3A%7B%22type%22%3A%22array%22%2C%22items%22%3A%5B%7B%22type%22%3A%22object%22%2C%22properties%22%3A%7B%22sec%22%3A%7B%22type%22%3A%22string%22%7D%2C%22proof%22%3A%7B%22type%22%3A%22object%22%2C%22properties%22%3A%7B%22%40id%22%3A%7B%22type%22%3A%22string%22%7D%2C%22%40type%22%3A%7B%22type%22%3A%22string%22%7D%2C%22%40container%22%3A%7B%22type%22%3A%22string%22%7D%7D%7D%7D%7D%2C%7B%22type%22%3A%22string%22%7D%5D%7D%2C%22type%22%3A%7B%22type%22%3A%22string%22%7D%2C%22created%22%3A%7B%22type%22%3A%22string%22%7D%2C%22verificationMethod%22%3A%7B%22type%22%3A%22string%22%7D%2C%22proofPurpose%22%3A%7B%22type%22%3A%22string%22%7D%7D%7D%2C%22type%22%3A%7B%22type%22%3A%22string%22%7D%7D%2C%22%24schema%22%3A%22http%3A%2F%2Fjson-schema.org%2Fdraft-07%2Fschema%23%22%2C%22description%22%3A%22Schema%20Example%22%2C%22type%22%3A%22object%22%2C%22required%22%3A%5B%22email%22%2C%22alumniOf%22%5D%2C%22additionalProperties%22%3Afalse%7D\",\"type\":\"JsonSchemaValidator2018\",\"parsingOptions\":{\"useDefaults\":false,\"defaultMinimumInteger\":-4294967295,\"defaultDecimalPlaces\":0},\"version\":\"0.0.1\"}",
"revealedAttributes": {
"@context": "[\"https://www.w3.org/2018/credentials/v1\",\"https://www.w3.org/2018/credentials/examples/v1\",\"https://schema.org\"]",
"type": "[\"VerifiableCredential\",\"VaccinationCredential\"]",
"proof": {
"type": "Bls12381BBS+SignatureDock2022",
"verificationMethod": "did:infra:space:5EAFA4cfWyj6G7xxDWhAdCDcCTdh1tWenFzFaduTH8Mq2eCd#keys-2"
},
"credentialSubject": {
"alumniOf": "Example University"
}
}
}
],
"attributeEqualities": []
},
"attributeCiphertexts": {},
"proof": "2c4gy3tNNxy6T6LGDmq1H7ko976sBiHwCyff1w3qQTTcnSy5SG9a2FdTr4y1hGwzo5aSSbrkTYRFBLVc8UT1oQyzxL8ajy1W2Ah4x4RRrP6qfobc4oyHF25dbWuAJiPvHKL4JFMTb2mjw2Fv6RpjGf98dY9RB67C5tYySu5rxZPKu39jfSc2qs8vUakoDQASm6BgzWJ8sC23A8jsGnn4bWhNZQsjQAL5ZsKGHkKso9UcxWtDfFyy3VuBQqsa4gg2eveUeFVoEW63FCpkHTdaBZwVomxuaRTjtyxy1JyFutiY7jhoQC77xDY1jqWAfw7HV7EbwSC6dxqVBNxVgBQgrC1GDY7MpYHpPnCRQJWGSUeB793vvcQ5oaSWqMVEV2n4BVS5cv6mUSuvG57bSb1gY3q3QxcyFkKNF4rpca5GeqLboQq5e9UrjJy64kLjYqHi2aLbiK9ui8TQW6NMcoKqRaYo3QgqsFGSsyLcwyaNBAN6eNGmGBUq1G9xHhQ6sFDLepebJ28fkLrRvhpRCbwkCwauy52hUjp11wvQjooHACXRmU73cxBWCLEVh5u46sqdRWq2e3Lpiioin5daQiF3XyFySL4kMwLvyrV3PJth53Jyr45vFwGVxs6EnaSfLJKQ3uMfw3kfY84ckgj3WWPp5waDc9oroH6NLoSwyLtjmqrPqm6qV5EgAsKov24H95jpyp1XtMLsXW5wMsWizF6ABMLJVBqiNm8vQ9uWB6AbEzRRKF9bhN4e4LaZ2qzTkmofoiB3o9nQVuA9ncx2tbqynwi4XYRPsz6xMm4qxZiAhEwQA7jScndQ4dPLay4xK2zZWj5s8BYYCTeParhk52mNq7SBnaybp7i7EDiWY1ZPRUfXP75QwG7RkyMd2vmqBTWd5GzYpVtcFLkzPwoSRUk1irb9f4VNNVoCNvNyaAX6JR6Y5M9mF1WfB35sr7PJdNjmZBtCpS7YC5pNz2TySDeDoFjzyW4BbXAVgaeCpuMkugjYhTre8BBdqa7h79xQC4BayGtebVoPqRhozRuAhBqDNTAq6npT1B1Jc4itEj"
}
const verifyResult = await bbsPlusPresentation.verifyPresentation(
presentation,
{
resolver: issuerApi.Resolver
}
)
const holder = await InfraSS58.createNewSS58DIDSet('space')
// convert Ed25519 to X25519
const xPkU8a = CryptoHelper.edToX25519Pk(
hexToU8a(verifier.publicKey.toJSON()['Ed25519']),
'u8a'
)
const xPkJwk = CryptoHelper.edToX25519Pk(
hexToU8a(verifier.publicKey.toJSON()['Ed25519']),
'jwk'
)
const xPkKeyObject = CryptoHelper.edToX25519Pk(
hexToU8a(verifier.publicKey.toJSON()['Ed25519']),
'keyObject'
)
// convert Key Type
const obj2JWK = CryptoHelper.keyObject2JWK(xPkKeyObject as KeyObject)
const key2Jwk = CryptoHelper.key2JWK('X25519', xPkU8a as Uint8Array)
const jwk2Key = CryptoHelper.jwk2Key(xPkJwk as PublicJwk_ED).publicKey
const jwk2Obj = CryptoHelper.jwk2KeyObject(xPkJwk as PublicJwk_ED, 'public')
const verifierX25519KeyPair = CryptoHelper.edToX25519KeyPair(
hexToU8a(verifier.publicKey.toJSON()['Ed25519']),
hexToU8a(verifier.seed)
)
const holderX25519KeyPair = CryptoHelper.edToX25519KeyPair(
hexToU8a(holder.publicKey.toJSON()['Ed25519']),
hexToU8a(holder.seed)
)
const { publicKey: epk, privateKey: esk } =
CryptoHelper.generateX25519KeyPairObject()
const verifierSecretUsingESK = CryptoHelper.x25519ToEcdhesKeypair(
holderX25519KeyPair.publicKeyJWK,
esk
)
const holderSecretUsingEPK = CryptoHelper.x25519ToEcdhesKeypair(
epk,
holderX25519KeyPair.privateKeyJWK
)
const verifierDIDSharedKey = CryptoHelper.x25519ToEcdhesKeypair(
holderX25519KeyPair.publicKeyJWK,
verifierX25519KeyPair.privateKeyJWK
)
const holderDIDSharedKey = CryptoHelper.x25519ToEcdhesKeypair(
verifierX25519KeyPair.publicKeyJWK,
holderX25519KeyPair.privateKeyJWK
)
- according to the https://github.com/satoshilabs/slips/blob/master/slip-0010.md
- example is 1 depth of testvector 1
const seed = '0x000102030405060708090a0b0c0d0e0f'
const mk = await DerivedEd25519Key.getMasterKey(seed)
// expect(mk.path).toEqual('m');
// expect(u8aToHex(mk.chainCode)).toEqual('0x90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb');
// expect(u8aToHex(mk.sk)).toEqual('0x2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7');
// expect(u8aToHex(mk.pk)).toEqual('0xa4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed');
const dk = await DerivedEd25519Key.getDeriveKey(
mk.sk,
mk.chainCode,
mk.path,
0x80000000
)
// expect(dk.path).toEqual('m/0h');
// expect(u8aToHex(dk.chainCode)).toEqual('0x8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69');
// expect(u8aToHex(dk.sk)).toEqual('0x68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3');
// expect(u8aToHex(dk.pk)).toEqual('0x8c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c');