2024-01-23 18:40:34 +01:00

89 lines
2.8 KiB
TypeScript

import { Community } from '@entity/Community'
// https://www.npmjs.com/package/bip32-ed25519
import { LogError } from '@/server/LogError'
import { toPublic, derivePrivate, sign, verify, generateFromSeed } from 'bip32-ed25519'
import { Mnemonic } from './Mnemonic'
import { SignaturePair } from './proto/3_3/SignaturePair'
/**
* Class Managing Key Pair and also generate, sign and verify signature with it
*/
export class KeyPair {
private _publicKey: Buffer
private _chainCode: Buffer
private _privateKey: Buffer
/**
* @param input: Mnemonic = Mnemonic or Passphrase which work as seed for generating algorithms
* @param input: Buffer = extended private key, returned from bip32-ed25519 generateFromSeed or from derivePrivate
* @param input: Community = community entity with keys loaded from db
*
*/
public constructor(input: Mnemonic | Buffer | Community) {
if (input instanceof Mnemonic) {
this.loadFromExtendedPrivateKey(generateFromSeed(input.seed))
} else if (input instanceof Buffer) {
this.loadFromExtendedPrivateKey(input)
} else if (input instanceof Community) {
if (!input.rootPrivkey || !input.rootChaincode || !input.rootPubkey) {
throw new LogError('missing private key or chaincode or public key in commmunity entity')
}
this._privateKey = input.rootPrivkey
this._publicKey = input.rootPubkey
this._chainCode = input.rootChaincode
}
}
/**
* copy keys to community entity
* @param community
*/
public fillInCommunityKeys(community: Community) {
community.rootPubkey = this._publicKey
community.rootPrivkey = this._privateKey
community.rootChaincode = this._chainCode
}
private loadFromExtendedPrivateKey(extendedPrivateKey: Buffer) {
if (extendedPrivateKey.length !== 96) {
throw new LogError('invalid extended private key')
}
this._privateKey = extendedPrivateKey.subarray(0, 64)
this._chainCode = extendedPrivateKey.subarray(64, 96)
this._publicKey = toPublic(extendedPrivateKey).subarray(0, 32)
}
public getExtendPrivateKey(): Buffer {
return Buffer.concat([this._privateKey, this._chainCode])
}
public getExtendPublicKey(): Buffer {
return Buffer.concat([this._publicKey, this._chainCode])
}
public get publicKey(): Buffer {
return this._publicKey
}
public derive(path: number[]): KeyPair {
const extendedPrivateKey = this.getExtendPrivateKey()
return new KeyPair(
path.reduce(
(extendPrivateKey: Buffer, node: number) => derivePrivate(extendPrivateKey, node),
extendedPrivateKey,
),
)
}
public sign(message: Buffer): Buffer {
return sign(message, this.getExtendPrivateKey())
}
public static verify(message: Buffer, { signature, pubKey }: SignaturePair): boolean {
return verify(message, signature, pubKey)
}
}