From 680e358a0a28e5c6f03e9bde638e884b333f987c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ioan=20Biz=C4=83u?= Date: Wed, 22 Jan 2025 17:49:31 +0100 Subject: [PATCH] fix(core): use BIP-340 to sign Nostr events [no changelog] --- core/src/apps/nostr/sign_event.py | 4 +- tests/device_tests/nostr/test_nostr.py | 63 +++++++++++--------------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/core/src/apps/nostr/sign_event.py b/core/src/apps/nostr/sign_event.py index 95d02b8a6c..6af48682b5 100644 --- a/core/src/apps/nostr/sign_event.py +++ b/core/src/apps/nostr/sign_event.py @@ -13,7 +13,7 @@ async def sign_event(msg: NostrSignEvent, keychain: Keychain) -> NostrEventSigna from ubinascii import hexlify from trezor import TR - from trezor.crypto.curve import secp256k1 + from trezor.crypto.curve import bip340 from trezor.crypto.hashlib import sha256 from trezor.messages import NostrEventSignature from trezor.ui.layouts import confirm_value @@ -54,7 +54,7 @@ async def sign_event(msg: NostrSignEvent, keychain: Keychain) -> NostrEventSigna event_id = sha256(serialized_event).digest() # The event signature is basically the signature of the event ID computed above - signature = secp256k1.sign(sk, event_id)[-64:] + signature = bip340.sign(node.private_key(), event_id) return NostrEventSignature( pubkey=pk, diff --git a/tests/device_tests/nostr/test_nostr.py b/tests/device_tests/nostr/test_nostr.py index 9a8efe6835..465ca256eb 100644 --- a/tests/device_tests/nostr/test_nostr.py +++ b/tests/device_tests/nostr/test_nostr.py @@ -18,8 +18,6 @@ import json from hashlib import sha256 import pytest -from ecdsa import SECP256k1, VerifyingKey -from six import b from trezorlib import messages, nostr from trezorlib.tools import parse_path @@ -35,18 +33,25 @@ LEAD_MONKEY_PUBKEY_HEX = ( "17162c921dc4d2518f9a101db33695df1afb56ab82f5ff3e5da6eec3ca5cd917" ) +LEAD_MONKEY_EXPECTED_SIG = "a2981b2f9858184226a0c63ec000102bedfc35afcb2e7cb4a91bdd3a95d4faeeb6afb523ebae1f3a2889ed93be6b8f3d86e0ab1e9dd0fe4ebc7bf75ba9a4dc78" + WHAT_BLEAK_MNEMONIC = "what bleak badge arrange retreat wolf trade produce cricket blur garlic valid proud rude strong choose busy staff weather area salt hollow arm fade" WHAT_BLEAK_PUBKEY_HEX = ( "d41b22899549e1f3d335a31002cfd382174006e166d3e658e3a5eecdb6463573" ) +WHAT_BLEAK_EXPECTED_SIG = "dbfc47f0174ef263e471d07b5df99a6a9eb88b881250a207f67bff344c3503b8544cd25a4f4d183773ed11edfe3d3741925cb2fa9def09dcac3bab7d11d835ac" pytestmark_lead_monkey = pytest.mark.setup_client(mnemonic=LEAD_MONKEY_MNEMONIC) pytestmark_what_bleak = pytest.mark.setup_client(mnemonic=WHAT_BLEAK_MNEMONIC) VECTORS = [ - pytest.param(LEAD_MONKEY_PUBKEY_HEX, marks=pytestmark_lead_monkey), - pytest.param(WHAT_BLEAK_PUBKEY_HEX, marks=pytestmark_what_bleak), + pytest.param( + LEAD_MONKEY_PUBKEY_HEX, LEAD_MONKEY_EXPECTED_SIG, marks=pytestmark_lead_monkey + ), + pytest.param( + WHAT_BLEAK_PUBKEY_HEX, WHAT_BLEAK_EXPECTED_SIG, marks=pytestmark_what_bleak + ), ] TEST_EVENT = { @@ -81,8 +86,8 @@ SIGN_TEST_EVENT = messages.NostrSignEvent( ) -@pytest.mark.parametrize("pubkey_hex", VECTORS) -def test_get_pubkey(client, pubkey_hex): +@pytest.mark.parametrize("pubkey_hex,_", VECTORS) +def test_get_pubkey(client, pubkey_hex, _): response = nostr.get_pubkey( client, n=parse_path("m/44h/1237h/0h/0/0"), @@ -91,39 +96,25 @@ def test_get_pubkey(client, pubkey_hex): assert response == bytes.fromhex(pubkey_hex) -@pytest.mark.parametrize("pubkey_hex", VECTORS) -def test_sign_event(client, pubkey_hex): +@pytest.mark.parametrize("pubkey_hex,expected_sig", VECTORS) +def test_sign_event(client, pubkey_hex, expected_sig): response = nostr.sign_event(client, SIGN_TEST_EVENT) assert response.pubkey == bytes.fromhex(pubkey_hex) - expected_id = ( - sha256( - json.dumps( - [ - 0, - pubkey_hex, - TEST_EVENT["created_at"], - TEST_EVENT["kind"], - TEST_EVENT["tags"], - TEST_EVENT["content"], - ], - separators=(",", ":"), - ).encode() - ) - .digest() - .hex() - ) + expected_id = sha256( + json.dumps( + [ + 0, + pubkey_hex, + TEST_EVENT["created_at"], + TEST_EVENT["kind"], + TEST_EVENT["tags"], + TEST_EVENT["content"], + ], + separators=(",", ":"), + ).encode() + ).digest() assert response.id == expected_id - - vk = VerifyingKey.from_string( - b("\x03") + bytes.fromhex(pubkey_hex), - curve=SECP256k1, - # this is a pretty silly way to tell VerifyingKey - # that we do not want the message to be hashed - # when verifying the signature! - hashfunc=lambda x: type("h", (), {"digest": lambda: x}), - ) - - assert vk.verify(bytes.fromhex(response.signature), bytes.fromhex(response.id)) + assert response.signature == bytes.fromhex(expected_sig)