leviathan-crypto 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +265 -0
- package/LICENSE +21 -0
- package/README.md +322 -0
- package/SECURITY.md +174 -0
- package/dist/chacha.wasm +0 -0
- package/dist/chacha20/index.d.ts +49 -0
- package/dist/chacha20/index.js +177 -0
- package/dist/chacha20/ops.d.ts +16 -0
- package/dist/chacha20/ops.js +146 -0
- package/dist/chacha20/pool.d.ts +52 -0
- package/dist/chacha20/pool.js +188 -0
- package/dist/chacha20/pool.worker.d.ts +1 -0
- package/dist/chacha20/pool.worker.js +37 -0
- package/dist/chacha20/types.d.ts +30 -0
- package/dist/chacha20/types.js +1 -0
- package/dist/docs/architecture.md +795 -0
- package/dist/docs/argon2id.md +290 -0
- package/dist/docs/chacha20.md +602 -0
- package/dist/docs/chacha20_pool.md +306 -0
- package/dist/docs/fortuna.md +322 -0
- package/dist/docs/init.md +308 -0
- package/dist/docs/loader.md +206 -0
- package/dist/docs/serpent.md +914 -0
- package/dist/docs/sha2.md +620 -0
- package/dist/docs/sha3.md +509 -0
- package/dist/docs/types.md +198 -0
- package/dist/docs/utils.md +273 -0
- package/dist/docs/wasm.md +193 -0
- package/dist/embedded/chacha.d.ts +1 -0
- package/dist/embedded/chacha.js +2 -0
- package/dist/embedded/serpent.d.ts +1 -0
- package/dist/embedded/serpent.js +2 -0
- package/dist/embedded/sha2.d.ts +1 -0
- package/dist/embedded/sha2.js +2 -0
- package/dist/embedded/sha3.d.ts +1 -0
- package/dist/embedded/sha3.js +2 -0
- package/dist/fortuna.d.ts +72 -0
- package/dist/fortuna.js +445 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +44 -0
- package/dist/init.d.ts +11 -0
- package/dist/init.js +49 -0
- package/dist/loader.d.ts +4 -0
- package/dist/loader.js +30 -0
- package/dist/serpent/index.d.ts +65 -0
- package/dist/serpent/index.js +242 -0
- package/dist/serpent/seal.d.ts +8 -0
- package/dist/serpent/seal.js +70 -0
- package/dist/serpent/stream-encoder.d.ts +20 -0
- package/dist/serpent/stream-encoder.js +167 -0
- package/dist/serpent/stream-pool.d.ts +48 -0
- package/dist/serpent/stream-pool.js +285 -0
- package/dist/serpent/stream-sealer.d.ts +34 -0
- package/dist/serpent/stream-sealer.js +223 -0
- package/dist/serpent/stream.d.ts +28 -0
- package/dist/serpent/stream.js +205 -0
- package/dist/serpent/stream.worker.d.ts +32 -0
- package/dist/serpent/stream.worker.js +117 -0
- package/dist/serpent/types.d.ts +5 -0
- package/dist/serpent/types.js +1 -0
- package/dist/serpent.wasm +0 -0
- package/dist/sha2/hkdf.d.ts +16 -0
- package/dist/sha2/hkdf.js +108 -0
- package/dist/sha2/index.d.ts +40 -0
- package/dist/sha2/index.js +190 -0
- package/dist/sha2/types.d.ts +5 -0
- package/dist/sha2/types.js +1 -0
- package/dist/sha2.wasm +0 -0
- package/dist/sha3/index.d.ts +55 -0
- package/dist/sha3/index.js +246 -0
- package/dist/sha3/types.d.ts +5 -0
- package/dist/sha3/types.js +1 -0
- package/dist/sha3.wasm +0 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.js +26 -0
- package/dist/utils.d.ts +26 -0
- package/dist/utils.js +169 -0
- package/package.json +90 -0
package/dist/utils.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// ▄▄▄▄▄▄▄▄▄▄
|
|
2
|
+
// ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
|
|
3
|
+
// ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
|
|
4
|
+
// ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
|
|
5
|
+
// ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
|
|
6
|
+
// ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
|
|
7
|
+
// ███████▌ ▀██▀ ███
|
|
8
|
+
// ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
|
|
9
|
+
// ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
|
|
10
|
+
// ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
|
|
11
|
+
// ▀████▄ ▄██▄
|
|
12
|
+
// ▐████ ▐███ Author: xero (https://x-e.ro)
|
|
13
|
+
// ▄▄██████████ ▐███ ▄▄ License: MIT
|
|
14
|
+
// ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
|
|
15
|
+
// ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
|
|
16
|
+
// ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
|
|
17
|
+
// ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
|
|
18
|
+
// █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
|
|
19
|
+
// ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
|
|
20
|
+
// ▀█████▀▀
|
|
21
|
+
//
|
|
22
|
+
// src/ts/utils.ts
|
|
23
|
+
//
|
|
24
|
+
// Pure TypeScript utilities — no init() dependency.
|
|
25
|
+
// Ported from leviathan/src/base.ts (Convert namespace, Util namespace, constantTimeEqual).
|
|
26
|
+
// ── Encoding ─────────────────────────────────────────────────────────────────
|
|
27
|
+
/** Hex string to Uint8Array. Accepts lowercase/uppercase, optional 0x prefix. */
|
|
28
|
+
export const hexToBytes = (hex) => {
|
|
29
|
+
if (hex.startsWith('0x') || hex.startsWith('0X'))
|
|
30
|
+
hex = hex.slice(2);
|
|
31
|
+
if (hex.length % 2)
|
|
32
|
+
hex += '0';
|
|
33
|
+
const bin = new Uint8Array(hex.length >>> 1);
|
|
34
|
+
for (let i = 0, len = hex.length >>> 1; i < len; i++)
|
|
35
|
+
bin[i] = parseInt(hex.slice(i << 1, (i << 1) + 2), 16);
|
|
36
|
+
return bin;
|
|
37
|
+
};
|
|
38
|
+
/** Uint8Array to lowercase hex string. */
|
|
39
|
+
export const bytesToHex = (bytes) => {
|
|
40
|
+
const lut = '0123456789abcdef';
|
|
41
|
+
let str = '';
|
|
42
|
+
for (const b of bytes)
|
|
43
|
+
str += lut.charAt((b >>> 4) & 0x0f) + lut.charAt(b & 0x0f);
|
|
44
|
+
return str;
|
|
45
|
+
};
|
|
46
|
+
/** UTF-8 string to Uint8Array. */
|
|
47
|
+
export const utf8ToBytes = (str) => {
|
|
48
|
+
return new TextEncoder().encode(str);
|
|
49
|
+
};
|
|
50
|
+
/** Uint8Array to UTF-8 string. */
|
|
51
|
+
export const bytesToUtf8 = (bytes) => {
|
|
52
|
+
return new TextDecoder().decode(bytes);
|
|
53
|
+
};
|
|
54
|
+
/** Base64 or base64url string to Uint8Array. Returns undefined on invalid input. */
|
|
55
|
+
export const base64ToBytes = (b64) => {
|
|
56
|
+
// Normalise base64url → base64
|
|
57
|
+
b64 = b64.replace(/-/g, '+').replace(/_/g, '/').replace(/%3d/g, '=');
|
|
58
|
+
if (b64.length % 4 !== 0)
|
|
59
|
+
return undefined;
|
|
60
|
+
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(b64))
|
|
61
|
+
return undefined;
|
|
62
|
+
let strlen = b64.length / 4 * 3;
|
|
63
|
+
if (b64.charAt(b64.length - 1) === '=')
|
|
64
|
+
strlen--;
|
|
65
|
+
if (b64.charAt(b64.length - 2) === '=')
|
|
66
|
+
strlen--;
|
|
67
|
+
if (typeof atob !== 'undefined') {
|
|
68
|
+
try {
|
|
69
|
+
return new Uint8Array(atob(b64).split('').map(c => c.charCodeAt(0)));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Fallback: manual decode
|
|
76
|
+
const decodingTable = new Int8Array([
|
|
77
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
78
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
79
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
|
|
80
|
+
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
|
|
81
|
+
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
82
|
+
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
|
|
83
|
+
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
|
84
|
+
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
|
|
85
|
+
]);
|
|
86
|
+
let p = 0;
|
|
87
|
+
const bin = new Uint8Array(strlen);
|
|
88
|
+
for (let i = 0; i < b64.length;) {
|
|
89
|
+
const a = b64.charAt(i) === '=' || b64.charCodeAt(i) > 122 ? 0 : decodingTable[b64.charCodeAt(i)];
|
|
90
|
+
i++;
|
|
91
|
+
const b = b64.charAt(i) === '=' || b64.charCodeAt(i) > 122 ? 0 : decodingTable[b64.charCodeAt(i)];
|
|
92
|
+
i++;
|
|
93
|
+
const c = b64.charAt(i) === '=' || b64.charCodeAt(i) > 122 ? 0 : decodingTable[b64.charCodeAt(i)];
|
|
94
|
+
i++;
|
|
95
|
+
const d = b64.charAt(i) === '=' || b64.charCodeAt(i) > 122 ? 0 : decodingTable[b64.charCodeAt(i)];
|
|
96
|
+
i++;
|
|
97
|
+
const triple = (a << 18) + (b << 12) + (c << 6) + d;
|
|
98
|
+
if (b64.charAt(i - 3) !== '=')
|
|
99
|
+
bin[p++] = (triple >>> 16) & 0xff;
|
|
100
|
+
if (b64.charAt(i - 2) !== '=')
|
|
101
|
+
bin[p++] = (triple >>> 8) & 0xff;
|
|
102
|
+
if (b64.charAt(i - 1) !== '=')
|
|
103
|
+
bin[p++] = triple & 0xff;
|
|
104
|
+
}
|
|
105
|
+
return bin;
|
|
106
|
+
};
|
|
107
|
+
/** Uint8Array to base64 string. Pass url=true for base64url encoding. */
|
|
108
|
+
export const bytesToBase64 = (bytes, url = false) => {
|
|
109
|
+
if (typeof btoa !== 'undefined') {
|
|
110
|
+
const raw = btoa(String.fromCharCode.apply(null, Array.from(bytes)));
|
|
111
|
+
return url ? raw.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '%3d') : raw;
|
|
112
|
+
}
|
|
113
|
+
// Fallback: manual encode
|
|
114
|
+
const table = url
|
|
115
|
+
? 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
|
|
116
|
+
: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
117
|
+
let base64 = '';
|
|
118
|
+
for (let i = 0; i < bytes.length;) {
|
|
119
|
+
const a = i < bytes.length ? bytes[i] : 0;
|
|
120
|
+
i++;
|
|
121
|
+
const b = i < bytes.length ? bytes[i] : 0;
|
|
122
|
+
i++;
|
|
123
|
+
const c = i < bytes.length ? bytes[i] : 0;
|
|
124
|
+
i++;
|
|
125
|
+
const triple = (a << 0x10) + (b << 0x08) + c;
|
|
126
|
+
base64 += table.charAt((triple >>> 18) & 0x3F);
|
|
127
|
+
base64 += table.charAt((triple >>> 12) & 0x3F);
|
|
128
|
+
base64 += (i < bytes.length + 2) ? table.charAt((triple >>> 6) & 0x3F) : (url ? '%3d' : '=');
|
|
129
|
+
base64 += (i < bytes.length + 1) ? table.charAt(triple & 0x3F) : (url ? '%3d' : '=');
|
|
130
|
+
}
|
|
131
|
+
return base64;
|
|
132
|
+
};
|
|
133
|
+
// ── Crypto utilities ─────────────────────────────────────────────────────────
|
|
134
|
+
/**
|
|
135
|
+
* Constant-time byte-array equality.
|
|
136
|
+
* XOR-accumulate pattern — no early return on mismatch.
|
|
137
|
+
* Length check is not constant-time (length is non-secret in all protocols).
|
|
138
|
+
*/
|
|
139
|
+
export const constantTimeEqual = (a, b) => {
|
|
140
|
+
if (a.length !== b.length)
|
|
141
|
+
return false;
|
|
142
|
+
let diff = 0;
|
|
143
|
+
for (let i = 0; i < a.length; i++)
|
|
144
|
+
diff |= a[i] ^ b[i];
|
|
145
|
+
return diff === 0;
|
|
146
|
+
};
|
|
147
|
+
/** Zero a typed array in place. */
|
|
148
|
+
export const wipe = (data) => {
|
|
149
|
+
data.fill(0);
|
|
150
|
+
};
|
|
151
|
+
/** XOR two equal-length Uint8Arrays, returns new array. */
|
|
152
|
+
export const xor = (a, b) => {
|
|
153
|
+
if (a.length !== b.length)
|
|
154
|
+
throw new RangeError(`xor: length mismatch (${a.length} vs ${b.length})`);
|
|
155
|
+
return a.map((val, i) => val ^ b[i]);
|
|
156
|
+
};
|
|
157
|
+
/** Concatenate two Uint8Arrays, returns new array. */
|
|
158
|
+
export const concat = (a, b) => {
|
|
159
|
+
const result = new Uint8Array(a.length + b.length);
|
|
160
|
+
result.set(a, 0);
|
|
161
|
+
result.set(b, a.length);
|
|
162
|
+
return result;
|
|
163
|
+
};
|
|
164
|
+
/** Cryptographically secure random bytes via Web Crypto API. */
|
|
165
|
+
export const randomBytes = (n) => {
|
|
166
|
+
const buf = new Uint8Array(n);
|
|
167
|
+
crypto.getRandomValues(buf);
|
|
168
|
+
return buf;
|
|
169
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "leviathan-crypto",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "xero (https://x-e.ro)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"description": "Zero-dependency WebAssembly cryptography library for TypeScript: Serpent-256, XChaCha20-Poly1305, SHA-2/3, HMAC, HKDF, and Fortuna CSPRNG, with a strictly typed API built on vector-verified primitives.",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/index.js",
|
|
11
|
+
"./serpent": "./dist/serpent/index.js",
|
|
12
|
+
"./chacha20": "./dist/chacha20/index.js",
|
|
13
|
+
"./chacha20/pool": "./dist/chacha20/pool.js",
|
|
14
|
+
"./sha2": "./dist/sha2/index.js",
|
|
15
|
+
"./sha3": "./dist/sha3/index.js"
|
|
16
|
+
},
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"SECURITY.md",
|
|
21
|
+
"CLAUDE.md"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build:asm": "node scripts/build-asm.js",
|
|
25
|
+
"build:embed": "npx tsx scripts/embed-wasm.ts",
|
|
26
|
+
"build:ts": "tsc",
|
|
27
|
+
"build:docs": "bunx tsx scripts/copy-docs.ts",
|
|
28
|
+
"build": "rm -rf src/ts/embedded/* dist && bun run build:asm && bun run build:embed && bun run build:ts && cp build/*.wasm dist/ 2>/dev/null || true && cp docs/CLAUDE_consumer.md CLAUDE.md && bun run build:docs",
|
|
29
|
+
"test": "bun run build:asm && bun run build:embed && vitest run",
|
|
30
|
+
"test:browser": "bun run build && playwright test",
|
|
31
|
+
"test:all": "bun run test && bun run test:browser",
|
|
32
|
+
"lint": "eslint .",
|
|
33
|
+
"lint:fix": "eslint . --fix",
|
|
34
|
+
"pin-actions": "bun run scripts/pin-actions.ts",
|
|
35
|
+
"_shorthand": "# aliases: 'bun bake' = build, 'bun fix' = lint:fix, 'bun check' = test:all, 'bun pin' = pin-actions",
|
|
36
|
+
"bake": "bun run build",
|
|
37
|
+
"fix": "bun run lint:fix",
|
|
38
|
+
"check": "bun run test:all",
|
|
39
|
+
"pin": "bun run pin-actions"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@eslint/js": "^10.0.1",
|
|
43
|
+
"@playwright/test": "^1.58.2",
|
|
44
|
+
"@types/node": "^25.5.0",
|
|
45
|
+
"@vitest/web-worker": "^3.2.4",
|
|
46
|
+
"assemblyscript": "^0.27.37",
|
|
47
|
+
"eslint": "^10.0.3",
|
|
48
|
+
"jiti": "^2.6.1",
|
|
49
|
+
"pin-github-action": "^3.4.0",
|
|
50
|
+
"tsx": "^4.21.0",
|
|
51
|
+
"typescript": "^5.9.3",
|
|
52
|
+
"typescript-eslint": "^8.57.1",
|
|
53
|
+
"vitest": "^3.2.4"
|
|
54
|
+
},
|
|
55
|
+
"repository": {
|
|
56
|
+
"type": "git",
|
|
57
|
+
"url": "git+https://github.com/xero/leviathan-crypto.git"
|
|
58
|
+
},
|
|
59
|
+
"homepage": "https://github.com/xero/leviathan-crypto/wiki",
|
|
60
|
+
"bugs": {
|
|
61
|
+
"url": "https://github.com/xero/leviathan-crypto/issues"
|
|
62
|
+
},
|
|
63
|
+
"keywords": [
|
|
64
|
+
"cryptography",
|
|
65
|
+
"encryption",
|
|
66
|
+
"serpent",
|
|
67
|
+
"serpent-256",
|
|
68
|
+
"cipher",
|
|
69
|
+
"crypto",
|
|
70
|
+
"typescript",
|
|
71
|
+
"wasm",
|
|
72
|
+
"webassembly",
|
|
73
|
+
"chacha20",
|
|
74
|
+
"xchacha20",
|
|
75
|
+
"poly1305",
|
|
76
|
+
"xchacha20-poly1305",
|
|
77
|
+
"aead",
|
|
78
|
+
"sha",
|
|
79
|
+
"sha-256",
|
|
80
|
+
"sha-512",
|
|
81
|
+
"sha-3",
|
|
82
|
+
"keccak",
|
|
83
|
+
"shake",
|
|
84
|
+
"hmac",
|
|
85
|
+
"hkdf",
|
|
86
|
+
"fortuna",
|
|
87
|
+
"csprng",
|
|
88
|
+
"entropy"
|
|
89
|
+
]
|
|
90
|
+
}
|