Skip to content

Instantly share code, notes, and snippets.

@TransparentLC
Created June 27, 2021 05:25
Show Gist options
  • Save TransparentLC/a528c9122f1e356ba202892461cdce90 to your computer and use it in GitHub Desktop.
Save TransparentLC/a528c9122f1e356ba202892461cdce90 to your computer and use it in GitHub Desktop.
4 KB 左右的 ChaCha20Poly1305 认证加密算法实现,参考 https://github.com/thesimj/js-chacha20https://github.com/devi/chacha20poly1305 进行了少量修改。
const { ChaCha20Poly1305 } = require('./chacha20poly1305.min.js');
const hexToBytes = e => new Uint8Array(e.match(/[0-9a-f]{2}/gi).map(e => parseInt(e, 16)));
const bytesToHex = e => Array.from(e).map(e => e.toString(16).padStart(2, 0)).join('');
// Test vectors from:
// https://datatracker.ietf.org/doc/html/rfc7539#section-2.8.2
const keyC = hexToBytes('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f')
const nonceC = hexToBytes('070000004041424344454647');
const authC = hexToBytes('50515253c0c1c2c3c4c5c6c7');
const plainC1 = hexToBytes(''
+ '4c616469657320616e642047656e746c'
+ '656d656e206f662074686520636c6173'
+ '73206f66202739393a20496620492063'
+ '6f756c64206f6666657220796f75206f'
);
const plainC2 = hexToBytes(''
+ '6e6c79206f6e652074697020666f7220'
+ '746865206675747572652c2073756e73'
+ '637265656e20776f756c642062652069'
+ '742e'
);
const contextC1 = new ChaCha20Poly1305(keyC, nonceC, authC);
const cipherC1 = contextC1.encrypt(plainC1);
const cipherC2 = contextC1.encrypt(plainC2);
console.assert(
bytesToHex(cipherC1) === ''
+ 'd31a8d34648e60db7b86afbc53ef7ec2'
+ 'a4aded51296e08fea9e2b5a736ee62d6'
+ '3dbea45e8ca9671282fafb69da92728b'
+ '1a71de0a9e060b2905d6a5b67ecd3b36',
'Cipher C1'
);
console.assert(
bytesToHex(cipherC2) === ''
+ '92ddbd7f2d778b8c9803aee328091b58'
+ 'fab324e4fad675945585808b4831d7bc'
+ '3ff4def08e4b7a9de576d26586cec64b'
+ '6116',
'Cipher C2'
);
const macC = contextC1.mac();
console.assert(bytesToHex(macC) === '1ae10b594f09e26a7e902ecbd0600691', 'Mac C1');
const contextC2 = new ChaCha20Poly1305(keyC, nonceC, authC);
const decryptC1 = contextC2.decrypt(cipherC1);
const decryptC2 = contextC2.decrypt(cipherC2);
console.assert(bytesToHex(plainC1) === bytesToHex(decryptC1), 'Decrypt C1');
console.assert(bytesToHex(plainC2) === bytesToHex(decryptC2), 'Decrypt C2');
console.assert(contextC2.verify(macC), 'Verify C');
/*
* Copyright (c) 2017, Bubelich Mykola
* https://www.bubelich.com
*
* (。◕‿‿◕。)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met, 0x
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* ChaCha20 is a stream cipher designed by D. J. Bernstein.
* It is a refinement of the Salsa20 algorithm, and it uses a 256-bit key.
*
* ChaCha20 successively calls the ChaCha20 block function, with the same key and nonce, and with successively increasing block counter parameters.
* ChaCha20 then serializes the resulting state by writing the numbers in little-endian order, creating a keystream block.
*
* Concatenating the keystream blocks from the successive blocks forms a keystream.
* The ChaCha20 function then performs an XOR of this keystream with the plaintext.
* Alternatively, each keystream block can be XORed with a plaintext block before proceeding to create the next block, saving some memory.
* There is no requirement for the plaintext to be an integral multiple of 512 bits. If there is extra keystream from the last block, it is discarded.
*
* The inputs to ChaCha20 are
* - 256-bit key
* - 32-bit initial counter
* - 96-bit nonce. In some protocols, this is known as the Initialization Vector
* - Arbitrary-length plaintext
*
* Implementation derived from chacha-ref.c version 20080118
* See for details, 0x http, 0x//cr.yp.to/chacha/chacha-20080128.pdf
*/
/* poly1305
*
* Written in 2014 by Devi Mandiri. Public domain.
* Implementation derived from poly1305-donna-16.h
* See for details: https://github.com/floodyberry/poly1305-donna
*/
/*
Terser option:
{
module: true,
compress: {
passes: 2,
},
mangle: {
properties: {
keep_quoted: 'strict',
},
},
output: {},
parse: {},
rename: {},
}
*/
(() => {
/** @type {globalThis} */
const GLOBAL = typeof globalThis !== 'undefined' ? globalThis : (global || self);
const {
Error,
Uint8Array,
Uint16Array,
Uint32Array,
} = GLOBAL;
/**
* The basic operation of the ChaCha algorithm is the quarter round.
* It operates on four 32-bit unsigned integers, denoted a, b, c, and d.
*
* @param {Uint32Array} output
* @param {Number} a
* @param {Number} b
* @param {Number} c
* @param {Number} d
*/
const _quarterround = (output, a, b, c, d) => {
output[d] = _rotl(output[d] ^ (output[a] += output[b]), 16)
output[b] = _rotl(output[b] ^ (output[c] += output[d]), 12)
output[d] = _rotl(output[d] ^ (output[a] += output[b]), 8)
output[b] = _rotl(output[b] ^ (output[c] += output[d]), 7)
// JavaScript hack to make UINT32 :) //
// output[a] >>>= 0
// output[b] >>>= 0
// output[c] >>>= 0
// output[d] >>>= 0
}
/**
* Little-endian to uint 32 bytes
*
* @param {Uint8Array} data
* @param {Number} index
* @return {Number}
*/
const _get32 = (data, index) => data[index++] | (data[index++] << 8) | (data[index++] << 16) | (data[index] << 24);
/**
* Little-endian to uint 16 bytes
*
* @param {Uint8Array} data
* @param {Number} index
* @return {Number}
*/
const _get16 = (data, index) => data[index++] | (data[index] << 8);
/**
* Cyclic left rotation
*
* @param {Number} data
* @param {Number} shift
* @return {Number}
*/
const _rotl = (data, shift) => ((data << shift) | (data >>> (32 - shift)));
class ChaCha20 {
/**
* @param {Uint8Array} key
* @param {Uint8Array} nonce
* @param {Number} [counter]
*/
constructor(key, nonce, counter = 0) {
if (!(key instanceof Uint8Array) || key.length !== 32) {
throw new Error('Key should be 32 byte array!')
}
if (!(nonce instanceof Uint8Array) || nonce.length !== 12) {
throw new Error('Nonce should be 12 byte array!')
}
this._rounds = 20
// param construction
const _param = new Uint32Array(16);
_param.set(new Uint32Array([0x61707865, 0x3320646E, 0x79622D32, 0x6B206574]));
_param[12] = counter;
let i = 8;
while (i--) {
_param[i + 4] = _get32(key, i << 2);
}
i = 3;
while (i--) {
_param[i + 13] = _get32(nonce, i << 2);
}
this._param = _param;
// init 64 byte keystream block //
this._keystream = new Uint8Array(64)
// internal byte counter //
this._byteCounter = 0
}
_chacha() {
// copy param array to mix //
const mix = new Uint32Array(this._param)
let i = 0
let j = 0
// mix rounds //
for (i = 0; i < this._rounds; i += 2) {
for (j = 0; j < 4; j++) {
_quarterround(mix, j, j | 0x4, j | 0x8, j | 0xC);
// _quarterround(mix, j, j + 4, j + 8, j + 12);
}
// this._quarterround(mix, 0, 4, 8, 12)
// this._quarterround(mix, 1, 5, 9, 13)
// this._quarterround(mix, 2, 6, 10, 14)
// this._quarterround(mix, 3, 7, 11, 15)
for (j = 0; j < 4; j++) {
_quarterround(mix, j, ((j + 1) & 3) | 0x4, ((j + 2) & 3) | 0x8, ((j + 3) & 3) | 0xC)
// _quarterround(mix, j, ((j + 1) & 3) + 4, ((j + 2) & 3) + 8, ((j + 3) & 3) + 12)
}
// _quarterround(mix, 0, 5, 10, 15)
// _quarterround(mix, 1, 6, 11, 12)
// _quarterround(mix, 2, 7, 8, 13)
// _quarterround(mix, 3, 4, 9, 14)
}
let b = 0
for (i = 0; i < 16; i++) {
// add
mix[i] += this._param[i]
// store keystream
for (j = 0; j < 4; j++) {
this._keystream[b++] = (mix[i] >>> (j << 3)) // & 0xFF
}
// this._keystream[b++] = mix[i] & 0xFF
// this._keystream[b++] = (mix[i] >>> 8) & 0xFF
// this._keystream[b++] = (mix[i] >>> 16) & 0xFF
// this._keystream[b++] = (mix[i] >>> 24) & 0xFF
}
}
/**
* Encrypt or Decrypt data with key and nonce
*
* @param {Uint8Array} data
* @return {Uint8Array}
*/
_update(data) {
if (!(data instanceof Uint8Array) || data.length === 0) {
throw new Error('Data should be Uint8Array and not empty!')
}
const output = new Uint8Array(data.length)
// core function, build block and xor with input data //
for (let i = 0; i < data.length; i++) {
if (this._byteCounter === 0 || this._byteCounter === 64) {
// generate new block //
this._chacha()
// counter increment //
this._param[12]++
// reset internal counter //
this._byteCounter = 0
}
output[i] = data[i] ^ this._keystream[this._byteCounter++]
}
return output
}
/**
* Encrypt data with key and nonce
*
* @param {Uint8Array} data
* @return {Uint8Array}
*/
'encrypt'(data) {
return this._update(data);
}
/**
* Decrypt data with key and nonce
*
* @param {Uint8Array} data
* @return {Uint8Array}
*/
'decrypt'(data) {
return this._update(data);
}
}
class Poly1305 {
/**
* @param {Uint8Array} key
*/
constructor(key) {
this.b = new Uint8Array(16);
this.l = 0;
this.h = new Uint16Array(10);
this.p = new Uint16Array(8);
this.f = false;
const t = new Uint16Array(8);
let i;
for (i = 8; i--;) t[i] = _get16(key, i << 1);
this.r = new Uint16Array([
t[0] & 0x1fff,
((t[0] >>> 13) | (t[1] << 3)) & 0x1fff,
((t[1] >>> 10) | (t[2] << 6)) & 0x1f03,
((t[2] >>> 7) | (t[3] << 9)) & 0x1fff,
((t[3] >>> 4) | (t[4] << 12)) & 0x00ff,
(t[4] >>> 1) & 0x1ffe,
((t[4] >>> 14) | (t[5] << 2)) & 0x1fff,
((t[5] >>> 11) | (t[6] << 5)) & 0x1f81,
((t[6] >>> 8) | (t[7] << 8)) & 0x1fff,
(t[7] >>> 5) & 0x007f,
]);
for (i = 8; i--;) {
// this.p[i] = _get16(key, 16 + (i << 1));
this.p[i] = _get16(key, (i << 1) | 16);
}
this.l = 0;
}
/**
* @param {Uint8Array} m
* @param {Number} mpos
* @param {Number} bytes
*/
blocks(m, mpos, bytes) {
let hibit = this.f ? 0 : (1 << 11);
const t = new Uint16Array(8);
const d = new Uint32Array(10);
const {h, r} = this;
let c = 0, i = 0, j = 0;
while (bytes >= 16) {
for (i = 8; i--;) t[i] = _get16(m, (i << 1) + mpos);
h[0] += t[0] & 0x1FFF;
h[1] += ((t[0] >>> 13) | (t[1] << 3)) & 0x1FFF;
h[2] += ((t[1] >>> 10) | (t[2] << 6)) & 0x1FFF;
h[3] += ((t[2] >>> 7) | (t[3] << 9)) & 0x1FFF;
h[4] += ((t[3] >>> 4) | (t[4] << 12)) & 0x1FFF;
h[5] += (t[4] >>> 1) & 0x1FFF;
h[6] += ((t[4] >>> 14) | (t[5] << 2)) & 0x1FFF;
h[7] += ((t[5] >>> 11) | (t[6] << 5)) & 0x1FFF;
h[8] += ((t[6] >>> 8) | (t[7] << 8)) & 0x1FFF;
h[9] += (t[7] >>> 5) | hibit;
for (i = 0, c = 0; i < 10; i++) {
d[i] = c;
for (j = 0; j < 10; j++) {
d[i] += (h[j] & 0xFFFFFFFF) * ((j <= i) ? r[i - j] : (5 * r[i + 10 - j]));
if (j === 4) {
c = d[i] >>> 13;
d[i] &= 0x1FFF;
}
}
c += d[i] >>> 13;
d[i] &= 0x1FFF;
}
c = (c << 2) + c;
c += d[0];
d[0] = c & 0x1FFF;
c >>>= 13;
d[1] += c;
h.set(d);
// for (i = 10; i--;) h[i] = d[i];
mpos += 16;
bytes -= 16;
}
}
/**
* @param {Uint8Array} m
*/
'update'(m) {
let want = 0, i = 0, mpos = 0, bytes = m.length;
const {b} = this;
if (this.l) {
want = 16 - this.l;
if (want > bytes)
want = bytes;
for (i = want; i--;) {
b[this.l+i] = m[i+mpos];
}
bytes -= want;
mpos += want;
this.l += want;
if (this.l < 16)
return;
this.blocks(b, 0, 16);
this.l = 0;
}
if (bytes >= 16) {
want = (bytes & -16);
this.blocks(m, mpos, want);
mpos += want;
bytes -= want;
}
if (bytes) {
b.set(m.subarray(mpos, mpos + bytes), this.l);
// for (i = bytes; i--;) {
// b[this.l+i] = m[i+mpos];
// }
this.l += bytes;
}
}
/**
* @returns {Uint8Array}
*/
'finish'() {
const mac = new Uint8Array(16);
const g = new Uint16Array(10);
const {b, h} = this;
let c = 0, mask = 0, f = 0, i = 0;
if (this.l) {
i = this.l;
b[i++] = 1;
for (; i < 16; i++) {
b[i] = 0;
}
this.f = true;
this.blocks(b, 0, 16);
}
c = h[1] >>> 13;
h[1] &= 0x1FFF;
for (i = 2; i < 10; i++) {
h[i] += c;
c = h[i] >>> 13;
h[i] &= 0x1FFF;
}
h[0] += c * 5;
c = h[0] >>> 13;
h[0] &= 0x1FFF;
h[1] += c;
c = h[1] >>> 13;
h[1] &= 0x1FFF;
h[2] += c;
g[0] = h[0] + 5;
c = g[0] >>> 13;
g[0] &= 0x1FFF;
for (i = 1; i < 10; i++) {
g[i] = h[i] + c;
c = g[i] >>> 13;
g[i] &= 0x1FFF;
}
g[9] -= 1 << 13;
mask = (g[9] >>> 15) - 1;
for (i = 10; i--;) g[i] &= mask;
mask = ~mask;
for (i = 10; i--;) {
h[i] = (h[i] & mask) | g[i];
}
h[0] = (h[0] ) | (h[1] << 13);
h[1] = (h[1] >> 3) | (h[2] << 10);
h[2] = (h[2] >> 6) | (h[3] << 7);
h[3] = (h[3] >> 9) | (h[4] << 4);
h[4] = (h[4] >> 12) | (h[5] << 1) | (h[6] << 14);
h[5] = (h[6] >> 2) | (h[7] << 11);
h[6] = (h[7] >> 5) | (h[8] << 8);
h[7] = (h[8] >> 8) | (h[9] << 5);
f = (h[0] & 0xFFFFFFFF) + this.p[0];
h[0] = f;
for (i = 1; i < 8; i++) {
f = (h[i] & 0xFFFFFFFF) + this.p[i] + (f >>> 16);
h[i] = f;
}
for (i = 8; i--;) {
mac[i << 1] = h[i];
mac[(i << 1) + 1] = h[i] >>> 8;
}
return mac;
}
}
class ChaCha20Poly1305 {
/**
* @param {Uint8Array} key
* @param {Uint8Array} nonce
* @param {Uint8Array} auth
*/
constructor(key, nonce, auth) {
if (!(auth instanceof Uint8Array) || auth.length === 0) {
throw new Error('Auth should be Uint8Array and not empty!');
}
this.chacha20 = new ChaCha20(key, nonce);
this.poly1305 = new Poly1305(this.chacha20['encrypt'](new Uint8Array(64)));
this.authLength = auth.length;
this.dataLength = 0;
this.poly1305['update'](auth);
if (16 - auth.length & 15) {
this.poly1305['update'](new Uint8Array(16 - auth.length & 15));
}
}
/**
* @param {Uint8Array} data
* @returns {Uint8Array}
*/
'encrypt'(data) {
const cipher = this.chacha20['encrypt'](data);
this.dataLength += cipher.length;
this.poly1305['update'](cipher);
return cipher;
}
/**
* @param {Uint8Array} data
* @returns {Uint8Array}
*/
'decrypt'(data) {
this.poly1305['update'](data);
const plain = this.chacha20['decrypt'](data);
this.dataLength += plain.length;
return plain;
}
/**
* @returns {Uint8Array}
*/
'mac'() {
if (16 - this.dataLength & 15) {
this.poly1305['update'](new Uint8Array(16 - this.dataLength & 15));
}
// Uint32 only. Javascript cannot handle Uint64.
this.poly1305['update'](new Uint8Array(new Uint32Array([this.authLength, 0, this.dataLength, 0]).buffer));
return this.poly1305['finish']();
}
/**
* @param {Uint8Array} mac
* @returns {Boolean}
*/
'verify'(mac) {
const m = this['mac']();
let i = 16;
let result = 0;
while (i--) result |= m[i] ^ mac[i];
return !result;
}
}
// EXPORT //
if (typeof module !== 'undefined') {
module.exports = {
'ChaCha20': ChaCha20,
'ChaCha20Poly1305': ChaCha20Poly1305,
};
} else {
GLOBAL['ChaCha20'] = ChaCha20;
GLOBAL['ChaCha20Poly1305'] = ChaCha20Poly1305;
}
})();
(()=>{const t="undefined"!=typeof globalThis?globalThis:global||self,{Error:s,Uint8Array:i,Uint16Array:h,Uint32Array:e}=t,r=(t,s,i,h,e)=>{t[e]=f(t[e]^(t[s]+=t[i]),16),t[i]=f(t[i]^(t[h]+=t[e]),12),t[e]=f(t[e]^(t[s]+=t[i]),8),t[i]=f(t[i]^(t[h]+=t[e]),7)},n=(t,s)=>t[s++]|t[s++]<<8|t[s++]<<16|t[s]<<24,o=(t,s)=>t[s++]|t[s]<<8,f=(t,s)=>t<<s|t>>>32-s;class c{constructor(t,h,r=0){if(!(t instanceof i)||32!==t.length)throw new s("Key should be 32 byte array!");if(!(h instanceof i)||12!==h.length)throw new s("Nonce should be 12 byte array!");this.t=20;const o=new e(16);o.set(new e([1634760805,857760878,2036477234,1797285236])),o[12]=r;let f=8;for(;f--;)o[f+4]=n(t,f<<2);for(f=3;f--;)o[f+13]=n(h,f<<2);this.i=o,this.h=new i(64),this.o=0}l(){const t=new e(this.i);let s=0,i=0;for(s=0;s<this.t;s+=2){for(i=0;i<4;i++)r(t,i,4|i,8|i,12|i);for(i=0;i<4;i++)r(t,i,i+1&3|4,i+2&3|8,i+3&3|12)}let h=0;for(s=0;s<16;s++)for(t[s]+=this.i[s],i=0;i<4;i++)this.h[h++]=t[s]>>>(i<<3)}u(t){if(!(t instanceof i)||0===t.length)throw new s("Data should be Uint8Array and not empty!");const h=new i(t.length);for(let s=0;s<t.length;s++)0!==this.o&&64!==this.o||(this.l(),this.i[12]++,this.o=0),h[s]=t[s]^this.h[this.o++];return h}encrypt(t){return this.u(t)}decrypt(t){return this.u(t)}}class a{constructor(t){this.b=new i(16),this.p=0,this.A=new h(10),this.m=new h(8),this.f=!1;const s=new h(8);let e;for(e=8;e--;)s[e]=o(t,e<<1);for(this.r=new h([8191&s[0],8191&(s[0]>>>13|s[1]<<3),7939&(s[1]>>>10|s[2]<<6),8191&(s[2]>>>7|s[3]<<9),255&(s[3]>>>4|s[4]<<12),s[4]>>>1&8190,8191&(s[4]>>>14|s[5]<<2),8065&(s[5]>>>11|s[6]<<5),8191&(s[6]>>>8|s[7]<<8),s[7]>>>5&127]),e=8;e--;)this.m[e]=o(t,e<<1|16);this.p=0}U(t,s,i){let r=this.f?0:2048;const n=new h(8),f=new e(10),{A:c,r:a}=this;let w=0,l=0,u=0;for(;i>=16;){for(l=8;l--;)n[l]=o(t,(l<<1)+s);for(c[0]+=8191&n[0],c[1]+=8191&(n[0]>>>13|n[1]<<3),c[2]+=8191&(n[1]>>>10|n[2]<<6),c[3]+=8191&(n[2]>>>7|n[3]<<9),c[4]+=8191&(n[3]>>>4|n[4]<<12),c[5]+=n[4]>>>1&8191,c[6]+=8191&(n[4]>>>14|n[5]<<2),c[7]+=8191&(n[5]>>>11|n[6]<<5),c[8]+=8191&(n[6]>>>8|n[7]<<8),c[9]+=n[7]>>>5|r,l=0,w=0;l<10;l++){for(f[l]=w,u=0;u<10;u++)f[l]+=(4294967295&c[u])*(u<=l?a[l-u]:5*a[l+10-u]),4===u&&(w=f[l]>>>13,f[l]&=8191);w+=f[l]>>>13,f[l]&=8191}w=(w<<2)+w,w+=f[0],f[0]=8191&w,w>>>=13,f[1]+=w,c.set(f),s+=16,i-=16}}update(t){let s=0,i=0,h=0,e=t.length;const{b:r}=this;if(this.p){for(s=16-this.p,s>e&&(s=e),i=s;i--;)r[this.p+i]=t[i+h];if(e-=s,h+=s,this.p+=s,this.p<16)return;this.U(r,0,16),this.p=0}e>=16&&(s=-16&e,this.U(t,h,s),h+=s,e-=s),e&&(r.set(t.subarray(h,h+e),this.p),this.p+=e)}finish(){const t=new i(16),s=new h(10),{b:e,A:r}=this;let n=0,o=0,f=0,c=0;if(this.p){for(c=this.p,e[c++]=1;c<16;c++)e[c]=0;this.f=!0,this.U(e,0,16)}for(n=r[1]>>>13,r[1]&=8191,c=2;c<10;c++)r[c]+=n,n=r[c]>>>13,r[c]&=8191;for(r[0]+=5*n,n=r[0]>>>13,r[0]&=8191,r[1]+=n,n=r[1]>>>13,r[1]&=8191,r[2]+=n,s[0]=r[0]+5,n=s[0]>>>13,s[0]&=8191,c=1;c<10;c++)s[c]=r[c]+n,n=s[c]>>>13,s[c]&=8191;for(s[9]-=8192,o=(s[9]>>>15)-1,c=10;c--;)s[c]&=o;for(o=~o,c=10;c--;)r[c]=r[c]&o|s[c];for(r[0]=r[0]|r[1]<<13,r[1]=r[1]>>3|r[2]<<10,r[2]=r[2]>>6|r[3]<<7,r[3]=r[3]>>9|r[4]<<4,r[4]=r[4]>>12|r[5]<<1|r[6]<<14,r[5]=r[6]>>2|r[7]<<11,r[6]=r[7]>>5|r[8]<<8,r[7]=r[8]>>8|r[9]<<5,f=(4294967295&r[0])+this.m[0],r[0]=f,c=1;c<8;c++)f=(4294967295&r[c])+this.m[c]+(f>>>16),r[c]=f;for(c=8;c--;)t[c<<1]=r[c],t[1+(c<<1)]=r[c]>>>8;return t}}class w{constructor(t,h,e){if(!(e instanceof i)||0===e.length)throw new s("Auth should be Uint8Array and not empty!");this.C=new c(t,h),this.g=new a(this.C.encrypt(new i(64))),this.T=e.length,this._=0,this.g.update(e),16-e.length&15&&this.g.update(new i(16-e.length&15))}encrypt(t){const s=this.C.encrypt(t);return this._+=s.length,this.g.update(s),s}decrypt(t){this.g.update(t);const s=this.C.decrypt(t);return this._+=s.length,s}mac(){return 16-this._&15&&this.g.update(new i(16-this._&15)),this.g.update(new i(new e([this.T,0,this._,0]).buffer)),this.g.finish()}verify(t){const s=this.mac();let i=16,h=0;for(;i--;)h|=s[i]^t[i];return!h}}"undefined"!=typeof module?module.exports={ChaCha20:c,ChaCha20Poly1305:w}:(t.ChaCha20=c,t.ChaCha20Poly1305=w)})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment