bigint-hash
Version:
Common hashing functions with bigint support
489 lines (487 loc) • 17.4 kB
JavaScript
'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 = false;
const xxhashjs = require('xxhashjs');
{
try {
libopenssl = require('bindings')('openssl');
libkeccak = require('bindings')('keccak');
libxxhash = require('bindings')('xxhash');
}
catch (e) {
console.warn(e);
console.warn('bigint-crypto: Failed to load bindings, pure JS will be used (try npm run rebuild?)');
fallback = true;
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;