@theqrl/qrl-cryptography 0.1.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/LICENSE +22 -0
- package/README.md +258 -0
- package/aes.d.ts +2 -0
- package/aes.js +70 -0
- package/argon2id.d.ts +4 -0
- package/argon2id.js +17 -0
- package/eslint.config.js +25 -0
- package/index.d.ts +0 -0
- package/index.js +2 -0
- package/keccak.d.ts +11 -0
- package/keccak.js +13 -0
- package/ml_dsa87.d.ts +8 -0
- package/ml_dsa87.js +20 -0
- package/package.json +82 -0
- package/random.d.ts +2 -0
- package/random.js +12 -0
- package/utils.d.ts +11 -0
- package/utils.js +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Patricio Palladino, Paul Miller, ethereum-cryptography contributors
|
|
4
|
+
Copyright (c) 2024 The QRL Contributors
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the “Software”), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# @theqrl/qrl-cryptography
|
|
2
|
+
|
|
3
|
+
All pure-js cryptographic primitives normally used when
|
|
4
|
+
developing Javascript / TypeScript applications and tools for QRL.
|
|
5
|
+
|
|
6
|
+
The cryptographic primitives included are:
|
|
7
|
+
|
|
8
|
+
* [Hashes: keccak-256](#hasheskeccak-256)
|
|
9
|
+
* [KDFs: Argon2id](#kdfs-argon2id)
|
|
10
|
+
* [CSPRNG (Cryptographically strong pseudorandom number generator)](#csprng-cryptographically-strong-pseudorandom-number-generator)
|
|
11
|
+
* [AES Encryption](#aes-encryption)
|
|
12
|
+
* [ML-DSA-87](#ml-dsa-87)
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
Use NPM / Yarn in node.js / browser:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# NPM
|
|
20
|
+
npm install @theqrl/qrl-cryptography
|
|
21
|
+
|
|
22
|
+
# Yarn
|
|
23
|
+
yarn add @theqrl/qrl-cryptography
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
See [browser usage](#browser-usage) for information on using the package with major Javascript bundlers. It is
|
|
27
|
+
tested with **Webpack, Rollup and Parcel**.
|
|
28
|
+
|
|
29
|
+
This package has no single entry-point, but submodule for each cryptographic
|
|
30
|
+
primitive. Read each primitive's section of this document to learn how to use
|
|
31
|
+
them.
|
|
32
|
+
|
|
33
|
+
The reason for this is that importing everything from a single file will lead to
|
|
34
|
+
huge bundles when using this package for the web. This could be avoided through
|
|
35
|
+
tree-shaking, but the possibility of it not working properly on one of
|
|
36
|
+
[the supported bundlers](#browser-usage) is too high.
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
// Hashes
|
|
40
|
+
const { keccak256 } = require("@theqrl/qrl-cryptography/keccak");
|
|
41
|
+
|
|
42
|
+
// KDFs
|
|
43
|
+
const { argon2idSync } = require("@theqrl/qrl-cryptography/argon2id");
|
|
44
|
+
|
|
45
|
+
// Random
|
|
46
|
+
const { getRandomBytesSync } = require("@theqrl/qrl-cryptography/random");
|
|
47
|
+
|
|
48
|
+
// AES encryption
|
|
49
|
+
const { encrypt } = require("@theqrl/qrl-cryptography/aes");
|
|
50
|
+
|
|
51
|
+
// ML-DSA-87
|
|
52
|
+
const { ml_dsa87 } = require("@theqrl/qrl-cryptography/ml_dsa87");
|
|
53
|
+
|
|
54
|
+
// utilities
|
|
55
|
+
const { hexToBytes, toHex, utf8ToBytes } = require("@theqrl/qrl-cryptography/utils");
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Hashes: keccak-256
|
|
59
|
+
```typescript
|
|
60
|
+
function keccak256(msg: Uint8Array): Uint8Array;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Exposes following cryptographic hash functions:
|
|
64
|
+
|
|
65
|
+
- keccak-256 variant of SHA3 (also `keccak224`, `keccak384`,
|
|
66
|
+
and `keccak512`)
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
const { keccak256, keccak224, keccak384, keccak512 } = require("@theqrl/qrl-cryptography/keccak");
|
|
70
|
+
|
|
71
|
+
keccak256(Uint8Array.from([1, 2, 3]))
|
|
72
|
+
|
|
73
|
+
// Can be used with strings
|
|
74
|
+
const { utf8ToBytes } = require("@theqrl/qrl-cryptography/utils");
|
|
75
|
+
keccak256(utf8ToBytes("abc"))
|
|
76
|
+
|
|
77
|
+
// If you need hex
|
|
78
|
+
const { bytesToHex as toHex } = require("@theqrl/qrl-cryptography/utils");
|
|
79
|
+
toHex(keccak256(utf8ToBytes("abc")))
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## KDFs: Argon2id
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
function argon2id(password: Uint8Array, salt: Uint8Array, t: number, m: number, p: number, dkLen: number, onProgress?: (progress: number) => void): Promise<Uint8Array>;
|
|
86
|
+
function argon2idSync(password: Uint8Array, salt: Uint8Array, t: number, m: number, p: number, dkLen: number, onProgress?: (progress: number) => void): Uint8Array;
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The `argon2id` submodule has two functions implementing the Argon2id key
|
|
90
|
+
derivation algorithm in synchronous and asynchronous ways. This algorithm is
|
|
91
|
+
very slow, and using the synchronous version in the browser is not recommended,
|
|
92
|
+
as it will block its main thread and hang your UI.
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
const { argon2id } = require("@theqrl/qrl-cryptography/argon2id");
|
|
96
|
+
const { utf8ToBytes } = require("@theqrl/qrl-cryptography/utils");
|
|
97
|
+
console.log(await argon2id(utf8ToBytes("password"), utf8ToBytes("salt"), 8, 262144, 1, 32));
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## CSPRNG (Cryptographically strong pseudorandom number generator)
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
function getRandomBytes(bytes: number): Promise<Uint8Array>;
|
|
104
|
+
function getRandomBytesSync(bytes: number): Uint8Array;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The `random` submodule has functions to generate cryptographically strong
|
|
108
|
+
pseudo-random data in synchronous and asynchronous ways.
|
|
109
|
+
|
|
110
|
+
Backed by [`crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) in browser and by [`crypto.randomBytes`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) in node.js. If backends are somehow not available, the module would throw an error and won't work, as keeping them working would be insecure.
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
const { getRandomBytesSync } = require("@theqrl/qrl-cryptography/random");
|
|
114
|
+
console.log(getRandomBytesSync(32));
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## AES Encryption
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
function encrypt(msg: Uint8Array, key: Uint8Array, iv: Uint8Array, mode = "aes-256-gcm", pkcs7PaddingEnabled = true): Promise<Uint8Array>;
|
|
121
|
+
function decrypt(cypherText: Uint8Array, key: Uint8Array, iv: Uint8Array, mode = "aes-256-gcm", pkcs7PaddingEnabled = true): Promise<Uint8Array>;
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The `aes` submodule contains encryption and decryption functions implementing
|
|
125
|
+
the [Advanced Encryption Standard](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard)
|
|
126
|
+
algorithm.
|
|
127
|
+
|
|
128
|
+
### Encrypting with passwords
|
|
129
|
+
|
|
130
|
+
AES is not supposed to be used directly with a password. Doing that will
|
|
131
|
+
compromise your users' security.
|
|
132
|
+
|
|
133
|
+
The `key` parameters in this submodule are meant to be strong cryptographic
|
|
134
|
+
keys. If you want to obtain such a key from a password, please use a
|
|
135
|
+
[key derivation function](https://en.wikipedia.org/wiki/Key_derivation_function)
|
|
136
|
+
like [argon2id](#kdfs-argon2id).
|
|
137
|
+
|
|
138
|
+
### Operation modes
|
|
139
|
+
|
|
140
|
+
This submodule works with different [block cipher modes of operation](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation). If you are using this module in a new
|
|
141
|
+
application, we recommend using the default.
|
|
142
|
+
|
|
143
|
+
While this module may work with any mode supported by OpenSSL, we only test it
|
|
144
|
+
with `aes-256-gcm`. If you use another module a warning will be printed in the
|
|
145
|
+
console.
|
|
146
|
+
|
|
147
|
+
We only recommend using `aes-256-gcm` to decrypt already encrypted data.
|
|
148
|
+
|
|
149
|
+
### Padding plaintext messages
|
|
150
|
+
|
|
151
|
+
Some operation modes require the plaintext message to be a multiple of `16`. If
|
|
152
|
+
that isn't the case, your message has to be padded.
|
|
153
|
+
|
|
154
|
+
By default, this module automatically pads your messages according to [PKCS#7](https://tools.ietf.org/html/rfc2315).
|
|
155
|
+
Note that this padding scheme always adds at least 1 byte of padding. If you
|
|
156
|
+
are unsure what anything of this means, we **strongly** recommend you to use
|
|
157
|
+
the defaults.
|
|
158
|
+
|
|
159
|
+
If you need to encrypt without padding or want to use another padding scheme,
|
|
160
|
+
you can disable PKCS#7 padding by passing `false` as the last argument and
|
|
161
|
+
handling padding yourself. Note that if you do this and your operation mode
|
|
162
|
+
requires padding, `encrypt` will throw if your plaintext message isn't a
|
|
163
|
+
multiple of `16`.
|
|
164
|
+
|
|
165
|
+
This option is only present to enable the decryption of already encrypted data.
|
|
166
|
+
To encrypt new data, we recommend using the default.
|
|
167
|
+
|
|
168
|
+
### How to use the IV parameter
|
|
169
|
+
|
|
170
|
+
The `iv` parameter of the `encrypt` function must be unique, or the security
|
|
171
|
+
of the encryption algorithm can be compromised.
|
|
172
|
+
|
|
173
|
+
You can generate a new `iv` using the `random` module.
|
|
174
|
+
|
|
175
|
+
Note that to decrypt a value, you have to provide the same `iv` used to encrypt
|
|
176
|
+
it.
|
|
177
|
+
|
|
178
|
+
### How to handle errors with this module
|
|
179
|
+
|
|
180
|
+
Sensitive information can be leaked via error messages when using this module.
|
|
181
|
+
To avoid this, you should make sure that the errors you return don't
|
|
182
|
+
contain the exact reason for the error. Instead, errors must report general
|
|
183
|
+
encryption/decryption failures.
|
|
184
|
+
|
|
185
|
+
Note that implementing this can mean catching all errors that can be thrown
|
|
186
|
+
when calling on of this module's functions, and just throwing a new generic
|
|
187
|
+
exception.
|
|
188
|
+
|
|
189
|
+
### Example usage
|
|
190
|
+
|
|
191
|
+
```js
|
|
192
|
+
const { encrypt } = require("@theqrl/qrl-cryptography/aes");
|
|
193
|
+
const { hexToBytes, utf8ToBytes } = require("@theqrl/qrl-cryptography/utils");
|
|
194
|
+
|
|
195
|
+
console.log(
|
|
196
|
+
encrypt(
|
|
197
|
+
utf8ToBytes("message"),
|
|
198
|
+
hexToBytes("2b7e151628aed2a6abf7158809cf4f3c"),
|
|
199
|
+
hexToBytes("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
|
|
200
|
+
)
|
|
201
|
+
);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## ML-DSA-87
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
function keygen(seed: Uint8Array): { publicKey: Uint8Array; secretKey: Uint8Array };
|
|
208
|
+
function sign(secretKey: Uint8Array, message: Uint8Array, ctx: Uint8Array): Uint8Array;
|
|
209
|
+
function verify(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array, ctx: Uint8Array): boolean;
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
The `ml_dsa87` submodule provides the ML-DSA-87 (FIPS 204) post-quantum digital signature scheme, powered by [`@theqrl/mldsa87`](https://www.npmjs.com/package/@theqrl/mldsa87).
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
const { ml_dsa87 } = require("@theqrl/qrl-cryptography/ml_dsa87");
|
|
216
|
+
const { utf8ToBytes } = require("@theqrl/qrl-cryptography/utils");
|
|
217
|
+
|
|
218
|
+
// Generate a key pair
|
|
219
|
+
const { publicKey, secretKey } = ml_dsa87.keygen(seed);
|
|
220
|
+
|
|
221
|
+
// Sign a message
|
|
222
|
+
const ctx = utf8ToBytes("context");
|
|
223
|
+
const msg = utf8ToBytes("hello");
|
|
224
|
+
const signature = ml_dsa87.sign(secretKey, msg, ctx);
|
|
225
|
+
|
|
226
|
+
// Verify a signature
|
|
227
|
+
const isValid = ml_dsa87.verify(publicKey, msg, signature, ctx);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Browser usage
|
|
231
|
+
|
|
232
|
+
### Rollup setup
|
|
233
|
+
|
|
234
|
+
Using this library with Rollup requires the following plugins:
|
|
235
|
+
|
|
236
|
+
* [`@rollup/plugin-commonjs`](https://www.npmjs.com/package/@rollup/plugin-commonjs)
|
|
237
|
+
* [`@rollup/plugin-node-resolve`](https://www.npmjs.com/package/@rollup/plugin-node-resolve)
|
|
238
|
+
|
|
239
|
+
These can be used by setting your `plugins` array like this:
|
|
240
|
+
|
|
241
|
+
```js
|
|
242
|
+
plugins: [
|
|
243
|
+
commonjs(),
|
|
244
|
+
resolve({
|
|
245
|
+
browser: true,
|
|
246
|
+
preferBuiltins: false,
|
|
247
|
+
}),
|
|
248
|
+
]
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## License
|
|
252
|
+
|
|
253
|
+
`qrl-cryptography` is released under The MIT License (MIT)
|
|
254
|
+
|
|
255
|
+
Copyright (c) 2021 Patricio Palladino, Paul Miller, ethereum-cryptography contributors
|
|
256
|
+
Copyright (c) 2024 The QRL Contributors
|
|
257
|
+
|
|
258
|
+
See [LICENSE](./LICENSE) file.
|
package/aes.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare function encrypt(msg: Uint8Array, key: Uint8Array, iv: Uint8Array, mode?: string, pkcs7PaddingEnabled?: boolean): Promise<Uint8Array>;
|
|
2
|
+
export declare function decrypt(cypherText: Uint8Array, key: Uint8Array, iv: Uint8Array, mode?: string, pkcs7PaddingEnabled?: boolean): Promise<Uint8Array>;
|
package/aes.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decrypt = exports.encrypt = void 0;
|
|
4
|
+
const crypto_1 = require("@noble/hashes/crypto");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
const crypto = { web: crypto_1.crypto };
|
|
7
|
+
function validateOpt(key, iv, mode) {
|
|
8
|
+
if (!mode.startsWith("aes-")) {
|
|
9
|
+
throw new Error(`AES submodule doesn't support mode ${mode}`);
|
|
10
|
+
}
|
|
11
|
+
if (iv.length !== 12) {
|
|
12
|
+
throw new Error("AES: wrong IV length");
|
|
13
|
+
}
|
|
14
|
+
if (mode.startsWith("aes-256") && key.length !== 32) {
|
|
15
|
+
throw new Error("AES: wrong key length");
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function getBrowserKey(mode, key, iv) {
|
|
19
|
+
if (!crypto.web) {
|
|
20
|
+
throw new Error("Browser crypto not available.");
|
|
21
|
+
}
|
|
22
|
+
let keyMode;
|
|
23
|
+
if (["aes-256-gcm"].includes(mode)) {
|
|
24
|
+
keyMode = "gcm";
|
|
25
|
+
}
|
|
26
|
+
if (!keyMode) {
|
|
27
|
+
throw new Error("AES: unsupported mode");
|
|
28
|
+
}
|
|
29
|
+
const wKey = await crypto.web.subtle.importKey("raw", key, { name: `AES-${keyMode.toUpperCase()}`, length: key.length * 8 }, true, ["encrypt", "decrypt"]);
|
|
30
|
+
// TODO(rgeraldes24): missing fields
|
|
31
|
+
// node.js uses whole 128 bit as a counter, without nonce, instead of 64 bit
|
|
32
|
+
// recommended by NIST SP800-38A
|
|
33
|
+
return [wKey, { name: `aes-${keyMode}`, iv }];
|
|
34
|
+
}
|
|
35
|
+
async function encrypt(msg, key, iv, mode = "aes-256-gcm", pkcs7PaddingEnabled = true) {
|
|
36
|
+
validateOpt(key, iv, mode);
|
|
37
|
+
if (crypto.web) {
|
|
38
|
+
const [wKey, wOpt] = await getBrowserKey(mode, key, iv);
|
|
39
|
+
const cipher = await crypto.web.subtle.encrypt(wOpt, wKey, msg);
|
|
40
|
+
let res = new Uint8Array(cipher);
|
|
41
|
+
return res;
|
|
42
|
+
}
|
|
43
|
+
else if (crypto.node) {
|
|
44
|
+
const cipher = crypto.node.createCipheriv(mode, key, iv);
|
|
45
|
+
cipher.setAutoPadding(pkcs7PaddingEnabled);
|
|
46
|
+
return (0, utils_1.concatBytes)(cipher.update(msg), cipher.final());
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
throw new Error("The environment doesn't have AES module");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.encrypt = encrypt;
|
|
53
|
+
async function decrypt(cypherText, key, iv, mode = "aes-256-gcm", pkcs7PaddingEnabled = true) {
|
|
54
|
+
validateOpt(key, iv, mode);
|
|
55
|
+
if (crypto.web) {
|
|
56
|
+
const [wKey, wOpt] = await getBrowserKey(mode, key, iv);
|
|
57
|
+
const msg = await crypto.web.subtle.decrypt(wOpt, wKey, cypherText);
|
|
58
|
+
const msgBytes = new Uint8Array(msg);
|
|
59
|
+
return msgBytes;
|
|
60
|
+
}
|
|
61
|
+
else if (crypto.node) {
|
|
62
|
+
const decipher = crypto.node.createDecipheriv(mode, key, iv);
|
|
63
|
+
decipher.setAutoPadding(pkcs7PaddingEnabled);
|
|
64
|
+
return (0, utils_1.concatBytes)(decipher.update(cypherText), decipher.final());
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
throw new Error("The environment doesn't have AES module");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.decrypt = decrypt;
|
package/argon2id.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
type OnProgressCallback = (progress: number) => void;
|
|
2
|
+
export declare function argon2id(password: Uint8Array, salt: Uint8Array, t: number, m: number, p: number, dkLen: number, onProgress?: OnProgressCallback): Promise<Uint8Array>;
|
|
3
|
+
export declare function argon2idSync(password: Uint8Array, salt: Uint8Array, t: number, m: number, p: number, dkLen: number, onProgress?: OnProgressCallback): Uint8Array;
|
|
4
|
+
export {};
|
package/argon2id.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.argon2idSync = exports.argon2id = void 0;
|
|
4
|
+
const argon2_1 = require("@noble/hashes/argon2");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
async function argon2id(password, salt, t, m, p, dkLen, onProgress) {
|
|
7
|
+
(0, utils_1.assertBytes)(password);
|
|
8
|
+
(0, utils_1.assertBytes)(salt);
|
|
9
|
+
return (0, argon2_1.argon2idAsync)(password, salt, { t, m, p, dkLen, onProgress });
|
|
10
|
+
}
|
|
11
|
+
exports.argon2id = argon2id;
|
|
12
|
+
function argon2idSync(password, salt, t, m, p, dkLen, onProgress) {
|
|
13
|
+
(0, utils_1.assertBytes)(password);
|
|
14
|
+
(0, utils_1.assertBytes)(salt);
|
|
15
|
+
return (0, argon2_1.argon2id)(password, salt, { t, m, p, dkLen, onProgress });
|
|
16
|
+
}
|
|
17
|
+
exports.argon2idSync = argon2idSync;
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const tseslint = require("@typescript-eslint/eslint-plugin");
|
|
2
|
+
const tsparser = require("@typescript-eslint/parser");
|
|
3
|
+
const prettier = require("eslint-plugin-prettier");
|
|
4
|
+
|
|
5
|
+
module.exports = [
|
|
6
|
+
{
|
|
7
|
+
files: ["**/*.ts"],
|
|
8
|
+
languageOptions: {
|
|
9
|
+
parser: tsparser,
|
|
10
|
+
},
|
|
11
|
+
plugins: {
|
|
12
|
+
"@typescript-eslint": tseslint,
|
|
13
|
+
prettier: prettier,
|
|
14
|
+
},
|
|
15
|
+
rules: {
|
|
16
|
+
...tseslint.configs.recommended.rules,
|
|
17
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
18
|
+
"@typescript-eslint/no-unused-vars": "warn",
|
|
19
|
+
"prettier/prettier": "error",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
ignores: ["node_modules", "test-builds", "*.js", "*.d.ts"],
|
|
24
|
+
},
|
|
25
|
+
];
|
package/index.d.ts
ADDED
|
File without changes
|
package/index.js
ADDED
package/keccak.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Keccak } from "@noble/hashes/sha3";
|
|
2
|
+
import { Hash } from "@noble/hashes/utils";
|
|
3
|
+
interface K256 {
|
|
4
|
+
(data: Uint8Array): Uint8Array;
|
|
5
|
+
create(): Hash<Keccak>;
|
|
6
|
+
}
|
|
7
|
+
export declare const keccak224: (msg: Uint8Array) => Uint8Array;
|
|
8
|
+
export declare const keccak256: K256;
|
|
9
|
+
export declare const keccak384: (msg: Uint8Array) => Uint8Array;
|
|
10
|
+
export declare const keccak512: (msg: Uint8Array) => Uint8Array;
|
|
11
|
+
export {};
|
package/keccak.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.keccak512 = exports.keccak384 = exports.keccak256 = exports.keccak224 = void 0;
|
|
4
|
+
const sha3_1 = require("@noble/hashes/sha3");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
exports.keccak224 = (0, utils_1.wrapHash)(sha3_1.keccak_224);
|
|
7
|
+
exports.keccak256 = (() => {
|
|
8
|
+
const k = (0, utils_1.wrapHash)(sha3_1.keccak_256);
|
|
9
|
+
k.create = sha3_1.keccak_256.create;
|
|
10
|
+
return k;
|
|
11
|
+
})();
|
|
12
|
+
exports.keccak384 = (0, utils_1.wrapHash)(sha3_1.keccak_384);
|
|
13
|
+
exports.keccak512 = (0, utils_1.wrapHash)(sha3_1.keccak_512);
|
package/ml_dsa87.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const ml_dsa87: {
|
|
2
|
+
keygen(seed: Uint8Array): {
|
|
3
|
+
publicKey: Uint8Array;
|
|
4
|
+
secretKey: Uint8Array;
|
|
5
|
+
};
|
|
6
|
+
sign(secretKey: Uint8Array, message: Uint8Array, ctx: Uint8Array): Uint8Array;
|
|
7
|
+
verify(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array, ctx: Uint8Array): boolean;
|
|
8
|
+
};
|
package/ml_dsa87.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ml_dsa87 = void 0;
|
|
4
|
+
const mldsa87_1 = require("@theqrl/mldsa87");
|
|
5
|
+
exports.ml_dsa87 = {
|
|
6
|
+
keygen(seed) {
|
|
7
|
+
const pk = new Uint8Array(mldsa87_1.CryptoPublicKeyBytes);
|
|
8
|
+
const sk = new Uint8Array(mldsa87_1.CryptoSecretKeyBytes);
|
|
9
|
+
(0, mldsa87_1.cryptoSignKeypair)(seed, pk, sk);
|
|
10
|
+
return { publicKey: pk, secretKey: sk };
|
|
11
|
+
},
|
|
12
|
+
sign(secretKey, message, ctx) {
|
|
13
|
+
const sig = new Uint8Array(mldsa87_1.CryptoBytes);
|
|
14
|
+
(0, mldsa87_1.cryptoSignSignature)(sig, message, secretKey, false, ctx);
|
|
15
|
+
return sig;
|
|
16
|
+
},
|
|
17
|
+
verify(publicKey, message, signature, ctx) {
|
|
18
|
+
return (0, mldsa87_1.cryptoSignVerify)(signature, message, publicKey, ctx);
|
|
19
|
+
},
|
|
20
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@theqrl/qrl-cryptography",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "All the cryptographic primitives used in QRL",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/theQRL/js-qrl-cryptography.git"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"main": "./index.js",
|
|
11
|
+
"files": [
|
|
12
|
+
"*.js",
|
|
13
|
+
"*.d.ts"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@noble/curves": "1.0.0",
|
|
17
|
+
"@noble/hashes": "1.6.1",
|
|
18
|
+
"@theqrl/mldsa87": "2.0.1"
|
|
19
|
+
},
|
|
20
|
+
"browser": {
|
|
21
|
+
"crypto": false
|
|
22
|
+
},
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"scripts": {
|
|
25
|
+
"prepare": "npm run build",
|
|
26
|
+
"build": "npm-run-all build:tsc",
|
|
27
|
+
"build:tsc": "tsc --project tsconfig.prod.json",
|
|
28
|
+
"test": "npm-run-all test:node",
|
|
29
|
+
"test:node": "mocha",
|
|
30
|
+
"clean": "rimraf test-builds '*.js' '*.js.map' '*.d.ts' '*.d.ts.map' 'src/**/*.js'",
|
|
31
|
+
"lint": "eslint",
|
|
32
|
+
"lint:fix": "eslint --fix",
|
|
33
|
+
"browser-tests": "npm-run-all browser-tests:build browser-tests:test",
|
|
34
|
+
"browser-tests:build": "bash -x ./scripts/build-browser-tests.sh",
|
|
35
|
+
"browser-tests:test": "npm-run-all browser-tests:test-parcel browser-tests:test-webpack browser-tests:test-rollup",
|
|
36
|
+
"browser-tests:test-parcel": "karma start --single-run --browsers ChromeHeadless test/karma.parcel.conf.js",
|
|
37
|
+
"browser-tests:test-webpack": "karma start --single-run --browsers ChromeHeadless test/karma.webpack.conf.js",
|
|
38
|
+
"browser-tests:test-rollup": "karma start --single-run --browsers ChromeHeadless test/karma.rollup.conf.js"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@rollup/plugin-commonjs": "29.0.2",
|
|
42
|
+
"@rollup/plugin-node-resolve": "16.0.3",
|
|
43
|
+
"@types/estree": "1.0.8",
|
|
44
|
+
"@types/mocha": "9.1.1",
|
|
45
|
+
"@types/node": "18.15.11",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "8.58.0",
|
|
47
|
+
"@typescript-eslint/parser": "8.58.0",
|
|
48
|
+
"eslint": "9.26.0",
|
|
49
|
+
"eslint-plugin-prettier": "5.5.5",
|
|
50
|
+
"karma": "6.4.0",
|
|
51
|
+
"karma-chrome-launcher": "3.1.1",
|
|
52
|
+
"karma-mocha": "2.0.1",
|
|
53
|
+
"karma-mocha-reporter": "2.2.5",
|
|
54
|
+
"mocha": "10.0.0",
|
|
55
|
+
"npm-run-all": "4.1.5",
|
|
56
|
+
"parcel": "2.6.2",
|
|
57
|
+
"prettier": "3.8.1",
|
|
58
|
+
"rimraf": "~3.0.2",
|
|
59
|
+
"rollup": "4.59.0",
|
|
60
|
+
"ts-node": "10.9.1",
|
|
61
|
+
"typescript": "5.0.2",
|
|
62
|
+
"webpack": "5.104.1",
|
|
63
|
+
"webpack-cli": "4.10"
|
|
64
|
+
},
|
|
65
|
+
"keywords": [
|
|
66
|
+
"qrl",
|
|
67
|
+
"cryptography",
|
|
68
|
+
"digital signature",
|
|
69
|
+
"hash",
|
|
70
|
+
"encryption",
|
|
71
|
+
"prng",
|
|
72
|
+
"keccak",
|
|
73
|
+
"argon2id",
|
|
74
|
+
"aes",
|
|
75
|
+
"advanced encryption standar"
|
|
76
|
+
],
|
|
77
|
+
"targets": {
|
|
78
|
+
"parcel_tests": {
|
|
79
|
+
"context": "browser"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
package/random.d.ts
ADDED
package/random.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getRandomBytes = exports.getRandomBytesSync = void 0;
|
|
4
|
+
const utils_1 = require("@noble/hashes/utils");
|
|
5
|
+
function getRandomBytesSync(bytes) {
|
|
6
|
+
return (0, utils_1.randomBytes)(bytes);
|
|
7
|
+
}
|
|
8
|
+
exports.getRandomBytesSync = getRandomBytesSync;
|
|
9
|
+
async function getRandomBytes(bytes) {
|
|
10
|
+
return (0, utils_1.randomBytes)(bytes);
|
|
11
|
+
}
|
|
12
|
+
exports.getRandomBytes = getRandomBytes;
|
package/utils.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare const assertBytes: typeof import("@noble/hashes/_assert").abytes;
|
|
2
|
+
export { /*assertBool,*/ assertBytes };
|
|
3
|
+
export { bytesToHex, bytesToHex as toHex, concatBytes, createView, utf8ToBytes, } from "@noble/hashes/utils";
|
|
4
|
+
export declare function bytesToUtf8(data: Uint8Array): string;
|
|
5
|
+
export declare function hexToBytes(data: string): Uint8Array;
|
|
6
|
+
export declare function equalsBytes(a: Uint8Array, b: Uint8Array): boolean;
|
|
7
|
+
export declare function wrapHash(hash: (msg: Uint8Array) => Uint8Array): (msg: Uint8Array) => Uint8Array;
|
|
8
|
+
export declare const crypto: {
|
|
9
|
+
node?: any;
|
|
10
|
+
web?: Crypto;
|
|
11
|
+
};
|
package/utils.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.crypto = exports.wrapHash = exports.equalsBytes = exports.hexToBytes = exports.bytesToUtf8 = exports.utf8ToBytes = exports.createView = exports.concatBytes = exports.toHex = exports.bytesToHex = exports.assertBytes = void 0;
|
|
7
|
+
// buf.toString('hex') -> toHex(buf)
|
|
8
|
+
const _assert_1 = __importDefault(require("@noble/hashes/_assert"));
|
|
9
|
+
const utils_1 = require("@noble/hashes/utils");
|
|
10
|
+
// const assertBool = assert.bool;
|
|
11
|
+
const assertBytes = _assert_1.default.bytes;
|
|
12
|
+
exports.assertBytes = assertBytes;
|
|
13
|
+
var utils_2 = require("@noble/hashes/utils");
|
|
14
|
+
Object.defineProperty(exports, "bytesToHex", { enumerable: true, get: function () { return utils_2.bytesToHex; } });
|
|
15
|
+
Object.defineProperty(exports, "toHex", { enumerable: true, get: function () { return utils_2.bytesToHex; } });
|
|
16
|
+
Object.defineProperty(exports, "concatBytes", { enumerable: true, get: function () { return utils_2.concatBytes; } });
|
|
17
|
+
Object.defineProperty(exports, "createView", { enumerable: true, get: function () { return utils_2.createView; } });
|
|
18
|
+
Object.defineProperty(exports, "utf8ToBytes", { enumerable: true, get: function () { return utils_2.utf8ToBytes; } });
|
|
19
|
+
// buf.toString('utf8') -> bytesToUtf8(buf)
|
|
20
|
+
function bytesToUtf8(data) {
|
|
21
|
+
if (!(data instanceof Uint8Array)) {
|
|
22
|
+
throw new TypeError(`bytesToUtf8 expected Uint8Array, got ${typeof data}`);
|
|
23
|
+
}
|
|
24
|
+
return new TextDecoder().decode(data);
|
|
25
|
+
}
|
|
26
|
+
exports.bytesToUtf8 = bytesToUtf8;
|
|
27
|
+
function hexToBytes(data) {
|
|
28
|
+
const sliced = data.startsWith("0x") ? data.substring(2) : data;
|
|
29
|
+
return (0, utils_1.hexToBytes)(sliced);
|
|
30
|
+
}
|
|
31
|
+
exports.hexToBytes = hexToBytes;
|
|
32
|
+
// buf.equals(buf2) -> equalsBytes(buf, buf2)
|
|
33
|
+
function equalsBytes(a, b) {
|
|
34
|
+
if (a.length !== b.length) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
for (let i = 0; i < a.length; i++) {
|
|
38
|
+
if (a[i] !== b[i]) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
exports.equalsBytes = equalsBytes;
|
|
45
|
+
// Internal utils
|
|
46
|
+
function wrapHash(hash) {
|
|
47
|
+
return (msg) => {
|
|
48
|
+
_assert_1.default.bytes(msg);
|
|
49
|
+
return hash(msg);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
exports.wrapHash = wrapHash;
|
|
53
|
+
exports.crypto = (() => {
|
|
54
|
+
const webCrypto = typeof self === "object" && "crypto" in self ? self.crypto : undefined;
|
|
55
|
+
const nodeRequire = typeof module !== "undefined" &&
|
|
56
|
+
typeof module.require === "function" &&
|
|
57
|
+
module.require.bind(module);
|
|
58
|
+
return {
|
|
59
|
+
node: nodeRequire && !webCrypto ? nodeRequire("crypto") : undefined,
|
|
60
|
+
web: webCrypto,
|
|
61
|
+
};
|
|
62
|
+
})();
|