From 58f7576422addbc3c523d60121d150287f60a066 Mon Sep 17 00:00:00 2001 From: Mathias Buus Date: Thu, 8 Jun 2017 19:13:29 +0200 Subject: [PATCH] pass @emilbayes' test vectors --- .travis.yml | 6 +++++ blake2b.wasm | Bin 8218 -> 8397 bytes blake2b.wat | 44 +++++++++++++++++----------------- index.js | 37 ++++++++++++++++++++++++----- package.json | 7 ++++-- test.js | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 130 insertions(+), 29 deletions(-) create mode 100644 .travis.yml create mode 100644 test.js diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..1331083 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +sudo: false + +language: node_js + +node_js: + - "8" diff --git a/blake2b.wasm b/blake2b.wasm index d847981210716296d986c8e0f8d686beffbf0613..cdd7667cea0027e9df03d9f9a610fa1b4b4c011d 100644 GIT binary patch delta 331 zcmbQ`aMp1`Mg3(5mTAlk3JgvR<{-+EBMZh7fU_jvECo1A1I{vlvn=4O0}OEH2?X;3 zf_VeV)COAl03rMW!Tf+={(vwi&eREZJOK{tbey>yN#m&LShC` z;^W&dKb9{4yL@TAqXa@`0Z`^*>#X;`&QEE-$l#~|l9|LPV(F-XP_qH3=Jl_(Tl=?u iJ1FmHfRNY$l=yk*$LxuVH-EUz;AjDo*=)^tUk(7et62&F delta 153 zcmX@>ILl!|h2jExmdA_?jtmNnRtyY|jE)Q-ipdeoV+K)^l^Aub&6yb#7#t@sW;w0? zaQVyncYC(mK!j!hg+9Lh@?+`pzsr}_L&O#U#V)qadjISEl=h1ZlNU0Is6!++03}}k iYP+?6>$ijQ5TPAFp`V9-%$~S-^M~6Eo8K|smjeKaBRM1h diff --git a/blake2b.wat b/blake2b.wat index 5ef36be..757bf0e 100644 --- a/blake2b.wat +++ b/blake2b.wat @@ -5,33 +5,35 @@ (func (export "blake2b_init") (param $ptr i32) (param $outlen i32) ;; setup param block (expect memory to be cleared) - ;; 1 byte outlen. - (i32.store8 (i32.const 0) (get_local $outlen)) - - ;; 1 byte keylen. - (i32.store8 (i32.const 1) (i32.const 0)) - - ;; 1 byte fanout. - (i32.store8 (i32.const 2) (i32.const 1)) - - ;; 1 byte depth. - (i32.store8 (i32.const 3) (i32.const 1)) - - ;; init the hash - ;; b array: 0-128 + (i64.store (get_local $ptr) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 8)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 16)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 24)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 32)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 40)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 48)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 56)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 64)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 72)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 80)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 88)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 96)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 104)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 112)) (i64.const 0)) + (i64.store (i32.add (get_local $ptr) (i32.const 120)) (i64.const 0)) ;; h array: 128-192, (8 * i64) ;; TODO: support xor against param block and stuff, for now just xor against length (i64.store (i32.add (get_local $ptr) (i32.const 128)) (i64.xor (i64.const 0x6a09e667f3bcc908) (i64.load (i32.const 0)))) - (i64.store (i32.add (get_local $ptr) (i32.const 136)) (i64.const 0xbb67ae8584caa73b)) - (i64.store (i32.add (get_local $ptr) (i32.const 144)) (i64.const 0x3c6ef372fe94f82b)) - (i64.store (i32.add (get_local $ptr) (i32.const 152)) (i64.const 0xa54ff53a5f1d36f1)) - (i64.store (i32.add (get_local $ptr) (i32.const 160)) (i64.const 0x510e527fade682d1)) - (i64.store (i32.add (get_local $ptr) (i32.const 168)) (i64.const 0x9b05688c2b3e6c1f)) - (i64.store (i32.add (get_local $ptr) (i32.const 176)) (i64.const 0x1f83d9abfb41bd6b)) - (i64.store (i32.add (get_local $ptr) (i32.const 184)) (i64.const 0x5be0cd19137e2179)) + (i64.store (i32.add (get_local $ptr) (i32.const 136)) (i64.xor (i64.const 0xbb67ae8584caa73b) (i64.load (i32.const 8)))) + (i64.store (i32.add (get_local $ptr) (i32.const 144)) (i64.xor (i64.const 0x3c6ef372fe94f82b) (i64.load (i32.const 16)))) + (i64.store (i32.add (get_local $ptr) (i32.const 152)) (i64.xor (i64.const 0xa54ff53a5f1d36f1) (i64.load (i32.const 24)))) + (i64.store (i32.add (get_local $ptr) (i32.const 160)) (i64.xor (i64.const 0x510e527fade682d1) (i64.load (i32.const 32)))) + (i64.store (i32.add (get_local $ptr) (i32.const 168)) (i64.xor (i64.const 0x9b05688c2b3e6c1f) (i64.load (i32.const 40)))) + (i64.store (i32.add (get_local $ptr) (i32.const 176)) (i64.xor (i64.const 0x1f83d9abfb41bd6b) (i64.load (i32.const 48)))) + (i64.store (i32.add (get_local $ptr) (i32.const 184)) (i64.xor (i64.const 0x5be0cd19137e2179) (i64.load (i32.const 56)))) ;; t int.64: 192-200 (i64.store (i32.add (get_local $ptr) (i32.const 192)) (i64.const 0)) diff --git a/index.js b/index.js index 123d40b..bc45ea0 100644 --- a/index.js +++ b/index.js @@ -9,8 +9,8 @@ var freeList = [] module.exports = Blake2b -function Blake2b () { - if (!(this instanceof Blake2b)) return new Blake2b() +function Blake2b (digestLength, key, salt, personal) { + if (!(this instanceof Blake2b)) return new Blake2b(digestLength, key, salt, personal) if (!mod) throw new Error('WASM not loaded. Wait for Blake2b.ready(cb)') if (!freeList.length) { @@ -18,9 +18,26 @@ function Blake2b () { head += 216 } + this.digestLength = digestLength || 32 this.finalized = false this.pointer = freeList.pop() - mod.blake2b_init(this.pointer, 32) + + memory.fill(0, 0, 64) + memory[0] = this.digestLength + memory[1] = key ? key.length : 0 + memory[2] = 1 // fanout + memory[3] = 1 // depth + + if (salt) memory.set(salt, 32) + if (personal) memory.set(personal, 48) + + mod.blake2b_init(this.pointer, this.digestLength) + + if (key) { + this.update(key) + memory.fill(0, head, head + key.length) // whiteout key + memory[this.pointer + 200] = 128 + } } Blake2b.prototype.ready = Blake2b.ready @@ -40,10 +57,18 @@ Blake2b.prototype.digest = function (enc) { freeList.push(this.pointer) mod.blake2b_final(this.pointer) - if (!enc || enc === 'binary') return memory.slice(this.pointer + 128, this.pointer + 128 + 32) - if (enc === 'hex') return hexSlice(memory, this.pointer + 128, 32) + if (!enc || enc === 'binary') { + return memory.slice(this.pointer + 128, this.pointer + 128 + this.digestLength) + } + + if (enc === 'hex') { + return hexSlice(memory, this.pointer + 128, this.digestLength) + } + + for (var i = 0; i < this.digestLength; i++) { + enc[i] = memory[this.pointer + 128 + i] + } - for (var i = 0; i < 32; i++) enc[i] = memory[this.pointer + 128 + i] return enc } diff --git a/package.json b/package.json index 6f316ae..d3ce234 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "brfs": "^1.4.3" }, "devDependencies": { - "browserify": "^14.4.0" + "blake2b": "^1.2.0", + "browserify": "^14.4.0", + "tape": "^4.6.3" }, "browserify": { "transform": [ @@ -16,7 +18,8 @@ }, "scripts": { "compile": "wast2wasm blake2b.wat -o blake2b.wasm", - "demo": "browserify example.js > bundle.js" + "demo": "browserify example.js > bundle.js", + "test": "tape tape.js" }, "repository": { "type": "git", diff --git a/test.js b/test.js new file mode 100644 index 0000000..aedc68a --- /dev/null +++ b/test.js @@ -0,0 +1,65 @@ +var tape = require('tape') +var blake2b = require('./') +var vectors = require('blake2b/test-vectors.json') + +blake2b.ready(function () { + tape('hello world', function (t) { + var hash = blake2b() + .update(Buffer.from('hello')) + .update(Buffer.from(' ')) + .update(Buffer.from('world')) + .digest('hex') + + t.same(hash, '256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610') + t.end() + }) + + tape('hello world', function (t) { + var hash = blake2b(64) + .update(Buffer.from('hello')) + .update(Buffer.from(' ')) + .update(Buffer.from('world')) + .digest('hex') + + t.same(hash, '021ced8799296ceca557832ab941a50b4a11f83478cf141f51f933f653ab9fbcc05a037cddbed06e309bf334942c4e58cdf1a46e237911ccd7fcf9787cbc7fd0') + t.end() + }) + + tape('both at the same time', function (t) { + var a = blake2b() + var b = blake2b(64) + + var hash = a + .update(Buffer.from('hello')) + .update(Buffer.from(' ')) + .update(Buffer.from('world')) + .digest('hex') + + t.same(hash, '256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610') + + var hash = b + .update(Buffer.from('hello')) + .update(Buffer.from(' ')) + .update(Buffer.from('world')) + .digest('hex') + + t.same(hash, '021ced8799296ceca557832ab941a50b4a11f83478cf141f51f933f653ab9fbcc05a037cddbed06e309bf334942c4e58cdf1a46e237911ccd7fcf9787cbc7fd0') + t.end() + }) + + vectors.forEach(function (vector, i) { + tape('test-vectors.json #' + i, function (t) { + var key = vector.key && Buffer.from(vector.key, 'hex') + var salt = vector.salt && Buffer.from(vector.salt, 'hex') + var personal = vector.personal && Buffer.from(vector.personal, 'hex') + + var hash = blake2b(vector.outlen, key, salt, personal) + .update(Buffer.from(vector.input, 'hex')) + .digest('hex') + + t.same(hash, vector.out) + t.end() + }) + }) +}) +