@noble/post-quantum 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 +21 -0
- package/README.md +300 -0
- package/_crystals.d.ts +34 -0
- package/_crystals.d.ts.map +1 -0
- package/_crystals.js +171 -0
- package/_crystals.js.map +1 -0
- package/esm/_crystals.js +167 -0
- package/esm/_crystals.js.map +1 -0
- package/esm/index.js +3 -0
- package/esm/index.js.map +1 -0
- package/esm/ml-dsa.js +529 -0
- package/esm/ml-dsa.js.map +1 -0
- package/esm/ml-kem.js +361 -0
- package/esm/ml-kem.js.map +1 -0
- package/esm/package.json +10 -0
- package/esm/slh-dsa.js +602 -0
- package/esm/slh-dsa.js.map +1 -0
- package/esm/utils.js +86 -0
- package/esm/utils.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -0
- package/index.js +3 -0
- package/index.js.map +1 -0
- package/ml-dsa.d.ts +37 -0
- package/ml-dsa.d.ts.map +1 -0
- package/ml-dsa.js +532 -0
- package/ml-dsa.js.map +1 -0
- package/ml-kem.d.ts +134 -0
- package/ml-kem.d.ts.map +1 -0
- package/ml-kem.js +364 -0
- package/ml-kem.js.map +1 -0
- package/package.json +100 -0
- package/slh-dsa.d.ts +70 -0
- package/slh-dsa.d.ts.map +1 -0
- package/slh-dsa.js +605 -0
- package/slh-dsa.js.map +1 -0
- package/src/_crystals.ts +197 -0
- package/src/index.ts +1 -0
- package/src/ml-dsa.ts +569 -0
- package/src/ml-kem.ts +403 -0
- package/src/package.json +3 -0
- package/src/slh-dsa.ts +771 -0
- package/src/utils.ts +113 -0
- package/utils.d.ts +38 -0
- package/utils.d.ts.map +1 -0
- package/utils.js +94 -0
- package/utils.js.map +1 -0
package/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Paul Miller (https://paulmillr.com)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the โSoftwareโ), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED โAS ISโ, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
@@ -0,0 +1,300 @@
|
|
1
|
+
# noble-post-quantum
|
2
|
+
|
3
|
+
Auditable & minimal JS implementation of public-key post-quantum cryptography.
|
4
|
+
|
5
|
+
- ๐ Auditable
|
6
|
+
- ๐ป Tree-shaking-friendly: use only what's necessary, other code won't be included
|
7
|
+
- ๐ฆพ ML-KEM & CRYSTALS-Kyber: lattice-based kem
|
8
|
+
- ๐ ML-DSA & CRYSTALS-Dilithium: lattice-based signatures
|
9
|
+
- ๐ SLH-DSA & SPHINCS+: hash-based signatures
|
10
|
+
- ๐ FIPS-203, FIPS-204, FIPS-205 drafts
|
11
|
+
- ๐ชถ 2000 lines for all algorithms
|
12
|
+
|
13
|
+
Check out [What should I use](#what-should-i-use) section for benchmarks
|
14
|
+
and algorithm selection guidance. For discussions, questions and support, visit
|
15
|
+
[GitHub Discussions](https://github.com/paulmillr/noble-post-quantum/discussions)
|
16
|
+
section of the repository.
|
17
|
+
|
18
|
+
### This library belongs to _noble_ cryptography
|
19
|
+
|
20
|
+
> **noble cryptography** โ high-security, easily auditable set of contained cryptographic libraries and tools.
|
21
|
+
|
22
|
+
- Zero or minimal dependencies
|
23
|
+
- Highly readable TypeScript / JS code
|
24
|
+
- PGP-signed releases and transparent NPM builds
|
25
|
+
- All libraries:
|
26
|
+
[ciphers](https://github.com/paulmillr/noble-ciphers),
|
27
|
+
[curves](https://github.com/paulmillr/noble-curves),
|
28
|
+
[hashes](https://github.com/paulmillr/noble-hashes),
|
29
|
+
[post-quantum](https://github.com/paulmillr/noble-post-quantum),
|
30
|
+
4kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /
|
31
|
+
[ed25519](https://github.com/paulmillr/noble-ed25519)
|
32
|
+
- [Check out homepage](https://paulmillr.com/noble/)
|
33
|
+
for reading resources, documentation and apps built with noble
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
> npm install @noble/post-quantum
|
38
|
+
|
39
|
+
We support all major platforms and runtimes.
|
40
|
+
For [Deno](https://deno.land), ensure to use
|
41
|
+
[npm specifier](https://deno.land/manual@v1.28.0/node/npm_specifiers).
|
42
|
+
For React Native, you may need a
|
43
|
+
[polyfill for getRandomValues](https://github.com/LinusU/react-native-get-random-values).
|
44
|
+
A standalone file
|
45
|
+
[noble-post-quantum.js](https://github.com/paulmillr/noble-post-quantum/releases) is also available.
|
46
|
+
|
47
|
+
```js
|
48
|
+
// import * from '@noble/post-quantum'; // Error: use sub-imports, to ensure small app size
|
49
|
+
import { ml_kem768, kyber768 } from '@noble/post-quantum/ml-kem';
|
50
|
+
// import { ml_kem768, kyber768 } from 'npm:@noble/post-quantum@0.1.0/ml-kem'; // Deno
|
51
|
+
```
|
52
|
+
|
53
|
+
- [What should I use?](#what-should-i-use)
|
54
|
+
- [ML-KEM / Kyber](#ml-kem--kyber-shared-secrets)
|
55
|
+
- [ML-DSA / Dilithium](#ml-dsa--dilithium-signatures)
|
56
|
+
- [SLH-DSA / SPHINCS+](#slh-dsa--sphincs-signatures)
|
57
|
+
- [Security](#security)
|
58
|
+
- [Speed](#speed)
|
59
|
+
- [Contributing & testing](#contributing--testing)
|
60
|
+
- [Resources](#resources)
|
61
|
+
- [License](#license)
|
62
|
+
|
63
|
+
### What should I use?
|
64
|
+
|
65
|
+
| | Speed | Key size | Sig size | Created in | Popularized in | Post-quantum? |
|
66
|
+
|-----------|--------|-------------|-------------|------------|----------------|---------------|
|
67
|
+
| RSA | Normal | 256B - 2KB | 256B - 2KB | 1970s | 1990s | No |
|
68
|
+
| ECC | Normal | 32 - 256B | 48 - 128B | 1980s | 2010s | No |
|
69
|
+
| Kyber | Fast | 1.6 - 31KB | 1KB | 1990s | 2020s | Yes |
|
70
|
+
| Dilithium | Normal | 1.3 - 2.5KB | 2.5 - 4.5KB | 1990s | 2020s | Yes |
|
71
|
+
| SPHINCS | Slow | 32 - 128B | 17 - 50KB | 1970s | 2020s | Yes |
|
72
|
+
|
73
|
+
Speed (higher is better):
|
74
|
+
|
75
|
+
| OPs/sec | Keygen | Signing | Verification | Shared secret |
|
76
|
+
|--------------|--------|---------|--------------|---------------|
|
77
|
+
| ECC ed25519 | 10270 | 5110 | 1050 | 1470 |
|
78
|
+
| Kyber-512 | 3050 | | | 2090 |
|
79
|
+
| Dilithium-2 | 580 | 170 | 550 | |
|
80
|
+
| SPHINCS-128f | 200 | 8 | 140 | |
|
81
|
+
|
82
|
+
tl;dr: ECC + ML-KEM for key agreement, SLH-DSA for pq signatures.
|
83
|
+
|
84
|
+
It's recommended to use SPHINCS, which is built on
|
85
|
+
top of older, conservative primitives.
|
86
|
+
|
87
|
+
Kyber and Dilithium are lattice-based, so they're less "proven".
|
88
|
+
There's some chance of advancement, which will break this algorithm class.
|
89
|
+
|
90
|
+
FIPS wants to release final standards in 2024.
|
91
|
+
Until then, they provide no test vectors, meaning
|
92
|
+
implementations could be producing invalid output.
|
93
|
+
Moreover, if you'll use non-FIPS versions, or even FIPS
|
94
|
+
versions today, it's possible the final spec will be
|
95
|
+
incompatible, and you'll be stuck with old implementations.
|
96
|
+
Similar to what happened to Keccak and SHA-3.
|
97
|
+
|
98
|
+
Symmetrical algorithms like AES and ChaCha (available in [noble-ciphers](https://github.com/paulmillr/noble-ciphers))
|
99
|
+
suffer less from quantum computers. For AES, simply update from AES-128 to AES-256.
|
100
|
+
|
101
|
+
### ML-KEM / Kyber shared secrets
|
102
|
+
|
103
|
+
```ts
|
104
|
+
import { ml_kem512, ml_kem768, ml_kem1024 } from '@noble/post-quantum/ml-kem';
|
105
|
+
// import { kyber512, kyber768, kyber1024 } from '@noble/post-quantum/ml-kem';
|
106
|
+
// import { kyber512_90s, kyber768_90s, kyber1024_90s } from '@noble/post-quantum/ml-kem';
|
107
|
+
const aliceKeys = ml_kem768.keygen();
|
108
|
+
const alicePub = aliceKeys.publicKey;
|
109
|
+
const { cipherText, sharedSecret: bobShared } = ml_kem768.encapsulate(alicePub);
|
110
|
+
const aliceShared = ml_kem768.decapsulate(cipherText, aliceKeys.secretKey); // [Alice] decrypts sharedSecret from Bob
|
111
|
+
// aliceShared == bobShared
|
112
|
+
```
|
113
|
+
|
114
|
+
Lattice-based key encapsulation mechanism.
|
115
|
+
See [official site](https://www.pq-crystals.org/kyber/resources.shtml),
|
116
|
+
[repo](https://github.com/pq-crystals/kyber),
|
117
|
+
[spec](https://datatracker.ietf.org/doc/draft-cfrg-schwabe-kyber/).
|
118
|
+
|
119
|
+
Key encapsulation is similar to DH / ECDH (think X25519), with important differences:
|
120
|
+
|
121
|
+
- We can't verify if it was "Bob" who've sent the shared secret.
|
122
|
+
In ECDH, it's always verified
|
123
|
+
- It is probabalistic and relies on quality of randomness (CSPRNG).
|
124
|
+
ECDH doesn't (to this extent).
|
125
|
+
- Kyber decapsulation never throws an error, even when shared secret was
|
126
|
+
encrypted by a different public key. It will just return a different
|
127
|
+
shared secret
|
128
|
+
|
129
|
+
There are some concerns with regards to security: see
|
130
|
+
[djb blog](https://blog.cr.yp.to/20231003-countcorrectly.html) and
|
131
|
+
[mailing list](https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/W2VOzy0wz_E).
|
132
|
+
|
133
|
+
Three versions are provided:
|
134
|
+
|
135
|
+
1. Kyber
|
136
|
+
2. Kyber-90s, using algorithms from 1990s
|
137
|
+
3. ML-KEM aka [FIPS-203](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf)
|
138
|
+
|
139
|
+
```ts
|
140
|
+
// Alice generates keys
|
141
|
+
const aliceKeys = kyber1024.keygen(); // [Alice] generates key pair (secret and public key)
|
142
|
+
const alicePub = aliceKeys.publicKey; // [Alice] sends public key to Bob (somehow)
|
143
|
+
// aliceKeys.secretKey never leaves [Alice] system and unknown to other parties
|
144
|
+
|
145
|
+
// Bob creates cipherText for Alice
|
146
|
+
// [Bob] generates shared secret for Alice publicKey
|
147
|
+
const { cipherText, sharedSecret: bobShared } = kyber1024.encapsulate(alicePub);
|
148
|
+
// bobShared never leaves [Bob] system and unknown to other parties
|
149
|
+
|
150
|
+
// Alice gets cipherText from Bob
|
151
|
+
// [Alice] decrypts sharedSecret from Bob
|
152
|
+
const aliceShared = kyber1024.decapsulate(cipherText, aliceKeys.secretKey);
|
153
|
+
|
154
|
+
// Now, both Alice and Both have same sharedSecret key without exchanging in plainText
|
155
|
+
deepStrictEqual(aliceShared, bobShared);
|
156
|
+
|
157
|
+
// Warning: Can be MITM-ed
|
158
|
+
const carolKeys = kyber1024.keygen();
|
159
|
+
const carolShared = kyber1024.decapsulate(cipherText, carolKeys.secretKey); // No error!
|
160
|
+
notDeepStrictEqual(aliceShared, carolShared); // Different key!
|
161
|
+
```
|
162
|
+
|
163
|
+
### ML-DSA / Dilithium signatures
|
164
|
+
|
165
|
+
```ts
|
166
|
+
import { ml_dsa44, ml_dsa65, ml_dsa87 } from '@noble/post-quantum/ml-dsa';
|
167
|
+
// import { dilithium_v30, dilithium_v31 } from '@noble/post-quantum/ml-dsa';
|
168
|
+
// import { dilithium_v30_aes, dilithium_v31_aes } from '@noble/post-quantum/ml-dsa';
|
169
|
+
const aliceKeys = ml_dsa65.keygen();
|
170
|
+
const msg = new Uint8Array(1);
|
171
|
+
const sig = ml_dsa65.sign(aliceKeys.secretKey, msg);
|
172
|
+
const isValid = ml_dsa65.verify(aliceKeys.publicKey, msg, sig)
|
173
|
+
```
|
174
|
+
|
175
|
+
Lattice-based digital signature algorithm. See
|
176
|
+
[official site](https://www.pq-crystals.org/dilithium/index.shtml),
|
177
|
+
[repo](https://github.com/pq-crystals/dilithium).
|
178
|
+
Dilithium has similar internals to Kyber, but their keys and params are different.
|
179
|
+
|
180
|
+
Three versions are provided:
|
181
|
+
|
182
|
+
1. Dilithium v3.0, v3.0 AES
|
183
|
+
2. Dilithium v3.1, v3.1 AES
|
184
|
+
3. ML-DSA aka [FIPS-204](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.ipd.pdf)
|
185
|
+
|
186
|
+
### SLH-DSA / SPHINCS+ signatures
|
187
|
+
|
188
|
+
```ts
|
189
|
+
import { slh_dsa_sha2_128f as sph } from '@noble/post-quantum/slh-dsa';
|
190
|
+
// import { sphincs_shake_128f_simple } from '@noble/post-quantum/slh-dsa';
|
191
|
+
// import { sphincs_sha2_128f_simple } from '@noble/post-quantum/slh-dsa';
|
192
|
+
// Full list of imports can be seen below in "FIPS-205" section details
|
193
|
+
const aliceKeys = sph.keygen();
|
194
|
+
const msg = new Uint8Array(1);
|
195
|
+
const sig = sph.sign(aliceKeys.secretKey, msg);
|
196
|
+
const isValid = sph.verify(aliceKeys.publicKey, msg, sig);
|
197
|
+
```
|
198
|
+
|
199
|
+
Hash-based digital signature algorithm. See [official site](https://sphincs.org).
|
200
|
+
We implement spec v3.1 with latest FIPS-205 changes.
|
201
|
+
It's compatible with the latest version in the [official repo](https://github.com/sphincs/sphincsplus).
|
202
|
+
Some wasm libraries use older specs.
|
203
|
+
|
204
|
+
Three versions are provided:
|
205
|
+
|
206
|
+
1. SHAKE256-based
|
207
|
+
2. SHA2-based
|
208
|
+
3. SLH-DSA aka [FIPS-205](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.205.ipd.pdf)
|
209
|
+
|
210
|
+
The pattern for exported name is:
|
211
|
+
|
212
|
+
```
|
213
|
+
sphincs_{HASH}_{BITS}{SIZE}_{KIND}
|
214
|
+
|
215
|
+
where
|
216
|
+
HASH: shake | sha2
|
217
|
+
BITS: 128 | 192 | 256
|
218
|
+
SIZE: f | s (full, short)
|
219
|
+
KIND: simple | robust
|
220
|
+
|
221
|
+
// Examples
|
222
|
+
sphincs_shake_128f_simple
|
223
|
+
sphincs_sha2_192s_robust
|
224
|
+
```
|
225
|
+
|
226
|
+
All imports:
|
227
|
+
|
228
|
+
```ts
|
229
|
+
import {
|
230
|
+
sphincs_shake_128f_simple,
|
231
|
+
sphincs_shake_128f_robust,
|
232
|
+
sphincs_shake_128s_simple,
|
233
|
+
sphincs_shake_128s_robust,
|
234
|
+
sphincs_shake_192f_simple,
|
235
|
+
sphincs_shake_192f_robust,
|
236
|
+
sphincs_shake_192s_simple,
|
237
|
+
sphincs_shake_192s_robust,
|
238
|
+
sphincs_shake_256f_simple,
|
239
|
+
sphincs_shake_256f_robust,
|
240
|
+
sphincs_shake_256s_simple,
|
241
|
+
sphincs_shake_256s_robust,
|
242
|
+
} from '@noble/post-quantum/slh-dsa';
|
243
|
+
|
244
|
+
import {
|
245
|
+
sphincs_sha2_128f_simple,
|
246
|
+
sphincs_sha2_128f_robust,
|
247
|
+
sphincs_sha2_128s_simple,
|
248
|
+
sphincs_sha2_128s_robust,
|
249
|
+
sphincs_sha2_192f_simple,
|
250
|
+
sphincs_sha2_192f_robust,
|
251
|
+
sphincs_sha2_192s_simple,
|
252
|
+
sphincs_sha2_192s_robust,
|
253
|
+
sphincs_sha2_256f_simple,
|
254
|
+
sphincs_sha2_256f_robust,
|
255
|
+
sphincs_sha2_256s_simple,
|
256
|
+
sphincs_sha2_256s_robust,
|
257
|
+
} from '@noble/post-quantum/slh-dsa';
|
258
|
+
|
259
|
+
import {
|
260
|
+
slh_dsa_sha2_128f,
|
261
|
+
slh_dsa_sha2_128s,
|
262
|
+
slh_dsa_sha2_192f,
|
263
|
+
slh_dsa_sha2_192s,
|
264
|
+
slh_dsa_sha2_256f,
|
265
|
+
slh_dsa_sha2_256s,
|
266
|
+
} from '@noble/post-quantum/slh-dsa';
|
267
|
+
```
|
268
|
+
|
269
|
+
## Security
|
270
|
+
|
271
|
+
The library has not been independently audited yet.
|
272
|
+
|
273
|
+
If you see anything unusual: investigate and report.
|
274
|
+
|
275
|
+
## Speed
|
276
|
+
|
277
|
+
To summarize, noble is the fastest JS implementation of post-quantum algorithms.
|
278
|
+
|
279
|
+
Check out [What should I use](#what-should-i-use) table for now.
|
280
|
+
|
281
|
+
## Contributing & testing
|
282
|
+
|
283
|
+
1. Clone the repository
|
284
|
+
2. `npm install` to install build dependencies like TypeScript
|
285
|
+
3. `npm run build` to compile TypeScript code
|
286
|
+
4. `npm run test` will execute all main tests
|
287
|
+
|
288
|
+
## Resources
|
289
|
+
|
290
|
+
Check out [paulmillr.com/noble](https://paulmillr.com/noble/)
|
291
|
+
for useful resources, articles, documentation and demos
|
292
|
+
related to the library.
|
293
|
+
|
294
|
+
## License
|
295
|
+
|
296
|
+
The MIT License (MIT)
|
297
|
+
|
298
|
+
Copyright (c) 2024 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)
|
299
|
+
|
300
|
+
See LICENSE file.
|
package/_crystals.d.ts
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
import type { TypedArray } from '@noble/hashes/utils';
|
2
|
+
import { BytesCoderLen, Coder } from './utils.js';
|
3
|
+
export type XOF = (seed: Uint8Array, blockLen?: number) => {
|
4
|
+
stats: () => {
|
5
|
+
calls: number;
|
6
|
+
xofs: number;
|
7
|
+
};
|
8
|
+
get: (x: number, y: number) => () => Uint8Array;
|
9
|
+
clean: () => void;
|
10
|
+
};
|
11
|
+
export type CrystalOpts<T extends TypedArray> = {
|
12
|
+
newPoly: TypedCons<T>;
|
13
|
+
N: number;
|
14
|
+
Q: number;
|
15
|
+
F: number;
|
16
|
+
ROOT_OF_UNITY: number;
|
17
|
+
brvBits: number;
|
18
|
+
isKyber: boolean;
|
19
|
+
};
|
20
|
+
export type TypedCons<T extends TypedArray> = (n: number) => T;
|
21
|
+
export declare const genCrystals: <T extends TypedArray>(opts: CrystalOpts<T>) => {
|
22
|
+
mod: (a: number, modulo?: number) => number;
|
23
|
+
smod: (a: number, modulo?: number) => number;
|
24
|
+
nttZetas: T;
|
25
|
+
NTT: {
|
26
|
+
encode: (r: T) => T;
|
27
|
+
decode: (r: T) => T;
|
28
|
+
};
|
29
|
+
bitsCoder: (d: number, c: Coder<number, number>) => BytesCoderLen<T>;
|
30
|
+
};
|
31
|
+
export declare const XOF128: XOF;
|
32
|
+
export declare const XOF256: XOF;
|
33
|
+
export declare const XOF_AES: XOF;
|
34
|
+
//# sourceMappingURL=_crystals.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"_crystals.d.ts","sourceRoot":"","sources":["src/_crystals.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,KAAK,EAAW,MAAM,YAAY,CAAC;AAE3D,MAAM,MAAM,GAAG,GAAG,CAChB,IAAI,EAAE,UAAU,EAChB,QAAQ,CAAC,EAAE,MAAM,KACd;IACH,KAAK,EAAE,MAAM;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,UAAU,CAAC;IAChD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,UAAU,IAAI;IAC9C,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,UAAU,IAAI,CAAC,CAAC,EAAE,MAAM,KAAK,CAAC,CAAC;AAU/D,eAAO,MAAM,WAAW;aAGN,MAAM,sBAAe,MAAM;cAK1B,MAAM,sBAAe,MAAM;;;;;;mBAsDtB,MAAM,KAAK,MAAM,MAAM,EAAE,MAAM,CAAC;CA2BvD,CAAC;AAuCF,eAAO,MAAM,MAAM,KAA2C,CAAC;AAC/D,eAAO,MAAM,MAAM,KAA2C,CAAC;AAgC/D,eAAO,MAAM,OAAO,KAAuC,CAAC"}
|
package/_crystals.js
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.XOF_AES = exports.XOF256 = exports.XOF128 = exports.genCrystals = void 0;
|
4
|
+
/*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */
|
5
|
+
const aes_1 = require("@noble/ciphers/aes");
|
6
|
+
const sha3_1 = require("@noble/hashes/sha3");
|
7
|
+
const utils_js_1 = require("./utils.js");
|
8
|
+
// TODO: benchmark
|
9
|
+
function bitReversal(n, bits = 8) {
|
10
|
+
const padded = n.toString(2).padStart(8, '0');
|
11
|
+
const sliced = padded.slice(-bits).padStart(7, '0');
|
12
|
+
const revrsd = sliced.split('').reverse().join('');
|
13
|
+
return Number.parseInt(revrsd, 2);
|
14
|
+
}
|
15
|
+
const genCrystals = (opts) => {
|
16
|
+
// isKyber: true means Kyber, false means Dilithium
|
17
|
+
const { newPoly, N, Q, F, ROOT_OF_UNITY, brvBits, isKyber } = opts;
|
18
|
+
const mod = (a, modulo = Q) => {
|
19
|
+
const result = a % modulo | 0;
|
20
|
+
return (result >= 0 ? result | 0 : (modulo + result) | 0) | 0;
|
21
|
+
};
|
22
|
+
// -(Q-1)/2 < a <= (Q-1)/2
|
23
|
+
const smod = (a, modulo = Q) => {
|
24
|
+
const r = mod(a, modulo) | 0;
|
25
|
+
return (r > modulo >> 1 ? (r - modulo) | 0 : r) | 0;
|
26
|
+
};
|
27
|
+
// Generate zettas
|
28
|
+
function getZettas() {
|
29
|
+
const out = newPoly(N);
|
30
|
+
for (let i = 0; i < N; i++) {
|
31
|
+
const b = bitReversal(i, brvBits);
|
32
|
+
const p = BigInt(ROOT_OF_UNITY) ** BigInt(b) % BigInt(Q);
|
33
|
+
out[i] = Number(p) | 0;
|
34
|
+
}
|
35
|
+
return out;
|
36
|
+
}
|
37
|
+
const nttZetas = getZettas();
|
38
|
+
// Number-Theoretic Transform
|
39
|
+
// Explained: https://electricdusk.com/ntt.html
|
40
|
+
// Kyber has slightly different params, since there is no 512th primitive root of unity mod q,
|
41
|
+
// only 256th primitive root of unity mod. Which also complicates MultiplyNTT.
|
42
|
+
// TODO: there should be less ugly way to define this.
|
43
|
+
const LEN1 = isKyber ? 128 : N;
|
44
|
+
const LEN2 = isKyber ? 1 : 0;
|
45
|
+
const NTT = {
|
46
|
+
encode: (r) => {
|
47
|
+
for (let k = 1, len = 128; len > LEN2; len >>= 1) {
|
48
|
+
for (let start = 0; start < N; start += 2 * len) {
|
49
|
+
const zeta = nttZetas[k++];
|
50
|
+
for (let j = start; j < start + len; j++) {
|
51
|
+
const t = mod(zeta * r[j + len]);
|
52
|
+
r[j + len] = mod(r[j] - t) | 0;
|
53
|
+
r[j] = mod(r[j] + t) | 0;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
return r;
|
58
|
+
},
|
59
|
+
decode: (r) => {
|
60
|
+
for (let k = LEN1 - 1, len = 1 + LEN2; len < LEN1 + LEN2; len <<= 1) {
|
61
|
+
for (let start = 0; start < N; start += 2 * len) {
|
62
|
+
const zeta = nttZetas[k--];
|
63
|
+
for (let j = start; j < start + len; j++) {
|
64
|
+
const t = r[j];
|
65
|
+
r[j] = mod(t + r[j + len]);
|
66
|
+
r[j + len] = mod(zeta * (r[j + len] - t));
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
for (let i = 0; i < r.length; i++)
|
71
|
+
r[i] = mod(F * r[i]);
|
72
|
+
return r;
|
73
|
+
},
|
74
|
+
};
|
75
|
+
// Encode polynominal as bits
|
76
|
+
const bitsCoder = (d, c) => {
|
77
|
+
const mask = (0, utils_js_1.getMask)(d);
|
78
|
+
const bytesLen = d * (N / 8);
|
79
|
+
return {
|
80
|
+
bytesLen,
|
81
|
+
encode: (poly) => {
|
82
|
+
const r = new Uint8Array(bytesLen);
|
83
|
+
for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < poly.length; i++) {
|
84
|
+
buf |= (c.encode(poly[i]) & mask) << bufLen;
|
85
|
+
bufLen += d;
|
86
|
+
for (; bufLen >= 8; bufLen -= 8, buf >>= 8)
|
87
|
+
r[pos++] = buf & (0, utils_js_1.getMask)(bufLen);
|
88
|
+
}
|
89
|
+
return r;
|
90
|
+
},
|
91
|
+
decode: (bytes) => {
|
92
|
+
const r = newPoly(N);
|
93
|
+
for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < bytes.length; i++) {
|
94
|
+
buf |= bytes[i] << bufLen;
|
95
|
+
bufLen += 8;
|
96
|
+
for (; bufLen >= d; bufLen -= d, buf >>= d)
|
97
|
+
r[pos++] = c.decode(buf & mask);
|
98
|
+
}
|
99
|
+
return r;
|
100
|
+
},
|
101
|
+
};
|
102
|
+
};
|
103
|
+
return { mod, smod, nttZetas, NTT, bitsCoder };
|
104
|
+
};
|
105
|
+
exports.genCrystals = genCrystals;
|
106
|
+
const createXofShake = (shake) => (seed, blockLen) => {
|
107
|
+
if (!blockLen)
|
108
|
+
blockLen = shake.blockLen;
|
109
|
+
// Optimizations that won't mater:
|
110
|
+
// - cached seed update (two .update(), on start and on the end)
|
111
|
+
// - another cache which cloned into working copy
|
112
|
+
// Faster than multiple updates, since seed less than blockLen
|
113
|
+
const _seed = new Uint8Array(seed.length + 2);
|
114
|
+
_seed.set(seed);
|
115
|
+
const seedLen = seed.length;
|
116
|
+
const buf = new Uint8Array(blockLen); // == shake128.blockLen
|
117
|
+
let h = shake.create({});
|
118
|
+
let calls = 0;
|
119
|
+
let xofs = 0;
|
120
|
+
return {
|
121
|
+
stats: () => ({ calls, xofs }),
|
122
|
+
get: (x, y) => {
|
123
|
+
_seed[seedLen + 0] = x;
|
124
|
+
_seed[seedLen + 1] = y;
|
125
|
+
h.destroy();
|
126
|
+
h = shake.create({}).update(_seed);
|
127
|
+
calls++;
|
128
|
+
return () => {
|
129
|
+
xofs++;
|
130
|
+
return h.xofInto(buf);
|
131
|
+
};
|
132
|
+
},
|
133
|
+
clean: () => {
|
134
|
+
h.destroy();
|
135
|
+
buf.fill(0);
|
136
|
+
_seed.fill(0);
|
137
|
+
},
|
138
|
+
};
|
139
|
+
};
|
140
|
+
exports.XOF128 = createXofShake(sha3_1.shake128);
|
141
|
+
exports.XOF256 = createXofShake(sha3_1.shake256);
|
142
|
+
const createXofAes = (aes) => (seed, blockLen) => {
|
143
|
+
if (!blockLen)
|
144
|
+
blockLen = 16 * 3; // 288
|
145
|
+
const nonce = new Uint8Array(16);
|
146
|
+
const xk = aes.expandKeyLE(seed.subarray(0, 32));
|
147
|
+
const block = new Uint8Array(blockLen);
|
148
|
+
const out = block.slice();
|
149
|
+
let calls = 0;
|
150
|
+
let xofs = 0;
|
151
|
+
return {
|
152
|
+
stats: () => ({ calls, xofs }),
|
153
|
+
get: (x, y) => {
|
154
|
+
nonce.fill(0); // clean counter
|
155
|
+
nonce[0] = x;
|
156
|
+
nonce[1] = y;
|
157
|
+
calls++;
|
158
|
+
return () => {
|
159
|
+
xofs++;
|
160
|
+
return aes.ctrCounter(xk, nonce, block, out);
|
161
|
+
};
|
162
|
+
},
|
163
|
+
clean: () => {
|
164
|
+
nonce.fill(0);
|
165
|
+
xk.fill(0);
|
166
|
+
out.fill(0);
|
167
|
+
},
|
168
|
+
};
|
169
|
+
};
|
170
|
+
exports.XOF_AES = createXofAes(aes_1.unsafe);
|
171
|
+
//# sourceMappingURL=_crystals.js.map
|
package/_crystals.js.map
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"_crystals.js","sourceRoot":"","sources":["src/_crystals.ts"],"names":[],"mappings":"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"}
|