import elliptic from 'elliptic'; import { createHash } from 'crypto'; import * as fs from 'fs'; export default class ECCKey { keyPair: elliptic.ec.KeyPair; constructor(keyPair: elliptic.ec.KeyPair) { this.keyPair = keyPair; } static generate(): ECCKey { const EC = new elliptic.ec('p256'); const keyPair = EC.genKeyPair(); return new ECCKey(keyPair); } static construct(privateKey: Buffer | string | number): ECCKey { if (Buffer.isBuffer(privateKey)) { privateKey = privateKey.toString('hex'); } else if (typeof privateKey === 'number') { privateKey = privateKey.toString(16); } const EC = new elliptic.ec('p256'); const keyPair = EC.keyFromPrivate(privateKey, 'hex'); return new ECCKey(keyPair); } static loads(data: string | Buffer): ECCKey { if (typeof data === 'string') { data = Buffer.from(data, 'base64'); } if (!Buffer.isBuffer(data)) { throw new Error(`Expecting Bytes or Base64 input, got ${data}`); } if (data.length !== 96 && data.length !== 32) { throw new Error( `Invalid data length. Expecting 96 or 32 bytes, got ${data.length}` ); } const privateKey = data.subarray(0, 32); return ECCKey.construct(privateKey); } static load(filePath: string): ECCKey { const data = fs.readFileSync(filePath); return ECCKey.loads(data); } dumps(): Buffer { return Buffer.concat([this.privateBytes(), this.publicBytes()]); } dump(filePath: string): void { fs.writeFileSync(filePath, this.dumps()); } getPoint(): { x: string; y: string } { const publicKey = this.keyPair.getPublic(); return { x: publicKey.getX().toString('hex'), y: publicKey.getY().toString('hex'), }; } privateBytes(): Buffer { const privateKey = this.keyPair.getPrivate(); return Buffer.from(privateKey.toArray('be', 32)); } privateSha256Digest(): Buffer { const hash = createHash('sha256'); hash.update(this.privateBytes()); return hash.digest(); } publicBytes(): Buffer { const publicKey = this.keyPair.getPublic(); const x = publicKey.getX().toArray('be', 32); const y = publicKey.getY().toArray('be', 32); return Buffer.concat([Buffer.from(x), Buffer.from(y)]); } publicSha256Digest(): Buffer { const hash = createHash('sha256'); hash.update(this.publicBytes()); return hash.digest(); } }