@bsv/sdk 1.9.2 → 1.9.4
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/dist/cjs/package.json +1 -1
- package/dist/cjs/src/kvstore/GlobalKVStore.js +116 -98
- package/dist/cjs/src/kvstore/GlobalKVStore.js.map +1 -1
- package/dist/cjs/src/kvstore/types.js.map +1 -1
- package/dist/cjs/src/overlay-tools/index.js +1 -0
- package/dist/cjs/src/overlay-tools/index.js.map +1 -1
- package/dist/cjs/src/overlay-tools/withDoubleSpendRetry.js +55 -0
- package/dist/cjs/src/overlay-tools/withDoubleSpendRetry.js.map +1 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/kvstore/GlobalKVStore.js +117 -99
- package/dist/esm/src/kvstore/GlobalKVStore.js.map +1 -1
- package/dist/esm/src/kvstore/types.js.map +1 -1
- package/dist/esm/src/overlay-tools/index.js +1 -0
- package/dist/esm/src/overlay-tools/index.js.map +1 -1
- package/dist/esm/src/overlay-tools/withDoubleSpendRetry.js +48 -0
- package/dist/esm/src/overlay-tools/withDoubleSpendRetry.js.map +1 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/kvstore/GlobalKVStore.d.ts.map +1 -1
- package/dist/types/src/kvstore/types.d.ts +2 -0
- package/dist/types/src/kvstore/types.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/index.d.ts +1 -0
- package/dist/types/src/overlay-tools/index.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/withDoubleSpendRetry.d.ts +14 -0
- package/dist/types/src/overlay-tools/withDoubleSpendRetry.d.ts.map +1 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +2 -2
- package/dist/umd/bundle.js.map +1 -1
- package/docs/fast-docs.png +0 -0
- package/docs/index.md +49 -44
- package/docs/reference/kvstore.md +9 -0
- package/docs/reference/overlay-tools.md +32 -0
- package/docs/swagger.png +0 -0
- package/package.json +1 -1
- package/src/kvstore/GlobalKVStore.ts +134 -114
- package/src/kvstore/__tests/GlobalKVStore.test.ts +11 -1
- package/src/kvstore/types.ts +2 -0
- package/src/overlay-tools/index.ts +1 -0
- package/src/overlay-tools/withDoubleSpendRetry.ts +71 -0
- package/docs/MARKDOWN_VALIDATION_GUIDE.md +0 -175
- package/docs/concepts/beef.md +0 -92
- package/docs/concepts/chain-tracking.md +0 -134
- package/docs/concepts/decentralized-identity.md +0 -221
- package/docs/concepts/fees.md +0 -249
- package/docs/concepts/identity-certificates.md +0 -307
- package/docs/concepts/index.md +0 -77
- package/docs/concepts/key-management.md +0 -185
- package/docs/concepts/script-templates.md +0 -176
- package/docs/concepts/sdk-philosophy.md +0 -80
- package/docs/concepts/signatures.md +0 -194
- package/docs/concepts/spv-verification.md +0 -118
- package/docs/concepts/transaction-encoding.md +0 -167
- package/docs/concepts/transaction-structure.md +0 -67
- package/docs/concepts/trust-model.md +0 -139
- package/docs/concepts/verification.md +0 -250
- package/docs/concepts/wallet-integration.md +0 -101
- package/docs/guides/development-wallet-setup.md +0 -374
- package/docs/guides/direct-transaction-creation.md +0 -147
- package/docs/guides/http-client-configuration.md +0 -488
- package/docs/guides/index.md +0 -138
- package/docs/guides/large-transactions.md +0 -448
- package/docs/guides/multisig-transactions.md +0 -792
- package/docs/guides/security-best-practices.md +0 -494
- package/docs/guides/transaction-batching.md +0 -132
- package/docs/guides/transaction-signing-methods.md +0 -419
- package/docs/reference/arc-config.md +0 -698
- package/docs/reference/brc-100.md +0 -33
- package/docs/reference/configuration.md +0 -835
- package/docs/reference/debugging.md +0 -705
- package/docs/reference/errors.md +0 -597
- package/docs/reference/index.md +0 -111
- package/docs/reference/network-config.md +0 -914
- package/docs/reference/op-codes.md +0 -325
- package/docs/reference/transaction-signatures.md +0 -95
- package/docs/tutorials/advanced-transaction.md +0 -572
- package/docs/tutorials/aes-encryption.md +0 -949
- package/docs/tutorials/authfetch-tutorial.md +0 -986
- package/docs/tutorials/ecdh-key-exchange.md +0 -549
- package/docs/tutorials/elliptic-curve-fundamentals.md +0 -606
- package/docs/tutorials/error-handling.md +0 -1216
- package/docs/tutorials/first-transaction-low-level.md +0 -205
- package/docs/tutorials/first-transaction.md +0 -275
- package/docs/tutorials/hashes-and-hmacs.md +0 -788
- package/docs/tutorials/identity-management.md +0 -729
- package/docs/tutorials/index.md +0 -219
- package/docs/tutorials/key-management.md +0 -538
- package/docs/tutorials/protowallet-development.md +0 -743
- package/docs/tutorials/script-construction.md +0 -690
- package/docs/tutorials/spv-merkle-proofs.md +0 -685
- package/docs/tutorials/testnet-transactions-low-level.md +0 -359
- package/docs/tutorials/transaction-broadcasting.md +0 -538
- package/docs/tutorials/transaction-types.md +0 -420
- package/docs/tutorials/type-42.md +0 -568
- package/docs/tutorials/uhrp-storage.md +0 -599
|
@@ -1,606 +0,0 @@
|
|
|
1
|
-
# Elliptic Curve Fundamentals: Numbers & Points
|
|
2
|
-
|
|
3
|
-
**Duration**: 90 minutes
|
|
4
|
-
**Prerequisites**: Basic TypeScript knowledge, basic mathematical understanding
|
|
5
|
-
|
|
6
|
-
## Learning Goals
|
|
7
|
-
|
|
8
|
-
By the end of this tutorial, you will:
|
|
9
|
-
|
|
10
|
-
- Understand the mathematical foundations of elliptic curves used in Bitcoin
|
|
11
|
-
- Work with BigNumber for handling large integers in cryptographic operations
|
|
12
|
-
- Manipulate elliptic curve points using the SDK
|
|
13
|
-
- Implement point addition and scalar multiplication
|
|
14
|
-
- Understand the relationship between private keys, public keys, and curve points
|
|
15
|
-
- Apply elliptic curve operations in practical Bitcoin scenarios
|
|
16
|
-
|
|
17
|
-
## Introduction to Elliptic Curve Mathematics
|
|
18
|
-
|
|
19
|
-
Elliptic curve cryptography (ECC) forms the foundation of Bitcoin's security model. Bitcoin uses the secp256k1 elliptic curve, which provides the mathematical basis for:
|
|
20
|
-
|
|
21
|
-
- **Digital signatures** (ECDSA) for transaction authorization
|
|
22
|
-
- **Key derivation** for generating Bitcoin addresses
|
|
23
|
-
- **Key exchange** (ECDH) for secure communication
|
|
24
|
-
- **Point multiplication** for public key generation
|
|
25
|
-
|
|
26
|
-
This tutorial explores these mathematical concepts and shows how to work with them using the BSV TypeScript SDK.
|
|
27
|
-
|
|
28
|
-
## Setting Up Your Environment
|
|
29
|
-
|
|
30
|
-
First, let's import the necessary classes from the SDK:
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
import { BigNumber, Curve, PrivateKey, PublicKey, Random } from '@bsv/sdk'
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Working with Big Numbers
|
|
37
|
-
|
|
38
|
-
### The Need for BigNumber
|
|
39
|
-
|
|
40
|
-
In JavaScript and TypeScript, natural numbers are limited to 53 bits of precision (approximately 15-16 decimal digits). However, cryptographic operations in Bitcoin require 256-bit numbers, which are far larger than JavaScript can natively handle.
|
|
41
|
-
|
|
42
|
-
The SDK's `BigNumber` class provides this capability:
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
// JavaScript's limitation
|
|
46
|
-
const maxSafeInteger = Number.MAX_SAFE_INTEGER
|
|
47
|
-
console.log('Max safe integer:', maxSafeInteger)
|
|
48
|
-
// 9007199254740991 (about 9 quadrillion)
|
|
49
|
-
|
|
50
|
-
// Bitcoin private keys are 256-bit numbers (much larger!)
|
|
51
|
-
const bitcoinPrivateKey = new BigNumber(Random(32))
|
|
52
|
-
console.log('Bitcoin private key:', bitcoinPrivateKey.toHex())
|
|
53
|
-
// Example: fd026136e9803295655bb342553ab8ad3260bd5e1a73ca86a7a92de81d9cee78
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Creating and Manipulating BigNumbers
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
// Creating BigNumbers from different sources
|
|
60
|
-
const bn1 = new BigNumber(7)
|
|
61
|
-
const bn2 = new BigNumber(4)
|
|
62
|
-
const bn3 = new BigNumber('123456789012345678901234567890')
|
|
63
|
-
const bn4 = new BigNumber(Random(32)) // 32 random bytes (256 bits)
|
|
64
|
-
|
|
65
|
-
// Basic arithmetic operations
|
|
66
|
-
const sum = bn1.add(bn2)
|
|
67
|
-
const difference = bn1.sub(bn2)
|
|
68
|
-
const product = bn1.mul(bn2)
|
|
69
|
-
const quotient = bn1.div(bn2)
|
|
70
|
-
const remainder = bn1.mod(bn2)
|
|
71
|
-
|
|
72
|
-
console.log('7 + 4 =', sum.toNumber()) // 11
|
|
73
|
-
console.log('7 - 4 =', difference.toNumber()) // 3
|
|
74
|
-
console.log('7 * 4 =', product.toNumber()) // 28
|
|
75
|
-
console.log('7 / 4 =', quotient.toNumber()) // 1 (integer division)
|
|
76
|
-
console.log('7 % 4 =', remainder.toNumber()) // 3
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### BigNumber Formats and Conversions
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
// Generate a random 256-bit number (like a Bitcoin private key)
|
|
83
|
-
const randomBigNum = new BigNumber(Random(32))
|
|
84
|
-
|
|
85
|
-
// Convert to different formats
|
|
86
|
-
console.log('Hex format:', randomBigNum.toHex())
|
|
87
|
-
console.log('Byte array:', randomBigNum.toArray())
|
|
88
|
-
console.log('Binary array:', randomBigNum.toBitArray())
|
|
89
|
-
|
|
90
|
-
// Working with multiplication (important for key derivation)
|
|
91
|
-
const multiplier = new BigNumber(65536) // 2^16
|
|
92
|
-
const multiplied = randomBigNum.muln(65536)
|
|
93
|
-
|
|
94
|
-
console.log('Original:', randomBigNum.toHex())
|
|
95
|
-
console.log('Multiplied by 65536:', multiplied.toHex())
|
|
96
|
-
// Notice the result has 4 extra zeros (2 bytes) at the end
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Understanding Elliptic Curves
|
|
100
|
-
|
|
101
|
-
### The secp256k1 Curve
|
|
102
|
-
|
|
103
|
-
Bitcoin uses the secp256k1 elliptic curve, which has the mathematical form:
|
|
104
|
-
|
|
105
|
-
```
|
|
106
|
-
y² = x³ + 7 (mod p)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
Where `p` is a very large prime number. This curve has special properties that make it suitable for cryptography.
|
|
110
|
-
|
|
111
|
-
### Working with the Curve Class
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
// Create an instance of the secp256k1 curve
|
|
115
|
-
const curve = new Curve()
|
|
116
|
-
|
|
117
|
-
// Get the generator point (G) - the standard starting point for all operations
|
|
118
|
-
const G = curve.g
|
|
119
|
-
|
|
120
|
-
console.log('Generator point G:', G.toString())
|
|
121
|
-
// Example output: 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
The generator point G is a predefined point on the curve that serves as the foundation for all cryptographic operations.
|
|
125
|
-
|
|
126
|
-
## Working with Points on the Curve
|
|
127
|
-
|
|
128
|
-
### Creating Points from Private Keys
|
|
129
|
-
|
|
130
|
-
The fundamental operation in elliptic curve cryptography is multiplying the generator point by a private key to get a public key:
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
// Generate a random private key (256-bit number)
|
|
134
|
-
const privateKey = new BigNumber(Random(32))
|
|
135
|
-
|
|
136
|
-
// Multiply the generator point by the private key to get the public key point
|
|
137
|
-
const publicKeyPoint = G.mul(privateKey)
|
|
138
|
-
|
|
139
|
-
console.log('Private key:', privateKey.toHex())
|
|
140
|
-
console.log('Public key point:', publicKeyPoint.toString())
|
|
141
|
-
|
|
142
|
-
// This demonstrates the one-way nature of elliptic curve operations:
|
|
143
|
-
// - Easy: privateKey * G = publicKeyPoint (point multiplication)
|
|
144
|
-
// - Hard: publicKeyPoint / G = privateKey (point "division" - computationally infeasible)
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Point Addition
|
|
148
|
-
|
|
149
|
-
Points on an elliptic curve can be added together using special geometric rules:
|
|
150
|
-
|
|
151
|
-
```typescript
|
|
152
|
-
// Create two different key pairs
|
|
153
|
-
const privateKey1 = new BigNumber(Random(32))
|
|
154
|
-
const privateKey2 = new BigNumber(Random(32))
|
|
155
|
-
|
|
156
|
-
const publicPoint1 = G.mul(privateKey1)
|
|
157
|
-
const publicPoint2 = G.mul(privateKey2)
|
|
158
|
-
|
|
159
|
-
// Add the two public key points together
|
|
160
|
-
const addedPoints = publicPoint1.add(publicPoint2)
|
|
161
|
-
|
|
162
|
-
console.log('Point 1:', publicPoint1.toString())
|
|
163
|
-
console.log('Point 2:', publicPoint2.toString())
|
|
164
|
-
console.log('Point 1 + Point 2:', addedPoints.toString())
|
|
165
|
-
|
|
166
|
-
// Point addition is commutative: P1 + P2 = P2 + P1
|
|
167
|
-
const addedReverse = publicPoint2.add(publicPoint1)
|
|
168
|
-
console.log('Points are equal:', addedPoints.toString() === addedReverse.toString())
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### Point Multiplication
|
|
172
|
-
|
|
173
|
-
Point multiplication is the core operation that makes ECDH (Elliptic Curve Diffie-Hellman) work:
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
// Demonstrate the mathematical property that makes ECDH secure
|
|
177
|
-
const alicePrivate = new BigNumber(Random(32))
|
|
178
|
-
const bobPrivate = new BigNumber(Random(32))
|
|
179
|
-
|
|
180
|
-
// Each person generates their public key
|
|
181
|
-
const alicePublic = G.mul(alicePrivate)
|
|
182
|
-
const bobPublic = G.mul(bobPrivate)
|
|
183
|
-
|
|
184
|
-
// Alice can compute a shared secret using Bob's public key and her private key
|
|
185
|
-
const aliceSharedSecret = bobPublic.mul(alicePrivate)
|
|
186
|
-
|
|
187
|
-
// Bob can compute the same shared secret using Alice's public key and his private key
|
|
188
|
-
const bobSharedSecret = alicePublic.mul(bobPrivate)
|
|
189
|
-
|
|
190
|
-
// The secrets are identical because:
|
|
191
|
-
// Alice: (Bob_private * G) * Alice_private = Bob_private * Alice_private * G
|
|
192
|
-
// Bob: (Alice_private * G) * Bob_private = Alice_private * Bob_private * G
|
|
193
|
-
console.log('Shared secrets match:', aliceSharedSecret.toString() === bobSharedSecret.toString())
|
|
194
|
-
console.log('Shared secret:', aliceSharedSecret.toString())
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## Working with SDK Key Classes
|
|
198
|
-
|
|
199
|
-
### PrivateKey and PublicKey Classes
|
|
200
|
-
|
|
201
|
-
The SDK provides higher-level wrappers around BigNumber and Point for easier key management:
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
// Generate a private key using the SDK's PrivateKey class
|
|
205
|
-
const privateKey = PrivateKey.fromRandom()
|
|
206
|
-
|
|
207
|
-
// Get the corresponding public key
|
|
208
|
-
const publicKey = privateKey.toPublicKey()
|
|
209
|
-
|
|
210
|
-
// Access the underlying mathematical objects - using available methods
|
|
211
|
-
const privateKeyHex = privateKey.toString() // This gives the hex representation
|
|
212
|
-
const publicKeyHex = publicKey.toString() // This gives the hex representation
|
|
213
|
-
|
|
214
|
-
console.log('Private key (hex):', privateKeyHex)
|
|
215
|
-
console.log('Public key (hex):', publicKeyHex)
|
|
216
|
-
|
|
217
|
-
// We can create BigNumber from the hex string
|
|
218
|
-
const privateBigNumber = new BigNumber(privateKeyHex, 16)
|
|
219
|
-
|
|
220
|
-
// Verify the mathematical relationship using curve operations
|
|
221
|
-
const curve = new Curve()
|
|
222
|
-
const computedPublicPoint = curve.g.mul(privateBigNumber)
|
|
223
|
-
|
|
224
|
-
// Compare with the public key (we'll compare hex representations)
|
|
225
|
-
console.log('Manual computation point:', computedPublicPoint.toString())
|
|
226
|
-
console.log('SDK public key matches manual computation')
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Key Formats and Serialization
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
const privateKey = PrivateKey.fromRandom()
|
|
233
|
-
const publicKey = privateKey.toPublicKey()
|
|
234
|
-
|
|
235
|
-
// Private key formats
|
|
236
|
-
console.log('Private key WIF:', privateKey.toWif())
|
|
237
|
-
console.log('Private key hex:', privateKey.toString())
|
|
238
|
-
|
|
239
|
-
// Public key formats
|
|
240
|
-
console.log('Public key hex (compressed):', publicKey.toString())
|
|
241
|
-
console.log('Public key DER:', publicKey.toDER())
|
|
242
|
-
|
|
243
|
-
// We can work with the hex representations
|
|
244
|
-
const privateHex = privateKey.toString()
|
|
245
|
-
const publicHex = publicKey.toString()
|
|
246
|
-
|
|
247
|
-
console.log('Private key length:', privateHex.length / 2, 'bytes')
|
|
248
|
-
console.log('Public key length (compressed):', publicHex.length / 2, 'bytes')
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
## Practical Applications
|
|
252
|
-
|
|
253
|
-
### Manual Key Pair Generation
|
|
254
|
-
|
|
255
|
-
Let's create a complete example that manually generates a key pair and verifies the mathematical relationships:
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
import { BigNumber, Curve, PrivateKey, Random } from '@bsv/sdk'
|
|
259
|
-
|
|
260
|
-
function generateKeyPairManually() {
|
|
261
|
-
// Step 1: Generate a random 256-bit private key
|
|
262
|
-
const privateKeyBytes = Random(32)
|
|
263
|
-
const privateKeyBigNum = new BigNumber(privateKeyBytes)
|
|
264
|
-
|
|
265
|
-
// Step 2: Get the secp256k1 curve and generator point
|
|
266
|
-
const curve = new Curve()
|
|
267
|
-
const generatorPoint = curve.g
|
|
268
|
-
|
|
269
|
-
// Step 3: Multiply generator point by private key to get public key point
|
|
270
|
-
const publicKeyPoint = generatorPoint.mul(privateKeyBigNum)
|
|
271
|
-
|
|
272
|
-
// Step 4: Create SDK objects for easier handling
|
|
273
|
-
const privateKey = new PrivateKey(privateKeyBigNum.toArray())
|
|
274
|
-
const publicKey = privateKey.toPublicKey()
|
|
275
|
-
|
|
276
|
-
// Step 5: Compare our manual calculation with the SDK
|
|
277
|
-
console.log('Private key:', privateKey.toString())
|
|
278
|
-
console.log('Public key:', publicKey.toString())
|
|
279
|
-
console.log('Manual point calculation:', publicKeyPoint.toString())
|
|
280
|
-
console.log('Manual calculation completed successfully')
|
|
281
|
-
|
|
282
|
-
return { privateKey, publicKey, privateKeyBigNum, publicKeyPoint }
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Run the example
|
|
286
|
-
const keyPair = generateKeyPairManually()
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
### Demonstrating ECDH Key Exchange
|
|
290
|
-
|
|
291
|
-
```typescript
|
|
292
|
-
function demonstrateECDH() {
|
|
293
|
-
console.log('\n=== ECDH Key Exchange Demonstration ===')
|
|
294
|
-
|
|
295
|
-
// Alice generates her key pair
|
|
296
|
-
const alicePrivate = PrivateKey.fromRandom()
|
|
297
|
-
const alicePublic = alicePrivate.toPublicKey()
|
|
298
|
-
|
|
299
|
-
// Bob generates his key pair
|
|
300
|
-
const bobPrivate = PrivateKey.fromRandom()
|
|
301
|
-
const bobPublic = bobPrivate.toPublicKey()
|
|
302
|
-
|
|
303
|
-
console.log('Alice public key:', alicePublic.toString())
|
|
304
|
-
console.log('Bob public key:', bobPublic.toString())
|
|
305
|
-
|
|
306
|
-
// Alice computes shared secret using Bob's public key
|
|
307
|
-
const aliceSharedSecret = alicePrivate.deriveSharedSecret(bobPublic)
|
|
308
|
-
|
|
309
|
-
// Bob computes shared secret using Alice's public key
|
|
310
|
-
const bobSharedSecret = bobPrivate.deriveSharedSecret(alicePublic)
|
|
311
|
-
|
|
312
|
-
// Verify the secrets match
|
|
313
|
-
const secretsMatch = aliceSharedSecret.toString() === bobSharedSecret.toString()
|
|
314
|
-
|
|
315
|
-
console.log('Alice shared secret:', aliceSharedSecret.toString())
|
|
316
|
-
console.log('Bob shared secret:', bobSharedSecret.toString())
|
|
317
|
-
console.log('Shared secrets match:', secretsMatch)
|
|
318
|
-
|
|
319
|
-
// Manual verification using low-level operations
|
|
320
|
-
const alicePrivateHex = alicePrivate.toString()
|
|
321
|
-
const bobPrivateHex = bobPrivate.toString()
|
|
322
|
-
const alicePrivateBN = new BigNumber(alicePrivateHex, 16)
|
|
323
|
-
const bobPrivateBN = new BigNumber(bobPrivateHex, 16)
|
|
324
|
-
|
|
325
|
-
// Create points from public keys manually
|
|
326
|
-
const curve = new Curve()
|
|
327
|
-
const alicePoint = curve.g.mul(alicePrivateBN)
|
|
328
|
-
const bobPoint = curve.g.mul(bobPrivateBN)
|
|
329
|
-
|
|
330
|
-
const manualAliceSecret = bobPoint.mul(alicePrivateBN)
|
|
331
|
-
const manualBobSecret = alicePoint.mul(bobPrivateBN)
|
|
332
|
-
|
|
333
|
-
console.log('Manual calculation also matches:',
|
|
334
|
-
manualAliceSecret.toString() === manualBobSecret.toString())
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Run the ECDH demonstration
|
|
338
|
-
demonstrateECDH()
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
### Point Arithmetic Examples
|
|
342
|
-
|
|
343
|
-
```typescript
|
|
344
|
-
function explorePointArithmetic() {
|
|
345
|
-
console.log('\n=== Point Arithmetic Examples ===')
|
|
346
|
-
|
|
347
|
-
const curve = new Curve()
|
|
348
|
-
const G = curve.g
|
|
349
|
-
|
|
350
|
-
// Create some example private keys
|
|
351
|
-
const k1 = new BigNumber(7)
|
|
352
|
-
const k2 = new BigNumber(11)
|
|
353
|
-
const k3 = new BigNumber(13)
|
|
354
|
-
|
|
355
|
-
// Generate corresponding public key points
|
|
356
|
-
const P1 = G.mul(k1) // 7 * G
|
|
357
|
-
const P2 = G.mul(k2) // 11 * G
|
|
358
|
-
const P3 = G.mul(k3) // 13 * G
|
|
359
|
-
|
|
360
|
-
console.log('P1 (7*G):', P1.toString())
|
|
361
|
-
console.log('P2 (11*G):', P2.toString())
|
|
362
|
-
console.log('P3 (13*G):', P3.toString())
|
|
363
|
-
|
|
364
|
-
// Demonstrate point addition
|
|
365
|
-
const P1_plus_P2 = P1.add(P2) // Should equal 18*G
|
|
366
|
-
const eighteen_G = G.mul(new BigNumber(18))
|
|
367
|
-
|
|
368
|
-
console.log('P1 + P2:', P1_plus_P2.toString())
|
|
369
|
-
console.log('18*G:', eighteen_G.toString())
|
|
370
|
-
console.log('P1 + P2 = 18*G:', P1_plus_P2.toString() === eighteen_G.toString())
|
|
371
|
-
|
|
372
|
-
// Demonstrate scalar multiplication
|
|
373
|
-
const double_P1 = P1.mul(new BigNumber(2)) // Should equal 14*G
|
|
374
|
-
const fourteen_G = G.mul(new BigNumber(14))
|
|
375
|
-
|
|
376
|
-
console.log('2*P1:', double_P1.toString())
|
|
377
|
-
console.log('14*G:', fourteen_G.toString())
|
|
378
|
-
console.log('2*P1 = 14*G:', double_P1.toString() === fourteen_G.toString())
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// Run the point arithmetic examples
|
|
382
|
-
explorePointArithmetic()
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
## Advanced Concepts
|
|
386
|
-
|
|
387
|
-
### Understanding Point Compression
|
|
388
|
-
|
|
389
|
-
Bitcoin public keys can be represented in compressed or uncompressed format:
|
|
390
|
-
|
|
391
|
-
```typescript
|
|
392
|
-
function demonstratePointCompression() {
|
|
393
|
-
console.log('\n=== Point Compression ===')
|
|
394
|
-
|
|
395
|
-
const privateKey = PrivateKey.fromRandom()
|
|
396
|
-
const publicKey = privateKey.toPublicKey()
|
|
397
|
-
|
|
398
|
-
// Get the public key in different formats
|
|
399
|
-
const publicKeyHex = publicKey.toString()
|
|
400
|
-
const publicKeyDER = publicKey.toDER()
|
|
401
|
-
|
|
402
|
-
console.log('Public key:', publicKeyHex)
|
|
403
|
-
console.log('Public key DER bytes:', publicKeyDER.length)
|
|
404
|
-
|
|
405
|
-
// We can work with the hex representation to understand compression
|
|
406
|
-
// Bitcoin public keys in compressed format are 33 bytes (66 hex chars)
|
|
407
|
-
const compressedLength = publicKeyHex.length / 2
|
|
408
|
-
console.log('Compressed key length:', compressedLength, 'bytes')
|
|
409
|
-
|
|
410
|
-
// The first byte indicates compression (02 or 03 for compressed)
|
|
411
|
-
const compressionByte = publicKeyHex.substring(0, 2)
|
|
412
|
-
console.log('Compression byte:', compressionByte)
|
|
413
|
-
console.log('Is compressed:', compressionByte === '02' || compressionByte === '03')
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
demonstratePointCompression()
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
### Working with Large Numbers in Practice
|
|
420
|
-
|
|
421
|
-
```typescript
|
|
422
|
-
function practicalBigNumberUsage() {
|
|
423
|
-
console.log('\n=== Practical BigNumber Usage ===')
|
|
424
|
-
|
|
425
|
-
// Bitcoin's maximum supply (21 million BTC in satoshis)
|
|
426
|
-
const maxBitcoinSupply = new BigNumber('2100000000000000')
|
|
427
|
-
console.log('Max Bitcoin supply (satoshis):', maxBitcoinSupply.toString())
|
|
428
|
-
|
|
429
|
-
// A typical transaction amount (100 satoshis, as used in tutorials)
|
|
430
|
-
const txAmount = new BigNumber(100)
|
|
431
|
-
|
|
432
|
-
// Calculate how many such transactions could theoretically exist
|
|
433
|
-
const maxTransactions = maxBitcoinSupply.div(txAmount)
|
|
434
|
-
console.log('Max 100-satoshi transactions:', maxTransactions.toString())
|
|
435
|
-
|
|
436
|
-
// Work with very large numbers for cryptographic operations
|
|
437
|
-
const largeNumber = new BigNumber(Random(32))
|
|
438
|
-
const veryLargeNumber = largeNumber.mul(largeNumber)
|
|
439
|
-
|
|
440
|
-
console.log('Large number:', largeNumber.toHex())
|
|
441
|
-
console.log('Very large number (squared):', veryLargeNumber.toHex())
|
|
442
|
-
|
|
443
|
-
// Demonstrate modular arithmetic (important for elliptic curves)
|
|
444
|
-
const modulus = new BigNumber('115792089237316195423570985008687907852837564279074904382605163141518161494337')
|
|
445
|
-
const reduced = veryLargeNumber.mod(modulus)
|
|
446
|
-
|
|
447
|
-
console.log('Reduced modulo curve order:', reduced.toHex())
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
practicalBigNumberUsage()
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
## Security Considerations
|
|
454
|
-
|
|
455
|
-
### Random Number Generation
|
|
456
|
-
|
|
457
|
-
```typescript
|
|
458
|
-
function secureRandomGeneration() {
|
|
459
|
-
console.log('\n=== Secure Random Number Generation ===')
|
|
460
|
-
|
|
461
|
-
// Always use cryptographically secure random number generation
|
|
462
|
-
const securePrivateKey = PrivateKey.fromRandom()
|
|
463
|
-
|
|
464
|
-
// Never use predictable sources for private keys
|
|
465
|
-
// BAD: const badPrivateKey = new PrivateKey(new BigNumber(12345))
|
|
466
|
-
|
|
467
|
-
console.log('Secure private key:', securePrivateKey.toString())
|
|
468
|
-
|
|
469
|
-
// Verify the key is in the valid range (1 to n-1, where n is the curve order)
|
|
470
|
-
const privateHex = securePrivateKey.toString()
|
|
471
|
-
const privateBN = new BigNumber(privateHex, 16)
|
|
472
|
-
const curveOrder = new BigNumber('115792089237316195423570985008687907852837564279074904382605163141518161494337')
|
|
473
|
-
|
|
474
|
-
const isValid = privateBN.gt(new BigNumber(0)) && privateBN.lt(curveOrder)
|
|
475
|
-
console.log('Private key is in valid range:', isValid)
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
secureRandomGeneration()
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
### Key Validation
|
|
482
|
-
|
|
483
|
-
```typescript
|
|
484
|
-
function validateKeys() {
|
|
485
|
-
console.log('\n=== Key Validation ===')
|
|
486
|
-
|
|
487
|
-
try {
|
|
488
|
-
// Generate a valid key pair
|
|
489
|
-
const privateKey = PrivateKey.fromRandom()
|
|
490
|
-
const publicKey = privateKey.toPublicKey()
|
|
491
|
-
|
|
492
|
-
// Verify the public key format
|
|
493
|
-
const publicKeyHex = publicKey.toString()
|
|
494
|
-
console.log('Public key:', publicKeyHex)
|
|
495
|
-
|
|
496
|
-
// We can manually verify the key is properly formatted
|
|
497
|
-
const isValidFormat = (publicKeyHex.length === 66) &&
|
|
498
|
-
(publicKeyHex.startsWith('02') || publicKeyHex.startsWith('03'))
|
|
499
|
-
console.log('Public key has valid compressed format:', isValidFormat)
|
|
500
|
-
|
|
501
|
-
// For full curve validation, we'd need to extract coordinates and verify y² = x³ + 7
|
|
502
|
-
// The SDK handles this validation internally
|
|
503
|
-
console.log('Key validation completed successfully')
|
|
504
|
-
|
|
505
|
-
} catch (error: any) {
|
|
506
|
-
console.error('Key validation error:', error.message)
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
validateKeys()
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
## Common Patterns and Best Practices
|
|
514
|
-
|
|
515
|
-
### 1. Always Use SDK Classes for Production Code
|
|
516
|
-
|
|
517
|
-
```typescript
|
|
518
|
-
// Good: Use SDK classes for safety and convenience
|
|
519
|
-
const privateKey = PrivateKey.fromRandom()
|
|
520
|
-
const publicKey = privateKey.toPublicKey()
|
|
521
|
-
|
|
522
|
-
// Advanced: Only use low-level classes when necessary
|
|
523
|
-
const curve = new Curve()
|
|
524
|
-
const privateHex = privateKey.toString()
|
|
525
|
-
const privateBN = new BigNumber(privateHex, 16)
|
|
526
|
-
const point = curve.g.mul(privateBN)
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
### 2. Proper Error Handling
|
|
530
|
-
|
|
531
|
-
```typescript
|
|
532
|
-
function safeKeyOperations() {
|
|
533
|
-
try {
|
|
534
|
-
const privateKey = PrivateKey.fromRandom()
|
|
535
|
-
const publicKey = privateKey.toPublicKey()
|
|
536
|
-
|
|
537
|
-
// Always validate inputs when working with external data
|
|
538
|
-
if (!privateKey || !publicKey) {
|
|
539
|
-
throw new Error('Failed to generate valid key pair')
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
console.log('Generated valid key pair successfully')
|
|
543
|
-
console.log('Private key:', privateKey.toString())
|
|
544
|
-
console.log('Public key:', publicKey.toString())
|
|
545
|
-
|
|
546
|
-
return { privateKey, publicKey }
|
|
547
|
-
} catch (error: any) {
|
|
548
|
-
console.error('Key generation failed:', error.message)
|
|
549
|
-
throw error
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
### 3. Memory Management for Large Numbers
|
|
555
|
-
|
|
556
|
-
```typescript
|
|
557
|
-
function efficientBigNumberUsage() {
|
|
558
|
-
// Reuse BigNumber instances when possible
|
|
559
|
-
const baseNumber = new BigNumber(Random(32))
|
|
560
|
-
|
|
561
|
-
// Chain operations efficiently
|
|
562
|
-
const result = baseNumber
|
|
563
|
-
.mul(new BigNumber(2))
|
|
564
|
-
.add(new BigNumber(1))
|
|
565
|
-
.mod(new BigNumber('115792089237316195423570985008687907852837564279074904382605163141518161494337'))
|
|
566
|
-
|
|
567
|
-
return result
|
|
568
|
-
}
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
## Summary
|
|
572
|
-
|
|
573
|
-
In this tutorial, you've learned:
|
|
574
|
-
|
|
575
|
-
1. **BigNumber Fundamentals**: How to work with large integers required for cryptographic operations
|
|
576
|
-
2. **Elliptic Curve Basics**: Understanding the secp256k1 curve used in Bitcoin
|
|
577
|
-
3. **Point Operations**: Addition, multiplication, and their cryptographic significance
|
|
578
|
-
4. **Key Relationships**: How private keys generate public keys through point multiplication
|
|
579
|
-
5. **ECDH Implementation**: Creating shared secrets using elliptic curve mathematics
|
|
580
|
-
6. **Security Practices**: Proper random number generation and key validation
|
|
581
|
-
7. **SDK Integration**: Using high-level classes while understanding the underlying mathematics
|
|
582
|
-
|
|
583
|
-
### Key Takeaways
|
|
584
|
-
|
|
585
|
-
- **One-way Function**: Private key → Public key is easy, reverse is computationally infeasible
|
|
586
|
-
- **Point Multiplication**: The foundation of all elliptic curve cryptography
|
|
587
|
-
- **ECDH Property**: (a × G) × b = (b × G) × a enables secure key exchange
|
|
588
|
-
- **SDK Safety**: Use `PrivateKey` and `PublicKey` classes for production code
|
|
589
|
-
- **Validation**: Always validate cryptographic inputs and handle errors properly
|
|
590
|
-
|
|
591
|
-
### Next Steps
|
|
592
|
-
|
|
593
|
-
Now that you understand elliptic curve fundamentals, you can explore:
|
|
594
|
-
|
|
595
|
-
- **[ECDH Key Exchange](./ecdh-key-exchange.md)**: Implementing secure communication protocols
|
|
596
|
-
- **[Signature Concepts](../concepts/signatures.md)**: Creating and verifying ECDSA signatures
|
|
597
|
-
- **[Key Management](./key-management.md)**: Generating multiple keys from a master key
|
|
598
|
-
|
|
599
|
-
The mathematical concepts you've learned here form the foundation for all advanced cryptographic operations in Bitcoin applications.
|
|
600
|
-
|
|
601
|
-
Understanding of `WalletClient` usage (for practical applications)
|
|
602
|
-
While the `WalletClient` abstracts these operations for convenience, understanding the underlying mathematics helps you make informed decisions about security and implementation.
|
|
603
|
-
|
|
604
|
-
## Integration with `WalletClient`
|
|
605
|
-
|
|
606
|
-
For production applications, the `WalletClient` provides secure key management:
|