morphit/node_modules/@beblurt/dblurt/lib/crypto.js
Morphit Team 24240cef4c
Some checks failed
morphit-release / Build + publish release tarball (push) Has been cancelled
Reputation flags clearable across all four signals; names and avatars stop vanishing
2026-07-23 14:28:04 -07:00

625 lines
24 KiB
JavaScript

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.cryptoUtils = exports.encodeMemo = exports.decodeMemo = exports.Signature = exports.PrivateKey = exports.PublicKey = void 0;
/**
* @file Blurt crypto helpers.
* @author BeBlurt <https://beblurt.com/@beblurt>
* @description adaptation from Johan Nordberg <code@johan-nordberg.com> crypto helpers.
* @license
* Copyright (c) 2017 Johan Nordberg. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You acknowledge that this software is not designed, licensed or intended for use
* in the design, construction, operation or maintenance of any military facility.
*/
const assert_1 = __importDefault(require("assert"));
const bs58_1 = __importDefault(require("bs58"));
const aesjs = require('aes-js');
const nobleSha2 = require('@noble/hashes/sha2');
const nobleLegacy = require('@noble/hashes/legacy');
// eslint-disable-next-line import/order
const ByteBuffer = require('bytebuffer/dist/bytebuffer');
const Long = ByteBuffer.Long;
const secp256k1 = __importStar(require("@noble/secp256k1"));
const nobleHmac = require('@noble/hashes/hmac');
secp256k1.utils.hmacSha256Sync = (key, ...messages) => (nobleHmac.hmac(nobleSha2.sha256, key, secp256k1.utils.concatBytes(...messages)));
const errors_1 = require("./errors");
const serializer_1 = require("./chain/serializer");
const deserializer_1 = require("./chain/deserializer");
const client_1 = require("./client");
const utils_1 = require("./utils");
/** Network id used in WIF-encoding */
const NETWORK_ID = Buffer.from([0x80]);
/** Regexp for a graphene account */
const regExpAccount = /^(?=.{3,16}$)[a-z][0-9a-z\-]{1,}[0-9a-z]([\.][a-z][0-9a-z\-]{1,}[0-9a-z]){0,}$/;
/** Regexp for a graphene account with @ */
const regExpAtAccount = /^@(?=.{3,16}$)[a-z][0-9a-z\-]{1,}[0-9a-z]([\.][a-z][0-9a-z\-]{1,}[0-9a-z]){0,}$/;
/** From Buffer to Uint8Array */
const toUint8Array = (buf) => {
const ab = new ArrayBuffer(buf.length);
const view = new Uint8Array(ab);
for (let i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return view;
};
/** From ArrayBuffer to Buffer */
const toBuffer = (ab) => {
const buf = Buffer.alloc(ab.byteLength);
const view = new Uint8Array(ab);
for (let i = 0; i < buf.length; ++i) {
buf[i] = view[i];
}
return buf;
};
/**
* Converts a string, number or Long to a ByteBuffer object.
*
* @param o - The value to be converted.
* @returns A ByteBuffer object.
* @throws An error if the input is not a string, number or Long.
*/
const toByteBuffer = (o) => {
if (typeof o === 'string') {
return Long.fromString(o);
}
else if (typeof o === 'number') {
return Long.fromNumber(o);
}
else if (o instanceof ByteBuffer.Long) {
return o;
}
else {
throw new Error('Input is not a string, number or Long');
}
};
/**
* Generates a unique 64 bit unsigned number string. Being time based,
* this is careful to never choose the same nonce twice. This value could
* be recorded in the blockchain for a long time.
* @returns The unique nonce.
*/
let unique_nonce_entropy = Math.floor(Math.random() * 0xFFFF);
const uniqueNonce = () => {
let long = BigInt(Date.now());
const entropy = ++unique_nonce_entropy % 0xFFFF;
if (entropy === 0) {
const last = Number(long >> BigInt(16));
const now = Date.now();
if (now <= last) {
long += BigInt(1);
}
unique_nonce_entropy = 0;
}
long = (long << BigInt(16)) | BigInt(entropy);
return long.toString(16).padStart(16, '0');
};
/** Return ripemd160 hash of input */
const ripemd160 = (input) => Buffer.from(nobleLegacy.ripemd160(hashInput(input)));
/** Return sha256 hash of input */
const sha256 = (input) => Buffer.from(nobleSha2.sha256(hashInput(input)));
/** Return sha512 hash of input */
const sha512 = (input) => Buffer.from(nobleSha2.sha512(hashInput(input)));
/** Normalize input for hash libraries. */
const hashInput = (input) => typeof input === 'string' ? Buffer.from(input) : input;
/** PKCS#7 block padding used by Node's createCipheriv autoPadding default. */
const pkcs7Pad = (input, blockSize = 16) => {
const remainder = input.length % blockSize;
const padding = remainder === 0 ? blockSize : blockSize - remainder;
return Buffer.concat([Buffer.from(input), Buffer.alloc(padding, padding)]);
};
/** Remove PKCS#7 block padding produced by AES-CBC encryption. */
const pkcs7Unpad = (input, blockSize = 16) => {
(0, assert_1.default)(input.length > 0 && input.length % blockSize === 0, 'invalid pkcs7 payload length');
const padding = input[input.length - 1];
(0, assert_1.default)(padding > 0 && padding <= blockSize, 'invalid pkcs7 padding');
for (let i = input.length - padding; i < input.length; i++) {
(0, assert_1.default)(input[i] === padding, 'invalid pkcs7 padding');
}
return Buffer.from(input).slice(0, input.length - padding);
};
/** Encrypt AES-256-CBC with PKCS#7 padding. */
const aes256CbcEncrypt = (key, iv, input) => {
const cipher = new aesjs.ModeOfOperation.cbc(Array.from(key), Array.from(iv));
return Buffer.from(cipher.encrypt(Array.from(pkcs7Pad(input))));
};
/** Decrypt AES-256-CBC with PKCS#7 padding. */
const aes256CbcDecrypt = (key, iv, input) => {
const decipher = new aesjs.ModeOfOperation.cbc(Array.from(key), Array.from(iv));
return Buffer.from(pkcs7Unpad(decipher.decrypt(Array.from(input))));
};
/** Return 2-round sha256 hash of input */
const doubleSha256 = (input) => sha256(sha256(input));
/** Encode public key with bs58+ripemd160-checksum */
const encodePublic = (key, prefix) => {
const checksum = ripemd160(key);
return prefix + bs58_1.default.encode(Buffer.concat([key, toUint8Array(checksum).slice(0, 4)]));
};
/** Decode bs58+ripemd160-checksum encoded public key */
const decodePublic = (encodedKey) => {
const prefix = encodedKey.slice(0, 3);
encodedKey = encodedKey.slice(3);
const uint8Array = bs58_1.default.decode(encodedKey);
const checksum = uint8Array.slice(-4);
const key = uint8Array.slice(0, -4);
const bufKey = Buffer.from(key);
const checksumVerify = toUint8Array(ripemd160(bufKey)).slice(0, 4);
if (Buffer.compare(toBuffer(checksumVerify), toBuffer(checksum)) !== 0) {
throw new Error('public key checksum mismatch');
}
return { key: bufKey, prefix };
};
/** Encode bs58+doubleSha256-checksum private key */
const encodePrivate = (key) => {
assert_1.default.strictEqual(key.readUInt8(0), 0x80, 'private key network id mismatch');
const checksum = doubleSha256(key);
return bs58_1.default.encode(Buffer.concat([key, toUint8Array(checksum).slice(0, 4)]));
};
/** Decode bs58+doubleSha256-checksum encoded private key */
const decodePrivate = (encodedKey) => {
const uint8Array = bs58_1.default.decode(encodedKey);
const toCompare = toBuffer(uint8Array.slice(0, 1));
if (Buffer.compare(NETWORK_ID, toCompare) !== 0) {
throw new Error('private key network id mismatch');
}
const checksum = uint8Array.slice(-4);
const key = uint8Array.slice(0, -4);
const bufKey = Buffer.from(key);
const dSha256 = sha256(sha256(bufKey));
const checksumVerify = toUint8Array(dSha256).slice(0, 4);
if (Buffer.compare(toBuffer(checksumVerify), toBuffer(checksum)) !== 0) {
throw new Error('private key checksum mismatch');
}
return bufKey;
};
/** Return true if signature is canonical, otherwise false */
const isCanonicalSignature = (signature) => (!(signature[0] & 0x80) &&
!(signature[0] === 0 && !(signature[1] & 0x80)) &&
!(signature[32] & 0x80) &&
!(signature[32] === 0 && !(signature[33] & 0x80)));
/** Return true if string is wif, otherwise false */
const isWif = (privWif) => {
try {
const bufWif = Buffer.from(bs58_1.default.decode(privWif));
if (bufWif.length !== 37) {
return false;
}
if (Buffer.compare(bufWif.slice(0, 1), NETWORK_ID) !== 0) {
return false;
}
const privKey = bufWif.slice(0, -4);
const checksum = bufWif.slice(-4);
const newChecksum = doubleSha256(privKey).slice(0, 4);
return Buffer.compare(checksum, newChecksum) === 0;
}
catch (e) {
return false;
}
};
/**
* ECDSA (secp256k1) public key.
*/
class PublicKey {
constructor(key, prefix = client_1.DEFAULT_ADDRESS_PREFIX) {
this.key = key;
this.prefix = prefix;
(0, assert_1.default)(secp256k1.Point.fromHex(key), 'invalid public key');
this.uncompressed = Buffer.from(secp256k1.Point.fromHex(key).toRawBytes(false));
}
/**
* Create a new instance from a WIF-encoded key.
*/
static fromString(wif) {
const { key, prefix } = decodePublic(wif);
return new PublicKey(key, prefix);
}
static fromBuffer(key) {
(0, assert_1.default)(secp256k1.Point.fromHex(key), 'invalid buffer as public key');
return { key };
}
/**
* Create a new instance.
*/
static from(value) {
if (value instanceof PublicKey) {
return value;
}
else {
return PublicKey.fromString(value);
}
}
/**
* Verify a 32-byte signature.
* @param message 32-byte message to verify.
* @param signature Signature to verify.
*/
verify(message, signature) {
return secp256k1.verify(signature.data, message, this.key, { strict: false });
}
/**
* Return a WIF-encoded representation of the key.
*/
toString() {
return encodePublic(this.key, this.prefix);
}
/**
* Return JSON representation of this key, same as toString().
*/
toJSON() {
return this.toString();
}
/**
* Used by `utils.inspect` and `console.log` in node.js.
*/
inspect() {
return `PublicKey: ${this.toString()}`;
}
}
exports.PublicKey = PublicKey;
/**
* ECDSA (secp256k1) private key.
*/
class PrivateKey {
constructor(key) {
this.key = key;
(0, assert_1.default)(secp256k1.utils.isValidPrivateKey(key), 'invalid private key');
}
/**
* Convenience to create a new instance from WIF string or buffer.
*/
static from(value) {
if (typeof value === 'string') {
return PrivateKey.fromString(value);
}
else {
return new PrivateKey(value);
}
}
/**
* Create a new instance from a WIF-encoded key.
*/
static fromString(wif) {
const decoded = toUint8Array(decodePrivate(wif)).slice(1);
return new PrivateKey(toBuffer(decoded));
}
/**
* Create a new instance from a seed.
*/
static fromSeed(seed) {
return new PrivateKey(sha256(seed));
}
/**
* Create key from username and password.
*/
static fromLogin(username, password, role = 'active') {
const seed = username + role + password;
return PrivateKey.fromSeed(seed);
}
/**
* Sign message.
* @param message 32-byte message.
*/
sign(message) {
let rv;
let attempts = 0;
do {
const options = {
data: sha256(Buffer.concat([message, Buffer.alloc(1, ++attempts)]))
};
const [signature, recid] = secp256k1.signSync(message, this.key, {
der: false,
extraEntropy: options.data,
recovered: true
});
rv = { signature, recid };
} while (!isCanonicalSignature(toBuffer(rv.signature)));
return new Signature(toBuffer(rv.signature), rv.recid);
}
/**
* Derive the public key for this private key.
*/
createPublic(prefix) {
return new PublicKey(Buffer.from(secp256k1.getPublicKey(this.key, true)), prefix);
}
/**
* Return a WIF-encoded representation of the key.
*/
toString() {
return encodePrivate(Buffer.concat([NETWORK_ID, this.key]));
}
/**
* Get shared secret for memo cryptography
*/
getSharedSecret(publicKey) {
const sharedPoint = Buffer.from(secp256k1.getSharedSecret(this.key, publicKey.key, false));
return sha512(sharedPoint.slice(1, 33));
}
/**
* Used by `utils.inspect` and `console.log` in node.js. Does not show the full key
* to get the full encoded key you need to explicitly call {@link toString}.
*/
inspect() {
const key = this.toString();
return `PrivateKey: ${key.slice(0, 6)}...${key.slice(-6)}`;
}
}
exports.PrivateKey = PrivateKey;
/**
* ECDSA (secp256k1) signature.
*/
class Signature {
constructor(data, recovery) {
this.data = data;
this.recovery = recovery;
assert_1.default.strictEqual(data.length, 64, 'invalid signature');
}
static fromBuffer(buffer) {
assert_1.default.strictEqual(buffer.length, 65, 'invalid signature');
const recovery = buffer.readUInt8(0) - 31;
const data = toUint8Array(buffer).slice(1);
return new Signature(toBuffer(data), recovery);
}
static fromString(string) {
return Signature.fromBuffer(Buffer.from(string, 'hex'));
}
/**
* Recover public key from signature by providing original signed message.
* @param message 32-byte message that was used to create the signature.
*/
recover(message, prefix) {
return new PublicKey(Buffer.from(secp256k1.recoverPublicKey(message, this.data, this.recovery, true)), prefix);
}
toBuffer() {
const buffer = Buffer.alloc(65);
buffer.writeUInt8(this.recovery + 31, 0);
this.data.copy(buffer, 1);
return buffer;
}
toString() {
return this.toBuffer().toString('hex');
}
}
exports.Signature = Signature;
/**
* Return the sha256 transaction digest.
* @param chainId The chain id to use when creating the hash.
*/
const transactionDigest = (transaction, chainId = client_1.DEFAULT_CHAIN_ID) => {
const buffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
try {
serializer_1.Types.Transaction(buffer, transaction);
}
catch (cause) {
throw new errors_1.SerializationError(cause);
}
buffer.flip();
const transactionData = Buffer.from(buffer.toBuffer());
const digest = sha256(Buffer.concat([chainId, transactionData]));
return digest;
};
/**
* Return copy of transaction with signature appended to signatures array.
* @param transaction Transaction to sign.
* @param keys Key(s) to sign transaction with.
* @param chainId Chain id used when computing the transaction digest.
*/
// eslint-disable-next-line max-len
const signTransaction = (transaction, keys, chainId = client_1.DEFAULT_CHAIN_ID) => {
const digest = transactionDigest(transaction, chainId);
const signedTransaction = (0, utils_1.copy)(transaction);
if (!signedTransaction.signatures) {
signedTransaction.signatures = [];
}
if (!Array.isArray(keys)) {
keys = [keys];
}
for (const key of keys) {
const signature = key.sign(digest);
signedTransaction.signatures.push(signature.toString());
}
return signedTransaction;
};
const generateTrxId = (transaction) => {
const buffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
try {
serializer_1.Types.Transaction(buffer, transaction);
}
catch (cause) {
throw new errors_1.SerializationError(cause);
}
buffer.flip();
const transactionData = Buffer.from(buffer.toBuffer());
return exports.cryptoUtils.sha256(transactionData).toString('hex').slice(0, 40);
};
/**
* Memo Encode/Decode
*/
/**
* remove varint length prefix
*
* @param decryptedMessage - Buffer of the decrypted message
* @returns the decrypted message minus the varint length prefix
*/
const removeVarintLengthPrefix = (decryptedMessage) => {
const mbuf = ByteBuffer.fromBinary(decryptedMessage.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
try {
mbuf.mark();
return '#' + mbuf.readVString();
}
catch (e) {
mbuf.reset();
// Sender did not length-prefix the memo
const memo = Buffer.from(mbuf.toString('binary'), 'binary').toString('utf-8');
return '#' + memo;
}
};
/**
* Decrypts an encrypted memo.
*
* @param memo - The encrypted memo to decrypt (need to start with #).
* @param receiverPrivateMemoKey - The private Memo key of the recipient.
* @returns The decrypted message.
*/
const decodeMemo = (memo, receiverPrivateMemoKey) => {
try {
(0, assert_1.default)(typeof receiverPrivateMemoKey === 'string' || receiverPrivateMemoKey.toString(), 'Invalid Receiver private MEMO key!');
if (!memo.startsWith('#')) {
return memo;
}
const privateKey = typeof receiverPrivateMemoKey === 'string' ? PrivateKey.from(receiverPrivateMemoKey) : receiverPrivateMemoKey;
memo = memo.substring(1);
const memoBuff = bs58_1.default.decode(memo);
const deserialized = (0, deserializer_1.EncryptedMemoDeserializer)(Buffer.from(memoBuff));
// const { from, to, nonce, check, encrypted } = deserialized
const { from, nonce, check, encrypted } = deserialized;
const publicKey = new PublicKey(from.key);
const nonceLong = toByteBuffer(nonce);
// Appending nonce to buffer "ebuf" and rehash with sha512
const S = privateKey.getSharedSecret(publicKey);
let ebuf = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
ebuf.writeUint64(nonceLong);
ebuf.append(S.toString('binary'), 'binary');
ebuf = Buffer.from(ebuf.copy(0, ebuf.offset).toBinary(), 'binary');
const encryption_key = sha512(ebuf);
const iv = encryption_key.slice(32, 48);
const tag = encryption_key.slice(0, 32);
// check if first 64 bit of sha256 hash treated as uint64_t truncated to 32 bits.
let checksum = sha256(encryption_key);
checksum = checksum.slice(0, 4);
const cbuf = ByteBuffer.fromBinary(checksum.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
checksum = cbuf.readUint32();
(0, assert_1.default)(check === checksum, 'Invalid nonce!');
const binaryMessage = toUint8Array(encrypted);
const decryptedMessage = aes256CbcDecrypt(tag, iv, binaryMessage);
return removeVarintLengthPrefix(decryptedMessage);
}
catch (e) {
throw e;
}
};
exports.decodeMemo = decodeMemo;
/**
* Encrypt a memo.
*
* @param memo - The memo to encrypt (need to start with #).
* @param senderPrivateMemoKey - The private Memo key of the sender.
* @param receiverPublicMemoKey - The publicKey Memo key of the recipient.
* @returns The encrypted message.
*/
const encodeMemo = (memo, senderPrivateMemoKey, receiverPublicMemoKey) => {
try {
(0, assert_1.default)(typeof senderPrivateMemoKey === 'string' || senderPrivateMemoKey.toString(), 'Invalid Sender private MEMO key!');
(0, assert_1.default)(typeof receiverPublicMemoKey === 'string' || receiverPublicMemoKey.toString(), 'Invalid Receiver public MEMO key!');
if (!memo.startsWith('#')) {
return memo;
}
const privateKey = typeof senderPrivateMemoKey === 'string' ? PrivateKey.from(senderPrivateMemoKey) : senderPrivateMemoKey;
const publicKey = typeof receiverPublicMemoKey === 'string' ? PublicKey.from(receiverPublicMemoKey) : receiverPublicMemoKey;
memo = memo.substring(1);
const mbuf = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
mbuf.writeVString(memo);
const memoBuff = Buffer.from(mbuf.flip().toBinary(), 'binary');
const nonceLong = toByteBuffer(uniqueNonce());
// Appending nonce to buffer "ebuf" and rehash with sha512
const S = privateKey.getSharedSecret(publicKey);
let ebuf = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
ebuf.writeUint64(nonceLong);
ebuf.append(S.toString('binary'), 'binary');
ebuf = Buffer.from(ebuf.copy(0, ebuf.offset).toBinary(), 'binary');
const encryption_key = sha512(ebuf);
const iv = encryption_key.slice(32, 48);
const tag = encryption_key.slice(0, 32);
// check if first 64 bit of sha256 hash treated as uint64_t truncated to 32 bits.
let check = sha256(encryption_key);
check = check.slice(0, 4);
const cbuf = ByteBuffer.fromBinary(check.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
check = cbuf.readUint32();
let message = toUint8Array(memoBuff);
message = aes256CbcEncrypt(tag, iv, message);
const lbuf = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
serializer_1.Types.Memo(lbuf, {
check,
encrypted: message,
from: privateKey.createPublic(),
nonce: nonceLong,
to: publicKey
});
lbuf.flip();
const data = Buffer.from(lbuf.toBuffer());
return '#' + bs58_1.default.encode(data);
}
catch (e) {
throw e;
}
};
exports.encodeMemo = encodeMemo;
/** Misc crypto utility functions. */
exports.cryptoUtils = {
decodePrivate,
doubleSha256,
encodePrivate,
encodePublic,
generateTrxId,
isCanonicalSignature,
isWif,
regExpAccount,
regExpAtAccount,
ripemd160,
sha256,
signTransaction,
toBuffer,
toByteBuffer,
toUint8Array,
transactionDigest,
uniqueNonce
};