UNPKG

@dwn-protocol/id-sdk

Version:

SDK for accessing the features and capabilities

111 lines (86 loc) 3.92 kB
import type { IDCrypto } from '../types/iddwn-crypto.js'; import type { BytesKeyPair } from '../types/crypto-key.js'; import { isBytesKeyPair } from '../utils.js'; import { Secp256k1 } from '../crypto-primitives/index.js'; import { CryptoKey, BaseEcdsaAlgorithm } from '../algorithms-api/index.js'; export class EcdsaAlgorithm extends BaseEcdsaAlgorithm { public readonly hashAlgorithms = ['SHA-256']; public readonly namedCurves = ['secp256k1']; public async generateKey(options: { algorithm: IDCrypto.EcdsaGenerateKeyOptions, extractable: boolean, keyUsages: IDCrypto.KeyUsage[] }): Promise<IDCrypto.CryptoKeyPair> { const { algorithm, extractable, keyUsages } = options; this.checkGenerateKey({ algorithm, keyUsages }); let keyPair: BytesKeyPair | undefined; let cryptoKeyPair: IDCrypto.CryptoKeyPair; switch (algorithm.namedCurve) { case 'secp256k1': { algorithm.compressedPublicKey ??= true; keyPair = await Secp256k1.generateKeyPair({ compressedPublicKey: algorithm.compressedPublicKey }); break; } // Default case not needed because checkGenerateKey() already validates the specified namedCurve is supported. } if (!isBytesKeyPair(keyPair)) { throw new Error('Operation failed to generate key pair.'); } cryptoKeyPair = { privateKey : new CryptoKey(algorithm, extractable, keyPair.privateKey, 'private', this.keyUsages.privateKey), publicKey : new CryptoKey(algorithm, true, keyPair.publicKey, 'public', this.keyUsages.publicKey) }; return cryptoKeyPair; } public async sign(options: { algorithm: IDCrypto.EcdsaOptions, key: IDCrypto.CryptoKey, data: Uint8Array }): Promise<Uint8Array> { const { algorithm, key, data } = options; this.checkAlgorithmOptions({ algorithm }); // The key's algorithm must match the algorithm implementation processing the operation. this.checkKeyAlgorithm({ keyAlgorithmName: key.algorithm.name }); // The key must be a private key. this.checkKeyType({ keyType: key.type, allowedKeyType: 'private' }); // The key must be allowed to be used for sign operations. this.checkKeyUsages({ keyUsages: ['sign'], allowedKeyUsages: key.usages }); let signature: Uint8Array; const keyAlgorithm = key.algorithm as IDCrypto.EcdsaGenerateKeyOptions; // Type guard. switch (keyAlgorithm.namedCurve) { case 'secp256k1': { signature = await Secp256k1.sign({ hash: algorithm.hash, key: key.material, data }); break; } default: throw new TypeError(`Out of range: '${keyAlgorithm.namedCurve}'. Must be one of '${this.namedCurves.join(', ')}'`); } return signature; } public async verify(options: { algorithm: IDCrypto.EcdsaOptions; key: IDCrypto.CryptoKey; signature: Uint8Array; data: Uint8Array; }): Promise<boolean> { const { algorithm, key, signature, data } = options; this.checkAlgorithmOptions({ algorithm }); // The key's algorithm must match the algorithm implementation processing the operation. this.checkKeyAlgorithm({ keyAlgorithmName: key.algorithm.name }); // The key must be a public key. this.checkKeyType({ keyType: key.type, allowedKeyType: 'public' }); // The key must be allowed to be used for verify operations. this.checkKeyUsages({ keyUsages: ['verify'], allowedKeyUsages: key.usages }); let isValid: boolean; const keyAlgorithm = key.algorithm as IDCrypto.EcdsaGenerateKeyOptions; // Type guard. switch (keyAlgorithm.namedCurve) { case 'secp256k1': { isValid = await Secp256k1.verify({ hash: algorithm.hash, key: key.material, signature, data }); break; } default: throw new TypeError(`Out of range: '${keyAlgorithm.namedCurve}'. Must be one of '${this.namedCurves.join(', ')}'`); } return isValid; } }