UNPKG

@xmr-core/xmr-crypto-utils

Version:

Core crypto operations for Monero and implementations and interfaces of various hardware devices for creating Monero transactions securely

340 lines (293 loc) 8.07 kB
import { HWDevice, IAccountKeys, PublicAddress, DeviceMode, PublicKey, KeyDerivation, ISubaddressIndex, PublicSpendKey, SecretKey, Key, EcScalar, Hash8, KeyV, CtKeyV, } from "./types"; import * as crypto from "../crypto-ops"; import { cn_fast_hash } from "@xmr-core/xmr-fast-hash"; import { secret_key_to_public_key, generate_keys, random_keypair, } from "../key-utils"; import { KeyPair, Commit } from "../types"; import { encrypt_payment_id } from "../pid"; export class DefaultDevice implements HWDevice { private name: string; constructor() { this.name = ""; } /* ======================================================================= */ /* SETUP/TEARDOWN */ /* ======================================================================= */ // #region SETUP/TEARDOWN public set_name(name: string) { this.name = name; return true; } public get_name() { return this.name; } public async set_mode(_mode: DeviceMode) { return true; } // #endregion SETUP/TEARDOWN /* ======================================================================= */ /* WALLET & ADDRESS */ /* ======================================================================= */ // #region WALLET & ADDRESS public async get_public_address(): Promise<PublicAddress> { return this.notSupported(); } public async get_secret_keys() { return this.notSupported(); } public async generate_chacha_key(_keys: IAccountKeys) { return this.notSupported(); } // #endregion WALLET & ADDRESS /* ======================================================================= */ /* SUB ADDRESS */ /* ======================================================================= */ // #region SUB ADDRESS public async derive_subaddress_public_key( out_key: PublicKey, derivation: KeyDerivation, output_index: number, ): Promise<PublicKey> { return crypto.derivation.derive_subaddress_public_key( out_key, derivation, output_index, ); } public async get_subaddress_spend_public_key( keys: IAccountKeys, index: ISubaddressIndex, ): Promise<PublicKey> { if (index.isZero()) { return keys.m_account_address.spend_public_key; } return this.notSupported(); } public async get_subaddress_spend_public_keys( _keys: IAccountKeys, _account: number, _begin: number, _end: number, ): Promise<PublicSpendKey[]> { return this.notSupported(); } public async get_subaddress( keys: IAccountKeys, index: ISubaddressIndex, ): Promise<PublicAddress> { if (index.isZero()) { return keys.m_account_address; } return this.notSupported(); } public async get_subaddress_secret_key( _sec: SecretKey, _index: ISubaddressIndex, ): Promise<SecretKey> { return this.notSupported(); } /* ======================================================================= */ /* DERIVATION & KEY */ /* ======================================================================= */ // #region DERIVATION & KEY public async put_key( _privViewKey: string, _pubViewKey: string, _privSpendKey: string, _pubSpendKey: string, _b58PubKey: string, ) { return true; } public async verify_keys( secretKey: SecretKey, publicKey: PublicKey, ): Promise<boolean> { const calculatedPubKey = secret_key_to_public_key(secretKey); return calculatedPubKey === publicKey; } public async scalarmultKey(P: Key, a: Key): Promise<Key> { return crypto.primitive_ops.ge_scalarmult(P, a); } public async scalarmultBase(a: Key): Promise<Key> { return crypto.primitive_ops.ge_scalarmult_base(a); } public async sc_secret_add(a: SecretKey, b: SecretKey): Promise<SecretKey> { return crypto.primitive_ops.sc_add(a, b); } public async generate_keys(recoveryKey?: SecretKey): Promise<KeyPair> { if (recoveryKey) { return generate_keys(recoveryKey); } return random_keypair(); } public async generate_key_derivation( pub: PublicKey, sec: SecretKey, ): Promise<KeyDerivation> { return crypto.derivation.generate_key_derivation(pub, sec); } public async conceal_derivation( derivation: KeyDerivation, _tx_pub_key: PublicKey, _additional_tx_pub_keys: PublicKey[], _main_derivation: KeyDerivation, _additional_derivations: KeyDerivation[], ): Promise<PublicKey> { return derivation; } public async derivation_to_scalar( derivation: KeyDerivation, output_index: number, ): Promise<EcScalar> { return crypto.derivation.derivation_to_scalar(derivation, output_index); } public async derive_secret_key( derivation: KeyDerivation, output_index: number, sec: SecretKey, ): Promise<SecretKey> { return crypto.derivation.derive_secret_key( derivation, output_index, sec, ); } public async derive_public_key( derivation: KeyDerivation, output_index: number, pub: PublicKey, ): Promise<PublicKey> { return crypto.derivation.derive_public_key( derivation, output_index, pub, ); } public async generate_key_image( pub: PublicKey, sec: SecretKey, ): Promise<PublicKey> { return crypto.key_image.generate_key_image(pub, sec); } public async secret_key_to_public_key(sec: SecretKey): Promise<PublicKey> { return secret_key_to_public_key(sec); } /* ======================================================================= */ /* TRANSACTION */ /* ======================================================================= */ // #region TRANSACTION public async open_tx(): Promise<SecretKey> { const { sec } = random_keypair(); return sec; } public async encrypt_payment_id( paymentId: string, public_key: string, secret_key: string, ): Promise<Hash8> { return encrypt_payment_id(paymentId, public_key, secret_key); } public async decrypt_payment_id( paymentId: string, public_key: string, secret_key: string, ): Promise<Hash8> { return this.encrypt_payment_id(paymentId, public_key, secret_key); } public async ecdhEncode( unmasked: Commit, sharedSec: SecretKey, ): Promise<Commit> { return crypto.rctOps.encode_ecdh(unmasked, sharedSec); } public async ecdhDecode( masked: Commit, sharedSec: SecretKey, ): Promise<Commit> { return crypto.rctOps.decode_ecdh(masked, sharedSec); } public add_output_key_mapping( _Aout: PublicKey, _Bout: PublicKey, _is_subaddress: boolean, _real_output_index: number, _amount_key: Key, _out_eph_public_key: PublicKey, ): boolean { return true; } public async mlsag_prehash( _blob: string, _inputs_size: number, _outputs_size: number, hashes: KeyV, _outPk: CtKeyV, ): Promise<Key> { return cn_fast_hash(hashes.join("")); } public async mlsag_prepare( H: Key, xx: Key, ): Promise<{ a: Key; aG: Key; aHP: Key; II: Key }>; public async mlsag_prepare(): Promise<{ a: Key; aG: Key }>; public async mlsag_prepare(H?: Key, xx?: Key) { const { sec: a, pub: aG } = random_keypair(); if (H && xx) { const aHP = await this.scalarmultKey(H, a); const II = await this.scalarmultKey(H, xx); return { a, aG, aHP, II }; } else { return { a, aG }; } } public async mlsag_hash(toHash: KeyV): Promise<Key> { return crypto.hash_ops.hash_to_scalar(toHash.join("")); } public async mlsag_sign( c: Key, xx: KeyV, alpha: KeyV, rows: number, dsRows: number, ss: KeyV, ): Promise<KeyV> { if (dsRows > rows) { throw Error("dsRows greater than rows"); } if (xx.length !== rows) { throw Error("xx size does not match rows"); } if (alpha.length !== rows) { throw Error("alpha size does not match rows"); } for (let j = 0; j < rows; j++) { ss[j] = crypto.primitive_ops.sc_mulsub(c, xx[j], alpha[j]); } return ss; } public async close_tx(): Promise<boolean> { return true; } private notSupported(): any { throw Error("This device function is not supported"); } }