@airgap/coinlib-core
Version:
The @airgap/coinlib-core is a protocol agnostic library to prepare, sign and broadcast cryptocurrency transactions.
455 lines • 17.6 kB
JavaScript
"use strict";
// Copyright (C) 2017 Dmitry Chestnykh
// MIT License. See LICENSE file for details.
Object.defineProperty(exports, "__esModule", { value: true });
exports.hash = exports.BLAKE2b = exports.MAX_MAX_DEPTH = exports.MAX_FANOUT = exports.MAX_LEAF_SIZE = exports.SALT_LENGTH = exports.PERSONALIZATION_LENGTH = exports.KEY_LENGTH = exports.DIGEST_LENGTH = exports.BLOCK_SIZE = void 0;
var binary_1 = require("../../../../@stablelib/binary-1.0.1/packages/binary/binary");
var wipe_1 = require("../../../../@stablelib/wipe-1.0.1/packages/wipe/wipe");
exports.BLOCK_SIZE = 128;
exports.DIGEST_LENGTH = 64;
exports.KEY_LENGTH = 64;
exports.PERSONALIZATION_LENGTH = 16;
exports.SALT_LENGTH = 16;
exports.MAX_LEAF_SIZE = Math.pow(2, 32) - 1;
exports.MAX_FANOUT = 255;
exports.MAX_MAX_DEPTH = 255; // not a typo
var IV = new Uint32Array([
// low bits // high bits
0xf3bcc908, 0x6a09e667,
0x84caa73b, 0xbb67ae85,
0xfe94f82b, 0x3c6ef372,
0x5f1d36f1, 0xa54ff53a,
0xade682d1, 0x510e527f,
0x2b3e6c1f, 0x9b05688c,
0xfb41bd6b, 0x1f83d9ab,
0x137e2179, 0x5be0cd19,
]);
// Note: sigma values are doubled since we store
// 64-bit ints as two 32-bit ints in arrays.
var SIGMA = [
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30],
[28, 20, 8, 16, 18, 30, 26, 12, 2, 24, 0, 4, 22, 14, 10, 6],
[22, 16, 24, 0, 10, 4, 30, 26, 20, 28, 6, 12, 14, 2, 18, 8],
[14, 18, 6, 2, 26, 24, 22, 28, 4, 12, 10, 20, 8, 0, 30, 16],
[18, 0, 10, 14, 4, 8, 20, 30, 28, 2, 22, 24, 12, 16, 6, 26],
[4, 24, 12, 20, 0, 22, 16, 6, 8, 26, 14, 10, 30, 28, 2, 18],
[24, 10, 2, 30, 28, 26, 8, 20, 0, 14, 12, 6, 18, 4, 16, 22],
[26, 22, 14, 28, 24, 2, 6, 18, 10, 0, 30, 8, 16, 12, 4, 20],
[12, 30, 28, 18, 22, 6, 0, 16, 24, 4, 26, 14, 2, 8, 20, 10],
[20, 4, 16, 8, 14, 12, 2, 10, 30, 22, 18, 28, 6, 24, 26, 0],
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30],
[28, 20, 8, 16, 18, 30, 26, 12, 2, 24, 0, 4, 22, 14, 10, 6]
];
/**
* BLAKE2b hash function.
*/
var BLAKE2b = /** @class */ (function () {
function BLAKE2b(digestLength, config) {
if (digestLength === void 0) { digestLength = 64; }
this.digestLength = digestLength;
this.blockSize = exports.BLOCK_SIZE;
// Note: Int32Arrays for state and message are used for performance reasons.
this._state = new Int32Array(IV); // hash state, initialized with IV
this._buffer = new Uint8Array(exports.BLOCK_SIZE); // buffer for data
this._bufferLength = 0; // number of bytes in buffer
this._ctr = new Uint32Array(4);
this._flag = new Uint32Array(4);
this._lastNode = false;
this._finished = false;
this._vtmp = new Uint32Array(32);
this._mtmp = new Uint32Array(32);
// Validate digest length.
if (digestLength < 1 || digestLength > exports.DIGEST_LENGTH) {
throw new Error("blake2b: wrong digest length");
}
// Validate config, if present.
if (config) {
this.validateConfig(config);
}
// Get key length from config.
var keyLength = 0;
if (config && config.key) {
keyLength = config.key.length;
}
// Get tree fanout and maxDepth from config.
var fanout = 1;
var maxDepth = 1;
if (config && config.tree) {
fanout = config.tree.fanout;
maxDepth = config.tree.maxDepth;
}
// Xor common parameters into state.
this._state[0] ^= digestLength | (keyLength << 8) | (fanout << 16) | (maxDepth << 24);
// Xor tree parameters into state.
if (config && config.tree) {
this._state[1] ^= config.tree.leafSize;
this._state[2] ^= config.tree.nodeOffsetLowBits;
this._state[3] ^= config.tree.nodeOffsetHighBits;
this._state[4] ^= config.tree.nodeDepth | (config.tree.innerDigestLength << 8);
this._lastNode = config.tree.lastNode;
}
// Xor salt into state.
if (config && config.salt) {
this._state[8] ^= (0, binary_1.readUint32LE)(config.salt, 0);
this._state[9] ^= (0, binary_1.readUint32LE)(config.salt, 4);
this._state[10] ^= (0, binary_1.readUint32LE)(config.salt, 8);
this._state[11] ^= (0, binary_1.readUint32LE)(config.salt, 12);
}
// Xor personalization into state.
if (config && config.personalization) {
this._state[12] ^= (0, binary_1.readUint32LE)(config.personalization, 0);
this._state[13] ^= (0, binary_1.readUint32LE)(config.personalization, 4);
this._state[14] ^= (0, binary_1.readUint32LE)(config.personalization, 8);
this._state[15] ^= (0, binary_1.readUint32LE)(config.personalization, 12);
}
// Save a copy of initialized state for reset.
this._initialState = new Uint32Array(this._state);
// Process key.
if (config && config.key && keyLength > 0) {
this._paddedKey = new Uint8Array(exports.BLOCK_SIZE);
this._paddedKey.set(config.key);
// Put padded key into buffer.
this._buffer.set(this._paddedKey);
this._bufferLength = exports.BLOCK_SIZE;
}
}
BLAKE2b.prototype.reset = function () {
// Restore initial state.
this._state.set(this._initialState);
if (this._paddedKey) {
// Put padded key into buffer.
this._buffer.set(this._paddedKey);
this._bufferLength = exports.BLOCK_SIZE;
}
else {
this._bufferLength = 0;
}
// Clear counters and flags.
(0, wipe_1.wipe)(this._ctr);
(0, wipe_1.wipe)(this._flag);
this._finished = false;
return this;
};
BLAKE2b.prototype.validateConfig = function (config) {
if (config.key && config.key.length > exports.KEY_LENGTH) {
throw new Error("blake2b: wrong key length");
}
if (config.salt && config.salt.length !== exports.SALT_LENGTH) {
throw new Error("blake2b: wrong salt length");
}
if (config.personalization &&
config.personalization.length !== exports.PERSONALIZATION_LENGTH) {
throw new Error("blake2b: wrong personalization length");
}
if (config.tree) {
if (config.tree.fanout < 0 || config.tree.fanout > exports.MAX_FANOUT) {
throw new Error("blake2b: wrong tree fanout");
}
if (config.tree.maxDepth < 0 || config.tree.maxDepth > exports.MAX_MAX_DEPTH) {
throw new Error("blake2b: wrong tree depth");
}
if (config.tree.leafSize < 0 || config.tree.leafSize > exports.MAX_LEAF_SIZE) {
throw new Error("blake2b: wrong leaf size");
}
if (config.tree.innerDigestLength < 0 ||
config.tree.innerDigestLength > exports.DIGEST_LENGTH) {
throw new Error("blake2b: wrong tree inner digest length");
}
}
};
BLAKE2b.prototype.update = function (data, dataLength) {
if (dataLength === void 0) { dataLength = data.length; }
if (this._finished) {
throw new Error("blake2b: can't update because hash was finished.");
}
var left = exports.BLOCK_SIZE - this._bufferLength;
var dataPos = 0;
if (dataLength === 0) {
return this;
}
// Finish buffer.
if (dataLength > left) {
for (var i = 0; i < left; i++) {
this._buffer[this._bufferLength + i] = data[dataPos + i];
}
this._processBlock(exports.BLOCK_SIZE);
dataPos += left;
dataLength -= left;
this._bufferLength = 0;
}
// Process data blocks.
while (dataLength > exports.BLOCK_SIZE) {
for (var i = 0; i < exports.BLOCK_SIZE; i++) {
this._buffer[i] = data[dataPos + i];
}
this._processBlock(exports.BLOCK_SIZE);
dataPos += exports.BLOCK_SIZE;
dataLength -= exports.BLOCK_SIZE;
this._bufferLength = 0;
}
// Copy leftovers to buffer.
for (var i = 0; i < dataLength; i++) {
this._buffer[this._bufferLength + i] = data[dataPos + i];
}
this._bufferLength += dataLength;
return this;
};
BLAKE2b.prototype.finish = function (out) {
if (!this._finished) {
for (var i = this._bufferLength; i < exports.BLOCK_SIZE; i++) {
this._buffer[i] = 0;
}
// Set last block flag.
this._flag[0] = 0xffffffff;
this._flag[1] = 0xffffffff;
// Set last node flag if last node in tree.
if (this._lastNode) {
this._flag[2] = 0xffffffff;
this._flag[3] = 0xffffffff;
}
this._processBlock(this._bufferLength);
this._finished = true;
}
// Reuse buffer as temporary space for digest.
var tmp = this._buffer.subarray(0, 64);
for (var i = 0; i < 16; i++) {
(0, binary_1.writeUint32LE)(this._state[i], tmp, i * 4);
}
out.set(tmp.subarray(0, out.length));
return this;
};
BLAKE2b.prototype.digest = function () {
var out = new Uint8Array(this.digestLength);
this.finish(out);
return out;
};
BLAKE2b.prototype.clean = function () {
(0, wipe_1.wipe)(this._vtmp);
(0, wipe_1.wipe)(this._mtmp);
(0, wipe_1.wipe)(this._state);
(0, wipe_1.wipe)(this._buffer);
(0, wipe_1.wipe)(this._initialState);
if (this._paddedKey) {
(0, wipe_1.wipe)(this._paddedKey);
}
this._bufferLength = 0;
(0, wipe_1.wipe)(this._ctr);
(0, wipe_1.wipe)(this._flag);
this._lastNode = false;
this._finished = false;
};
BLAKE2b.prototype.saveState = function () {
if (this._finished) {
throw new Error("blake2b: cannot save finished state");
}
return {
state: new Uint32Array(this._state),
buffer: new Uint8Array(this._buffer),
bufferLength: this._bufferLength,
ctr: new Uint32Array(this._ctr),
flag: new Uint32Array(this._flag),
lastNode: this._lastNode,
paddedKey: this._paddedKey ? new Uint8Array(this._paddedKey) : undefined,
initialState: new Uint32Array(this._initialState)
};
};
BLAKE2b.prototype.restoreState = function (savedState) {
this._state.set(savedState.state);
this._buffer.set(savedState.buffer);
this._bufferLength = savedState.bufferLength;
this._ctr.set(savedState.ctr);
this._flag.set(savedState.flag);
this._lastNode = savedState.lastNode;
if (this._paddedKey) {
(0, wipe_1.wipe)(this._paddedKey);
}
this._paddedKey = savedState.paddedKey ? new Uint8Array(savedState.paddedKey) : undefined;
this._initialState.set(savedState.initialState);
return this;
};
BLAKE2b.prototype.cleanSavedState = function (savedState) {
(0, wipe_1.wipe)(savedState.state);
(0, wipe_1.wipe)(savedState.buffer);
(0, wipe_1.wipe)(savedState.initialState);
if (savedState.paddedKey) {
(0, wipe_1.wipe)(savedState.paddedKey);
}
savedState.bufferLength = 0;
(0, wipe_1.wipe)(savedState.ctr);
(0, wipe_1.wipe)(savedState.flag);
savedState.lastNode = false;
};
BLAKE2b.prototype._G = function (v, al, bl, cl, dl, ah, bh, ch, dh, ml0, mh0, ml1, mh1) {
var vla = v[al], vha = v[ah], vlb = v[bl], vhb = v[bh], vlc = v[cl], vhc = v[ch], vld = v[dl], vhd = v[dh];
// 64-bit: va += vb
var w = vla & 0xffff, x = vla >>> 16, y = vha & 0xffff, z = vha >>> 16;
w += vlb & 0xffff;
x += vlb >>> 16;
y += vhb & 0xffff;
z += vhb >>> 16;
x += w >>> 16;
y += x >>> 16;
z += y >>> 16;
vha = (y & 0xffff) | (z << 16);
vla = (w & 0xffff) | (x << 16);
// 64-bit: va += m[sigma[r][2 * i + 0]]
w = vla & 0xffff;
x = vla >>> 16;
y = vha & 0xffff;
z = vha >>> 16;
w += ml0 & 0xffff;
x += ml0 >>> 16;
y += mh0 & 0xffff;
z += mh0 >>> 16;
x += w >>> 16;
y += x >>> 16;
z += y >>> 16;
vha = (y & 0xffff) | (z << 16);
vla = (w & 0xffff) | (x << 16);
// 64-bit: vd ^= va
vld ^= vla;
vhd ^= vha;
// 64-bit: rot(vd, 32)
w = vhd;
vhd = vld;
vld = w;
// 64-bit: vc += vd
w = vlc & 0xffff;
x = vlc >>> 16;
y = vhc & 0xffff;
z = vhc >>> 16;
w += vld & 0xffff;
x += vld >>> 16;
y += vhd & 0xffff;
z += vhd >>> 16;
x += w >>> 16;
y += x >>> 16;
z += y >>> 16;
vhc = (y & 0xffff) | (z << 16);
vlc = (w & 0xffff) | (x << 16);
// 64-bit: vb ^= vc
vlb ^= vlc;
vhb ^= vhc;
// 64-bit: rot(vb, 24)
w = vlb << 8 | vhb >>> 24;
vlb = vhb << 8 | vlb >>> 24;
vhb = w;
// 64-bit: va += vb
w = vla & 0xffff;
x = vla >>> 16;
y = vha & 0xffff;
z = vha >>> 16;
w += vlb & 0xffff;
x += vlb >>> 16;
y += vhb & 0xffff;
z += vhb >>> 16;
x += w >>> 16;
y += x >>> 16;
z += y >>> 16;
vha = (y & 0xffff) | (z << 16);
vla = (w & 0xffff) | (x << 16);
// 64-bit: va += m[sigma[r][2 * i + 1]
w = vla & 0xffff;
x = vla >>> 16;
y = vha & 0xffff;
z = vha >>> 16;
w += ml1 & 0xffff;
x += ml1 >>> 16;
y += mh1 & 0xffff;
z += mh1 >>> 16;
x += w >>> 16;
y += x >>> 16;
z += y >>> 16;
vha = (y & 0xffff) | (z << 16);
vla = (w & 0xffff) | (x << 16);
// 64-bit: vd ^= va
vld ^= vla;
vhd ^= vha;
// 64-bit: rot(vd, 16)
w = vld << 16 | vhd >>> 16;
vld = vhd << 16 | vld >>> 16;
vhd = w;
// 64-bit: vc += vd
w = vlc & 0xffff;
x = vlc >>> 16;
y = vhc & 0xffff;
z = vhc >>> 16;
w += vld & 0xffff;
x += vld >>> 16;
y += vhd & 0xffff;
z += vhd >>> 16;
x += w >>> 16;
y += x >>> 16;
z += y >>> 16;
vhc = (y & 0xffff) | (z << 16);
vlc = (w & 0xffff) | (x << 16);
// 64-bit: vb ^= vc
vlb ^= vlc;
vhb ^= vhc;
// 64-bit: rot(vb, 63)
w = vhb << 1 | vlb >>> 31;
vlb = vlb << 1 | vhb >>> 31;
vhb = w;
v[al] = vla;
v[ah] = vha;
v[bl] = vlb;
v[bh] = vhb;
v[cl] = vlc;
v[ch] = vhc;
v[dl] = vld;
v[dh] = vhd;
};
BLAKE2b.prototype._incrementCounter = function (n) {
for (var i = 0; i < 3; i++) {
var a = this._ctr[i] + n;
this._ctr[i] = a >>> 0;
if (this._ctr[i] === a) {
return;
}
n = 1;
}
};
BLAKE2b.prototype._processBlock = function (length) {
this._incrementCounter(length);
var v = this._vtmp;
v.set(this._state);
v.set(IV, 16);
v[12 * 2 + 0] ^= this._ctr[0];
v[12 * 2 + 1] ^= this._ctr[1];
v[13 * 2 + 0] ^= this._ctr[2];
v[13 * 2 + 1] ^= this._ctr[3];
v[14 * 2 + 0] ^= this._flag[0];
v[14 * 2 + 1] ^= this._flag[1];
v[15 * 2 + 0] ^= this._flag[2];
v[15 * 2 + 1] ^= this._flag[3];
var m = this._mtmp;
for (var i = 0; i < 32; i++) {
m[i] = (0, binary_1.readUint32LE)(this._buffer, i * 4);
}
for (var r = 0; r < 12; r++) {
this._G(v, 0, 8, 16, 24, 1, 9, 17, 25, m[SIGMA[r][0]], m[SIGMA[r][0] + 1], m[SIGMA[r][1]], m[SIGMA[r][1] + 1]);
this._G(v, 2, 10, 18, 26, 3, 11, 19, 27, m[SIGMA[r][2]], m[SIGMA[r][2] + 1], m[SIGMA[r][3]], m[SIGMA[r][3] + 1]);
this._G(v, 4, 12, 20, 28, 5, 13, 21, 29, m[SIGMA[r][4]], m[SIGMA[r][4] + 1], m[SIGMA[r][5]], m[SIGMA[r][5] + 1]);
this._G(v, 6, 14, 22, 30, 7, 15, 23, 31, m[SIGMA[r][6]], m[SIGMA[r][6] + 1], m[SIGMA[r][7]], m[SIGMA[r][7] + 1]);
this._G(v, 0, 10, 20, 30, 1, 11, 21, 31, m[SIGMA[r][8]], m[SIGMA[r][8] + 1], m[SIGMA[r][9]], m[SIGMA[r][9] + 1]);
this._G(v, 2, 12, 22, 24, 3, 13, 23, 25, m[SIGMA[r][10]], m[SIGMA[r][10] + 1], m[SIGMA[r][11]], m[SIGMA[r][11] + 1]);
this._G(v, 4, 14, 16, 26, 5, 15, 17, 27, m[SIGMA[r][12]], m[SIGMA[r][12] + 1], m[SIGMA[r][13]], m[SIGMA[r][13] + 1]);
this._G(v, 6, 8, 18, 28, 7, 9, 19, 29, m[SIGMA[r][14]], m[SIGMA[r][14] + 1], m[SIGMA[r][15]], m[SIGMA[r][15] + 1]);
}
for (var i = 0; i < 16; i++) {
this._state[i] ^= v[i] ^ v[i + 16];
}
};
return BLAKE2b;
}());
exports.BLAKE2b = BLAKE2b;
function hash(data, digestLength, config) {
if (digestLength === void 0) { digestLength = exports.DIGEST_LENGTH; }
var h = new BLAKE2b(digestLength, config);
h.update(data);
var digest = h.digest();
h.clean();
return digest;
}
exports.hash = hash;
//# sourceMappingURL=blake2b.js.map