mirror of
https://git.wownero.com/lza_menace/wownero-python.git
synced 2024-08-15 03:25:25 +00:00
Merge pull request #23 from atward/mnemonics
Add support for multiple mnemonic wordlist
This commit is contained in:
commit
a76cfa03fd
17 changed files with 20633 additions and 1688 deletions
|
@ -39,7 +39,7 @@ from monero import address
|
|||
from monero import wordlists
|
||||
from monero import ed25519
|
||||
from monero import base58
|
||||
from binascii import crc32, hexlify, unhexlify
|
||||
from binascii import hexlify, unhexlify
|
||||
from os import urandom
|
||||
from sha3 import keccak_256
|
||||
|
||||
|
@ -49,19 +49,18 @@ class Seed(object):
|
|||
:rtype: :class:`Seed <monero.seed.Seed>`
|
||||
"""
|
||||
|
||||
n = 1626
|
||||
wordlist = wordlists.english.wordlist # default english for now
|
||||
|
||||
phrase = "" #13 or 25 word mnemonic word string
|
||||
hex = "" # hexadecimal
|
||||
|
||||
def __init__(self, phrase_or_hex=""):
|
||||
def __init__(self, phrase_or_hex="", wordlist="English"):
|
||||
"""If user supplied a seed string to the class, break it down and determine
|
||||
if it's hexadecimal or mnemonic word string. Gather the values and store them.
|
||||
If no seed is passed, automatically generate a new one from local system randomness.
|
||||
|
||||
:rtype: :class:`Seed <monero.seed.Seed>`
|
||||
"""
|
||||
self.phrase = "" #13 or 25 word mnemonic word string
|
||||
self.hex = "" # hexadecimal
|
||||
|
||||
self.word_list = wordlists.get_wordlist(wordlist)
|
||||
|
||||
if phrase_or_hex:
|
||||
seed_split = phrase_or_hex.split(" ")
|
||||
if len(seed_split) >= 24:
|
||||
|
@ -94,41 +93,15 @@ class Seed(object):
|
|||
"""Returns True if the seed is MyMonero-style (12/13-word)."""
|
||||
return len(self.hex) == 32
|
||||
|
||||
def endian_swap(self, word):
|
||||
"""Given any string, swap bits and return the result.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return "".join([word[i:i+2] for i in [6, 4, 2, 0]])
|
||||
|
||||
def _encode_seed(self):
|
||||
"""Convert hexadecimal string to mnemonic word representation with checksum.
|
||||
"""
|
||||
out = []
|
||||
for i in range(len(self.hex) // 8):
|
||||
word = self.endian_swap(self.hex[8*i:8*i+8])
|
||||
x = int(word, 16)
|
||||
w1 = x % self.n
|
||||
w2 = (x // self.n + w1) % self.n
|
||||
w3 = (x // self.n // self.n + w2) % self.n
|
||||
out += [self.wordlist[w1], self.wordlist[w2], self.wordlist[w3]]
|
||||
checksum = get_checksum(" ".join(out))
|
||||
out.append(checksum)
|
||||
self.phrase = " ".join(out)
|
||||
self.phrase = self.word_list.encode(self.hex)
|
||||
|
||||
def _decode_seed(self):
|
||||
"""Calculate hexadecimal representation of the phrase.
|
||||
"""
|
||||
phrase = self.phrase.split(" ")
|
||||
out = ""
|
||||
for i in range(len(phrase) // 3):
|
||||
word1, word2, word3 = phrase[3*i:3*i+3]
|
||||
w1 = self.wordlist.index(word1)
|
||||
w2 = self.wordlist.index(word2) % self.n
|
||||
w3 = self.wordlist.index(word3) % self.n
|
||||
x = w1 + self.n *((w2 - w1) % self.n) + self.n * self.n * ((w3 - w2) % self.n)
|
||||
out += self.endian_swap("%08x" % x)
|
||||
self.hex = out
|
||||
self.hex = self.word_list.decode(self.phrase)
|
||||
|
||||
def _validate_checksum(self):
|
||||
"""Given a mnemonic word string, confirm seed checksum (last word) matches the computed checksum.
|
||||
|
@ -136,7 +109,7 @@ class Seed(object):
|
|||
:rtype: bool
|
||||
"""
|
||||
phrase = self.phrase.split(" ")
|
||||
if get_checksum(self.phrase) == phrase[-1]:
|
||||
if self.word_list.get_checksum(self.phrase) == phrase[-1]:
|
||||
return True
|
||||
raise ValueError("Invalid checksum")
|
||||
|
||||
|
@ -191,25 +164,6 @@ class Seed(object):
|
|||
return base58.encode(data + checksum[0:8])
|
||||
|
||||
|
||||
def get_checksum(phrase):
|
||||
"""Given a mnemonic word string, return a string of the computed checksum.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
phrase_split = phrase.split(" ")
|
||||
if len(phrase_split) < 12:
|
||||
raise ValueError("Invalid mnemonic phrase")
|
||||
if len(phrase_split) > 13:
|
||||
# Standard format
|
||||
phrase = phrase_split[:24]
|
||||
else:
|
||||
# MyMonero format
|
||||
phrase = phrase_split[:12]
|
||||
wstr = "".join(word[:3] for word in phrase)
|
||||
z = ((crc32(wstr.encode()) & 0xffffffff) ^ 0xffffffff ) >> 0
|
||||
z2 = ((z ^ 0xffffffff) >> 0) % len(phrase)
|
||||
return phrase_split[z2]
|
||||
|
||||
def generate_hex(n_bytes=32):
|
||||
"""Generate a secure and random hexadecimal string. 32 bytes by default, but arguments can override.
|
||||
|
||||
|
|
|
@ -1 +1,14 @@
|
|||
from . import english
|
||||
from .wordlist import get_wordlist, list_wordlists
|
||||
from .english import English
|
||||
|
||||
from .chinese_simplified import ChineseSimplified
|
||||
from .dutch import Dutch
|
||||
from .esperanto import Esperanto
|
||||
from .french import French
|
||||
from .german import German
|
||||
from .italian import Italian
|
||||
from .japanese import Japanese
|
||||
from .lojban import Lojban
|
||||
from .portuguese import Portuguese
|
||||
from .russian import Russian
|
||||
from .spanish import Spanish
|
||||
|
|
1694
monero/wordlists/chinese_simplified.py
Normal file
1694
monero/wordlists/chinese_simplified.py
Normal file
File diff suppressed because it is too large
Load diff
1693
monero/wordlists/dutch.py
Normal file
1693
monero/wordlists/dutch.py
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
1694
monero/wordlists/esperanto.py
Normal file
1694
monero/wordlists/esperanto.py
Normal file
File diff suppressed because it is too large
Load diff
1694
monero/wordlists/french.py
Normal file
1694
monero/wordlists/french.py
Normal file
File diff suppressed because it is too large
Load diff
1693
monero/wordlists/german.py
Normal file
1693
monero/wordlists/german.py
Normal file
File diff suppressed because it is too large
Load diff
1694
monero/wordlists/italian.py
Normal file
1694
monero/wordlists/italian.py
Normal file
File diff suppressed because it is too large
Load diff
1694
monero/wordlists/japanese.py
Normal file
1694
monero/wordlists/japanese.py
Normal file
File diff suppressed because it is too large
Load diff
1693
monero/wordlists/lojban.py
Normal file
1693
monero/wordlists/lojban.py
Normal file
File diff suppressed because it is too large
Load diff
1694
monero/wordlists/portuguese.py
Normal file
1694
monero/wordlists/portuguese.py
Normal file
File diff suppressed because it is too large
Load diff
1694
monero/wordlists/russian.py
Normal file
1694
monero/wordlists/russian.py
Normal file
File diff suppressed because it is too large
Load diff
1694
monero/wordlists/spanish.py
Normal file
1694
monero/wordlists/spanish.py
Normal file
File diff suppressed because it is too large
Load diff
111
monero/wordlists/wordlist.py
Normal file
111
monero/wordlists/wordlist.py
Normal file
|
@ -0,0 +1,111 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from binascii import crc32
|
||||
|
||||
from six import with_metaclass
|
||||
|
||||
|
||||
WORDLISTS = {}
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WordlistType(type):
|
||||
def __new__(cls, name, bases, attrs):
|
||||
if bases:
|
||||
if 'language_name' not in attrs:
|
||||
raise TypeError("Missing language_name for {0}".format(name))
|
||||
if 'unique_prefix_length' not in attrs:
|
||||
raise TypeError("Missing 'unique_prefix_length' for {0}".format(name))
|
||||
if 'word_list' not in attrs:
|
||||
raise TypeError("Missing 'word_list' for {0}".format(name))
|
||||
|
||||
if 'english_language_name' not in attrs:
|
||||
_log.warn("No 'english_language_name' for {0} using '{1}'".format(name, language_name))
|
||||
attrs['english_language_name'] = attrs['language_name']
|
||||
|
||||
if len(attrs['word_list']) != 1626:
|
||||
raise TypeError("Wrong word list length for {0}".format(name))
|
||||
|
||||
new_cls = super(WordlistType, cls).__new__(cls, name, bases, attrs)
|
||||
|
||||
if bases:
|
||||
WORDLISTS[new_cls.english_language_name] = new_cls
|
||||
|
||||
return new_cls
|
||||
|
||||
|
||||
class Wordlist(with_metaclass(WordlistType)):
|
||||
n = 1626
|
||||
|
||||
@classmethod
|
||||
def encode(cls, hex):
|
||||
"""Convert hexadecimal string to mnemonic word representation with checksum.
|
||||
"""
|
||||
out = []
|
||||
for i in range(len(hex) // 8):
|
||||
word = endian_swap(hex[8*i:8*i+8])
|
||||
x = int(word, 16)
|
||||
w1 = x % cls.n
|
||||
w2 = (x // cls.n + w1) % cls.n
|
||||
w3 = (x // cls.n // cls.n + w2) % cls.n
|
||||
out += [cls.word_list[w1], cls.word_list[w2], cls.word_list[w3]]
|
||||
checksum = cls.get_checksum(" ".join(out))
|
||||
out.append(checksum)
|
||||
return " ".join(out)
|
||||
|
||||
@classmethod
|
||||
def decode(cls, phrase):
|
||||
"""Calculate hexadecimal representation of the phrase.
|
||||
"""
|
||||
phrase = phrase.split(" ")
|
||||
out = ""
|
||||
for i in range(len(phrase) // 3):
|
||||
word1, word2, word3 = phrase[3*i:3*i+3]
|
||||
w1 = cls.word_list.index(word1)
|
||||
w2 = cls.word_list.index(word2) % cls.n
|
||||
w3 = cls.word_list.index(word3) % cls.n
|
||||
x = w1 + cls.n *((w2 - w1) % cls.n) + cls.n * cls.n * ((w3 - w2) % cls.n)
|
||||
out += endian_swap("%08x" % x)
|
||||
return out
|
||||
|
||||
@classmethod
|
||||
def get_checksum(cls, phrase):
|
||||
"""Given a mnemonic word string, return a string of the computed checksum.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
phrase_split = phrase.split(" ")
|
||||
if len(phrase_split) < 12:
|
||||
raise ValueError("Invalid mnemonic phrase")
|
||||
if len(phrase_split) > 13:
|
||||
# Standard format
|
||||
phrase = phrase_split[:24]
|
||||
else:
|
||||
# MyMonero format
|
||||
phrase = phrase_split[:12]
|
||||
wstr = "".join(word[:cls.unique_prefix_length] for word in phrase)
|
||||
wstr = bytearray(wstr.encode('utf-8'))
|
||||
z = ((crc32(wstr) & 0xffffffff) ^ 0xffffffff ) >> 0
|
||||
z2 = ((z ^ 0xffffffff) >> 0) % len(phrase)
|
||||
return phrase_split[z2]
|
||||
|
||||
|
||||
def get_wordlist(name):
|
||||
try:
|
||||
return WORDLISTS[name]
|
||||
except KeyError:
|
||||
raise ValueError("No such word list")
|
||||
|
||||
|
||||
def list_wordlists():
|
||||
return WORDLISTS.keys()
|
||||
|
||||
|
||||
def endian_swap(word):
|
||||
"""Given any string, swap bits and return the result.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return "".join([word[i:i+2] for i in [6, 4, 2, 0]])
|
|
@ -1,2 +1,3 @@
|
|||
pysha3
|
||||
requests
|
||||
six
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
from monero.seed import Seed, get_checksum
|
||||
from monero.seed import Seed
|
||||
from monero.wordlists import list_wordlists
|
||||
|
||||
class SeedTestCase(unittest.TestCase):
|
||||
|
||||
|
@ -92,6 +94,205 @@ class SeedTestCase(unittest.TestCase):
|
|||
seed.public_address(),
|
||||
'47dwi1w9it69yZyTBBRD52ctQqw3B2FZx79bCEgVUKGHH2m7MjmaXrjeQfchMMkarG6AF9a36JvBWCyRaqEcUixpKLQRxdj')
|
||||
|
||||
def test_languages(self):
|
||||
for wordlist in list_wordlists():
|
||||
print("Language: {}".format(wordlist))
|
||||
# Generate random seed
|
||||
seed = Seed(wordlist=wordlist)
|
||||
|
||||
# Convert it from phrase
|
||||
seed_from_phrase = Seed(seed.phrase, wordlist=wordlist)
|
||||
self.assertEqual(seed.hex, seed_from_phrase.hex)
|
||||
self.assertEqual(seed.phrase, seed_from_phrase.phrase)
|
||||
|
||||
# Convert it from hex
|
||||
seed_from_hex = Seed(seed.hex, wordlist=wordlist)
|
||||
self.assertEqual(seed.hex, seed_from_hex.hex)
|
||||
self.assertEqual(seed.phrase, seed_from_hex.phrase)
|
||||
|
||||
def test_chinese_simplified(self):
|
||||
seed = Seed(u"遭 牲 本 点 司 司 仲 吉 虎 只 绝 生 指 纯 伟 破 夫 惊 群 楚 祥 旋 暗 骨 伟", "Chinese (simplified)")
|
||||
self.assertEqual(
|
||||
seed.secret_spend_key(),
|
||||
'2ec46011b23b0c00468946f1d9a64995bf0a89f9ee0bbf4f64058a3acd81a70e')
|
||||
self.assertEqual(
|
||||
seed.secret_view_key(),
|
||||
'aa141796baa24539583306300b44a72495bb7823a0cc6ad856de6d372288d10f')
|
||||
self.assertEqual(
|
||||
seed.public_spend_key(),
|
||||
'76cc3b927e70fee85a43a6141d019b53c77f46bbcd6c4dc6d814dfc271af361c')
|
||||
self.assertEqual(
|
||||
seed.public_view_key(),
|
||||
'91ef3783492e173ca366a818ae7ee37f062daea909fd9ed9ca40d41e7d572dd4')
|
||||
self.assertEqual(
|
||||
seed.public_address(),
|
||||
'468Dewci4TPfs7TATZ2nf4F1mKAEMp6RraG37wiSU4uT5nAbBwGz5LaB9GWHG23o6ANFJ1Q9cBYk5dRqWNNkmFN4Qx3RqBD')
|
||||
|
||||
def test_dutch(self):
|
||||
seed = Seed(u"ralf tolvrij copier roon ossuarium wedstrijd splijt debbie bomtapijt occlusie oester noren hiaat scenario geshockt veeteler rotten symboliek jarig bock yoghurt plegen weert zeeblauw wedstrijd", "Dutch")
|
||||
self.assertEqual(
|
||||
seed.secret_spend_key(),
|
||||
'600d3c5022e1844dd2df02f178a074fc2e566793e99d9e1465926adcbfa9b508')
|
||||
self.assertEqual(
|
||||
seed.secret_view_key(),
|
||||
'bb8984647124dafcb8682f1c257b5232bb12b96d682bfc320b4f8ce935e2d303')
|
||||
self.assertEqual(
|
||||
seed.public_spend_key(),
|
||||
'df4be25f7ccaf632f1525b06fd9b0d7e9f64b21ebfb609353d643a24de16221b')
|
||||
self.assertEqual(
|
||||
seed.public_view_key(),
|
||||
'2fcd275e4337152ea77ac68ec02f166a243f4917ebd53b2a381ab27b84d24065')
|
||||
self.assertEqual(
|
||||
seed.public_address(),
|
||||
'4A5uCL4cXoB9XD3WjTrEwvNBQ6JRPTHaY9uVaxfWmcLy5YkE81tW7B28oc42XGzAeRJkhyHjKAxSE84aZnihjVBVCQf15mw')
|
||||
|
||||
def test_esperanto(self):
|
||||
seed = Seed(u"knedi aspekti boli asbesto pterido aparta muro sandalo hufumo porcelana degeli utopia ebono lifto dutaga hundo vejno ebono higieno nikotino orkestro arlekeno insekto jaguaro hundo", "Esperanto")
|
||||
self.assertEqual(
|
||||
seed.secret_spend_key(),
|
||||
'a8e8a30d3638cc4d09d1fa9f4de12ac0096c69a77896774793627c0cc6a28703')
|
||||
self.assertEqual(
|
||||
seed.secret_view_key(),
|
||||
'8b4dcbcbafaf3d195af5bd54aa386d767a8de3b45236c9842cb876212427f103')
|
||||
self.assertEqual(
|
||||
seed.public_spend_key(),
|
||||
'32c8a782c05db039018caa150bef1f66621831b3cb591401381e1dfc3c3d423e')
|
||||
self.assertEqual(
|
||||
seed.public_view_key(),
|
||||
'047963206a0267649657936d268824e35e59e3426c63b9f3b04788b14af1d85f')
|
||||
self.assertEqual(
|
||||
seed.public_address(),
|
||||
'43YjCQcHm8TAY2kKbSMHz6J8FDZQwjPxw1Cq1vQ7SsQVBNeYEUMwGTQHppi5ffwg3df2m56DYexj2hm5uaQDtqpTBnUVzmD')
|
||||
|
||||
def test_french(self):
|
||||
seed = Seed(u"sauce exprimer chasse asile larve tacler digestion muguet rondeur sept clore narrer fluor arme torse dans glace tant salon sanguin globe quiche ficher flaque clore", "French")
|
||||
self.assertEqual(
|
||||
seed.secret_spend_key(),
|
||||
'597703dd73d0da6b3996b83c3e1e2f602be4f0de453e15846171aa9076901603')
|
||||
self.assertEqual(
|
||||
seed.secret_view_key(),
|
||||
'f6e448dbbeaa7682a541b3b5b7e2e8ebb614fac032f1c3dff659ca26ab430f09')
|
||||
self.assertEqual(
|
||||
seed.public_spend_key(),
|
||||
'10b42e100196ef2a68eeec191a46d8dc5c83d73c0861c185e5244202cd432087')
|
||||
self.assertEqual(
|
||||
seed.public_view_key(),
|
||||
'34c4c479d53b10d3e9c0a3d11432fd13611b12dc5b721c8ff3802329b7bac328')
|
||||
self.assertEqual(
|
||||
seed.public_address(),
|
||||
'42FpfU7DfLi86RtY3ajKUKdrnKvXTx41WPPx6wsyp9XVPcfnrLDXxhucSphpzt3mDv4F1DMiCrfHmR5WPZq1erzn5bs4eA7')
|
||||
|
||||
def test_german(self):
|
||||
seed = Seed(u"Erdgas Gesuch beeilen Chiffon Abendrot Alter Helium Salz Almweide Ampel Dichter Rotglut Dialekt Akkord Rampe Gesöff Ziege Boykott keuchen Krach Anbau Labor Esel Ferien Ampel", "German")
|
||||
self.assertEqual(
|
||||
seed.secret_spend_key(),
|
||||
'193152abe15c5e0a0ff56e3020229398769cd7c6ca5a4e30e439d6702c4f320a')
|
||||
self.assertEqual(
|
||||
seed.secret_view_key(),
|
||||
'cdb967c501195827d78a791e1173d4b8826a5ae73b0885984898c84b6c9dd80c')
|
||||
self.assertEqual(
|
||||
seed.public_spend_key(),
|
||||
'32eac115ca4b072c18198966c7ac9cb63b9f701a691eb52bfa18345d0fbcd90f')
|
||||
self.assertEqual(
|
||||
seed.public_view_key(),
|
||||
'06a2119dfa7c48bdc03ad251026fc509bd01f3a4f7521802ca31b93cf06539ac')
|
||||
self.assertEqual(
|
||||
seed.public_address(),
|
||||
'43Z2BHsCkU68NmZrxzfZuuXUtUHCXWttt8MdcnNyDMkC3WmfoFb9byqYjpeBaC4Xtx2dUUv8YPv1d1U4krZCLzyWLUFif2E')
|
||||
|
||||
def test_italian(self):
|
||||
seed = Seed(u"tramonto spuntare ruota afrodite binocolo riferire moneta assalire tuta firmare malattia flagello paradiso tacere sindrome spuntare sogliola volare follia versare insulto diagnosi lapide meteo malattia", "Italian")
|
||||
self.assertEqual(
|
||||
seed.secret_spend_key(),
|
||||
'29c8d9e91c1cb59e059bddd901e011db85f8d4f00f967226ffb5e185bd10e70d')
|
||||
self.assertEqual(
|
||||
seed.secret_view_key(),
|
||||
'1f224a0330ee358428fe91fa48b6986941030c34f2d1efecc4eb26ea9f838b02')
|
||||
self.assertEqual(
|
||||
seed.public_spend_key(),
|
||||
'149bdad48fd1ca40e1eb3e323b676132e2cae1eedbd715ac131b97c2c749c6b4')
|
||||
self.assertEqual(
|
||||
seed.public_view_key(),
|
||||
'efc1a3382c33ac58ecfdd3a71497b0d0aeef061d0af94e5c49278d653167d643')
|
||||
self.assertEqual(
|
||||
seed.public_address(),
|
||||
'42QQUPDR9PoBrSc9rB5VvG9Wf7KmtjXhEVnLhGKif9rDXGK3n1e6rsVFsh62YDqDf5buVQXuL6oLHGSHg4ANgQUu8beDd9R')
|
||||
|
||||
def test_japanese(self):
|
||||
seed = Seed(u"いもり すあな いきる しちょう うったえる ちひょう けなみ たいちょう うぶごえ しかい しなぎれ いっせい つかれる しなん ばあさん たいまつばな しひょう おいかける あんがい ていへん せんもん きこく せんく そそぐ つかれる", "Japanese")
|
||||
self.assertFalse(seed.is_mymonero())
|
||||
self.assertEqual(
|
||||
seed.secret_spend_key(),
|
||||
'a047598095d2ada065af73758f7082900b9b0d721b5f99a541a78bd461ffc607')
|
||||
self.assertEqual(
|
||||
seed.secret_view_key(),
|
||||
'080c6135edf93233176d41c8535caef0f13d596dc5093b5a5afa4279339dbc00')
|
||||
self.assertEqual(
|
||||
seed.public_spend_key(),
|
||||
'85d849793fce4d0238d991d3aab7ac790cee73e5732d378c216f11bd3b873e43')
|
||||
self.assertEqual(
|
||||
seed.public_view_key(),
|
||||
'19dc462a6074a26fa7788b45e542a71ffdbd48502e41ae8790c46fd6de556de3')
|
||||
self.assertEqual(
|
||||
seed.public_address(),
|
||||
'46hHs9s3boi1NZJHGSwMgfMFLpCBaKwdQQSSf7fqVjWdCDxudsDmqqbKgBkpYDX6JA6MMZG8o5yrMPg9ztrXHdEkSfUA131')
|
||||
|
||||
def test_portuguese(self):
|
||||
seed = Seed(u"rebuscar mefistofelico luto isca vulva ontologico autuar epiteto jarro invulneravel inquisitorial vietnamita voile potro mamute giroscopio scherzo cheroqui gueto loquaz fissurar fazer violoncelo viquingue vulva", "Portuguese")
|
||||
self.assertFalse(seed.is_mymonero())
|
||||
self.assertEqual(
|
||||
seed.secret_spend_key(),
|
||||
'60916cfcb10fa0b2b0648e36ecd7037f5c1972d36b2e6d56c2f4feca613a4200')
|
||||
self.assertEqual(
|
||||
seed.secret_view_key(),
|
||||
'b23941e3f4da76e0fab171d94a36fe70031fb501f1f80e0cb3b4b4638b5f7106')
|
||||
self.assertEqual(
|
||||
seed.public_spend_key(),
|
||||
'340c89026a03637e8b0abda566ac99b98a7c85b30a81281be19af869c3631dfb')
|
||||
self.assertEqual(
|
||||
seed.public_view_key(),
|
||||
'23bb38c5e34867c49a65f0e7192138483361d419febbd429f256088e5e62a55e')
|
||||
self.assertEqual(
|
||||
seed.public_address(),
|
||||
'43bWUqKAoYWNAdMtuaSF2pY2yptw7zfCB5fV2fXLkYTvj1NNYUKM4aaZtJCVYJunHuD5SNE2CPTCo81wDhZc8bReBidbX1w')
|
||||
|
||||
def test_russian(self):
|
||||
seed = Seed(u"дощатый ателье мыло паек азот ружье домашний уныние уплата торговля шкаф кекс газета тревога улица армия лазерный иголка друг хищник пашня дневник кричать лыжный иголка", "Russian")
|
||||
self.assertEqual(
|
||||
seed.secret_spend_key(),
|
||||
'6dc31f6ebcf834ab375a69006cb19c66fcccfa0732dfb3ea1b0662b455226b0d')
|
||||
self.assertEqual(
|
||||
seed.secret_view_key(),
|
||||
'5467825ef0148a11582115f80b01c9af90fe31216a9cf6fb2d6b3c78698ce80a')
|
||||
self.assertEqual(
|
||||
seed.public_spend_key(),
|
||||
'200657c6d14ab19cd3fccd8634e8f23e81290a559b8eb5e58dda3696553ddffc')
|
||||
self.assertEqual(
|
||||
seed.public_view_key(),
|
||||
'f7563d9efb1c03a299b9c91a604caf7fd0c5a6998fdeedf18b58a63930958a24')
|
||||
self.assertEqual(
|
||||
seed.public_address(),
|
||||
'42qVnaWnHSGTERsT6diSvdBTNbHfQZauSfPxpc5EuHc2jK699E28uwpUCRrHr9aaZ4NNyJ9ABdxX6hQHPHv2YcW55A26UbQ')
|
||||
|
||||
def test_spanish(self):
|
||||
seed = Seed(u"riesgo lápiz martes fuerza dinero pupila pago mensaje guion libro órgano juntar imperio puñal historia pasión nación posible paso límite don afirmar receta reposo fuerza", "Spanish")
|
||||
self.assertFalse(seed.is_mymonero())
|
||||
self.assertEqual(
|
||||
seed.secret_spend_key(),
|
||||
'5973d91299466a9a51ddfcd20d1710c776aa1399279b292b264ab6b7ab608105')
|
||||
self.assertEqual(
|
||||
seed.secret_view_key(),
|
||||
'5f7a66cf32120515870f89e3a156ec2024154334a3b43af1da05244ec4cf250d')
|
||||
self.assertEqual(
|
||||
seed.public_spend_key(),
|
||||
'42161417635c6bd31a8dce8c2bd3b5f4879369fb732073d9f6fa82b18329c7f7')
|
||||
self.assertEqual(
|
||||
seed.public_view_key(),
|
||||
'6acc984fecb5894b5661d446954ffcfe302cd1d2cf0e5177c2553aafb1dc3d2a')
|
||||
self.assertEqual(
|
||||
seed.public_address(),
|
||||
'448MxehQwbgcJyJ3fKnTYYhuF7g7cs7AJdTXoybMu8UEiPFtFpEVNTaDbsK5vatPHVjWwjvJfyWKiM2pBKXJrg4U5qeGXjZ')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
Loading…
Reference in a new issue