Package to create and validate signatures made with IDM devices and sessions.
$ npm install idm-signatures
This library is written in modern JavaScript and is published in both CommonJS and ES module transpiled variants. If you target older browsers please make sure to transpile accordingly.
Signatures in the DID ecosystem usually rely on Linked Data Signatures. We feel that the spec is still maturing and have the downside of not allowing to sign binary data directly. For those reasons and for the short-term, IDM relies on a signature scheme called IdmSignature
.
A IdmSignature
has the following shape:
{
didUrl: 'did:ipid:xxxxxx#public-key-id'
keyPath: 'm',
createdAt: 1560259756980,
value: 'de43432daa....'
}
The didUrl
references the DID and the (device) public key within the DID Document. The keyPath
specifies the derivation path for the actual key used for signing, which may be m
if it was the device key or m/<number>
for a session key. The key derivation is based on bip32.
To verify that a signature is valid:
- Fetch the DID Document associated with the
didUrl
- Check if the public key reference in the
didUrl
fragment is present there - Take the
publicExtendedKeyBase58
field of the public key and derive the child public key based on thekeyPath
(derivation path) - Check if the signature matches the data (as defined in RFC 6979) with the derived child public key
The IdmSignature
scheme makes signatures compact as they don't contain the actual public key contents, even for signatures made with session keys. In the future, we will provide a binary format to make them even more compact.
Signer:
import { createSigner } from 'idm-signatures';
const didUrl = 'did:ipid:xxxxx#idm-device-yyyyy';
const privateKeyPem = '-----BEGIN EC PRIVATE KEY-----...';
const sign = createSigner(didUrl, privateKeyPem);
await (async () => {
// Data may also be an ArrayBuffer or any TypedArray
const data = { foo: 'bar' };
const signature = await sign(data);
console.log('signature', signature);
// {
// didUrl: 'did:ipid:xxxxxx#public-key-id'
// keyPath: 'm',
// createdAt: 1560259756980,
// value: 'de43432daa....'
// }
})();
Verifier:
import resolveDid from 'did-resolver';
import { createVerifier } from 'idm-signatures';
const verify = createVerifier(resolveDid);
await (async () => {
// Data may also be an ArrayBuffer or any TypedArray
const data = { foo: 'bar' };
const signature = {
didUrl: 'did:ipid:xxxxxx#public-key-id'
keyPath: 'm',
createdAt: 1560259756980,
value: 'de43432daa....'
};
const result = await verify(data, signature);
console.log('result', result);
// {
// valid: false // ...or true
// error: // contains the error explaining why signature is not valid
// }
})();
Creates a signer for the specified didUrl
refering to a DID + public key (secp256k1)
. The privateKey
is the actual key that will be used to produce signatures, and keyPath
is the BIP32 derivation path used to determine the privateKey
(non hardened). The privateKey
format may be any of the ones supported by crypto-key-composer.
Returns a function that receives any data
to be signed:
async (data) => {};
When called, it returns a Promise to the IdmSignature
.
Creates a verifier. The resolveDid
is a function that takes a DID and resolves DID Documents:
async (did) => {};
Returns a function that receives the data
and the signature
to be checked:
async (data, signature) => {}
When called, it returns a Promise to an object with the following shape:
{
valid, // Boolean indicating if the signature is valid or not
error // When invalid, contains the error explaining the reason why the signature is not valid
}
Note that the Promise will fail if any operational error occurs, such as if the DID Document was unable to be resolved. In these scenarios, the signature might either be valid or invalid.. it just happens that we were unable to actually verify it.
$ npm test
$ npm test -- --watch # during development
Released under the MIT License.