Skip to content

Commit 8c35b74

Browse files
authored
feat: add one-shot sign/verify and Ed class docs (#890)
1 parent 5ea7a1c commit 8c35b74

File tree

6 files changed

+556
-42
lines changed

6 files changed

+556
-42
lines changed

docs/content/docs/api/ed25519.mdx

Lines changed: 157 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import { Callout } from 'fumadocs-ui/components/callout';
1010
## Table of Contents
1111

1212
- [Theory](#theory)
13-
- [Module Methods](#module-methods)
14-
- [Usage](#usage)
13+
- [Node.js Compatible API](#nodejs-compatible-api)
14+
- [Ed Class (Noble-style API)](#ed-class-noble-style-api)
1515
- [Best Practices](#best-practices)
1616

1717
## Theory
@@ -24,9 +24,9 @@ import { Callout } from 'fumadocs-ui/components/callout';
2424
They are faster and safer than RSA and older NIST curves.
2525
</Callout>
2626

27-
## Module Methods
27+
## Node.js Compatible API
2828

29-
Use `generateKeyPair` or `generateKeyPairSync`.
29+
Use `generateKeyPair` or `generateKeyPairSync` for Node.js-compatible key generation.
3030

3131
```ts
3232
import { generateKeyPairSync } from 'react-native-quick-crypto';
@@ -40,60 +40,158 @@ const xKeys = generateKeyPairSync('x25519');
4040
console.log(xKeys.publicKey.export({ format: 'pem', type: 'spki' }));
4141
```
4242

43-
## Usage
44-
45-
### Ed25519 Signatures
46-
47-
Ed25519 signatures are deterministic and do not require random number generation during signing, making them safe against weak RNG vulnerabilities.
43+
### Ed25519 Signatures (Node.js API)
4844

4945
```ts
50-
import { generateKeyPairSync, createSign, createVerify } from 'react-native-quick-crypto';
46+
import { generateKeyPairSync, sign, verify } from 'react-native-quick-crypto';
5147

5248
const { publicKey, privateKey } = generateKeyPairSync('ed25519');
53-
const message = 'Hello, secure world!';
54-
55-
// Sign
56-
// Note: For Ed25519, we use null as algorithm or specific flow depending on implementation
57-
// react-native-quick-crypto implies compatibility with Node.js
58-
const signer = createSign('ed25519' as any); // Type cast if needed
59-
signer.update(message);
60-
const signature = signer.sign(privateKey);
49+
const message = Buffer.from('Hello, secure world!');
6150

51+
// Sign (one-shot)
52+
const signature = sign(null, message, privateKey);
6253
console.log('Signature:', signature.toString('hex'));
6354

64-
// Verify
65-
const verifier = createVerify('ed25519' as any);
66-
verifier.update(message);
67-
const isValid = verifier.verify(publicKey, signature);
68-
55+
// Verify (one-shot)
56+
const isValid = verify(null, message, publicKey, signature);
6957
console.log('Valid:', isValid); // true
7058
```
7159

72-
### X25519 Key Exchange
73-
74-
X25519 is used for Diffie-Hellman key exchange.
60+
### X25519 Key Exchange (Node.js API)
7561

7662
```ts
7763
import { generateKeyPairSync, diffieHellman } from 'react-native-quick-crypto';
7864

79-
// Alice
65+
// Alice generates her key pair
8066
const alice = generateKeyPairSync('x25519');
8167

82-
// Bob
68+
// Bob generates his key pair
8369
const bob = generateKeyPairSync('x25519');
8470

85-
// Exchange (using hypothetical diffieHellman helper or similar mechanism)
86-
// Note: Node.js uses crypto.diffieHellman({ privateKey, publicKey })
87-
// react-native-quick-crypto may support this via similar API
88-
89-
/*
90-
const secret = diffieHellman({
71+
// Both compute the same shared secret
72+
const aliceSecret = diffieHellman({
9173
privateKey: alice.privateKey,
9274
publicKey: bob.publicKey
9375
});
94-
*/
76+
77+
const bobSecret = diffieHellman({
78+
privateKey: bob.privateKey,
79+
publicKey: alice.publicKey
80+
});
81+
82+
// aliceSecret and bobSecret are identical
9583
```
9684

85+
---
86+
87+
## Ed Class (Noble-style API)
88+
89+
<Callout type="info" title="Extended API">
90+
The `Ed` class provides a simpler, more direct API inspired by the [@noble/curves](https://github.com/paulmillr/noble-curves) library. This is **not** part of the Node.js crypto API but offers a convenient alternative for developers familiar with noble libraries.
91+
</Callout>
92+
93+
### Creating an Ed Instance
94+
95+
```ts
96+
import { Ed } from 'react-native-quick-crypto';
97+
98+
// For Ed25519 signatures
99+
const ed = new Ed('ed25519', {});
100+
101+
// For X25519 key exchange
102+
const x = new Ed('x25519', {});
103+
104+
// For Ed448 signatures
105+
const ed448 = new Ed('ed448', {});
106+
107+
// For X448 key exchange
108+
const x448 = new Ed('x448', {});
109+
```
110+
111+
### Key Generation
112+
113+
```ts
114+
import { Ed } from 'react-native-quick-crypto';
115+
116+
const ed = new Ed('ed25519', {});
117+
118+
// Synchronous key generation
119+
ed.generateKeyPairSync();
120+
121+
// Or async
122+
await ed.generateKeyPair();
123+
124+
// Get the keys as ArrayBuffer
125+
const publicKey = ed.getPublicKey();
126+
const privateKey = ed.getPrivateKey();
127+
```
128+
129+
### Signing and Verifying
130+
131+
```ts
132+
import { Ed } from 'react-native-quick-crypto';
133+
134+
const ed = new Ed('ed25519', {});
135+
ed.generateKeyPairSync();
136+
137+
const message = new TextEncoder().encode('Hello, world!');
138+
139+
// Sign (async)
140+
const signature = await ed.sign(message);
141+
142+
// Verify (async)
143+
const isValid = await ed.verify(signature, message);
144+
console.log('Valid:', isValid); // true
145+
146+
// Sync versions also available
147+
const signatureSync = ed.signSync(message);
148+
const isValidSync = ed.verifySync(signatureSync, message);
149+
```
150+
151+
### X25519 Shared Secret (Diffie-Hellman)
152+
153+
```ts
154+
import { Ed } from 'react-native-quick-crypto';
155+
156+
// Alice
157+
const alice = new Ed('x25519', {});
158+
alice.generateKeyPairSync();
159+
160+
// Bob
161+
const bob = new Ed('x25519', {});
162+
bob.generateKeyPairSync();
163+
164+
// Compute shared secret
165+
const aliceSecret = alice.getSharedSecret(
166+
alice.getPrivateKey(),
167+
bob.getPublicKey()
168+
);
169+
170+
const bobSecret = bob.getSharedSecret(
171+
bob.getPrivateKey(),
172+
alice.getPublicKey()
173+
);
174+
175+
// Both secrets are identical - use for symmetric encryption
176+
```
177+
178+
### Ed Class Methods Reference
179+
180+
| Method | Description |
181+
|:-------|:------------|
182+
| `generateKeyPair()` | Async key pair generation |
183+
| `generateKeyPairSync()` | Sync key pair generation |
184+
| `getPublicKey()` | Returns public key as `ArrayBuffer` |
185+
| `getPrivateKey()` | Returns private key as `ArrayBuffer` |
186+
| `sign(message, key?)` | Async signing (uses internal key if not provided) |
187+
| `signSync(message, key?)` | Sync signing |
188+
| `verify(signature, message, key?)` | Async verification |
189+
| `verifySync(signature, message, key?)` | Sync verification |
190+
| `getSharedSecret(privateKey, publicKey)` | X25519/X448 Diffie-Hellman |
191+
| `diffieHellman(options, callback?)` | Node.js-style DH with KeyObjects |
192+
193+
---
194+
97195
## Best Practices
98196

99197
<Callout type="warn" title="Security Warning">
@@ -103,6 +201,7 @@ const secret = diffieHellman({
103201
1. **Use Ed25519 for Signatures**: It's faster and safer than RSA.
104202
2. **Use X25519 for ECDH**: It's efficient and secure.
105203
3. **Don't use Ed25519 keys for X25519** directly without conversion (and vice versa).
204+
4. **Choose the right API**: Use Node.js API for compatibility, Ed class for simplicity.
106205

107206
## Common Errors
108207

@@ -111,18 +210,35 @@ const secret = diffieHellman({
111210
Trying to use RSA options with Ed25519.
112211

113212
```ts
114-
// ❌ Wrong
115-
// const signer = createSign('SHA256'); // Ed25519 hashes internally
213+
// ❌ Wrong - Ed25519 hashes internally
214+
const signer = createSign('SHA256');
116215

117-
// ✅ Correct
118-
// const signer = createSign(null); // or 'ed25519'
216+
// ✅ Correct - use null for Ed25519
217+
const signature = sign(null, data, ed25519PrivateKey);
119218
```
120219

121220
### Key Mismatch
122221

123222
Mixing Ed25519 and X25519 keys.
124223

125224
```ts
126-
// ❌ Wrong
127-
// sign(null, data, x25519PrivateKey); // Error: invalid key type
225+
// ❌ Wrong - can't sign with X25519 key
226+
sign(null, data, x25519PrivateKey); // Error: invalid key type
227+
228+
// ✅ Correct - use Ed25519 for signing
229+
sign(null, data, ed25519PrivateKey);
230+
```
231+
232+
### Wrong Ed Class Type
233+
234+
```ts
235+
// ❌ Wrong - can't sign with x25519 Ed instance
236+
const x = new Ed('x25519', {});
237+
x.generateKeyPairSync();
238+
await x.sign(message); // Error!
239+
240+
// ✅ Correct - use ed25519 for signing
241+
const ed = new Ed('ed25519', {});
242+
ed.generateKeyPairSync();
243+
await ed.sign(message);
128244
```

docs/data/coverage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ export const COVERAGE_DATA: CoverageCategory[] = [
134134
{ name: 'createSign', status: 'implemented' },
135135
{ name: 'createVerify', status: 'implemented' },
136136
{ name: 'decapsulate', status: 'missing' },
137+
{ name: 'sign', status: 'implemented', note: 'One-shot signing' },
138+
{ name: 'verify', status: 'implemented', note: 'One-shot verification' },
137139
{
138140
name: 'diffieHellman',
139141
subItems: [

example/src/hooks/useTestsList.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import '../tests/keys/generate_key';
1515
import '../tests/keys/generate_keypair';
1616
import '../tests/keys/public_cipher';
1717
import '../tests/keys/sign_verify_streaming';
18+
import '../tests/keys/sign_verify_oneshot';
1819
import '../tests/pbkdf2/pbkdf2_tests';
1920
import '../tests/random/random_tests';
2021
import '../tests/scrypt/scrypt_tests';

0 commit comments

Comments
 (0)