Forking what is left of ZeroNet and hopefully adding an AT Proto Frontend/Proxy
1import logging
2import base64
3import binascii
4import time
5import hashlib
6
7from util.Electrum import dbl_format
8from Config import config
9
10import util.OpensslFindPatch
11
12lib_verify_best = "sslcrypto"
13
14from lib import sslcrypto
15sslcurve_native = sslcrypto.ecc.get_curve("secp256k1")
16sslcurve_fallback = sslcrypto.fallback.ecc.get_curve("secp256k1")
17sslcurve = sslcurve_native
18
19def loadLib(lib_name, silent=False):
20 global sslcurve, libsecp256k1message, lib_verify_best
21 if lib_name == "libsecp256k1":
22 s = time.time()
23 from lib import libsecp256k1message
24 import coincurve
25 lib_verify_best = "libsecp256k1"
26 if not silent:
27 logging.info(
28 "Libsecpk256k1 loaded: %s in %.3fs" %
29 (type(coincurve._libsecp256k1.lib).__name__, time.time() - s)
30 )
31 elif lib_name == "sslcrypto":
32 sslcurve = sslcurve_native
33 if sslcurve_native == sslcurve_fallback:
34 logging.warning("SSLCurve fallback loaded instead of native")
35 elif lib_name == "sslcrypto_fallback":
36 sslcurve = sslcurve_fallback
37
38try:
39 if not config.use_libsecp256k1:
40 raise Exception("Disabled by config")
41 loadLib("libsecp256k1")
42 lib_verify_best = "libsecp256k1"
43except Exception as err:
44 logging.info("Libsecp256k1 load failed: %s" % err)
45
46
47def newPrivatekey(): # Return new private key
48 return sslcurve.private_to_wif(sslcurve.new_private_key()).decode()
49
50
51def newSeed():
52 return binascii.hexlify(sslcurve.new_private_key()).decode()
53
54
55def hdPrivatekey(seed, child):
56 # Too large child id could cause problems
57 privatekey_bin = sslcurve.derive_child(seed.encode(), child % 100000000)
58 return sslcurve.private_to_wif(privatekey_bin).decode()
59
60
61def privatekeyToAddress(privatekey): # Return address from private key
62 try:
63 if len(privatekey) == 64:
64 privatekey_bin = bytes.fromhex(privatekey)
65 else:
66 privatekey_bin = sslcurve.wif_to_private(privatekey.encode())
67 return sslcurve.private_to_address(privatekey_bin).decode()
68 except Exception: # Invalid privatekey
69 return False
70
71
72def sign(data, privatekey): # Return sign to data using private key
73 if privatekey.startswith("23") and len(privatekey) > 52:
74 return None # Old style private key not supported
75 return base64.b64encode(sslcurve.sign(
76 data.encode(),
77 sslcurve.wif_to_private(privatekey.encode()),
78 recoverable=True,
79 hash=dbl_format
80 )).decode()
81
82
83def verify(data, valid_address, sign, lib_verify=None): # Verify data using address and sign
84 if not lib_verify:
85 lib_verify = lib_verify_best
86
87 if not sign:
88 return False
89
90 if lib_verify == "libsecp256k1":
91 sign_address = libsecp256k1message.recover_address(data.encode("utf8"), sign).decode("utf8")
92 elif lib_verify in ("sslcrypto", "sslcrypto_fallback"):
93 publickey = sslcurve.recover(base64.b64decode(sign), data.encode(), hash=dbl_format)
94 sign_address = sslcurve.public_to_address(publickey).decode()
95 else:
96 raise Exception("No library enabled for signature verification")
97
98 if type(valid_address) is list: # Any address in the list
99 return sign_address in valid_address
100 else: # One possible address
101 return sign_address == valid_address