or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aead.mdauth.mdbox.mded25519.mdhash.mdindex.mdkdf.mdkx.mdmemory.mdpwhash.mdrandom.mdsecretbox.mdsecretstream.mdshorthash.mdsign.mdstream.md

ed25519.mddocs/

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

```