PyBitmessage-2021-04-27/src/pyelliptic/arithmetic.py

164 lines
4.2 KiB
Python
Raw Permalink Normal View History

2019-12-21 10:43:03 +01:00
"""
Arithmetic Expressions
"""
2018-05-22 12:34:01 +02:00
import hashlib
import re
P = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1
2013-01-16 17:52:52 +01:00
A = 0
Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240
Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424
2018-05-22 12:34:01 +02:00
G = (Gx, Gy)
def inv(a, n):
2019-12-21 10:43:03 +01:00
"""Inversion"""
2018-05-22 12:34:01 +02:00
lm, hm = 1, 0
low, high = a % n, n
while low > 1:
r = high // low
2018-05-22 12:34:01 +02:00
nm, new = hm - lm * r, high - low * r
lm, low, hm, high = nm, new, lm, low
return lm % n
2013-01-16 17:52:52 +01:00
def get_code_string(base):
2019-12-21 10:43:03 +01:00
"""Returns string according to base value"""
2018-05-22 12:34:01 +02:00
if base == 2:
return '01'
elif base == 10:
return '0123456789'
elif base == 16:
return "0123456789abcdef"
elif base == 58:
return "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
elif base == 256:
return ''.join([chr(x) for x in range(256)])
else:
raise ValueError("Invalid base!")
def encode(val, base, minlen=0):
2019-12-21 10:43:03 +01:00
"""Returns the encoded string"""
2018-05-22 12:34:01 +02:00
code_string = get_code_string(base)
result = ""
while val > 0:
val, i = divmod(val, base)
result = code_string[i] + result
2018-05-22 12:34:01 +02:00
if len(result) < minlen:
result = code_string[0] * (minlen - len(result)) + result
return result
def decode(string, base):
2019-12-21 10:43:03 +01:00
"""Returns the decoded string"""
2018-05-22 12:34:01 +02:00
code_string = get_code_string(base)
result = 0
if base == 16:
string = string.lower()
while string:
result *= base
result += code_string.find(string[0])
string = string[1:]
return result
def changebase(string, frm, to, minlen=0):
2019-12-21 10:43:03 +01:00
"""Change base of the string"""
2018-05-22 12:34:01 +02:00
return encode(decode(string, frm), to, minlen)
def base10_add(a, b):
2019-12-21 10:43:03 +01:00
"""Adding the numbers that are of base10"""
# pylint: disable=too-many-function-args
2018-05-22 12:34:01 +02:00
if a is None:
return b[0], b[1]
if b is None:
return a[0], a[1]
if a[0] == b[0]:
if a[1] == b[1]:
return base10_double(a[0], a[1])
return None
m = ((b[1] - a[1]) * inv(b[0] - a[0], P)) % P
x = (m * m - a[0] - b[0]) % P
y = (m * (a[0] - x) - a[1]) % P
return (x, y)
2013-01-16 17:52:52 +01:00
def base10_double(a):
2019-12-21 10:43:03 +01:00
"""Double the numbers that are of base10"""
2018-05-22 12:34:01 +02:00
if a is None:
return None
m = ((3 * a[0] * a[0] + A) * inv(2 * a[1], P)) % P
x = (m * m - 2 * a[0]) % P
y = (m * (a[0] - x) - a[1]) % P
return (x, y)
def base10_multiply(a, n):
2019-12-21 10:43:03 +01:00
"""Multiply the numbers that are of base10"""
2018-05-22 12:34:01 +02:00
if n == 0:
return G
if n == 1:
return a
n, m = divmod(n, 2)
if m == 0:
return base10_double(base10_multiply(a, n))
if m == 1:
return base10_add(base10_double(base10_multiply(a, n)), a)
2018-05-22 12:34:01 +02:00
return None
def hex_to_point(h):
2019-12-21 10:43:03 +01:00
"""Converting hexadecimal to point value"""
2018-05-22 12:34:01 +02:00
return (decode(h[2:66], 16), decode(h[66:], 16))
2013-01-16 17:52:52 +01:00
2018-05-22 12:34:01 +02:00
def point_to_hex(p):
2019-12-21 10:43:03 +01:00
"""Converting point value to hexadecimal"""
2018-05-22 12:34:01 +02:00
return '04' + encode(p[0], 16, 64) + encode(p[1], 16, 64)
2013-01-16 17:52:52 +01:00
2018-05-22 12:34:01 +02:00
def multiply(privkey, pubkey):
2019-12-21 10:43:03 +01:00
"""Multiplying keys"""
return point_to_hex(base10_multiply(
hex_to_point(pubkey), decode(privkey, 16)))
2018-05-22 12:34:01 +02:00
2013-01-16 17:52:52 +01:00
def privtopub(privkey):
2019-12-21 10:43:03 +01:00
"""Converting key from private to public"""
2018-05-22 12:34:01 +02:00
return point_to_hex(base10_multiply(G, decode(privkey, 16)))
def add(p1, p2):
2019-12-21 10:43:03 +01:00
"""Adding two public keys"""
2018-05-22 12:34:01 +02:00
if len(p1) == 32:
return encode(decode(p1, 16) + decode(p2, 16) % P, 16, 32)
return point_to_hex(base10_add(hex_to_point(p1), hex_to_point(p2)))
2013-01-16 17:52:52 +01:00
def hash_160(string):
2019-12-21 10:43:03 +01:00
"""Hashed version of public key"""
2018-05-22 12:34:01 +02:00
intermed = hashlib.sha256(string).digest()
ripemd160 = hashlib.new('ripemd160')
ripemd160.update(intermed)
return ripemd160.digest()
2013-01-16 17:52:52 +01:00
def dbl_sha256(string):
2019-12-21 10:43:03 +01:00
"""Double hashing (SHA256)"""
2018-05-22 12:34:01 +02:00
return hashlib.sha256(hashlib.sha256(string).digest()).digest()
2013-01-16 17:52:52 +01:00
def bin_to_b58check(inp):
2019-12-21 10:43:03 +01:00
"""Convert binary to base58"""
2018-05-22 12:34:01 +02:00
inp_fmtd = '\x00' + inp
leadingzbytes = len(re.match('^\x00*', inp_fmtd).group(0))
checksum = dbl_sha256(inp_fmtd)[:4]
return '1' * leadingzbytes + changebase(inp_fmtd + checksum, 256, 58)
2013-01-16 17:52:52 +01:00
def pubkey_to_address(pubkey):
2019-12-21 10:43:03 +01:00
"""Convert a public key (in hex) to a Bitcoin address"""
2018-05-22 12:34:01 +02:00
return bin_to_b58check(hash_160(changebase(pubkey, 16, 256)))