mirror of
https://github.com/permissionlesstech/georelays.git
synced 2026-07-24 20:45:18 +00:00
Use embit for Python 3.14-compatible NIP-42 signing (#11)
* Avoid native dependency for NIP-42 signing * Use embit for NIP-42 Schnorr signatures
This commit is contained in:
@@ -22,7 +22,7 @@ from typing import Set, List, Dict, Optional, Tuple
|
||||
from urllib.parse import urlparse
|
||||
import websockets
|
||||
import websockets.exceptions
|
||||
from coincurve import PrivateKey
|
||||
from embit import ec
|
||||
|
||||
|
||||
# Configure logging
|
||||
@@ -35,7 +35,6 @@ logger = logging.getLogger(__name__)
|
||||
# Save progress every N relays processed
|
||||
SAVE_POINT = 10
|
||||
|
||||
|
||||
@dataclass
|
||||
class RelayDiscoveryStats:
|
||||
"""Statistics for the relay discovery process"""
|
||||
@@ -127,10 +126,14 @@ class NostrRelayDiscovery:
|
||||
return base64.b64encode(random_bytes).decode()
|
||||
|
||||
@staticmethod
|
||||
def _load_private_key(private_key_hex: Optional[str]) -> PrivateKey:
|
||||
def _load_private_key(private_key_hex: Optional[str]) -> ec.PrivateKey:
|
||||
"""Load a configured Nostr secret or generate an ephemeral discovery key."""
|
||||
if private_key_hex is None:
|
||||
return PrivateKey()
|
||||
while True:
|
||||
try:
|
||||
return ec.PrivateKey(secrets.token_bytes(32))
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
try:
|
||||
secret = bytes.fromhex(private_key_hex)
|
||||
@@ -141,13 +144,15 @@ class NostrRelayDiscovery:
|
||||
raise ValueError("--private-key must be 64 hexadecimal characters")
|
||||
|
||||
try:
|
||||
return PrivateKey(secret)
|
||||
return ec.PrivateKey(secret)
|
||||
except ValueError as exc:
|
||||
raise ValueError("--private-key is not a valid secp256k1 secret") from exc
|
||||
raise ValueError(
|
||||
"--private-key is not a valid secp256k1 secret"
|
||||
) from exc
|
||||
|
||||
def build_auth_event(self, relay_url: str, challenge: str) -> Dict:
|
||||
"""Build and sign a NIP-42 kind 22242 authentication event."""
|
||||
pubkey = self.private_key.public_key.format(compressed=True)[1:].hex()
|
||||
pubkey = self.private_key.xonly().hex()
|
||||
event = {
|
||||
"pubkey": pubkey,
|
||||
"created_at": int(time.time()),
|
||||
@@ -172,7 +177,11 @@ class NostrRelayDiscovery:
|
||||
).encode()
|
||||
event_id = hashlib.sha256(serialized).digest()
|
||||
event["id"] = event_id.hex()
|
||||
event["sig"] = self.private_key.sign_schnorr(event_id).hex()
|
||||
signature = self.private_key.schnorr_sign(event_id)
|
||||
public_key = ec.PublicKey.from_xonly(bytes.fromhex(pubkey))
|
||||
if not public_key.schnorr_verify(signature, event_id):
|
||||
raise RuntimeError("generated an invalid BIP-340 signature")
|
||||
event["sig"] = signature.serialize().hex()
|
||||
return event
|
||||
|
||||
async def receive_with_auth(
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
websockets>=12.0
|
||||
coincurve>=20.0.0
|
||||
embit>=0.8.0
|
||||
matplotlib>=3.5.0
|
||||
pandas>=1.4.0
|
||||
numpy>=1.20.0
|
||||
|
||||
@@ -4,7 +4,7 @@ import json
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from coincurve import PublicKeyXOnly
|
||||
from embit import ec
|
||||
|
||||
from nostr_relay_discovery import NostrRelayDiscovery
|
||||
|
||||
@@ -50,8 +50,8 @@ class Nip42Tests(unittest.TestCase):
|
||||
|
||||
self.assertEqual(event["id"], event_id.hex())
|
||||
self.assertTrue(
|
||||
PublicKeyXOnly(bytes.fromhex(event["pubkey"])).verify(
|
||||
bytes.fromhex(event["sig"]), event_id
|
||||
ec.PublicKey.from_xonly(bytes.fromhex(event["pubkey"])).schnorr_verify(
|
||||
ec.SchnorrSig.parse(bytes.fromhex(event["sig"])), event_id
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user