UNPKG

julc

Version:

yul with some solidioms

299 lines (231 loc) 6.04 kB
/*! * ripemd160.js - RIPEMD160 implementation for bcrypto * Copyright (c) 2017-2019, Christopher Jeffrey (MIT License). * https://github.com/bcoin-org/bcrypto * * Parts of this software are based on indutny/hash.js: * Copyright (c) 2014, Fedor Indutny (MIT License). * https://github.com/indutny/hash.js * * Resources: * https://en.wikipedia.org/wiki/RIPEMD-160 * https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf * https://github.com/indutny/hash.js/blob/master/lib/hash/ripemd.js */ 'use strict'; const assert = require('assert'); /* * Constants */ const FINALIZED = -1; const DESC = Buffer.alloc(8, 0x00); const PADDING = Buffer.alloc(64, 0x00); PADDING[0] = 0x80; const r = new Uint8Array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 ]); const rh = new Uint8Array([ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 ]); const s = new Uint8Array([ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 ]); const sh = new Uint8Array([ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 ]); /** * RIPEMD160 */ class RIPEMD160 { constructor() { this.state = new Uint32Array(5); this.msg = new Uint32Array(16); this.block = Buffer.alloc(64); this.size = FINALIZED; } init() { this.state[0] = 0x67452301; this.state[1] = 0xefcdab89; this.state[2] = 0x98badcfe; this.state[3] = 0x10325476; this.state[4] = 0xc3d2e1f0; this.size = 0; return this; } update(data) { assert(Buffer.isBuffer(data)); this._update(data, data.length); return this; } final() { return this._final(Buffer.alloc(20)); } _update(data, len) { assert(this.size !== FINALIZED, 'Context is not initialized.'); let pos = this.size & 63; let off = 0; this.size += len; if (pos > 0) { let want = 64 - pos; if (want > len) want = len; data.copy(this.block, pos, off, off + want); pos += want; len -= want; off += want; if (pos < 64) return; this._transform(this.block, 0); } while (len >= 64) { this._transform(data, off); off += 64; len -= 64; } if (len > 0) data.copy(this.block, 0, off, off + len); } _final(out) { assert(this.size !== FINALIZED, 'Context is not initialized.'); const pos = this.size & 63; const len = this.size * 8; writeU32(DESC, len >>> 0, 0); writeU32(DESC, (len * (1 / 0x100000000)) >>> 0, 4); this._update(PADDING, 1 + ((119 - pos) & 63)); this._update(DESC, 8); for (let i = 0; i < 5; i++) { writeU32(out, this.state[i], i * 4); this.state[i] = 0; } for (let i = 0; i < 16; i++) this.msg[i] = 0; for (let i = 0; i < 64; i++) this.block[i] = 0; this.size = FINALIZED; return out; } _transform(chunk, pos) { const W = this.msg; let A = this.state[0]; let B = this.state[1]; let C = this.state[2]; let D = this.state[3]; let E = this.state[4]; let Ah = A; let Bh = B; let Ch = C; let Dh = D; let Eh = E; for (let i = 0; i < 16; i++) W[i] = readU32(chunk, pos + i * 4); for (let j = 0; j < 80; j++) { let a = A + f(j, B, C, D) + W[r[j]] + K(j); let b = rotl32(a, s[j]); let T = b + E; A = E; E = D; D = rotl32(C, 10); C = B; B = T; a = Ah + f(79 - j, Bh, Ch, Dh) + W[rh[j]] + Kh(j); b = rotl32(a, sh[j]); T = b + Eh; Ah = Eh; Eh = Dh; Dh = rotl32(Ch, 10); Ch = Bh; Bh = T; } const T = this.state[1] + C + Dh; this.state[1] = this.state[2] + D + Eh; this.state[2] = this.state[3] + E + Ah; this.state[3] = this.state[4] + A + Bh; this.state[4] = this.state[0] + B + Ch; this.state[0] = T; } static hash() { return new RIPEMD160(); } static digest(data) { return RIPEMD160.ctx.init().update(data).final(); } } /* * Static */ RIPEMD160.ctx = new RIPEMD160(); /* * Helpers */ function rotl32(w, b) { return (w << b) | (w >>> (32 - b)); } function f(j, x, y, z) { if (j <= 15) return x ^ y ^ z; if (j <= 31) return (x & y) | ((~x) & z); if (j <= 47) return (x | (~y)) ^ z; if (j <= 63) return (x & z) | (y & (~z)); return x ^ (y | (~z)); } function K(j) { if (j <= 15) return 0x00000000; if (j <= 31) return 0x5a827999; if (j <= 47) return 0x6ed9eba1; if (j <= 63) return 0x8f1bbcdc; return 0xa953fd4e; } function Kh(j) { if (j <= 15) return 0x50a28be6; if (j <= 31) return 0x5c4dd124; if (j <= 47) return 0x6d703ef3; if (j <= 63) return 0x7a6d76e9; return 0x00000000; } function readU32(data, off) { return (data[off++] + data[off++] * 0x100 + data[off++] * 0x10000 + data[off] * 0x1000000); } function writeU32(dst, num, off) { dst[off++] = num; num >>>= 8; dst[off++] = num; num >>>= 8; dst[off++] = num; num >>>= 8; dst[off++] = num; return off; } /* * Expose */ module.exports = RIPEMD160;