0
# Scalar Multiplication
1
2
Low-level scalar multiplication using x25519. These functions provide the underlying elliptic curve operations used by the higher-level box functions, enabling custom cryptographic protocols and key derivation.
3
4
## Capabilities
5
6
### Scalar Multiplication Operations
7
8
Perform elliptic curve scalar multiplication operations.
9
10
```javascript { .api }
11
/**
12
* Multiplies an integer scalar by a group element (point on the curve)
13
* @param {Uint8Array} n - The scalar (32 bytes)
14
* @param {Uint8Array} p - The group element/point (32 bytes)
15
* @returns {Uint8Array} Resulting group element (32 bytes)
16
*/
17
nacl.scalarMult(n, p): Uint8Array
18
19
/**
20
* Multiplies an integer scalar by the standard base point of the curve
21
* @param {Uint8Array} n - The scalar (32 bytes)
22
* @returns {Uint8Array} Resulting group element (32 bytes)
23
*/
24
nacl.scalarMult.base(n): Uint8Array
25
```
26
27
**Usage Examples:**
28
29
```javascript
30
const nacl = require('tweetnacl');
31
32
// Generate a random scalar (private key)
33
const scalar = nacl.randomBytes(nacl.scalarMult.scalarLength);
34
35
// Multiply scalar by base point to get public key
36
const publicKey = nacl.scalarMult.base(scalar);
37
console.log(publicKey.length); // 32
38
39
// Perform Diffie-Hellman key exchange
40
const aliceSecret = nacl.randomBytes(32);
41
const bobSecret = nacl.randomBytes(32);
42
43
const alicePublic = nacl.scalarMult.base(aliceSecret);
44
const bobPublic = nacl.scalarMult.base(bobSecret);
45
46
// Both parties can compute the same shared secret
47
const aliceShared = nacl.scalarMult(aliceSecret, bobPublic);
48
const bobShared = nacl.scalarMult(bobSecret, alicePublic);
49
50
// Verify shared secrets are identical
51
const secretsMatch = aliceShared.every((byte, i) => byte === bobShared[i]);
52
console.log(secretsMatch); // true
53
```
54
55
**Key Derivation Example:**
56
57
```javascript
58
const nacl = require('tweetnacl');
59
60
// Master key derivation
61
const masterKey = nacl.randomBytes(32);
62
const basePoint = nacl.scalarMult.base(masterKey);
63
64
// Derive child keys using different scalars
65
const childScalar1 = nacl.hash(new TextEncoder().encode("child1")).slice(0, 32);
66
const childScalar2 = nacl.hash(new TextEncoder().encode("child2")).slice(0, 32);
67
68
const childKey1 = nacl.scalarMult(childScalar1, basePoint);
69
const childKey2 = nacl.scalarMult(childScalar2, basePoint);
70
71
console.log("Child key 1:", childKey1);
72
console.log("Child key 2:", childKey2);
73
```
74
75
## Constants
76
77
```javascript { .api }
78
nacl.scalarMult.scalarLength: number // 32 - Length of scalar in bytes
79
nacl.scalarMult.groupElementLength: number // 32 - Length of group element in bytes
80
```
81
82
## Advanced Usage
83
84
### Custom Diffie-Hellman Implementation
85
86
```javascript
87
const nacl = require('tweetnacl');
88
89
function createDiffieHellmanKeyPair() {
90
const secretKey = nacl.randomBytes(nacl.scalarMult.scalarLength);
91
const publicKey = nacl.scalarMult.base(secretKey);
92
return { secretKey, publicKey };
93
}
94
95
function computeSharedSecret(mySecretKey, theirPublicKey) {
96
return nacl.scalarMult(mySecretKey, theirPublicKey);
97
}
98
99
// Usage
100
const alice = createDiffieHellmanKeyPair();
101
const bob = createDiffieHellmanKeyPair();
102
103
const sharedSecretAlice = computeSharedSecret(alice.secretKey, bob.publicKey);
104
const sharedSecretBob = computeSharedSecret(bob.secretKey, alice.publicKey);
105
106
// Both shared secrets are identical
107
console.log(sharedSecretAlice.every((byte, i) => byte === sharedSecretBob[i])); // true
108
```
109
110
### Key Validation
111
112
```javascript
113
const nacl = require('tweetnacl');
114
115
function isValidGroupElement(element) {
116
if (element.length !== nacl.scalarMult.groupElementLength) {
117
return false;
118
}
119
120
// Check if all bytes are zero (invalid point)
121
const allZero = element.every(byte => byte === 0);
122
return !allZero;
123
}
124
125
function isValidScalar(scalar) {
126
if (scalar.length !== nacl.scalarMult.scalarLength) {
127
return false;
128
}
129
130
// Check if all bytes are zero (invalid scalar)
131
const allZero = scalar.every(byte => byte === 0);
132
return !allZero;
133
}
134
135
// Example validation
136
const publicKey = nacl.scalarMult.base(nacl.randomBytes(32));
137
console.log(isValidGroupElement(publicKey)); // true
138
139
const zeroKey = new Uint8Array(32); // All zeros
140
console.log(isValidGroupElement(zeroKey)); // false
141
```
142
143
## Security Considerations
144
145
- **Scalar Validation**: Ensure scalars are not all zeros and are properly random when used as private keys.
146
- **Point Validation**: Group elements should be validated to ensure they represent valid curve points.
147
- **Side-Channel Resistance**: The scalar multiplication is designed to be constant-time to prevent timing attacks.
148
- **Key Management**: When using these functions to implement custom protocols, follow proper key management practices.
149
- **Protocol Design**: These are low-level primitives. Most applications should use the higher-level `nacl.box` functions instead.
150
151
## Relationship to Box Functions
152
153
The `nacl.box` functions internally use scalar multiplication:
154
- `nacl.box.keyPair()` uses `nacl.scalarMult.base()` to generate public keys
155
- `nacl.box.before()` uses `nacl.scalarMult()` to compute shared secrets
156
157
Understanding scalar multiplication helps in designing custom protocols or optimizing performance-critical applications.