Example #1
0
def combine_mnemonics(mnemonics: List[str]) -> Tuple[int, int, bytes, int]:
    """
    Combines mnemonic shares to obtain the encrypted master secret which was previously
    split using Shamir's secret sharing scheme.
    Returns identifier, iteration exponent and the encrypted master secret.
    """

    if not mnemonics:
        raise MnemonicError("The list of mnemonics is empty.")

    identifier, iteration_exponent, group_threshold, group_count, groups = _decode_mnemonics(
        mnemonics)

    if len(groups) != group_threshold:
        raise MnemonicError(
            "Wrong number of mnemonic groups. Expected {} groups, but {} were provided."
            .format(group_threshold, len(groups)))

    for group_index, group in groups.items():
        if len(group[1]) != group[0]:  # group[0] is threshold
            raise MnemonicError(
                "Wrong number of mnemonics. Expected {} mnemonics, but {} were provided."
                .format(group[0], len(group[1])))

    group_shares = [(group_index, _recover_secret(group[0], list(group[1])))
                    for group_index, group in groups.items()]

    encrypted_master_secret = _recover_secret(group_threshold, group_shares)
    return identifier, iteration_exponent, encrypted_master_secret, group_count
Example #2
0
def combine_mnemonics(mnemonics: List[str]) -> Tuple[int, int, bytes]:
    """
    Combines mnemonic shares to obtain the master secret which was previously split using
    Shamir's secret sharing scheme.
    :param mnemonics: List of mnemonics.
    :type mnemonics: List of strings.
    :return: Identifier, iteration exponent, the encrypted master secret.
    :rtype: Integer, integer, array of bytes.
    """

    if not mnemonics:
        raise MnemonicError("The list of mnemonics is empty.")

    identifier, iteration_exponent, group_threshold, group_count, groups = _decode_mnemonics(
        mnemonics)

    if len(groups) != group_threshold:
        raise MnemonicError(
            "Wrong number of mnemonic groups. Expected {} groups, but {} were provided."
            .format(group_threshold, len(groups)))

    for group_index, group in groups.items():
        if len(group[1]) != group[0]:
            raise MnemonicError(
                "Wrong number of mnemonics. Expected {} mnemonics, but {} were provided."
                .format(group[0], len(group[1])))

    group_shares = [(group_index, _recover_secret(group[0], list(group[1])))
                    for group_index, group in groups.items()]

    return (
        identifier,
        iteration_exponent,
        _recover_secret(group_threshold, group_shares),
    )
Example #3
0
def decode_mnemonic(mnemonic: str) -> Share:
    """Converts a share mnemonic to share data."""

    mnemonic_data = tuple(_mnemonic_to_indices(mnemonic))

    if len(mnemonic_data) < _MIN_MNEMONIC_LENGTH_WORDS:
        raise MnemonicError(
            "Invalid mnemonic length. The length of each mnemonic must be at least {} words."
            .format(_MIN_MNEMONIC_LENGTH_WORDS))

    padding_len = (_RADIX_BITS *
                   (len(mnemonic_data) - _METADATA_LENGTH_WORDS)) % 16
    if padding_len > 8:
        raise MnemonicError("Invalid mnemonic length.")

    if not _rs1024_verify_checksum(mnemonic_data):
        raise MnemonicError("Invalid mnemonic checksum.")

    id_exp_int = _int_from_indices(mnemonic_data[:_ID_EXP_LENGTH_WORDS])
    identifier = id_exp_int >> _ITERATION_EXP_LENGTH_BITS
    iteration_exponent = id_exp_int & ((1 << _ITERATION_EXP_LENGTH_BITS) - 1)
    tmp = _int_from_indices(
        mnemonic_data[_ID_EXP_LENGTH_WORDS:_ID_EXP_LENGTH_WORDS + 2])
    (
        group_index,
        group_threshold,
        group_count,
        member_index,
        member_threshold,
    ) = _int_to_indices(tmp, 5, 4)
    value_data = mnemonic_data[_ID_EXP_LENGTH_WORDS +
                               2:-_CHECKSUM_LENGTH_WORDS]

    if group_count < group_threshold:
        raise MnemonicError(
            "Invalid mnemonic. Group threshold cannot be greater than group count."
        )

    value_byte_count = _bits_to_bytes(_RADIX_BITS * len(value_data) -
                                      padding_len)
    value_int = _int_from_indices(value_data)
    if value_data[0] >= 1 << (_RADIX_BITS - padding_len):
        raise MnemonicError("Invalid mnemonic padding")
    value = value_int.to_bytes(value_byte_count, "big")

    return Share(
        identifier,
        iteration_exponent,
        group_index,
        group_threshold + 1,
        group_count + 1,
        member_index,
        member_threshold + 1,
        value,
    )
Example #4
0
def _decode_mnemonics(
    mnemonics: List[str],
) -> Tuple[int, int, int, int, MnemonicGroups]:
    identifiers = set()
    iteration_exponents = set()
    group_thresholds = set()
    group_counts = set()

    # { group_index : [threshold, set_of_member_shares] }
    groups = {}  # type: MnemonicGroups
    for mnemonic in mnemonics:
        share = decode_mnemonic(mnemonic)
        identifiers.add(share.identifier)
        iteration_exponents.add(share.iteration_exponent)
        group_thresholds.add(share.group_threshold)
        group_counts.add(share.group_count)
        group = groups.setdefault(share.group_index, (share.threshold, set()))
        if group[0] != share.threshold:
            raise MnemonicError(
                "Invalid set of mnemonics. All mnemonics in a group must have the same member threshold."
            )
        group[1].add((share.index, share.share_value))

    if len(identifiers) != 1 or len(iteration_exponents) != 1:
        raise MnemonicError(
            "Invalid set of mnemonics. All mnemonics must begin with the same {} words.".format(
                _ID_EXP_LENGTH_WORDS
            )
        )

    if len(group_thresholds) != 1:
        raise MnemonicError(
            "Invalid set of mnemonics. All mnemonics must have the same group threshold."
        )

    if len(group_counts) != 1:
        raise MnemonicError(
            "Invalid set of mnemonics. All mnemonics must have the same group count."
        )

    for group_index, group in groups.items():
        if len(set(share[0] for share in group[1])) != len(group[1]):
            raise MnemonicError(
                "Invalid set of shares. Member indices in each group must be unique."
            )

    return (
        identifiers.pop(),
        iteration_exponents.pop(),
        group_thresholds.pop(),
        group_counts.pop(),
        groups,
    )
Example #5
0
def _process_bip39(words: str) -> bytes:
    """
    Receives single mnemonic and processes it. Returns what is then stored
    in the storage, which is the mnemonic itself for BIP-39.
    """
    if not bip39.check(words):
        raise MnemonicError()
    return words.encode()
Example #6
0
def _recover_secret(threshold: int, shares: List[Tuple[int, bytes]]) -> bytes:
    # If the threshold is 1, then the digest of the shared secret is not used.
    if threshold == 1:
        return shares[0][1]

    shared_secret = shamir.interpolate(shares, _SECRET_INDEX)
    digest_share = shamir.interpolate(shares, _DIGEST_INDEX)
    digest = digest_share[:_DIGEST_LENGTH_BYTES]
    random_part = digest_share[_DIGEST_LENGTH_BYTES:]

    if digest != _create_digest(random_part, shared_secret):
        raise MnemonicError("Invalid digest of the shared secret.")

    return shared_secret