@unknownncat/curve25519-node 2.1.0 → 2.1.2
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 +1 -1
- package/NOTICE.md +6 -6
- package/README.en.md +34 -391
- package/README.md +35 -392
- package/SECURITY.md +11 -0
- package/dist/axlsign.d.ts +1 -1
- package/dist/axlsign.d.ts.map +1 -1
- package/dist/axlsign.js +8 -29
- package/dist/axlsign.js.map +1 -1
- package/dist/cjs/axlsign.js +8 -29
- package/dist/cjs/axlsign.js.map +1 -1
- package/dist/cjs/index.js +2 -11
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/assert.js +1 -1
- package/dist/cjs/internal/assert.js.map +1 -1
- package/dist/cjs/internal/axlsign-wasm/LICENSE +1 -1
- package/dist/cjs/internal/axlsign-wasm/axlsign_wasm.js +129 -65
- package/dist/cjs/internal/axlsign-wasm/axlsign_wasm_bg.wasm +0 -0
- package/dist/cjs/internal/axlsign-wasm/axlsign_wasm_bg.wasm.d.ts +8 -10
- package/dist/index.d.ts +1 -59
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -10
- package/dist/index.js.map +1 -1
- package/dist/internal/assert.js +1 -1
- package/dist/internal/assert.js.map +1 -1
- package/dist/internal/axlsign-wasm/LICENSE +1 -1
- package/dist/internal/axlsign-wasm/axlsign_wasm.js +129 -65
- package/dist/internal/axlsign-wasm/axlsign_wasm_bg.wasm +0 -0
- package/dist/internal/axlsign-wasm/axlsign_wasm_bg.wasm.d.ts +8 -10
- package/package.json +12 -25
- package/dist/cjs/internal/curve25519-wasm/LICENSE +0 -21
- package/dist/cjs/internal/curve25519-wasm/curve25519_wasm.d.ts +0 -12
- package/dist/cjs/internal/curve25519-wasm/curve25519_wasm.js +0 -165
- package/dist/cjs/internal/curve25519-wasm/curve25519_wasm_bg.wasm +0 -0
- package/dist/cjs/internal/curve25519-wasm/curve25519_wasm_bg.wasm.d.ts +0 -13
- package/dist/cjs/internal/curve25519-wasm/package.json +0 -17
- package/dist/cjs/wasm.js +0 -228
- package/dist/cjs/wasm.js.map +0 -1
- package/dist/internal/curve25519-wasm/LICENSE +0 -21
- package/dist/internal/curve25519-wasm/curve25519_wasm.d.ts +0 -12
- package/dist/internal/curve25519-wasm/curve25519_wasm.js +0 -165
- package/dist/internal/curve25519-wasm/curve25519_wasm_bg.wasm +0 -0
- package/dist/internal/curve25519-wasm/curve25519_wasm_bg.wasm.d.ts +0 -13
- package/dist/internal/curve25519-wasm/package.json +0 -17
- package/dist/wasm.d.ts +0 -92
- package/dist/wasm.d.ts.map +0 -1
- package/dist/wasm.js +0 -204
- package/dist/wasm.js.map +0 -1
package/LICENSE
CHANGED
package/NOTICE.md
CHANGED
|
@@ -19,12 +19,12 @@ Repository: <https://github.com/unknownncat/curve25519-node>
|
|
|
19
19
|
- OpenSSL (used through Node.js `node:crypto`) — Apache-2.0
|
|
20
20
|
<https://www.openssl.org/>
|
|
21
21
|
|
|
22
|
-
## Rust
|
|
22
|
+
## Rust dependency notices
|
|
23
23
|
|
|
24
|
-
The project contains
|
|
24
|
+
The project contains Rust crates for WASM:
|
|
25
25
|
|
|
26
|
-
- `
|
|
27
|
-
- `
|
|
26
|
+
- `rust/crates/curve-wasm`
|
|
27
|
+
- `rust/crates/axlsign-wasm`
|
|
28
28
|
|
|
29
29
|
License inventory was collected with:
|
|
30
30
|
|
|
@@ -69,7 +69,7 @@ cargo license -t
|
|
|
69
69
|
| wasm-bindgen-shared | Apache-2.0 OR MIT |
|
|
70
70
|
| x25519-dalek | BSD-3-Clause |
|
|
71
71
|
|
|
72
|
-
### Crates present only in `
|
|
72
|
+
### Crates present only in `rust/crates/axlsign-wasm`
|
|
73
73
|
|
|
74
74
|
| Crate | License |
|
|
75
75
|
| ------- | ----------------- |
|
|
@@ -86,4 +86,4 @@ cargo license -t
|
|
|
86
86
|
|
|
87
87
|
- Upstream licenses remain with their respective authors and projects.
|
|
88
88
|
- This NOTICE summarizes dependencies and does not replace upstream license texts.
|
|
89
|
-
- For full build/runtime details, see `README.md`, `README.en.md`, and
|
|
89
|
+
- For full build/runtime details, see `README.md`, `README.en.md`, and `../../rust/README.md`.
|
package/README.en.md
CHANGED
|
@@ -1,26 +1,13 @@
|
|
|
1
1
|
# @unknownncat/curve25519-node
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Portuguese version: [README.md](./README.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Node.js implementation with a clean API:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
[](https://www.npmjs.com/package/@unknownncat/curve25519-node)
|
|
12
|
-
[](https://nodejs.org/)
|
|
13
|
-
[](./dist/index.d.ts)
|
|
14
|
-

|
|
15
|
-

|
|
16
|
-
[](./LICENSE)
|
|
17
|
-
|
|
18
|
-
- Node: `>= 20`
|
|
19
|
-
- Runtime dependencies: `0`
|
|
20
|
-
- TypeScript: `strict`
|
|
21
|
-
- Module formats: ESM + CJS
|
|
22
|
-
|
|
23
|
-
---
|
|
7
|
+
- `x25519` and `ed25519` via `node:crypto` (OpenSSL)
|
|
8
|
+
- legacy-compatible `axlsign` accelerated by an internal Rust/WASM backend
|
|
9
|
+
- no `wasm` namespace
|
|
10
|
+
- no `napi` namespace
|
|
24
11
|
|
|
25
12
|
## Install
|
|
26
13
|
|
|
@@ -28,395 +15,51 @@ Zero-runtime-dependency implementation of:
|
|
|
28
15
|
npm i @unknownncat/curve25519-node
|
|
29
16
|
```
|
|
30
17
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
## Quick Usage
|
|
18
|
+
## Quick usage
|
|
34
19
|
|
|
35
20
|
```ts
|
|
36
21
|
import { randomBytes } from "node:crypto";
|
|
37
|
-
import { asBytes32, x25519, ed25519 } from "@unknownncat/curve25519-node";
|
|
22
|
+
import { asBytes32, x25519, ed25519, axlsign } from "@unknownncat/curve25519-node";
|
|
38
23
|
|
|
39
|
-
const
|
|
40
|
-
const
|
|
24
|
+
const seedA = asBytes32(randomBytes(32));
|
|
25
|
+
const seedB = asBytes32(randomBytes(32));
|
|
41
26
|
|
|
42
|
-
const
|
|
43
|
-
const
|
|
27
|
+
const alice = x25519.generateKeyPair(seedA);
|
|
28
|
+
const bob = x25519.generateKeyPair(seedB);
|
|
29
|
+
const shared = x25519.sharedKey(alice.private, bob.public);
|
|
44
30
|
|
|
45
|
-
const secret1 = x25519.sharedKey(aliceX.private, bobX.public);
|
|
46
|
-
const secret2 = x25519.sharedKey(bobX.private, aliceX.public);
|
|
47
|
-
// secret1 === secret2
|
|
48
|
-
|
|
49
|
-
const signerSeed = asBytes32(randomBytes(32));
|
|
50
|
-
const signer = ed25519.generateKeyPair(signerSeed);
|
|
51
31
|
const msg = new TextEncoder().encode("hello");
|
|
32
|
+
const sig = ed25519.sign(seedA, msg);
|
|
33
|
+
const ok = ed25519.verify(ed25519.publicKey(seedA), msg, sig);
|
|
52
34
|
|
|
53
|
-
const
|
|
54
|
-
const
|
|
35
|
+
const axlSig = axlsign.sign(alice.private, msg, randomBytes(64));
|
|
36
|
+
const axlOk = axlsign.verify(alice.public, msg, axlSig);
|
|
55
37
|
```
|
|
56
38
|
|
|
57
39
|
CommonJS:
|
|
58
40
|
|
|
59
41
|
```js
|
|
60
|
-
const { x25519, ed25519,
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Legacy axlsign via WASM:
|
|
64
|
-
|
|
65
|
-
```ts
|
|
66
|
-
import { asBytes32, axlsign } from "@unknownncat/curve25519-node";
|
|
67
|
-
|
|
68
|
-
const seed = asBytes32(new Uint8Array(32));
|
|
69
|
-
const kp = axlsign.generateKeyPair(seed); // curve25519-js-compatible X25519 keypair
|
|
70
|
-
const sig = axlsign.sign(kp.private, new TextEncoder().encode("hello"), new Uint8Array(64));
|
|
71
|
-
const ok = axlsign.verify(kp.public, new TextEncoder().encode("hello"), sig);
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Modern WASM mode (`wasm`):
|
|
75
|
-
|
|
76
|
-
```ts
|
|
77
|
-
import { asBytes32, wasm } from "@unknownncat/curve25519-node";
|
|
78
|
-
|
|
79
|
-
const seed = asBytes32(new Uint8Array(32));
|
|
80
|
-
const kp = wasm.x25519.generateKeyPair(seed);
|
|
81
|
-
const shared = wasm.x25519.sharedKey(kp.private, kp.public);
|
|
82
|
-
|
|
83
|
-
const msg = new TextEncoder().encode("hello");
|
|
84
|
-
const sig = wasm.ed25519.sign(seed, msg);
|
|
85
|
-
const ok = wasm.ed25519.verify(wasm.ed25519.publicKey(seed), msg, sig);
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## API
|
|
91
|
-
|
|
92
|
-
### `x25519`
|
|
93
|
-
|
|
94
|
-
- `createPrivateKeyObject(secretKey32: Bytes32): KeyObject`
|
|
95
|
-
- `createPublicKeyObject(publicKey32: Bytes32): KeyObject`
|
|
96
|
-
- `publicKeyFromPrivateKeyObject(privateKey: KeyObject): Bytes32`
|
|
97
|
-
- `publicKey(secretKey32: Bytes32): Bytes32`
|
|
98
|
-
- `sharedKeyFromKeyObjects(privateKey: KeyObject, publicKey: KeyObject): Bytes32`
|
|
99
|
-
- `sharedKey(secretKey32: Bytes32, publicKey32: Bytes32): Bytes32`
|
|
100
|
-
- `sharedKeyStrict(secretKey32: Bytes32, publicKey32: Bytes32): Bytes32` (rejects all-zero shared secret)
|
|
101
|
-
- `sharedKeyStrictFromKeyObjects(privateKey: KeyObject, publicKey: KeyObject): Bytes32` (rejects all-zero shared secret)
|
|
102
|
-
- `isAllZero32(bytes32: Bytes32): boolean`
|
|
103
|
-
- `generateKeyPair(seed32: Bytes32): { public: Bytes32; private: Bytes32 }`
|
|
104
|
-
|
|
105
|
-
### `ed25519`
|
|
106
|
-
|
|
107
|
-
- `createPrivateKeyObject(secretSeed32: Bytes32): KeyObject`
|
|
108
|
-
- `createPublicKeyObject(publicKey32: Bytes32): KeyObject`
|
|
109
|
-
- `publicKeyFromPrivateKeyObject(privateKey: KeyObject): Bytes32`
|
|
110
|
-
- `publicKey(secretSeed32: Bytes32): Bytes32`
|
|
111
|
-
- `generateKeyPair(seed32: Bytes32): { public: Bytes32; private: Bytes32 }`
|
|
112
|
-
- `sign(secretSeed32: Bytes32, msg: Uint8Array): Bytes64`
|
|
113
|
-
- `signWithPrivateKey(privateKey: KeyObject, msg: Uint8Array): Bytes64`
|
|
114
|
-
- `verify(publicKey32: Bytes32, msg: Uint8Array, signature64: Bytes64): boolean`
|
|
115
|
-
- `verifyWithPublicKey(publicKey: KeyObject, msg: Uint8Array, signature64: Bytes64): boolean`
|
|
116
|
-
- `signMessage(secretSeed32: Bytes32, msg: Uint8Array): Uint8Array` (`signature || message`)
|
|
117
|
-
- `openMessage(publicKey32: Bytes32, signedMsg: Uint8Array): Uint8Array | null`
|
|
118
|
-
|
|
119
|
-
### `axlsign` (legacy compatibility via WASM)
|
|
120
|
-
|
|
121
|
-
- `publicKey(secretKey32: Bytes32): Bytes32`
|
|
122
|
-
- `sharedKey(secretKey32: Bytes32, publicKey32: Bytes32): Bytes32`
|
|
123
|
-
- `generateKeyPair(seed32: Bytes32): { public: Bytes32; private: Bytes32 }`
|
|
124
|
-
- `sign(secretKey32: Bytes32, msg: Uint8Array, opt_random?: Bytes64): Bytes64`
|
|
125
|
-
- `verify(publicKey32: Bytes32, msg: Uint8Array, signature64: Bytes64): boolean`
|
|
126
|
-
- `signMessage(secretKey32: Bytes32, msg: Uint8Array, opt_random?: Bytes64): Uint8Array`
|
|
127
|
-
- `openMessage(publicKey32: Bytes32, signedMsg: Uint8Array): Uint8Array | null`
|
|
128
|
-
|
|
129
|
-
### `wasm` (optional modern mode via WASM)
|
|
130
|
-
|
|
131
|
-
`wasm.x25519`:
|
|
132
|
-
|
|
133
|
-
- `createPrivateKeyObject(secretKey32: Bytes32): WasmX25519PrivateKeyObject`
|
|
134
|
-
- `createPublicKeyObject(publicKey32: Bytes32): WasmX25519PublicKeyObject`
|
|
135
|
-
- `publicKeyFromPrivateKeyObject(privateKey: WasmX25519PrivateKeyObject): Bytes32`
|
|
136
|
-
- `publicKey(secretKey32: Bytes32): Bytes32`
|
|
137
|
-
- `sharedKeyFromKeyObjects(privateKey: WasmX25519PrivateKeyObject, publicKey: WasmX25519PublicKeyObject): Bytes32`
|
|
138
|
-
- `sharedKey(secretKey32: Bytes32, publicKey32: Bytes32): Bytes32`
|
|
139
|
-
- `sharedKeyStrict(secretKey32: Bytes32, publicKey32: Bytes32): Bytes32`
|
|
140
|
-
- `sharedKeyStrictFromKeyObjects(privateKey: WasmX25519PrivateKeyObject, publicKey: WasmX25519PublicKeyObject): Bytes32`
|
|
141
|
-
- `isAllZero32(bytes32: Bytes32): boolean`
|
|
142
|
-
- `generateKeyPair(seed32: Bytes32): { public: Bytes32; private: Bytes32 }`
|
|
143
|
-
|
|
144
|
-
`wasm.ed25519`:
|
|
145
|
-
|
|
146
|
-
- `createPrivateKeyObject(secretSeed32: Bytes32): WasmEd25519PrivateKeyObject`
|
|
147
|
-
- `createPublicKeyObject(publicKey32: Bytes32): WasmEd25519PublicKeyObject`
|
|
148
|
-
- `publicKeyFromPrivateKeyObject(privateKey: WasmEd25519PrivateKeyObject): Bytes32`
|
|
149
|
-
- `publicKey(secretSeed32: Bytes32): Bytes32`
|
|
150
|
-
- `generateKeyPair(seed32: Bytes32): { public: Bytes32; private: Bytes32 }`
|
|
151
|
-
- `sign(secretSeed32: Bytes32, msg: Uint8Array): Bytes64`
|
|
152
|
-
- `signWithPrivateKey(privateKey: WasmEd25519PrivateKeyObject, msg: Uint8Array): Bytes64`
|
|
153
|
-
- `verify(publicKey32: Bytes32, msg: Uint8Array, signature64: Bytes64): boolean`
|
|
154
|
-
- `verifyWithPublicKey(publicKey: WasmEd25519PublicKeyObject, msg: Uint8Array, signature64: Bytes64): boolean`
|
|
155
|
-
- `signMessage(secretSeed32: Bytes32, msg: Uint8Array): Uint8Array`
|
|
156
|
-
- `openMessage(publicKey32: Bytes32, signedMsg: Uint8Array): Uint8Array | null`
|
|
157
|
-
|
|
158
|
-
### Top-level compatibility aliases
|
|
159
|
-
|
|
160
|
-
- `sharedKey = x25519.sharedKey`
|
|
161
|
-
- `sharedKeyStrict = x25519.sharedKeyStrict`
|
|
162
|
-
- `generateKeyPair = x25519.generateKeyPair`
|
|
163
|
-
- `sign`, `verify`, `signMessage`, `openMessage` (Ed25519 semantics)
|
|
164
|
-
- `generateKeyPairX25519`, `generateKeyPairEd25519`
|
|
165
|
-
|
|
166
|
-
---
|
|
167
|
-
|
|
168
|
-
## Compatibility Notes
|
|
169
|
-
|
|
170
|
-
This package provides three modes:
|
|
171
|
-
|
|
172
|
-
- **modern native (recommended):** `x25519` + `ed25519` via `node:crypto`
|
|
173
|
-
- **modern WASM (optional):** `wasm` namespace (`wasm.x25519` + `wasm.ed25519`)
|
|
174
|
-
- **legacy:** `axlsign` via WASM for `curve25519-js` compatibility
|
|
175
|
-
|
|
176
|
-
| Feature | `curve25519-js` | `curve25519-node` |
|
|
177
|
-
| -------------------------------- | --------------- | ------------------------------------------- |
|
|
178
|
-
| Signature scheme (modern) | axlsign | Ed25519 (standard) |
|
|
179
|
-
| Alternative modern scheme | no | Ed25519 via WASM (`wasm.ed25519`) |
|
|
180
|
-
| Signature scheme (legacy) | axlsign | axlsign (namespace `axlsign`) |
|
|
181
|
-
| Key agreement | X25519 | X25519 |
|
|
182
|
-
| Alternative modern key agreement | no | X25519 via WASM (`wasm.x25519`) |
|
|
183
|
-
| Same key for signing + ECDH | yes | only in `axlsign` namespace |
|
|
184
|
-
| `opt_random` in signing APIs | yes | yes in `axlsign`, no in top-level/`ed25519` |
|
|
185
|
-
| OpenSSL backend | no | yes |
|
|
186
|
-
|
|
187
|
-
Important:
|
|
188
|
-
|
|
189
|
-
- X25519 public keys and Ed25519 public keys are different.
|
|
190
|
-
- For stricter protocol flows (Signal-like), prefer `sharedKeyStrict` to reject all-zero shared secrets.
|
|
191
|
-
- `node:crypto` does not expose an API to convert X25519 public keys to/from Ed25519 public keys.
|
|
192
|
-
- Top-level `sign`/`signMessage` and `ed25519` keep Ed25519 semantics and reject `opt_random`.
|
|
193
|
-
- For `curve25519-js` compatibility (including `opt_random`), use namespace `axlsign`.
|
|
194
|
-
- Ed25519 signatures here are deterministic (OpenSSL default behavior).
|
|
195
|
-
- WASM modules (`axlsign` and `wasm`) are lazy-loaded on first call (importing only `x25519`/`ed25519` does not initialize WASM).
|
|
196
|
-
|
|
197
|
-
---
|
|
198
|
-
|
|
199
|
-
## Why This Exists
|
|
200
|
-
|
|
201
|
-
`curve25519-js` is an important project, but it relies on manual finite-field arithmetic in JS (`Float64Array`, TweetNaCl style internals).
|
|
202
|
-
|
|
203
|
-
This package targets modern Node using OpenSSL primitives:
|
|
204
|
-
|
|
205
|
-
- safer implementation path by default
|
|
206
|
-
- better performance on Node >= 20
|
|
207
|
-
- smaller, explicit API surface
|
|
208
|
-
- strong typing with zero runtime dependencies
|
|
209
|
-
|
|
210
|
-
In addition:
|
|
211
|
-
|
|
212
|
-
- WASM `axlsign` enables progressive migration of legacy code.
|
|
213
|
-
- WASM `wasm` provides a modern backend option without relying on `node:crypto` in the crypto execution path.
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
## Branded Types
|
|
218
|
-
|
|
219
|
-
- `Bytes32`
|
|
220
|
-
- `Bytes64`
|
|
221
|
-
|
|
222
|
-
Validation helpers (no copy):
|
|
223
|
-
|
|
224
|
-
- `asBytes32(u8)`
|
|
225
|
-
- `asBytes64(u8)`
|
|
226
|
-
|
|
227
|
-
---
|
|
228
|
-
|
|
229
|
-
## RFC Map (what this project uses)
|
|
230
|
-
|
|
231
|
-
| RFC | Sections used | How it is used | Where in code |
|
|
232
|
-
| --------------------------------- | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- | ----------------------- |
|
|
233
|
-
| RFC 7748 (X25519) | Section 5 (`The X25519 and X448 Functions`) | Scalar decoding/clamping and X25519 behavior (clear low 3 bits, clear top bit, set second-top bit). | `src/x25519.ts` |
|
|
234
|
-
| RFC 7748 (X25519) | Section 5.2 (`Test Vectors`), Section 6.1 (`Diffie-Hellman / Curve25519`) | Official vectors for interoperability and correctness checks. | `test/x25519.test.mjs` |
|
|
235
|
-
| RFC 8032 (Ed25519) | Section 5.1.5 (`Key Generation`), 5.1.6 (`Sign`), 5.1.7 (`Verify`) | Ed25519 keygen/sign/verify semantics (performed by OpenSSL via `node:crypto`). | `src/ed25519.ts` |
|
|
236
|
-
| RFC 8032 (Ed25519) | Section 7.1 (`Test Vectors for Ed25519`) | Deterministic vector checks for public key and signature correctness. | `test/ed25519.test.mjs` |
|
|
237
|
-
| RFC 8410 (X25519/Ed25519 in PKIX) | Section 3 (algorithm identifiers), Section 4 (`Subject Public Key Fields`), Section 7 (`Private Key Format`) | DER layout for raw 32-byte key import/export to SPKI/PKCS#8 with X25519/Ed25519 OIDs. | `src/internal/der.ts` |
|
|
238
|
-
|
|
239
|
-
Indirect references via RFC 8410 structures:
|
|
240
|
-
|
|
241
|
-
- RFC 5958 (OneAsymmetricKey / PKCS#8 family)
|
|
242
|
-
- RFC 5280 Section 4.1.2.7 (`Subject Public Key Info`)
|
|
243
|
-
|
|
244
|
-
Notes:
|
|
245
|
-
|
|
246
|
-
- This project does not reimplement curve arithmetic in JS; cryptographic operations are delegated to OpenSSL via `node:crypto`.
|
|
247
|
-
- Tests include official vectors from RFC 7748 and RFC 8032.
|
|
248
|
-
|
|
249
|
-
Run tests:
|
|
250
|
-
|
|
251
|
-
```bash
|
|
252
|
-
npm test
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
---
|
|
256
|
-
|
|
257
|
-
## Technical Details (DER / RFC 8410)
|
|
258
|
-
|
|
259
|
-
Raw 32-byte keys are imported/exported using fixed DER prefixes:
|
|
260
|
-
|
|
261
|
-
- X25519 PKCS#8: `302e020100300506032b656e04220420`
|
|
262
|
-
- X25519 SPKI: `302a300506032b656e032100`
|
|
263
|
-
- Ed25519 PKCS#8: `302e020100300506032b657004220420`
|
|
264
|
-
- Ed25519 SPKI: `302a300506032b6570032100`
|
|
265
|
-
|
|
266
|
-
Implementation notes:
|
|
267
|
-
|
|
268
|
-
- preallocated buffers + `.set`
|
|
269
|
-
- zero-copy `Uint8Array` views when safe
|
|
270
|
-
- no `Buffer.concat` in hot paths
|
|
271
|
-
|
|
272
|
-
---
|
|
273
|
-
|
|
274
|
-
## Performance Notes
|
|
275
|
-
|
|
276
|
-
- Avoids unnecessary byte copies in critical paths.
|
|
277
|
-
- `signMessage` builds `signature || message` with a single preallocated `Uint8Array`.
|
|
278
|
-
- For high-throughput loops, use `KeyObject` helpers (`create*KeyObject`, `*FromKeyObjects`) to reduce ASN.1 parse overhead.
|
|
279
|
-
|
|
280
|
-
---
|
|
281
|
-
|
|
282
|
-
## Security Notes
|
|
283
|
-
|
|
284
|
-
- strict type/length validation on public APIs
|
|
285
|
-
- no secret logging
|
|
286
|
-
- `timingSafeEqual` for internal fixed-size comparisons where needed
|
|
287
|
-
|
|
288
|
-
---
|
|
289
|
-
|
|
290
|
-
## Benchmarks
|
|
291
|
-
|
|
292
|
-
Benchmark suite is isolated in `bench/` (separate subproject) and compares against `curve25519-js`.
|
|
293
|
-
|
|
294
|
-
```bash
|
|
295
|
-
npm run build
|
|
296
|
-
cd bench
|
|
297
|
-
npm install
|
|
298
|
-
npm run bench
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### Real benchmark snapshot (`npm run bench:ci`) on GitHub Codespaces
|
|
302
|
-
|
|
303
|
-
Command:
|
|
304
|
-
|
|
305
|
-
```bash
|
|
306
|
-
node --expose-gc bench.mjs --rounds=16 --roundMs=350 --warmupMs=500 --vectors=64 --variants=raw,cached --strict --verifyEvery=64 --jsonFile=results/bench-results.json
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
Environment:
|
|
310
|
-
|
|
311
|
-
- Node: `v24.11.1`
|
|
312
|
-
- OpenSSL: `3.5.4`
|
|
313
|
-
- CPU: `AMD EPYC 7763 64-Core Processor`
|
|
314
|
-
- Logical cores: `4`
|
|
315
|
-
- Vectors: `64`
|
|
316
|
-
|
|
317
|
-
### Table 1 - Modern API (`x25519` + `ed25519`)
|
|
318
|
-
|
|
319
|
-
`sign`/`verify` rows below compare API throughput, not cryptographic equivalence (Ed25519 vs legacy axlsign).
|
|
320
|
-
|
|
321
|
-
| Operation | Modern raw | Legacy raw (`curve25519-js`) | Raw speedup | Modern cached | Legacy cached (`curve25519-js`) | Cached speedup |
|
|
322
|
-
| ------------------------------ | ---------: | ---------------------------: | ----------: | ------------: | ------------------------------: | -------------: |
|
|
323
|
-
| `x25519.generateKeyPair` | 14,378 | 1,591 | 9.04x | 41,120 | 1,478 | 27.83x |
|
|
324
|
-
| `x25519.sharedKey` | 9,970 | 1,591 | 6.27x | 23,995 | 1,554 | 15.44x |
|
|
325
|
-
| `ed25519.sign (msg32)` | 11,273 | 143 | 78.95x | 23,696 | 133 | 178.10x |
|
|
326
|
-
| `ed25519.sign (msg1024)` | 10,800 | 138 | 78.07x | 22,502 | 147 | 152.92x |
|
|
327
|
-
| `ed25519.verify (msg32)` | 7,280 | 136 | 53.36x | 8,271 | 155 | 53.37x |
|
|
328
|
-
| `ed25519.verify (msg1024)` | 7,160 | 132 | 54.33x | 8,159 | 154 | 52.90x |
|
|
329
|
-
| `ed25519.signMessage (msg256)` | 10,624 | 131 | 81.09x | 23,304 | 148 | 156.97x |
|
|
330
|
-
| `ed25519.openMessage (msg256)` | 6,574 | 124 | 52.93x | 8,129 | 154 | 52.64x |
|
|
331
|
-
|
|
332
|
-
### Table 2 - `axlsign` compatibility mode (equivalent to `curve25519-js`)
|
|
333
|
-
|
|
334
|
-
This table compares the same cryptographic scheme (equivalence + throughput).
|
|
335
|
-
|
|
336
|
-
| Operation | Modern raw | Legacy raw (`curve25519-js`) | Raw speedup | Modern cached | Legacy cached (`curve25519-js`) | Cached speedup |
|
|
337
|
-
| ----------------------------------------- | ---------: | ---------------------------: | ----------: | ------------: | ------------------------------: | -------------: |
|
|
338
|
-
| `axlsign.generateKeyPair` | 8,429 | 1,583 | 5.33x | 8,384 | 1,585 | 5.29x |
|
|
339
|
-
| `axlsign.sharedKey` | 8,452 | 1,583 | 5.34x | 8,396 | 1,570 | 5.35x |
|
|
340
|
-
| `axlsign.sign (msg32)` | 3,973 | 144 | 27.61x | 3,952 | 140 | 28.28x |
|
|
341
|
-
| `axlsign.sign (msg32,opt_random)` | 3,969 | 147 | 27.03x | 3,984 | 139 | 28.58x |
|
|
342
|
-
| `axlsign.sign (msg1024)` | 3,881 | 143 | 27.16x | 3,864 | 139 | 27.72x |
|
|
343
|
-
| `axlsign.verify (msg32)` | 6,527 | 146 | 44.70x | 6,534 | 143 | 45.72x |
|
|
344
|
-
| `axlsign.verify (msg32,opt_random)` | 6,506 | 144 | 45.07x | 6,469 | 141 | 45.80x |
|
|
345
|
-
| `axlsign.verify (msg1024)` | 6,361 | 141 | 45.03x | 6,337 | 135 | 46.92x |
|
|
346
|
-
| `axlsign.signMessage (msg256)` | 3,902 | 140 | 27.79x | 3,935 | 141 | 27.98x |
|
|
347
|
-
| `axlsign.signMessage (msg256,opt_random)` | 3,885 | 142 | 27.40x | 3,864 | 145 | 26.60x |
|
|
348
|
-
| `axlsign.openMessage (msg256)` | 6,441 | 138 | 46.57x | 6,300 | 131 | 47.93x |
|
|
349
|
-
| `axlsign.openMessage (msg256,opt_random)` | 6,362 | 141 | 45.24x | 6,285 | 130 | 48.22x |
|
|
350
|
-
|
|
351
|
-
Notes:
|
|
352
|
-
|
|
353
|
-
- `raw` includes end-to-end API cost.
|
|
354
|
-
- `cached` reduces setup overhead to better expose cryptographic throughput.
|
|
355
|
-
- Numbers are sourced from the `bench:ci` JSON output (`results/bench-results.json`).
|
|
356
|
-
|
|
357
|
-
---
|
|
358
|
-
|
|
359
|
-
## Building WASM namespaces (`axlsign` and `wasm`)
|
|
360
|
-
|
|
361
|
-
In the npm package, WASM artifacts are already prebuilt under `dist/`.
|
|
362
|
-
|
|
363
|
-
To build from source, you need:
|
|
364
|
-
|
|
365
|
-
- Rust toolchain
|
|
366
|
-
- `wasm-pack` installed
|
|
367
|
-
|
|
368
|
-
Then `npm run build` runs:
|
|
369
|
-
|
|
370
|
-
1. `wasm-pack build` (`wasm/axlsign`)
|
|
371
|
-
2. `wasm-pack build` (`wasm/curve25519-wasm`)
|
|
372
|
-
3. TypeScript ESM + CJS build
|
|
373
|
-
4. copy of WASM artifacts to `dist/internal/axlsign-wasm` and `dist/internal/curve25519-wasm`
|
|
374
|
-
|
|
375
|
-
Rust crates reference: [wasm/README.md](./wasm/README.md)
|
|
376
|
-
|
|
377
|
-
---
|
|
378
|
-
|
|
379
|
-
## Contributing
|
|
380
|
-
|
|
381
|
-
- Guide: [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
382
|
-
- Code of conduct: [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md)
|
|
383
|
-
- Security: [SECURITY.md](./SECURITY.md)
|
|
384
|
-
|
|
385
|
-
Full local validation:
|
|
386
|
-
|
|
387
|
-
```bash
|
|
388
|
-
npm run ci
|
|
42
|
+
const { x25519, ed25519, axlsign } = require("@unknownncat/curve25519-node");
|
|
389
43
|
```
|
|
390
44
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
## License
|
|
394
|
-
|
|
395
|
-
MIT
|
|
45
|
+
## Exports
|
|
396
46
|
|
|
397
|
-
|
|
47
|
+
- `x25519`
|
|
48
|
+
- `ed25519`
|
|
49
|
+
- `axlsign`
|
|
50
|
+
- top-level aliases: `sharedKey`, `sharedKeyStrict`, `generateKeyPair`, `sign`, `verify`, `signMessage`, `openMessage`
|
|
51
|
+
- types/helpers: `Bytes32`, `Bytes64`, `asBytes32`, `asBytes64`
|
|
398
52
|
|
|
399
|
-
|
|
400
|
-
- [THIRD_PARTY_NOTICE.md](./THIRD_PARTY_NOTICE.md) and [THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md) (compatibility aliases)
|
|
401
|
-
- [SECURITY.md](./SECURITY.md) (security policy and vulnerability reporting)
|
|
53
|
+
## Notes
|
|
402
54
|
|
|
403
|
-
|
|
55
|
+
- Top-level `sign`/`verify` keep Ed25519 semantics and reject `opt_random`.
|
|
56
|
+
- For legacy compatibility with `curve25519-js`, use `axlsign.*`.
|
|
57
|
+
- For browser WASM runtime, use `@unknownncat/curve25519-browser`.
|
|
404
58
|
|
|
405
|
-
##
|
|
59
|
+
## License and notices
|
|
406
60
|
|
|
407
|
-
- [
|
|
408
|
-
- [
|
|
409
|
-
-
|
|
410
|
-
- [
|
|
411
|
-
- [
|
|
412
|
-
- [RustCrypto](https://github.com/RustCrypto)
|
|
413
|
-
- [wasm-bindgen](https://github.com/wasm-bindgen/wasm-bindgen)
|
|
414
|
-
- [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek)
|
|
415
|
-
- [ed25519-dalek](https://github.com/dalek-cryptography/ed25519-dalek)
|
|
416
|
-
- [x25519-dalek](https://github.com/dalek-cryptography/x25519-dalek)
|
|
417
|
-
- [zeroize](https://github.com/RustCrypto/utils/tree/master/zeroize)
|
|
418
|
-
- [RFC 7748](https://www.rfc-editor.org/rfc/rfc7748)
|
|
419
|
-
- [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032)
|
|
420
|
-
- [RFC 8410](https://www.rfc-editor.org/rfc/rfc8410)
|
|
421
|
-
- [RFC 5958](https://www.rfc-editor.org/rfc/rfc5958)
|
|
422
|
-
- [RFC 5280](https://www.rfc-editor.org/rfc/rfc5280)
|
|
61
|
+
- [LICENSE](./LICENSE)
|
|
62
|
+
- [NOTICE.md](./NOTICE.md)
|
|
63
|
+
- [THIRD_PARTY_NOTICE.md](./THIRD_PARTY_NOTICE.md)
|
|
64
|
+
- [THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md)
|
|
65
|
+
- [SECURITY.md](./SECURITY.md)
|