Skip to content
Fetching contributors… Cannot retrieve contributors at this time
135 lines (102 sloc) 3.32 KB
 """ Stealth addresses in bitcoin Basically a diffie-hellman with extra steps """ import math import web3 import hashlib import functools import ecdsa from random import randint from web3 import Web3 from typing import Tuple, List, Union from py_ecc import bn128 from py_ecc.bn128 import FQ, add, multiply, double from py_ecc.bn128.bn128_field_elements import inv # Signature :: (Initial construction value, array of public keys, link of unique signer) Point = Tuple[int, int] Signature = Tuple[int, List[int], Point] Scalar = int asint = lambda x: x.n if isinstance(x, bn128.FQ) else x fq2point = lambda x: (asint(x), asint(x)) randsn = lambda: randint(1, N - 1) randsp = lambda: randint(1, P - 1) sbmul = lambda s: bn128.multiply(G, asint(s)) addmodn = lambda x, y: (x + y) % N addmodp = lambda x, y: (x + y) % P mulmodn = lambda x, y: (x * y) % N mulmodp = lambda x, y: (x * y) % P submodn = lambda x, y: (x - y) % N submodp = lambda x, y: (x - y) % P invmodn = lambda x: inv(x, N) invmodp = lambda x: inv(x, P) negp = lambda x: (x, -x) G: Point = fq2point(bn128.G1) N: int = bn128.curve_order P: int = bn128.field_modulus A: int = 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52 MASK: int = 0x8000000000000000000000000000000000000000000000000000000000000000 def hash_int(i: int) -> int: """ Hashes int and returns """ b = "0x" + i.encode('utf-8').hex() return int( Web3.soliditySha3(["bytes"], [b]).hex(), 16 ) % N def decode_int(b: bytes) -> int: return int(b, 16) def ecMul(p: Point, x: int) -> Point: pt = FQ(p), FQ(p) return fq2point(multiply(pt, x)) def ecAdd(p1: Point, p2: Point) -> Point: p1 = FQ(p1), FQ(p1) p2 = FQ(p2), FQ(p2) return fq2point(add(p1, p2)) def serialize(*args) -> bytes: """ Helper function Serializes all supplied arguments into bytes """ b = b"" for i in range(len(args)): if type(args[i]) is int: b += args[i].to_bytes(32, 'big') elif type(args[i]) is Point: b += args[i].x().to_bytes(32, 'big') b += args[i].y().to_bytes(32, 'big') elif type(args[i]) is str: b += args[i].encode('utf-8') elif type(args[i]) is bytes: b += args[i] elif type(args[i]) is list: b += serialize(*args[i]) return b # Alice's secret key & public key alice_sk = randsp() alice_pk = ecMul(G, alice_sk) # Bob's secret key bob_sk = randsp() bob_pk = ecMul(G, bob_sk) # Alice generates a stealth address for Bob random_sk = randsp() random_pk = ecMul(G, random_sk) d = ecMul(bob_pk, random_sk) # Hash d to make it unlinkable stealth_sk = decode_int( Web3.soliditySha3(["bytes"], ["0x" + serialize(d).hex()]).hex() ) stealth_address = ecMul(G, stealth_sk) # Alice publishes the stealth_pk along with the random_pk # Given the random_pk and the stealth_pk # Bob checks if the stealth address belongs to him bob_d = ecMul(random_pk, bob_sk) bob_stealth_sk = decode_int( Web3.soliditySha3(["bytes"], ["0x" + serialize(bob_d).hex()]).hex() ) bob_stealth_address = ecMul(G, bob_stealth_sk) assert bob_stealth_address == stealth_address # Construct the one-time private key associated with the stealth address assert ecMul(G, bob_stealth_sk) == stealth_address assert ecMul(G, stealth_sk) == bob_stealth_address
You can’t perform that action at this time.