@dwn-protocol/id-sdk
Version:
SDK for accessing the features and capabilities
110 lines (84 loc) • 3.72 kB
text/typescript
import type { IDCrypto } from '../types/iddwn-crypto.js';
import type { BytesKeyPair } from '../types/crypto-key.js';
import { isBytesKeyPair } from '../utils.js';
import { Ed25519 } from '../crypto-primitives/index.js';
import { CryptoKey, BaseEdDsaAlgorithm } from '../algorithms-api/index.js';
export class EdDsaAlgorithm extends BaseEdDsaAlgorithm {
public readonly namedCurves = ['Ed25519', 'Ed448'];
public async generateKey(options: {
algorithm: IDCrypto.EdDsaGenerateKeyOptions,
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 'Ed25519': {
keyPair = await Ed25519.generateKeyPair();
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.EdDsaOptions,
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.EdDsaGenerateKeyOptions; // Type guard.
switch (keyAlgorithm.namedCurve) {
case 'Ed25519': {
signature = await Ed25519.sign({ 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.EdDsaOptions;
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.EdDsaGenerateKeyOptions; // Type guard.
switch (keyAlgorithm.namedCurve) {
case 'Ed25519': {
isValid = await Ed25519.verify({ key: key.material, signature, data });
break;
}
default:
throw new TypeError(`Out of range: '${keyAlgorithm.namedCurve}'. Must be one of '${this.namedCurves.join(', ')}'`);
}
return isValid;
}
}