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

rollup of many fixes and improvements, windows-compatible #84

Open
wants to merge 19 commits into
base: main
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
12 changes: 6 additions & 6 deletions nostr/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from dataclasses import dataclass, field
from enum import IntEnum
from typing import List
from secp256k1 import PublicKey
from hashlib import sha256

from . import bech32
from .message_type import ClientMessageType
from .secp import PublicKey



Expand Down Expand Up @@ -78,10 +78,8 @@ def verify(self) -> bool:
pub_key = PublicKey(bytes.fromhex("02" + self.public_key), True) # add 02 for schnorr (bip340)
return pub_key.schnorr_verify(bytes.fromhex(self.id), bytes.fromhex(self.signature), None, raw=True)


def to_message(self) -> str:
return json.dumps(
[
def to_json(self) -> list:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useful!

return [
ClientMessageType.EVENT,
{
"id": self.id,
Expand All @@ -93,7 +91,9 @@ def to_message(self) -> str:
"sig": self.signature
}
]
)

def to_message(self) -> str:
return json.dumps(self.to_json())



Expand Down
12 changes: 7 additions & 5 deletions nostr/key.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import secrets
import base64
import secp256k1
from cffi import FFI
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from hashlib import sha256

import nostr.secp as secp256k1

from .delegation import Delegation
from .event import EncryptedDirectMessage, Event, EventKind
from . import bech32
Expand Down Expand Up @@ -51,17 +52,18 @@ def from_nsec(cls, nsec: str):
raw_secret = bech32.convertbits(data, 5, 8)[:-1]
return cls(bytes(raw_secret))

@classmethod
def from_hex(cls, hex: str):
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added from_hex

""" Load a PrivateKey from its bech32/nsec form """
return cls(bytes.fromhex(hex))

def bech32(self) -> str:
converted_bits = bech32.convertbits(self.raw_secret, 8, 5)
return bech32.bech32_encode("nsec", converted_bits, bech32.Encoding.BECH32)

def hex(self) -> str:
return self.raw_secret.hex()

def tweak_add(self, scalar: bytes) -> bytes:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got rid of this because it's not used, and not tested

sk = secp256k1.PrivateKey(self.raw_secret)
return sk.tweak_add(scalar)

def compute_shared_secret(self, public_key_hex: str) -> bytes:
pk = secp256k1.PublicKey(bytes.fromhex("02" + public_key_hex), True)
return pk.ecdh(self.raw_secret, hashfn=copy_x)
Expand Down
4 changes: 2 additions & 2 deletions nostr/relay.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import time
from dataclasses import dataclass
from dataclasses import dataclass, field
from queue import Queue
from threading import Lock
from typing import Optional
Expand Down Expand Up @@ -34,7 +34,7 @@ class RelayProxyConnectionConfig:
class Relay:
url: str
message_pool: MessagePool
policy: RelayPolicy = RelayPolicy()
policy: RelayPolicy = field(default_factory=RelayPolicy)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python 3.11 fix

ssl_options: Optional[dict] = None
proxy_config: RelayProxyConnectionConfig = None

Expand Down
3 changes: 2 additions & 1 deletion nostr/relay_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ def add_relay(

threading.Thread(
target=relay.connect,
name=f"{relay.url}-thread"
name=f"{relay.url}-thread",
daemon=True
).start()

threading.Thread(
Expand Down
51 changes: 51 additions & 0 deletions nostr/secp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import coincurve
from coincurve._libsecp256k1 import ffi, lib

### compat with secp256k1 python lib

class PublicKey:
def __init__(self, pubkey=None, raw=False):
self.cc = coincurve.PublicKey(pubkey) if pubkey else None
self.__compressed = None

def serialize(self, compressed=True):
if compressed:
if not self.__compressed:
self.__compressed = self.cc.format(compressed=True)
return self.__compressed
else:
return self.cc.format(compressed=False)

def ecdh(self, scalar, hashfn=ffi.NULL, hasharg=ffi.NULL):
priv = coincurve.PrivateKey(scalar)
result = ffi.new('char [32]')
res = lib.secp256k1_ecdh(
priv.context.ctx, result, self.cc.public_key, priv.secret, hashfn, hasharg
)
if not res:
raise Exception(f'invalid scalar ({res})')
return bytes(ffi.buffer(result, 32))

def schnorr_verify(self, msg, schnorr_sig, bip340tag, raw=False):
assert bip340tag is None
assert raw
pk = coincurve.PublicKeyXOnly(self.serialize()[1:])
try:
return pk.verify(schnorr_sig, msg)
except ValueError:
return False

class PrivateKey:
def __init__(self, privkey=None, raw=True):
if not raw:
self.cc = coincurve.PrivateKey.from_der(privkey)
else:
self.cc = coincurve.PrivateKey(privkey)

self.pubkey = PublicKey()
self.pubkey.cc = coincurve.PublicKey.from_valid_secret(self.cc.secret)

def schnorr_sign(self, hash, bip340tag, raw=True):
assert bip340tag is None
assert raw
return self.cc.sign_schnorr(hash)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dependencies = [
"cryptography>=37.0.4",
"pycparser>=2.21",
"python-socks>=2.1.1",
"secp256k1>=0.14.0",
"coincurve>=18.0.0",
"websocket-client>=1.3.3",
]
license = {file = "LICENSE"}
Expand Down