async def sign(self, spend_bundle: SpendBundle) -> SpendBundle: sigs: List[G2Element] = [] for spend in spend_bundle.coin_spends: matched, puzzle_args = match_cat_puzzle( spend.puzzle_reveal.to_program()) if matched: _, _, inner_puzzle = puzzle_args puzzle_hash = inner_puzzle.get_tree_hash() pubkey, private = await self.wallet_state_manager.get_keys( puzzle_hash) synthetic_secret_key = calculate_synthetic_secret_key( private, DEFAULT_HIDDEN_PUZZLE_HASH) error, conditions, cost = conditions_dict_for_solution( spend.puzzle_reveal.to_program(), spend.solution.to_program(), self.wallet_state_manager.constants.MAX_BLOCK_COST_CLVM, ) if conditions is not None: synthetic_pk = synthetic_secret_key.get_g1() for pk, msg in pkm_pairs_for_conditions_dict( conditions, spend.coin.name(), self.wallet_state_manager.constants. AGG_SIG_ME_ADDITIONAL_DATA): try: assert bytes(synthetic_pk) == pk sigs.append( AugSchemeMPL.sign(synthetic_secret_key, msg)) except AssertionError: raise ValueError( "This spend bundle cannot be signed by the CAT wallet" ) agg_sig = AugSchemeMPL.aggregate(sigs) return SpendBundle.aggregate([spend_bundle, SpendBundle([], agg_sig)])
def sign_transaction(self, coin_solutions: List[CoinSolution]) -> SpendBundle: signatures = [] solution: Program puzzle: Program for coin_solution in coin_solutions: # type: ignore # noqa secret_key = self.get_private_key_for_puzzle_hash( coin_solution.coin.puzzle_hash) synthetic_secret_key = calculate_synthetic_secret_key( secret_key, DEFAULT_HIDDEN_PUZZLE_HASH) err, con, cost = conditions_for_solution( coin_solution.puzzle_reveal, coin_solution.solution, self.constants.MAX_BLOCK_COST_CLVM) if not con: raise ValueError(err) conditions_dict = conditions_by_opcode(con) for _, msg in pkm_pairs_for_conditions_dict( conditions_dict, bytes(coin_solution.coin.name()), self.constants.AGG_SIG_ME_ADDITIONAL_DATA): signature = AugSchemeMPL.sign(synthetic_secret_key, msg) signatures.append(signature) aggsig = AugSchemeMPL.aggregate(signatures) spend_bundle = SpendBundle(coin_solutions, aggsig) return spend_bundle
def __init__(self, parent, name, pk, priv): """Internal use constructor, use Network::make_wallet Fields: parent - The Network object that created this Wallet name - The textural name of the actor pk_ - The actor's public key sk_ - The actor's private key usable_coins - Standard coins spendable by this actor puzzle - A program for creating this actor's standard coin puzzle_hash - The puzzle hash for this actor's standard coin pk_to_sk_dict - a dictionary for retrieving the secret keys when presented with the corresponding public key """ self.parent = parent self.name = name self.pk_ = pk self.sk_ = priv self.usable_coins = {} self.puzzle = puzzle_for_pk(self.pk()) self.puzzle_hash = self.puzzle.get_tree_hash() synth_sk = calculate_synthetic_secret_key(self.sk_, DEFAULT_HIDDEN_PUZZLE_HASH) self.pk_to_sk_dict = { str(self.pk_): self.sk_, str(synth_sk.get_g1()): synth_sk }
def sign_transaction(self, coin_spends: List[CoinSpend]) -> SpendBundle: signatures = [] solution: Program puzzle: Program for coin_spend in coin_spends: # noqa secret_key = self.get_private_key_for_puzzle_hash(coin_spend.coin.puzzle_hash) synthetic_secret_key = calculate_synthetic_secret_key(secret_key, DEFAULT_HIDDEN_PUZZLE_HASH) err, con, cost = conditions_for_solution( coin_spend.puzzle_reveal, coin_spend.solution, self.constants.MAX_BLOCK_COST_CLVM ) if not con: raise ValueError(err) conditions_dict = conditions_by_opcode(con) for cwa in conditions_dict.get(ConditionOpcode.AGG_SIG_UNSAFE, []): msg = cwa.vars[1] signature = AugSchemeMPL.sign(synthetic_secret_key, msg) signatures.append(signature) for cwa in conditions_dict.get(ConditionOpcode.AGG_SIG_ME, []): msg = cwa.vars[1] + bytes(coin_spend.coin.name()) + self.constants.AGG_SIG_ME_ADDITIONAL_DATA signature = AugSchemeMPL.sign(synthetic_secret_key, msg) signatures.append(signature) aggsig = AugSchemeMPL.aggregate(signatures) spend_bundle = SpendBundle(coin_spends, aggsig) return spend_bundle
def sign_delegated_puz(self, del_puz: Program, coin: Coin) -> G2Element: synthetic_secret_key: PrivateKey = p2_delegated_puzzle_or_hidden_puzzle.calculate_synthetic_secret_key( # noqa PrivateKey.from_bytes( secret_exponent_for_index(1).to_bytes(32, "big"), ), p2_delegated_puzzle_or_hidden_puzzle.DEFAULT_HIDDEN_PUZZLE_HASH, ) return AugSchemeMPL.sign( synthetic_secret_key, (del_puz.get_tree_hash() + coin.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA), # noqa )
async def get_sigs(self, innerpuz: Program, innersol: Program, coin_name: bytes32) -> List[G2Element]: puzzle_hash = innerpuz.get_tree_hash() pubkey, private = await self.wallet_state_manager.get_keys(puzzle_hash) synthetic_secret_key = calculate_synthetic_secret_key(private, DEFAULT_HIDDEN_PUZZLE_HASH) sigs: List[G2Element] = [] error, conditions, cost = conditions_dict_for_solution(innerpuz, innersol) if conditions is not None: for _, msg in pkm_pairs_for_conditions_dict( conditions, coin_name, self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA ): signature = AugSchemeMPL.sign(synthetic_secret_key, msg) sigs.append(signature) return sigs
async def hack_populate_secret_key_for_puzzle_hash(self, puzzle_hash: bytes32) -> G1Element: maybe = await self.wallet_state_manager.get_keys(puzzle_hash) if maybe is None: error_msg = f"Wallet couldn't find keys for puzzle_hash {puzzle_hash}" self.log.error(error_msg) raise ValueError(error_msg) # Get puzzle for pubkey public_key, secret_key = maybe # HACK synthetic_secret_key = calculate_synthetic_secret_key(secret_key, DEFAULT_HIDDEN_PUZZLE_HASH) self.secret_key_store.save_secret_key(synthetic_secret_key) return public_key
async def launch_smart_coin(self, source, **kwargs) -> CoinWrapper: """Create a new smart coin based on a parent coin and return the smart coin's living coin to the user or None if the spend failed.""" amt = 1 if 'amt' in kwargs: amt = kwargs['amt'] found_coin = await self.choose_coin(amt) if found_coin is None: raise ValueError( f'could not find available coin containing {amt} mojo') # Create a puzzle based on the incoming smart coin cw = ContractWrapper(DEFAULT_CONSTANTS.GENESIS_CHALLENGE, source) condition_args = [ [ConditionOpcode.CREATE_COIN, cw.puzzle_hash(), amt], ] if amt < found_coin.amount: condition_args.append([ ConditionOpcode.CREATE_COIN, self.puzzle_hash, found_coin.amount - amt ]) delegated_puzzle_solution = Program.to((1, condition_args)) solution = Program.to([[], delegated_puzzle_solution, []]) # Sign the (delegated_puzzle_hash + coin_name) with synthetic secret key signature = AugSchemeMPL.sign( calculate_synthetic_secret_key(self.sk_, DEFAULT_HIDDEN_PUZZLE_HASH), (delegated_puzzle_solution.get_tree_hash() + found_coin.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA)) spend_bundle = SpendBundle( [ CoinSpend( found_coin.as_coin(), # Coin to spend self.puzzle, # Puzzle used for found_coin solution, # The solution to the puzzle locking found_coin ) ], signature) pushed = await self.parent.push_tx(spend_bundle) if 'error' not in pushed: return cw.custom_coin(found_coin, amt) else: return None
def sign_tx(pks: List[str], spend_bundle: SpendBundle): # This field is the ADDITIONAL_DATA found in the constants additional_data: bytes = bytes.fromhex( "ccd5bb71183532bff220ba46c268991a3ff07eb358e8255a65c30a2dce0e5fbb") puzzle_hash_to_sk: Dict[bytes32, PrivateKey] = {} for p in pks: child_sk: PrivateKey = PrivateKey.from_bytes(bytes.fromhex(p)) # master_private_key = PrivateKey.from_bytes( # bytes.fromhex(p)) # child_sk = master_sk_to_wallet_sk(master_private_key, 242) child_pk: G1Element = child_sk.get_g1() puzzle = puzzle_for_pk(child_pk) puzzle_hash = puzzle.get_tree_hash() puzzle_hash_to_sk[puzzle_hash] = child_sk aggregate_signature: G2Element = G2Element() for coin_solution in spend_bundle.coin_solutions: if coin_solution.coin.puzzle_hash not in puzzle_hash_to_sk: return sk: PrivateKey = puzzle_hash_to_sk[coin_solution.coin.puzzle_hash] synthetic_secret_key: PrivateKey = calculate_synthetic_secret_key( sk, DEFAULT_HIDDEN_PUZZLE_HASH) err, conditions_dict, cost = conditions_dict_for_solution( coin_solution.puzzle_reveal, coin_solution.solution, 11000000000) if err or conditions_dict is None: print( f"Sign transaction failed, con:{conditions_dict}, error: {err}" ) return pk_msgs = pkm_pairs_for_conditions_dict( conditions_dict, bytes(coin_solution.coin.name()), additional_data) assert len(pk_msgs) == 1 _, msg = pk_msgs[0] signature = AugSchemeMPL.sign(synthetic_secret_key, msg) aggregate_signature = AugSchemeMPL.aggregate( [aggregate_signature, signature]) new_spend_bundle = SpendBundle(spend_bundle.coin_solutions, aggregate_signature) # print(json.dumps(new_spend_bundle.to_json_dict())) return json.dumps(new_spend_bundle.to_json_dict())
def create_standard_spend(self, priv, conditions): delegated_puzzle_solution = Program.to((1, conditions)) solution = Program.to([[], delegated_puzzle_solution, []]) coin_solution_object = CoinSpend( self.as_coin(), self.puzzle(), solution, ) # Create a signature for each of these. We'll aggregate them at the end. signature = AugSchemeMPL.sign( calculate_synthetic_secret_key(priv, DEFAULT_HIDDEN_PUZZLE_HASH), (delegated_puzzle_solution.get_tree_hash() + self.name() + DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA)) return coin_solution_object, signature
def sign_tx(intermediate_sk: PrivateKey, spend_bundle: SpendBundle, use_hardened_keys: bool): """ Takes in an unsigned transaction (called a spend bundle in chia), and a 24 word mnemonic (master sk) and generates the aggregate BLS signature for the transaction. """ # This field is the ADDITIONAL_DATA found in the constants additional_data: bytes = bytes.fromhex( "ccd5bb71183532bff220ba46c268991a3ff07eb358e8255a65c30a2dce0e5fbb") puzzle_hash_to_sk: Dict[bytes32, PrivateKey] = {} if use_hardened_keys: # Change this loop to scan more keys if you have more for i in range(5000): child_sk: PrivateKey = AugSchemeMPL.derive_child_sk( intermediate_sk, i) child_pk: G1Element = child_sk.get_g1() puzzle = puzzle_for_pk(child_pk) puzzle_hash = puzzle.get_tree_hash() puzzle_hash_to_sk[puzzle_hash] = child_sk else: # Change this loop to scan more keys if you have more for i in range(5000): child_sk: PrivateKey = AugSchemeMPL.derive_child_sk_unhardened( intermediate_sk, i) child_pk: G1Element = child_sk.get_g1() puzzle = puzzle_for_pk(child_pk) puzzle_hash = puzzle.get_tree_hash() puzzle_hash_to_sk[puzzle_hash] = child_sk aggregate_signature: G2Element = G2Element() for coin_solution in spend_bundle.coin_solutions: if coin_solution.coin.puzzle_hash not in puzzle_hash_to_sk: print( f"Puzzle hash {coin_solution.coin.puzzle_hash} not found for this key." ) return sk: PrivateKey = puzzle_hash_to_sk[coin_solution.coin.puzzle_hash] synthetic_secret_key: PrivateKey = calculate_synthetic_secret_key( sk, DEFAULT_HIDDEN_PUZZLE_HASH) err, conditions_dict, cost = conditions_dict_for_solution( coin_solution.puzzle_reveal, coin_solution.solution, 11000000000) if err or conditions_dict is None: print( f"Sign transaction failed, con:{conditions_dict}, error: {err}" ) return pk_msgs = pkm_pairs_for_conditions_dict( conditions_dict, bytes(coin_solution.coin.name()), additional_data) assert len(pk_msgs) == 1 _, msg = pk_msgs[0] signature = AugSchemeMPL.sign(synthetic_secret_key, msg) aggregate_signature = AugSchemeMPL.aggregate( [aggregate_signature, signature]) new_spend_bundle = SpendBundle(spend_bundle.coin_solutions, aggregate_signature) print("") print("Signed spend bundle JSON:\n") print(json.dumps(new_spend_bundle.to_json_dict()))