or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bls-signatures.mdbls12-381.mdbn128.mdfields.mdindex.mdoptimized.mdsecp256k1.md

secp256k1.mddocs/

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

```