From 8aaf0facce2df44ba69d25e3226b2335ebb7225e Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 1 Oct 2026 09:07:44 +0000 Subject: [PATCH] share: Show the master fingerprint after the threshold `ms32 secret` shows the master fingerprint with the recovered secret, but `ms32 share` never did, so the operator couldn't compare it with the wallet record before writing a new card. Print it above the derived share on a terminal, whether every input is a share or one of them is the secret. `--plain` and redirected output stay unchanged. Closes #86 Claude-Session: https://claude.ai/code/session_015CuLXqAvAovfoVcUmmogwa --- src/codex32/cli.py | 4 ++++ tests/test_cli.py | 12 +++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/codex32/cli.py b/src/codex32/cli.py index 6e81e43..a23c3a5 100644 --- a/src/codex32/cli.py +++ b/src/codex32/cli.py @@ -189,6 +189,10 @@ def _share_command(index: str, plain: bool, context: _CliContext, core: BitcoinC derived = derive_share(artifacts, index) except CodexError as error: raise _CommandError(str(error)) from error + if core is not None and sys.stdout.isatty() and not plain: + given = [artifact for artifact in artifacts if isinstance(artifact, Secret)] + seed = cast(MasterSeed, given[0] if given else _secret(artifacts)) + _print(f"Master fingerprint: {core.fingerprint(seed).hex().upper()}\n") _emit(derived, plain) if sys.stdin.isatty() and sys.stdout.isatty() and not plain: try: diff --git a/tests/test_cli.py b/tests/test_cli.py index 889b175..e2b6198 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1693,13 +1693,15 @@ def test_create_rejects_bip39_partial_basis_and_selector_conflicts() -> None: assert result.exit_code != 0 -def test_terminal_secret_has_fingerprint_but_share_does_not() -> None: - secret = _invoke_terminal(["secret"], VECTOR_1["secret_s"]) +def test_terminal_secret_and_share_show_the_master_fingerprint() -> None: + secret = _invoke_terminal(["secret"], VECTOR_2["share_A"], VECTOR_2["share_C"]) share = _invoke_terminal(["share", "d"], VECTOR_2["share_A"], VECTOR_2["share_C"]) + from_secret = _invoke_terminal(["share", "d"], VECTOR_2["secret_S"], VECTOR_2["share_C"]) + fingerprint = _FakeBitcoinCore().fingerprint(cast(MasterSeed, parse_codex32(VECTOR_2["secret_S"]))) + line = f"Master fingerprint: {fingerprint.hex().upper()}" - assert secret.exit_code == share.exit_code == 0 - assert "Master fingerprint:" in secret.stdout - assert "Master fingerprint:" not in share.stdout + assert secret.exit_code == share.exit_code == from_secret.exit_code == 0 + assert line in secret.stdout and line in share.stdout and line in from_secret.stdout assert "Backup identifier:" in secret.stdout and "Backup identifier:" in share.stdout