/ src / pyelliptic / arithmetic.py
arithmetic.py
  1  """
  2  Arithmetic Expressions
  3  """
  4  import hashlib
  5  import re
  6  
  7  P = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1
  8  A = 0
  9  Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240
 10  Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424
 11  G = (Gx, Gy)
 12  
 13  
 14  def inv(a, n):
 15      """Inversion"""
 16      lm, hm = 1, 0
 17      low, high = a % n, n
 18      while low > 1:
 19          r = high // low
 20          nm, new = hm - lm * r, high - low * r
 21          lm, low, hm, high = nm, new, lm, low
 22      return lm % n
 23  
 24  
 25  def get_code_string(base):
 26      """Returns string according to base value"""
 27      if base == 2:
 28          return b'01'
 29      if base == 10:
 30          return b'0123456789'
 31      if base == 16:
 32          return b'0123456789abcdef'
 33      if base == 58:
 34          return b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
 35      if base == 256:
 36          try:
 37              return b''.join([chr(x) for x in range(256)])
 38          except TypeError:
 39              return bytes([x for x in range(256)])
 40  
 41      raise ValueError("Invalid base!")
 42  
 43  
 44  def encode(val, base, minlen=0):
 45      """Returns the encoded string"""
 46      code_string = get_code_string(base)
 47      result = b''
 48      while val > 0:
 49          val, i = divmod(val, base)
 50          result = code_string[i:i + 1] + result
 51      if len(result) < minlen:
 52          result = code_string[0:1] * (minlen - len(result)) + result
 53      return result
 54  
 55  
 56  def decode(string, base):
 57      """Returns the decoded string"""
 58      code_string = get_code_string(base)
 59      result = 0
 60      if base == 16:
 61          string = string.lower()
 62      while string:
 63          result *= base
 64          result += code_string.find(string[0])
 65          string = string[1:]
 66      return result
 67  
 68  
 69  def changebase(string, frm, to, minlen=0):
 70      """Change base of the string"""
 71      return encode(decode(string, frm), to, minlen)
 72  
 73  
 74  def base10_add(a, b):
 75      """Adding the numbers that are of base10"""
 76      # pylint: disable=too-many-function-args
 77      if a is None:
 78          return b[0], b[1]
 79      if b is None:
 80          return a[0], a[1]
 81      if a[0] == b[0]:
 82          if a[1] == b[1]:
 83              return base10_double(a[0], a[1])
 84          return None
 85      m = ((b[1] - a[1]) * inv(b[0] - a[0], P)) % P
 86      x = (m * m - a[0] - b[0]) % P
 87      y = (m * (a[0] - x) - a[1]) % P
 88      return (x, y)
 89  
 90  
 91  def base10_double(a):
 92      """Double the numbers that are of base10"""
 93      if a is None:
 94          return None
 95      m = ((3 * a[0] * a[0] + A) * inv(2 * a[1], P)) % P
 96      x = (m * m - 2 * a[0]) % P
 97      y = (m * (a[0] - x) - a[1]) % P
 98      return (x, y)
 99  
100  
101  def base10_multiply(a, n):
102      """Multiply the numbers that are of base10"""
103      if n == 0:
104          return G
105      if n == 1:
106          return a
107      n, m = divmod(n, 2)
108      if m == 0:
109          return base10_double(base10_multiply(a, n))
110      if m == 1:
111          return base10_add(base10_double(base10_multiply(a, n)), a)
112      return None
113  
114  
115  def hex_to_point(h):
116      """Converting hexadecimal to point value"""
117      return (decode(h[2:66], 16), decode(h[66:], 16))
118  
119  
120  def point_to_hex(p):
121      """Converting point value to hexadecimal"""
122      return b'04' + encode(p[0], 16, 64) + encode(p[1], 16, 64)
123  
124  
125  def multiply(privkey, pubkey):
126      """Multiplying keys"""
127      return point_to_hex(base10_multiply(
128          hex_to_point(pubkey), decode(privkey, 16)))
129  
130  
131  def privtopub(privkey):
132      """Converting key from private to public"""
133      return point_to_hex(base10_multiply(G, decode(privkey, 16)))
134  
135  
136  def add(p1, p2):
137      """Adding two public keys"""
138      if len(p1) == 32:
139          return encode(decode(p1, 16) + decode(p2, 16) % P, 16, 32)
140      return point_to_hex(base10_add(hex_to_point(p1), hex_to_point(p2)))
141  
142  
143  def hash_160(string):
144      """Hashed version of public key"""
145      intermed = hashlib.sha256(string).digest()
146      ripemd160 = hashlib.new('ripemd160')
147      ripemd160.update(intermed)
148      return ripemd160.digest()
149  
150  
151  def dbl_sha256(string):
152      """Double hashing (SHA256)"""
153      return hashlib.sha256(hashlib.sha256(string).digest()).digest()
154  
155  
156  def bin_to_b58check(inp):
157      """Convert binary to base58"""
158      inp_fmtd = '\x00' + inp
159      leadingzbytes = len(re.match('^\x00*', inp_fmtd).group(0))
160      checksum = dbl_sha256(inp_fmtd)[:4]
161      return '1' * leadingzbytes + changebase(inp_fmtd + checksum, 256, 58)
162  
163  
164  def pubkey_to_address(pubkey):
165      """Convert a public key (in hex) to a Bitcoin address"""
166      return bin_to_b58check(hash_160(changebase(pubkey, 16, 256)))