mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-31 17:31:36 +00:00
revealer: split some core parts out into separate file
for easier testing
This commit is contained in:
parent
94afd7a9ea
commit
f969edcf50
3 changed files with 117 additions and 77 deletions
|
@ -13,47 +13,26 @@ import os
|
|||
import random
|
||||
import qrcode
|
||||
import traceback
|
||||
from hashlib import sha256
|
||||
from decimal import Decimal
|
||||
from typing import NamedTuple, Optional, Dict, Tuple
|
||||
|
||||
from PyQt5.QtPrintSupport import QPrinter
|
||||
|
||||
from electrum.plugin import BasePlugin, hook
|
||||
from electrum.plugin import hook
|
||||
from electrum.i18n import _
|
||||
from electrum.util import to_bytes, make_dir, InvalidPassword, UserCancelled, bh2u, bfh
|
||||
from electrum.util import make_dir, InvalidPassword, UserCancelled, bh2u, bfh
|
||||
from electrum.gui.qt.util import *
|
||||
from electrum.gui.qt.qrtextedit import ScanQRTextEdit
|
||||
from electrum.gui.qt.main_window import StatusBarButton
|
||||
|
||||
from .hmac_drbg import DRBG
|
||||
from .revealer import RevealerPlugin, VersionedSeed
|
||||
|
||||
|
||||
class VersionedSeed(NamedTuple):
|
||||
version: str
|
||||
seed: str
|
||||
checksum: str
|
||||
|
||||
def get_ui_string_version_plus_seed(self):
|
||||
version, seed = self.version, self.seed
|
||||
assert isinstance(version, str) and len(version) == 1, version
|
||||
assert isinstance(seed, str) and len(seed) >= 32
|
||||
ret = version + seed
|
||||
ret = ret.upper()
|
||||
return ' '.join(ret[i : i+4] for i in range(0, len(ret), 4))
|
||||
|
||||
|
||||
class Plugin(BasePlugin):
|
||||
|
||||
LATEST_VERSION = '1'
|
||||
KNOWN_VERSIONS = ('0', '1')
|
||||
assert LATEST_VERSION in KNOWN_VERSIONS
|
||||
class Plugin(RevealerPlugin):
|
||||
|
||||
MAX_PLAINTEXT_LEN = 189 # chars
|
||||
SIZE = (159, 97)
|
||||
|
||||
def __init__(self, parent, config, name):
|
||||
BasePlugin.__init__(self, parent, config, name)
|
||||
RevealerPlugin.__init__(self, parent, config, name)
|
||||
self.base_dir = os.path.join(config.electrum_path(), 'revealer')
|
||||
|
||||
if self.config.get('calibration_h') is None:
|
||||
|
@ -169,30 +148,6 @@ class Plugin(BasePlugin):
|
|||
self.user_input = bool(versioned_seed)
|
||||
self.next_button.setEnabled(bool(versioned_seed))
|
||||
|
||||
@classmethod
|
||||
def code_hashid(cls, txt: str) -> str:
|
||||
x = to_bytes(txt, 'utf8')
|
||||
hash = sha256(x).hexdigest()
|
||||
return hash[-3:].upper()
|
||||
|
||||
@classmethod
|
||||
def get_versioned_seed_from_user_input(cls, txt: str) -> Optional[VersionedSeed]:
|
||||
if len(txt) < 34:
|
||||
return None
|
||||
try:
|
||||
int(txt, 16)
|
||||
except:
|
||||
return None
|
||||
version = txt[0]
|
||||
if version not in cls.KNOWN_VERSIONS:
|
||||
return None
|
||||
checksum = cls.code_hashid(txt[:-3])
|
||||
if txt[-3:].upper() != checksum.upper():
|
||||
return None
|
||||
return VersionedSeed(version=version.upper(),
|
||||
seed=txt[1:-3].upper(),
|
||||
checksum=checksum.upper())
|
||||
|
||||
def make_digital(self, dialog):
|
||||
self.make_rawnoise(True)
|
||||
self.bdone(dialog)
|
||||
|
@ -377,33 +332,6 @@ class Plugin(BasePlugin):
|
|||
if create_revealer:
|
||||
self.make_revealer()
|
||||
|
||||
@classmethod
|
||||
def get_noise_map(self, versioned_seed: VersionedSeed) -> Dict[Tuple[int, int], int]:
|
||||
"""Returns a map from (x,y) coordinate to pixel value 0/1, to be used as noise."""
|
||||
w, h = self.SIZE
|
||||
version = versioned_seed.version
|
||||
hex_seed = versioned_seed.seed
|
||||
checksum = versioned_seed.checksum
|
||||
noise_map = {}
|
||||
if version == '0':
|
||||
random.seed(int(hex_seed, 16))
|
||||
for x in range(w):
|
||||
for y in range(h):
|
||||
noise_map[(x, y)] = random.randint(0, 1)
|
||||
elif version == '1':
|
||||
prng_seed = bfh(hex_seed + version + checksum)
|
||||
drbg = DRBG(prng_seed)
|
||||
num_noise_bytes = 1929 # ~ w*h
|
||||
noise_array = bin(int.from_bytes(drbg.generate(num_noise_bytes), 'big'))[2:]
|
||||
i = 0
|
||||
for x in range(w):
|
||||
for y in range(h):
|
||||
noise_map[(x, y)] = int(noise_array[i])
|
||||
i += 1
|
||||
else:
|
||||
raise Exception(f"unexpected revealer version: {version}")
|
||||
return noise_map
|
||||
|
||||
def make_calnoise(self):
|
||||
random.seed(self.calibration_noise)
|
||||
w, h = self.SIZE
|
||||
|
|
86
electrum/plugins/revealer/revealer.py
Normal file
86
electrum/plugins/revealer/revealer.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
import random
|
||||
from hashlib import sha256
|
||||
from typing import NamedTuple, Optional, Dict, Tuple
|
||||
|
||||
from electrum.plugin import BasePlugin
|
||||
from electrum.util import to_bytes, bh2u, bfh
|
||||
|
||||
from .hmac_drbg import DRBG
|
||||
|
||||
|
||||
class VersionedSeed(NamedTuple):
|
||||
version: str
|
||||
seed: str
|
||||
checksum: str
|
||||
|
||||
def get_ui_string_version_plus_seed(self):
|
||||
version, seed = self.version, self.seed
|
||||
assert isinstance(version, str) and len(version) == 1, version
|
||||
assert isinstance(seed, str) and len(seed) >= 32
|
||||
ret = version + seed
|
||||
ret = ret.upper()
|
||||
return ' '.join(ret[i : i+4] for i in range(0, len(ret), 4))
|
||||
|
||||
|
||||
class RevealerPlugin(BasePlugin):
|
||||
|
||||
LATEST_VERSION = '1'
|
||||
KNOWN_VERSIONS = ('0', '1')
|
||||
assert LATEST_VERSION in KNOWN_VERSIONS
|
||||
|
||||
SIZE = (159, 97)
|
||||
|
||||
def __init__(self, parent, config, name):
|
||||
BasePlugin.__init__(self, parent, config, name)
|
||||
|
||||
@classmethod
|
||||
def code_hashid(cls, txt: str) -> str:
|
||||
txt = txt.lower()
|
||||
x = to_bytes(txt, 'utf8')
|
||||
hash = sha256(x).hexdigest()
|
||||
return hash[-3:].upper()
|
||||
|
||||
@classmethod
|
||||
def get_versioned_seed_from_user_input(cls, txt: str) -> Optional[VersionedSeed]:
|
||||
if len(txt) < 34:
|
||||
return None
|
||||
try:
|
||||
int(txt, 16)
|
||||
except:
|
||||
return None
|
||||
version = txt[0]
|
||||
if version not in cls.KNOWN_VERSIONS:
|
||||
return None
|
||||
checksum = cls.code_hashid(txt[:-3])
|
||||
if txt[-3:].upper() != checksum.upper():
|
||||
return None
|
||||
return VersionedSeed(version=version.upper(),
|
||||
seed=txt[1:-3].upper(),
|
||||
checksum=checksum.upper())
|
||||
|
||||
@classmethod
|
||||
def get_noise_map(self, versioned_seed: VersionedSeed) -> Dict[Tuple[int, int], int]:
|
||||
"""Returns a map from (x,y) coordinate to pixel value 0/1, to be used as rawnoise."""
|
||||
w, h = self.SIZE
|
||||
version = versioned_seed.version
|
||||
hex_seed = versioned_seed.seed
|
||||
checksum = versioned_seed.checksum
|
||||
noise_map = {}
|
||||
if version == '0':
|
||||
random.seed(int(hex_seed, 16))
|
||||
for x in range(w):
|
||||
for y in range(h):
|
||||
noise_map[(x, y)] = random.randint(0, 1)
|
||||
elif version == '1':
|
||||
prng_seed = bfh(hex_seed + version + checksum)
|
||||
drbg = DRBG(prng_seed)
|
||||
num_noise_bytes = 1929 # ~ w*h
|
||||
noise_array = bin(int.from_bytes(drbg.generate(num_noise_bytes), 'big'))[2:]
|
||||
i = 0
|
||||
for x in range(w):
|
||||
for y in range(h):
|
||||
noise_map[(x, y)] = int(noise_array[i])
|
||||
i += 1
|
||||
else:
|
||||
raise Exception(f"unexpected revealer version: {version}")
|
||||
return noise_map
|
26
electrum/tests/test_revealer.py
Normal file
26
electrum/tests/test_revealer.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
from electrum.plugins.revealer.revealer import RevealerPlugin
|
||||
|
||||
from . import SequentialTestCase
|
||||
|
||||
|
||||
class TestRevealer(SequentialTestCase):
|
||||
|
||||
def test_version_0_noisemap(self):
|
||||
versioned_seed = RevealerPlugin.get_versioned_seed_from_user_input('03b0c557d6d0d4308a3393851d78bd8c7861')
|
||||
noise_map = RevealerPlugin.get_noise_map(versioned_seed)
|
||||
bigint = 0
|
||||
for (x, y), pixel in noise_map.items():
|
||||
if pixel:
|
||||
bigint |= 1 << (y*RevealerPlugin.SIZE[1]+x)
|
||||
self.assertEqual(0x541dde00b20ac7d320510e943d7ed9ffff5ff6b431c915353fbeffbc1beb737ff3a59c032a39ff8cbd532dffe42655bccbbef4f777ffeff8ec90e64aacbff5f4ff37ef4f32ac1d7240ed2bbb37dfeff459c7c2e2e0bfddffff7fffc7fd27eeb84a5ceafcf6bf9ffaff632367f97fffbf9fbfecff2b3a11a1c5befdfbfe7f125fba2c3e5d4ded591f9fbbbadbeed2220fb4337df9e4c7bfbe6ce4ad7b18ad57f3d75dfe7b6deb7350478bdbf7b7bfdf776eb301217d1f5c7f7ffffeefffe2070f52dbedfff2fef7f27f7d27f80b6a7bfb7f67bcbf7faf11f6b577dfbefebd44ffffe7bf5ee17ba4fb3377e1fcffeded781eca37a5bff3ebefdccbe1538c16129aed7fadfd7eb3bab55bcbdaee7e5d5b9fff57bd662333923b27af4f4da5ffd8bb15b58effed8bbeeff9ab7ecb75b62b977fdd88f3fbaeef6997a999b4dfffbfa375bf9e9c12b6011e2fde9fef7f66efc1155cc4fedfeefffeeff6ded645712b12bfe2b35df796f7ca05e0f12afbff6fefd1dd7f736bb9a567dff5797eafc1bfa0cf6cd090ddddfbfb79fd9f7f17bba2197e5dd3fb7fd9ff7579f0b6e28f7df3bdfe6fa8efd5a0a2e48f4d6efff79bf5efebc2638ff7eefffbbdfdb5bfac80426052df6fe6fd33eff5336a3c87c9fcff797b6bddbf91fea62e635333ffd7bfdd35f5c365432f5dfe7fd8bfb6c6e7cc90e6b5796d1dfeef567fdf390124a4bfeefd7efd1eee7f88ca45658fbf5cabffbfebf9fefe2c9f73dbffd36d7df77d73665c5f1dfa7b5b7fffafb6ea18bf9396e37b77fffffffb6aefdb0635ff7e43cfeef77fd8a527741dd3fffef1eddedf7f4259cc4253ffd9dffffb3bfbb0632d3d7fbf7bfbbfedfff2a7589be7624faffffbdbd7dfb5b5189b66fde8abf8bfbba7f440b80c2ba86de5fdfdf7ffba25625877fb9fdbf6f39333fe20e7710cdffadef8e7fb727d059237ef3dfceb9bd7ffef7b041565f2bb7ffdfefffff1ba3c7abb9a0fcf3fdf78fee7efb5da83dd1ffadebde675ff36d725426027dfffd9f76df3f7605b7f6fa4f75ff6e3df57ffd1a56c6239feffebffeecffdbd1ecc69f99ffea7f5ec759e2b2a99977b467edbffafae5faef9e719b7bff73fe9fed753ddc20ba23d8e7fdf4adfdbefadbb6a6775f7ef7eddffdfffeead7be0b38dcefeeb6afffef3d272d1b0492e733fff15dc3bfa2bfb83b9fefbfdf853fbddfbdbdf354868fd6dedf93edffca29130013bfcfbe27f4feffc86bbaa925bffdeed3fede76b321dc0abb57fe367df5adaaf30cc615c1efef7fbffe3993e583ff3721bdfbe66edef8faef24697f311ff6ff57ffefbebff9b90325bda76f77daeabfbcb9abd45c0bffe576bc3fffffc96911d477ddbbc3feef7f63a4510ec1265e6e1fe765eaafbca10400876bff7bffdfdffcc9920f60119beedfffd57e6ff383e6c3637def9fdffb7bfffb3339f94eb3fdf5bd7bbdfdf621d8f008dad195dffd6ffbff57a1ce166e5ef9f85febdde28a4a013987bf7ffebffffb56cf7aa522589bdafdf51ff4f39ed386097667fafdbfffff7ef9379dbc136bedfb9ff7aefffc3f081be97bf4e7ecfbde35cea3018d1bf1bffbfaeebefb9fac072f05bac77f7fdffeffe2eb1bd4d90a6fddafd7c2ff7bf9ba80d6f6df77ce727ff9a97fb41f03dcfbc557b3fbcc80b,
|
||||
bigint)
|
||||
|
||||
def test_version_1_noisemap(self):
|
||||
versioned_seed = RevealerPlugin.get_versioned_seed_from_user_input('125Df05b7ccf079ce2978Ae18e99219868cd')
|
||||
noise_map = RevealerPlugin.get_noise_map(versioned_seed)
|
||||
bigint = 0
|
||||
for (x, y), pixel in noise_map.items():
|
||||
if pixel:
|
||||
bigint |= 1 << (y*RevealerPlugin.SIZE[1]+x)
|
||||
self.assertEqual(0x36fde1eece10b3f674227ea76f7ababbcbf87dfba1eddf2edebfeefec3dffff719ee1cbd477b9be7cf6fcdaff924ff05a26ff2fb7bfdbbdef1a2f90c097d7cdadfbb9d1ef592c27c85efffffff7ffc8dff60d6de87f71c9fe77f7f5372cfdb1dc0eb9e959dbed42197c7ee4288f7fbf73b65fdfbd5e153ede49bb957edaefe6f7dee4a72502eef77babfa7fff7d0a3fc6f5ffefb3b7b67aab66118a56eb1fffe1ddafbeefefa96b26d715bb8e5fafbbb2ffcf64e8df2bdffeffed39ffdfdef986491a7fbf97bffb7fafee072640b7af6edf8da2f7cdff268ccd52b75f53f9afef77b4be4db9c5f9debffeff5f7f1f7b1882cb4eed67f757b37ebf0b2c7f849bd73f4737f3ffb5a3f75ac537ff5fff8edcdfeb6be63d3147ffeefa9caf7ebf740989520c1eddedabdfd73f7f821fc3977fdfbe9fbee7d6e8ca9f16b8b8f1decbffef17f806ade988d77fef5775cff3f7bd9759675f4773fff6fefaff385fe807fdbfcbbffefa6d7c4ed54a0d1959cefeecffdffe8cd539451dfdfbff71ff7e97cf37aec8069efffcf7536ebbc515e991cf293ff97feffd72cebe110d44bf787f1efecda7306ac88cd49dfff257cbd9ff7ff8fd1686eedf2dfeb373fbe2a10ed81f7d9c979316efceeea745926377ffcffba7edf67fc79cace0eeef5ff5ceffeeeff94d20c4dadd53efee6f97bfed2f8ae059ff7ffbfedfbf17f2d45bc8afdebf1dff7856ebd02c39ae22ef7befc9e97cbb7f31af5bd57e3feffafc4d7fef9ae222e9fdcf5a2dfbffefd50399d7d095d22fd7bf9fdef6d5d5044bafffdfd57fff7cbe6af91096b3f5fffe3fff7fb97fa930d316db6dfbf236ddbc8abb3bbea6edf9deafd39b8efac7ae014e7ffbdd97cfebe7ec84a72a7b323fe77afffd7f1c8eaec48e6ff3fdf7da9fffaf2d57e961d7f5debc9afe7ff32d72ff374d3ff57fff2fbffdbe9833405fcbabff8beb8ff1e55f53b2d6e96bdf7e7fbfd0fb6b130071c13cf5de5be5ef8ade46a2dd53d77ff69eff7ff946ad4e32febddff87b73fceeaf2ce94adafbb9fddeff8fbf11f4161ad6cb29dbe5f2ffe6ee2023ceeb79c76d7fff7bbffaf4485b6f6f3b7f97f9f75ce372c173177fedd65e5fb76fdc5bbf7a737f9bdddefefff1f7a5533dd1efde7ffafabcd96e1193e3cadb93e76fcdfdb4fa533bc3d3a7eff5eebc9f3ffce91aa51bbf5e7f6bcfd7dfbfd1928c0726f3f26ef8f3ffe2eb8843cbb1dfd2eabfe4f7ffec47a95263e5c65737affe73e3e3735d61e8cbffdbf75e37fc04a991ad7ff7feffa6fafdfed988b50fdf379ffdfff2f7eeb6738c0ceffff77f32fe7f2b22c866514db75f7c3df6e5fd210a70bb4bbf31bcfb6d325f4a00b06ed7d34c9dbbdffff3fd6fd8ed570d7def1dcf789ff5ae040339ff35deb5e37bedf889d83bcf5feffb77e57ffcfdd8edfd91bb8bffd3b7dbd8fea3083734c3d7dedd9ffefcb78c5d87e1919f5655bf5bf1bfb3dd65fb64ee2fffd777afef18965d03872d73bbfb6fa7df7250f3e8d6ef7ff9ffffeadff5e39abf8727fde93febddfffee3096ca1779ceabbf7ff7bda2f756353be9dfabf2bcff6feec1cad233fffbf9ecefffffa21b7b8b17ffded7ff7fef56ee44b02d9bdf3d3cf42aa777fd90ba9b08af4cfd5b797dadb3694bf3282abcb39fb2d760f9,
|
||||
bigint)
|
Loading…
Add table
Reference in a new issue