0
# Elliptic Curve Operations
1
2
Low-level elliptic curve operations on Ed25519 for advanced cryptographic protocols, scalar arithmetic, and point operations.
3
4
## Capabilities
5
6
### Scalar Multiplication
7
8
Perform scalar multiplication operations on Ed25519 curve points.
9
10
```javascript { .api }
11
/**
12
* Multiply Ed25519 base point by scalar
13
* @param q - Output buffer for resulting point (must be BYTES long)
14
* @param n - Scalar buffer (must be SCALARBYTES long)
15
* @throws Error if buffer sizes are incorrect or operation fails
16
*/
17
function crypto_scalarmult_ed25519_base(q: Buffer, n: Buffer): void;
18
19
/**
20
* Multiply Ed25519 point by scalar
21
* @param q - Output buffer for resulting point (must be BYTES long)
22
* @param n - Scalar buffer (must be SCALARBYTES long)
23
* @param p - Point buffer to multiply (must be BYTES long)
24
* @throws Error if buffer sizes are incorrect or operation fails
25
*/
26
function crypto_scalarmult_ed25519(q: Buffer, n: Buffer, p: Buffer): void;
27
28
/**
29
* Multiply Ed25519 base point by scalar (no clamping)
30
* @param q - Output buffer for resulting point (must be BYTES long)
31
* @param n - Scalar buffer (must be SCALARBYTES long)
32
* @throws Error if buffer sizes are incorrect or operation fails
33
*/
34
function crypto_scalarmult_ed25519_base_noclamp(q: Buffer, n: Buffer): void;
35
36
/**
37
* Multiply Ed25519 point by scalar (no clamping)
38
* @param q - Output buffer for resulting point (must be BYTES long)
39
* @param n - Scalar buffer (must be SCALARBYTES long)
40
* @param p - Point buffer to multiply (must be BYTES long)
41
* @throws Error if buffer sizes are incorrect or operation fails
42
*/
43
function crypto_scalarmult_ed25519_noclamp(q: Buffer, n: Buffer, p: Buffer): void;
44
```
45
46
**Usage Example:**
47
48
```javascript
49
const sodium = require('sodium-native');
50
51
// Generate random scalar
52
const scalar = Buffer.alloc(sodium.crypto_scalarmult_ed25519_SCALARBYTES);
53
sodium.randombytes_buf(scalar);
54
55
// Multiply base point by scalar (equivalent to generating public key)
56
const point = Buffer.alloc(sodium.crypto_scalarmult_ed25519_BYTES);
57
sodium.crypto_scalarmult_ed25519_base(point, scalar);
58
59
// Multiply the resulting point by another scalar
60
const scalar2 = Buffer.alloc(sodium.crypto_scalarmult_ed25519_SCALARBYTES);
61
sodium.randombytes_buf(scalar2);
62
63
const point2 = Buffer.alloc(sodium.crypto_scalarmult_ed25519_BYTES);
64
sodium.crypto_scalarmult_ed25519(point2, scalar2, point);
65
```
66
67
### Point Operations
68
69
Perform addition and subtraction operations on Ed25519 curve points.
70
71
```javascript { .api }
72
/**
73
* Add two Ed25519 points
74
* @param r - Output buffer for result point (must be BYTES long)
75
* @param p - First point buffer (must be BYTES long)
76
* @param q - Second point buffer (must be BYTES long)
77
* @throws Error if buffer sizes are incorrect or operation fails
78
*/
79
function crypto_core_ed25519_add(r: Buffer, p: Buffer, q: Buffer): void;
80
81
/**
82
* Subtract Ed25519 points (r = p - q)
83
* @param r - Output buffer for result point (must be BYTES long)
84
* @param p - First point buffer (must be BYTES long)
85
* @param q - Second point buffer (must be BYTES long)
86
* @throws Error if buffer sizes are incorrect or operation fails
87
*/
88
function crypto_core_ed25519_sub(r: Buffer, p: Buffer, q: Buffer): void;
89
```
90
91
### Point Validation
92
93
Check if a buffer represents a valid Ed25519 curve point.
94
95
```javascript { .api }
96
/**
97
* Check if buffer represents a valid Ed25519 point
98
* @param p - Point buffer to validate (must be BYTES long)
99
* @returns true if point is valid, false otherwise
100
*/
101
function crypto_core_ed25519_is_valid_point(p: Buffer): boolean;
102
```
103
104
### Point Generation
105
106
Generate Ed25519 points from uniform random bytes.
107
108
```javascript { .api }
109
/**
110
* Map uniform bytes to Ed25519 curve point
111
* @param p - Output buffer for point (must be BYTES long)
112
* @param r - Uniform random bytes (must be UNIFORMBYTES long)
113
* @throws Error if buffer sizes are incorrect or mapping fails
114
*/
115
function crypto_core_ed25519_from_uniform(p: Buffer, r: Buffer): void;
116
```
117
118
**Usage Example:**
119
120
```javascript
121
const sodium = require('sodium-native');
122
123
// Generate two random points
124
const uniform1 = Buffer.alloc(sodium.crypto_core_ed25519_UNIFORMBYTES);
125
const uniform2 = Buffer.alloc(sodium.crypto_core_ed25519_UNIFORMBYTES);
126
sodium.randombytes_buf(uniform1);
127
sodium.randombytes_buf(uniform2);
128
129
const point1 = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
130
const point2 = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
131
132
sodium.crypto_core_ed25519_from_uniform(point1, uniform1);
133
sodium.crypto_core_ed25519_from_uniform(point2, uniform2);
134
135
// Validate points
136
console.log('Point 1 valid:', sodium.crypto_core_ed25519_is_valid_point(point1));
137
console.log('Point 2 valid:', sodium.crypto_core_ed25519_is_valid_point(point2));
138
139
// Add points
140
const sum = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
141
sodium.crypto_core_ed25519_add(sum, point1, point2);
142
143
// Subtract points
144
const difference = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
145
sodium.crypto_core_ed25519_sub(difference, point1, point2);
146
```
147
148
### Scalar Operations
149
150
Perform arithmetic operations on Ed25519 scalars.
151
152
```javascript { .api }
153
/**
154
* Generate random Ed25519 scalar
155
* @param r - Output buffer for scalar (must be SCALARBYTES long)
156
*/
157
function crypto_core_ed25519_scalar_random(r: Buffer): void;
158
159
/**
160
* Reduce bytes to Ed25519 scalar modulo curve order
161
* @param r - Output buffer for reduced scalar (must be SCALARBYTES long)
162
* @param s - Input bytes to reduce (must be NONREDUCEDSCALARBYTES long)
163
*/
164
function crypto_core_ed25519_scalar_reduce(r: Buffer, s: Buffer): void;
165
166
/**
167
* Invert Ed25519 scalar (multiplicative inverse)
168
* @param recip - Output buffer for inverted scalar (must be SCALARBYTES long)
169
* @param s - Scalar buffer to invert (must be SCALARBYTES long)
170
*/
171
function crypto_core_ed25519_scalar_invert(recip: Buffer, s: Buffer): void;
172
173
/**
174
* Negate Ed25519 scalar
175
* @param neg - Output buffer for negated scalar (must be SCALARBYTES long)
176
* @param s - Scalar buffer to negate (must be SCALARBYTES long)
177
*/
178
function crypto_core_ed25519_scalar_negate(neg: Buffer, s: Buffer): void;
179
180
/**
181
* Complement Ed25519 scalar (1 - s)
182
* @param comp - Output buffer for complement (must be SCALARBYTES long)
183
* @param s - Scalar buffer to complement (must be SCALARBYTES long)
184
*/
185
function crypto_core_ed25519_scalar_complement(comp: Buffer, s: Buffer): void;
186
187
/**
188
* Add Ed25519 scalars modulo curve order
189
* @param z - Output buffer for sum (must be SCALARBYTES long)
190
* @param x - First scalar buffer (must be SCALARBYTES long)
191
* @param y - Second scalar buffer (must be SCALARBYTES long)
192
*/
193
function crypto_core_ed25519_scalar_add(z: Buffer, x: Buffer, y: Buffer): void;
194
195
/**
196
* Subtract Ed25519 scalars modulo curve order
197
* @param z - Output buffer for difference (must be SCALARBYTES long)
198
* @param x - First scalar buffer (must be SCALARBYTES long)
199
* @param y - Second scalar buffer (must be SCALARBYTES long)
200
*/
201
function crypto_core_ed25519_scalar_sub(z: Buffer, x: Buffer, y: Buffer): void;
202
```
203
204
**Usage Example:**
205
206
```javascript
207
const sodium = require('sodium-native');
208
209
// Generate random scalars
210
const scalar1 = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
211
const scalar2 = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
212
sodium.crypto_core_ed25519_scalar_random(scalar1);
213
sodium.crypto_core_ed25519_scalar_random(scalar2);
214
215
// Scalar arithmetic
216
const sum = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
217
const difference = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
218
const inverse = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
219
220
sodium.crypto_core_ed25519_scalar_add(sum, scalar1, scalar2);
221
sodium.crypto_core_ed25519_scalar_sub(difference, scalar1, scalar2);
222
sodium.crypto_core_ed25519_scalar_invert(inverse, scalar1);
223
224
// Reduce large bytes to scalar
225
const largeBytes = Buffer.alloc(sodium.crypto_core_ed25519_NONREDUCEDSCALARBYTES);
226
sodium.randombytes_buf(largeBytes);
227
228
const reducedScalar = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
229
sodium.crypto_core_ed25519_scalar_reduce(reducedScalar, largeBytes);
230
```
231
232
### Curve25519 Scalar Multiplication
233
234
Perform scalar multiplication on Curve25519 (Montgomery form).
235
236
```javascript { .api }
237
/**
238
* Multiply Curve25519 base point by scalar
239
* @param q - Output buffer for resulting point (must be BYTES long)
240
* @param n - Scalar buffer (must be SCALARBYTES long)
241
* @throws Error if buffer sizes are incorrect or operation fails
242
*/
243
function crypto_scalarmult_base(q: Buffer, n: Buffer): void;
244
245
/**
246
* Multiply Curve25519 point by scalar
247
* @param q - Output buffer for resulting point (must be BYTES long)
248
* @param n - Scalar buffer (must be SCALARBYTES long)
249
* @param p - Point buffer to multiply (must be BYTES long)
250
* @throws Error if buffer sizes are incorrect or operation fails
251
*/
252
function crypto_scalarmult(q: Buffer, n: Buffer, p: Buffer): void;
253
```
254
255
## Constants
256
257
```javascript { .api }
258
// Ed25519 point size in bytes
259
const crypto_core_ed25519_BYTES: number;
260
261
// Ed25519 uniform bytes size for point generation
262
const crypto_core_ed25519_UNIFORMBYTES: number;
263
264
// Ed25519 scalar size in bytes
265
const crypto_core_ed25519_SCALARBYTES: number;
266
267
// Ed25519 non-reduced scalar size in bytes
268
const crypto_core_ed25519_NONREDUCEDSCALARBYTES: number;
269
270
// Ed25519 scalar multiplication constants
271
const crypto_scalarmult_ed25519_BYTES: number;
272
const crypto_scalarmult_ed25519_SCALARBYTES: number;
273
274
// Curve25519 scalar multiplication constants
275
const crypto_scalarmult_BYTES: number;
276
const crypto_scalarmult_SCALARBYTES: number;
277
```
278
279
## Security Considerations
280
281
- **Scalar Validation**: Always validate scalars and points received from external sources.
282
- **Timing Attacks**: All operations are designed to be constant-time.
283
- **Point Validation**: Use `crypto_core_ed25519_is_valid_point` for untrusted points.
284
- **Clamping**: Use non-clamping variants only when you understand the implications.
285
286
## Common Patterns
287
288
### Threshold Signatures Setup
289
290
```javascript
291
const sodium = require('sodium-native');
292
293
class ThresholdSignature {
294
static generateShares(threshold, participants) {
295
const coefficients = [];
296
297
// Generate polynomial coefficients
298
for (let i = 0; i < threshold; i++) {
299
const coeff = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
300
sodium.crypto_core_ed25519_scalar_random(coeff);
301
coefficients.push(coeff);
302
}
303
304
const shares = [];
305
306
// Generate shares for each participant
307
for (let participant = 1; participant <= participants; participant++) {
308
let share = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
309
share.fill(0);
310
311
// Evaluate polynomial at participant index
312
for (let i = 0; i < coefficients.length; i++) {
313
const term = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
314
// term = coefficient * (participant^i)
315
// Simplified for example - real implementation needs proper field arithmetic
316
if (i === 0) {
317
Buffer.from(coefficients[i]).copy(term);
318
} else {
319
// Simplified power computation
320
Buffer.from(coefficients[i]).copy(term);
321
}
322
323
sodium.crypto_core_ed25519_scalar_add(share, share, term);
324
}
325
326
shares.push({ participant, share });
327
}
328
329
return { shares, publicKey: this.derivePublicKey(coefficients[0]) };
330
}
331
332
static derivePublicKey(secretKey) {
333
const publicKey = Buffer.alloc(sodium.crypto_scalarmult_ed25519_BYTES);
334
sodium.crypto_scalarmult_ed25519_base(publicKey, secretKey);
335
return publicKey;
336
}
337
}
338
```
339
340
### Elliptic Curve Diffie-Hellman
341
342
```javascript
343
const sodium = require('sodium-native');
344
345
class ECDHKeyExchange {
346
constructor() {
347
// Generate private key (scalar)
348
this.privateKey = Buffer.alloc(sodium.crypto_scalarmult_SCALARBYTES);
349
sodium.randombytes_buf(this.privateKey);
350
351
// Generate public key (point)
352
this.publicKey = Buffer.alloc(sodium.crypto_scalarmult_BYTES);
353
sodium.crypto_scalarmult_base(this.publicKey, this.privateKey);
354
}
355
356
// Compute shared secret with peer's public key
357
computeSharedSecret(peerPublicKey) {
358
const sharedSecret = Buffer.alloc(sodium.crypto_scalarmult_BYTES);
359
sodium.crypto_scalarmult(sharedSecret, this.privateKey, peerPublicKey);
360
return sharedSecret;
361
}
362
363
// Derive encryption key from shared secret
364
deriveKey(sharedSecret, info = 'encryption') {
365
const key = Buffer.alloc(32);
366
const combined = Buffer.concat([sharedSecret, Buffer.from(info)]);
367
sodium.crypto_generichash(key, combined);
368
return key;
369
}
370
}
371
372
// Usage
373
const alice = new ECDHKeyExchange();
374
const bob = new ECDHKeyExchange();
375
376
const aliceShared = alice.computeSharedSecret(bob.publicKey);
377
const bobShared = bob.computeSharedSecret(alice.publicKey);
378
379
console.log('Shared secrets match:', aliceShared.equals(bobShared));
380
381
const encryptionKey = alice.deriveKey(aliceShared);
382
```
383
384
### Point Compression/Decompression
385
386
```javascript
387
const sodium = require('sodium-native');
388
389
class PointCompression {
390
// Compress Ed25519 point (32 bytes -> 32 bytes with sign bit)
391
static compressPoint(point) {
392
// Ed25519 points are already in compressed form in sodium-native
393
// This is a conceptual example
394
return point;
395
}
396
397
// Decompress Ed25519 point
398
static decompressPoint(compressedPoint) {
399
// Validate the compressed point
400
if (!sodium.crypto_core_ed25519_is_valid_point(compressedPoint)) {
401
throw new Error('Invalid compressed point');
402
}
403
return compressedPoint;
404
}
405
406
// Generate valid random point
407
static generateRandomPoint() {
408
const uniform = Buffer.alloc(sodium.crypto_core_ed25519_UNIFORMBYTES);
409
sodium.randombytes_buf(uniform);
410
411
const point = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
412
sodium.crypto_core_ed25519_from_uniform(point, uniform);
413
414
return point;
415
}
416
}
417
```
418
419
### Multi-scalar Multiplication
420
421
```javascript
422
const sodium = require('sodium-native');
423
424
class MultiScalarMult {
425
// Compute sum of scalar multiplications: s1*P1 + s2*P2 + ... + sn*Pn
426
static multiScalarMult(scalars, points) {
427
if (scalars.length !== points.length) {
428
throw new Error('Scalars and points arrays must have same length');
429
}
430
431
let result = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
432
result.fill(0); // Start with identity point
433
434
for (let i = 0; i < scalars.length; i++) {
435
const product = Buffer.alloc(sodium.crypto_scalarmult_ed25519_BYTES);
436
sodium.crypto_scalarmult_ed25519(product, scalars[i], points[i]);
437
438
if (i === 0) {
439
Buffer.from(product).copy(result);
440
} else {
441
sodium.crypto_core_ed25519_add(result, result, product);
442
}
443
}
444
445
return result;
446
}
447
448
// Compute linear combination with base point: s1*G + s2*P2 + ... + sn*Pn
449
static linearCombination(baseScalar, scalars, points) {
450
const baseProduct = Buffer.alloc(sodium.crypto_scalarmult_ed25519_BYTES);
451
sodium.crypto_scalarmult_ed25519_base(baseProduct, baseScalar);
452
453
if (scalars.length === 0) {
454
return baseProduct;
455
}
456
457
const otherProducts = this.multiScalarMult(scalars, points);
458
459
const result = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
460
sodium.crypto_core_ed25519_add(result, baseProduct, otherProducts);
461
462
return result;
463
}
464
}
465
```