|
|
// https://tools.ietf.org/html/rfc7693
|
|
|
import {MASK,int32s2bytes,bytes2int32s,zeroPad} from "./util.js";
|
|
|
import {MASK, int32s2bytes, bytes2int32s, zeroPad} from "./util.js";
|
|
|
|
|
|
const BLOCK_LEN=64;
|
|
|
const BLOCK_LEN = 64;
|
|
|
|
|
|
const IV=[0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19];
|
|
|
const IV = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19];
|
|
|
|
|
|
function rrot(x,shift){
|
|
|
return ((x>>>shift)|(x<<(32-shift)))&MASK;
|
|
|
function rrot(x, shift) {
|
|
|
return ((x >>> shift) | (x << (32-shift))) & MASK;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -14,81 +14,83 @@ function rrot(x,shift){
|
|
|
* @param {Array} key byte array, 0<=key.length<=32
|
|
|
* @returns {BLAKE2S}
|
|
|
*/
|
|
|
export function BLAKE2S(outputLen=32,key=[]){
|
|
|
this._buffer=[];
|
|
|
this._dataLen=[0,0]; // low, high
|
|
|
this._outputLen=outputLen;
|
|
|
|
|
|
this._state=IV.slice();
|
|
|
this._state[0]^=0x01010000^(key.length<<8)^this._outputLen;
|
|
|
|
|
|
if(key.length>0){this.update(zeroPad(key,BLOCK_LEN));}
|
|
|
export function BLAKE2S(outputLen = 32, key = []) {
|
|
|
this._buffer = [];
|
|
|
this._dataLen = [0, 0]; // low, high
|
|
|
this._outputLen = outputLen;
|
|
|
|
|
|
this._state = IV.slice();
|
|
|
this._state[0] ^= 0x01010000 ^ (key.length << 8) ^ this._outputLen;
|
|
|
|
|
|
if (key.length > 0) {this.update(zeroPad(key, BLOCK_LEN));}
|
|
|
}
|
|
|
|
|
|
BLAKE2S.prototype.update=function(data){
|
|
|
for(let i=0;i<data.length;i++){
|
|
|
if(this._buffer.length==BLOCK_LEN){
|
|
|
BLAKE2S.prototype.update = function (data) {
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
if (this._buffer.length == BLOCK_LEN) {
|
|
|
this._compress(false);
|
|
|
this._buffer=[];
|
|
|
this._buffer = [];
|
|
|
}
|
|
|
this._buffer.push(data[i]);
|
|
|
this._dataLen[0]=(this._dataLen[0]+1)&MASK;
|
|
|
if(this._dataLen[0]<this._buffer.length){this._dataLen[1]++;}
|
|
|
this._dataLen[0] = (this._dataLen[0]+1) & MASK;
|
|
|
if (this._dataLen[0] < this._buffer.length) {this._dataLen[1]++;}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
BLAKE2S.prototype.digest=function(){
|
|
|
this._buffer=zeroPad(this._buffer,BLOCK_LEN);
|
|
|
BLAKE2S.prototype.digest = function () {
|
|
|
this._buffer = zeroPad(this._buffer, BLOCK_LEN);
|
|
|
this._compress(true);
|
|
|
return int32s2bytes(this._state).slice(0,this._outputLen);
|
|
|
return int32s2bytes(this._state).slice(0, this._outputLen);
|
|
|
};
|
|
|
|
|
|
BLAKE2S.prototype._compress=function(last){
|
|
|
const 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]
|
|
|
BLAKE2S.prototype._compress = function (last) {
|
|
|
const 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]
|
|
|
];
|
|
|
let v=this._state.concat(IV);
|
|
|
v[12]^=this._dataLen[0];
|
|
|
v[13]^=this._dataLen[1];
|
|
|
if(last){v[14]^=MASK;}
|
|
|
let data=bytes2int32s(this._buffer);
|
|
|
let v = this._state.concat(IV);
|
|
|
v[12] ^= this._dataLen[0];
|
|
|
v[13] ^= this._dataLen[1];
|
|
|
if (last) {v[14] ^= MASK;}
|
|
|
let data = bytes2int32s(this._buffer);
|
|
|
|
|
|
for(let i=0;i<10;i++){
|
|
|
let perm=SIGMA[i%10];
|
|
|
this._mix(v,0,4,8,12,data[perm[0]],data[perm[1]]);
|
|
|
this._mix(v,1,5,9,13,data[perm[2]],data[perm[3]]);
|
|
|
this._mix(v,2,6,10,14,data[perm[4]],data[perm[5]]);
|
|
|
this._mix(v,3,7,11,15,data[perm[6]],data[perm[7]]);
|
|
|
for (let i = 0; i < 10; i++) {
|
|
|
let perm = SIGMA[i % 10];
|
|
|
this._mix(v, 0, 4, 8, 12, data[perm[0]], data[perm[1]]);
|
|
|
this._mix(v, 1, 5, 9, 13, data[perm[2]], data[perm[3]]);
|
|
|
this._mix(v, 2, 6, 10, 14, data[perm[4]], data[perm[5]]);
|
|
|
this._mix(v, 3, 7, 11, 15, data[perm[6]], data[perm[7]]);
|
|
|
|
|
|
this._mix(v,0,5,10,15,data[perm[8]],data[perm[9]]);
|
|
|
this._mix(v,1,6,11,12,data[perm[10]],data[perm[11]]);
|
|
|
this._mix(v,2,7,8,13,data[perm[12]],data[perm[13]]);
|
|
|
this._mix(v,3,4,9,14,data[perm[14]],data[perm[15]]);
|
|
|
this._mix(v, 0, 5, 10, 15, data[perm[8]], data[perm[9]]);
|
|
|
this._mix(v, 1, 6, 11, 12, data[perm[10]], data[perm[11]]);
|
|
|
this._mix(v, 2, 7, 8, 13, data[perm[12]], data[perm[13]]);
|
|
|
this._mix(v, 3, 4, 9, 14, data[perm[14]], data[perm[15]]);
|
|
|
}
|
|
|
|
|
|
this._state=this._state.map((x,i)=>x^v[i]^v[i+8]);
|
|
|
this._state = this._state.map((x, i) => x ^ v[i] ^ v[i+8]);
|
|
|
};
|
|
|
|
|
|
BLAKE2S.prototype._mix=function(arr,ia,ib,ic,id,x,y){
|
|
|
let a=arr[ia], b=arr[ib], c=arr[ic], d=arr[id];
|
|
|
a=(a+b+x)&MASK; d=rrot(d^a,16);
|
|
|
c=(c+d)&MASK; b=rrot(b^c,12);
|
|
|
a=(a+b+y)&MASK; d=rrot(d^a,8);
|
|
|
c=(c+d)&MASK; b=rrot(b^c,7);
|
|
|
arr[ia]=a; arr[ib]=b; arr[ic]=c; arr[id]=d;
|
|
|
BLAKE2S.prototype._mix = function (arr, ia, ib, ic, id, x, y) {
|
|
|
let a = arr[ia], b = arr[ib], c = arr[ic], d = arr[id];
|
|
|
a = (a + b + x) & MASK; d = rrot(d ^ a, 16);
|
|
|
c = (c + d) & MASK; b = rrot(b ^ c, 12);
|
|
|
a = (a + b + y) & MASK; d = rrot(d ^ a, 8);
|
|
|
c = (c + d) & MASK; b = rrot(b ^ c, 7);
|
|
|
arr[ia] = a; arr[ib] = b; arr[ic] = c; arr[id] = d;
|
|
|
};
|
|
|
|
|
|
export function blake2s(data,outputLen=32,key=[]){
|
|
|
let h=new BLAKE2S(outputLen,key);
|
|
|
for(let i=0;i<data.length;i+=BLOCK_LEN){h.update(data.slice(i,i+BLOCK_LEN));}
|
|
|
export function blake2s(data, outputLen = 32, key = []) {
|
|
|
let h = new BLAKE2S(outputLen, key);
|
|
|
for (let i = 0; i < data.length; i += BLOCK_LEN) {
|
|
|
h.update(data.slice(i, i + BLOCK_LEN));
|
|
|
}
|
|
|
return h.digest();
|
|
|
}
|