@noble/post-quantum 0.4.1 → 0.5.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/README.md +47 -32
- package/_crystals.d.ts +1 -1
- package/_crystals.d.ts.map +1 -1
- package/_crystals.js +31 -46
- package/_crystals.js.map +1 -1
- package/hybrid.d.ts +102 -0
- package/hybrid.d.ts.map +1 -0
- package/hybrid.js +283 -0
- package/hybrid.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.js +4 -4
- package/index.js.map +1 -1
- package/ml-dsa.d.ts +16 -8
- package/ml-dsa.d.ts.map +1 -1
- package/ml-dsa.js +126 -68
- package/ml-dsa.js.map +1 -1
- package/ml-kem.d.ts +1 -14
- package/ml-kem.d.ts.map +1 -1
- package/ml-kem.js +70 -54
- package/ml-kem.js.map +1 -1
- package/package.json +39 -85
- package/slh-dsa.d.ts +4 -3
- package/slh-dsa.d.ts.map +1 -1
- package/slh-dsa.js +113 -86
- package/slh-dsa.js.map +1 -1
- package/src/_crystals.ts +30 -41
- package/src/hybrid.ts +372 -0
- package/src/index.ts +3 -3
- package/src/ml-dsa.ts +125 -39
- package/src/ml-kem.ts +49 -46
- package/src/slh-dsa.ts +90 -50
- package/src/utils.ts +85 -50
- package/utils.d.ts +52 -10
- package/utils.d.ts.map +1 -1
- package/utils.js +54 -60
- package/utils.js.map +1 -1
- package/esm/_crystals.d.ts +0 -34
- package/esm/_crystals.d.ts.map +0 -1
- package/esm/_crystals.js +0 -141
- package/esm/_crystals.js.map +0 -1
- package/esm/index.d.ts +0 -2
- package/esm/index.d.ts.map +0 -1
- package/esm/index.js +0 -21
- package/esm/index.js.map +0 -1
- package/esm/ml-dsa.d.ts +0 -25
- package/esm/ml-dsa.d.ts.map +0 -1
- package/esm/ml-dsa.js +0 -525
- package/esm/ml-dsa.js.map +0 -1
- package/esm/ml-kem.d.ts +0 -34
- package/esm/ml-kem.d.ts.map +0 -1
- package/esm/ml-kem.js +0 -306
- package/esm/ml-kem.js.map +0 -1
- package/esm/package.json +0 -10
- package/esm/slh-dsa.d.ts +0 -62
- package/esm/slh-dsa.d.ts.map +0 -1
- package/esm/slh-dsa.js +0 -596
- package/esm/slh-dsa.js.map +0 -1
- package/esm/utils.d.ts +0 -40
- package/esm/utils.d.ts.map +0 -1
- package/esm/utils.js +0 -133
- package/esm/utils.js.map +0 -1
- package/src/package.json +0 -3
package/README.md
CHANGED
@@ -8,7 +8,8 @@ Auditable & minimal JS implementation of post-quantum public-key cryptography.
|
|
8
8
|
- 🦾 ML-KEM & CRYSTALS-Kyber: lattice-based kem from FIPS-203
|
9
9
|
- 🔋 ML-DSA & CRYSTALS-Dilithium: lattice-based signatures from FIPS-204
|
10
10
|
- 🐈 SLH-DSA & SPHINCS+: hash-based Winternitz signatures from FIPS-205
|
11
|
-
-
|
11
|
+
- 🍡 Hybrid algorithms, combining classic & post-quantum
|
12
|
+
- 🪶 16KB (gzipped) for everything, including bundled noble-hashes & noble-curves
|
12
13
|
|
13
14
|
Take a glance at [GitHub Discussions](https://github.com/paulmillr/noble-post-quantum/discussions) for questions and support.
|
14
15
|
|
@@ -30,7 +31,7 @@ Take a glance at [GitHub Discussions](https://github.com/paulmillr/noble-post-qu
|
|
30
31
|
[curves](https://github.com/paulmillr/noble-curves),
|
31
32
|
[hashes](https://github.com/paulmillr/noble-hashes),
|
32
33
|
[post-quantum](https://github.com/paulmillr/noble-post-quantum),
|
33
|
-
|
34
|
+
5kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /
|
34
35
|
[ed25519](https://github.com/paulmillr/noble-ed25519)
|
35
36
|
- [Check out homepage](https://paulmillr.com/noble/)
|
36
37
|
for reading resources, documentation and apps built with noble
|
@@ -41,8 +42,6 @@ Take a glance at [GitHub Discussions](https://github.com/paulmillr/noble-post-qu
|
|
41
42
|
|
42
43
|
> `deno add jsr:@noble/post-quantum`
|
43
44
|
|
44
|
-
> `deno doc jsr:@noble/post-quantum` # command-line documentation
|
45
|
-
|
46
45
|
We support all major platforms and runtimes.
|
47
46
|
For React Native, you may need a
|
48
47
|
[polyfill for getRandomValues](https://github.com/LinusU/react-native-get-random-values).
|
@@ -51,8 +50,8 @@ A standalone file
|
|
51
50
|
|
52
51
|
```js
|
53
52
|
// import * from '@noble/post-quantum'; // Error: use sub-imports instead
|
54
|
-
import { ml_kem512, ml_kem768, ml_kem1024 } from '@noble/post-quantum/ml-kem';
|
55
|
-
import { ml_dsa44, ml_dsa65, ml_dsa87 } from '@noble/post-quantum/ml-dsa';
|
53
|
+
import { ml_kem512, ml_kem768, ml_kem1024 } from '@noble/post-quantum/ml-kem.js';
|
54
|
+
import { ml_dsa44, ml_dsa65, ml_dsa87 } from '@noble/post-quantum/ml-dsa.js';
|
56
55
|
import {
|
57
56
|
slh_dsa_sha2_128f,
|
58
57
|
slh_dsa_sha2_128s,
|
@@ -66,12 +65,13 @@ import {
|
|
66
65
|
slh_dsa_shake_192s,
|
67
66
|
slh_dsa_shake_256f,
|
68
67
|
slh_dsa_shake_256s,
|
69
|
-
} from '@noble/post-quantum/slh-dsa';
|
68
|
+
} from '@noble/post-quantum/slh-dsa.js';
|
70
69
|
```
|
71
70
|
|
72
71
|
- [ML-KEM / Kyber](#ml-kem--kyber-shared-secrets)
|
73
72
|
- [ML-DSA / Dilithium](#ml-dsa--dilithium-signatures)
|
74
73
|
- [SLH-DSA / SPHINCS+](#slh-dsa--sphincs-signatures)
|
74
|
+
- [Hybrids: XWing, KitchenSink and others](#hybrids-xwing-kitchensink-and-others)
|
75
75
|
- [What should I use?](#what-should-i-use)
|
76
76
|
- [Security](#security)
|
77
77
|
- [Speed](#speed)
|
@@ -81,30 +81,28 @@ import {
|
|
81
81
|
### ML-KEM / Kyber shared secrets
|
82
82
|
|
83
83
|
```ts
|
84
|
-
import { ml_kem512, ml_kem768, ml_kem1024 } from '@noble/post-quantum/ml-kem';
|
85
|
-
import { randomBytes } from '@noble/post-quantum/utils';
|
86
|
-
|
87
|
-
// 1. [Alice] generates secret & public keys, then sends publicKey to Bob
|
84
|
+
import { ml_kem512, ml_kem768, ml_kem1024 } from '@noble/post-quantum/ml-kem.js';
|
85
|
+
import { randomBytes } from '@noble/post-quantum/utils.js';
|
88
86
|
const seed = randomBytes(64); // seed is optional
|
89
87
|
const aliceKeys = ml_kem768.keygen(seed);
|
90
|
-
|
91
|
-
// 2. [Bob] generates shared secret for Alice publicKey
|
92
|
-
// bobShared never leaves [Bob] system and is unknown to other parties
|
93
88
|
const { cipherText, sharedSecret: bobShared } = ml_kem768.encapsulate(aliceKeys.publicKey);
|
94
|
-
|
95
|
-
// 3. [Alice] gets and decrypts cipherText from Bob
|
96
89
|
const aliceShared = ml_kem768.decapsulate(cipherText, aliceKeys.secretKey);
|
97
90
|
|
98
|
-
// Now, both Alice and Bob have same sharedSecret key
|
99
|
-
// without exchanging in plainText: aliceShared == bobShared
|
100
|
-
|
101
91
|
// Warning: Can be MITM-ed
|
102
|
-
const
|
103
|
-
const
|
104
|
-
notDeepStrictEqual(aliceShared,
|
92
|
+
const malloryKeys = ml_kem768.keygen();
|
93
|
+
const malloryShared = ml_kem768.decapsulate(cipherText, malloryKeys.secretKey); // No error!
|
94
|
+
notDeepStrictEqual(aliceShared, malloryShared); // Different key!
|
105
95
|
```
|
106
96
|
|
107
97
|
Lattice-based key encapsulation mechanism, defined in [FIPS-203](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf).
|
98
|
+
Can be used as follows:
|
99
|
+
|
100
|
+
1. *Alice* generates secret & public keys, then sends publicKey to *Bob*
|
101
|
+
2. *Bob* generates shared secret for Alice publicKey.
|
102
|
+
bobShared never leaves *Bob* system and is unknown to other parties
|
103
|
+
3. *Alice* gets and decrypts cipherText from Bob
|
104
|
+
Now, both Alice and Bob have same sharedSecret key
|
105
|
+
without exchanging in plainText: aliceShared == bobShared.
|
108
106
|
|
109
107
|
See [website](https://www.pq-crystals.org/kyber/resources.shtml) and [repo](https://github.com/pq-crystals/kyber).
|
110
108
|
There are some concerns with regards to security: see
|
@@ -121,11 +119,11 @@ Old, incompatible version (Kyber) is not provided. Open an issue if you need it.
|
|
121
119
|
### ML-DSA / Dilithium signatures
|
122
120
|
|
123
121
|
```ts
|
124
|
-
import { ml_dsa44, ml_dsa65, ml_dsa87 } from '@noble/post-quantum/ml-dsa';
|
125
|
-
import {
|
122
|
+
import { ml_dsa44, ml_dsa65, ml_dsa87 } from '@noble/post-quantum/ml-dsa.js';
|
123
|
+
import { randomBytes } from '@noble/post-quantum/utils.js';
|
126
124
|
const seed = randomBytes(32); // seed is optional
|
127
125
|
const keys = ml_dsa65.keygen(seed);
|
128
|
-
const msg =
|
126
|
+
const msg = new TextEncoder().encode('hello noble');
|
129
127
|
const sig = ml_dsa65.sign(keys.secretKey, msg);
|
130
128
|
const isValid = ml_dsa65.verify(keys.publicKey, msg, sig);
|
131
129
|
```
|
@@ -151,11 +149,10 @@ import {
|
|
151
149
|
slh_dsa_shake_192s,
|
152
150
|
slh_dsa_shake_256f,
|
153
151
|
slh_dsa_shake_256s,
|
154
|
-
} from '@noble/post-quantum/slh-dsa';
|
155
|
-
import { utf8ToBytes } from '@noble/post-quantum/utils';
|
152
|
+
} from '@noble/post-quantum/slh-dsa.js';
|
156
153
|
|
157
154
|
const keys2 = sph.keygen();
|
158
|
-
const msg2 =
|
155
|
+
const msg2 = new TextEncoder().encode('hello noble');
|
159
156
|
const sig2 = sph.sign(keys2.secretKey, msg2);
|
160
157
|
const isValid2 = sph.verify(keys2.publicKey, msg2, sig2);
|
161
158
|
```
|
@@ -167,6 +164,24 @@ There are many different kinds,
|
|
167
164
|
but basically `sha2` / `shake` indicate internal hash, `128` / `192` / `256` indicate security level, and `s` /`f` indicate trade-off (Small / Fast).
|
168
165
|
SLH-DSA is slow: see [benchmarks](#speed) for key size & speed.
|
169
166
|
|
167
|
+
### Hybrids: XWing, KitchenSink and others
|
168
|
+
|
169
|
+
```js
|
170
|
+
import {
|
171
|
+
XWing,
|
172
|
+
KitchenSinkMLKEM768X25519,
|
173
|
+
QSFMLKEM768P256, QSFMLKEM1024P384
|
174
|
+
} from '@noble/post-quantum/hybrids.js';
|
175
|
+
```
|
176
|
+
|
177
|
+
XWing is x25519+mlkem768, just like kitchensink.
|
178
|
+
|
179
|
+
The following spec drafts are matched:
|
180
|
+
|
181
|
+
- [irtf-cfrg-hybrid-kems](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hybrid-kems/)
|
182
|
+
- [connolly-cfrg-xwing-kem](https://datatracker.ietf.org/doc/draft-connolly-cfrg-xwing-kem/)
|
183
|
+
- [tls-westerbaan-xyber768d00](https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/)
|
184
|
+
|
170
185
|
### What should I use?
|
171
186
|
|
172
187
|
| | Speed | Key size | Sig size | Created in | Popularized in | Post-quantum? |
|
@@ -204,9 +219,9 @@ Keep in mind that even hardware versions ML-KEM [are vulnerable](https://eprint.
|
|
204
219
|
### Supply chain security
|
205
220
|
|
206
221
|
- **Commits** are signed with PGP keys, to prevent forgery. Make sure to verify commit signatures
|
207
|
-
- **Releases** are transparent and built on GitHub CI.
|
208
|
-
|
209
|
-
|
222
|
+
- **Releases** are transparent and built on GitHub CI.
|
223
|
+
Check out [attested checksums of single-file builds](https://github.com/paulmillr/noble-post-quantum/attestations)
|
224
|
+
and [provenance logs](https://github.com/paulmillr/noble-post-quantum/actions/workflows/release.yml)
|
210
225
|
- **Rare releasing** is followed to ensure less re-audit need for end-users
|
211
226
|
- **Dependencies** are minimized and locked-down: any dependency could get hacked and users will be downloading malware with every install.
|
212
227
|
- We make sure to use as few dependencies as possible
|
@@ -235,7 +250,7 @@ Noble is the fastest JS implementation of post-quantum algorithms.
|
|
235
250
|
WASM libraries can be faster.
|
236
251
|
For SLH-DSA, SHAKE slows everything down 8x, and -s versions do another 20-50x slowdown.
|
237
252
|
|
238
|
-
Benchmarks on Apple M4:
|
253
|
+
Benchmarks on Apple M4 (**higher is better**):
|
239
254
|
|
240
255
|
| OPs/sec | Keygen | Signing | Verification | Shared secret |
|
241
256
|
| ----------------- | ------ | ------- | ------------ | ------------- |
|
package/_crystals.d.ts
CHANGED
package/_crystals.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"_crystals.d.ts","sourceRoot":"","sources":["src/_crystals.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"_crystals.d.ts","sourceRoot":"","sources":["src/_crystals.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,aAAa,EAAc,KAAK,KAAK,EAAW,MAAM,YAAY,CAAC;AAEjF,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,wCAAwC;AACxC,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;AAE/D,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,UAAU,EAC9C,MAAM,WAAW,CAAC,CAAC,CAAC,KACnB;IACD,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7C,QAAQ,EAAE,CAAC,CAAC;IACZ,GAAG,EAAE;QACH,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;KACrB,CAAC;IACF,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC;CAuFtE,CAAC;AAsCF,eAAO,MAAM,MAAM,EAAE,GAA8C,CAAC;AACpE,eAAO,MAAM,MAAM,EAAE,GAA8C,CAAC"}
|
package/_crystals.js
CHANGED
@@ -1,21 +1,12 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.XOF256 = exports.XOF128 = exports.genCrystals = void 0;
|
4
1
|
/**
|
5
2
|
* Internal methods for lattice-based ML-KEM and ML-DSA.
|
6
3
|
* @module
|
7
4
|
*/
|
8
5
|
/*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
const padded = n.toString(2).padStart(8, '0');
|
14
|
-
const sliced = padded.slice(-bits).padStart(7, '0');
|
15
|
-
const revrsd = sliced.split('').reverse().join('');
|
16
|
-
return Number.parseInt(revrsd, 2);
|
17
|
-
}
|
18
|
-
const genCrystals = (opts) => {
|
6
|
+
import { FFTCore, reverseBits } from '@noble/curves/abstract/fft.js';
|
7
|
+
import { shake128, shake256 } from '@noble/hashes/sha3.js';
|
8
|
+
import { cleanBytes, getMask } from "./utils.js";
|
9
|
+
export const genCrystals = (opts) => {
|
19
10
|
// isKyber: true means Kyber, false means Dilithium
|
20
11
|
const { newPoly, N, Q, F, ROOT_OF_UNITY, brvBits, isKyber } = opts;
|
21
12
|
const mod = (a, modulo = Q) => {
|
@@ -27,11 +18,11 @@ const genCrystals = (opts) => {
|
|
27
18
|
const r = mod(a, modulo) | 0;
|
28
19
|
return (r > modulo >> 1 ? (r - modulo) | 0 : r) | 0;
|
29
20
|
};
|
30
|
-
// Generate zettas
|
21
|
+
// Generate zettas (different from roots of unity, negacyclic uses phi, where acyclic uses omega)
|
31
22
|
function getZettas() {
|
32
23
|
const out = newPoly(N);
|
33
24
|
for (let i = 0; i < N; i++) {
|
34
|
-
const b =
|
25
|
+
const b = reverseBits(i, brvBits);
|
35
26
|
const p = BigInt(ROOT_OF_UNITY) ** BigInt(b) % BigInt(Q);
|
36
27
|
out[i] = Number(p) | 0;
|
37
28
|
}
|
@@ -42,34 +33,30 @@ const genCrystals = (opts) => {
|
|
42
33
|
// Explained: https://electricdusk.com/ntt.html
|
43
34
|
// Kyber has slightly different params, since there is no 512th primitive root of unity mod q,
|
44
35
|
// only 256th primitive root of unity mod. Which also complicates MultiplyNTT.
|
45
|
-
|
46
|
-
|
47
|
-
|
36
|
+
const field = {
|
37
|
+
add: (a, b) => mod((a | 0) + (b | 0)) | 0,
|
38
|
+
sub: (a, b) => mod((a | 0) - (b | 0)) | 0,
|
39
|
+
mul: (a, b) => mod((a | 0) * (b | 0)) | 0,
|
40
|
+
inv: (_a) => {
|
41
|
+
throw new Error('not implemented');
|
42
|
+
},
|
43
|
+
};
|
44
|
+
const nttOpts = {
|
45
|
+
N,
|
46
|
+
roots: nttZetas,
|
47
|
+
invertButterflies: true,
|
48
|
+
skipStages: isKyber ? 1 : 0,
|
49
|
+
brp: false,
|
50
|
+
};
|
51
|
+
const dif = FFTCore(field, { dit: false, ...nttOpts });
|
52
|
+
const dit = FFTCore(field, { dit: true, ...nttOpts });
|
48
53
|
const NTT = {
|
49
54
|
encode: (r) => {
|
50
|
-
|
51
|
-
for (let start = 0; start < N; start += 2 * len) {
|
52
|
-
const zeta = nttZetas[k++];
|
53
|
-
for (let j = start; j < start + len; j++) {
|
54
|
-
const t = mod(zeta * r[j + len]);
|
55
|
-
r[j + len] = mod(r[j] - t) | 0;
|
56
|
-
r[j] = mod(r[j] + t) | 0;
|
57
|
-
}
|
58
|
-
}
|
59
|
-
}
|
60
|
-
return r;
|
55
|
+
return dif(r);
|
61
56
|
},
|
62
57
|
decode: (r) => {
|
63
|
-
|
64
|
-
|
65
|
-
const zeta = nttZetas[k--];
|
66
|
-
for (let j = start; j < start + len; j++) {
|
67
|
-
const t = r[j];
|
68
|
-
r[j] = mod(t + r[j + len]);
|
69
|
-
r[j + len] = mod(zeta * (r[j + len] - t));
|
70
|
-
}
|
71
|
-
}
|
72
|
-
}
|
58
|
+
dit(r);
|
59
|
+
// kyber uses 128 here, because brv && stuff
|
73
60
|
for (let i = 0; i < r.length; i++)
|
74
61
|
r[i] = mod(F * r[i]);
|
75
62
|
return r;
|
@@ -77,7 +64,7 @@ const genCrystals = (opts) => {
|
|
77
64
|
};
|
78
65
|
// Encode polynominal as bits
|
79
66
|
const bitsCoder = (d, c) => {
|
80
|
-
const mask =
|
67
|
+
const mask = getMask(d);
|
81
68
|
const bytesLen = d * (N / 8);
|
82
69
|
return {
|
83
70
|
bytesLen,
|
@@ -87,7 +74,7 @@ const genCrystals = (opts) => {
|
|
87
74
|
buf |= (c.encode(poly[i]) & mask) << bufLen;
|
88
75
|
bufLen += d;
|
89
76
|
for (; bufLen >= 8; bufLen -= 8, buf >>= 8)
|
90
|
-
r[pos++] = buf &
|
77
|
+
r[pos++] = buf & getMask(bufLen);
|
91
78
|
}
|
92
79
|
return r;
|
93
80
|
},
|
@@ -105,7 +92,6 @@ const genCrystals = (opts) => {
|
|
105
92
|
};
|
106
93
|
return { mod, smod, nttZetas, NTT, bitsCoder };
|
107
94
|
};
|
108
|
-
exports.genCrystals = genCrystals;
|
109
95
|
const createXofShake = (shake) => (seed, blockLen) => {
|
110
96
|
if (!blockLen)
|
111
97
|
blockLen = shake.blockLen;
|
@@ -135,11 +121,10 @@ const createXofShake = (shake) => (seed, blockLen) => {
|
|
135
121
|
},
|
136
122
|
clean: () => {
|
137
123
|
h.destroy();
|
138
|
-
buf
|
139
|
-
_seed.fill(0);
|
124
|
+
cleanBytes(buf, _seed);
|
140
125
|
},
|
141
126
|
};
|
142
127
|
};
|
143
|
-
|
144
|
-
|
128
|
+
export const XOF128 = /* @__PURE__ */ createXofShake(shake128);
|
129
|
+
export const XOF256 = /* @__PURE__ */ createXofShake(shake256);
|
145
130
|
//# sourceMappingURL=_crystals.js.map
|
package/_crystals.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"_crystals.js","sourceRoot":"","sources":["src/_crystals.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"_crystals.js","sourceRoot":"","sources":["src/_crystals.ts"],"names":[],"mappings":"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"}
|
package/hybrid.d.ts
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
/**
|
2
|
+
* Post-Quantum Hybrid Cryptography
|
3
|
+
*
|
4
|
+
* The current implementation is flawed and likely redundant. We should offer
|
5
|
+
* a small, generic API to compose hybrid schemes instead of reimplementing
|
6
|
+
* protocol-specific logic (SSH, GPG, etc.) with ad hoc encodings.
|
7
|
+
*
|
8
|
+
* 1. Core Issues
|
9
|
+
* - sign/verify: implemented as two separate operations with different keys.
|
10
|
+
* - EC getSharedSecret: could be refactored into a proper KEM.
|
11
|
+
* - Multiple calls: keys, signatures, and shared secrets could be
|
12
|
+
* concatenated to reduce the number of API invocations.
|
13
|
+
* - Reinvention: most libraries add strange domain separations and
|
14
|
+
* encodings instead of simple byte concatenation.
|
15
|
+
*
|
16
|
+
* 2. API Goals
|
17
|
+
* - Provide primitives to build hybrids generically.
|
18
|
+
* - Avoid embedding SSH- or GPG-specific formats in the core API.
|
19
|
+
*
|
20
|
+
* 3. Edge Cases
|
21
|
+
* • Variable-length signatures:
|
22
|
+
* - DER-encoded (Weierstrass curves).
|
23
|
+
* - Falcon (unpadded).
|
24
|
+
* - Concatenation works only if length is fixed; otherwise a length
|
25
|
+
* prefix is required (but that breaks compatibility).
|
26
|
+
*
|
27
|
+
* • getSharedSecret:
|
28
|
+
* - Default: non-KEM (authenticated ECDH).
|
29
|
+
* - KEM conversion: generate a random SK to remove implicit auth.
|
30
|
+
*
|
31
|
+
* 4. Common Pitfalls
|
32
|
+
* - Seed expansion:
|
33
|
+
* • Expanding a small seed into multiple keys reduces entropy.
|
34
|
+
* • API should allow identity mapping (no expansion).
|
35
|
+
*
|
36
|
+
* - Skipping full point encoding:
|
37
|
+
* • Some omit the compression byte (parity) for WebCrypto compatibility.
|
38
|
+
* • Better: hash the raw secret; coordinate output is already non-uniform.
|
39
|
+
* • Some curves (e.g., X448) produce secrets that must be re-hashed to match
|
40
|
+
* symmetric-key lengths.
|
41
|
+
*
|
42
|
+
* - Combiner inconsistencies:
|
43
|
+
* • Different domain separations and encodings across libraries.
|
44
|
+
* • Should live at the application layer, since key lengths vary.
|
45
|
+
*
|
46
|
+
* 5. Protocol Examples
|
47
|
+
* - SSH:
|
48
|
+
* • Concatenate keys.
|
49
|
+
* • Combiner: SHA-512.
|
50
|
+
*
|
51
|
+
* - GPG:
|
52
|
+
* • Concatenate keys.
|
53
|
+
* • Combiner: SHA3-256(kemShare || ecdhShare || ciphertext || pubKey || algId || domSep || len(domSep))
|
54
|
+
*
|
55
|
+
* - TLS:
|
56
|
+
* • Transcript-based derivation (HKDF).
|
57
|
+
*
|
58
|
+
* 6. Relevant Specs & Implementations
|
59
|
+
* - IETF Hybrid KEM drafts:
|
60
|
+
* • draft-irtf-cfrg-hybrid-kems
|
61
|
+
* • draft-connolly-cfrg-xwing-kem
|
62
|
+
* • draft-westerbaan-tls-xyber768d00
|
63
|
+
*
|
64
|
+
* - PQC Libraries:
|
65
|
+
* • superdilithium (cyph/pqcrypto.js) – low adoption.
|
66
|
+
* • hybrid-pqc (DogeProtocol, quantumcoinproject) – complex encodings.
|
67
|
+
*
|
68
|
+
* 7. Signatures
|
69
|
+
* - Ed25519: fixed-size, easy to support.
|
70
|
+
* - Variable-size: introduces custom format requirements; best left to
|
71
|
+
* higher-level code.
|
72
|
+
*
|
73
|
+
* @module
|
74
|
+
*/
|
75
|
+
/*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */
|
76
|
+
import { type EdDSA } from '@noble/curves/abstract/edwards.js';
|
77
|
+
import { type MontgomeryECDH } from '@noble/curves/abstract/montgomery.js';
|
78
|
+
import { type ECDSA } from '@noble/curves/abstract/weierstrass.js';
|
79
|
+
import { type CHash, type CHashXOF } from '@noble/hashes/utils.js';
|
80
|
+
import { type KEM, type Signer } from './utils.ts';
|
81
|
+
type CurveECDH = ECDSA | MontgomeryECDH;
|
82
|
+
type CurveSign = ECDSA | EdDSA;
|
83
|
+
export declare const ecdhKem: (curve: CurveECDH, allowZeroKey?: boolean) => KEM;
|
84
|
+
export declare const ecSigner: (curve: CurveSign, allowZeroKey?: boolean) => Signer;
|
85
|
+
export type ExpandSeed = (seed: Uint8Array, len: number) => Uint8Array;
|
86
|
+
type XOF = CHashXOF<any, {
|
87
|
+
dkLen: number;
|
88
|
+
}>;
|
89
|
+
export declare function expandSeedXof(xof: XOF): ExpandSeed;
|
90
|
+
export type Combiner = (publicKeys: Uint8Array[], cipherTexts: Uint8Array[], sharedSecrets: Uint8Array[]) => Uint8Array;
|
91
|
+
export declare function combineKEMS(realSeedLen: number | undefined, // how much bytes expandSeed expects
|
92
|
+
realMsgLen: number | undefined, // how much bytes combiner returns
|
93
|
+
expandSeed: ExpandSeed, combiner: Combiner, ...kems: KEM[]): KEM;
|
94
|
+
export declare function combineSigners(realSeedLen: number | undefined, expandSeed: ExpandSeed, ...signers: Signer[]): Signer;
|
95
|
+
export declare function QSF(label: string, pqc: KEM, curveKEM: KEM, xof: XOF, kdf: CHash): KEM;
|
96
|
+
export declare const QSFMLKEM768P256: KEM;
|
97
|
+
export declare const QSFMLKEM1024P384: KEM;
|
98
|
+
export declare function KitchenSink(label: string, pqc: KEM, curveKEM: KEM, xof: XOF, hash: CHash): KEM;
|
99
|
+
export declare const KitchenSinkMLKEM768X25519: KEM;
|
100
|
+
export declare const XWing: KEM;
|
101
|
+
export {};
|
102
|
+
//# sourceMappingURL=hybrid.d.ts.map
|
package/hybrid.d.ts.map
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"hybrid.d.ts","sourceRoot":"","sources":["src/hybrid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,4EAA4E;AAC5E,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,uCAAuC,CAAC;AAanE,OAAO,EAA0B,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAE3F,OAAO,EAKL,KAAK,GAAG,EACR,KAAK,MAAM,EACZ,MAAM,YAAY,CAAC;AAGpB,KAAK,SAAS,GAAG,KAAK,GAAG,cAAc,CAAC;AACxC,KAAK,SAAS,GAAG,KAAK,GAAG,KAAK,CAAC;AAyB/B,eAAO,MAAM,OAAO,GAAI,OAAO,SAAS,EAAE,eAAc,OAAe,KAAG,GAmBzE,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,EAAE,eAAc,OAAe,KAAG,MAU1E,CAAC;AAcF,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,UAAU,CAAC;AACvE,KAAK,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAG5C,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,UAAU,CAElD;AAED,MAAM,MAAM,QAAQ,GAAG,CACrB,UAAU,EAAE,UAAU,EAAE,EACxB,WAAW,EAAE,UAAU,EAAE,EACzB,aAAa,EAAE,UAAU,EAAE,KACxB,UAAU,CAAC;AAsChB,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,oCAAoC;AACrE,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,kCAAkC;AAClE,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,QAAQ,EAClB,GAAG,IAAI,EAAE,GAAG,EAAE,GACb,GAAG,CAoCL;AAGD,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,UAAU,EAAE,UAAU,EACtB,GAAG,OAAO,EAAE,MAAM,EAAE,GACnB,MAAM,CAwBR;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,CAWrF;AAED,eAAO,MAAM,eAAe,EAAE,GAM7B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,GAM9B,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,GAAG,GAAG,CAwB9F;AAGD,eAAO,MAAM,yBAAyB,EAAE,GAMvC,CAAC;AAGF,eAAO,MAAM,KAAK,EAAE,GAQnB,CAAC"}
|