Skip to content
This repository has been archived by the owner on Feb 7, 2023. It is now read-only.

Heap & asm instance pooling #155

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/aes/aes.asm.js
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,38 @@ export var AES_asm = function () {
return 16;
}

/**
* Store the internal nonce vector into the heap.
* @instance
* @memberof AES_asm
* @param {number} pos - offset where to put the data
* @return {number} The number of bytes have been written into the heap, always 16.
*/
function get_nonce(pos) {
pos = pos | 0;

if (pos & 15) return -1;

DATA[pos | 0] = N0 >>> 24,
DATA[pos | 1] = N0 >>> 16 & 255,
DATA[pos | 2] = N0 >>> 8 & 255,
DATA[pos | 3] = N0 & 255,
DATA[pos | 4] = N1 >>> 24,
DATA[pos | 5] = N1 >>> 16 & 255,
DATA[pos | 6] = N1 >>> 8 & 255,
DATA[pos | 7] = N1 & 255,
DATA[pos | 8] = N2 >>> 24,
DATA[pos | 9] = N2 >>> 16 & 255,
DATA[pos | 10] = N2 >>> 8 & 255,
DATA[pos | 11] = N2 & 255,
DATA[pos | 12] = N3 >>> 24,
DATA[pos | 13] = N3 >>> 16 & 255,
DATA[pos | 14] = N3 >>> 8 & 255,
DATA[pos | 15] = N3 & 255;

return 16;
}

/**
* GCM initialization.
* @instance
Expand Down Expand Up @@ -887,6 +919,7 @@ export var AES_asm = function () {
set_counter: set_counter,
get_state: get_state,
get_iv: get_iv,
get_nonce: get_nonce,
gcm_init: gcm_init,
cipher: cipher,
mac: mac,
Expand Down
47 changes: 41 additions & 6 deletions src/aes/aes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { AES_asm, AES_mode } from './aes.asm';
import { _heap_init, _heap_write, is_bytes } from '../other/utils';
import { IllegalArgumentError, SecurityError } from '../other/errors';

const heap_pool = [];
const asm_pool = [];

export abstract class AES {
protected readonly heap: Uint8Array;
protected readonly asm: AES_asm;
Expand All @@ -13,14 +16,36 @@ export abstract class AES {
protected constructor(key: Uint8Array, iv: Uint8Array | undefined, padding = true, mode: AES_mode) {
this.mode = mode;

// The AES "worker"
this.heap = _heap_init().subarray(AES_asm.HEAP_DATA);
this.asm = new AES_asm(null, this.heap.buffer);

// The AES object state
this.pos = 0;
this.len = 0;

this.key = key;
this.iv = iv;
this.padding = padding;

// The AES "worker"
this.acquire_asm();
}

protected acquire_asm() {
if (this.heap === undefined && this.asm === undefined) {
this.heap = heap_pool.pop() || _heap_init().subarray(AES_asm.HEAP_DATA);
this.asm = asm_pool.pop() || AES_asm(null, this.heap.buffer);
this.reset(this.key, this.iv);
}
}

protected release_asm() {
this.iv = this.heap.slice(0, this.asm[this.mode === 'CTR' ? 'get_nonce' : 'get_iv'](AES_asm.HEAP_DATA));

heap_pool.push(this.heap);
asm_pool.push(this.asm);
this.heap = undefined;
this.asm = undefined;
}

protected reset(key, iv) {
// Key
const keylen = key.length;
if (keylen !== 16 && keylen !== 24 && keylen !== 32) throw new IllegalArgumentError('illegal key size');
Expand Down Expand Up @@ -48,13 +73,13 @@ export abstract class AES {
} else {
this.asm.set_iv(0, 0, 0, 0);
}

this.padding = padding;
}

AES_Encrypt_process(data: Uint8Array): Uint8Array {
if (!is_bytes(data)) throw new TypeError("data isn't of expected type");

this.acquire_asm();

let asm = this.asm;
let heap = this.heap;
let amode = AES_asm.ENC[this.mode];
Expand Down Expand Up @@ -96,6 +121,8 @@ export abstract class AES {
}

AES_Encrypt_finish(): Uint8Array {
this.acquire_asm();

let asm = this.asm;
let heap = this.heap;
let amode = AES_asm.ENC[this.mode];
Expand Down Expand Up @@ -128,12 +155,16 @@ export abstract class AES {
this.pos = 0;
this.len = 0;

this.release_asm();

return result;
}

AES_Decrypt_process(data: Uint8Array): Uint8Array {
if (!is_bytes(data)) throw new TypeError("data isn't of expected type");

this.acquire_asm();

let asm = this.asm;
let heap = this.heap;
let amode = AES_asm.DEC[this.mode];
Expand Down Expand Up @@ -181,6 +212,8 @@ export abstract class AES {
}

AES_Decrypt_finish(): Uint8Array {
this.acquire_asm();

let asm = this.asm;
let heap = this.heap;
let amode = AES_asm.DEC[this.mode];
Expand Down Expand Up @@ -221,6 +254,8 @@ export abstract class AES {
this.pos = 0;
this.len = 0;

this.release_asm();

return result;
}
}
5 changes: 4 additions & 1 deletion src/aes/ctr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ export class AES_CTR extends AES {
}

constructor(key: Uint8Array, nonce: Uint8Array) {
super(key, undefined, false, 'CTR');
super(key, nonce, false, 'CTR');
delete this.padding;
}

protected reset(key: Uint8Array, nonce: Uint8Array) {
super.reset(key, undefined);
this.AES_CTR_set_options(nonce);
}

Expand Down
33 changes: 32 additions & 1 deletion src/hash/hash.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { _heap_write } from '../other/utils';
import { _heap_init, _heap_write } from '../other/utils';
import { IllegalStateError } from '../other/errors';
import { sha1result } from './sha1/sha1.asm';
import { sha256result } from './sha256/sha256.asm';
Expand All @@ -13,7 +13,32 @@ export abstract class Hash<T extends sha1result | sha256result | sha512result> {
public BLOCK_SIZE!: number;
public HASH_SIZE!: number;

protected static heap_pool !: Array;
protected static asm_pool !: Array;
protected static asm_function!: Function;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A definite assignment assertion '!' is not permitted in this context.
Generic type 'Array<T>' requires 1 type argument(s).


constructor() {
this.acquire_asm();
}

protected acquire_asm() {
if (this.heap === undefined && this.asm === undefined) {
this.heap = this.constructor.heap_pool.pop() || _heap_init();
this.asm = this.constructor.asm_pool.pop() || this.constructor.asm_function({ Uint8Array: Uint8Array }, null, this.heap.buffer);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Property 'heap_pool' does not exist on type 'Function'
Property 'asm_pool' does not exist on type
Property 'asm_function' does not exist on type 'Function'

this.reset();
}
}

protected release_asm() {
this.constructor.heap_pool.push(this.heap));
this.constructor.asm_pool.push(this.asm);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Property 'heap_pool' does not exist on type 'Function'
';' expected (extra parenthesis)
Property 'asm_pool' does not exist on type 'Function'

this.heap = undefined;
this.asm = undefined;
}

reset() {
this.acquire_asm();

this.result = null;
this.pos = 0;
this.len = 0;
Expand All @@ -26,6 +51,8 @@ export abstract class Hash<T extends sha1result | sha256result | sha512result> {
process(data: Uint8Array) {
if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data');

this.acquire_asm();

let asm = this.asm;
let heap = this.heap;
let hpos = this.pos;
Expand Down Expand Up @@ -57,6 +84,8 @@ export abstract class Hash<T extends sha1result | sha256result | sha512result> {
finish() {
if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data');

this.acquire_asm();

this.asm.finish(this.pos, this.len, 0);

this.result = new Uint8Array(this.HASH_SIZE);
Expand All @@ -65,6 +94,8 @@ export abstract class Hash<T extends sha1result | sha256result | sha512result> {
this.pos = 0;
this.len = 0;

this.release_asm();

return this;
}
}
12 changes: 5 additions & 7 deletions src/hash/sha1/sha1.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { sha1_asm, sha1result } from './sha1.asm';
import { Hash } from '../hash';
import { _heap_init } from '../../other/utils';

export const _sha1_block_size = 64;
export const _sha1_hash_size = 20;
Expand All @@ -11,12 +10,11 @@ export class Sha1 extends Hash<sha1result> {
public BLOCK_SIZE = _sha1_block_size;
public HASH_SIZE = _sha1_hash_size;

constructor() {
super();
protected static heap_pool = [];
protected static asm_pool = [];
protected static asm_function = sha1_asm;

this.heap = _heap_init();
this.asm = sha1_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer);

this.reset();
static bytes(data: Uint8Array): Uint8Array {
return new Sha1().process(data).finish().result;
}
}
12 changes: 5 additions & 7 deletions src/hash/sha256/sha256.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { sha256_asm, sha256result } from './sha256.asm';
import { Hash } from '../hash';
import { _heap_init } from '../../other/utils';

export const _sha256_block_size = 64;
export const _sha256_hash_size = 32;
Expand All @@ -11,12 +10,11 @@ export class Sha256 extends Hash<sha256result> {
public BLOCK_SIZE = _sha256_block_size;
public HASH_SIZE = _sha256_hash_size;

constructor() {
super();
protected static heap_pool = [];
protected static asm_pool = [];
protected static asm_function = sha256_asm;

this.heap = _heap_init();
this.asm = sha256_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer);

this.reset();
static bytes(data: Uint8Array): Uint8Array {
return new Sha256().process(data).finish().result;
}
}
12 changes: 5 additions & 7 deletions src/hash/sha512/sha512.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { sha512_asm, sha512result } from './sha512.asm';
import { Hash } from '../hash';
import { _heap_init } from '../../other/utils';

export const _sha512_block_size = 128;
export const _sha512_hash_size = 64;
Expand All @@ -11,12 +10,11 @@ export class Sha512 extends Hash<sha512result> {
public BLOCK_SIZE = _sha512_block_size;
public HASH_SIZE = _sha512_hash_size;

constructor() {
super();
protected static heap_pool = [];
protected static asm_pool = [];
protected static asm_function = sha512_asm;

this.heap = _heap_init();
this.asm = sha512_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer);

this.reset();
static bytes(data: Uint8Array): Uint8Array {
return new Sha512().process(data).finish().result;
}
}
Loading