jsonld-signatures-merkleproof2019
Version:
A jsonld signature implementation to support MerkleProof2019 verification in Verifiable Credential context
245 lines (209 loc) • 6.59 kB
text/typescript
import keyto from '@trust/keyto';
import base64url from 'base64url';
import crypto from 'crypto';
import bs58 from 'bs58';
import secp256k1 from 'secp256k1';
import { Buffer as BufferPolyfill } from 'buffer';
import canonicalize from 'canonicalize';
// @ts-expect-error not a TS package
import * as multikey from '@digitalbazaar/ecdsa-multikey';
const buffer = typeof Buffer === 'undefined' ? BufferPolyfill : Buffer;
const compressedHexEncodedPublicKeyLength = 66;
/** Secp256k1 Private Key */
export interface ISecp256k1PrivateKeyJwk {
/** key type */
kty: string;
/** curve */
crv: string;
/** private point */
d: string;
/** public point */
x: string;
/** public point */
y: string;
/** key id */
kid: string;
}
/** Secp256k1 Public Key */
export interface ISecp256k1PublicKeyJwk {
/** key type */
kty: string;
/** curve */
crv: string;
/** public point */
x: string;
/** public point */
y: string;
/** key id */
kid: string;
}
/**
* Example
* ```js
* {
* kty: 'EC',
* crv: 'secp256k1',
* d: 'rhYFsBPF9q3-uZThy7B3c4LDF_8wnozFUAEm5LLC4Zw',
* x: 'dWCvM4fTdeM0KmloF57zxtBPXTOythHPMm1HCLrdd3A',
* y: '36uMVGM7hnw-N6GnjFcihWE3SkrhMLzzLCdPMXPEXlA',
* kid: 'JUvpllMEYUZ2joO59UNui_XYDqxVqiFLLAJ8klWuPBw'
* }
* ```
* See [rfc7638](https://tools.ietf.org/html/rfc7638) for more details on Jwk.
*/
export const getKid = (
jwk: ISecp256k1PrivateKeyJwk | ISecp256k1PublicKeyJwk
): string => {
const copy = { ...jwk } as any;
delete copy.d;
delete copy.kid;
delete copy.alg;
const digest = crypto
.createHash('sha256')
.update(canonicalize(copy))
.digest();
return base64url.encode(buffer.from(digest));
};
/** convert compressed hex encoded private key to jwk */
export const privateKeyJwkFromPrivateKeyHex = (privateKeyHex: string): ISecp256k1PrivateKeyJwk => {
const jwk: ISecp256k1PrivateKeyJwk = {
...keyto.from(privateKeyHex, 'blk').toJwk('private'),
crv: 'secp256k1'
};
const kid: string = getKid(jwk);
return {
...jwk,
kid
};
};
/** convert compressed hex encoded public key to jwk */
export const publicKeyJwkFromPublicKeyHex = (publicKeyHex: string): ISecp256k1PublicKeyJwk => {
let key: string = publicKeyHex;
if (publicKeyHex.length === compressedHexEncodedPublicKeyLength) {
const keyBin = secp256k1.publicKeyConvert(
buffer.from(publicKeyHex, 'hex'),
false
);
key = buffer.from(keyBin).toString('hex');
}
const jwk: ISecp256k1PublicKeyJwk = {
...keyto.from(key, 'blk').toJwk('public'),
crv: 'secp256k1'
};
const kid: string = getKid(jwk);
return {
...jwk,
kid
};
};
/** convert pem encoded private key to jwk */
export const privateKeyJwkFromPrivateKeyPem = (privateKeyPem: string): ISecp256k1PrivateKeyJwk => {
const jwk: ISecp256k1PrivateKeyJwk = {
...keyto.from(privateKeyPem, 'pem').toJwk('private'),
crv: 'secp256k1'
};
// console.log(jwk);
const kid: string = getKid(jwk);
return {
...jwk,
kid
};
};
/** convert pem encoded public key to jwk */
export const publicKeyJwkFromPublicKeyPem = (publicKeyPem: string): ISecp256k1PublicKeyJwk => {
const jwk: ISecp256k1PublicKeyJwk = {
...keyto.from(publicKeyPem, 'pem').toJwk('public'),
crv: 'secp256k1'
};
const kid = getKid(jwk);
return {
...jwk,
kid
};
};
/** convert jwk to hex encoded private key */
export const privateKeyHexFromJwk = (jwk: ISecp256k1PrivateKeyJwk): string =>
keyto
.from(
{
...jwk,
crv: 'K-256'
},
'jwk'
)
.toString('blk', 'private');
/** convert jwk to hex encoded public key */
export const publicKeyHexFromJwk = (jwk: ISecp256k1PublicKeyJwk): string => {
const uncompressedPublicKey: string = keyto
.from(
{
...jwk,
crv: 'K-256'
},
'jwk'
)
.toString('blk', 'public');
const compressed: string = secp256k1.publicKeyConvert(
buffer.from(uncompressedPublicKey, 'hex'),
true
);
return buffer.from(compressed).toString('hex');
};
/** convert jwk to binary encoded private key */
export const privateKeyUInt8ArrayFromJwk = (jwk: ISecp256k1PrivateKeyJwk): Buffer => {
const privateKeyHex: string = privateKeyHexFromJwk(jwk);
let asBuffer = buffer.from(privateKeyHex, 'hex');
let padding = 32 - asBuffer.length;
while (padding > 0) {
asBuffer = buffer.concat([buffer.from('00', 'hex'), asBuffer]);
padding--;
}
return asBuffer;
};
/** convert jwk to binary encoded public key */
export const publicKeyUInt8ArrayFromJwk = (jwk: ISecp256k1PublicKeyJwk): Buffer => {
const publicKeyHex: string = publicKeyHexFromJwk(jwk);
let asBuffer = buffer.from(publicKeyHex, 'hex');
let padding = 32 - asBuffer.length;
while (padding > 0) {
asBuffer = buffer.concat([buffer.from('00', 'hex'), asBuffer]);
padding--;
}
return asBuffer;
};
export const publicKeyUInt8ArrayFromMultibase = async (publicKeyMultibase): Promise<Buffer> => {
const pubKeyJwk: ISecp256k1PublicKeyJwk = await multikey.toJwk({ keyPair: publicKeyMultibase });
return publicKeyUInt8ArrayFromJwk(pubKeyJwk);
};
/** convert publicKeyHex to base58 */
export const publicKeyBase58FromPublicKeyHex = (publicKeyHex: string): string => {
return bs58.encode(buffer.from(publicKeyHex, 'hex'));
};
/** convert publicKeyHex to base58 */
export const privateKeyBase58FromPrivateKeyHex = (privateKeyHex: string): string => {
return bs58.encode(buffer.from(privateKeyHex, 'hex'));
};
export const privateKeyUInt8ArrayFromPrivateKeyBase58 = (
privateKeyBase58: string
): Uint8Array<ArrayBufferLike> => {
return bs58.decode(privateKeyBase58);
};
export const publicKeyUInt8ArrayFromPublicKeyBase58 = (
publicKeyBase58: string
): Uint8Array<ArrayBufferLike> => {
return bs58.decode(publicKeyBase58);
};
export const publicKeyHexFromPrivateKeyHex = (privateKeyHex: string): string => {
const publicKey = secp256k1.publicKeyCreate(
new Uint8Array(buffer.from(privateKeyHex, 'hex'))
);
return buffer.from(publicKey).toString('hex');
};
export const publicKeyJwkFromPublicKeyBase58 = (publicKeybase58: string): ISecp256k1PublicKeyJwk => {
const decodedPublicKeyAsHex: string = bs58.decode(publicKeybase58).toString();
return publicKeyJwkFromPublicKeyHex(decodedPublicKeyAsHex);
};
export const privateKeyJwkFromPrivateKeyBase58 = (privateKeyBase58: string): ISecp256k1PrivateKeyJwk => {
const decodedPrivateKeyAsHex: string = bs58.decode(privateKeyBase58).toString();
return privateKeyJwkFromPrivateKeyHex(decodedPrivateKeyAsHex);
};