Skip to content

Commit e8f64fc

Browse files
committed
Bytes
1 parent 32bfd7e commit e8f64fc

File tree

9 files changed

+43
-31
lines changed

9 files changed

+43
-31
lines changed

src/_arx.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ xchacha [^2] uses the subkey and remaining 8 byte nonce with ChaCha20 as normal
3737
* @module
3838
*/
3939
import {
40+
type Bytes,
4041
type PRG,
4142
type XorStream,
4243
abool,
@@ -275,7 +276,7 @@ export class _XorStreamPRG implements PRG {
275276
this.state.set(this.randomBytes(this.state.length));
276277
this.reseed(seed);
277278
}
278-
randomBytes(len: number): Uint8Array {
279+
randomBytes(len: number): Bytes {
279280
anumber(len);
280281
if (len === 0) return new Uint8Array(0);
281282
const out = new Uint8Array(len);

src/_poly1305.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import {
2222
abytes, aexists, aoutput, bytesToHex,
2323
clean, concatBytes, copyBytes, hexToNumber, numberToBytesBE,
24+
type Bytes,
2425
type IHash2
2526
} from './utils.ts';
2627

@@ -328,7 +329,7 @@ export class Poly1305 implements IHash2 {
328329
}
329330
return out;
330331
}
331-
digest(): Uint8Array {
332+
digest(): Bytes {
332333
const { buffer, outputLen } = this;
333334
this.digestInto(buffer);
334335
const res = buffer.slice(0, outputLen);

src/_polyval.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
copyBytes,
2121
createView,
2222
u32,
23+
type Bytes,
2324
type IHash2,
2425
} from './utils.ts';
2526

@@ -186,7 +187,7 @@ export class GHASH implements IHash2 {
186187
o32[3] = s3;
187188
return out;
188189
}
189-
digest(): Uint8Array {
190+
digest(): Bytes {
190191
const res = new Uint8Array(BLOCK_SIZE);
191192
this.digestInto(res);
192193
this.destroy();

src/aes.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
abytes, anumber, clean, complexOverlapBytes, concatBytes,
2424
copyBytes, createView, equalBytes, getOutput, isAligned32, overlapBytes,
2525
u32, u64Lengths, u8, wrapCipher,
26+
type Bytes,
2627
type Cipher, type CipherWithOutput, type PRG
2728
} from './utils.ts';
2829

@@ -261,8 +262,8 @@ function ctrCounter(
261262
xk: Uint32Array,
262263
nonce: Uint8Array,
263264
src: Uint8Array,
264-
dst?: Uint8Array
265-
): Uint8Array {
265+
dst?: Bytes
266+
): Bytes {
266267
abytes(nonce, BLOCK_SIZE, 'nonce');
267268
abytes(src);
268269
const srcLen = src.length;
@@ -303,8 +304,8 @@ function ctr32(
303304
isLE: boolean,
304305
nonce: Uint8Array,
305306
src: Uint8Array,
306-
dst?: Uint8Array
307-
): Uint8Array {
307+
dst?: Bytes
308+
): Bytes {
308309
abytes(nonce, BLOCK_SIZE, 'nonce');
309310
abytes(src);
310311
dst = getOutput(src.length, dst);
@@ -379,7 +380,7 @@ function validateBlockDecrypt(data: Uint8Array) {
379380
}
380381
}
381382

382-
function validateBlockEncrypt(plaintext: Uint8Array, pcks5: boolean, dst?: Uint8Array) {
383+
function validateBlockEncrypt(plaintext: Uint8Array, pcks5: boolean, dst?: Bytes) {
383384
abytes(plaintext);
384385
let outLen = plaintext.length;
385386
const remaining = outLen % BLOCK_SIZE;

src/chacha.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { type XorPRG, createCipher, createPRG, rotl } from './_arx.ts';
1818
import { poly1305 } from './_poly1305.ts';
1919
import {
2020
type ARXCipher,
21+
type Bytes,
2122
type CipherWithOutput,
2223
type XorStream,
2324
abytes,
@@ -305,7 +306,7 @@ export const _poly1305_aead =
305306
(key: Uint8Array, nonce: Uint8Array, AAD?: Uint8Array): CipherWithOutput => {
306307
const tagLength = 16;
307308
return {
308-
encrypt(plaintext: Uint8Array, output?: Uint8Array) {
309+
encrypt(plaintext: Uint8Array, output?: Bytes) {
309310
const plength = plaintext.length;
310311
output = getOutput(plength + tagLength, output, false);
311312
output.set(plaintext);
@@ -317,7 +318,7 @@ export const _poly1305_aead =
317318
clean(tag);
318319
return output;
319320
},
320-
decrypt(ciphertext: Uint8Array, output?: Uint8Array) {
321+
decrypt(ciphertext: Uint8Array, output?: Bytes) {
321322
output = getOutput(ciphertext.length - tagLength, output, false);
322323
const data = ciphertext.subarray(0, -tagLength);
323324
const passedTag = ciphertext.subarray(-tagLength);

src/ff1.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @module
55
*/
66
import { unsafe } from './aes.ts';
7-
import { type Cipher, abytes, anumber, bytesToNumberBE, clean, numberToBytesBE } from './utils.ts';
7+
import { type Bytes, type Cipher, abytes, anumber, bytesToNumberBE, clean, numberToBytesBE } from './utils.ts';
88

99
// NOTE: no point in inlining encrypt instead of encryptBlock, since BigInt stuff will be slow
1010
const { expandKeyLE, encryptBlock } = unsafe;
@@ -141,7 +141,7 @@ const binLE = {
141141
}
142142
return x;
143143
},
144-
decode(b: number[]): Uint8Array {
144+
decode(b: number[]): Bytes {
145145
if (!Array.isArray(b) || b.length % 8) throw new Error('Invalid binary string');
146146
const res = new Uint8Array(b.length / 8);
147147
for (let i = 0, j = 0; i < res.length; i++) {

src/salsa.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { poly1305 } from './_poly1305.ts';
1919
import {
2020
abytes,
2121
type ARXCipher,
22+
type Bytes,
2223
type CipherWithOutput,
2324
clean,
2425
equalBytes,
@@ -202,7 +203,7 @@ export const xsalsa20poly1305: ARXCipher = /* @__PURE__ */ wrapCipher(
202203
{ blockSize: 64, nonceLength: 24, tagLength: 16 },
203204
(key: Uint8Array, nonce: Uint8Array): CipherWithOutput => {
204205
return {
205-
encrypt(plaintext: Uint8Array, output?: Uint8Array) {
206+
encrypt(plaintext: Uint8Array, output?: Bytes): Bytes {
206207
// xsalsa20poly1305 optimizes by calculating auth key during the same call as encryption.
207208
// Unfortunately, makes it hard to separate tag calculation & encryption itself,
208209
// because 32 bytes is half-block of 64-byte salsa.
@@ -217,7 +218,7 @@ export const xsalsa20poly1305: ARXCipher = /* @__PURE__ */ wrapCipher(
217218
clean(output.subarray(0, 16), tag); // clean-up authKey remnants & copy of tag
218219
return output.subarray(16); // return output[16..]
219220
},
220-
decrypt(ciphertext: Uint8Array, output?: Uint8Array) {
221+
decrypt(ciphertext: Uint8Array, output?: Bytes): Bytes {
221222
// tmp part passed tag ciphertext
222223
// [0..32] [32..48] [48..]
223224
abytes(ciphertext);

src/utils.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,18 @@ export function aoutput(out: any, instance: any): void {
4949
}
5050

5151
export type IHash = {
52-
(data: string | Uint8Array): Uint8Array;
52+
(data: Uint8Array): Bytes;
5353
blockLen: number;
5454
outputLen: number;
5555
create: any;
5656
};
5757

58+
/**
59+
* Unified, backwards-compatible ArrayBuffer-based Uint8Array.
60+
* In ts5.5: `Uint8Array`; in ts5.9: `Uint8Array<ArrayBuffer>`.
61+
*/
62+
export type Bytes = ReturnType<typeof Uint8Array.from>;
63+
5864
/** Generic type encompassing 8/16/32-byte arrays - but not 64-byte. */
5965
// prettier-ignore
6066
export type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |
@@ -248,10 +254,10 @@ export function equalBytes(a: Uint8Array, b: Uint8Array): boolean {
248254
export interface IHash2 {
249255
blockLen: number; // Bytes per block
250256
outputLen: number; // Bytes in output
251-
update(buf: string | Uint8Array): this;
257+
update(buf: Uint8Array): this;
252258
// Writes digest into buf
253259
digestInto(buf: Uint8Array): void;
254-
digest(): Uint8Array;
260+
digest(): Bytes;
255261
/**
256262
* Resets internal state. Makes Hash instance unusable.
257263
* Reset is impossible for keyed hashes if key is consumed into state. If digest is not consumed
@@ -265,20 +271,20 @@ export interface IHash2 {
265271

266272
/** Sync cipher: takes byte array and returns byte array. */
267273
export type Cipher = {
268-
encrypt(plaintext: Uint8Array): Uint8Array;
269-
decrypt(ciphertext: Uint8Array): Uint8Array;
274+
encrypt(plaintext: Uint8Array): Bytes;
275+
decrypt(ciphertext: Uint8Array): Bytes;
270276
};
271277

272278
/** Async cipher e.g. from built-in WebCrypto. */
273279
export type AsyncCipher = {
274-
encrypt(plaintext: Uint8Array): Promise<Uint8Array>;
275-
decrypt(ciphertext: Uint8Array): Promise<Uint8Array>;
280+
encrypt(plaintext: Uint8Array): Promise<Bytes>;
281+
decrypt(ciphertext: Uint8Array): Promise<Bytes>;
276282
};
277283

278284
/** Cipher with `output` argument which can optimize by doing 1 less allocation. */
279285
export type CipherWithOutput = Cipher & {
280-
encrypt(plaintext: Uint8Array, output?: Uint8Array): Uint8Array;
281-
decrypt(ciphertext: Uint8Array, output?: Uint8Array): Uint8Array;
286+
encrypt(plaintext: Uint8Array, output?: Uint8Array): Bytes;
287+
decrypt(ciphertext: Uint8Array, output?: Uint8Array): Bytes;
282288
};
283289

284290
/**
@@ -375,9 +381,9 @@ export type XorStream = (
375381
*/
376382
export function getOutput(
377383
expectedLength: number,
378-
out?: Uint8Array,
384+
out?: Bytes,
379385
onlyAligned = true
380-
): Uint8Array {
386+
): Bytes {
381387
if (out === undefined) return new Uint8Array(expectedLength);
382388
if (out.length !== expectedLength)
383389
throw new Error(
@@ -422,7 +428,7 @@ export function randomBytes(bytesLength = 32): Uint8Array {
422428
*/
423429
export interface PRG {
424430
addEntropy(seed: Uint8Array): void;
425-
randomBytes(length: number): Uint8Array;
431+
randomBytes(length: number): Bytes;
426432
clean(): void;
427433
}
428434

src/webcrypto.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
44
* @module
55
*/
6-
import { abytes, anumber, type AsyncCipher } from './utils.ts';
6+
import { abytes, anumber, type AsyncCipher, type Bytes } from './utils.ts';
77

88
function getWebcryptoSubtle(): any {
99
const cr = typeof globalThis !== 'undefined' && (globalThis as any).crypto;
@@ -16,15 +16,15 @@ function getWebcryptoSubtle(): any {
1616
* for example in React Native.
1717
*/
1818
export const utils: {
19-
encrypt: (key: Uint8Array, ...all: any[]) => Promise<Uint8Array>;
20-
decrypt: (key: Uint8Array, ...all: any[]) => Promise<Uint8Array>;
19+
encrypt: (key: Uint8Array, ...all: any[]) => Promise<Bytes>;
20+
decrypt: (key: Uint8Array, ...all: any[]) => Promise<Bytes>;
2121
} = {
2222
async encrypt(
2323
key: Uint8Array,
2424
keyParams: any,
2525
cryptParams: any,
2626
plaintext: Uint8Array
27-
): Promise<Uint8Array> {
27+
): Promise<Bytes> {
2828
const cr = getWebcryptoSubtle();
2929
const iKey = await cr.importKey('raw', key, keyParams, true, ['encrypt']);
3030
const ciphertext = await cr.encrypt(cryptParams, iKey, plaintext);
@@ -35,7 +35,7 @@ export const utils: {
3535
keyParams: any,
3636
cryptParams: any,
3737
ciphertext: Uint8Array
38-
): Promise<Uint8Array> {
38+
): Promise<Bytes> {
3939
const cr = getWebcryptoSubtle();
4040
const iKey = await cr.importKey('raw', key, keyParams, true, ['decrypt']);
4141
const plaintext = await cr.decrypt(cryptParams, iKey, ciphertext);

0 commit comments

Comments
 (0)