@unknownncat/curve25519-node 1.0.0 → 2.0.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.en.md +332 -0
- package/README.md +232 -110
- package/dist/axlsign.d.ts +31 -0
- package/dist/axlsign.d.ts.map +1 -0
- package/dist/axlsign.js +96 -0
- package/dist/axlsign.js.map +1 -0
- package/dist/cjs/axlsign.js +105 -0
- package/dist/cjs/axlsign.js.map +1 -0
- package/dist/cjs/index.js +15 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/axlsign-wasm/LICENSE +21 -0
- package/dist/cjs/internal/axlsign-wasm/axlsign_wasm.d.ts +12 -0
- package/dist/cjs/internal/axlsign-wasm/axlsign_wasm.js +171 -0
- package/dist/cjs/internal/axlsign-wasm/axlsign_wasm_bg.wasm +0 -0
- package/dist/cjs/internal/axlsign-wasm/axlsign_wasm_bg.wasm.d.ts +13 -0
- package/dist/cjs/internal/axlsign-wasm/package.json +17 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/axlsign-wasm/LICENSE +21 -0
- package/dist/internal/axlsign-wasm/axlsign_wasm.d.ts +12 -0
- package/dist/internal/axlsign-wasm/axlsign_wasm.js +171 -0
- package/dist/internal/axlsign-wasm/axlsign_wasm_bg.wasm +0 -0
- package/dist/internal/axlsign-wasm/axlsign_wasm_bg.wasm.d.ts +13 -0
- package/dist/internal/axlsign-wasm/package.json +17 -0
- package/package.json +14 -2
package/README.md
CHANGED
|
@@ -1,54 +1,27 @@
|
|
|
1
1
|
# @unknownncat/curve25519-node
|
|
2
2
|
|
|
3
|
-
[
|
|
4
|
-
[](https://www.npmjs.com/package/@unknownncat/curve25519-node)
|
|
5
|
-
[](./dist/index.d.ts)
|
|
6
|
-
[](./LICENSE)
|
|
7
|
-
[](https://nodejs.org/)
|
|
8
|
-

|
|
9
|
-

|
|
10
|
-
|
|
11
|
-
Modern **zero-dependency** X25519 + Ed25519 for Node.js using OpenSSL via `node:crypto`.
|
|
12
|
-
|
|
13
|
-
- **Node:** `>= 20`
|
|
14
|
-
- **Runtime deps:** `0`
|
|
15
|
-
- **TypeScript:** `strict`, **ESM-first**
|
|
16
|
-
- **Compat:** ESM + CJS (`import` e `require`)
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## Why
|
|
21
|
-
|
|
22
|
-
O projeto original ([curve25519-js](https://github.com/harveyconnor/curve25519-js)) fazia aritmética de campo manual (loops extensos BigInt/Float64) para Curve25519/Ed25519.
|
|
3
|
+
> 🇺🇸 English version: [README.en.md](./README.en.md)
|
|
23
4
|
|
|
24
|
-
|
|
5
|
+
Implementação sem dependências de runtime de:
|
|
25
6
|
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
- **API pequena** e **bem tipada**
|
|
7
|
+
- X25519 + Ed25519 (modo moderno via OpenSSL em `node:crypto`)
|
|
8
|
+
- axlsign legado (modo opcional via WASM, compatível com `curve25519-js`)
|
|
29
9
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Aqui a API é **padrão moderna**:
|
|
37
|
-
|
|
38
|
-
- acordo de chave: **X25519**
|
|
39
|
-
- assinatura: **Ed25519**
|
|
40
|
-
|
|
41
|
-
Consequências:
|
|
10
|
+
[](https://www.npmjs.com/package/@unknownncat/curve25519-node)
|
|
11
|
+
[](https://nodejs.org/)
|
|
12
|
+
[](./dist/index.d.ts)
|
|
13
|
+

|
|
14
|
+

|
|
15
|
+
[](./LICENSE)
|
|
42
16
|
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
- O compat layer aceita um 3º argumento apenas por compatibilidade de chamada, mas **sempre lança erro** se ele for fornecido.
|
|
17
|
+
- Node: `>= 20`
|
|
18
|
+
- Dependências de runtime: `0`
|
|
19
|
+
- TypeScript: `strict`
|
|
20
|
+
- Formatos de módulo: ESM + CJS
|
|
48
21
|
|
|
49
22
|
---
|
|
50
23
|
|
|
51
|
-
##
|
|
24
|
+
## Instalação
|
|
52
25
|
|
|
53
26
|
```bash
|
|
54
27
|
npm i @unknownncat/curve25519-node
|
|
@@ -56,155 +29,304 @@ npm i @unknownncat/curve25519-node
|
|
|
56
29
|
|
|
57
30
|
---
|
|
58
31
|
|
|
59
|
-
##
|
|
60
|
-
|
|
61
|
-
### ESM (TypeScript / Node moderno)
|
|
32
|
+
## Uso Rápido
|
|
62
33
|
|
|
63
34
|
```ts
|
|
64
|
-
import {
|
|
65
|
-
|
|
66
|
-
x25519,
|
|
67
|
-
ed25519,
|
|
68
|
-
sign, // compat top-level (Ed25519)
|
|
69
|
-
verify, // compat top-level (Ed25519)
|
|
70
|
-
} from "@unknownncat/curve25519-node";
|
|
35
|
+
import { randomBytes } from "node:crypto";
|
|
36
|
+
import { asBytes32, x25519, ed25519 } from "@unknownncat/curve25519-node";
|
|
71
37
|
|
|
72
|
-
const aliceSeed = asBytes32(
|
|
73
|
-
const bobSeed = asBytes32(
|
|
38
|
+
const aliceSeed = asBytes32(randomBytes(32));
|
|
39
|
+
const bobSeed = asBytes32(randomBytes(32));
|
|
74
40
|
|
|
75
41
|
const aliceX = x25519.generateKeyPair(aliceSeed);
|
|
76
42
|
const bobX = x25519.generateKeyPair(bobSeed);
|
|
77
43
|
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
const signerSeed = asBytes32(crypto.getRandomValues(new Uint8Array(32)));
|
|
83
|
-
const ed = ed25519.generateKeyPair(signerSeed);
|
|
44
|
+
const segredo1 = x25519.sharedKey(aliceX.private, bobX.public);
|
|
45
|
+
const segredo2 = x25519.sharedKey(bobX.private, aliceX.public);
|
|
46
|
+
// segredo1 === segredo2
|
|
84
47
|
|
|
48
|
+
const signerSeed = asBytes32(randomBytes(32));
|
|
49
|
+
const signer = ed25519.generateKeyPair(signerSeed);
|
|
85
50
|
const msg = new TextEncoder().encode("hello");
|
|
86
51
|
|
|
87
52
|
const sig = ed25519.sign(signerSeed, msg);
|
|
88
|
-
const ok = verify(
|
|
89
|
-
|
|
90
|
-
const signedMsg = ed25519.signMessage(signerSeed, msg);
|
|
91
|
-
const opened = ed25519.openMessage(ed.public, signedMsg);
|
|
53
|
+
const ok = ed25519.verify(signer.public, msg, sig);
|
|
92
54
|
```
|
|
93
55
|
|
|
94
|
-
|
|
56
|
+
CommonJS:
|
|
95
57
|
|
|
96
58
|
```js
|
|
97
59
|
const { x25519, ed25519, asBytes32 } = require("@unknownncat/curve25519-node");
|
|
98
|
-
|
|
99
|
-
const seed = asBytes32(new Uint8Array(32));
|
|
100
|
-
const kp = x25519.generateKeyPair(seed);
|
|
101
|
-
|
|
102
|
-
const sig = ed25519.sign(seed, Buffer.from("hello"));
|
|
103
60
|
```
|
|
104
61
|
|
|
105
|
-
|
|
62
|
+
Legado axlsign via WASM:
|
|
106
63
|
|
|
107
64
|
```ts
|
|
108
|
-
import {
|
|
109
|
-
|
|
110
|
-
|
|
65
|
+
import { asBytes32, axlsign } from "@unknownncat/curve25519-node";
|
|
66
|
+
|
|
67
|
+
const seed = asBytes32(new Uint8Array(32));
|
|
68
|
+
const kp = axlsign.generateKeyPair(seed); // X25519 keypair compatível com curve25519-js
|
|
69
|
+
const sig = axlsign.sign(
|
|
70
|
+
kp.private,
|
|
71
|
+
new TextEncoder().encode("hello"),
|
|
72
|
+
new Uint8Array(64),
|
|
73
|
+
);
|
|
74
|
+
const ok = axlsign.verify(kp.public, new TextEncoder().encode("hello"), sig);
|
|
111
75
|
```
|
|
112
76
|
|
|
113
77
|
---
|
|
114
78
|
|
|
115
79
|
## API
|
|
116
80
|
|
|
117
|
-
###
|
|
81
|
+
### `x25519`
|
|
118
82
|
|
|
119
83
|
- `publicKey(secretKey32: Bytes32): Bytes32`
|
|
120
84
|
- `sharedKey(secretKey32: Bytes32, publicKey32: Bytes32): Bytes32`
|
|
121
85
|
- `generateKeyPair(seed32: Bytes32): { public: Bytes32; private: Bytes32 }`
|
|
122
86
|
|
|
123
|
-
###
|
|
87
|
+
### `ed25519`
|
|
124
88
|
|
|
125
89
|
- `publicKey(secretSeed32: Bytes32): Bytes32`
|
|
126
90
|
- `generateKeyPair(seed32: Bytes32): { public: Bytes32; private: Bytes32 }`
|
|
127
91
|
- `sign(secretSeed32: Bytes32, msg: Uint8Array): Bytes64`
|
|
128
92
|
- `verify(publicKey32: Bytes32, msg: Uint8Array, signature64: Bytes64): boolean`
|
|
129
|
-
- `signMessage(secretSeed32: Bytes32, msg: Uint8Array): Uint8Array`
|
|
93
|
+
- `signMessage(secretSeed32: Bytes32, msg: Uint8Array): Uint8Array` (`assinatura || mensagem`)
|
|
130
94
|
- `openMessage(publicKey32: Bytes32, signedMsg: Uint8Array): Uint8Array | null`
|
|
131
95
|
|
|
132
|
-
###
|
|
96
|
+
### `axlsign` (compatibilidade legado, via WASM)
|
|
97
|
+
|
|
98
|
+
- `publicKey(secretKey32: Bytes32): Bytes32`
|
|
99
|
+
- `sharedKey(secretKey32: Bytes32, publicKey32: Bytes32): Bytes32`
|
|
100
|
+
- `generateKeyPair(seed32: Bytes32): { public: Bytes32; private: Bytes32 }`
|
|
101
|
+
- `sign(secretKey32: Bytes32, msg: Uint8Array, opt_random?: Bytes64): Bytes64`
|
|
102
|
+
- `verify(publicKey32: Bytes32, msg: Uint8Array, signature64: Bytes64): boolean`
|
|
103
|
+
- `signMessage(secretKey32: Bytes32, msg: Uint8Array, opt_random?: Bytes64): Uint8Array`
|
|
104
|
+
- `openMessage(publicKey32: Bytes32, signedMsg: Uint8Array): Uint8Array | null`
|
|
105
|
+
|
|
106
|
+
### Aliases de compatibilidade (top-level)
|
|
133
107
|
|
|
134
108
|
- `sharedKey = x25519.sharedKey`
|
|
135
109
|
- `generateKeyPair = x25519.generateKeyPair`
|
|
136
|
-
- `sign`, `verify`, `signMessage`, `openMessage` (
|
|
110
|
+
- `sign`, `verify`, `signMessage`, `openMessage` (semântica Ed25519)
|
|
137
111
|
- `generateKeyPairX25519`, `generateKeyPairEd25519`
|
|
138
112
|
|
|
139
|
-
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Notas de Compatibilidade
|
|
116
|
+
|
|
117
|
+
Este pacote suporta dois modos:
|
|
118
|
+
|
|
119
|
+
- **moderno (recomendado):** `x25519` + `ed25519` via `node:crypto`
|
|
120
|
+
- **legado:** `axlsign` via WASM para compatibilidade com `curve25519-js`
|
|
121
|
+
|
|
122
|
+
| Recurso | `curve25519-js` | `curve25519-node` |
|
|
123
|
+
| ----------------------------------- | --------------- | -------------------------------------------- |
|
|
124
|
+
| Esquema de assinatura (moderno) | axlsign | Ed25519 (padrão) |
|
|
125
|
+
| Esquema de assinatura (legado) | axlsign | axlsign (namespace `axlsign`) |
|
|
126
|
+
| Acordo de chave | X25519 | X25519 |
|
|
127
|
+
| Mesma chave para assinatura + ECDH | sim | apenas no namespace `axlsign` |
|
|
128
|
+
| `opt_random` nas APIs de assinatura | sim | sim no `axlsign`, não no top-level/`ed25519` |
|
|
129
|
+
| Backend OpenSSL | não | sim |
|
|
130
|
+
|
|
131
|
+
Importante:
|
|
132
|
+
|
|
133
|
+
- Chaves públicas X25519 e Ed25519 são diferentes.
|
|
134
|
+
- `node:crypto` não expõe API para converter public key X25519 ↔ Ed25519.
|
|
135
|
+
- Top-level `sign`/`signMessage` e namespace `ed25519` continuam com semântica Ed25519 e rejeitam `opt_random`.
|
|
136
|
+
- Para compatibilidade com `curve25519-js` (incluindo `opt_random`), use o namespace `axlsign`.
|
|
137
|
+
- Assinaturas Ed25519 continuam determinísticas (comportamento padrão do OpenSSL).
|
|
140
138
|
|
|
141
139
|
---
|
|
142
140
|
|
|
143
|
-
##
|
|
141
|
+
## Motivação
|
|
142
|
+
|
|
143
|
+
O `curve25519-js` é um projeto importante, mas usa aritmética de campo manual em JS (`Float64Array`, estilo TweetNaCl).
|
|
144
|
+
|
|
145
|
+
Este pacote foca em Node moderno com primitivas do OpenSSL:
|
|
146
|
+
|
|
147
|
+
- caminho de implementação mais seguro
|
|
148
|
+
- melhor desempenho em Node >= 20
|
|
149
|
+
- API menor e explícita
|
|
150
|
+
- tipagem forte com zero dependências de runtime
|
|
151
|
+
|
|
152
|
+
Além disso, o namespace `axlsign` via WASM permite migração progressiva de código legado sem reintroduzir aritmética de curva em JavaScript puro.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Tipos Branded
|
|
144
157
|
|
|
145
158
|
- `Bytes32`
|
|
146
159
|
- `Bytes64`
|
|
147
160
|
|
|
148
|
-
Helpers:
|
|
161
|
+
Helpers (validam sem copiar):
|
|
149
162
|
|
|
150
163
|
- `asBytes32(u8)`
|
|
151
164
|
- `asBytes64(u8)`
|
|
152
165
|
|
|
153
|
-
✅ Os helpers validam tamanho e retornam o **mesmo objeto** (sem cópia).
|
|
154
|
-
|
|
155
166
|
---
|
|
156
167
|
|
|
157
|
-
##
|
|
168
|
+
## Mapa de RFCs (uso no projeto)
|
|
169
|
+
|
|
170
|
+
| RFC | Seções usadas | Uso no projeto | Onde no código |
|
|
171
|
+
| --------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
|
|
172
|
+
| RFC 7748 (X25519) | Seção 5 (`The X25519 and X448 Functions`) | Regras de clamping/decoding do escalar e comportamento da função X25519 (zera 3 bits baixos, zera bit mais alto, seta o segundo bit mais alto). | `src/x25519.ts` |
|
|
173
|
+
| RFC 7748 (X25519) | Seção 5.2 (`Test Vectors`), Seção 6.1 (`Diffie-Hellman / Curve25519`) | Vetores oficiais para validação de interoperabilidade e corretude. | `test/x25519.test.mjs` |
|
|
174
|
+
| RFC 8032 (Ed25519) | Seção 5.1.5 (`Key Generation`), 5.1.6 (`Sign`), 5.1.7 (`Verify`) | Semântica de keygen/sign/verify Ed25519 (executada por OpenSSL via `node:crypto`). | `src/ed25519.ts` |
|
|
175
|
+
| RFC 8032 (Ed25519) | Seção 7.1 (`Test Vectors for Ed25519`) | Vetores determinísticos para validação de chave pública e assinatura. | `test/ed25519.test.mjs` |
|
|
176
|
+
| RFC 8410 (X25519/Ed25519 em PKIX) | Seção 3 (identificadores de algoritmo), Seção 4 (`Subject Public Key Fields`), Seção 7 (`Private Key Format`) | Estrutura DER para import/export de chaves raw de 32 bytes em SPKI/PKCS#8 com OIDs de X25519 e Ed25519. | `src/internal/der.ts` |
|
|
177
|
+
|
|
178
|
+
Referências indiretas por estrutura ASN.1/PKIX:
|
|
179
|
+
|
|
180
|
+
- RFC 5958 (OneAsymmetricKey / família PKCS#8)
|
|
181
|
+
- RFC 5280, Seção 4.1.2.7 (`Subject Public Key Info`)
|
|
158
182
|
|
|
159
|
-
|
|
183
|
+
Observações:
|
|
160
184
|
|
|
161
|
-
-
|
|
162
|
-
-
|
|
163
|
-
- Ed25519 PKCS#8 prefix: `302e020100300506032b657004220420`
|
|
164
|
-
- Ed25519 SPKI prefix: `302a300506032b6570032100`
|
|
185
|
+
- O projeto não reimplementa aritmética de curva em JS; as operações criptográficas usam OpenSSL via `node:crypto`.
|
|
186
|
+
- A suíte de testes cobre vetores oficiais do RFC 7748 e RFC 8032.
|
|
165
187
|
|
|
166
|
-
|
|
188
|
+
Rodar testes:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm test
|
|
192
|
+
```
|
|
167
193
|
|
|
168
194
|
---
|
|
169
195
|
|
|
170
|
-
##
|
|
196
|
+
## Detalhes Técnicos (DER / RFC 8410)
|
|
171
197
|
|
|
172
|
-
|
|
173
|
-
- `Uint8Array` → `Buffer` usa view zero-copy:
|
|
174
|
-
- `Buffer.from(u8.buffer, u8.byteOffset, u8.byteLength)`
|
|
198
|
+
Chaves raw de 32 bytes são importadas/exportadas com prefixos fixos:
|
|
175
199
|
|
|
176
|
-
-
|
|
177
|
-
-
|
|
200
|
+
- X25519 PKCS#8: `302e020100300506032b656e04220420`
|
|
201
|
+
- X25519 SPKI: `302a300506032b656e032100`
|
|
202
|
+
- Ed25519 PKCS#8: `302e020100300506032b657004220420`
|
|
203
|
+
- Ed25519 SPKI: `302a300506032b6570032100`
|
|
204
|
+
|
|
205
|
+
Notas de implementação:
|
|
206
|
+
|
|
207
|
+
- buffers prealocados + `.set`
|
|
208
|
+
- views zero-copy de `Uint8Array` quando seguro
|
|
209
|
+
- sem `Buffer.concat` em hot path
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Notas de Performance
|
|
214
|
+
|
|
215
|
+
- Evita cópias desnecessárias de bytes nos caminhos críticos.
|
|
216
|
+
- `signMessage` monta `assinatura || mensagem` com um único `Uint8Array` prealocado.
|
|
217
|
+
- Para throughput máximo em loops longos, cache de `KeyObject` no nível da aplicação reduz overhead de parse ASN.1.
|
|
178
218
|
|
|
179
219
|
---
|
|
180
220
|
|
|
181
|
-
##
|
|
221
|
+
## Notas de Segurança
|
|
182
222
|
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
-
|
|
223
|
+
- validação estrita de tipo/tamanho nas APIs públicas
|
|
224
|
+
- sem log de segredos
|
|
225
|
+
- `timingSafeEqual` em comparações internas de tamanho fixo quando necessário
|
|
186
226
|
|
|
187
227
|
---
|
|
188
228
|
|
|
189
|
-
##
|
|
229
|
+
## Benchmarks
|
|
230
|
+
|
|
231
|
+
A suíte de benchmark fica isolada em `bench/` (subprojeto separado) e compara com `curve25519-js`.
|
|
190
232
|
|
|
191
233
|
```bash
|
|
192
|
-
npm
|
|
234
|
+
npm run build
|
|
235
|
+
cd bench
|
|
236
|
+
npm install
|
|
237
|
+
npm run bench
|
|
193
238
|
```
|
|
194
239
|
|
|
195
|
-
|
|
240
|
+
### Snapshot real de benchmark (`npm run bench:ci`) no GitHub Codespaces
|
|
196
241
|
|
|
197
|
-
|
|
198
|
-
|
|
242
|
+
Comando:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
node --expose-gc bench.mjs --rounds=16 --roundMs=350 --warmupMs=500 --vectors=64 --variants=raw,cached --strict --verifyEvery=64 --jsonFile=results/bench-results.json
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Ambiente:
|
|
249
|
+
|
|
250
|
+
- Node: `v24.11.1`
|
|
251
|
+
- OpenSSL: `3.5.4`
|
|
252
|
+
- CPU: `AMD EPYC 7763 64-Core Processor`
|
|
253
|
+
- Cores lógicos: `4`
|
|
254
|
+
- Vetores: `64`
|
|
255
|
+
|
|
256
|
+
### Tabela 1 - API moderna (`x25519` + `ed25519`)
|
|
257
|
+
|
|
258
|
+
`sign`/`verify` abaixo comparam throughput de API, não equivalência criptográfica (Ed25519 vs axlsign legado).
|
|
259
|
+
|
|
260
|
+
| Operação | Moderno raw | Legado raw (`curve25519-js`) | Speedup raw | Moderno cached | Legado cached (`curve25519-js`) | Speedup cached |
|
|
261
|
+
| ------------------------------ | ----------: | ---------------------------: | ----------: | -------------: | ------------------------------: | -------------: |
|
|
262
|
+
| `x25519.generateKeyPair` | 14,378 | 1,591 | 9.04x | 41,120 | 1,478 | 27.83x |
|
|
263
|
+
| `x25519.sharedKey` | 9,970 | 1,591 | 6.27x | 23,995 | 1,554 | 15.44x |
|
|
264
|
+
| `ed25519.sign (msg32)` | 11,273 | 143 | 78.95x | 23,696 | 133 | 178.10x |
|
|
265
|
+
| `ed25519.sign (msg1024)` | 10,800 | 138 | 78.07x | 22,502 | 147 | 152.92x |
|
|
266
|
+
| `ed25519.verify (msg32)` | 7,280 | 136 | 53.36x | 8,271 | 155 | 53.37x |
|
|
267
|
+
| `ed25519.verify (msg1024)` | 7,160 | 132 | 54.33x | 8,159 | 154 | 52.90x |
|
|
268
|
+
| `ed25519.signMessage (msg256)` | 10,624 | 131 | 81.09x | 23,304 | 148 | 156.97x |
|
|
269
|
+
| `ed25519.openMessage (msg256)` | 6,574 | 124 | 52.93x | 8,129 | 154 | 52.64x |
|
|
270
|
+
|
|
271
|
+
### Tabela 2 - Compatibilidade `axlsign` (equivalente ao `curve25519-js`)
|
|
272
|
+
|
|
273
|
+
Aqui a comparação é de mesmo esquema criptográfico (equivalência + throughput).
|
|
274
|
+
|
|
275
|
+
| Operação | Moderno raw | Legado raw (`curve25519-js`) | Speedup raw | Moderno cached | Legado cached (`curve25519-js`) | Speedup cached |
|
|
276
|
+
| ----------------------------------------- | ----------: | ---------------------------: | ----------: | -------------: | ------------------------------: | -------------: |
|
|
277
|
+
| `axlsign.generateKeyPair` | 8,429 | 1,583 | 5.33x | 8,384 | 1,585 | 5.29x |
|
|
278
|
+
| `axlsign.sharedKey` | 8,452 | 1,583 | 5.34x | 8,396 | 1,570 | 5.35x |
|
|
279
|
+
| `axlsign.sign (msg32)` | 3,973 | 144 | 27.61x | 3,952 | 140 | 28.28x |
|
|
280
|
+
| `axlsign.sign (msg32,opt_random)` | 3,969 | 147 | 27.03x | 3,984 | 139 | 28.58x |
|
|
281
|
+
| `axlsign.sign (msg1024)` | 3,881 | 143 | 27.16x | 3,864 | 139 | 27.72x |
|
|
282
|
+
| `axlsign.verify (msg32)` | 6,527 | 146 | 44.70x | 6,534 | 143 | 45.72x |
|
|
283
|
+
| `axlsign.verify (msg32,opt_random)` | 6,506 | 144 | 45.07x | 6,469 | 141 | 45.80x |
|
|
284
|
+
| `axlsign.verify (msg1024)` | 6,361 | 141 | 45.03x | 6,337 | 135 | 46.92x |
|
|
285
|
+
| `axlsign.signMessage (msg256)` | 3,902 | 140 | 27.79x | 3,935 | 141 | 27.98x |
|
|
286
|
+
| `axlsign.signMessage (msg256,opt_random)` | 3,885 | 142 | 27.40x | 3,864 | 145 | 26.60x |
|
|
287
|
+
| `axlsign.openMessage (msg256)` | 6,441 | 138 | 46.57x | 6,300 | 131 | 47.93x |
|
|
288
|
+
| `axlsign.openMessage (msg256,opt_random)` | 6,362 | 141 | 45.24x | 6,285 | 130 | 48.22x |
|
|
289
|
+
|
|
290
|
+
Notas:
|
|
291
|
+
|
|
292
|
+
- `raw` inclui custo fim-a-fim da API.
|
|
293
|
+
- `cached` reduz overhead de setup para evidenciar melhor o throughput criptográfico.
|
|
294
|
+
- Fonte dos números: saída JSON de `bench:ci` (`results/bench-results.json`).
|
|
199
295
|
|
|
200
296
|
---
|
|
201
297
|
|
|
202
|
-
##
|
|
298
|
+
## Build do namespace `axlsign`
|
|
299
|
+
|
|
300
|
+
No pacote publicado no npm, os artefatos WASM já vêm prontos em `dist/`.
|
|
301
|
+
|
|
302
|
+
Para buildar a partir do código-fonte, você precisa:
|
|
303
|
+
|
|
304
|
+
- Rust toolchain
|
|
305
|
+
- `wasm-pack` instalado
|
|
203
306
|
|
|
204
|
-
|
|
307
|
+
Com isso, `npm run build` executa:
|
|
308
|
+
|
|
309
|
+
1. `wasm-pack build` (`wasm/axlsign`)
|
|
310
|
+
2. `tsc` ESM + CJS
|
|
311
|
+
3. cópia dos artefatos WASM para `dist/internal/axlsign-wasm`
|
|
205
312
|
|
|
206
313
|
---
|
|
207
314
|
|
|
208
|
-
##
|
|
315
|
+
## Licença
|
|
316
|
+
|
|
317
|
+
MIT
|
|
318
|
+
|
|
319
|
+
---
|
|
209
320
|
|
|
210
|
-
|
|
321
|
+
## Créditos
|
|
322
|
+
|
|
323
|
+
- [curve25519-js](https://github.com/harveyconnor/curve25519-js) (Harvey Connor, Dmitry Chestnykh)
|
|
324
|
+
- [TweetNaCl.js](https://tweetnacl.js.org/)
|
|
325
|
+
- Trevor Perrin, ideia de assinaturas Curve25519: <https://moderncrypto.org/mail-archive/curves/2014/000205.html>
|
|
326
|
+
- [Documentação Node.js `crypto`](https://nodejs.org/api/crypto.html)
|
|
327
|
+
- [OpenSSL](https://www.openssl.org/)
|
|
328
|
+
- [RFC 7748](https://www.rfc-editor.org/rfc/rfc7748)
|
|
329
|
+
- [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032)
|
|
330
|
+
- [RFC 8410](https://www.rfc-editor.org/rfc/rfc8410)
|
|
331
|
+
- [RFC 5958](https://www.rfc-editor.org/rfc/rfc5958)
|
|
332
|
+
- [RFC 5280](https://www.rfc-editor.org/rfc/rfc5280)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Bytes32, Bytes64, KeyPair32 } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Derives an axlsign-compatible public key (Montgomery/X25519 format).
|
|
4
|
+
*/
|
|
5
|
+
export declare function publicKey(secretKey32: Bytes32): Bytes32;
|
|
6
|
+
/**
|
|
7
|
+
* Computes an axlsign-compatible X25519 shared key.
|
|
8
|
+
*/
|
|
9
|
+
export declare function sharedKey(secretKey32: Bytes32, publicKey32: Bytes32): Bytes32;
|
|
10
|
+
/**
|
|
11
|
+
* Generates an axlsign-compatible key pair from a 32-byte seed.
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateKeyPair(seed32: Bytes32): KeyPair32;
|
|
14
|
+
/**
|
|
15
|
+
* Detached axlsign signature using X25519-format secret key.
|
|
16
|
+
* opt_random (64 bytes) enables randomized signing as in curve25519-js.
|
|
17
|
+
*/
|
|
18
|
+
export declare function sign(secretKey32: Bytes32, msg: Uint8Array, opt_random?: Uint8Array): Bytes64;
|
|
19
|
+
/**
|
|
20
|
+
* Verifies detached axlsign signature.
|
|
21
|
+
*/
|
|
22
|
+
export declare function verify(publicKey32: Bytes32, msg: Uint8Array, signature64: Bytes64): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Returns signature || message (axlsign mode).
|
|
25
|
+
*/
|
|
26
|
+
export declare function signMessage(secretKey32: Bytes32, msg: Uint8Array, opt_random?: Uint8Array): Uint8Array;
|
|
27
|
+
/**
|
|
28
|
+
* Verifies signature || message and returns original message on success.
|
|
29
|
+
*/
|
|
30
|
+
export declare function openMessage(publicKey32: Bytes32, signedMsg: Uint8Array): Uint8Array | null;
|
|
31
|
+
//# sourceMappingURL=axlsign.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axlsign.d.ts","sourceRoot":"","sources":["../src/axlsign.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAiB9D;;GAEG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,OAAO,GAAG,OAAO,CAIvD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO,CAK7E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAQ1D;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,OAAO,CAU5F;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO,CAK3F;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,UAAU,CAUtG;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI,CAe1F"}
|
package/dist/axlsign.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { asBytes32, asBytes64, assertBytes32, assertBytes64, assertUint8Array } from "./internal/assert.js";
|
|
2
|
+
import * as wasmAxl from "./internal/axlsign-wasm/axlsign_wasm.js";
|
|
3
|
+
function clampScalar(seed32) {
|
|
4
|
+
const out = new Uint8Array(32);
|
|
5
|
+
out.set(seed32);
|
|
6
|
+
out[0] = (out[0] ?? 0) & 248;
|
|
7
|
+
const last = out[31] ?? 0;
|
|
8
|
+
out[31] = (last & 127) | 64;
|
|
9
|
+
return asBytes32(out, "clamped scalar");
|
|
10
|
+
}
|
|
11
|
+
function assertOptionalRandom64(value, fnName) {
|
|
12
|
+
if (value === undefined)
|
|
13
|
+
return;
|
|
14
|
+
assertBytes64(value, `${fnName} opt_random`);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Derives an axlsign-compatible public key (Montgomery/X25519 format).
|
|
18
|
+
*/
|
|
19
|
+
export function publicKey(secretKey32) {
|
|
20
|
+
assertBytes32(secretKey32, "secretKey32");
|
|
21
|
+
const out = wasmAxl.axlsignPublicKey(secretKey32);
|
|
22
|
+
return asBytes32(out, "axlsign public key");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Computes an axlsign-compatible X25519 shared key.
|
|
26
|
+
*/
|
|
27
|
+
export function sharedKey(secretKey32, publicKey32) {
|
|
28
|
+
assertBytes32(secretKey32, "secretKey32");
|
|
29
|
+
assertBytes32(publicKey32, "publicKey32");
|
|
30
|
+
const out = wasmAxl.axlsignSharedKey(secretKey32, publicKey32);
|
|
31
|
+
return asBytes32(out, "axlsign shared key");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generates an axlsign-compatible key pair from a 32-byte seed.
|
|
35
|
+
*/
|
|
36
|
+
export function generateKeyPair(seed32) {
|
|
37
|
+
assertBytes32(seed32, "seed32");
|
|
38
|
+
const privateKey = clampScalar(seed32);
|
|
39
|
+
const publicKey32 = publicKey(privateKey);
|
|
40
|
+
return {
|
|
41
|
+
public: publicKey32,
|
|
42
|
+
private: privateKey,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Detached axlsign signature using X25519-format secret key.
|
|
47
|
+
* opt_random (64 bytes) enables randomized signing as in curve25519-js.
|
|
48
|
+
*/
|
|
49
|
+
export function sign(secretKey32, msg, opt_random) {
|
|
50
|
+
assertBytes32(secretKey32, "secretKey32");
|
|
51
|
+
assertUint8Array(msg, "msg");
|
|
52
|
+
assertOptionalRandom64(opt_random, "sign");
|
|
53
|
+
const signature = opt_random === undefined
|
|
54
|
+
? wasmAxl.axlsignSign(secretKey32, msg)
|
|
55
|
+
: wasmAxl.axlsignSignRnd(secretKey32, msg, opt_random);
|
|
56
|
+
return asBytes64(signature, "axlsign signature");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Verifies detached axlsign signature.
|
|
60
|
+
*/
|
|
61
|
+
export function verify(publicKey32, msg, signature64) {
|
|
62
|
+
assertBytes32(publicKey32, "publicKey32");
|
|
63
|
+
assertUint8Array(msg, "msg");
|
|
64
|
+
assertBytes64(signature64, "signature64");
|
|
65
|
+
return wasmAxl.axlsignVerify(publicKey32, msg, signature64);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Returns signature || message (axlsign mode).
|
|
69
|
+
*/
|
|
70
|
+
export function signMessage(secretKey32, msg, opt_random) {
|
|
71
|
+
assertBytes32(secretKey32, "secretKey32");
|
|
72
|
+
assertUint8Array(msg, "msg");
|
|
73
|
+
assertOptionalRandom64(opt_random, "signMessage");
|
|
74
|
+
const signature = sign(secretKey32, msg, opt_random);
|
|
75
|
+
const out = new Uint8Array(64 + msg.byteLength);
|
|
76
|
+
out.set(signature, 0);
|
|
77
|
+
out.set(msg, 64);
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Verifies signature || message and returns original message on success.
|
|
82
|
+
*/
|
|
83
|
+
export function openMessage(publicKey32, signedMsg) {
|
|
84
|
+
assertBytes32(publicKey32, "publicKey32");
|
|
85
|
+
assertUint8Array(signedMsg, "signedMsg");
|
|
86
|
+
if (signedMsg.byteLength < 64) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const signature64 = asBytes64(signedMsg.subarray(0, 64), "signedMsg signature");
|
|
90
|
+
const msg = signedMsg.subarray(64);
|
|
91
|
+
if (!verify(publicKey32, msg, signature64)) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return new Uint8Array(msg);
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=axlsign.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axlsign.js","sourceRoot":"","sources":["../src/axlsign.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE5G,OAAO,KAAK,OAAO,MAAM,yCAAyC,CAAC;AAEnE,SAAS,WAAW,CAAC,MAAe;IAClC,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAC/B,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAChB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;IAC7B,MAAM,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAC1B,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC;IAC5B,OAAO,SAAS,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,sBAAsB,CAAC,KAA6B,EAAE,MAAc;IAC3E,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO;IAChC,aAAa,CAAC,KAAK,EAAE,GAAG,MAAM,aAAa,CAAC,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,WAAoB;IAC5C,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAClD,OAAO,SAAS,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,WAAoB,EAAE,WAAoB;IAClE,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1C,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC/D,OAAO,SAAS,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAe;IAC7C,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChC,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAC1C,OAAO;QACL,MAAM,EAAE,WAAW;QACnB,OAAO,EAAE,UAAU;KACpB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,WAAoB,EAAE,GAAe,EAAE,UAAuB;IACjF,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1C,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,sBAAsB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAE3C,MAAM,SAAS,GACb,UAAU,KAAK,SAAS;QACtB,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,GAAG,CAAC;QACvC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,WAAW,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;IAC3D,OAAO,SAAS,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;AACnD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,WAAoB,EAAE,GAAe,EAAE,WAAoB;IAChF,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1C,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1C,OAAO,OAAO,CAAC,aAAa,CAAC,WAAW,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,WAAoB,EAAE,GAAe,EAAE,UAAuB;IACxF,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1C,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,sBAAsB,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAElD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;IAChD,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IACtB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjB,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,WAAoB,EAAE,SAAqB;IACrE,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1C,gBAAgB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAEzC,IAAI,SAAS,CAAC,UAAU,GAAG,EAAE,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAChF,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC"}
|