DID Specification | DID Registry Contracts
This library is an implementation of LACChain DID Method in NodeJS. It provides the necessary methods and functions to interact with a DID and resolve a DID Document without the need to directly call the smart contracts.
- NodeJS > 14.4
Just install the package from NPM repository.
npm install @lacchain/did
And import it in your NodeJS project.
import { DID, DIDRecoverable, Resolver } from '@lacchain/did'
- The
DID(config={})
andDIDRecoverable(config={})
classes can be used to create and update a DID Document. Where config is an object that can have the following properties:
Name | Type | Required | Description |
---|---|---|---|
registry | String | true | The address of DID Registry |
rpcUrl | String | true | The URL of Ethereum RPC API |
network | String | true | The name of the network (ie: main, test) |
address | String | false | The address of a DID. If this is set a read-only LACChainDID Object will be created unless you provide controllerPrivateKey property |
controllerPrivateKey | String | false | The private key of the DID address. If you set the controller private key you must also provide the DID address |
If you don't provide the address
and controllerPrivateKey
, the class will generate one automatically.
-
The
Resolver(config={})
class can be used to resolve a DID Document from the DID identifier.Where config is an object that can have the following properties:
Name | Type | Required | Description |
---|---|---|---|
networks | Array | true | An array of network config objects to use for resolving DID Document, where each item is an object with the following properties: - name: The network name - registry: The address of DID Registry - rpcUrl: The URL of Ethereum RPC API |
mode | String | false | The resolving DID Document mechanism: explicit, implicit (default) |
Depending on the functionalities that you want to use, there are two types of classes to operate a DID
- Regular DID: It is the basic DID that allows multiple controllers and automatic key rotation.
const did = new DID( {
registry: '0xbDa1238272FDA6888556449Cb77A87Fc8205E8ba',
rpcUrl: 'https://writer.lacchain.net',
network: 'main'
} );
- Recoverable DID: It is the advanced DID that allows, in addition to the functions of a basic DID, key recovery.
const did = new DIDRecoverable( {
registry: '0xbDa1238272FDA6888556449Cb77A87Fc8205E8ba',
rpcUrl: 'https://writer.lacchain.net',
network: 'main'
} );
If you are planning to interact with the LACChain / LACNET Gas Model, just specify the nodeAddress & expiration parameters in the config object:
const did = new DID( {
registry: '0xB9D96a0bDd52FE48fC504d0BB28AF51091275C81',
rpcUrl: 'http://34.69.22.82',
nodeAddress: '0xd00e6624a73f88b39f82ab34e8bf2b4d226fd768',
expiration: 1736394529,
network: 'main'
} );
Or,
const did = new DIDRecoverable( {
registry: '0xB9D96a0bDd52FE48fC504d0BB28AF51091275C81',
rpcUrl: 'http://34.69.22.82',
nodeAddress: '0xd00e6624a73f88b39f82ab34e8bf2b4d226fd768',
expiration: 1736394529,
network: 'main'
} );
Note: Use the same parameters in the resolver
class
The basic properties of a DID are:
console.log( did.id ); // did:lac:main:0x47adc0faa4f6eb42b499187317949ed99e77ee85
console.log( did.address ); // 0x47adc0faa4f6eb42b499187317949ed99e77ee85
Before change to another controller, it is necessarily to add it first by invoking the next function:
await did.addController( '0x4a5a6460d00c4d8c2835a3067f53fb42021d5bb9' );
It is also possible to remove an extra controller registered with two conditions:
- The controller to remove cannot be the current controller
- Must remain at least one controller
await did.removeController( '0x4a5a6460d00c4d8c2835a3067f53fb42021d5bb9' );
Once the new controller has been registered, it can be changed by invoking the following function:
await did.changeController( '0x4a5a6460d00c4d8c2835a3067f53fb42021d5bb9' );
The current controller is the only one that has the permissions to execute changes on the DID (there can only be one current controller), that is why when changing the controller, it is necessary to specify to the DID class which is the controller's private key to that can continue to sign transactions to the network. To specify the private key of current controller, just call the next function:
await did.setControllerKey( PRIVATE_KEY_HEX );
Note: The private key must be in hex format without 0x prefix.
To get the current active controller, just call:
const currentController = await did.getController(); // 0x4a5a6460d00c4d8c2835a3067f53fb42021d5bb9
The function to get all the controllers registered for the DID will return an array of controllers addresses:
const controllers = await did.getController(); // ['0x47adc0faa4f6eb42b499187317949ed99e77ee85', '0x4a5a6460d00c4d8c2835a3067f53fb42021d5bb9']
According to the W3C specification, it is possible to add Verification Methods to a DID that have a general purpose, for this it is enough to invoke the following function:
await did.addVerificationMethod({
type: 'vm',
algorithm: 'esecp256k1rm',
encoding: 'hex',
publicKey: PUBLIC_KEY_HEX,
controller: PUBLIC_KEY_CONTROLLER,
expiration: 31536000 // default: 31536000
});
Where type can (according to the W3C DID Verification Relationships):
- vm: Generic Verification Method
- auth: Authentication Method
- asse: Assertion Method
- keya: Key Agreement
- dele: Delegation Capability
- invo: Invocation Capability
And algorithm can be (see W3C DID Verification Method Types):
- jwk: JsonWebKey2020,
- esecp256k1vk: EcdsaSecp256k1VerificationKey2019,
- esecp256k1rm: EcdsaSecp256k1RecoveryMethod2020,
- edd25519vk: Ed25519VerificationKey2018,
- gpgvk: GpgVerificationKey2020,
- rsavk: RsaVerificationKey2018,
- x25519ka: X25519KeyAgreementKey2019,
- ssecp256k1vk: SchnorrSecp256k1VerificationKey2019
And encoding support the following formats (according to the W3C DID Verification Method Properties):
- hex: Hexadecimal
- base64: Base 64
- base58: Base 58
The publicKey represents the Public Key itself in the encoding format specified.
And the controller must be the Public Key Controller (String), usually a DID. Can be even of other DID method.
The expiration is the expiration time (in seconds) ahead of current time. This field is optional, and the default expiration time is: 31536000
In order to facilitate the registration of Verification Methods according to the type of Relationship, it is possible to use specific functions for this purpose.
- To add an Authentication Method
await did.addAuthenticationMethod( {
algorithm: 'esecp256k1rm',
encoding: 'hex',
publicKey: PUBLIC_KEY_HEX,
controller: PUBLIC_KEY_CONTROLLER
} );
- To add an Assertion Method
await did.addAssertionMethod( {
algorithm: 'esecp256k1rm',
encoding: 'hex',
publicKey: PUBLIC_KEY_HEX,
controller: PUBLIC_KEY_CONTROLLER
} );
- To add a Key Agreement
await did.addKeyAgreement( {
algorithm: 'x25519ka',
encoding: 'hex',
publicKey: PUBLIC_KEY_HEX,
controller: PUBLIC_KEY_CONTROLLER
} );
- To add a Delegation Capability
await did.addCapabilityDelegation( {
algorithm: 'edd25519vk',
encoding: 'hex',
publicKey: PUBLIC_KEY_HEX,
controller: PUBLIC_KEY_CONTROLLER
} );
- To add an Invocation Capability
await did.addCapabilityInvocation( {
algorithm: 'edd25519vk',
encoding: 'hex',
publicKey: PUBLIC_KEY_HEX,
controller: PUBLIC_KEY_CONTROLLER
} );
It is also possible to have a Verification Method (VM) associated with more than one relationship, that is why once a VM is registered it is possible to bind it to a specific relationship using the VM id.
Depending on the relationship it is possible to bind a VM:
- To bind an Authentication Method
await did.bindAuthenticationMethod( VERIFICATION_METHOD_ID );
- To bind an Assertion Method
await did.bindAssertionMethod( VERIFICATION_METHOD_ID );
- To bind a Key Agreement
await did.bindKeyAgreement( VERIFICATION_METHOD_ID );
- To bind a Delegation Capability
await did.bindCapabilityDelegation( VERIFICATION_METHOD_ID );
- To bind an Invocation Capability
await did.bindCapabilityInvocation( VERIFICATION_METHOD_ID );
All VMs have an expiration time, however, it is possible to revoke them early using the following function:
await did.revokeVerificationMethod( {
type: 'vm',
algorithm: 'esecp256k1rm',
encoding: 'hex',
publicKey: PUBLIC_KEY_HEX,
controller: PUBLIC_KEY_CONTROLLER
} );
It is important to provide all properties of the VM to revoke (except the expiration time), that is because they conform the key of the VM.
To add a Service to the DID, just provide the type and endpoint fields as Strings.
await did.addService( {
type: 'mailbox',
endpoint: 'https://mailbox.lacchain.net'
} );
To enable Automatic Key Rotation functionality, it is necessarily to comply with the following condition:
- Add at least el minimum number of controllers specified in the DID Registry
- The key rotation time (in seconds) must be greater or equal that the minimum rotation time specified in the DID Registry
await did.enableKeyRotation( ROTATION_TIME_SECONDS );
To disable this functionality, just call:
await did.disableKeyRotation();
This functionality will only be available if the DIDRecoverable class is instantiated and also the registry points to the Smart Contract that supports it.
await did.recover( CONTROLLER_ADDRESS, CONTROLLER_PRIVATE_KEY );
Where:
- CONTROLLER_ADDRESS: The controller address that you will prove ownership (Needs to be previously registered in the DID)
- CONTROLLER_PRIVATE_KEY: Is the controller private key that you will prove ownership (in hex format without 0x prefix)
Note: The recover function needs to be called n/2 + 1
times.
The unit test will be performed in the LACChain Main Network. If you want to change that, edit directly the files in the /test directory
$ npm install
$ npm test