Example #1
0
 def signature_for_solution(self, solution):
     signatures = []
     conditions_dict = conditions_by_opcode(conditions_for_solution(solution))
     for _ in hash_key_pairs_for_conditions_dict(conditions_dict):
         signature = self.sign(_)
         signatures.append(signature)
     return BLSSignature.aggregate(signatures)
Example #2
0
    def generate_recovery_transaction(self, coins, root_public_key, secret_key,
                                      escrow_duration):
        recovery_pubkey = root_public_key.public_child(
            0).get_public_key().serialize()
        signatures = []
        coin_solutions = []
        secret_key = BLSPrivateKey(secret_key)
        for coin in coins:
            pubkey = self.find_pubkey_for_escrow_puzzle(
                coin, root_public_key, escrow_duration)
            puzzle = self.get_escrow_puzzle_with_params(
                recovery_pubkey, pubkey.serialize(), escrow_duration)

            op_create_coin = ConditionOpcode.CREATE_COIN[0]
            puzzlehash = f'0x' + str(hexbytes(self.get_new_puzzlehash()))
            solution_src = sexp(
                quote(sexp(sexp(op_create_coin, puzzlehash, coin.amount))),
                sexp(), 1)
            solution = Program(binutils.assemble(solution_src))

            puzzle_solution_list = clvm.to_sexp_f([puzzle, solution])
            coin_solution = CoinSolution(coin, puzzle_solution_list)
            coin_solutions.append(coin_solution)

            conditions_dict = conditions_by_opcode(
                conditions_for_solution(puzzle_solution_list))
            for _ in hash_key_pairs_for_conditions_dict(conditions_dict):
                signature = secret_key.sign(_.message_hash)
                signatures.append(signature)

        coin_solution_list = CoinSolutionList(coin_solutions)
        aggsig = BLSSignature.aggregate(signatures)
        spend_bundle = SpendBundle(coin_solution_list, aggsig)
        return spend_bundle
Example #3
0
def generate_signatures(pst, private_wallet):
    """
    For a given unfinalized SpendBundle, look at the hints to see if the given
    private wallet can generate any signatures, and generate them.
    """
    hd_hints = pst.get("hd_hints")
    sigs = {}
    private_fingerprint = private_wallet.fingerprint()

    for coin_solution in pst.get("coin_solutions"):
        solution = coin_solution.solution
        # run maximal_solution and get conditions
        conditions_dict = conditions_dict_for_solution(solution)
        # look for AGG_SIG conditions
        hkp_list = hash_key_pairs_for_conditions_dict(conditions_dict)
        # see if we have enough info to build signatures
        for aggsig_pair in hkp_list:
            pub_key = aggsig_pair.public_key
            message_hash = aggsig_pair.message_hash
            fp = fingerprint_for_pk(pub_key)
            if fp in hd_hints:
                hint = hd_hints[fp]
                if private_fingerprint == hint.get("hd_fingerprint"):
                    private_key = private_wallet.private_child(hint.get("index"))
                    signature = private_key.sign(message_hash)
                    sigs[aggsig_pair] = signature
    return list(sigs.values())
Example #4
0
def sigs_to_aggsig_sig_dict(wallet, pst, sigs):
    """
    Figure out which signatures in sigs correspond to which
    aggsig pairs in the unfinalized SpendBundle pst.

    Return a dictionary with keys that are aggsig pairs and
    signature values.

    This is an n^2 algorithm, so not ideal, but fine for small
    M and N.
    """
    all_sigs_dict = {}
    all_aggsigs = set()
    for coin_solution in pst.get("coin_solutions"):
        solution = coin_solution.solution
        conditions_dict = conditions_dict_for_solution(solution)
        hkp_list = hash_key_pairs_for_conditions_dict(conditions_dict)
        all_aggsigs.update(hkp_list)
    for sig in sigs:
        for aggsig in all_aggsigs:
            if sig.validate([aggsig]):
                all_sigs_dict[aggsig] = sig
                all_aggsigs.remove(aggsig)
                break
    return all_sigs_dict
Example #5
0
 def sign_transaction(self, spends: (Program, [CoinSolution])):
     sigs = []
     for puzzle, solution in spends:
         pubkey, secretkey = self.get_keys(solution.coin.puzzle_hash)
         code_ = [puzzle, solution.solution]
         sexp = clvm.to_sexp_f(code_)
         conditions_dict = conditions_by_opcode(
             conditions_for_solution(sexp))
         for _ in hash_key_pairs_for_conditions_dict(conditions_dict):
             signature = secretkey.sign(_.message_hash)
             sigs.append(signature)
     aggsig = BLSSignature.aggregate(sigs)
     solution_list = CoinSolutionList(
         [CoinSolution(coin_solution.coin, clvm.to_sexp_f([puzzle, coin_solution.solution])) for
          (puzzle, coin_solution) in spends])
     spend_bundle = SpendBundle(solution_list, aggsig)
     return spend_bundle
Example #6
0
def finalize_pst(wallet, pst, sigs):
    """
    Return a pair (SpendBundle or None, summary_list).

    If we have a finalized SpendBundle, it's returned, otherwise None,
    The summary_list item is a list of items (coin, hkp_list, sigs_to_use, m)
    which allows the UI to give the end user information about which
    coins still need signatures.

    Note that hkp is short for hash_key_pair (ie. aggsig pair)
    """
    m = wallet.m()
    coin_solutions = []
    sig_dict = sigs_to_aggsig_sig_dict(wallet, pst, sigs)

    all_sigs_to_use = []

    summary_list = []

    for coin_solution in pst.get("coin_solutions"):
        coin, solution = coin_solution.coin, coin_solution.solution
        # run maximal_solution and get conditions
        conditions_dict = conditions_dict_for_solution(solution)
        # look for AGG_SIG conditions
        hkp_list = hash_key_pairs_for_conditions_dict(conditions_dict)
        # see if we have enough info to build signatures
        found_list = []
        sigs_to_use = []
        for aggsig_pair in hkp_list:
            add_me = 0
            if len(sigs_to_use) < m:
                if aggsig_pair in sig_dict:
                    sigs_to_use.append(sig_dict[aggsig_pair])
                    add_me = 1
            found_list.append(add_me)

        all_sigs_to_use.extend(sigs_to_use)

        conditions = pst.get("conditions")
        delegated_puzzle = puzzle_for_conditions(conditions)
        delegated_solution = solution_for_conditions(conditions)

        index = wallet.index_for_puzzle_hash(coin.puzzle_hash, GAP_LIMIT)
        pub_keys = wallet.pub_keys_for_index(index)
        actual_solution = solution_for_delegated_puzzle(
            m, pub_keys, found_list, delegated_puzzle, delegated_solution
        )

        coin_solution = CoinSolution(coin, actual_solution)
        coin_solutions.append(coin_solution)
        summary = (coin, hkp_list, sigs_to_use, m)
        summary_list.append(summary)

    if len(all_sigs_to_use) > 0:
        aggregated_sig = all_sigs_to_use[0].aggregate(all_sigs_to_use)
        spend_bundle = SpendBundle(coin_solutions, aggregated_sig)
        try:
            if validate_spend_bundle_signature(spend_bundle):
                return spend_bundle, summary_list
        except Exception:
            pass

    return None, summary_list