Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SECP256K1 Member Puzzle #18870

Open
wants to merge 9 commits into
base: quex.multi_sig_chialisp_drivers
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 79 additions & 1 deletion chia/_tests/clvm/test_member_puzzles.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@
PuzzleWithRestrictions,
Restriction,
)
from chia.wallet.puzzles.custody.member_puzzles.member_puzzles import BLSMember, PasskeyMember, SECPR1Member
from chia.wallet.puzzles.custody.member_puzzles.member_puzzles import (
BLSMember,
PasskeyMember,
SECPK1Member,
SECPR1Member,
)
from chia.wallet.wallet_spend_bundle import WalletSpendBundle


Expand Down Expand Up @@ -355,3 +360,76 @@ async def test_secp256r1_member(cost_logger: CostLogger) -> None:
assert result == (MempoolInclusionStatus.SUCCESS, None)
await sim.farm_block()
await sim.rewind(block_height)


@pytest.mark.anyio
async def test_secp256k1_member(cost_logger: CostLogger) -> None:
async with sim_and_client() as (sim, client):
delegated_puzzle = Program.to(1)
delegated_puzzle_hash = delegated_puzzle.get_tree_hash()

# setup keys
secp_sk = ec.generate_private_key(ec.SECP256K1())
secp_pk = secp_sk.public_key().public_bytes(Encoding.X962, PublicFormat.CompressedPoint)

secpk1_member = SECPK1Member(secp_pk)

secpk1_puzzle = PuzzleWithRestrictions(0, [], secpk1_member)

# Farm and find coin
await sim.farm_block(secpk1_puzzle.puzzle_hash())
coin = (
await client.get_coin_records_by_puzzle_hashes([secpk1_puzzle.puzzle_hash()], include_spent_coins=False)
)[0].coin
block_height = sim.block_height

# Create an announcements to be asserted in the delegated puzzle
announcement = CreateCoinAnnouncement(msg=b"foo", coin_id=coin.name())

# Get signature for AGG_SIG_ME
coin_id = coin.name()
signature_message = delegated_puzzle_hash + coin_id
der_sig = secp_sk.sign(
signature_message,
# The type stubs are weird here, `deterministic_signing` is assuredly an argument
ec.ECDSA(hashes.SHA256(), deterministic_signing=True), # type: ignore[call-arg]
)
r, s = decode_dss_signature(der_sig)
sig = r.to_bytes(32, byteorder="big") + s.to_bytes(32, byteorder="big")
sb = WalletSpendBundle(
[
make_spend(
coin,
secpk1_puzzle.puzzle_reveal(),
secpk1_puzzle.solve(
[],
[],
Program.to(
[
coin_id,
sig,
]
),
DelegatedPuzzleAndSolution(
delegated_puzzle,
Program.to(
[
announcement.to_program(),
announcement.corresponding_assertion().to_program(),
]
),
),
),
)
],
G2Element(),
)
result = await client.push_tx(
cost_logger.add_cost(
"secp spendbundle",
sb,
)
)
assert result == (MempoolInclusionStatus.SUCCESS, None)
await sim.farm_block()
await sim.rewind(block_height)
18 changes: 18 additions & 0 deletions chia/wallet/puzzles/custody/member_puzzles/member_puzzles.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
"secp256r1_member.clsp", package_or_requirement="chia.wallet.puzzles.custody.member_puzzles"
)

SECPK1_MEMBER_MOD = load_clvm_maybe_recompile(
"secp256k1_member.clsp", package_or_requirement="chia.wallet.puzzles.custody.member_puzzles"
)


@dataclass(frozen=True)
class BLSMember(Puzzle):
Expand Down Expand Up @@ -80,3 +84,17 @@ def puzzle(self, nonce: int) -> Program:

def puzzle_hash(self, nonce: int) -> bytes32:
return self.puzzle(nonce).get_tree_hash()


@dataclass(frozen=True)
class SECPK1Member(Puzzle):
secp_pk: bytes

def memo(self, nonce: int) -> Program:
return Program.to(0)

def puzzle(self, nonce: int) -> Program:
return SECPK1_MEMBER_MOD.curry(self.secp_pk)

def puzzle_hash(self, nonce: int) -> bytes32:
return self.puzzle(nonce).get_tree_hash()
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
; this puzzle follows the Managed Inner Puzzle Spec MIPS01 as a Member Puzzle
; this code offers a secure approval of a delegated puzzle passed in as a Truth to be run elsewhere

(mod (SECP_PK Delegated_Puzzle_Hash my_id signature) ; delegated puzzle is passed in from the above M of N layer
(include condition_codes.clib)

(c
(list ASSERT_MY_COIN_ID my_id)
(secp256k1_verify SECP_PK (sha256 Delegated_Puzzle_Hash my_id) signature)
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ff02ffff01ff04ffff04ff02ffff04ff17ff808080ffff8413d61f00ff05ffff0bff0bff1780ff2f8080ffff04ffff0146ff018080
1 change: 1 addition & 0 deletions chia/wallet/puzzles/deployed_puzzle_hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"restrictions": "a28d59d39f964a93159c986b1914694f6f2f1c9901178f91e8b0ba4045980eef",
"rom_bootstrap_generator": "161bade1f822dcd62ab712ebaf30f3922a301e48a639e4295c5685f8bece7bd9",
"secp256r1_member": "05aaa1f2fb6c48b5bce952b09f3da99afa4241989878a9919aafb7d74b70ac54",
"secp256k1_member": "2b05daf134c9163acc8f2ac05b61f7d8328fca3dcc963154a28e89bcfc4dbfca",
"settlement_payments": "cfbfdeed5c4ca2de3d0bf520b9cb4bb7743a359bd2e6a188d19ce7dffc21d3e7",
"singleton_launcher": "eff07522495060c066f66f32acc2a77e3a3e737aca8baea4d1a64ea4cdc13da9",
"singleton_top_layer": "24e044101e57b3d8c908b8a38ad57848afd29d3eecc439dba45f4412df4954fd",
Expand Down
Loading