0
# secp256k1
1
2
Bitcoin's elliptic curve operations providing ECDSA (Elliptic Curve Digital Signature Algorithm) functionality, key generation, and signature recovery. This is the same curve used in Bitcoin and Ethereum for transaction signatures.
3
4
## Constants
5
6
```python { .api }
7
# Curve parameters
8
P: int # Field modulus: 2^256 - 2^32 - 977
9
N: int # Curve order: 115792089237316195423570985008687907852837564279074904382605163141518161494337
10
A: int # Curve coefficient a: 0
11
B: int # Curve coefficient b: 7
12
G: Tuple[int, int] # Generator point coordinates
13
```
14
15
## Capabilities
16
17
### Key Operations
18
19
Convert between private keys and public keys, and perform basic key validation.
20
21
```python { .api }
22
def privtopub(privkey: bytes) -> Tuple[int, int]:
23
"""
24
Convert a private key to its corresponding public key point.
25
26
Args:
27
privkey (bytes): 32-byte private key
28
29
Returns:
30
Tuple[int, int]: Public key as (x, y) coordinates
31
"""
32
```
33
34
### ECDSA Signing
35
36
Sign message hashes using ECDSA with deterministic k-value generation according to RFC 6979.
37
38
```python { .api }
39
def ecdsa_raw_sign(msghash: bytes, priv: bytes) -> Tuple[int, int, int]:
40
"""
41
Sign a message hash using ECDSA.
42
43
Args:
44
msghash (bytes): 32-byte hash of the message to sign
45
priv (bytes): 32-byte private key
46
47
Returns:
48
Tuple[int, int, int]: (v, r, s) signature components where:
49
- v: recovery parameter (27 or 28)
50
- r: signature r component
51
- s: signature s component
52
"""
53
```
54
55
### ECDSA Recovery
56
57
Recover the public key from a signature and message hash, enabling verification without storing public keys.
58
59
```python { .api }
60
def ecdsa_raw_recover(msghash: bytes, vrs: Tuple[int, int, int]) -> Tuple[int, int]:
61
"""
62
Recover the public key from an ECDSA signature.
63
64
Args:
65
msghash (bytes): 32-byte hash of the original message
66
vrs (Tuple[int, int, int]): (v, r, s) signature components
67
68
Returns:
69
Tuple[int, int]: Recovered public key as (x, y) coordinates
70
"""
71
```
72
73
### Point Arithmetic
74
75
Low-level elliptic curve point operations for custom cryptographic protocols.
76
77
```python { .api }
78
def multiply(a: Tuple[int, int], n: int) -> Tuple[int, int]:
79
"""
80
Multiply a point by a scalar (point * scalar).
81
82
Args:
83
a (Tuple[int, int]): Point as (x, y) coordinates
84
n (int): Scalar multiplier
85
86
Returns:
87
Tuple[int, int]: Resulting point coordinates
88
"""
89
90
def add(a: Tuple[int, int], b: Tuple[int, int]) -> Tuple[int, int]:
91
"""
92
Add two elliptic curve points.
93
94
Args:
95
a (Tuple[int, int]): First point as (x, y) coordinates
96
b (Tuple[int, int]): Second point as (x, y) coordinates
97
98
Returns:
99
Tuple[int, int]: Sum of the two points
100
"""
101
```
102
103
### Low-Level Operations
104
105
Internal operations for advanced use cases and custom implementations.
106
107
```python { .api }
108
def to_jacobian(p: Tuple[int, int]) -> Tuple[int, int, int]:
109
"""Convert point from affine to Jacobian coordinates."""
110
111
def from_jacobian(p: Tuple[int, int, int]) -> Tuple[int, int]:
112
"""Convert point from Jacobian to affine coordinates."""
113
114
def jacobian_double(p: Tuple[int, int, int]) -> Tuple[int, int, int]:
115
"""Double a point in Jacobian coordinates."""
116
117
def jacobian_add(p: Tuple[int, int, int], q: Tuple[int, int, int]) -> Tuple[int, int, int]:
118
"""Add two points in Jacobian coordinates."""
119
120
def jacobian_multiply(a: Tuple[int, int, int], n: int) -> Tuple[int, int, int]:
121
"""Multiply a point by scalar in Jacobian coordinates."""
122
123
def inv(a: int, n: int) -> int:
124
"""Modular inverse using extended Euclidean algorithm."""
125
126
def bytes_to_int(x: bytes) -> int:
127
"""Convert bytes to integer."""
128
129
def deterministic_generate_k(msghash: bytes, priv: bytes) -> int:
130
"""Generate deterministic k value for ECDSA signing (RFC 6979)."""
131
```
132
133
## Usage Examples
134
135
### Basic Key Generation and Signing
136
137
```python
138
from py_ecc.secp256k1 import privtopub, ecdsa_raw_sign, ecdsa_raw_recover
139
import os
140
import hashlib
141
142
# Generate a random private key
143
private_key = os.urandom(32)
144
print(f"Private key: {private_key.hex()}")
145
146
# Derive public key
147
public_key = privtopub(private_key)
148
print(f"Public key: ({public_key[0]}, {public_key[1]})")
149
150
# Sign a message
151
message = b"Hello, secp256k1!"
152
message_hash = hashlib.sha256(message).digest()
153
v, r, s = ecdsa_raw_sign(message_hash, private_key)
154
print(f"Signature: v={v}, r={r}, s={s}")
155
156
# Recover public key from signature
157
recovered_pubkey = ecdsa_raw_recover(message_hash, (v, r, s))
158
assert recovered_pubkey == public_key
159
print("Signature verification successful!")
160
```
161
162
### Point Arithmetic
163
164
```python
165
from py_ecc.secp256k1 import G, multiply, add
166
167
# Generate some points
168
point1 = multiply(G, 123) # 123 * G
169
point2 = multiply(G, 456) # 456 * G
170
171
# Add points
172
sum_point = add(point1, point2)
173
174
# This should equal (123 + 456) * G
175
expected = multiply(G, 123 + 456)
176
assert sum_point == expected
177
print("Point arithmetic verified!")
178
```
179
180
### Bitcoin-style Address Generation
181
182
```python
183
from py_ecc.secp256k1 import privtopub
184
import hashlib
185
186
def pubkey_to_address(pubkey):
187
"""Convert secp256k1 public key to Bitcoin address format."""
188
# Compress public key
189
x, y = pubkey
190
if y % 2 == 0:
191
compressed = b'\x02' + x.to_bytes(32, 'big')
192
else:
193
compressed = b'\x03' + x.to_bytes(32, 'big')
194
195
# Hash with SHA256 then RIPEMD160
196
sha256_hash = hashlib.sha256(compressed).digest()
197
ripemd160 = hashlib.new('ripemd160', sha256_hash).digest()
198
199
return ripemd160
200
201
# Example usage
202
private_key = b'\x01' * 32 # Don't use this in production!
203
public_key = privtopub(private_key)
204
address_hash = pubkey_to_address(public_key)
205
print(f"Address hash: {address_hash.hex()}")
206
```
207
208
### Signature Verification (Manual)
209
210
```python
211
from py_ecc.secp256k1 import ecdsa_raw_sign, ecdsa_raw_recover
212
import hashlib
213
214
def verify_signature(message_hash, signature, expected_pubkey):
215
"""Manually verify an ECDSA signature."""
216
try:
217
recovered_pubkey = ecdsa_raw_recover(message_hash, signature)
218
return recovered_pubkey == expected_pubkey
219
except:
220
return False
221
222
# Example
223
private_key = b'\x12' * 32
224
public_key = privtopub(private_key)
225
message = b"Test message"
226
message_hash = hashlib.sha256(message).digest()
227
228
# Sign
229
signature = ecdsa_raw_sign(message_hash, private_key)
230
231
# Verify
232
is_valid = verify_signature(message_hash, signature, public_key)
233
print(f"Signature valid: {is_valid}")
234
```
235
236
## Types
237
238
```python { .api }
239
from typing import Tuple
240
241
# Point representations
242
PlainPoint2D = Tuple[int, int] # Affine coordinates (x, y)
243
PlainPoint3D = Tuple[int, int, int] # Jacobian coordinates (x, y, z)
244
```
245
246
## Error Handling
247
248
The secp256k1 module functions may raise various exceptions for invalid inputs:
249
250
- `ValueError`: For invalid point coordinates or parameters
251
- `ZeroDivisionError`: For degenerate cases in point operations
252
- Mathematical errors for invalid curve operations
253
254
Always validate inputs when working with untrusted data:
255
256
```python
257
from py_ecc.secp256k1 import privtopub, ecdsa_raw_recover
258
259
try:
260
# Validate private key range
261
if not (1 <= int.from_bytes(private_key, 'big') < N):
262
raise ValueError("Private key out of range")
263
264
public_key = privtopub(private_key)
265
recovered = ecdsa_raw_recover(message_hash, signature)
266
except ValueError as e:
267
print(f"Invalid input: {e}")
268
except Exception as e:
269
print(f"Cryptographic error: {e}")
270
```