satoshi-proof-sdk 1.0.0
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/README.md +363 -0
- package/dist/bitcoin.d.ts +94 -0
- package/dist/bitcoin.js +280 -0
- package/dist/bitcoin.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# @satoshi-proof/sdk
|
|
2
|
+
|
|
3
|
+
**Bitcoin signature verification and proof generation SDK for Starknet**
|
|
4
|
+
|
|
5
|
+
This SDK implements BIP-137 Bitcoin signed message verification with Poseidon hashing, enabling trustless Bitcoin balance proofs on Starknet.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @satoshi-proof/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
yarn add @satoshi-proof/sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm add @satoshi-proof/sdk
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { generateProof } from '@satoshi-proof/sdk';
|
|
29
|
+
|
|
30
|
+
// User signs a message with their Bitcoin wallet
|
|
31
|
+
const message = "I own this Bitcoin address";
|
|
32
|
+
const signature = "H8k3..."; // Base64 signature from wallet
|
|
33
|
+
const btcBalance = 25.5; // BTC
|
|
34
|
+
|
|
35
|
+
// Generate cryptographic proof
|
|
36
|
+
const proof = generateProof(message, signature, btcBalance);
|
|
37
|
+
|
|
38
|
+
console.log(proof.btcAddress); // "1A1zP1..."
|
|
39
|
+
console.log(proof.bracketName); // "fish" (10-50 BTC)
|
|
40
|
+
console.log(proof.pubkeyHash); // Poseidon hash for on-chain verification
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## API Reference
|
|
46
|
+
|
|
47
|
+
### `generateProof(message, signature, btcBalance)`
|
|
48
|
+
|
|
49
|
+
Generate a complete cryptographic proof from a Bitcoin signed message.
|
|
50
|
+
|
|
51
|
+
**Parameters:**
|
|
52
|
+
- `message` (string): The message that was signed
|
|
53
|
+
- `signature` (string): Base64-encoded Bitcoin signature (BIP-137 format)
|
|
54
|
+
- `btcBalance` (number): Bitcoin balance in BTC
|
|
55
|
+
|
|
56
|
+
**Returns:** `ProofData`
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
interface ProofData {
|
|
60
|
+
message: string; // Original message
|
|
61
|
+
msgHash: string; // SHA256(SHA256(Bitcoin message format))
|
|
62
|
+
sigR: string; // ECDSA signature r component (hex)
|
|
63
|
+
sigS: string; // ECDSA signature s component (hex)
|
|
64
|
+
yParity: boolean; // Public key y-coordinate parity
|
|
65
|
+
pubkeyX: string; // Recovered public key x-coordinate (hex)
|
|
66
|
+
pubkeyY: string; // Recovered public key y-coordinate (hex)
|
|
67
|
+
pubkeyHash: string; // Poseidon hash of pubkey (for Starknet)
|
|
68
|
+
btcAddress: string; // Derived P2PKH Bitcoin address
|
|
69
|
+
bracket: number; // Bracket ID (0-4)
|
|
70
|
+
bracketName: string; // 'shrimp' | 'crab' | 'fish' | 'shark' | 'whale'
|
|
71
|
+
bracketEmoji: string; // 🦐 | 🦀 | 🐟 | 🦈 | 🐋
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### `getBracket(btcBalance)`
|
|
78
|
+
|
|
79
|
+
Determine the balance bracket based on BTC amount.
|
|
80
|
+
|
|
81
|
+
**Parameters:**
|
|
82
|
+
- `btcBalance` (number): Bitcoin balance in BTC
|
|
83
|
+
|
|
84
|
+
**Returns:** Bracket object
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
type Bracket = {
|
|
88
|
+
name: 'shrimp' | 'crab' | 'fish' | 'shark' | 'whale';
|
|
89
|
+
min: number;
|
|
90
|
+
max: number;
|
|
91
|
+
id: number;
|
|
92
|
+
emoji: string;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Bracket ranges:
|
|
96
|
+
// 🦐 shrimp: 0-1 BTC
|
|
97
|
+
// 🦀 crab: 1-10 BTC
|
|
98
|
+
// 🐟 fish: 10-50 BTC
|
|
99
|
+
// 🦈 shark: 50-100 BTC
|
|
100
|
+
// 🐋 whale: 100+ BTC
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### `parseSignature(base64Sig)`
|
|
106
|
+
|
|
107
|
+
Parse a base64 Bitcoin signature into its cryptographic components.
|
|
108
|
+
|
|
109
|
+
**Parameters:**
|
|
110
|
+
- `base64Sig` (string): Base64-encoded signature
|
|
111
|
+
|
|
112
|
+
**Returns:** `ParsedSignature`
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
interface ParsedSignature {
|
|
116
|
+
r: bigint; // ECDSA r component
|
|
117
|
+
s: bigint; // ECDSA s component
|
|
118
|
+
recoveryFlag: number; // 0 or 1 (for pubkey recovery)
|
|
119
|
+
yParity: boolean; // true if y-coordinate is odd
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
### `recoverPublicKey(msgHash, sig)`
|
|
126
|
+
|
|
127
|
+
Recover the secp256k1 public key from a message hash and signature.
|
|
128
|
+
|
|
129
|
+
**Parameters:**
|
|
130
|
+
- `msgHash` (Uint8Array): Bitcoin message hash (from `bitcoinMessageHash()`)
|
|
131
|
+
- `sig` (ParsedSignature): Parsed signature
|
|
132
|
+
|
|
133
|
+
**Returns:**
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
{
|
|
137
|
+
x: bigint; // Public key x-coordinate
|
|
138
|
+
y: bigint; // Public key y-coordinate
|
|
139
|
+
compressed: Uint8Array; // Compressed pubkey (33 bytes)
|
|
140
|
+
uncompressed: Uint8Array; // Uncompressed pubkey (65 bytes)
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### `pubkeyToPoseidonHash(x, y)`
|
|
147
|
+
|
|
148
|
+
Compute the Poseidon hash of a public key for Starknet on-chain verification.
|
|
149
|
+
|
|
150
|
+
**Parameters:**
|
|
151
|
+
- `x` (bigint): Public key x-coordinate
|
|
152
|
+
- `y` (bigint): Public key y-coordinate
|
|
153
|
+
|
|
154
|
+
**Returns:** Poseidon hash (hex string)
|
|
155
|
+
|
|
156
|
+
This matches the Cairo contract implementation:
|
|
157
|
+
```cairo
|
|
158
|
+
PoseidonTrait::new()
|
|
159
|
+
.update(x.low).update(x.high)
|
|
160
|
+
.update(y.low).update(y.high)
|
|
161
|
+
.finalize()
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### `bitcoinMessageHash(message)`
|
|
167
|
+
|
|
168
|
+
Compute the Bitcoin message hash following BIP-137 format.
|
|
169
|
+
|
|
170
|
+
**Parameters:**
|
|
171
|
+
- `message` (string): The message to hash
|
|
172
|
+
|
|
173
|
+
**Returns:** `Uint8Array` (32 bytes)
|
|
174
|
+
|
|
175
|
+
**Format:**
|
|
176
|
+
```
|
|
177
|
+
SHA256(SHA256("\x18Bitcoin Signed Message:\n" + varint(len) + message))
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### `pubkeyToP2PKH(compressedPubkey, testnet?)`
|
|
183
|
+
|
|
184
|
+
Derive a P2PKH Bitcoin address from a compressed public key.
|
|
185
|
+
|
|
186
|
+
**Parameters:**
|
|
187
|
+
- `compressedPubkey` (Uint8Array): 33-byte compressed public key
|
|
188
|
+
- `testnet` (boolean, optional): Use testnet version byte (default: false)
|
|
189
|
+
|
|
190
|
+
**Returns:** Bitcoin address (string)
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Code Examples
|
|
195
|
+
|
|
196
|
+
### Example 1: Verify a Bitcoin signature
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import {
|
|
200
|
+
bitcoinMessageHash,
|
|
201
|
+
parseSignature,
|
|
202
|
+
recoverPublicKey,
|
|
203
|
+
pubkeyToP2PKH
|
|
204
|
+
} from '@satoshi-proof/sdk';
|
|
205
|
+
|
|
206
|
+
const message = "Prove I own this address";
|
|
207
|
+
const signature = "H8k3Qn..."; // From Bitcoin wallet
|
|
208
|
+
|
|
209
|
+
// Step 1: Hash the message
|
|
210
|
+
const msgHash = bitcoinMessageHash(message);
|
|
211
|
+
|
|
212
|
+
// Step 2: Parse the signature
|
|
213
|
+
const sig = parseSignature(signature);
|
|
214
|
+
|
|
215
|
+
// Step 3: Recover the public key
|
|
216
|
+
const pubkey = recoverPublicKey(msgHash, sig);
|
|
217
|
+
|
|
218
|
+
// Step 4: Derive the Bitcoin address
|
|
219
|
+
const address = pubkeyToP2PKH(pubkey.compressed);
|
|
220
|
+
|
|
221
|
+
console.log(`Signer address: ${address}`);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
### Example 2: Generate proof for Starknet contract
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { generateProof } from '@satoshi-proof/sdk';
|
|
230
|
+
|
|
231
|
+
async function submitProof(message: string, signature: string, btcBalance: number) {
|
|
232
|
+
// Generate proof
|
|
233
|
+
const proof = generateProof(message, signature, btcBalance);
|
|
234
|
+
|
|
235
|
+
// Call Starknet contract
|
|
236
|
+
const tx = await contract.verify_signature({
|
|
237
|
+
msg_hash: proof.msgHash,
|
|
238
|
+
r: proof.sigR,
|
|
239
|
+
s: proof.sigS,
|
|
240
|
+
y_parity: proof.yParity,
|
|
241
|
+
expected_pubkey_hash: proof.pubkeyHash,
|
|
242
|
+
bracket: proof.bracket
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
console.log(`Proof submitted for ${proof.btcAddress}`);
|
|
246
|
+
console.log(`Bracket: ${proof.bracketEmoji} ${proof.bracketName}`);
|
|
247
|
+
|
|
248
|
+
return tx;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
### Example 3: Batch verify multiple signatures
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { generateProof, getBracket, BRACKETS } from '@satoshi-proof/sdk';
|
|
258
|
+
|
|
259
|
+
interface User {
|
|
260
|
+
message: string;
|
|
261
|
+
signature: string;
|
|
262
|
+
balance: number;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function processBatch(users: User[]) {
|
|
266
|
+
const results = users.map(user => {
|
|
267
|
+
try {
|
|
268
|
+
const proof = generateProof(user.message, user.signature, user.balance);
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
address: proof.btcAddress,
|
|
272
|
+
bracket: proof.bracketName,
|
|
273
|
+
pubkeyHash: proof.pubkeyHash,
|
|
274
|
+
valid: true
|
|
275
|
+
};
|
|
276
|
+
} catch (error) {
|
|
277
|
+
return {
|
|
278
|
+
address: null,
|
|
279
|
+
bracket: null,
|
|
280
|
+
pubkeyHash: null,
|
|
281
|
+
valid: false,
|
|
282
|
+
error: error.message
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Group by bracket
|
|
288
|
+
const byBracket = BRACKETS.map(bracket => ({
|
|
289
|
+
...bracket,
|
|
290
|
+
count: results.filter(r => r.bracket === bracket.name).length
|
|
291
|
+
}));
|
|
292
|
+
|
|
293
|
+
console.log('Distribution:', byBracket);
|
|
294
|
+
|
|
295
|
+
return results;
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Technical Details
|
|
302
|
+
|
|
303
|
+
### BIP-137 Bitcoin Signed Message Format
|
|
304
|
+
|
|
305
|
+
The SDK implements the standard Bitcoin message signing format:
|
|
306
|
+
|
|
307
|
+
1. **Message prefix**: `\x18Bitcoin Signed Message:\n`
|
|
308
|
+
2. **Length encoding**: Compact size varint
|
|
309
|
+
3. **Double SHA-256**: Hash the concatenated data twice
|
|
310
|
+
4. **Signature format**: 65 bytes (1 header byte + 32 bytes r + 32 bytes s)
|
|
311
|
+
|
|
312
|
+
### Signature Header Bytes
|
|
313
|
+
|
|
314
|
+
- **27-30**: Uncompressed public key
|
|
315
|
+
- **31-34**: Compressed public key
|
|
316
|
+
- **35-38**: Segwit P2SH-P2WPKH
|
|
317
|
+
- **39-42**: Segwit Bech32
|
|
318
|
+
|
|
319
|
+
Recovery flag = `(header - base) % 4`, where `base` is 27, 31, 35, or 39.
|
|
320
|
+
|
|
321
|
+
### Poseidon Hashing for Starknet
|
|
322
|
+
|
|
323
|
+
Public keys are hashed using Poseidon (Starknet's native hash function) by splitting each coordinate into 128-bit low/high components:
|
|
324
|
+
|
|
325
|
+
```
|
|
326
|
+
hash = Poseidon(x_low, x_high, y_low, y_high)
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
This allows efficient on-chain verification without storing full public keys.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Dependencies
|
|
334
|
+
|
|
335
|
+
- `@noble/curves` - secp256k1 cryptography
|
|
336
|
+
- `@noble/hashes` - SHA-256, RIPEMD-160
|
|
337
|
+
- `starknet` - Poseidon hashing
|
|
338
|
+
|
|
339
|
+
All dependencies are audited and widely used in production crypto applications.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## License
|
|
344
|
+
|
|
345
|
+
MIT
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Contributing
|
|
350
|
+
|
|
351
|
+
Issues and PRs welcome at [github.com/yourusername/satoshi-proof](https://github.com/yourusername/satoshi-proof)
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Security
|
|
356
|
+
|
|
357
|
+
This SDK handles cryptographic operations. Always:
|
|
358
|
+
- ✅ Verify signatures client-side before submitting to chain
|
|
359
|
+
- ✅ Use official Bitcoin wallets for signing
|
|
360
|
+
- ✅ Never share private keys
|
|
361
|
+
- ✅ Audit contract code before mainnet deployment
|
|
362
|
+
|
|
363
|
+
For security issues, please email: security@yourproject.com
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bitcoin Message Signing utilities
|
|
3
|
+
*
|
|
4
|
+
* Handles BIP-137 Bitcoin signed message format:
|
|
5
|
+
* 1. Message hash: SHA256(SHA256("\x18Bitcoin Signed Message:\n" + varint(len) + message))
|
|
6
|
+
* 2. Signature parsing: base64 → (r, s, recovery_flag)
|
|
7
|
+
* 3. Public key recovery from signature
|
|
8
|
+
* 4. Public key → Bitcoin address derivation
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Compute Bitcoin message hash (double SHA-256)
|
|
12
|
+
* Format: SHA256(SHA256("\x18Bitcoin Signed Message:\n" + varint(len) + message))
|
|
13
|
+
*/
|
|
14
|
+
export declare function bitcoinMessageHash(message: string): Uint8Array;
|
|
15
|
+
/**
|
|
16
|
+
* Convert message hash bytes to u256 hex string (for Starknet contract)
|
|
17
|
+
*/
|
|
18
|
+
export declare function hashToU256Hex(hash: Uint8Array): string;
|
|
19
|
+
export interface ParsedSignature {
|
|
20
|
+
r: bigint;
|
|
21
|
+
s: bigint;
|
|
22
|
+
recoveryFlag: number;
|
|
23
|
+
yParity: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse a base64 Bitcoin signature (BIP-137 format)
|
|
27
|
+
* First byte is the header: 27-30 (uncompressed), 31-34 (compressed)
|
|
28
|
+
* recovery_flag = (header - 27) % 4 for uncompressed
|
|
29
|
+
* recovery_flag = (header - 31) % 4 for compressed
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseSignature(base64Sig: string): ParsedSignature;
|
|
32
|
+
/**
|
|
33
|
+
* Recover the public key from a Bitcoin signed message
|
|
34
|
+
* Uses @noble/curves/secp256k1 Signature class with proper recovery
|
|
35
|
+
*/
|
|
36
|
+
export declare function recoverPublicKey(msgHash: Uint8Array, sig: ParsedSignature): {
|
|
37
|
+
x: bigint;
|
|
38
|
+
y: bigint;
|
|
39
|
+
compressed: Uint8Array;
|
|
40
|
+
uncompressed: Uint8Array;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Derive P2PKH Bitcoin address from compressed public key
|
|
44
|
+
*/
|
|
45
|
+
export declare function pubkeyToP2PKH(compressedPubkey: Uint8Array, testnet?: boolean): string;
|
|
46
|
+
export declare function pubkeyToHash160(compressedPubkey: Uint8Array): Uint8Array;
|
|
47
|
+
/**
|
|
48
|
+
* Derive P2WPKH (SegWit) address from compressed public key (bc1q...)
|
|
49
|
+
*/
|
|
50
|
+
export declare function pubkeyToP2WPKH(compressedPubkey: Uint8Array, testnet?: boolean): string;
|
|
51
|
+
/**
|
|
52
|
+
* Derive all address formats from a compressed public key
|
|
53
|
+
*/
|
|
54
|
+
export declare function pubkeyToAllAddresses(compressedPubkey: Uint8Array): {
|
|
55
|
+
p2pkh: string;
|
|
56
|
+
p2wpkh: string;
|
|
57
|
+
p2shP2wpkh: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Compute Poseidon hash of public key coordinates (for on-chain comparison)
|
|
61
|
+
* Matches the Cairo contract: PoseidonTrait::new().update(x.low).update(x.high).update(y.low).update(y.high).finalize()
|
|
62
|
+
*/
|
|
63
|
+
export declare function pubkeyToPoseidonHash(x: bigint, y: bigint): string;
|
|
64
|
+
export type Bracket = 'shrimp' | 'crab' | 'fish' | 'shark' | 'whale';
|
|
65
|
+
export declare const BRACKETS: {
|
|
66
|
+
name: Bracket;
|
|
67
|
+
min: number;
|
|
68
|
+
max: number;
|
|
69
|
+
id: number;
|
|
70
|
+
emoji: string;
|
|
71
|
+
}[];
|
|
72
|
+
export declare function getBracket(btcBalance: number): typeof BRACKETS[0];
|
|
73
|
+
/**
|
|
74
|
+
* Generate proof message with nonce for replay protection
|
|
75
|
+
*/
|
|
76
|
+
export declare function createProofMessage(contractAddress: string, nonce: number, chain?: string): string;
|
|
77
|
+
export interface ProofData {
|
|
78
|
+
message: string;
|
|
79
|
+
msgHash: string;
|
|
80
|
+
sigR: string;
|
|
81
|
+
sigS: string;
|
|
82
|
+
yParity: boolean;
|
|
83
|
+
pubkeyX: string;
|
|
84
|
+
pubkeyY: string;
|
|
85
|
+
pubkeyHash: string;
|
|
86
|
+
btcAddress: string;
|
|
87
|
+
bracket: number;
|
|
88
|
+
bracketName: string;
|
|
89
|
+
bracketEmoji: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Generate a complete proof from a Bitcoin signed message
|
|
93
|
+
*/
|
|
94
|
+
export declare function generateProof(message: string, base64Signature: string, btcBalance: number): ProofData;
|
package/dist/bitcoin.js
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bitcoin Message Signing utilities
|
|
3
|
+
*
|
|
4
|
+
* Handles BIP-137 Bitcoin signed message format:
|
|
5
|
+
* 1. Message hash: SHA256(SHA256("\x18Bitcoin Signed Message:\n" + varint(len) + message))
|
|
6
|
+
* 2. Signature parsing: base64 → (r, s, recovery_flag)
|
|
7
|
+
* 3. Public key recovery from signature
|
|
8
|
+
* 4. Public key → Bitcoin address derivation
|
|
9
|
+
*/
|
|
10
|
+
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
11
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
12
|
+
import { ripemd160 } from '@noble/hashes/legacy.js';
|
|
13
|
+
import { hash as starkHash } from 'starknet';
|
|
14
|
+
// ─── Bitcoin Message Hash ───
|
|
15
|
+
function varintBuf(n) {
|
|
16
|
+
if (n < 0xfd)
|
|
17
|
+
return new Uint8Array([n]);
|
|
18
|
+
if (n <= 0xffff) {
|
|
19
|
+
const buf = new Uint8Array(3);
|
|
20
|
+
buf[0] = 0xfd;
|
|
21
|
+
buf[1] = n & 0xff;
|
|
22
|
+
buf[2] = (n >> 8) & 0xff;
|
|
23
|
+
return buf;
|
|
24
|
+
}
|
|
25
|
+
throw new Error('Message too long');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compute Bitcoin message hash (double SHA-256)
|
|
29
|
+
* Format: SHA256(SHA256("\x18Bitcoin Signed Message:\n" + varint(len) + message))
|
|
30
|
+
*/
|
|
31
|
+
export function bitcoinMessageHash(message) {
|
|
32
|
+
const prefix = '\x18Bitcoin Signed Message:\n';
|
|
33
|
+
const prefixBuf = new TextEncoder().encode(prefix);
|
|
34
|
+
const msgBuf = new TextEncoder().encode(message);
|
|
35
|
+
const lenBuf = varintBuf(msgBuf.length);
|
|
36
|
+
const combined = new Uint8Array(prefixBuf.length + lenBuf.length + msgBuf.length);
|
|
37
|
+
combined.set(prefixBuf, 0);
|
|
38
|
+
combined.set(lenBuf, prefixBuf.length);
|
|
39
|
+
combined.set(msgBuf, prefixBuf.length + lenBuf.length);
|
|
40
|
+
return sha256(sha256(combined));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Convert message hash bytes to u256 hex string (for Starknet contract)
|
|
44
|
+
*/
|
|
45
|
+
export function hashToU256Hex(hash) {
|
|
46
|
+
return '0x' + Array.from(hash).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Parse a base64 Bitcoin signature (BIP-137 format)
|
|
50
|
+
* First byte is the header: 27-30 (uncompressed), 31-34 (compressed)
|
|
51
|
+
* recovery_flag = (header - 27) % 4 for uncompressed
|
|
52
|
+
* recovery_flag = (header - 31) % 4 for compressed
|
|
53
|
+
*/
|
|
54
|
+
export function parseSignature(base64Sig) {
|
|
55
|
+
const raw = Uint8Array.from(atob(base64Sig), c => c.charCodeAt(0));
|
|
56
|
+
if (raw.length !== 65)
|
|
57
|
+
throw new Error(`Invalid signature length: ${raw.length}`);
|
|
58
|
+
const header = raw[0];
|
|
59
|
+
let recoveryFlag;
|
|
60
|
+
if (header >= 27 && header <= 30) {
|
|
61
|
+
recoveryFlag = header - 27;
|
|
62
|
+
}
|
|
63
|
+
else if (header >= 31 && header <= 34) {
|
|
64
|
+
recoveryFlag = header - 31;
|
|
65
|
+
}
|
|
66
|
+
else if (header >= 35 && header <= 38) {
|
|
67
|
+
recoveryFlag = header - 35;
|
|
68
|
+
}
|
|
69
|
+
else if (header >= 39 && header <= 42) {
|
|
70
|
+
recoveryFlag = header - 39;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
throw new Error(`Unknown signature header: ${header}`);
|
|
74
|
+
}
|
|
75
|
+
const r = BigInt('0x' + toHex(raw.slice(1, 33)));
|
|
76
|
+
const s = BigInt('0x' + toHex(raw.slice(33, 65)));
|
|
77
|
+
return {
|
|
78
|
+
r,
|
|
79
|
+
s,
|
|
80
|
+
recoveryFlag: recoveryFlag % 2,
|
|
81
|
+
yParity: (recoveryFlag % 2) === 1,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// ─── Public Key Recovery ───
|
|
85
|
+
/**
|
|
86
|
+
* Recover the public key from a Bitcoin signed message
|
|
87
|
+
* Uses @noble/curves/secp256k1 Signature class with proper recovery
|
|
88
|
+
*/
|
|
89
|
+
export function recoverPublicKey(msgHash, sig) {
|
|
90
|
+
// Create Signature object with recovery bit
|
|
91
|
+
const signature = new secp256k1.Signature(sig.r, sig.s).addRecoveryBit(sig.recoveryFlag);
|
|
92
|
+
// Recover public key point
|
|
93
|
+
const point = signature.recoverPublicKey(msgHash);
|
|
94
|
+
const compressed = point.toRawBytes(true); // 33 bytes
|
|
95
|
+
const uncompressed = point.toRawBytes(false); // 65 bytes
|
|
96
|
+
return { x: point.x, y: point.y, compressed, uncompressed };
|
|
97
|
+
}
|
|
98
|
+
// ─── Helpers ───
|
|
99
|
+
function toHex(arr) {
|
|
100
|
+
return Array.from(arr).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
101
|
+
}
|
|
102
|
+
// ─── Bitcoin Address Derivation ───
|
|
103
|
+
/**
|
|
104
|
+
* Derive P2PKH Bitcoin address from compressed public key
|
|
105
|
+
*/
|
|
106
|
+
export function pubkeyToP2PKH(compressedPubkey, testnet = false) {
|
|
107
|
+
const hash1 = sha256(compressedPubkey);
|
|
108
|
+
const hash160 = ripemd160(hash1);
|
|
109
|
+
const version = testnet ? 0x6f : 0x00;
|
|
110
|
+
const payload = new Uint8Array(21);
|
|
111
|
+
payload[0] = version;
|
|
112
|
+
payload.set(hash160, 1);
|
|
113
|
+
return base58Check(payload);
|
|
114
|
+
}
|
|
115
|
+
export function pubkeyToHash160(compressedPubkey) {
|
|
116
|
+
return ripemd160(sha256(compressedPubkey));
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Derive P2WPKH (SegWit) address from compressed public key (bc1q...)
|
|
120
|
+
*/
|
|
121
|
+
export function pubkeyToP2WPKH(compressedPubkey, testnet = false) {
|
|
122
|
+
const hash160 = ripemd160(sha256(compressedPubkey));
|
|
123
|
+
const hrp = testnet ? 'tb' : 'bc';
|
|
124
|
+
return bech32Encode(hrp, 0, hash160);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Derive all address formats from a compressed public key
|
|
128
|
+
*/
|
|
129
|
+
export function pubkeyToAllAddresses(compressedPubkey) {
|
|
130
|
+
const hash160Val = ripemd160(sha256(compressedPubkey));
|
|
131
|
+
const p2pkhPayload = new Uint8Array(21);
|
|
132
|
+
p2pkhPayload[0] = 0x00;
|
|
133
|
+
p2pkhPayload.set(hash160Val, 1);
|
|
134
|
+
const p2pkh = base58Check(p2pkhPayload);
|
|
135
|
+
const p2wpkh = bech32Encode('bc', 0, hash160Val);
|
|
136
|
+
const redeemScript = new Uint8Array(22);
|
|
137
|
+
redeemScript[0] = 0x00;
|
|
138
|
+
redeemScript[1] = 0x14;
|
|
139
|
+
redeemScript.set(hash160Val, 2);
|
|
140
|
+
const scriptHash = ripemd160(sha256(redeemScript));
|
|
141
|
+
const p2shPayload = new Uint8Array(21);
|
|
142
|
+
p2shPayload[0] = 0x05;
|
|
143
|
+
p2shPayload.set(scriptHash, 1);
|
|
144
|
+
const p2shP2wpkh = base58Check(p2shPayload);
|
|
145
|
+
return { p2pkh, p2wpkh, p2shP2wpkh };
|
|
146
|
+
}
|
|
147
|
+
function bech32Encode(hrp, witnessVersion, data) {
|
|
148
|
+
const CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
|
|
149
|
+
const converted = convertBits(data, 8, 5, true);
|
|
150
|
+
const values = [witnessVersion, ...converted];
|
|
151
|
+
const polymod = bech32Polymod(hrpExpand(hrp).concat(values).concat([0, 0, 0, 0, 0, 0])) ^ 1;
|
|
152
|
+
const checksum = [];
|
|
153
|
+
for (let i = 0; i < 6; i++)
|
|
154
|
+
checksum.push((polymod >> (5 * (5 - i))) & 31);
|
|
155
|
+
return hrp + '1' + values.concat(checksum).map(v => CHARSET[v]).join('');
|
|
156
|
+
}
|
|
157
|
+
function convertBits(data, fromBits, toBits, pad) {
|
|
158
|
+
let acc = 0, bits = 0;
|
|
159
|
+
const ret = [];
|
|
160
|
+
const maxv = (1 << toBits) - 1;
|
|
161
|
+
for (const value of data) {
|
|
162
|
+
acc = (acc << fromBits) | value;
|
|
163
|
+
bits += fromBits;
|
|
164
|
+
while (bits >= toBits) {
|
|
165
|
+
bits -= toBits;
|
|
166
|
+
ret.push((acc >> bits) & maxv);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (pad && bits > 0)
|
|
170
|
+
ret.push((acc << (toBits - bits)) & maxv);
|
|
171
|
+
return ret;
|
|
172
|
+
}
|
|
173
|
+
function hrpExpand(hrp) {
|
|
174
|
+
const ret = [];
|
|
175
|
+
for (let i = 0; i < hrp.length; i++)
|
|
176
|
+
ret.push(hrp.charCodeAt(i) >> 5);
|
|
177
|
+
ret.push(0);
|
|
178
|
+
for (let i = 0; i < hrp.length; i++)
|
|
179
|
+
ret.push(hrp.charCodeAt(i) & 31);
|
|
180
|
+
return ret;
|
|
181
|
+
}
|
|
182
|
+
function bech32Polymod(values) {
|
|
183
|
+
const GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
|
|
184
|
+
let chk = 1;
|
|
185
|
+
for (const v of values) {
|
|
186
|
+
const b = chk >> 25;
|
|
187
|
+
chk = ((chk & 0x1ffffff) << 5) ^ v;
|
|
188
|
+
for (let i = 0; i < 5; i++)
|
|
189
|
+
if ((b >> i) & 1)
|
|
190
|
+
chk ^= GEN[i];
|
|
191
|
+
}
|
|
192
|
+
return chk;
|
|
193
|
+
}
|
|
194
|
+
// Base58Check encoding
|
|
195
|
+
const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
196
|
+
function base58Check(payload) {
|
|
197
|
+
const checksum = sha256(sha256(payload)).slice(0, 4);
|
|
198
|
+
const data = new Uint8Array(payload.length + 4);
|
|
199
|
+
data.set(payload, 0);
|
|
200
|
+
data.set(checksum, payload.length);
|
|
201
|
+
let num = 0n;
|
|
202
|
+
for (const byte of data)
|
|
203
|
+
num = num * 256n + BigInt(byte);
|
|
204
|
+
let result = '';
|
|
205
|
+
while (num > 0n) {
|
|
206
|
+
const rem = Number(num % 58n);
|
|
207
|
+
result = BASE58_ALPHABET[rem] + result;
|
|
208
|
+
num = num / 58n;
|
|
209
|
+
}
|
|
210
|
+
for (const byte of data) {
|
|
211
|
+
if (byte !== 0)
|
|
212
|
+
break;
|
|
213
|
+
result = '1' + result;
|
|
214
|
+
}
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
// ─── Starknet Integration ───
|
|
218
|
+
/**
|
|
219
|
+
* Compute Poseidon hash of public key coordinates (for on-chain comparison)
|
|
220
|
+
* Matches the Cairo contract: PoseidonTrait::new().update(x.low).update(x.high).update(y.low).update(y.high).finalize()
|
|
221
|
+
*/
|
|
222
|
+
export function pubkeyToPoseidonHash(x, y) {
|
|
223
|
+
const xLow = x & ((1n << 128n) - 1n);
|
|
224
|
+
const xHigh = x >> 128n;
|
|
225
|
+
const yLow = y & ((1n << 128n) - 1n);
|
|
226
|
+
const yHigh = y >> 128n;
|
|
227
|
+
return starkHash.computePoseidonHashOnElements([
|
|
228
|
+
'0x' + xLow.toString(16),
|
|
229
|
+
'0x' + xHigh.toString(16),
|
|
230
|
+
'0x' + yLow.toString(16),
|
|
231
|
+
'0x' + yHigh.toString(16),
|
|
232
|
+
]);
|
|
233
|
+
}
|
|
234
|
+
export const BRACKETS = [
|
|
235
|
+
{ name: 'shrimp', min: 0, max: 1, id: 0, emoji: '🦐' },
|
|
236
|
+
{ name: 'crab', min: 1, max: 10, id: 1, emoji: '🦀' },
|
|
237
|
+
{ name: 'fish', min: 10, max: 50, id: 2, emoji: '🐟' },
|
|
238
|
+
{ name: 'shark', min: 50, max: 100, id: 3, emoji: '🦈' },
|
|
239
|
+
{ name: 'whale', min: 100, max: Infinity, id: 4, emoji: '🐋' },
|
|
240
|
+
];
|
|
241
|
+
export function getBracket(btcBalance) {
|
|
242
|
+
for (let i = BRACKETS.length - 1; i >= 0; i--) {
|
|
243
|
+
if (btcBalance >= BRACKETS[i].min)
|
|
244
|
+
return BRACKETS[i];
|
|
245
|
+
}
|
|
246
|
+
return BRACKETS[0];
|
|
247
|
+
}
|
|
248
|
+
// ─── Proof Message Format ───
|
|
249
|
+
/**
|
|
250
|
+
* Generate proof message with nonce for replay protection
|
|
251
|
+
*/
|
|
252
|
+
export function createProofMessage(contractAddress, nonce, chain = 'SN_SEPOLIA') {
|
|
253
|
+
return `Satoshi Proof v1 | Chain: ${chain} | Contract: ${contractAddress} | Nonce: ${nonce} | `;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Generate a complete proof from a Bitcoin signed message
|
|
257
|
+
*/
|
|
258
|
+
export function generateProof(message, base64Signature, btcBalance) {
|
|
259
|
+
const msgHash = bitcoinMessageHash(message);
|
|
260
|
+
const sig = parseSignature(base64Signature);
|
|
261
|
+
const pubkey = recoverPublicKey(msgHash, sig);
|
|
262
|
+
const btcAddress = pubkeyToP2PKH(pubkey.compressed);
|
|
263
|
+
const pubkeyHash = pubkeyToPoseidonHash(pubkey.x, pubkey.y);
|
|
264
|
+
const bracket = getBracket(btcBalance);
|
|
265
|
+
return {
|
|
266
|
+
message,
|
|
267
|
+
msgHash: hashToU256Hex(msgHash),
|
|
268
|
+
sigR: '0x' + sig.r.toString(16),
|
|
269
|
+
sigS: '0x' + sig.s.toString(16),
|
|
270
|
+
yParity: sig.yParity,
|
|
271
|
+
pubkeyX: '0x' + pubkey.x.toString(16),
|
|
272
|
+
pubkeyY: '0x' + pubkey.y.toString(16),
|
|
273
|
+
pubkeyHash,
|
|
274
|
+
btcAddress,
|
|
275
|
+
bracket: bracket.id,
|
|
276
|
+
bracketName: bracket.name,
|
|
277
|
+
bracketEmoji: bracket.emoji,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=bitcoin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitcoin.js","sourceRoot":"","sources":["../src/bitcoin.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @satoshi-proof/sdk
|
|
3
|
+
*
|
|
4
|
+
* Bitcoin signature verification and proof generation for Starknet
|
|
5
|
+
* Implements BIP-137 Bitcoin signed message verification with Poseidon hashing
|
|
6
|
+
*/
|
|
7
|
+
export { generateProof, getBracket, bitcoinMessageHash, hashToU256Hex, parseSignature, recoverPublicKey, pubkeyToP2PKH, pubkeyToP2WPKH, pubkeyToAllAddresses, pubkeyToHash160, pubkeyToPoseidonHash, type ParsedSignature, type ProofData, type Bracket, BRACKETS, } from './bitcoin.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @satoshi-proof/sdk
|
|
3
|
+
*
|
|
4
|
+
* Bitcoin signature verification and proof generation for Starknet
|
|
5
|
+
* Implements BIP-137 Bitcoin signed message verification with Poseidon hashing
|
|
6
|
+
*/
|
|
7
|
+
export {
|
|
8
|
+
// Core functions
|
|
9
|
+
generateProof, getBracket,
|
|
10
|
+
// Bitcoin utilities
|
|
11
|
+
bitcoinMessageHash, hashToU256Hex, parseSignature, recoverPublicKey, pubkeyToP2PKH, pubkeyToP2WPKH, pubkeyToAllAddresses, pubkeyToHash160, pubkeyToPoseidonHash,
|
|
12
|
+
// Constants
|
|
13
|
+
BRACKETS, } from './bitcoin.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO;AACL,iBAAiB;AACjB,aAAa,EACb,UAAU;AAEV,oBAAoB;AACpB,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,oBAAoB;AAOpB,YAAY;AACZ,QAAQ,GACT,MAAM,cAAc,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "satoshi-proof-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Bitcoin signature verification and proof generation SDK for Starknet - implements BIP-137 message signing with Poseidon hashing",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"test": "vitest run"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"bitcoin",
|
|
24
|
+
"signature",
|
|
25
|
+
"bip137",
|
|
26
|
+
"starknet",
|
|
27
|
+
"poseidon",
|
|
28
|
+
"proof",
|
|
29
|
+
"secp256k1",
|
|
30
|
+
"verification"
|
|
31
|
+
],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@noble/hashes": "^2.0.1",
|
|
36
|
+
"@noble/secp256k1": "^3.0.0",
|
|
37
|
+
"starknet": "^7.6.4"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^25.3.3",
|
|
41
|
+
"typescript": "^5.9.3",
|
|
42
|
+
"vitest": "^4.0.18"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/yourusername/satoshi-proof"
|
|
47
|
+
},
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/yourusername/satoshi-proof/issues"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/yourusername/satoshi-proof#readme"
|
|
52
|
+
}
|