CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-py-ecc

Elliptic curve crypto in python including secp256k1, alt_bn128, and bls12_381

Pending
Overview
Eval results
Files

secp256k1.mddocs/

secp256k1

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.

Constants

# Curve parameters
P: int  # Field modulus: 2^256 - 2^32 - 977
N: int  # Curve order: 115792089237316195423570985008687907852837564279074904382605163141518161494337
A: int  # Curve coefficient a: 0
B: int  # Curve coefficient b: 7
G: Tuple[int, int]  # Generator point coordinates

Capabilities

Key Operations

Convert between private keys and public keys, and perform basic key validation.

def privtopub(privkey: bytes) -> Tuple[int, int]:
    """
    Convert a private key to its corresponding public key point.
    
    Args:
        privkey (bytes): 32-byte private key
        
    Returns:
        Tuple[int, int]: Public key as (x, y) coordinates
    """

ECDSA Signing

Sign message hashes using ECDSA with deterministic k-value generation according to RFC 6979.

def ecdsa_raw_sign(msghash: bytes, priv: bytes) -> Tuple[int, int, int]:
    """
    Sign a message hash using ECDSA.
    
    Args:
        msghash (bytes): 32-byte hash of the message to sign
        priv (bytes): 32-byte private key
        
    Returns:
        Tuple[int, int, int]: (v, r, s) signature components where:
            - v: recovery parameter (27 or 28)
            - r: signature r component
            - s: signature s component
    """

ECDSA Recovery

Recover the public key from a signature and message hash, enabling verification without storing public keys.

def ecdsa_raw_recover(msghash: bytes, vrs: Tuple[int, int, int]) -> Tuple[int, int]:
    """
    Recover the public key from an ECDSA signature.
    
    Args:
        msghash (bytes): 32-byte hash of the original message
        vrs (Tuple[int, int, int]): (v, r, s) signature components
        
    Returns:
        Tuple[int, int]: Recovered public key as (x, y) coordinates
    """

Point Arithmetic

Low-level elliptic curve point operations for custom cryptographic protocols.

def multiply(a: Tuple[int, int], n: int) -> Tuple[int, int]:
    """
    Multiply a point by a scalar (point * scalar).
    
    Args:
        a (Tuple[int, int]): Point as (x, y) coordinates
        n (int): Scalar multiplier
        
    Returns:
        Tuple[int, int]: Resulting point coordinates
    """

def add(a: Tuple[int, int], b: Tuple[int, int]) -> Tuple[int, int]:
    """
    Add two elliptic curve points.
    
    Args:
        a (Tuple[int, int]): First point as (x, y) coordinates
        b (Tuple[int, int]): Second point as (x, y) coordinates
        
    Returns:
        Tuple[int, int]: Sum of the two points
    """

Low-Level Operations

Internal operations for advanced use cases and custom implementations.

def to_jacobian(p: Tuple[int, int]) -> Tuple[int, int, int]:
    """Convert point from affine to Jacobian coordinates."""

def from_jacobian(p: Tuple[int, int, int]) -> Tuple[int, int]:
    """Convert point from Jacobian to affine coordinates."""

def jacobian_double(p: Tuple[int, int, int]) -> Tuple[int, int, int]:
    """Double a point in Jacobian coordinates."""

def jacobian_add(p: Tuple[int, int, int], q: Tuple[int, int, int]) -> Tuple[int, int, int]:
    """Add two points in Jacobian coordinates."""

def jacobian_multiply(a: Tuple[int, int, int], n: int) -> Tuple[int, int, int]:
    """Multiply a point by scalar in Jacobian coordinates."""

def inv(a: int, n: int) -> int:
    """Modular inverse using extended Euclidean algorithm."""

def bytes_to_int(x: bytes) -> int:
    """Convert bytes to integer."""

def deterministic_generate_k(msghash: bytes, priv: bytes) -> int:
    """Generate deterministic k value for ECDSA signing (RFC 6979)."""

Usage Examples

Basic Key Generation and Signing

from py_ecc.secp256k1 import privtopub, ecdsa_raw_sign, ecdsa_raw_recover
import os
import hashlib

# Generate a random private key
private_key = os.urandom(32)
print(f"Private key: {private_key.hex()}")

# Derive public key
public_key = privtopub(private_key)
print(f"Public key: ({public_key[0]}, {public_key[1]})")

# Sign a message
message = b"Hello, secp256k1!"
message_hash = hashlib.sha256(message).digest()
v, r, s = ecdsa_raw_sign(message_hash, private_key)
print(f"Signature: v={v}, r={r}, s={s}")

# Recover public key from signature
recovered_pubkey = ecdsa_raw_recover(message_hash, (v, r, s))
assert recovered_pubkey == public_key
print("Signature verification successful!")

Point Arithmetic

from py_ecc.secp256k1 import G, multiply, add

# Generate some points
point1 = multiply(G, 123)  # 123 * G
point2 = multiply(G, 456)  # 456 * G

# Add points
sum_point = add(point1, point2)

# This should equal (123 + 456) * G
expected = multiply(G, 123 + 456)
assert sum_point == expected
print("Point arithmetic verified!")

Bitcoin-style Address Generation

from py_ecc.secp256k1 import privtopub
import hashlib

def pubkey_to_address(pubkey):
    """Convert secp256k1 public key to Bitcoin address format."""
    # Compress public key
    x, y = pubkey
    if y % 2 == 0:
        compressed = b'\x02' + x.to_bytes(32, 'big')
    else:
        compressed = b'\x03' + x.to_bytes(32, 'big')
    
    # Hash with SHA256 then RIPEMD160
    sha256_hash = hashlib.sha256(compressed).digest()
    ripemd160 = hashlib.new('ripemd160', sha256_hash).digest()
    
    return ripemd160

# Example usage
private_key = b'\x01' * 32  # Don't use this in production!
public_key = privtopub(private_key)
address_hash = pubkey_to_address(public_key)
print(f"Address hash: {address_hash.hex()}")

Signature Verification (Manual)

from py_ecc.secp256k1 import ecdsa_raw_sign, ecdsa_raw_recover
import hashlib

def verify_signature(message_hash, signature, expected_pubkey):
    """Manually verify an ECDSA signature."""
    try:
        recovered_pubkey = ecdsa_raw_recover(message_hash, signature)
        return recovered_pubkey == expected_pubkey
    except:
        return False

# Example
private_key = b'\x12' * 32
public_key = privtopub(private_key)
message = b"Test message"
message_hash = hashlib.sha256(message).digest()

# Sign
signature = ecdsa_raw_sign(message_hash, private_key)

# Verify
is_valid = verify_signature(message_hash, signature, public_key)
print(f"Signature valid: {is_valid}")

Types

from typing import Tuple

# Point representations
PlainPoint2D = Tuple[int, int]  # Affine coordinates (x, y)
PlainPoint3D = Tuple[int, int, int]  # Jacobian coordinates (x, y, z)

Error Handling

The secp256k1 module functions may raise various exceptions for invalid inputs:

  • ValueError: For invalid point coordinates or parameters
  • ZeroDivisionError: For degenerate cases in point operations
  • Mathematical errors for invalid curve operations

Always validate inputs when working with untrusted data:

from py_ecc.secp256k1 import privtopub, ecdsa_raw_recover

try:
    # Validate private key range
    if not (1 <= int.from_bytes(private_key, 'big') < N):
        raise ValueError("Private key out of range")
    
    public_key = privtopub(private_key)
    recovered = ecdsa_raw_recover(message_hash, signature)
except ValueError as e:
    print(f"Invalid input: {e}")
except Exception as e:
    print(f"Cryptographic error: {e}")

Install with Tessl CLI

npx tessl i tessl/pypi-py-ecc

docs

bls-signatures.md

bls12-381.md

bn128.md

fields.md

index.md

optimized.md

secp256k1.md

tile.json