hive-nectar 0.2.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hive_nectar-0.2.9.dist-info/METADATA +194 -0
- hive_nectar-0.2.9.dist-info/RECORD +87 -0
- hive_nectar-0.2.9.dist-info/WHEEL +4 -0
- hive_nectar-0.2.9.dist-info/entry_points.txt +2 -0
- hive_nectar-0.2.9.dist-info/licenses/LICENSE.txt +23 -0
- nectar/__init__.py +37 -0
- nectar/account.py +5076 -0
- nectar/amount.py +553 -0
- nectar/asciichart.py +303 -0
- nectar/asset.py +122 -0
- nectar/block.py +574 -0
- nectar/blockchain.py +1242 -0
- nectar/blockchaininstance.py +2590 -0
- nectar/blockchainobject.py +263 -0
- nectar/cli.py +5937 -0
- nectar/comment.py +1552 -0
- nectar/community.py +854 -0
- nectar/constants.py +95 -0
- nectar/discussions.py +1437 -0
- nectar/exceptions.py +152 -0
- nectar/haf.py +381 -0
- nectar/hive.py +630 -0
- nectar/imageuploader.py +114 -0
- nectar/instance.py +113 -0
- nectar/market.py +876 -0
- nectar/memo.py +542 -0
- nectar/message.py +379 -0
- nectar/nodelist.py +309 -0
- nectar/price.py +603 -0
- nectar/profile.py +74 -0
- nectar/py.typed +0 -0
- nectar/rc.py +333 -0
- nectar/snapshot.py +1024 -0
- nectar/storage.py +62 -0
- nectar/transactionbuilder.py +659 -0
- nectar/utils.py +630 -0
- nectar/version.py +3 -0
- nectar/vote.py +722 -0
- nectar/wallet.py +472 -0
- nectar/witness.py +728 -0
- nectarapi/__init__.py +12 -0
- nectarapi/exceptions.py +126 -0
- nectarapi/graphenerpc.py +596 -0
- nectarapi/node.py +194 -0
- nectarapi/noderpc.py +79 -0
- nectarapi/openapi.py +107 -0
- nectarapi/py.typed +0 -0
- nectarapi/rpcutils.py +98 -0
- nectarapi/version.py +3 -0
- nectarbase/__init__.py +15 -0
- nectarbase/ledgertransactions.py +106 -0
- nectarbase/memo.py +242 -0
- nectarbase/objects.py +521 -0
- nectarbase/objecttypes.py +21 -0
- nectarbase/operationids.py +102 -0
- nectarbase/operations.py +1357 -0
- nectarbase/py.typed +0 -0
- nectarbase/signedtransactions.py +89 -0
- nectarbase/transactions.py +11 -0
- nectarbase/version.py +3 -0
- nectargraphenebase/__init__.py +27 -0
- nectargraphenebase/account.py +1121 -0
- nectargraphenebase/aes.py +49 -0
- nectargraphenebase/base58.py +197 -0
- nectargraphenebase/bip32.py +575 -0
- nectargraphenebase/bip38.py +110 -0
- nectargraphenebase/chains.py +15 -0
- nectargraphenebase/dictionary.py +2 -0
- nectargraphenebase/ecdsasig.py +309 -0
- nectargraphenebase/objects.py +130 -0
- nectargraphenebase/objecttypes.py +8 -0
- nectargraphenebase/operationids.py +5 -0
- nectargraphenebase/operations.py +25 -0
- nectargraphenebase/prefix.py +13 -0
- nectargraphenebase/py.typed +0 -0
- nectargraphenebase/signedtransactions.py +221 -0
- nectargraphenebase/types.py +557 -0
- nectargraphenebase/unsignedtransactions.py +288 -0
- nectargraphenebase/version.py +3 -0
- nectarstorage/__init__.py +57 -0
- nectarstorage/base.py +317 -0
- nectarstorage/exceptions.py +15 -0
- nectarstorage/interfaces.py +244 -0
- nectarstorage/masterpassword.py +237 -0
- nectarstorage/py.typed +0 -0
- nectarstorage/ram.py +27 -0
- nectarstorage/sqlite.py +343 -0
nectarbase/memo.py
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import struct
|
|
3
|
+
from binascii import hexlify, unhexlify
|
|
4
|
+
from typing import Any, Tuple
|
|
5
|
+
|
|
6
|
+
from Cryptodome.Cipher import AES
|
|
7
|
+
|
|
8
|
+
from nectargraphenebase.account import PublicKey
|
|
9
|
+
from nectargraphenebase.base58 import base58decode, base58encode
|
|
10
|
+
from nectargraphenebase.types import varintdecode
|
|
11
|
+
|
|
12
|
+
from .objects import Memo
|
|
13
|
+
|
|
14
|
+
default_prefix = "STM"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_shared_secret(priv: Any, pub: PublicKey) -> str:
|
|
18
|
+
"""Derive the share secret between ``priv`` and ``pub``
|
|
19
|
+
:param `Base58` priv: Private Key
|
|
20
|
+
:param `Base58` pub: Public Key
|
|
21
|
+
:return: Shared secret
|
|
22
|
+
:rtype: hex
|
|
23
|
+
The shared secret is generated such that::
|
|
24
|
+
Pub(Alice) * Priv(Bob) = Pub(Bob) * Priv(Alice)
|
|
25
|
+
"""
|
|
26
|
+
pub_point = pub.point()
|
|
27
|
+
priv_point = int(repr(priv), 16)
|
|
28
|
+
res = pub_point * priv_point
|
|
29
|
+
res_hex = "%032x" % res.x()
|
|
30
|
+
# Zero padding
|
|
31
|
+
res_hex = "0" * (64 - len(res_hex)) + res_hex
|
|
32
|
+
return res_hex
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def init_aes(shared_secret: str, nonce: int) -> Any:
|
|
36
|
+
"""Initialize AES instance
|
|
37
|
+
:param hex shared_secret: Shared Secret to use as encryption key
|
|
38
|
+
:param int nonce: Random nonce
|
|
39
|
+
:return: AES instance
|
|
40
|
+
:rtype: AES
|
|
41
|
+
"""
|
|
42
|
+
" Shared Secret "
|
|
43
|
+
ss = hashlib.sha512(unhexlify(shared_secret)).digest()
|
|
44
|
+
" Seed "
|
|
45
|
+
seed = bytes(str(nonce), "ascii") + hexlify(ss)
|
|
46
|
+
seed_digest = hexlify(hashlib.sha512(seed).digest()).decode("ascii")
|
|
47
|
+
" AES "
|
|
48
|
+
key = unhexlify(seed_digest[0:64])
|
|
49
|
+
iv = unhexlify(seed_digest[64:96])
|
|
50
|
+
return AES.new(key, AES.MODE_CBC, iv)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def init_aes_bts(shared_secret: str, nonce: int) -> Any:
|
|
54
|
+
"""Initialize AES instance
|
|
55
|
+
:param hex shared_secret: Shared Secret to use as encryption key
|
|
56
|
+
:param int nonce: Random nonce
|
|
57
|
+
:return: AES instance
|
|
58
|
+
:rtype: AES
|
|
59
|
+
"""
|
|
60
|
+
" Shared Secret "
|
|
61
|
+
ss = hashlib.sha512(unhexlify(shared_secret)).digest()
|
|
62
|
+
" Seed "
|
|
63
|
+
seed = bytes(str(nonce), "ascii") + hexlify(ss)
|
|
64
|
+
seed_digest = hexlify(hashlib.sha512(seed).digest()).decode("ascii")
|
|
65
|
+
" AES "
|
|
66
|
+
key = unhexlify(seed_digest[0:64])
|
|
67
|
+
iv = unhexlify(seed_digest[64:96])
|
|
68
|
+
return AES.new(key, AES.MODE_CBC, iv)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def init_aes2(shared_secret: str, nonce: int) -> Tuple[Any, int]:
|
|
72
|
+
"""Initialize AES instance
|
|
73
|
+
:param hex shared_secret: Shared Secret to use as encryption key
|
|
74
|
+
:param int nonce: Random nonce
|
|
75
|
+
"""
|
|
76
|
+
shared_secret = hashlib.sha512(unhexlify(shared_secret)).hexdigest()
|
|
77
|
+
# Seed
|
|
78
|
+
ss = unhexlify(shared_secret)
|
|
79
|
+
n = struct.pack("<Q", int(nonce))
|
|
80
|
+
encryption_key = hashlib.sha512(n + ss).hexdigest()
|
|
81
|
+
# Check'sum'
|
|
82
|
+
check = hashlib.sha256(unhexlify(encryption_key)).digest()
|
|
83
|
+
check = struct.unpack_from("<I", check[:4])[0]
|
|
84
|
+
# AES
|
|
85
|
+
key = unhexlify(encryption_key[0:64])
|
|
86
|
+
iv = unhexlify(encryption_key[64:96])
|
|
87
|
+
return AES.new(key, AES.MODE_CBC, iv), check
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _pad(s: bytes, BS: int) -> bytes:
|
|
91
|
+
numBytes = BS - len(s) % BS
|
|
92
|
+
return s + numBytes * struct.pack("B", numBytes)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _unpad(s: bytes, BS: int) -> bytes:
|
|
96
|
+
count = s[-1]
|
|
97
|
+
if s[-count::] == count * struct.pack("B", count):
|
|
98
|
+
return s[:-count]
|
|
99
|
+
return s
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def encode_memo_bts(priv: Any, pub: PublicKey, nonce: int, message: str) -> str:
|
|
103
|
+
"""Encode a message with a shared secret between Alice and Bob
|
|
104
|
+
|
|
105
|
+
:param PrivateKey priv: Private Key (of Alice)
|
|
106
|
+
:param PublicKey pub: Public Key (of Bob)
|
|
107
|
+
:param int nonce: Random nonce
|
|
108
|
+
:param str message: Memo message
|
|
109
|
+
:return: Encrypted message
|
|
110
|
+
:rtype: hex
|
|
111
|
+
|
|
112
|
+
"""
|
|
113
|
+
shared_secret = get_shared_secret(priv, pub)
|
|
114
|
+
aes = init_aes_bts(shared_secret, nonce)
|
|
115
|
+
" Checksum "
|
|
116
|
+
raw = bytes(message, "utf8")
|
|
117
|
+
checksum = hashlib.sha256(raw).digest()
|
|
118
|
+
raw = checksum[0:4] + raw
|
|
119
|
+
" Padding "
|
|
120
|
+
raw = _pad(raw, 16)
|
|
121
|
+
" Encryption "
|
|
122
|
+
return hexlify(aes.encrypt(raw)).decode("ascii")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def decode_memo_bts(priv: Any, pub: PublicKey, nonce: int, message: str) -> str:
|
|
126
|
+
"""Decode a message with a shared secret between Alice and Bob
|
|
127
|
+
|
|
128
|
+
:param PrivateKey priv: Private Key (of Bob)
|
|
129
|
+
:param PublicKey pub: Public Key (of Alice)
|
|
130
|
+
:param int nonce: Nonce used for Encryption
|
|
131
|
+
:param bytes message: Encrypted Memo message
|
|
132
|
+
:return: Decrypted message
|
|
133
|
+
:rtype: str
|
|
134
|
+
:raise ValueError: if message cannot be decoded as valid UTF-8
|
|
135
|
+
string
|
|
136
|
+
|
|
137
|
+
"""
|
|
138
|
+
shared_secret = get_shared_secret(priv, pub)
|
|
139
|
+
aes = init_aes_bts(shared_secret, nonce)
|
|
140
|
+
" Encryption "
|
|
141
|
+
raw = bytes(message, "ascii")
|
|
142
|
+
cleartext = aes.decrypt(unhexlify(raw))
|
|
143
|
+
" Checksum "
|
|
144
|
+
checksum = cleartext[0:4]
|
|
145
|
+
message_bytes = cleartext[4:]
|
|
146
|
+
message_bytes = _unpad(message_bytes, 16)
|
|
147
|
+
" Verify checksum "
|
|
148
|
+
check = hashlib.sha256(
|
|
149
|
+
message_bytes if isinstance(message_bytes, bytes) else message_bytes.encode("utf-8")
|
|
150
|
+
).digest()[0:4]
|
|
151
|
+
if check != checksum: # pragma: no cover
|
|
152
|
+
raise ValueError("checksum verification failure")
|
|
153
|
+
return message_bytes.decode("utf8") if isinstance(message_bytes, bytes) else message_bytes
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def encode_memo(priv: Any, pub: PublicKey, nonce: int, message: str, **kwargs: Any) -> str:
|
|
157
|
+
"""Encode a message with a shared secret between Alice and Bob
|
|
158
|
+
|
|
159
|
+
:param PrivateKey priv: Private Key (of Alice)
|
|
160
|
+
:param PublicKey pub: Public Key (of Bob)
|
|
161
|
+
:param int nonce: Random nonce
|
|
162
|
+
:param str message: Memo message
|
|
163
|
+
:return: Encrypted message
|
|
164
|
+
:rtype: hex
|
|
165
|
+
"""
|
|
166
|
+
shared_secret = get_shared_secret(priv, pub)
|
|
167
|
+
aes, check = init_aes2(shared_secret, nonce)
|
|
168
|
+
" Padding "
|
|
169
|
+
raw = bytes(message, "utf8")
|
|
170
|
+
raw = _pad(raw, 16)
|
|
171
|
+
" Encryption "
|
|
172
|
+
cipher = hexlify(aes.encrypt(raw)).decode("ascii")
|
|
173
|
+
prefix = kwargs.pop("prefix", default_prefix)
|
|
174
|
+
s = {
|
|
175
|
+
"from": format(priv.pubkey, prefix),
|
|
176
|
+
"to": format(pub, prefix),
|
|
177
|
+
"nonce": nonce,
|
|
178
|
+
"check": check,
|
|
179
|
+
"encrypted": cipher,
|
|
180
|
+
"prefix": prefix,
|
|
181
|
+
}
|
|
182
|
+
tx = Memo(**s)
|
|
183
|
+
return "#" + base58encode(hexlify(bytes(tx)).decode("ascii"))
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def extract_memo_data(message: str) -> Tuple[PublicKey, PublicKey, str, int, bytes]:
|
|
187
|
+
"""Returns the stored pubkey keys, nonce, checksum and encrypted message of a memo"""
|
|
188
|
+
raw = base58decode(message[1:])
|
|
189
|
+
from_key = PublicKey(raw[:66])
|
|
190
|
+
raw = raw[66:]
|
|
191
|
+
to_key = PublicKey(raw[:66])
|
|
192
|
+
raw = raw[66:]
|
|
193
|
+
nonce = str(struct.unpack_from("<Q", unhexlify(raw[:16]))[0])
|
|
194
|
+
raw = raw[16:]
|
|
195
|
+
check = struct.unpack_from("<I", unhexlify(raw[:8]))[0]
|
|
196
|
+
raw = raw[8:]
|
|
197
|
+
cipher = unhexlify(raw)
|
|
198
|
+
return from_key, to_key, nonce, check, cipher
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def decode_memo(priv: Any, message: str) -> str:
|
|
202
|
+
"""Decode a message with a shared secret between Alice and Bob
|
|
203
|
+
|
|
204
|
+
:param PrivateKey priv: Private Key (of Bob)
|
|
205
|
+
:param base58encoded message: Encrypted Memo message
|
|
206
|
+
:return: Decrypted message
|
|
207
|
+
:rtype: str
|
|
208
|
+
:raise ValueError: if message cannot be decoded as valid UTF-8
|
|
209
|
+
string
|
|
210
|
+
"""
|
|
211
|
+
# decode structure
|
|
212
|
+
from_key, to_key, nonce, check, cipher = extract_memo_data(message)
|
|
213
|
+
|
|
214
|
+
if repr(to_key) == repr(priv.pubkey):
|
|
215
|
+
shared_secret = get_shared_secret(priv, from_key)
|
|
216
|
+
elif repr(from_key) == repr(priv.pubkey):
|
|
217
|
+
shared_secret = get_shared_secret(priv, to_key)
|
|
218
|
+
else:
|
|
219
|
+
raise ValueError("Incorrect PrivateKey")
|
|
220
|
+
|
|
221
|
+
# Init encryption
|
|
222
|
+
aes, checksum = init_aes2(shared_secret, int(nonce))
|
|
223
|
+
# Check
|
|
224
|
+
if not check == checksum:
|
|
225
|
+
raise AssertionError("Checksum failure")
|
|
226
|
+
# Encryption
|
|
227
|
+
# remove the varint prefix (FIXME, long messages!)
|
|
228
|
+
numBytes = 16 - len(cipher) % 16
|
|
229
|
+
n = 16 - numBytes
|
|
230
|
+
message_bytes = cipher[n:]
|
|
231
|
+
message_bytes = aes.decrypt(message_bytes)
|
|
232
|
+
message_bytes = _unpad(message_bytes, 16)
|
|
233
|
+
n = varintdecode(message_bytes)
|
|
234
|
+
if (len(message_bytes) - n) > 0 and (len(message_bytes) - n) < 8:
|
|
235
|
+
message_part = message_bytes[len(message_bytes) - n :]
|
|
236
|
+
if isinstance(message_part, bytes):
|
|
237
|
+
message_part = message_part.decode("utf8")
|
|
238
|
+
return "#" + message_part
|
|
239
|
+
else:
|
|
240
|
+
return "#" + (
|
|
241
|
+
message_bytes.decode("utf8") if isinstance(message_bytes, bytes) else message_bytes
|
|
242
|
+
)
|