@noble/post-quantum 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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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"}
|