diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 450f791..988e25c 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -29,15 +29,6 @@ jobs: with: go-version: "1.25" - - name: Install libsecp256k1 - run: ./scripts/ubuntu_install_libsecp256k1.sh - - - name: Build with cgo - run: go build -v ./... - - - name: Test with cgo - run: go test -v $(go list ./... | xargs -n1 sh -c 'ls $0/*_test.go 1>/dev/null 2>&1 && echo $0' | grep .) - - name: Set CGO off run: echo "CGO_ENABLED=0" >> $GITHUB_ENV @@ -61,9 +52,6 @@ jobs: with: go-version: '1.25' - - name: Install libsecp256k1 - run: ./scripts/ubuntu_install_libsecp256k1.sh - - name: Build Release Binaries if: startsWith(github.ref, 'refs/tags/v') run: | @@ -75,11 +63,7 @@ jobs: mkdir -p release-binaries # Build for different platforms - GOEXPERIMENT=greenteagc,jsonv2 GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -ldflags "-s -w" -o release-binaries/orly-${VERSION}-linux-amd64 . - # GOEXPERIMENT=greenteagc,jsonv2 GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o release-binaries/orly-${VERSION}-linux-arm64 . - # GOEXPERIMENT=greenteagc,jsonv2 GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -o release-binaries/orly-${VERSION}-darwin-amd64 . - # GOEXPERIMENT=greenteagc,jsonv2 GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -o release-binaries/orly-${VERSION}-darwin-arm64 . - # GOEXPERIMENT=greenteagc,jsonv2 GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o release-binaries/orly-${VERSION}-windows-amd64.exe . + GOEXPERIMENT=greenteagc,jsonv2 GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -o release-binaries/orly-${VERSION}-linux-amd64 . # Note: Only building orly binary as requested # Other cmd utilities (aggregator, benchmark, convert, policytest, stresstest) are development tools diff --git a/app/handle-relayinfo.go b/app/handle-relayinfo.go index 1f4aff9..c1cd33b 100644 --- a/app/handle-relayinfo.go +++ b/app/handle-relayinfo.go @@ -9,7 +9,7 @@ import ( "lol.mleku.dev/chk" "lol.mleku.dev/log" "next.orly.dev/pkg/acl" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/protocol/relayinfo" "next.orly.dev/pkg/version" @@ -74,7 +74,7 @@ func (s *Server) HandleRelayInfo(w http.ResponseWriter, r *http.Request) { // Get relay identity pubkey as hex var relayPubkey string if skb, err := s.D.GetRelayIdentitySecret(); err == nil && len(skb) == 32 { - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.InitSec(skb); err == nil { relayPubkey = hex.Enc(sign.Pub()) } diff --git a/app/listener.go b/app/listener.go index 6b451e6..3de96dc 100644 --- a/app/listener.go +++ b/app/listener.go @@ -49,13 +49,37 @@ func (l *Listener) Ctx() context.Context { // writeWorker is the single goroutine that handles all writes to the websocket connection. // This serializes all writes to prevent concurrent write panics. func (l *Listener) writeWorker() { - defer close(l.writeDone) + var channelClosed bool + defer func() { + // Only unregister write channel if connection is actually dead/closing + // Unregister if: + // 1. Context is cancelled (connection closing) + // 2. Channel was closed (connection closing) + // 3. Connection error occurred (already handled inline) + if l.ctx.Err() != nil || channelClosed { + // Connection is closing - safe to unregister + if socketPub := l.publishers.GetSocketPublisher(); socketPub != nil { + log.D.F("ws->%s write worker: unregistering write channel (connection closing)", l.remote) + socketPub.SetWriteChan(l.conn, nil) + } + } else { + // Exiting for other reasons (timeout, etc.) but connection may still be alive + // Don't unregister - let the connection cleanup handle it + log.D.F("ws->%s write worker: exiting but connection may still be alive, keeping write channel registered", l.remote) + } + close(l.writeDone) + }() for { select { case <-l.ctx.Done(): + // Context cancelled - connection is closing + log.D.F("ws->%s write worker: context cancelled, exiting", l.remote) return case req, ok := <-l.writeChan: if !ok { + // Channel closed - connection is closing + channelClosed = true + log.D.F("ws->%s write worker: write channel closed, exiting", l.remote) return } deadline := req.Deadline @@ -82,9 +106,15 @@ func (l *Listener) writeWorker() { websocket.CloseGoingAway, websocket.CloseNoStatusReceived) if isConnectionError { + // Connection is dead - unregister channel immediately + log.D.F("ws->%s write worker: connection error detected, unregistering write channel", l.remote) + if socketPub := l.publishers.GetSocketPublisher(); socketPub != nil { + socketPub.SetWriteChan(l.conn, nil) + } return } - // Continue for other errors (timeouts, etc.) + // Continue for other errors (timeouts, etc.) - connection may still be alive + log.D.F("ws->%s write worker: non-fatal error (timeout?), continuing", l.remote) } else { writeDuration := time.Since(writeStart) if writeDuration > time.Millisecond*100 { diff --git a/app/main.go b/app/main.go index cf48fb4..b2021b1 100644 --- a/app/main.go +++ b/app/main.go @@ -161,7 +161,7 @@ func Run( } if l.paymentProcessor, err = NewPaymentProcessor(ctx, cfg, db); err != nil { - log.E.F("failed to create payment processor: %v", err) + // log.E.F("failed to create payment processor: %v", err) // Continue without payment processor } else { if err = l.paymentProcessor.Start(); err != nil { diff --git a/app/payment_processor.go b/app/payment_processor.go index 09122ba..3a3133a 100644 --- a/app/payment_processor.go +++ b/app/payment_processor.go @@ -15,7 +15,7 @@ import ( "lol.mleku.dev/log" "next.orly.dev/app/config" "next.orly.dev/pkg/acl" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/database" "next.orly.dev/pkg/encoders/bech32encoding" "next.orly.dev/pkg/encoders/event" @@ -152,7 +152,7 @@ func (pp *PaymentProcessor) syncFollowList() error { return err } // signer - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.InitSec(skb); err != nil { return err } @@ -272,7 +272,7 @@ func (pp *PaymentProcessor) createExpiryWarningNote( } // Initialize signer - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.InitSec(skb); err != nil { return fmt.Errorf("failed to initialize signer: %w", err) } @@ -383,7 +383,7 @@ func (pp *PaymentProcessor) createTrialReminderNote( } // Initialize signer - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.InitSec(skb); err != nil { return fmt.Errorf("failed to initialize signer: %w", err) } @@ -530,7 +530,7 @@ func (pp *PaymentProcessor) handleNotification( if s, ok := metadata["relay_pubkey"].(string); ok && s != "" { if rpk, err := decodeAnyPubkey(s); err == nil { if skb, err := pp.db.GetRelayIdentitySecret(); err == nil && len(skb) == 32 { - var signer p256k.Signer + signer := p256k1signer.NewP256K1Signer() if err := signer.InitSec(skb); err == nil { if !strings.EqualFold( hex.Enc(rpk), hex.Enc(signer.Pub()), @@ -644,7 +644,7 @@ func (pp *PaymentProcessor) createPaymentNote( } // Initialize signer - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.InitSec(skb); err != nil { return fmt.Errorf("failed to initialize signer: %w", err) } @@ -738,7 +738,7 @@ func (pp *PaymentProcessor) CreateWelcomeNote(userPubkey []byte) error { } // Initialize signer - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.InitSec(skb); err != nil { return fmt.Errorf("failed to initialize signer: %w", err) } @@ -1025,7 +1025,7 @@ func (pp *PaymentProcessor) UpdateRelayProfile() error { } // Initialize signer - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.InitSec(skb); err != nil { return fmt.Errorf("failed to initialize signer: %w", err) } diff --git a/app/publisher.go b/app/publisher.go index a406f19..e21bb6d 100644 --- a/app/publisher.go +++ b/app/publisher.go @@ -89,10 +89,15 @@ func NewPublisher(c context.Context) (publisher *P) { func (p *P) Type() (typeName string) { return Type } // SetWriteChan stores the write channel for a websocket connection +// If writeChan is nil, the entry is removed from the map func (p *P) SetWriteChan(conn *websocket.Conn, writeChan chan<- publish.WriteRequest) { p.Mx.Lock() defer p.Mx.Unlock() - p.WriteChans[conn] = writeChan + if writeChan == nil { + delete(p.WriteChans, conn) + } else { + p.WriteChans[conn] = writeChan + } } // GetWriteChan returns the write channel for a websocket connection @@ -340,7 +345,9 @@ func (p *P) removeSubscriberId(ws *websocket.Conn, id string) { // Check the actual map after deletion, not the original reference if len(p.Map[ws]) == 0 { delete(p.Map, ws) - delete(p.WriteChans, ws) + // Don't remove write channel here - it's tied to the connection, not subscriptions + // The write channel will be removed when the connection closes (in handle-websocket.go defer) + // This allows new subscriptions to be created on the same connection } } } diff --git a/cmd/aggregator/main.go b/cmd/aggregator/main.go index bc160db..69328fa 100644 --- a/cmd/aggregator/main.go +++ b/cmd/aggregator/main.go @@ -17,7 +17,7 @@ import ( "lol.mleku.dev/chk" "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/crypto/sha256" "next.orly.dev/pkg/encoders/bech32encoding" "next.orly.dev/pkg/encoders/event" @@ -335,7 +335,7 @@ func NewAggregator(keyInput string, since, until *timestamp.T, bloomFilterFile s } // Create signer from private key - signer = &p256k.Signer{} + signer = p256k1signer.NewP256K1Signer() if err = signer.InitSec(secretBytes); chk.E(err) { return nil, fmt.Errorf("failed to initialize signer: %w", err) } diff --git a/cmd/benchmark/main.go b/cmd/benchmark/main.go index 6e21210..fff63fd 100644 --- a/cmd/benchmark/main.go +++ b/cmd/benchmark/main.go @@ -13,7 +13,6 @@ import ( "sync" "time" - "next.orly.dev/pkg/crypto/p256k" "next.orly.dev/pkg/database" "next.orly.dev/pkg/encoders/envelopes/eventenvelope" "next.orly.dev/pkg/encoders/event" @@ -22,6 +21,7 @@ import ( "next.orly.dev/pkg/encoders/tag" "next.orly.dev/pkg/encoders/timestamp" "next.orly.dev/pkg/protocol/ws" + p256k1signer "p256k1.mleku.dev/signer" ) type BenchmarkConfig struct { @@ -167,7 +167,7 @@ func runNetworkLoad(cfg *BenchmarkConfig) { fmt.Printf("worker %d: connected to %s\n", workerID, cfg.RelayURL) // Signer for this worker - var keys p256k.Signer + keys := p256k1signer.NewP256K1Signer() if err := keys.Generate(); err != nil { fmt.Printf("worker %d: keygen failed: %v\n", workerID, err) return @@ -244,7 +244,7 @@ func runNetworkLoad(cfg *BenchmarkConfig) { ev.Content = []byte(fmt.Sprintf( "bench worker=%d n=%d", workerID, count, )) - if err := ev.Sign(&keys); err != nil { + if err := ev.Sign(keys); err != nil { fmt.Printf("worker %d: sign error: %v\n", workerID, err) ev.Free() continue @@ -960,7 +960,7 @@ func (b *Benchmark) generateEvents(count int) []*event.E { now := timestamp.Now() // Generate a keypair for signing all events - var keys p256k.Signer + keys := p256k1signer.NewP256K1Signer() if err := keys.Generate(); err != nil { log.Fatalf("Failed to generate keys for benchmark events: %v", err) } @@ -983,7 +983,7 @@ func (b *Benchmark) generateEvents(count int) []*event.E { ) // Properly sign the event instead of generating fake signatures - if err := ev.Sign(&keys); err != nil { + if err := ev.Sign(keys); err != nil { log.Fatalf("Failed to sign event %d: %v", i, err) } diff --git a/cmd/policyfiltertest/main.go b/cmd/policyfiltertest/main.go index 21361e7..af4a3e8 100644 --- a/cmd/policyfiltertest/main.go +++ b/cmd/policyfiltertest/main.go @@ -10,7 +10,7 @@ import ( "lol.mleku.dev/chk" "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/filter" "next.orly.dev/pkg/encoders/hex" @@ -44,7 +44,7 @@ func main() { log.E.F("failed to decode allowed secret key: %v", err) os.Exit(1) } - allowedSigner := &p256k.Signer{} + allowedSigner := p256k1signer.NewP256K1Signer() if err = allowedSigner.InitSec(allowedSecBytes); chk.E(err) { log.E.F("failed to initialize allowed signer: %v", err) os.Exit(1) @@ -55,7 +55,7 @@ func main() { log.E.F("failed to decode unauthorized secret key: %v", err) os.Exit(1) } - unauthorizedSigner := &p256k.Signer{} + unauthorizedSigner := p256k1signer.NewP256K1Signer() if err = unauthorizedSigner.InitSec(unauthorizedSecBytes); chk.E(err) { log.E.F("failed to initialize unauthorized signer: %v", err) os.Exit(1) @@ -136,7 +136,7 @@ func main() { fmt.Println("\nāœ… All tests passed!") } -func testWriteEvent(ctx context.Context, url string, kindNum uint16, eventSigner, authSigner *p256k.Signer) error { +func testWriteEvent(ctx context.Context, url string, kindNum uint16, eventSigner, authSigner *p256k1signer.P256K1Signer) error { rl, err := ws.RelayConnect(ctx, url) if err != nil { return fmt.Errorf("connect error: %w", err) @@ -192,7 +192,7 @@ func testWriteEvent(ctx context.Context, url string, kindNum uint16, eventSigner return nil } -func testWriteEventUnauthenticated(ctx context.Context, url string, kindNum uint16, eventSigner *p256k.Signer) error { +func testWriteEventUnauthenticated(ctx context.Context, url string, kindNum uint16, eventSigner *p256k1signer.P256K1Signer) error { rl, err := ws.RelayConnect(ctx, url) if err != nil { return fmt.Errorf("connect error: %w", err) @@ -227,7 +227,7 @@ func testWriteEventUnauthenticated(ctx context.Context, url string, kindNum uint return nil } -func testReadEvent(ctx context.Context, url string, kindNum uint16, authSigner *p256k.Signer) error { +func testReadEvent(ctx context.Context, url string, kindNum uint16, authSigner *p256k1signer.P256K1Signer) error { rl, err := ws.RelayConnect(ctx, url) if err != nil { return fmt.Errorf("connect error: %w", err) diff --git a/cmd/policytest/main.go b/cmd/policytest/main.go index da2b3a3..5981cc9 100644 --- a/cmd/policytest/main.go +++ b/cmd/policytest/main.go @@ -8,7 +8,7 @@ import ( "lol.mleku.dev/chk" "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/kind" "next.orly.dev/pkg/encoders/tag" @@ -29,7 +29,7 @@ func main() { } defer rl.Close() - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err = signer.Generate(); chk.E(err) { log.E.F("signer generate error: %v", err) return diff --git a/cmd/stresstest/main.go b/cmd/stresstest/main.go index f559aa3..897b73c 100644 --- a/cmd/stresstest/main.go +++ b/cmd/stresstest/main.go @@ -16,7 +16,7 @@ import ( "time" "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/envelopes/eventenvelope" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/event/examples" @@ -35,7 +35,7 @@ func randomHex(n int) string { return hex.Enc(b) } -func makeEvent(rng *rand.Rand, signer *p256k.Signer) (*event.E, error) { +func makeEvent(rng *rand.Rand, signer *p256k1signer.P256K1Signer) (*event.E, error) { ev := &event.E{ CreatedAt: time.Now().Unix(), Kind: kind.TextNote.K, @@ -293,7 +293,7 @@ func publisherWorker( src := rand.NewSource(time.Now().UnixNano() ^ int64(id<<16)) rng := rand.New(src) // Generate and reuse signing key per worker - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err := signer.Generate(); err != nil { log.E.F("worker %d: signer generate error: %v", id, err) return diff --git a/pkg/blossom/utils_test.go b/pkg/blossom/utils_test.go index bdd2354..e7e6377 100644 --- a/pkg/blossom/utils_test.go +++ b/pkg/blossom/utils_test.go @@ -11,7 +11,7 @@ import ( "time" "next.orly.dev/pkg/acl" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/database" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/hex" @@ -59,8 +59,8 @@ func testSetup(t *testing.T) (*Server, func()) { } // createTestKeypair creates a test keypair for signing events -func createTestKeypair(t *testing.T) ([]byte, *p256k.Signer) { - signer := &p256k.Signer{} +func createTestKeypair(t *testing.T) ([]byte, *p256k1signer.P256K1Signer) { + signer := p256k1signer.NewP256K1Signer() if err := signer.Generate(); err != nil { t.Fatalf("Failed to generate keypair: %v", err) } @@ -70,7 +70,7 @@ func createTestKeypair(t *testing.T) ([]byte, *p256k.Signer) { // createAuthEvent creates a valid kind 24242 authorization event func createAuthEvent( - t *testing.T, signer *p256k.Signer, verb string, + t *testing.T, signer *p256k1signer.P256K1Signer, verb string, sha256Hash []byte, expiresIn int64, ) *event.E { now := time.Now().Unix() diff --git a/pkg/crypto/encryption/benchmark_test.go b/pkg/crypto/encryption/benchmark_test.go index aa466e8..b702e03 100644 --- a/pkg/crypto/encryption/benchmark_test.go +++ b/pkg/crypto/encryption/benchmark_test.go @@ -3,7 +3,7 @@ package encryption import ( "testing" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "lukechampine.com/frand" ) @@ -13,8 +13,8 @@ func createTestConversationKey() []byte { } // createTestKeyPair creates a key pair for ECDH testing -func createTestKeyPair() (*p256k.Signer, []byte) { - signer := &p256k.Signer{} +func createTestKeyPair() (*p256k1signer.P256K1Signer, []byte) { + signer := p256k1signer.NewP256K1Signer() if err := signer.Generate(); err != nil { panic(err) } diff --git a/pkg/crypto/encryption/nip44.go b/pkg/crypto/encryption/nip44.go index 9844939..20440d3 100644 --- a/pkg/crypto/encryption/nip44.go +++ b/pkg/crypto/encryption/nip44.go @@ -12,8 +12,9 @@ import ( "golang.org/x/crypto/hkdf" "lol.mleku.dev/chk" "lol.mleku.dev/errorf" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/crypto/sha256" + "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/interfaces/signer" "next.orly.dev/pkg/utils" ) @@ -176,11 +177,16 @@ func GenerateConversationKeyFromHex(pkh, skh string) (ck []byte, err error) { return } var sign signer.I - if sign, err = p256k.NewSecFromHex(skh); chk.E(err) { + sign = p256k1signer.NewP256K1Signer() + var sk []byte + if sk, err = hex.Dec(skh); chk.E(err) { + return + } + if err = sign.InitSec(sk); chk.E(err) { return } var pk []byte - if pk, err = p256k.HexToBin(pkh); chk.E(err) { + if pk, err = hex.Dec(pkh); chk.E(err) { return } var shared []byte diff --git a/pkg/crypto/keys/keys.go b/pkg/crypto/keys/keys.go index 954d890..57f438a 100644 --- a/pkg/crypto/keys/keys.go +++ b/pkg/crypto/keys/keys.go @@ -7,7 +7,7 @@ import ( "lol.mleku.dev/chk" "next.orly.dev/pkg/crypto/ec/schnorr" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/utils" ) @@ -17,7 +17,7 @@ var GeneratePrivateKey = func() string { return GenerateSecretKeyHex() } // GenerateSecretKey creates a new secret key and returns the bytes of the secret. func GenerateSecretKey() (skb []byte, err error) { - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err = signer.Generate(); chk.E(err) { return } @@ -40,7 +40,7 @@ func GetPublicKeyHex(sk string) (pk string, err error) { if b, err = hex.Dec(sk); chk.E(err) { return } - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err = signer.InitSec(b); chk.E(err) { return } @@ -50,7 +50,7 @@ func GetPublicKeyHex(sk string) (pk string, err error) { // SecretBytesToPubKeyHex generates a public key from secret key bytes. func SecretBytesToPubKeyHex(skb []byte) (pk string, err error) { - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err = signer.InitSec(skb); chk.E(err) { return } diff --git a/pkg/crypto/p256k/README.md b/pkg/crypto/p256k/README.md deleted file mode 100644 index 99dd183..0000000 --- a/pkg/crypto/p256k/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# p256k1 - -This is a library that uses the `bitcoin-core` optimized secp256k1 elliptic -curve signatures library for `nostr` schnorr signatures. - -If you need to build it without `libsecp256k1` C library, you must disable cgo: - - export CGO_ENABLED='0' - -This enables the fallback `btcec` pure Go library to be used in its place. This -CGO setting is not default for Go, so it must be set in order to disable this. - -The standard `libsecp256k1-0` and `libsecp256k1-dev` available through the -ubuntu dpkg repositories do not include support for the BIP-340 schnorr -signatures or the ECDH X-only shared secret generation algorithm, so you must -follow the following instructions to get the benefits of using this library. It -is 4x faster at signing and generating shared secrets so it is a must if your -intention is to use it for high throughput systems like a network transport. - -The easy way to install it, if you have ubuntu/debian, is the script -[../ubuntu_install_libsecp256k1.sh](../../../scripts/ubuntu_install_libsecp256k1.sh), -it -handles the dependencies and runs the build all in one step for you. Note that -it - -For ubuntu, you need these: - - sudo apt -y install build-essential autoconf libtool - -For other linux distributions, the process is the same but the dependencies are -likely different. The main thing is it requires make, gcc/++, autoconf and -libtool to run. The most important thing to point out is that you must enable -the schnorr signatures feature, and ECDH. - -The directory `p256k/secp256k1` needs to be initialized, built and installed, -like so: - -```bash -cd secp256k1 -git submodule init -git submodule update -``` - -Then to build, you can refer to the [instructions](./secp256k1/README.md) or -just use the default autotools: - -```bash -./autogen.sh -./configure --enable-module-schnorrsig --enable-module-ecdh --prefix=/usr -make -sudo make install -``` - -On WSL2 you may have to attend to various things to make this work, setting up -your basic locale (uncomment one or more in `/etc/locale.gen`, and run -`locale-gen`), installing the basic build tools (build-essential or base-devel) -and of course git, curl, wget, libtool and -autoconf. - -## ECDH - -TODO: Currently the use of the libsecp256k1 library for ECDH, used in nip-04 and -nip-44 encryption is not enabled, because the default version uses the Y -coordinate and this is incorrect for nostr. It will be enabled soon... for now -it is done with the `btcec` fallback version. This is slower, however previous -tests have shown that this ECDH library is fast enough to enable 8mb/s -throughput per CPU thread when used to generate a distinct secret for TCP -packets. The C library will likely raise this to 20mb/s or more. diff --git a/pkg/crypto/p256k/btcec.go b/pkg/crypto/p256k/btcec.go deleted file mode 100644 index b9d2801..0000000 --- a/pkg/crypto/p256k/btcec.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build !cgo - -package p256k - -import ( - "lol.mleku.dev/log" - p256k1signer "p256k1.mleku.dev/signer" -) - -func init() { - log.T.Ln("using p256k1.mleku.dev/signer (pure Go/Btcec)") -} - -// Signer is an alias for the BtcecSigner type from p256k1.mleku.dev/signer (btcec version). -// This is used when CGO is not available. -type Signer = p256k1signer.BtcecSigner - -// Keygen is an alias for the P256K1Gen type from p256k1.mleku.dev/signer (btcec version). -type Keygen = p256k1signer.P256K1Gen - -var NewKeygen = p256k1signer.NewP256K1Gen \ No newline at end of file diff --git a/pkg/crypto/p256k/btcec/btcec.go b/pkg/crypto/p256k/btcec/btcec.go deleted file mode 100644 index 5e3d78c..0000000 --- a/pkg/crypto/p256k/btcec/btcec.go +++ /dev/null @@ -1,169 +0,0 @@ -//go:build !cgo - -// Package btcec implements the signer.I interface for signatures and ECDH with nostr. -package btcec - -import ( - "lol.mleku.dev/chk" - "lol.mleku.dev/errorf" - "next.orly.dev/pkg/crypto/ec/schnorr" - "next.orly.dev/pkg/crypto/ec/secp256k1" - "next.orly.dev/pkg/interfaces/signer" -) - -// Signer is an implementation of signer.I that uses the btcec library. -type Signer struct { - SecretKey *secp256k1.SecretKey - PublicKey *secp256k1.PublicKey - BTCECSec *secp256k1.SecretKey - pkb, skb []byte -} - -var _ signer.I = &Signer{} - -// Generate creates a new Signer. -func (s *Signer) Generate() (err error) { - if s.SecretKey, err = secp256k1.GenerateSecretKey(); chk.E(err) { - return - } - s.skb = s.SecretKey.Serialize() - s.BTCECSec = secp256k1.PrivKeyFromBytes(s.skb) - s.PublicKey = s.SecretKey.PubKey() - s.pkb = schnorr.SerializePubKey(s.PublicKey) - return -} - -// InitSec initialises a Signer using raw secret key bytes. -func (s *Signer) InitSec(sec []byte) (err error) { - if len(sec) != secp256k1.SecKeyBytesLen { - err = errorf.E("sec key must be %d bytes", secp256k1.SecKeyBytesLen) - return - } - s.skb = sec - s.SecretKey = secp256k1.SecKeyFromBytes(sec) - s.PublicKey = s.SecretKey.PubKey() - s.pkb = schnorr.SerializePubKey(s.PublicKey) - s.BTCECSec = secp256k1.PrivKeyFromBytes(s.skb) - return -} - -// InitPub initializes a signature verifier Signer from raw public key bytes. -func (s *Signer) InitPub(pub []byte) (err error) { - if s.PublicKey, err = schnorr.ParsePubKey(pub); chk.E(err) { - return - } - s.pkb = pub - return -} - -// Sec returns the raw secret key bytes. -func (s *Signer) Sec() (b []byte) { - if s == nil { - return nil - } - return s.skb -} - -// Pub returns the raw BIP-340 schnorr public key bytes. -func (s *Signer) Pub() (b []byte) { - if s == nil { - return nil - } - return s.pkb -} - -// Sign a message with the Signer. Requires an initialised secret key. -func (s *Signer) Sign(msg []byte) (sig []byte, err error) { - if s.SecretKey == nil { - err = errorf.E("btcec: Signer not initialized") - return - } - var si *schnorr.Signature - if si, err = schnorr.Sign(s.SecretKey, msg); chk.E(err) { - return - } - sig = si.Serialize() - return -} - -// Verify a message signature, only requires the public key is initialised. -func (s *Signer) Verify(msg, sig []byte) (valid bool, err error) { - if s.PublicKey == nil { - err = errorf.E("btcec: Pubkey not initialized") - return - } - - // First try to verify using the schnorr package - var si *schnorr.Signature - if si, err = schnorr.ParseSignature(sig); err == nil { - valid = si.Verify(msg, s.PublicKey) - return - } - - // If parsing the signature failed, log it at debug level - chk.D(err) - - // If the signature is exactly 64 bytes, try to verify it directly - // This is to handle signatures created by p256k.Signer which uses libsecp256k1 - if len(sig) == schnorr.SignatureSize { - // Create a new signature with the raw bytes - var r secp256k1.FieldVal - var sScalar secp256k1.ModNScalar - - // Split the signature into r and s components - if overflow := r.SetByteSlice(sig[0:32]); !overflow { - sScalar.SetByteSlice(sig[32:64]) - - // Create a new signature and verify it - newSig := schnorr.NewSignature(&r, &sScalar) - valid = newSig.Verify(msg, s.PublicKey) - return - } - } - - // If all verification methods failed, return an error - err = errorf.E( - "failed to verify signature:\n%d %s", len(sig), sig, - ) - return -} - -// Zero wipes the bytes of the secret key. -func (s *Signer) Zero() { s.SecretKey.Key.Zero() } - -// ECDH creates a shared secret from a secret key and a provided public key bytes. It is advised -// to hash this result for security reasons. -func (s *Signer) ECDH(pubkeyBytes []byte) (secret []byte, err error) { - var pub *secp256k1.PublicKey - if pub, err = secp256k1.ParsePubKey( - append( - []byte{0x02}, pubkeyBytes..., - ), - ); chk.E(err) { - return - } - secret = secp256k1.GenerateSharedSecret(s.BTCECSec, pub) - return -} - -// Keygen implements a key generator. Used for such things as vanity npub mining. -type Keygen struct { - Signer -} - -// Generate a new key pair. If the result is suitable, the embedded Signer can have its contents -// extracted. -func (k *Keygen) Generate() (pubBytes []byte, err error) { - if k.Signer.SecretKey, err = secp256k1.GenerateSecretKey(); chk.E(err) { - return - } - k.Signer.PublicKey = k.SecretKey.PubKey() - k.Signer.pkb = schnorr.SerializePubKey(k.Signer.PublicKey) - pubBytes = k.Signer.pkb - return -} - -// KeyPairBytes returns the raw bytes of the embedded Signer. -func (k *Keygen) KeyPairBytes() (secBytes, cmprPubBytes []byte) { - return k.Signer.SecretKey.Serialize(), k.Signer.PublicKey.SerializeCompressed() -} diff --git a/pkg/crypto/p256k/btcec/btcec_test.go b/pkg/crypto/p256k/btcec/btcec_test.go deleted file mode 100644 index 7209bcd..0000000 --- a/pkg/crypto/p256k/btcec/btcec_test.go +++ /dev/null @@ -1,194 +0,0 @@ -//go:build !cgo - -package btcec_test - -import ( - "testing" - "time" - - "lol.mleku.dev/chk" - "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/p256k/btcec" - "next.orly.dev/pkg/utils" -) - -func TestSigner_Generate(t *testing.T) { - for _ = range 100 { - var err error - signer := &btcec.Signer{} - var skb []byte - if err = signer.Generate(); chk.E(err) { - t.Fatal(err) - } - skb = signer.Sec() - if err = signer.InitSec(skb); chk.E(err) { - t.Fatal(err) - } - } -} - -// func TestBTCECSignerVerify(t *testing.T) { -// evs := make([]*event.E, 0, 10000) -// scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache)) -// buf := make([]byte, 1_000_000) -// scanner.Buffer(buf, len(buf)) -// var err error -// -// // Create both btcec and p256k signers -// btcecSigner := &btcec.Signer{} -// p256kSigner := &p256k.Signer{} -// -// for scanner.Scan() { -// var valid bool -// b := scanner.Bytes() -// ev := event.New() -// if _, err = ev.Unmarshal(b); chk.E(err) { -// t.Errorf("failed to marshal\n%s", b) -// } else { -// // We know ev.Verify() works, so we'll use it as a reference -// if valid, err = ev.Verify(); chk.E(err) || !valid { -// t.Errorf("invalid signature\n%s", b) -// continue -// } -// } -// -// // Get the ID from the event -// storedID := ev.ID -// calculatedID := ev.GetIDBytes() -// -// // Check if the stored ID matches the calculated ID -// if !utils.FastEqual(storedID, calculatedID) { -// log.D.Ln("Event ID mismatch: stored ID doesn't match calculated ID") -// // Use the calculated ID for verification as ev.Verify() would do -// ev.ID = calculatedID -// } -// -// if len(ev.ID) != sha256.Size { -// t.Errorf("id should be 32 bytes, got %d", len(ev.ID)) -// continue -// } -// -// // Initialize both signers with the same public key -// if err = btcecSigner.InitPub(ev.Pubkey); chk.E(err) { -// t.Errorf("failed to init btcec pub key: %s\n%0x", err, b) -// } -// if err = p256kSigner.InitPub(ev.Pubkey); chk.E(err) { -// t.Errorf("failed to init p256k pub key: %s\n%0x", err, b) -// } -// -// // First try to verify with btcec.Signer -// if valid, err = btcecSigner.Verify(ev.ID, ev.Sig); err == nil && valid { -// // If btcec.Signer verification succeeds, great! -// log.D.Ln("btcec.Signer verification succeeded") -// } else { -// // If btcec.Signer verification fails, try with p256k.Signer -// // Use chk.T(err) like ev.Verify() does -// if valid, err = p256kSigner.Verify(ev.ID, ev.Sig); chk.T(err) { -// // If there's an error, log it but don't fail the test -// log.D.Ln("p256k.Signer verification error:", err) -// } else if !valid { -// // Only fail the test if both verifications fail -// t.Errorf( -// "invalid signature for pub %0x %0x %0x", ev.Pubkey, ev.ID, -// ev.Sig, -// ) -// } else { -// log.D.Ln("p256k.Signer verification succeeded where btcec.Signer failed") -// } -// } -// -// evs = append(evs, ev) -// } -// } - -// func TestBTCECSignerSign(t *testing.T) { -// evs := make([]*event.E, 0, 10000) -// scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache)) -// buf := make([]byte, 1_000_000) -// scanner.Buffer(buf, len(buf)) -// var err error -// signer := &btcec.Signer{} -// var skb []byte -// if err = signer.Generate(); chk.E(err) { -// t.Fatal(err) -// } -// skb = signer.Sec() -// if err = signer.InitSec(skb); chk.E(err) { -// t.Fatal(err) -// } -// verifier := &btcec.Signer{} -// pkb := signer.Pub() -// if err = verifier.InitPub(pkb); chk.E(err) { -// t.Fatal(err) -// } -// counter := 0 -// for scanner.Scan() { -// counter++ -// if counter > 1000 { -// break -// } -// b := scanner.Bytes() -// ev := event.New() -// if _, err = ev.Unmarshal(b); chk.E(err) { -// t.Errorf("failed to marshal\n%s", b) -// } -// evs = append(evs, ev) -// } -// var valid bool -// sig := make([]byte, schnorr.SignatureSize) -// for _, ev := range evs { -// ev.Pubkey = pkb -// id := ev.GetIDBytes() -// if sig, err = signer.Sign(id); chk.E(err) { -// t.Errorf("failed to sign: %s\n%0x", err, id) -// } -// if valid, err = verifier.Verify(id, sig); chk.E(err) { -// t.Errorf("failed to verify: %s\n%0x", err, id) -// } -// if !valid { -// t.Errorf("invalid signature") -// } -// } -// signer.Zero() -// } - -func TestBTCECECDH(t *testing.T) { - n := time.Now() - var err error - var counter int - const total = 50 - for _ = range total { - s1 := new(btcec.Signer) - if err = s1.Generate(); chk.E(err) { - t.Fatal(err) - } - s2 := new(btcec.Signer) - if err = s2.Generate(); chk.E(err) { - t.Fatal(err) - } - for _ = range total { - var secret1, secret2 []byte - if secret1, err = s1.ECDH(s2.Pub()); chk.E(err) { - t.Fatal(err) - } - if secret2, err = s2.ECDH(s1.Pub()); chk.E(err) { - t.Fatal(err) - } - if !utils.FastEqual(secret1, secret2) { - counter++ - t.Errorf( - "ECDH generation failed to work in both directions, %x %x", - secret1, - secret2, - ) - } - } - } - a := time.Now() - duration := a.Sub(n) - log.I.Ln( - "errors", counter, "total", total, "time", duration, "time/op", - int(duration/total), - "ops/sec", int(time.Second)/int(duration/total), - ) -} diff --git a/pkg/crypto/p256k/btcec/helpers-btcec.go b/pkg/crypto/p256k/btcec/helpers-btcec.go deleted file mode 100644 index ef53aa8..0000000 --- a/pkg/crypto/p256k/btcec/helpers-btcec.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build !cgo - -package btcec - -import ( - "lol.mleku.dev/chk" - "next.orly.dev/pkg/encoders/hex" - "next.orly.dev/pkg/interfaces/signer" -) - -func NewSecFromHex[V []byte | string](skh V) (sign signer.I, err error) { - sk := make([]byte, len(skh)/2) - if _, err = hex.DecBytes(sk, []byte(skh)); chk.E(err) { - return - } - sign = &Signer{} - if err = sign.InitSec(sk); chk.E(err) { - return - } - return -} - -func NewPubFromHex[V []byte | string](pkh V) (sign signer.I, err error) { - pk := make([]byte, len(pkh)/2) - if _, err = hex.DecBytes(pk, []byte(pkh)); chk.E(err) { - return - } - sign = &Signer{} - if err = sign.InitPub(pk); chk.E(err) { - return - } - return -} - -func HexToBin(hexStr string) (b []byte, err error) { - b = make([]byte, len(hexStr)/2) - if _, err = hex.DecBytes(b, []byte(hexStr)); chk.E(err) { - return - } - return -} diff --git a/pkg/crypto/p256k/doc.go b/pkg/crypto/p256k/doc.go deleted file mode 100644 index 8ba5e97..0000000 --- a/pkg/crypto/p256k/doc.go +++ /dev/null @@ -1,9 +0,0 @@ -// Package p256k provides a signer interface that uses p256k1.mleku.dev library for -// fast signature creation and verification of BIP-340 nostr X-only signatures and -// public keys, and ECDH. -// -// The package provides type aliases to p256k1.mleku.dev/signer: -// - cgo: Uses the CGO-optimized version from p256k1.mleku.dev -// - btcec: Uses the btcec version from p256k1.mleku.dev -// - default: Uses the pure Go version from p256k1.mleku.dev -package p256k diff --git a/pkg/crypto/p256k/helpers-btcec.go b/pkg/crypto/p256k/helpers-btcec.go deleted file mode 100644 index aec2c54..0000000 --- a/pkg/crypto/p256k/helpers-btcec.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build !cgo - -package p256k - -import ( - "lol.mleku.dev/chk" - "next.orly.dev/pkg/encoders/hex" - "next.orly.dev/pkg/interfaces/signer" - p256k1signer "p256k1.mleku.dev/signer" -) - -func NewSecFromHex[V []byte | string](skh V) (sign signer.I, err error) { - sk := make([]byte, len(skh)/2) - if _, err = hex.DecBytes(sk, []byte(skh)); chk.E(err) { - return - } - sign = p256k1signer.NewBtcecSigner() - if err = sign.InitSec(sk); chk.E(err) { - return - } - return -} - -func NewPubFromHex[V []byte | string](pkh V) (sign signer.I, err error) { - pk := make([]byte, len(pkh)/2) - if _, err = hex.DecBytes(pk, []byte(pkh)); chk.E(err) { - return - } - sign = p256k1signer.NewBtcecSigner() - if err = sign.InitPub(pk); chk.E(err) { - return - } - return -} - -func HexToBin(hexStr string) (b []byte, err error) { - if b, err = hex.DecAppend(b, []byte(hexStr)); chk.E(err) { - return - } - return -} diff --git a/pkg/crypto/p256k/helpers.go b/pkg/crypto/p256k/helpers.go deleted file mode 100644 index 0a2c07d..0000000 --- a/pkg/crypto/p256k/helpers.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build cgo - -package p256k - -import ( - "lol.mleku.dev/chk" - "next.orly.dev/pkg/encoders/hex" - "next.orly.dev/pkg/interfaces/signer" - p256k1signer "p256k1.mleku.dev/signer" -) - -func NewSecFromHex[V []byte | string](skh V) (sign signer.I, err error) { - sk := make([]byte, len(skh)/2) - if _, err = hex.DecBytes(sk, []byte(skh)); chk.E(err) { - return - } - sign = p256k1signer.NewP256K1Signer() - if err = sign.InitSec(sk); chk.E(err) { - return - } - return -} - -func NewPubFromHex[V []byte | string](pkh V) (sign signer.I, err error) { - pk := make([]byte, len(pkh)/2) - if _, err = hex.DecBytes(pk, []byte(pkh)); chk.E(err) { - return - } - sign = p256k1signer.NewP256K1Signer() - if err = sign.InitPub(pk); chk.E(err) { - return - } - return -} - -func HexToBin(hexStr string) (b []byte, err error) { - if b, err = hex.DecAppend(b, []byte(hexStr)); chk.E(err) { - return - } - return -} diff --git a/pkg/crypto/p256k/p256k.go b/pkg/crypto/p256k/p256k.go deleted file mode 100644 index 3ff20f7..0000000 --- a/pkg/crypto/p256k/p256k.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build cgo - -package p256k - -import ( - "lol.mleku.dev/log" - p256k1signer "p256k1.mleku.dev/signer" -) - -func init() { - log.T.Ln("using p256k1.mleku.dev/signer (CGO)") -} - -// Signer is an alias for the P256K1Signer type from p256k1.mleku.dev/signer (cgo version). -type Signer = p256k1signer.P256K1Signer - -// Keygen is an alias for the P256K1Gen type from p256k1.mleku.dev/signer (cgo version). -type Keygen = p256k1signer.P256K1Gen - -var NewKeygen = p256k1signer.NewP256K1Gen \ No newline at end of file diff --git a/pkg/crypto/p256k/p256k_test.go b/pkg/crypto/p256k/p256k_test.go deleted file mode 100644 index c08e9d4..0000000 --- a/pkg/crypto/p256k/p256k_test.go +++ /dev/null @@ -1,161 +0,0 @@ -//go:build cgo - -package p256k_test - -import ( - "testing" - "time" - - "lol.mleku.dev/chk" - "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/p256k" - "next.orly.dev/pkg/interfaces/signer" - "next.orly.dev/pkg/utils" -) - -func TestSigner_Generate(t *testing.T) { - for _ = range 10000 { - var err error - sign := &p256k.Signer{} - var skb []byte - if err = sign.Generate(); chk.E(err) { - t.Fatal(err) - } - skb = sign.Sec() - if err = sign.InitSec(skb); chk.E(err) { - t.Fatal(err) - } - } -} - -// func TestSignerVerify(t *testing.T) { -// // evs := make([]*event.E, 0, 10000) -// scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache)) -// buf := make([]byte, 1_000_000) -// scanner.Buffer(buf, len(buf)) -// var err error -// signer := &p256k.Signer{} -// for scanner.Scan() { -// var valid bool -// b := scanner.Bytes() -// bc := make([]byte, 0, len(b)) -// bc = append(bc, b...) -// ev := event.New() -// if _, err = ev.Unmarshal(b); chk.E(err) { -// t.Errorf("failed to marshal\n%s", b) -// } else { -// if valid, err = ev.Verify(); chk.T(err) || !valid { -// t.Errorf("invalid signature\n%s", bc) -// continue -// } -// } -// id := ev.GetIDBytes() -// if len(id) != sha256.Size { -// t.Errorf("id should be 32 bytes, got %d", len(id)) -// continue -// } -// if err = signer.InitPub(ev.Pubkey); chk.T(err) { -// t.Errorf("failed to init pub key: %s\n%0x", err, ev.Pubkey) -// continue -// } -// if valid, err = signer.Verify(id, ev.Sig); chk.E(err) { -// t.Errorf("failed to verify: %s\n%0x", err, ev.ID) -// continue -// } -// if !valid { -// t.Errorf( -// "invalid signature for\npub %0x\neid %0x\nsig %0x\n%s", -// ev.Pubkey, id, ev.Sig, bc, -// ) -// continue -// } -// // fmt.Printf("%s\n", bc) -// // evs = append(evs, ev) -// } -// } - -// func TestSignerSign(t *testing.T) { -// evs := make([]*event.E, 0, 10000) -// scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache)) -// buf := make([]byte, 1_000_000) -// scanner.Buffer(buf, len(buf)) -// var err error -// signer := &p256k.Signer{} -// var skb, pkb []byte -// if skb, pkb, _, _, err = p256k.Generate(); chk.E(err) { -// t.Fatal(err) -// } -// log.I.S(skb, pkb) -// if err = signer.InitSec(skb); chk.E(err) { -// t.Fatal(err) -// } -// verifier := &p256k.Signer{} -// if err = verifier.InitPub(pkb); chk.E(err) { -// t.Fatal(err) -// } -// for scanner.Scan() { -// b := scanner.Bytes() -// ev := event.New() -// if _, err = ev.Unmarshal(b); chk.E(err) { -// t.Errorf("failed to marshal\n%s", b) -// } -// evs = append(evs, ev) -// } -// var valid bool -// sig := make([]byte, schnorr.SignatureSize) -// for _, ev := range evs { -// ev.Pubkey = pkb -// id := ev.GetIDBytes() -// if sig, err = signer.Sign(id); chk.E(err) { -// t.Errorf("failed to sign: %s\n%0x", err, id) -// } -// if valid, err = verifier.Verify(id, sig); chk.E(err) { -// t.Errorf("failed to verify: %s\n%0x", err, id) -// } -// if !valid { -// t.Errorf("invalid signature") -// } -// } -// signer.Zero() -// } - -func TestECDH(t *testing.T) { - n := time.Now() - var err error - var s1, s2 signer.I - var counter int - const total = 100 - for _ = range total { - s1, s2 = &p256k.Signer{}, &p256k.Signer{} - if err = s1.Generate(); chk.E(err) { - t.Fatal(err) - } - for _ = range total { - if err = s2.Generate(); chk.E(err) { - t.Fatal(err) - } - var secret1, secret2 []byte - if secret1, err = s1.ECDH(s2.Pub()); chk.E(err) { - t.Fatal(err) - } - if secret2, err = s2.ECDH(s1.Pub()); chk.E(err) { - t.Fatal(err) - } - if !utils.FastEqual(secret1, secret2) { - counter++ - t.Errorf( - "ECDH generation failed to work in both directions, %x %x", - secret1, - secret2, - ) - } - } - } - a := time.Now() - duration := a.Sub(n) - log.I.Ln( - "errors", counter, "total", total*total, "time", duration, "time/op", - duration/total/total, "ops/sec", - float64(time.Second)/float64(duration/total/total), - ) -} diff --git a/pkg/crypto/p256k/secp256k1_test.go b/pkg/crypto/p256k/secp256k1_test.go deleted file mode 100644 index c49e9c6..0000000 --- a/pkg/crypto/p256k/secp256k1_test.go +++ /dev/null @@ -1,76 +0,0 @@ -//go:build cgo - -package p256k_test - -// func TestVerify(t *testing.T) { -// evs := make([]*event.E, 0, 10000) -// scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache)) -// buf := make([]byte, 1_000_000) -// scanner.Buffer(buf, len(buf)) -// var err error -// for scanner.Scan() { -// var valid bool -// b := scanner.Bytes() -// ev := event.New() -// if _, err = ev.Unmarshal(b); chk.E(err) { -// t.Errorf("failed to marshal\n%s", b) -// } else { -// if valid, err = ev.Verify(); chk.E(err) || !valid { -// t.Errorf("btcec: invalid signature\n%s", b) -// continue -// } -// } -// id := ev.GetIDBytes() -// if len(id) != sha256.Size { -// t.Errorf("id should be 32 bytes, got %d", len(id)) -// continue -// } -// if err = p256k.VerifyFromBytes(id, ev.Sig, ev.Pubkey); chk.E(err) { -// t.Error(err) -// continue -// } -// evs = append(evs, ev) -// } -// } - -// func TestSign(t *testing.T) { -// evs := make([]*event.E, 0, 10000) -// scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache)) -// buf := make([]byte, 1_000_000) -// scanner.Buffer(buf, len(buf)) -// var err error -// var sec1 *p256k.Sec -// var pub1 *p256k.XPublicKey -// var pb []byte -// if _, pb, sec1, pub1, err = p256k.Generate(); chk.E(err) { -// t.Fatal(err) -// } -// for scanner.Scan() { -// b := scanner.Bytes() -// ev := event.New() -// if _, err = ev.Unmarshal(b); chk.E(err) { -// t.Errorf("failed to marshal\n%s", b) -// } -// evs = append(evs, ev) -// } -// sig := make([]byte, schnorr.SignatureSize) -// for _, ev := range evs { -// ev.Pubkey = pb -// var uid *p256k.Uchar -// if uid, err = p256k.Msg(ev.GetIDBytes()); chk.E(err) { -// t.Fatal(err) -// } -// if sig, err = p256k.Sign(uid, sec1.Sec()); chk.E(err) { -// t.Fatal(err) -// } -// ev.Sig = sig -// var usig *p256k.Uchar -// if usig, err = p256k.Sig(sig); chk.E(err) { -// t.Fatal(err) -// } -// if !p256k.Verify(uid, usig, pub1.Key) { -// t.Errorf("invalid signature") -// } -// } -// p256k.Zero(&sec1.Key) -// } diff --git a/pkg/database/benchmark_test.go b/pkg/database/benchmark_test.go index b073b3b..90316d4 100644 --- a/pkg/database/benchmark_test.go +++ b/pkg/database/benchmark_test.go @@ -9,7 +9,7 @@ import ( "testing" "lol.mleku.dev/chk" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/database/indexes/types" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/event/examples" @@ -73,7 +73,7 @@ func BenchmarkSaveEvent(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { // Create a simple test event - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err := signer.Generate(); err != nil { b.Fatal(err) } diff --git a/pkg/database/query-events-multiple-param-replaceable_test.go b/pkg/database/query-events-multiple-param-replaceable_test.go index 3223cb3..ca7d9c3 100644 --- a/pkg/database/query-events-multiple-param-replaceable_test.go +++ b/pkg/database/query-events-multiple-param-replaceable_test.go @@ -6,7 +6,7 @@ import ( "testing" "lol.mleku.dev/chk" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/filter" "next.orly.dev/pkg/encoders/hex" @@ -25,7 +25,7 @@ func TestMultipleParameterizedReplaceableEvents(t *testing.T) { defer cancel() defer db.Close() - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.Generate(); chk.E(err) { t.Fatal(err) } diff --git a/pkg/database/query-events-search_test.go b/pkg/database/query-events-search_test.go index 7815479..50980e2 100644 --- a/pkg/database/query-events-search_test.go +++ b/pkg/database/query-events-search_test.go @@ -7,7 +7,7 @@ import ( "time" "lol.mleku.dev/chk" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/filter" "next.orly.dev/pkg/encoders/kind" @@ -44,7 +44,7 @@ func TestQueryEventsBySearchTerms(t *testing.T) { }() // signer for all events - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.Generate(); chk.E(err) { t.Fatalf("signer generate: %v", err) } diff --git a/pkg/database/query-events_test.go b/pkg/database/query-events_test.go index 0caff6e..79d87a1 100644 --- a/pkg/database/query-events_test.go +++ b/pkg/database/query-events_test.go @@ -10,7 +10,7 @@ import ( "testing" "lol.mleku.dev/chk" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/event/examples" "next.orly.dev/pkg/encoders/filter" @@ -198,7 +198,7 @@ func TestReplaceableEventsAndDeletion(t *testing.T) { defer db.Close() // Test querying for replaced events by ID - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.Generate(); chk.E(err) { t.Fatal(err) } @@ -380,7 +380,7 @@ func TestParameterizedReplaceableEventsAndDeletion(t *testing.T) { defer cancel() defer db.Close() - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.Generate(); chk.E(err) { t.Fatal(err) } diff --git a/pkg/database/save-event_test.go b/pkg/database/save-event_test.go index f813710..c1355d4 100644 --- a/pkg/database/save-event_test.go +++ b/pkg/database/save-event_test.go @@ -11,7 +11,7 @@ import ( "lol.mleku.dev/chk" "lol.mleku.dev/errorf" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/event/examples" "next.orly.dev/pkg/encoders/hex" @@ -120,7 +120,7 @@ func TestDeletionEventWithETagRejection(t *testing.T) { defer db.Close() // Create a signer - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.Generate(); chk.E(err) { t.Fatal(err) } @@ -199,7 +199,7 @@ func TestSaveExistingEvent(t *testing.T) { defer db.Close() // Create a signer - sign := new(p256k.Signer) + sign := p256k1signer.NewP256K1Signer() if err := sign.Generate(); chk.E(err) { t.Fatal(err) } diff --git a/pkg/encoders/envelopes/authenvelope/authenvelope_test.go b/pkg/encoders/envelopes/authenvelope/authenvelope_test.go index e9fbc1a..1782f12 100644 --- a/pkg/encoders/envelopes/authenvelope/authenvelope_test.go +++ b/pkg/encoders/envelopes/authenvelope/authenvelope_test.go @@ -4,7 +4,7 @@ import ( "testing" "lol.mleku.dev/chk" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/envelopes" "next.orly.dev/pkg/protocol/auth" "next.orly.dev/pkg/utils" @@ -15,7 +15,7 @@ const relayURL = "wss://example.com" func TestAuth(t *testing.T) { var err error - signer := new(p256k.Signer) + signer := p256k1signer.NewP256K1Signer() if err = signer.Generate(); chk.E(err) { t.Fatal(err) } diff --git a/pkg/encoders/event/benchmark_test.go b/pkg/encoders/event/benchmark_test.go index 9dbdeb5..b47fc9b 100644 --- a/pkg/encoders/event/benchmark_test.go +++ b/pkg/encoders/event/benchmark_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/encoders/kind" "next.orly.dev/pkg/encoders/tag" @@ -14,7 +14,7 @@ import ( // createTestEvent creates a realistic test event with proper signing func createTestEvent() *E { - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err := signer.Generate(); err != nil { panic(err) } @@ -44,7 +44,7 @@ func createTestEvent() *E { // createLargeTestEvent creates a larger event with more tags and content func createLargeTestEvent() *E { - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err := signer.Generate(); err != nil { panic(err) } diff --git a/pkg/encoders/event/signatures.go b/pkg/encoders/event/signatures.go index 9fb5fc3..302b128 100644 --- a/pkg/encoders/event/signatures.go +++ b/pkg/encoders/event/signatures.go @@ -4,7 +4,7 @@ import ( "lol.mleku.dev/chk" "lol.mleku.dev/errorf" "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/interfaces/signer" "next.orly.dev/pkg/utils" ) @@ -26,7 +26,7 @@ func (ev *E) Sign(keys signer.I) (err error) { // Verify an event is signed by the pubkey it contains. Uses // github.com/bitcoin-core/secp256k1 if available for faster verification. func (ev *E) Verify() (valid bool, err error) { - keys := p256k.Signer{} + keys := p256k1signer.NewP256K1Signer() if err = keys.InitPub(ev.Pubkey); chk.E(err) { return } diff --git a/pkg/encoders/filter/benchmark_test.go b/pkg/encoders/filter/benchmark_test.go index c8581f8..9000fe7 100644 --- a/pkg/encoders/filter/benchmark_test.go +++ b/pkg/encoders/filter/benchmark_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/crypto/sha256" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/hex" @@ -29,7 +29,7 @@ func createTestFilter() *F { // Add some authors for i := 0; i < 3; i++ { - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err := signer.Generate(); err != nil { panic(err) } @@ -72,7 +72,7 @@ func createComplexFilter() *F { // Add many authors for i := 0; i < 15; i++ { - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err := signer.Generate(); err != nil { panic(err) } @@ -100,7 +100,7 @@ func createComplexFilter() *F { // createTestEvent creates a test event for matching func createTestEvent() *event.E { - signer := &p256k.Signer{} + signer := p256k1signer.NewP256K1Signer() if err := signer.Generate(); err != nil { panic(err) } diff --git a/pkg/policy/benchmark_test.go b/pkg/policy/benchmark_test.go index b386ed3..1ab0d79 100644 --- a/pkg/policy/benchmark_test.go +++ b/pkg/policy/benchmark_test.go @@ -9,14 +9,14 @@ import ( "time" "lol.mleku.dev/chk" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/encoders/tag" ) // Helper function to create test event for benchmarks (reuses signer) -func createTestEventBench(b *testing.B, signer *p256k.Signer, content string, kind uint16) *event.E { +func createTestEventBench(b *testing.B, signer *p256k1signer.P256K1Signer, content string, kind uint16) *event.E { ev := event.New() ev.CreatedAt = time.Now().Unix() ev.Kind = kind diff --git a/pkg/policy/policy_integration_test.go b/pkg/policy/policy_integration_test.go index 47eeb13..4beeaeb 100644 --- a/pkg/policy/policy_integration_test.go +++ b/pkg/policy/policy_integration_test.go @@ -9,7 +9,7 @@ import ( "time" "lol.mleku.dev/chk" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/encoders/kind" @@ -23,13 +23,13 @@ func TestPolicyIntegration(t *testing.T) { } // Generate test keys - allowedSigner := &p256k.Signer{} + allowedSigner := p256k1signer.NewP256K1Signer() if err := allowedSigner.Generate(); chk.E(err) { t.Fatalf("Failed to generate allowed signer: %v", err) } allowedPubkeyHex := hex.Enc(allowedSigner.Pub()) - unauthorizedSigner := &p256k.Signer{} + unauthorizedSigner := p256k1signer.NewP256K1Signer() if err := unauthorizedSigner.Generate(); chk.E(err) { t.Fatalf("Failed to generate unauthorized signer: %v", err) } @@ -367,13 +367,13 @@ func TestPolicyWithRelay(t *testing.T) { } // Generate keys - allowedSigner := &p256k.Signer{} + allowedSigner := p256k1signer.NewP256K1Signer() if err := allowedSigner.Generate(); chk.E(err) { t.Fatalf("Failed to generate allowed signer: %v", err) } allowedPubkeyHex := hex.Enc(allowedSigner.Pub()) - unauthorizedSigner := &p256k.Signer{} + unauthorizedSigner := p256k1signer.NewP256K1Signer() if err := unauthorizedSigner.Generate(); chk.E(err) { t.Fatalf("Failed to generate unauthorized signer: %v", err) } diff --git a/pkg/policy/policy_test.go b/pkg/policy/policy_test.go index c56d874..9399bdd 100644 --- a/pkg/policy/policy_test.go +++ b/pkg/policy/policy_test.go @@ -10,7 +10,7 @@ import ( "time" "lol.mleku.dev/chk" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/encoders/tag" @@ -22,8 +22,8 @@ func int64Ptr(i int64) *int64 { } // Helper function to generate a keypair for testing -func generateTestKeypair(t *testing.T) (signer *p256k.Signer, pubkey []byte) { - signer = &p256k.Signer{} +func generateTestKeypair(t *testing.T) (signer *p256k1signer.P256K1Signer, pubkey []byte) { + signer = p256k1signer.NewP256K1Signer() if err := signer.Generate(); chk.E(err) { t.Fatalf("Failed to generate test keypair: %v", err) } @@ -32,8 +32,8 @@ func generateTestKeypair(t *testing.T) (signer *p256k.Signer, pubkey []byte) { } // Helper function to generate a keypair for benchmarks -func generateTestKeypairB(b *testing.B) (signer *p256k.Signer, pubkey []byte) { - signer = &p256k.Signer{} +func generateTestKeypairB(b *testing.B) (signer *p256k1signer.P256K1Signer, pubkey []byte) { + signer = p256k1signer.NewP256K1Signer() if err := signer.Generate(); chk.E(err) { b.Fatalf("Failed to generate test keypair: %v", err) } @@ -42,7 +42,7 @@ func generateTestKeypairB(b *testing.B) (signer *p256k.Signer, pubkey []byte) { } // Helper function to create a real test event with proper signing -func createTestEvent(t *testing.T, signer *p256k.Signer, content string, kind uint16) *event.E { +func createTestEvent(t *testing.T, signer *p256k1signer.P256K1Signer, content string, kind uint16) *event.E { ev := event.New() ev.CreatedAt = time.Now().Unix() ev.Kind = kind @@ -58,7 +58,7 @@ func createTestEvent(t *testing.T, signer *p256k.Signer, content string, kind ui } // Helper function to create a test event with a specific pubkey (for unauthorized tests) -func createTestEventWithPubkey(t *testing.T, signer *p256k.Signer, content string, kind uint16) *event.E { +func createTestEventWithPubkey(t *testing.T, signer *p256k1signer.P256K1Signer, content string, kind uint16) *event.E { ev := event.New() ev.CreatedAt = time.Now().Unix() ev.Kind = kind diff --git a/pkg/protocol/auth/nip42_test.go b/pkg/protocol/auth/nip42_test.go index f74bcba..7cb69e5 100644 --- a/pkg/protocol/auth/nip42_test.go +++ b/pkg/protocol/auth/nip42_test.go @@ -5,12 +5,12 @@ import ( "lol.mleku.dev/chk" "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" ) func TestCreateUnsigned(t *testing.T) { var err error - signer := new(p256k.Signer) + signer := p256k1signer.NewP256K1Signer() if err = signer.Generate(); chk.E(err) { t.Fatal(err) } diff --git a/pkg/protocol/directory/directory_test.go b/pkg/protocol/directory/directory_test.go index f1f117b..d7be5af 100644 --- a/pkg/protocol/directory/directory_test.go +++ b/pkg/protocol/directory/directory_test.go @@ -7,14 +7,14 @@ import ( "lol.mleku.dev/chk" "next.orly.dev/pkg/crypto/ec/secp256k1" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/bech32encoding" "next.orly.dev/pkg/protocol/directory" ) -// Helper to create a test keypair using p256k.Signer -func createTestKeypair(t *testing.T) (*p256k.Signer, []byte) { - signer := new(p256k.Signer) +// Helper to create a test keypair using p256k1signer.P256K1Signer +func createTestKeypair(t *testing.T) (*p256k1signer.P256K1Signer, []byte) { + signer := p256k1signer.NewP256K1Signer() if err := signer.Generate(); chk.E(err) { t.Fatalf("failed to generate keypair: %v", err) } diff --git a/pkg/protocol/nwc/crypto_test.go b/pkg/protocol/nwc/crypto_test.go index 314db5c..1d362c7 100644 --- a/pkg/protocol/nwc/crypto_test.go +++ b/pkg/protocol/nwc/crypto_test.go @@ -6,7 +6,7 @@ import ( "time" "next.orly.dev/pkg/crypto/encryption" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/encoders/tag" @@ -101,7 +101,7 @@ func TestNWCEventCreation(t *testing.T) { t.Fatal(err) } - clientKey := &p256k.Signer{} + clientKey := p256k1signer.NewP256K1Signer() if err := clientKey.InitSec(secretBytes); err != nil { t.Fatal(err) } diff --git a/pkg/protocol/nwc/mock_wallet_service.go b/pkg/protocol/nwc/mock_wallet_service.go index 761876c..9bbb0e8 100644 --- a/pkg/protocol/nwc/mock_wallet_service.go +++ b/pkg/protocol/nwc/mock_wallet_service.go @@ -10,7 +10,7 @@ import ( "lol.mleku.dev/chk" "next.orly.dev/pkg/crypto/encryption" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/filter" "next.orly.dev/pkg/encoders/hex" @@ -40,7 +40,7 @@ func NewMockWalletService( relay string, initialBalance int64, ) (service *MockWalletService, err error) { // Generate wallet keypair - walletKey := &p256k.Signer{} + walletKey := p256k1signer.NewP256K1Signer() if err = walletKey.Generate(); chk.E(err) { return } diff --git a/pkg/protocol/nwc/uri.go b/pkg/protocol/nwc/uri.go index 913fbb9..2a03f63 100644 --- a/pkg/protocol/nwc/uri.go +++ b/pkg/protocol/nwc/uri.go @@ -6,7 +6,8 @@ import ( "lol.mleku.dev/chk" "next.orly.dev/pkg/crypto/encryption" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" + "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/interfaces/signer" ) @@ -41,7 +42,7 @@ func ParseConnectionURI(nwcUri string) (parts *ConnectionParams, err error) { err = errors.New("incorrect scheme") return } - if parts.walletPublicKey, err = p256k.HexToBin(p.Host); chk.E(err) { + if parts.walletPublicKey, err = hex.Dec(p.Host); chk.E(err) { err = errors.New("invalid public key") return } @@ -62,11 +63,11 @@ func ParseConnectionURI(nwcUri string) (parts *ConnectionParams, err error) { return } var secretBytes []byte - if secretBytes, err = p256k.HexToBin(secret); chk.E(err) { + if secretBytes, err = hex.Dec(secret); chk.E(err) { err = errors.New("invalid secret") return } - clientKey := &p256k.Signer{} + clientKey := p256k1signer.NewP256K1Signer() if err = clientKey.InitSec(secretBytes); chk.E(err) { return } diff --git a/pkg/protocol/ws/client_test.go b/pkg/protocol/ws/client_test.go index 5a89780..23862cd 100644 --- a/pkg/protocol/ws/client_test.go +++ b/pkg/protocol/ws/client_test.go @@ -16,7 +16,7 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/net/websocket" "lol.mleku.dev/chk" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/filter" "next.orly.dev/pkg/encoders/hex" @@ -36,7 +36,7 @@ func TestPublish(t *testing.T) { Tags: tag.NewS(tag.NewFromAny("foo", "bar")), Pubkey: pub, } - sign := &p256k.Signer{} + sign := p256k1signer.NewP256K1Signer() var err error if err = sign.InitSec(priv); chk.E(err) { } @@ -208,7 +208,7 @@ var anyOriginHandshake = func(conf *websocket.Config, r *http.Request) error { func makeKeyPair(t *testing.T) (sec, pub []byte) { t.Helper() - sign := &p256k.Signer{} + sign := p256k1signer.NewP256K1Signer() var err error if err = sign.Generate(); chk.E(err) { return diff --git a/pkg/version/version b/pkg/version/version index 0ce32aa..6305c5a 100644 --- a/pkg/version/version +++ b/pkg/version/version @@ -1 +1 @@ -v0.23.1 \ No newline at end of file +v0.23.2 \ No newline at end of file diff --git a/relay-tester/client.go b/relay-tester/client.go index 80baff5..4d79cdc 100644 --- a/relay-tester/client.go +++ b/relay-tester/client.go @@ -36,6 +36,19 @@ func NewClient(url string) (c *Client, err error) { cancel() return } + + // Set up ping/pong handling to keep connection alive + pongWait := 60 * time.Second + conn.SetReadDeadline(time.Now().Add(pongWait)) + // Set pong handler to extend deadline when pongs are received + // Note: Relay sends pings, gorilla/websocket auto-responds with pongs + // The relay typically doesn't send pongs back, so we also handle timeouts in readLoop + conn.SetPongHandler(func(string) error { + conn.SetReadDeadline(time.Now().Add(pongWait)) + return nil + }) + // Don't set ping handler - let gorilla/websocket auto-respond to pings + c = &Client{ conn: conn, url: url, @@ -78,16 +91,41 @@ func (c *Client) Send(msg interface{}) (err error) { // readLoop reads messages from the relay and routes them to subscriptions. func (c *Client) readLoop() { defer c.conn.Close() + pongWait := 60 * time.Second for { select { case <-c.ctx.Done(): return default: } + // Don't set deadline here - let pong handler manage it + // SetReadDeadline is called initially in NewClient and extended by pong handler _, msg, err := c.conn.ReadMessage() if err != nil { + // Check if context is done + select { + case <-c.ctx.Done(): + return + default: + } + // Check if it's a timeout - connection might still be alive + if netErr, ok := err.(interface{ Timeout() bool }); ok && netErr.Timeout() { + // Pong handler should have extended deadline, but if we timeout, + // reset it and continue - connection might still be alive + // This can happen during idle periods when no messages are received + c.conn.SetReadDeadline(time.Now().Add(pongWait)) + // Continue reading - connection should still be alive if pings/pongs are working + continue + } + // For other errors, check if it's a close error + if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) { + return + } + // For other errors, return (connection is likely dead) return } + // Extend read deadline on successful read + c.conn.SetReadDeadline(time.Now().Add(pongWait)) var raw []interface{} if err = json.Unmarshal(msg, &raw); err != nil { continue diff --git a/relay-tester/keys.go b/relay-tester/keys.go index ad0cabb..2314152 100644 --- a/relay-tester/keys.go +++ b/relay-tester/keys.go @@ -6,7 +6,7 @@ import ( "time" "lol.mleku.dev/chk" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/bech32encoding" "next.orly.dev/pkg/encoders/event" "next.orly.dev/pkg/encoders/hex" @@ -16,7 +16,7 @@ import ( // KeyPair represents a test keypair. type KeyPair struct { - Secret *p256k.Signer + Secret *p256k1signer.P256K1Signer Pubkey []byte Nsec string Npub string @@ -25,7 +25,7 @@ type KeyPair struct { // GenerateKeyPair generates a new keypair for testing. func GenerateKeyPair() (kp *KeyPair, err error) { kp = &KeyPair{} - kp.Secret = &p256k.Signer{} + kp.Secret = p256k1signer.NewP256K1Signer() if err = kp.Secret.Generate(); chk.E(err) { return } @@ -44,7 +44,7 @@ func GenerateKeyPair() (kp *KeyPair, err error) { } // CreateEvent creates a signed event with the given parameters. -func CreateEvent(signer *p256k.Signer, kindNum uint16, content string, tags *tag.S) (ev *event.E, err error) { +func CreateEvent(signer *p256k1signer.P256K1Signer, kindNum uint16, content string, tags *tag.S) (ev *event.E, err error) { ev = event.New() ev.CreatedAt = time.Now().Unix() ev.Kind = kindNum @@ -61,7 +61,7 @@ func CreateEvent(signer *p256k.Signer, kindNum uint16, content string, tags *tag } // CreateEventWithTags creates an event with specific tags. -func CreateEventWithTags(signer *p256k.Signer, kindNum uint16, content string, tagPairs [][]string) (ev *event.E, err error) { +func CreateEventWithTags(signer *p256k1signer.P256K1Signer, kindNum uint16, content string, tagPairs [][]string) (ev *event.E, err error) { tags := tag.NewS() for _, pair := range tagPairs { if len(pair) >= 2 { @@ -78,17 +78,17 @@ func CreateEventWithTags(signer *p256k.Signer, kindNum uint16, content string, t } // CreateReplaceableEvent creates a replaceable event (kind 0-3, 10000-19999). -func CreateReplaceableEvent(signer *p256k.Signer, kindNum uint16, content string) (ev *event.E, err error) { +func CreateReplaceableEvent(signer *p256k1signer.P256K1Signer, kindNum uint16, content string) (ev *event.E, err error) { return CreateEvent(signer, kindNum, content, nil) } // CreateEphemeralEvent creates an ephemeral event (kind 20000-29999). -func CreateEphemeralEvent(signer *p256k.Signer, kindNum uint16, content string) (ev *event.E, err error) { +func CreateEphemeralEvent(signer *p256k1signer.P256K1Signer, kindNum uint16, content string) (ev *event.E, err error) { return CreateEvent(signer, kindNum, content, nil) } // CreateDeleteEvent creates a deletion event (kind 5). -func CreateDeleteEvent(signer *p256k.Signer, eventIDs [][]byte, reason string) (ev *event.E, err error) { +func CreateDeleteEvent(signer *p256k1signer.P256K1Signer, eventIDs [][]byte, reason string) (ev *event.E, err error) { tags := tag.NewS() for _, id := range eventIDs { // e tags must contain hex-encoded event IDs @@ -101,7 +101,7 @@ func CreateDeleteEvent(signer *p256k.Signer, eventIDs [][]byte, reason string) ( } // CreateParameterizedReplaceableEvent creates a parameterized replaceable event (kind 30000-39999). -func CreateParameterizedReplaceableEvent(signer *p256k.Signer, kindNum uint16, content string, dTag string) (ev *event.E, err error) { +func CreateParameterizedReplaceableEvent(signer *p256k1signer.P256K1Signer, kindNum uint16, content string, dTag string) (ev *event.E, err error) { tags := tag.NewS() tags.Append(tag.NewFromBytesSlice([]byte("d"), []byte(dTag))) return CreateEvent(signer, kindNum, content, tags) diff --git a/scripts/run-policy-filter-test.sh b/scripts/run-policy-filter-test.sh index 9b71a82..00b5cc1 100755 --- a/scripts/run-policy-filter-test.sh +++ b/scripts/run-policy-filter-test.sh @@ -38,13 +38,13 @@ package main import ( "encoding/json" "fmt" - "next.orly.dev/pkg/crypto/p256k" + p256k1signer "p256k1.mleku.dev/signer" "next.orly.dev/pkg/encoders/hex" ) func main() { // Generate allowed signer - allowedSigner := &p256k.Signer{} + allowedSigner := p256k1signer.NewP256K1Signer() if err := allowedSigner.Generate(); err != nil { panic(err) } @@ -52,7 +52,7 @@ func main() { allowedSecHex := hex.Enc(allowedSigner.Sec()) // Generate unauthorized signer - unauthorizedSigner := &p256k.Signer{} + unauthorizedSigner := p256k1signer.NewP256K1Signer() if err := unauthorizedSigner.Generate(); err != nil { panic(err) } diff --git a/scripts/test-workflow-act.sh b/scripts/test-workflow-act.sh new file mode 100755 index 0000000..cae2e9d --- /dev/null +++ b/scripts/test-workflow-act.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# Run GitHub Actions workflow locally using act +# Usage: ./scripts/test-workflow-local.sh [job-name] +# job-name: optional, defaults to 'build'. Can be 'build' or 'release' + +set -e + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +WORKFLOW_FILE="${SCRIPT_DIR}/../.github/workflows/go.yml" +JOB_NAME="${1:-build}" + +# Check if act is installed +if ! command -v act >/dev/null 2>&1; then + echo "Error: 'act' is not installed" + echo "Install it with:" + echo " curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash" + echo " # or on macOS: brew install act" + exit 1 +fi + +echo "=== Running GitHub Actions workflow locally ===" +echo "Workflow: .github/workflows/go.yml" +echo "Job: $JOB_NAME" +echo "" + +case "$JOB_NAME" in + build) + echo "Running build job..." + act push --workflows "$WORKFLOW_FILE" --job build + ;; + release) + echo "Running release job (simulating tag push)..." + # Simulate a tag push event with a valid tag format + # The workflow requires build to run first and succeed + echo "Step 1: Running build job (required dependency)..." + if ! act push --workflows "$WORKFLOW_FILE" --job build; then + echo "Error: Build job failed. Release job cannot proceed." + exit 1 + fi + + echo "" + echo "Step 2: Running release job..." + echo "Note: GitHub release creation may fail locally (no valid token), but binary building will be tested" + # Use a tag that matches the workflow pattern: v[0-9]+.[0-9]+.[0-9]+ + # Provide a dummy GITHUB_TOKEN to prevent immediate failure + # The release won't actually be created, but the workflow will test binary building + # Temporarily disable exit on error to allow release step to fail gracefully + set +e + GITHUB_REF=refs/tags/v1.0.0 \ + GITHUB_TOKEN=dummy_token_for_local_testing \ + act push \ + --workflows "$WORKFLOW_FILE" \ + --job release \ + --secret GITHUB_TOKEN=dummy_token_for_local_testing \ + --eventpath /dev/stdin </dev/null 2>&1 && echo $0' | grep .) +echo "" + +echo "=== Build job completed successfully ===" +