Mathias Buus
7 years ago
commit
771a3f767d
10 changed files with 3146 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||
node_modules |
|||
bundle.js |
@ -0,0 +1,21 @@ |
|||
The MIT License (MIT) |
|||
|
|||
Copyright (c) 2017 Mathias Buus |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in |
|||
all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
@ -0,0 +1,65 @@ |
|||
# blake2b-wasm |
|||
|
|||
Blake2b implemented in WASM |
|||
|
|||
``` |
|||
npm install blake2b-wasm |
|||
``` |
|||
|
|||
Works in browsers that support WASM and Node.js 8+. |
|||
|
|||
## Usage |
|||
|
|||
``` js |
|||
var blake2b = require('blake2b-wasm') |
|||
|
|||
if (!blake2b.SUPPORTED) { |
|||
console.log('WebAssembly not supported by your runtime') |
|||
} |
|||
|
|||
blake2b.ready(function (err) { |
|||
if (err) throw err |
|||
|
|||
var hash = blake2b() |
|||
.update(new Buffer('hello')) // pass in a buffer or uint8array |
|||
.update(new Buffer(' ')) |
|||
.update(new Buffer('world')) |
|||
.digest('hex') |
|||
|
|||
console.log('Blake2b hash of "hello world" is %s', hash) |
|||
}) |
|||
``` |
|||
|
|||
## API |
|||
|
|||
#### `var hash = blake2b()` |
|||
|
|||
Create a new hash instance |
|||
|
|||
#### `hash.update(data)` |
|||
|
|||
Update the hash with a new piece of data. `data` should be a buffer or uint8array. |
|||
|
|||
#### `var digest = hash.digest([enc])` |
|||
|
|||
Digest the hash. |
|||
|
|||
## Browser demo |
|||
|
|||
There is a browser example included in [example.html](example.html) and [example.js](example.js). |
|||
|
|||
## Contributing |
|||
|
|||
The bulk of this module is implemented in WebAssembly in the [blake2b.wat](blake2b.wat) file. |
|||
The format of this file is S-Expressions that can be compiled to their binary WASM representation by doing |
|||
|
|||
``` |
|||
# also available as `npm run compile` |
|||
wast2wasm blake2b.wat -o blake2b.wasm |
|||
``` |
|||
|
|||
If you do not have `wast2wasm` installed follow the instructions here, https://github.com/WebAssembly/wabt |
|||
|
|||
## License |
|||
|
|||
MIT |
Binary file not shown.
File diff suppressed because it is too large
@ -0,0 +1,14 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>Blake2b-WASM Demo</title> |
|||
</head> |
|||
<body> |
|||
<ol> |
|||
<li>Run `npm run demo` if you haven't</li> |
|||
<li>Reload this page</li> |
|||
<li>Open the console</li> |
|||
</ol> |
|||
<script src="bundle.js"></script> |
|||
</body> |
|||
</html> |
@ -0,0 +1,12 @@ |
|||
var blake2b = require('./') |
|||
|
|||
blake2b.ready(function () { |
|||
var hash = blake2b() |
|||
.update(new Buffer('hello')) |
|||
.update(new Buffer(' ')) |
|||
.update(new Buffer('world')) |
|||
.digest('hex') |
|||
|
|||
console.log('Blake2b hash of "hello world" is %s', hash) |
|||
}) |
|||
|
@ -0,0 +1,77 @@ |
|||
var sigma = [ |
|||
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ] , |
|||
[ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ] , |
|||
[ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ] , |
|||
[ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ] , |
|||
[ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ] , |
|||
[ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ] , |
|||
[ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ] , |
|||
[ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ] , |
|||
[ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ] , |
|||
[ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 ] , |
|||
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ] , |
|||
[ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ] |
|||
] |
|||
|
|||
function G (r, i, a, b, c, d) { |
|||
return ` |
|||
;; G(${r}, ${i}) |
|||
|
|||
;; ${a} = ${a} + ${b} + $m${sigma[r][2*i+0]} |
|||
(set_local ${a} (i64.add (get_local ${a}) (i64.add (get_local ${b}) (get_local $m${sigma[r][2*i+0]})))) |
|||
|
|||
;; ${d} = rotr64(${d} ^ ${a}, 32) |
|||
(set_local ${d} (i64.rotr (i64.xor (get_local ${d}) (get_local ${a})) (i64.const 32))) |
|||
|
|||
;; ${c} = ${c} + ${d} |
|||
(set_local ${c} (i64.add (get_local ${c}) (get_local ${d}))) |
|||
|
|||
;; ${b} = rotr64(${b} ^ ${c}, 24) |
|||
(set_local ${b} (i64.rotr (i64.xor (get_local ${b}) (get_local ${c})) (i64.const 24))) |
|||
|
|||
;; ${a} = ${a} + ${b} + $m${sigma[r][2*i+1]} |
|||
(set_local ${a} (i64.add (get_local ${a}) (i64.add (get_local ${b}) (get_local $m${sigma[r][2*i+1]})))) |
|||
|
|||
;; ${d} = rotr64(${d} ^ ${a}, 16) |
|||
(set_local ${d} (i64.rotr (i64.xor (get_local ${d}) (get_local ${a})) (i64.const 16))) |
|||
|
|||
;; ${c} = ${c} + ${d} |
|||
(set_local ${c} (i64.add (get_local ${c}) (get_local ${d}))) |
|||
|
|||
;; ${b} = rotr64(${b} ^ ${c}, 63) |
|||
(set_local ${b} (i64.rotr (i64.xor (get_local ${b}) (get_local ${c})) (i64.const 63)))` |
|||
} |
|||
|
|||
function ROUND (r) { |
|||
return ` |
|||
;; ROUND(${r}) |
|||
${G(r,0, '$v0', '$v4', '$v8', '$v12')} |
|||
${G(r,1, '$v1', '$v5', '$v9', '$v13')} |
|||
${G(r,2, '$v2', '$v6', '$v10', '$v14')} |
|||
${G(r,3, '$v3', '$v7', '$v11', '$v15')} |
|||
${G(r,4, '$v0', '$v5', '$v10', '$v15')} |
|||
${G(r,5, '$v1', '$v6', '$v11', '$v12')} |
|||
${G(r,6, '$v2', '$v7', '$v8', '$v13')} |
|||
${G(r,7, '$v3', '$v4', '$v9', '$v14')} |
|||
` |
|||
} |
|||
// function rotr64 (w, c) {
|
|||
// i64
|
|||
// // ( w >> c ) | ( w << ( 64 - c ) )
|
|||
// rotr64
|
|||
// }
|
|||
|
|||
console.log( |
|||
ROUND( 0 ), |
|||
ROUND( 1 ), |
|||
ROUND( 2 ), |
|||
ROUND( 3 ), |
|||
ROUND( 4 ), |
|||
ROUND( 5 ), |
|||
ROUND( 6 ), |
|||
ROUND( 7 ), |
|||
ROUND( 8 ), |
|||
ROUND( 9 ), |
|||
ROUND( 10 ), |
|||
ROUND( 11 ) |
|||
) |
@ -0,0 +1,94 @@ |
|||
var fs = require('fs') |
|||
var buf = toUint8Array(fs.readFileSync(__dirname + '/blake2b.wasm', 'base64')) |
|||
var rdy |
|||
|
|||
var head = 64 |
|||
var mod = null |
|||
var memory = null |
|||
var freeList = [] |
|||
|
|||
module.exports = Blake2b |
|||
|
|||
function Blake2b () { |
|||
if (!(this instanceof Blake2b)) return new Blake2b() |
|||
if (!mod) throw new Error('WASM not loaded. Wait for Blake2b.ready(cb)') |
|||
|
|||
if (!freeList.length) { |
|||
freeList.push(head) |
|||
head += 216 |
|||
} |
|||
|
|||
this.finalized = false |
|||
this.pointer = freeList.pop() |
|||
mod.blake2b_init(this.pointer, 32) |
|||
} |
|||
|
|||
Blake2b.prototype.ready = Blake2b.ready |
|||
|
|||
Blake2b.prototype.update = function (input) { |
|||
if (this.finalized) throw new Error('Hash instance finalized') |
|||
|
|||
memory.set(input, head) |
|||
mod.blake2b_update(this.pointer, head, head + input.length) |
|||
return this |
|||
} |
|||
|
|||
Blake2b.prototype.digest = function (enc) { |
|||
if (this.finalized) throw new Error('Hash instance finalized') |
|||
this.finalized = true |
|||
|
|||
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) |
|||
|
|||
for (var i = 0; i < 32; i++) enc[i] = memory[this.pointer + 128 + i] |
|||
return enc |
|||
} |
|||
|
|||
Blake2b.WASM = buf |
|||
Blake2b.SUPPORTED = typeof WebAssembly !== 'undefined' |
|||
|
|||
Blake2b.ready = function (cb) { |
|||
if (!cb) cb = noop |
|||
if (!Blake2b.SUPPORTED) return cb(new Error('WebAssembly not supported')) |
|||
|
|||
if (!rdy) { |
|||
rdy = WebAssembly.instantiate(buf).then(setup) |
|||
} |
|||
|
|||
return rdy.then(cb).catch(cb) |
|||
} |
|||
|
|||
function noop () {} |
|||
|
|||
function hexSlice (buf, start, len) { |
|||
var str = '' |
|||
for (var i = 0; i < len; i++) str += toHex(buf[start + i]) |
|||
return str |
|||
} |
|||
|
|||
function toHex (n) { |
|||
if (n < 16) return '0' + n.toString(16) |
|||
return n.toString(16) |
|||
} |
|||
|
|||
function setup (w) { |
|||
mod = w.instance.exports |
|||
memory = new Uint8Array(w.instance.exports.memory.buffer) |
|||
} |
|||
|
|||
function toUint8Array (s) { |
|||
if (typeof atob === 'function') { |
|||
return new Uint8Array(atob(s).split('').map(charCodeAt)) |
|||
} |
|||
var b = require('buf' + 'fer') |
|||
return new b.Buffer(s, 'base64') |
|||
} |
|||
|
|||
function charCodeAt (c) { |
|||
return c.charCodeAt(0) |
|||
} |
|||
|
|||
window.Blake2b = module.exports |
@ -0,0 +1,31 @@ |
|||
{ |
|||
"name": "blake2b-wasm", |
|||
"version": "0.0.0", |
|||
"description": "Blake2b implemented in WASM", |
|||
"main": "index.js", |
|||
"dependencies": { |
|||
"brfs": "^1.4.3" |
|||
}, |
|||
"devDependencies": { |
|||
"browserify": "^14.4.0" |
|||
}, |
|||
"browserify": { |
|||
"transform": [ |
|||
"brfs" |
|||
] |
|||
}, |
|||
"scripts": { |
|||
"compile": "wast2wasm blake2b.wat -o blake2b.wasm", |
|||
"demo": "browserify example.js > bundle.js" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "https://github.com/mafintosh/blake2b-wasm.git" |
|||
}, |
|||
"author": "Mathias Buus (@mafintosh)", |
|||
"license": "MIT", |
|||
"bugs": { |
|||
"url": "https://github.com/mafintosh/blake2b-wasm/issues" |
|||
}, |
|||
"homepage": "https://github.com/mafintosh/blake2b-wasm" |
|||
} |
Loading…
Reference in new issue