UNPKG

bigint-hash

Version:

Common hashing functions with bigint support

479 lines (477 loc) 17.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); const bigint_buffer_1 = require("bigint-buffer"); const crypto = require("crypto"); var OpenSSLHashType; (function (OpenSSLHashType) { OpenSSLHashType[OpenSSLHashType["OPENSSL_MD5"] = 0] = "OPENSSL_MD5"; OpenSSLHashType[OpenSSLHashType["OPENSSL_MD4"] = 1] = "OPENSSL_MD4"; OpenSSLHashType[OpenSSLHashType["OPENSSL_SHA1"] = 2] = "OPENSSL_SHA1"; OpenSSLHashType[OpenSSLHashType["OPENSSL_SHA224"] = 3] = "OPENSSL_SHA224"; OpenSSLHashType[OpenSSLHashType["OPENSSL_SHA256"] = 4] = "OPENSSL_SHA256"; OpenSSLHashType[OpenSSLHashType["OPENSSL_SHA384"] = 5] = "OPENSSL_SHA384"; OpenSSLHashType[OpenSSLHashType["OPENSSL_SHA512"] = 6] = "OPENSSL_SHA512"; })(OpenSSLHashType || (OpenSSLHashType = {})); var KeccakHashType; (function (KeccakHashType) { KeccakHashType[KeccakHashType["KECCAK_224"] = 0] = "KECCAK_224"; KeccakHashType[KeccakHashType["KECCAK_256"] = 1] = "KECCAK_256"; KeccakHashType[KeccakHashType["KECCAK_384"] = 2] = "KECCAK_384"; KeccakHashType[KeccakHashType["KECCAK_512"] = 3] = "KECCAK_512"; KeccakHashType[KeccakHashType["SHA3_224"] = 4] = "SHA3_224"; KeccakHashType[KeccakHashType["SHA3_256"] = 5] = "SHA3_256"; KeccakHashType[KeccakHashType["SHA3_384"] = 6] = "SHA3_384"; KeccakHashType[KeccakHashType["SHA3_512"] = 7] = "SHA3_512"; })(KeccakHashType || (KeccakHashType = {})); var XxHashType; (function (XxHashType) { XxHashType[XxHashType["xxHash64"] = 0] = "xxHash64"; XxHashType[XxHashType["xxHash32"] = 1] = "xxHash32"; })(XxHashType || (XxHashType = {})); let libopenssl; let libkeccak; let libxxhash; let keccak; let fallback = true; const xxhashjs = require('xxhashjs'); { keccak = require('keccak'); } /** * Represents a string that can be passed to request a supported hashing * algorithm. */ var HashType; (function (HashType) { /** * MD5, 128-bit digest as specified in RFC 1321. "Cryptographically broken * and unsuitable for further use." */ HashType["MD5"] = "md5"; /** SHA-1, a 160-bit digest. No longer considered secure. */ HashType["SHA1"] = "sha1"; /** SHA-224, a 224-bit digest from the SHA-2 family. */ HashType["SHA224"] = "sha224"; /** SHA-256, a 256-bit digest from the SHA-2 family. */ HashType["SHA256"] = "sha256"; /** SHA-384, a 384-bit digest from the SHA-2 family. */ HashType["SHA384"] = "sha384"; /** SHA-512, a 512-bit digest from the SHA-2 family. */ HashType["SHA512"] = "sha512"; /** * SHA3-224, a 224-bit digest using the Keccak family, with 0x6 used for * padding. */ HashType["SHA3_224"] = "sha3-224"; /** * SHA3-256, a 256-bit digest using the Keccak family, with 0x6 used for * padding. */ HashType["SHA3_256"] = "sha3-256"; /** * SHA3-384, a 384-bit digest using the Keccak family, with 0x6 used for * padding. */ HashType["SHA3_384"] = "sha3-384"; /** * SHA3-512, a 512-bit digest using the Keccak family, with 0x6 used for * padding. */ HashType["SHA3_512"] = "sha3-512"; /** * Keccak224, a 224-bit digest using the Keccak family, with 0x0 used for * padding. */ HashType["KECCAK224"] = "keccak224"; /** * Keccak256, a 256-bit digest using the Keccak family, with 0x0 used for * padding. Commonly used for Ethereum. */ HashType["KECCAK256"] = "keccak256"; /** * Keccak384, a 384-bit digest using the Keccak family, with 0x0 used for * padding. */ HashType["KECCAK384"] = "keccak384"; /** * Keccak512, a 512-bit digest using the Keccak family, with 0x0 used for * padding. */ HashType["KECCAK512"] = "keccak512"; /** * xxHash64, a extremely fast non-cryptographic hash algorithm with a 64-bit * digest. */ HashType["xxHash64"] = "xxHash64"; /** * xxHash32, a extremely fast non-cryptographic hash algorithm with a 32-bit * digest. */ HashType["xxHash32"] = "xxHash32"; })(HashType = exports.HashType || (exports.HashType = {})); /** Reperesents the types of input encoding which may be used by a string. */ var InputEncoding; (function (InputEncoding) { /** UTF-8, the default encoding */ InputEncoding["UTF8"] = "utf8"; /** ASCII, without UTF-8 extensions. */ InputEncoding["ASCII"] = "ascii"; /** Latin 1, as specified in ISO-8859-1 */ InputEncoding["LATIN1"] = "latin1"; })(InputEncoding = exports.InputEncoding || (exports.InputEncoding = {})); /** Reperesents the permitted set of output types for a digest. */ var OutputType; (function (OutputType) { /** Output a bigint digest. */ OutputType["BigInt"] = "bigint"; /** Output a buffer digest. */ OutputType["Buffer"] = "buffer"; })(OutputType = exports.OutputType || (exports.OutputType = {})); /** An internal hasher which calls OpenSSL. Do not use directly. */ class OpensslHasher { constructor(hash, opensslType = OpensslHasher.getOpensslType(hash), opensslHandle = fallback ? crypto.createHash(hash) : libopenssl.getHashHandle(opensslType)) { this.opensslType = opensslType; this.opensslHandle = opensslHandle; this.disposed = false; } static getOpensslType(hash) { switch (hash) { case HashType.MD5: return OpenSSLHashType.OPENSSL_MD5; case HashType.SHA1: return OpenSSLHashType.OPENSSL_SHA1; case HashType.SHA224: return OpenSSLHashType.OPENSSL_SHA224; case HashType.SHA256: return OpenSSLHashType.OPENSSL_SHA256; case HashType.SHA384: return OpenSSLHashType.OPENSSL_SHA384; case HashType.SHA512: return OpenSSLHashType.OPENSSL_SHA512; default: throw new Error(`Unsupported hash type ${hash}`); } } digest(output = OutputType.Buffer) { if (this.disposed) { throw new Error('Digest a disposed hasher'); } this.disposed = true; switch (output) { case OutputType.BigInt: if (fallback) { return bigint_buffer_1.toBigIntBE(this.opensslHandle.digest()); } return libopenssl.getHashDigestBigInt(this.opensslHandle); case OutputType.Buffer: if (fallback) { return this.opensslHandle.digest(); } return libopenssl.getHashDigestBuffer(this.opensslHandle); default: throw new Error('Unsupported output type'); } } digestBigInt() { return this.digest(OutputType.BigInt); } update(data, inputEncoding) { if (this.disposed) { throw new Error('Updating a disposed hasher'); } if (data.byteLength === undefined) { // this is a string data = Buffer.from(data, inputEncoding); } if (fallback) { this.opensslHandle.update(data); return this; } libopenssl.hashBuffer(this.opensslHandle, data); return this; } } exports.OpensslHasher = OpensslHasher; /** * An internal hasher which calls the eXtended Keccak Code Package. Do not use * directly. */ class KeccakHasher { constructor(hash, keccakType = KeccakHasher.getKeccakType(hash), keccakHandle = fallback ? keccak(hash) : libkeccak.getHashHandle(keccakType)) { this.keccakType = keccakType; this.keccakHandle = keccakHandle; this.disposed = false; } static getKeccakType(hash) { switch (hash) { case HashType.SHA3_224: return KeccakHashType.SHA3_224; case HashType.SHA3_256: return KeccakHashType.SHA3_256; case HashType.SHA3_384: return KeccakHashType.SHA3_384; case HashType.SHA3_512: return KeccakHashType.SHA3_512; case HashType.KECCAK224: return KeccakHashType.KECCAK_224; case HashType.KECCAK256: return KeccakHashType.KECCAK_256; case HashType.KECCAK384: return KeccakHashType.KECCAK_384; case HashType.KECCAK512: return KeccakHashType.KECCAK_512; default: throw new Error(`Unsupported hash type ${hash}`); } } digest(output = OutputType.Buffer) { if (this.disposed) { throw new Error('Digest a disposed hasher'); } this.disposed = true; if (fallback) { const result = this.keccakHandle.digest(); switch (output) { case OutputType.BigInt: return bigint_buffer_1.toBigIntBE(result); case OutputType.Buffer: return result; default: throw new Error('Unsupported output type'); } } switch (output) { case OutputType.BigInt: return libkeccak.getHashDigestBigInt(this.keccakHandle, this.keccakType); case OutputType.Buffer: return libkeccak.getHashDigestBuffer(this.keccakHandle, this.keccakType); default: throw new Error('Unsupported output type'); } } digestBigInt() { return this.digest(OutputType.BigInt); } update(data, inputEncoding) { if (this.disposed) { throw new Error('Updating a disposed hasher'); } if (data.byteLength === undefined) { // this is a string data = Buffer.from(data, inputEncoding); } if (fallback) { this.keccakHandle.update(data); } else { libkeccak.hashBuffer(this.keccakHandle, data); } return this; } } exports.KeccakHasher = KeccakHasher; /** * An internal hasher which calls xxHash. Do not use * directly. */ class XxHasher { constructor(hash, xxType = XxHasher.getXxHashType(hash), xxHandle = fallback ? hash === HashType.xxHash64 ? xxhashjs.h64(0) : xxhashjs.h32(0) : libxxhash.getHashHandle(xxType)) { this.xxType = xxType; this.xxHandle = xxHandle; this.disposed = false; } static getXxHashType(hash) { switch (hash) { case HashType.xxHash64: return XxHashType.xxHash64; case HashType.xxHash32: return XxHashType.xxHash32; default: throw new Error(`Unsupported hash type ${hash}`); } } digest(output = OutputType.Buffer) { if (this.disposed) { throw new Error('Digest a disposed hasher'); } this.disposed = true; if (fallback) { switch (output) { case OutputType.BigInt: return BigInt(`0x${this.xxHandle.digest().toString(16)}`); case OutputType.Buffer: let str = this.xxHandle.digest().toString(16); if (str.length % 2 !== 0) { str = str.padStart(str.length + 1, '0'); } return Buffer.from(str, 'hex'); default: throw new Error('Unsupported output type'); } } switch (output) { case OutputType.BigInt: return libxxhash.getHashDigestBigInt(this.xxHandle, this.xxType); case OutputType.Buffer: return libxxhash.getHashDigestBuffer(this.xxHandle, this.xxType); default: throw new Error('Unsupported output type'); } } digestBigInt() { return this.digest(OutputType.BigInt); } update(data, inputEncoding) { if (this.disposed) { throw new Error('Updating a disposed hasher'); } if (data.byteLength === undefined) { // this is a string data = Buffer.from(data, inputEncoding); } if (fallback) { this.xxHandle.update(data); } else { libxxhash.hashBuffer(this.xxHandle, this.xxType, data); } return this; } } exports.XxHasher = XxHasher; /** * Obtain a hasher instance for hashing. If you will only hash a single buffer, * call the [[hashAsBigInt]] or [[hashAsBuffer]] functions instead, as they * yield better performance. * * @param hash The type of algorithm to support * * @returns A [[Hash]] instance for hashing. */ function getHasher(hash) { switch (hash) { case HashType.MD5: case HashType.SHA1: case HashType.SHA224: case HashType.SHA256: case HashType.SHA384: case HashType.SHA512: return new OpensslHasher(hash); case HashType.SHA3_224: case HashType.SHA3_256: case HashType.SHA3_384: case HashType.SHA3_512: case HashType.KECCAK224: case HashType.KECCAK256: case HashType.KECCAK384: case HashType.KECCAK512: return new KeccakHasher(hash); case HashType.xxHash64: case HashType.xxHash32: return new XxHasher(hash); default: throw new Error(`Unsupported hash type!`); } } exports.getHasher = getHasher; /** * Hash the given buffer using the hashing algorithm specified, returning * the digest as a bigint. * * @param hash The hash algorithm to use. * @param buf The buffer to use. * * @returns A bigint with the message digest. */ function hashAsBigInt(hash, buf) { switch (hash) { case HashType.MD5: case HashType.SHA1: case HashType.SHA224: case HashType.SHA256: case HashType.SHA384: case HashType.SHA512: if (fallback) { return bigint_buffer_1.toBigIntBE(crypto.createHash(hash).update(buf).digest()); } return libopenssl.hashBufferOneshotBigInt(OpensslHasher.getOpensslType(hash), buf); case HashType.SHA3_224: case HashType.SHA3_256: case HashType.SHA3_384: case HashType.SHA3_512: case HashType.KECCAK224: case HashType.KECCAK256: case HashType.KECCAK384: case HashType.KECCAK512: if (fallback) { return bigint_buffer_1.toBigIntBE(keccak(hash).update(buf).digest()); } return libkeccak.hashBufferOneshotBigInt(KeccakHasher.getKeccakType(hash), buf); case HashType.xxHash64: if (fallback) { return BigInt(`0x${xxhashjs.h64().update(buf).digest().toString(16)}`); } return libxxhash.hashBufferOneshotBigInt(XxHasher.getXxHashType(hash), buf); case HashType.xxHash32: if (fallback) { return BigInt(`0x${xxhashjs.h32().update(buf).digest().toString(16)}`); } return libxxhash.hashBufferOneshotBigInt(XxHasher.getXxHashType(hash), buf); default: throw new Error(`Unsupported hash type!`); } } exports.hashAsBigInt = hashAsBigInt; /** * Hash the given buffer using the hashing algorithm specified, returning * the digest as a Buffer. * * @param hash The hash algorithm to use. * @param buf The buffer to use. * * @returns A buffer with the message digest. */ function hashAsBuffer(hash, buf) { switch (hash) { case HashType.MD5: case HashType.SHA1: case HashType.SHA224: case HashType.SHA256: case HashType.SHA384: case HashType.SHA512: if (fallback) { return crypto.createHash(hash).update(buf).digest(); } return libopenssl.hashBufferOneshotBuffer(OpensslHasher.getOpensslType(hash), buf); case HashType.SHA3_224: case HashType.SHA3_256: case HashType.SHA3_384: case HashType.SHA3_512: case HashType.KECCAK224: case HashType.KECCAK256: case HashType.KECCAK384: case HashType.KECCAK512: if (fallback) { return keccak(hash).update(buf).digest(); } return libkeccak.hashBufferOneshotBuffer(KeccakHasher.getKeccakType(hash), buf); case HashType.xxHash64: if (fallback) { return Buffer.from(xxhashjs.h64().update(buf).digest().toString(16), 'hex'); } return libxxhash.hashBufferOneshotBuffer(XxHasher.getXxHashType(hash), buf); case HashType.xxHash32: if (fallback) { return Buffer.from(xxhashjs.h32().update(buf).digest().toString(16), 'hex'); } return libxxhash.hashBufferOneshotBuffer(XxHasher.getXxHashType(hash), buf); default: throw new Error(`Unsupported hash type!`); } } exports.hashAsBuffer = hashAsBuffer;