|
|
|
@ -18,14 +18,13 @@
|
|
|
|
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
from trezor.crypto import pbkdf2
|
|
|
|
|
from trezor.crypto import hmac
|
|
|
|
|
from trezor.crypto import hashlib
|
|
|
|
|
import math
|
|
|
|
|
|
|
|
|
|
from trezor.crypto import hashlib, hmac, pbkdf2, random
|
|
|
|
|
from trezor.crypto.slip39_wordlist import wordlist
|
|
|
|
|
from trezor.crypto import random
|
|
|
|
|
from trezorcrypto import shamir
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConfigurationError(Exception):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
@ -150,9 +149,7 @@ class ShamirMnemonic(object):
|
|
|
|
|
def _int_to_indices(value, length, bits):
|
|
|
|
|
"""Converts an integer value to indices in big endian order."""
|
|
|
|
|
mask = (1 << bits) - 1
|
|
|
|
|
return (
|
|
|
|
|
(value >> (i * bits)) & mask for i in reversed(range(length))
|
|
|
|
|
)
|
|
|
|
|
return ((value >> (i * bits)) & mask for i in reversed(range(length)))
|
|
|
|
|
|
|
|
|
|
def mnemonic_from_indices(self, indices):
|
|
|
|
|
return " ".join(wordlist[i] for i in indices)
|
|
|
|
@ -166,7 +163,12 @@ class ShamirMnemonic(object):
|
|
|
|
|
@classmethod
|
|
|
|
|
def _round_function(cls, i, passphrase, e, salt, r):
|
|
|
|
|
"""The round function used internally by the Feistel cipher."""
|
|
|
|
|
return pbkdf2(pbkdf2.HMAC_SHA256, bytes([i]) + passphrase, salt + r, (cls.MIN_ITERATION_COUNT << e) // cls.ROUND_COUNT).key()[:len(r)]
|
|
|
|
|
return pbkdf2(
|
|
|
|
|
pbkdf2.HMAC_SHA256,
|
|
|
|
|
bytes([i]) + passphrase,
|
|
|
|
|
salt + r,
|
|
|
|
|
(cls.MIN_ITERATION_COUNT << e) // cls.ROUND_COUNT,
|
|
|
|
|
).key()[: len(r)]
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def _get_salt(cls, identifier):
|
|
|
|
@ -227,8 +229,7 @@ class ShamirMnemonic(object):
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
shares = [
|
|
|
|
|
(i, random.bytes(len(shared_secret)))
|
|
|
|
|
for i in range(random_share_count)
|
|
|
|
|
(i, random.bytes(len(shared_secret))) for i in range(random_share_count)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
random_part = random.bytes(len(shared_secret) - self.DIGEST_LENGTH_BYTES)
|
|
|
|
@ -263,8 +264,12 @@ class ShamirMnemonic(object):
|
|
|
|
|
cls, identifier, iteration_exponent, group_index, group_threshold, group_count
|
|
|
|
|
):
|
|
|
|
|
id_exp_int = (identifier << cls.ITERATION_EXP_LENGTH_BITS) + iteration_exponent
|
|
|
|
|
return tuple(cls._int_to_indices(id_exp_int, cls.ID_EXP_LENGTH_WORDS, cls.RADIX_BITS)) + (
|
|
|
|
|
(group_index << 6) + ((group_threshold - 1) << 2) + ((group_count - 1) >> 2),
|
|
|
|
|
return tuple(
|
|
|
|
|
cls._int_to_indices(id_exp_int, cls.ID_EXP_LENGTH_WORDS, cls.RADIX_BITS)
|
|
|
|
|
) + (
|
|
|
|
|
(group_index << 6)
|
|
|
|
|
+ ((group_threshold - 1) << 2)
|
|
|
|
|
+ ((group_count - 1) >> 2),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def encode_mnemonic(
|
|
|
|
@ -299,9 +304,17 @@ class ShamirMnemonic(object):
|
|
|
|
|
|
|
|
|
|
share_data = (
|
|
|
|
|
self._group_prefix(
|
|
|
|
|
identifier, iteration_exponent, group_index, group_threshold, group_count
|
|
|
|
|
identifier,
|
|
|
|
|
iteration_exponent,
|
|
|
|
|
group_index,
|
|
|
|
|
group_threshold,
|
|
|
|
|
group_count,
|
|
|
|
|
)
|
|
|
|
|
+ (
|
|
|
|
|
(((group_count - 1) & 3) << 8)
|
|
|
|
|
+ (member_index << 4)
|
|
|
|
|
+ (member_threshold - 1),
|
|
|
|
|
)
|
|
|
|
|
+ ((((group_count - 1) & 3) << 8) + (member_index << 4) + (member_threshold - 1),)
|
|
|
|
|
+ tuple(self._int_to_indices(value_int, value_word_count, self.RADIX_BITS))
|
|
|
|
|
)
|
|
|
|
|
checksum = self.rs1024_create_checksum(share_data)
|
|
|
|
@ -334,8 +347,12 @@ class ShamirMnemonic(object):
|
|
|
|
|
id_exp_int = self._int_from_indices(mnemonic_data[: self.ID_EXP_LENGTH_WORDS])
|
|
|
|
|
identifier = id_exp_int >> self.ITERATION_EXP_LENGTH_BITS
|
|
|
|
|
iteration_exponent = id_exp_int & ((1 << self.ITERATION_EXP_LENGTH_BITS) - 1)
|
|
|
|
|
tmp = self._int_from_indices(mnemonic_data[self.ID_EXP_LENGTH_WORDS: self.ID_EXP_LENGTH_WORDS + 2])
|
|
|
|
|
group_index, group_threshold, group_count, member_index, member_threshold = self._int_to_indices(tmp, 5, 4)
|
|
|
|
|
tmp = self._int_from_indices(
|
|
|
|
|
mnemonic_data[self.ID_EXP_LENGTH_WORDS : self.ID_EXP_LENGTH_WORDS + 2]
|
|
|
|
|
)
|
|
|
|
|
group_index, group_threshold, group_count, member_index, member_threshold = self._int_to_indices(
|
|
|
|
|
tmp, 5, 4
|
|
|
|
|
)
|
|
|
|
|
value_data = mnemonic_data[
|
|
|
|
|
self.ID_EXP_LENGTH_WORDS + 2 : -self.CHECKSUM_LENGTH_WORDS
|
|
|
|
|
]
|
|
|
|
@ -350,7 +367,11 @@ class ShamirMnemonic(object):
|
|
|
|
|
value_byte_count = (10 * len(value_data) - padding_len) // 8
|
|
|
|
|
value_int = self._int_from_indices(value_data)
|
|
|
|
|
if value_data[0] >= 1 << (10 - padding_len):
|
|
|
|
|
raise MnemonicError('Invalid mnemonic padding for "{} ...".'.format(" ".join(mnemonic.split()[: self.ID_EXP_LENGTH_WORDS + 2])))
|
|
|
|
|
raise MnemonicError(
|
|
|
|
|
'Invalid mnemonic padding for "{} ...".'.format(
|
|
|
|
|
" ".join(mnemonic.split()[: self.ID_EXP_LENGTH_WORDS + 2])
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
value = value_int.to_bytes(value_byte_count, "big")
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
@ -582,7 +603,11 @@ class ShamirMnemonic(object):
|
|
|
|
|
if len(groups) < group_threshold:
|
|
|
|
|
group_index, group = next(iter(bad_groups.items()))
|
|
|
|
|
prefix = self._group_prefix(
|
|
|
|
|
identifier, iteration_exponent, group_index, group_threshold, group_count
|
|
|
|
|
identifier,
|
|
|
|
|
iteration_exponent,
|
|
|
|
|
group_index,
|
|
|
|
|
group_threshold,
|
|
|
|
|
group_count,
|
|
|
|
|
)
|
|
|
|
|
raise MnemonicError(
|
|
|
|
|
'Insufficient number of mnemonics. At least {} mnemonics starting with "{} ..." are required.'.format(
|
|
|
|
|