diff --git a/connection_options.go b/connection_options.go index ada5885..c14b933 100644 --- a/connection_options.go +++ b/connection_options.go @@ -13,7 +13,7 @@ import ( var defaultConnectionOptions = &ws.DialOptions{ CompressionMode: ws.CompressionContextTakeover, HTTPHeader: http.Header{ - textproto.CanonicalMIMEHeaderKey("User-Agent"): {"fiatjaf.com/nostrlib"}, + textproto.CanonicalMIMEHeaderKey("User-Agent"): {"fiatjaf.com/nostr"}, }, } diff --git a/example/example.go b/example/example.go index 5082c1b..bca8380 100644 --- a/example/example.go +++ b/example/example.go @@ -9,8 +9,8 @@ import ( "time" jsoniter "github.com/json-iterator/go" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip19" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip19" ) func main() { diff --git a/keyer.go b/keyer.go index b267d49..387c14d 100644 --- a/keyer.go +++ b/keyer.go @@ -18,7 +18,7 @@ type Keyer interface { // User is an entity that has a public key (although they can't sign anything). type User interface { // GetPublicKey returns the public key associated with this user. - GetPublicKey(ctx context.Context) (string, error) + GetPublicKey(ctx context.Context) (PubKey, error) } // Signer is a User that can also sign events. @@ -35,9 +35,9 @@ type Signer interface { type Cipher interface { // Encrypt encrypts a plaintext message for a recipient. // Returns the encrypted message as a base64-encoded string. - Encrypt(ctx context.Context, plaintext string, recipientPublicKey string) (base64ciphertext string, err error) + Encrypt(ctx context.Context, plaintext string, recipient PubKey) (base64ciphertext string, err error) // Decrypt decrypts a base64-encoded ciphertext from a sender. // Returns the decrypted plaintext. - Decrypt(ctx context.Context, base64ciphertext string, senderPublicKey string) (plaintext string, err error) + Decrypt(ctx context.Context, base64ciphertext string, sender PubKey) (plaintext string, err error) } diff --git a/keyer/bunker.go b/keyer/bunker.go index d88745f..5f21391 100644 --- a/keyer/bunker.go +++ b/keyer/bunker.go @@ -5,8 +5,8 @@ import ( "errors" "time" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip46" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip46" ) var _ nostr.Keyer = (*BunkerSigner)(nil) diff --git a/keyer/encrypted.go b/keyer/encrypted.go index d11305c..99d592e 100644 --- a/keyer/encrypted.go +++ b/keyer/encrypted.go @@ -4,9 +4,9 @@ import ( "context" "fmt" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip44" - "fiatjaf.com/nostrlib/nip49" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip44" + "fiatjaf.com/nostr/nip49" ) var _ nostr.Keyer = (*EncryptedKeySigner)(nil) diff --git a/keyer/lib.go b/keyer/lib.go index bfff088..a027cc5 100644 --- a/keyer/lib.go +++ b/keyer/lib.go @@ -7,11 +7,11 @@ import ( "strings" "time" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip05" - "fiatjaf.com/nostrlib/nip19" - "fiatjaf.com/nostrlib/nip46" - "fiatjaf.com/nostrlib/nip49" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip05" + "fiatjaf.com/nostr/nip19" + "fiatjaf.com/nostr/nip46" + "fiatjaf.com/nostr/nip49" "github.com/puzpuzpuz/xsync/v3" ) diff --git a/keyer/manual.go b/keyer/manual.go index 6926ead..4a4cbca 100644 --- a/keyer/manual.go +++ b/keyer/manual.go @@ -3,7 +3,7 @@ package keyer import ( "context" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) var _ nostr.Keyer = (*ManualSigner)(nil) diff --git a/keyer/plain.go b/keyer/plain.go index 946979a..e9d41b0 100644 --- a/keyer/plain.go +++ b/keyer/plain.go @@ -3,8 +3,8 @@ package keyer import ( "context" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip44" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip44" "github.com/puzpuzpuz/xsync/v3" ) diff --git a/keyer/readonly.go b/keyer/readonly.go index c2d2e32..9b13a98 100644 --- a/keyer/readonly.go +++ b/keyer/readonly.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) var ( diff --git a/nip04/nip04.go b/nip04/nip04.go index b2619aa..1ddf902 100644 --- a/nip04/nip04.go +++ b/nip04/nip04.go @@ -10,27 +10,20 @@ import ( "fmt" "strings" + "fiatjaf.com/nostr" "github.com/btcsuite/btcd/btcec/v2" ) // ComputeSharedSecret returns a shared secret key used to encrypt messages. // The private and public keys should be hex encoded. // Uses the Diffie-Hellman key exchange (ECDH) (RFC 4753). -func ComputeSharedSecret(pub string, sk string) (sharedSecret []byte, err error) { - privKeyBytes, err := hex.DecodeString(sk) - if err != nil { - return nil, fmt.Errorf("error decoding sender private key: %w", err) - } - privKey, _ := btcec.PrivKeyFromBytes(privKeyBytes) +func ComputeSharedSecret(pub nostr.PubKey, sk [32]byte) (sharedSecret []byte, err error) { + privKey, _ := btcec.PrivKeyFromBytes(sk[:]) // adding 02 to signal that this is a compressed public key (33 bytes) - pubKeyBytes, err := hex.DecodeString("02" + pub) + pubKey, err := btcec.ParsePubKey(append([]byte{2}, pub[:]...)) if err != nil { - return nil, fmt.Errorf("error decoding hex string of receiver public key '%s': %w", "02"+pub, err) - } - pubKey, err := btcec.ParsePubKey(pubKeyBytes) - if err != nil { - return nil, fmt.Errorf("error parsing receiver public key '%s': %w", "02"+pub, err) + return nil, fmt.Errorf("error parsing receiver public key '%s': %w", "02"+hex.EncodeToString(pub[:]), err) } return btcec.GenerateSharedSecret(privKey, pubKey), nil diff --git a/nip04/nip04_test.go b/nip04/nip04_test.go index 123375d..487e6cf 100644 --- a/nip04/nip04_test.go +++ b/nip04/nip04_test.go @@ -1,10 +1,11 @@ package nip04 import ( + "encoding/hex" "strings" "testing" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" "github.com/stretchr/testify/require" ) @@ -13,10 +14,8 @@ func TestSharedKeysAreTheSame(t *testing.T) { sk1 := nostr.GeneratePrivateKey() sk2 := nostr.GeneratePrivateKey() - pk1, err := nostr.GetPublicKey(sk1) - require.NoError(t, err) - pk2, err := nostr.GetPublicKey(sk2) - require.NoError(t, err) + pk1 := nostr.GetPublicKey(sk1) + pk2 := nostr.GetPublicKey(sk2) ss1, err := ComputeSharedSecret(pk2, sk1) require.NoError(t, err) @@ -57,10 +56,10 @@ func TestEncryptionAndDecryptionWithMultipleLengths(t *testing.T) { } func TestNostrToolsCompatibility(t *testing.T) { - sk1 := "92996316beebf94171065a714cbf164d1f56d7ad9b35b329d9fc97535bf25352" - sk2 := "591c0c249adfb9346f8d37dfeed65725e2eea1d7a6e99fa503342f367138de84" - pk2, _ := nostr.GetPublicKey(sk2) - shared, _ := ComputeSharedSecret(pk2, sk1) + sk1, _ := hex.DecodeString("92996316beebf94171065a714cbf164d1f56d7ad9b35b329d9fc97535bf25352") + sk2, _ := hex.DecodeString("591c0c249adfb9346f8d37dfeed65725e2eea1d7a6e99fa503342f367138de84") + pk2 := nostr.GetPublicKey([32]byte(sk2)) + shared, _ := ComputeSharedSecret(pk2, [32]byte(sk1)) ciphertext := "A+fRnU4aXS4kbTLfowqAww==?iv=QFYUrl5or/n/qamY79ze0A==" plaintext, _ := Decrypt(ciphertext, shared) require.Equal(t, "hello", plaintext, "invalid decryption of nostr-tools payload") diff --git a/nip05/nip05.go b/nip05/nip05.go index b8ef441..a4e1f99 100644 --- a/nip05/nip05.go +++ b/nip05/nip05.go @@ -7,8 +7,8 @@ import ( "regexp" "strings" + "fiatjaf.com/nostr" jsoniter "github.com/json-iterator/go" - "fiatjaf.com/nostrlib" ) var NIP05_REGEX = regexp.MustCompile(`^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$`) @@ -40,16 +40,17 @@ func QueryIdentifier(ctx context.Context, fullname string) (*nostr.ProfilePointe return nil, err } - pubkey, ok := result.Names[name] + pubkeyh, ok := result.Names[name] if !ok { return nil, fmt.Errorf("no entry for name '%s'", name) } - if !nostr.IsValidPublicKey(pubkey) { - return nil, fmt.Errorf("got an invalid public key '%s'", pubkey) + pubkey, err := nostr.PubKeyFromHex(pubkeyh) + if err != nil { + return nil, fmt.Errorf("got an invalid public key '%s'", pubkeyh) } - relays, _ := result.Relays[pubkey] + relays, _ := result.Relays[pubkeyh] return &nostr.ProfilePointer{ PublicKey: pubkey, Relays: relays, diff --git a/nip10/nip10.go b/nip10/nip10.go index 5b848d2..d9409c3 100644 --- a/nip10/nip10.go +++ b/nip10/nip10.go @@ -1,6 +1,6 @@ package nip10 -import "fiatjaf.com/nostrlib" +import "fiatjaf.com/nostr" func GetThreadRoot(tags nostr.Tags) *nostr.EventPointer { for _, tag := range tags { diff --git a/nip11/fetch.go b/nip11/fetch.go index 97dea1d..dfdc2f5 100644 --- a/nip11/fetch.go +++ b/nip11/fetch.go @@ -7,7 +7,7 @@ import ( "time" jsoniter "github.com/json-iterator/go" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) // Fetch fetches the NIP-11 metadata for a relay. diff --git a/nip13/nip13.go b/nip13/nip13.go index 3286269..d850e24 100644 --- a/nip13/nip13.go +++ b/nip13/nip13.go @@ -9,7 +9,7 @@ import ( "runtime" "strconv" - nostr "fiatjaf.com/nostrlib" + nostr "fiatjaf.com/nostr" ) var ( diff --git a/nip13/nip13_test.go b/nip13/nip13_test.go index b3afc0b..9780737 100644 --- a/nip13/nip13_test.go +++ b/nip13/nip13_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - nostr "fiatjaf.com/nostrlib" + nostr "fiatjaf.com/nostr" "github.com/stretchr/testify/require" ) diff --git a/nip14/subject.go b/nip14/subject.go index 259ddf5..932d458 100644 --- a/nip14/subject.go +++ b/nip14/subject.go @@ -1,6 +1,6 @@ package nip14 -import "fiatjaf.com/nostrlib" +import "fiatjaf.com/nostr" func GetSubject(tags nostr.Tags) string { for _, tag := range tags { diff --git a/nip17/nip17.go b/nip17/nip17.go index 0b5b320..d08748e 100644 --- a/nip17/nip17.go +++ b/nip17/nip17.go @@ -5,8 +5,8 @@ import ( "fmt" "strings" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip59" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip59" ) func GetDMRelays(ctx context.Context, pubkey string, pool *nostr.SimplePool, relaysToQuery []string) []string { diff --git a/nip19/nip19.go b/nip19/nip19.go index 25e3b50..30fd815 100644 --- a/nip19/nip19.go +++ b/nip19/nip19.go @@ -3,11 +3,10 @@ package nip19 import ( "bytes" "encoding/binary" - "encoding/hex" "fmt" + "fiatjaf.com/nostr" "github.com/btcsuite/btcd/btcutil/bech32" - "fiatjaf.com/nostrlib" ) func Decode(bech32string string) (prefix string, value any, err error) { @@ -22,12 +21,21 @@ func Decode(bech32string string) (prefix string, value any, err error) { } switch prefix { - case "npub", "nsec", "note": + case "nsec": if len(data) != 32 { - return prefix, nil, fmt.Errorf("data should be 32 bytes (%d)", len(data)) + return prefix, nil, fmt.Errorf("nsec should be 32 bytes (%d)", len(data)) } - - return prefix, hex.EncodeToString(data[0:32]), nil + return prefix, [32]byte(data[0:32]), nil + case "note": + if len(data) != 32 { + return prefix, nil, fmt.Errorf("note should be 32 bytes (%d)", len(data)) + } + return prefix, [32]byte(data[0:32]), nil + case "npub": + if len(data) != 32 { + return prefix, nil, fmt.Errorf("npub should be 32 bytes (%d)", len(data)) + } + return prefix, nostr.PubKey(data[0:32]), nil case "nprofile": var result nostr.ProfilePointer curr := 0 @@ -35,7 +43,7 @@ func Decode(bech32string string) (prefix string, value any, err error) { t, v := readTLVEntry(data[curr:]) if v == nil { // end here - if result.PublicKey == "" { + if result.PublicKey == nostr.ZeroPK { return prefix, result, fmt.Errorf("no pubkey found for nprofile") } @@ -47,7 +55,7 @@ func Decode(bech32string string) (prefix string, value any, err error) { if len(v) != 32 { return prefix, nil, fmt.Errorf("pubkey should be 32 bytes (%d)", len(v)) } - result.PublicKey = hex.EncodeToString(v) + result.PublicKey = nostr.PubKey(v) case TLVRelay: result.Relays = append(result.Relays, string(v)) default: @@ -63,7 +71,7 @@ func Decode(bech32string string) (prefix string, value any, err error) { t, v := readTLVEntry(data[curr:]) if v == nil { // end here - if result.ID == "" { + if result.ID == nostr.ZeroID { return prefix, result, fmt.Errorf("no id found for nevent") } @@ -75,19 +83,19 @@ func Decode(bech32string string) (prefix string, value any, err error) { if len(v) != 32 { return prefix, nil, fmt.Errorf("id should be 32 bytes (%d)", len(v)) } - result.ID = hex.EncodeToString(v) + result.ID = nostr.ID(v) case TLVRelay: result.Relays = append(result.Relays, string(v)) case TLVAuthor: if len(v) != 32 { return prefix, nil, fmt.Errorf("author should be 32 bytes (%d)", len(v)) } - result.Author = hex.EncodeToString(v) + result.Author = nostr.PubKey(v) case TLVKind: if len(v) != 4 { return prefix, nil, fmt.Errorf("invalid uint32 value for integer (%v)", v) } - result.Kind = int(binary.BigEndian.Uint32(v)) + result.Kind = uint16(binary.BigEndian.Uint32(v)) default: // ignore } @@ -101,7 +109,7 @@ func Decode(bech32string string) (prefix string, value any, err error) { t, v := readTLVEntry(data[curr:]) if v == nil { // end here - if result.Kind == 0 || result.Identifier == "" || result.PublicKey == "" { + if result.Kind == 0 || result.Identifier == "" || result.PublicKey == nostr.ZeroPK { return prefix, result, fmt.Errorf("incomplete naddr") } @@ -117,9 +125,9 @@ func Decode(bech32string string) (prefix string, value any, err error) { if len(v) != 32 { return prefix, nil, fmt.Errorf("author should be 32 bytes (%d)", len(v)) } - result.PublicKey = hex.EncodeToString(v) + result.PublicKey = nostr.PubKey(v) case TLVKind: - result.Kind = int(binary.BigEndian.Uint32(v)) + result.Kind = uint16(binary.BigEndian.Uint32(v)) default: // ignore } @@ -131,13 +139,8 @@ func Decode(bech32string string) (prefix string, value any, err error) { return prefix, data, fmt.Errorf("unknown tag %s", prefix) } -func EncodePrivateKey(privateKeyHex string) (string, error) { - b, err := hex.DecodeString(privateKeyHex) - if err != nil { - return "", fmt.Errorf("failed to decode private key hex: %w", err) - } - - bits5, err := bech32.ConvertBits(b, 8, 5, true) +func EncodeNsec(sk [32]byte) (string, error) { + bits5, err := bech32.ConvertBits(sk[:], 8, 5, true) if err != nil { return "", err } @@ -145,79 +148,44 @@ func EncodePrivateKey(privateKeyHex string) (string, error) { return bech32.Encode("nsec", bits5) } -func EncodePublicKey(publicKeyHex string) (string, error) { - b, err := hex.DecodeString(publicKeyHex) - if err != nil { - return "", fmt.Errorf("failed to decode public key hex: %w", err) - } - - bits5, err := bech32.ConvertBits(b, 8, 5, true) - if err != nil { - return "", err - } - - return bech32.Encode("npub", bits5) +func EncodeNpub(pk nostr.PubKey) string { + bits5, _ := bech32.ConvertBits(pk[:], 8, 5, true) + npub, _ := bech32.Encode("npub", bits5) + return npub } -func EncodeNote(eventIDHex string) (string, error) { - b, err := hex.DecodeString(eventIDHex) - if err != nil { - return "", fmt.Errorf("failed to decode event id hex: %w", err) - } - - bits5, err := bech32.ConvertBits(b, 8, 5, true) - if err != nil { - return "", err - } - - return bech32.Encode("note", bits5) -} - -func EncodeProfile(publicKeyHex string, relays []string) (string, error) { +func EncodeNprofile(pk nostr.PubKey, relays []string) string { buf := &bytes.Buffer{} - pubkey, err := hex.DecodeString(publicKeyHex) - if err != nil { - return "", fmt.Errorf("invalid pubkey '%s': %w", publicKeyHex, err) - } - writeTLVEntry(buf, TLVDefault, pubkey) + writeTLVEntry(buf, TLVDefault, pk[:]) for _, url := range relays { writeTLVEntry(buf, TLVRelay, []byte(url)) } - bits5, err := bech32.ConvertBits(buf.Bytes(), 8, 5, true) - if err != nil { - return "", fmt.Errorf("failed to convert bits: %w", err) - } + bits5, _ := bech32.ConvertBits(buf.Bytes(), 8, 5, true) - return bech32.Encode("nprofile", bits5) + nprofile, _ := bech32.Encode("nprofile", bits5) + return nprofile } -func EncodeEvent(eventIDHex string, relays []string, author string) (string, error) { +func EncodeNevent(id nostr.ID, relays []string, author nostr.PubKey) string { buf := &bytes.Buffer{} - id, err := hex.DecodeString(eventIDHex) - if err != nil || len(id) != 32 { - return "", fmt.Errorf("invalid id '%s': %w", eventIDHex, err) - } - writeTLVEntry(buf, TLVDefault, id) + writeTLVEntry(buf, TLVDefault, id[:]) for _, url := range relays { writeTLVEntry(buf, TLVRelay, []byte(url)) } - if pubkey, _ := hex.DecodeString(author); len(pubkey) == 32 { - writeTLVEntry(buf, TLVAuthor, pubkey) + if author != nostr.ZeroPK { + writeTLVEntry(buf, TLVAuthor, author[:]) } - bits5, err := bech32.ConvertBits(buf.Bytes(), 8, 5, true) - if err != nil { - return "", fmt.Errorf("failed to convert bits: %w", err) - } - - return bech32.Encode("nevent", bits5) + bits5, _ := bech32.ConvertBits(buf.Bytes(), 8, 5, true) + nevent, _ := bech32.Encode("nevent", bits5) + return nevent } -func EncodeEntity(publicKey string, kind int, identifier string, relays []string) (string, error) { +func EncodeNaddr(pk nostr.PubKey, kind uint16, identifier string, relays []string) string { buf := &bytes.Buffer{} writeTLVEntry(buf, TLVDefault, []byte(identifier)) @@ -226,20 +194,13 @@ func EncodeEntity(publicKey string, kind int, identifier string, relays []string writeTLVEntry(buf, TLVRelay, []byte(url)) } - pubkey, err := hex.DecodeString(publicKey) - if err != nil { - return "", fmt.Errorf("invalid pubkey '%s': %w", pubkey, err) - } - writeTLVEntry(buf, TLVAuthor, pubkey) + writeTLVEntry(buf, TLVAuthor, pk[:]) kindBytes := make([]byte, 4) binary.BigEndian.PutUint32(kindBytes, uint32(kind)) writeTLVEntry(buf, TLVKind, kindBytes) - bits5, err := bech32.ConvertBits(buf.Bytes(), 8, 5, true) - if err != nil { - return "", fmt.Errorf("failed to convert bits: %w", err) - } - - return bech32.Encode("naddr", bits5) + bits5, _ := bech32.ConvertBits(buf.Bytes(), 8, 5, true) + naddr, _ := bech32.Encode("naddr", bits5) + return naddr } diff --git a/nip19/nip19_test.go b/nip19/nip19_test.go index 8c4edc4..648d46a 100644 --- a/nip19/nip19_test.go +++ b/nip19/nip19_test.go @@ -1,21 +1,24 @@ package nip19 import ( + "encoding/hex" "testing" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestEncodeNpub(t *testing.T) { - npub, err := EncodePublicKey("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d") - assert.NoError(t, err) + npub := EncodeNpub(nostr.MustPubKeyFromHex("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")) assert.Equal(t, "npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6", npub, "produced an unexpected npub string") } func TestEncodeNsec(t *testing.T) { - nsec, err := EncodePrivateKey("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d") + skh := "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d" + var sk [32]byte + hex.Decode(sk[:], []byte(skh)) + nsec, err := EncodeNsec(sk) assert.NoError(t, err) assert.Equal(t, "nsec180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsgyumg0", nsec, "produced an unexpected nsec string") } @@ -63,20 +66,22 @@ func TestDecodeNprofile(t *testing.T) { } func TestEncodeNprofile(t *testing.T) { - nprofile, err := EncodeProfile("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", []string{ - "wss://r.x.com", - "wss://djbas.sadkb.com", - }) + nprofile := EncodeNprofile( + nostr.MustPubKeyFromHex("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"), + []string{ + "wss://r.x.com", + "wss://djbas.sadkb.com", + }, + ) - assert.NoError(t, err) assert.Equal(t, "nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p", nprofile, "produced an unexpected nprofile string: %s", nprofile) } func TestEncodeDecodeNaddr(t *testing.T) { - naddr, err := EncodeEntity( - "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", + naddr := EncodeNaddr( + nostr.MustPubKeyFromHex("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"), nostr.KindArticle, "banana", []string{ @@ -84,7 +89,6 @@ func TestEncodeDecodeNaddr(t *testing.T) { "wss://nostr.banana.com", }) - assert.NoError(t, err) assert.Equal(t, "naddr1qqrxyctwv9hxzqfwwaehxw309aex2mrp0yhxummnw3ezuetcv9khqmr99ekhjer0d4skjm3wv4uxzmtsd3jjucm0d5q3vamnwvaz7tmwdaehgu3wvfskuctwvyhxxmmdqgsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8grqsqqqa28a3lkds", naddr, "produced an unexpected naddr string: %s", naddr) @@ -116,14 +120,12 @@ func TestDecodeNaddrWithoutRelays(t *testing.T) { } func TestEncodeDecodeNEvent(t *testing.T) { - nevent, err := EncodeEvent( - "45326f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194", + nevent := EncodeNevent( + nostr.MustIDFromHex("45326f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194"), []string{"wss://banana.com"}, - "7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751abb88", + nostr.MustPubKeyFromHex("7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751abb88"), ) - assert.NoError(t, err) - expectedNEvent := "nevent1qqsy2vn0t45k92c78n2zfe6ccvqzhpn977cd3h8wnl579zxhw5dvr9qpzpmhxue69uhkyctwv9hxztnrdaksygrl54h466tz4v0re4pyuavvxqptsejl0vxcmnhfl60z3rth2x4m3q04ndyp" assert.Equal(t, expectedNEvent, nevent) diff --git a/nip19/pointer.go b/nip19/pointer.go index b5db4fc..1a73c4d 100644 --- a/nip19/pointer.go +++ b/nip19/pointer.go @@ -3,7 +3,7 @@ package nip19 import ( "fmt" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) func EncodePointer(pointer nostr.Pointer) string { diff --git a/nip19/utils.go b/nip19/utils.go index bbcb985..fbebb94 100644 --- a/nip19/utils.go +++ b/nip19/utils.go @@ -1,10 +1,9 @@ package nip19 import ( - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) func NeventFromRelayEvent(ie nostr.RelayEvent) string { - v, _ := EncodeEvent(ie.ID, []string{ie.Relay.URL}, ie.PubKey) - return v + return EncodeNevent(ie.ID, []string{ie.Relay.URL}, ie.PubKey) } diff --git a/nip27/blocks.go b/nip27/blocks.go index 7b1ce9d..37b7eee 100644 --- a/nip27/blocks.go +++ b/nip27/blocks.go @@ -6,9 +6,9 @@ import ( "regexp" "strings" - "github.com/nbd-wtf/go-nostr" - "github.com/nbd-wtf/go-nostr/nip19" - "github.com/nbd-wtf/go-nostr/nip73" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip19" + "fiatjaf.com/nostr/nip73" ) type Block struct { @@ -54,7 +54,7 @@ func Parse(content string) iter.Seq[Block] { var pointer nostr.Pointer switch prefix { case "npub": - pointer = nostr.ProfilePointer{PublicKey: data.(string)} + pointer = nostr.ProfilePointer{PublicKey: data.(nostr.PubKey)} case "nprofile", "nevent", "naddr": pointer = data.(nostr.Pointer) case "note", "nsec": diff --git a/nip27/blocks_test.go b/nip27/blocks_test.go index ce25585..8a32d71 100644 --- a/nip27/blocks_test.go +++ b/nip27/blocks_test.go @@ -5,8 +5,8 @@ import ( "slices" "testing" - "github.com/nbd-wtf/go-nostr" - "github.com/nbd-wtf/go-nostr/nip73" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip73" "github.com/stretchr/testify/require" ) @@ -19,9 +19,9 @@ func TestParse(t *testing.T) { "hello, nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg wrote nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4!", []Block{ {Text: "hello, ", Start: 0}, - {Text: "nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg", Start: 7, Pointer: nostr.ProfilePointer{PublicKey: "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393"}}, + {Text: "nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg", Start: 7, Pointer: nostr.ProfilePointer{PublicKey: nostr.MustPubKeyFromHex("cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393")}}, {Text: " wrote ", Start: 83}, - {Text: "nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4", Start: 90, Pointer: nostr.EventPointer{ID: "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393"}}, + {Text: "nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4", Start: 90, Pointer: nostr.EventPointer{ID: nostr.MustIDFromHex("cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393")}}, {Text: "!", Start: 164}, }, }, diff --git a/nip27/references.go b/nip27/references.go deleted file mode 100644 index b4842ac..0000000 --- a/nip27/references.go +++ /dev/null @@ -1,82 +0,0 @@ -package nip27 - -import ( - "iter" - "regexp" - - "github.com/nbd-wtf/go-nostr" - "github.com/nbd-wtf/go-nostr/nip19" -) - -type Reference struct { - Text string - Start int - End int - Pointer nostr.Pointer -} - -var mentionRegex = regexp.MustCompile(`\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b`) - -// Deprecated: this is useless, use Parse() isntead (but the semantics is different) -func ParseReferences(evt nostr.Event) iter.Seq[Reference] { - return func(yield func(Reference) bool) { - for _, ref := range mentionRegex.FindAllStringSubmatchIndex(evt.Content, -1) { - reference := Reference{ - Text: evt.Content[ref[0]:ref[1]], - Start: ref[0], - End: ref[1], - } - - nip19code := evt.Content[ref[2]:ref[3]] - - if prefix, data, err := nip19.Decode(nip19code); err == nil { - switch prefix { - case "npub": - pointer := nostr.ProfilePointer{ - PublicKey: data.(string), Relays: []string{}, - } - tag := evt.Tags.FindWithValue("p", pointer.PublicKey) - if tag != nil && len(tag) >= 3 { - pointer.Relays = []string{tag[2]} - } - if nostr.IsValidPublicKey(pointer.PublicKey) { - reference.Pointer = pointer - } - case "nprofile": - pointer := data.(nostr.ProfilePointer) - tag := evt.Tags.FindWithValue("p", pointer.PublicKey) - if tag != nil && len(tag) >= 3 { - pointer.Relays = append(pointer.Relays, tag[2]) - } - if nostr.IsValidPublicKey(pointer.PublicKey) { - reference.Pointer = pointer - } - case "note": - // we don't even bother here because people using note1 codes aren't including relay hints anyway - reference.Pointer = nostr.EventPointer{ID: data.(string), Relays: nil} - case "nevent": - pointer := data.(nostr.EventPointer) - tag := evt.Tags.FindWithValue("e", pointer.ID) - if tag != nil && len(tag) >= 3 { - pointer.Relays = append(pointer.Relays, tag[2]) - if pointer.Author == "" && len(tag) >= 5 && nostr.IsValidPublicKey(tag[4]) { - pointer.Author = tag[4] - } - } - reference.Pointer = pointer - case "naddr": - pointer := data.(nostr.EntityPointer) - tag := evt.Tags.FindWithValue("a", pointer.AsTagReference()) - if tag != nil && len(tag) >= 3 { - pointer.Relays = append(pointer.Relays, tag[2]) - } - reference.Pointer = pointer - } - } - - if !yield(reference) { - return - } - } - } -} diff --git a/nip27/references_test.go b/nip27/references_test.go deleted file mode 100644 index b720ac9..0000000 --- a/nip27/references_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package nip27 - -import ( - "slices" - "testing" - - "github.com/nbd-wtf/go-nostr" - "github.com/stretchr/testify/require" -) - -func TestParseReferences(t *testing.T) { - evt := nostr.Event{ - Tags: nostr.Tags{ - {"p", "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393", "wss://xawr.com"}, - {"e", "a84c5de86efc2ec2cff7bad077c4171e09146b633b7ad117fffe088d9579ac33", "wss://other.com", "reply"}, - {"e", "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393", "wss://nasdj.com"}, - }, - Content: "hello, nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg wrote nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4!", - } - - expected := []Reference{ - { - Text: "nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg", - Start: 7, - End: 83, - Pointer: nostr.ProfilePointer{ - PublicKey: "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393", - Relays: []string{"wss://xawr.com"}, - }, - }, - { - Text: "nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4", - Start: 90, - End: 164, - Pointer: nostr.EventPointer{ - ID: "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393", - Relays: []string{"wss://nasdj.com"}, - Author: "", - }, - }, - } - - got := slices.Collect(ParseReferences(evt)) - - require.EqualValues(t, expected, got) -} diff --git a/nip29/group.go b/nip29/group.go index 08c0e39..aa2512d 100644 --- a/nip29/group.go +++ b/nip29/group.go @@ -6,7 +6,7 @@ import ( "slices" "strings" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type GroupAddress struct { diff --git a/nip29/nip29.go b/nip29/nip29.go index 94fc95b..6b97fee 100644 --- a/nip29/nip29.go +++ b/nip29/nip29.go @@ -3,7 +3,7 @@ package nip29 import ( "slices" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type Role struct { diff --git a/nip31/nip31.go b/nip31/nip31.go index 5383fad..0f0cc8a 100644 --- a/nip31/nip31.go +++ b/nip31/nip31.go @@ -1,6 +1,6 @@ package nip31 -import "fiatjaf.com/nostrlib" +import "fiatjaf.com/nostr" func GetAlt(event nostr.Event) string { for _, tag := range event.Tags { diff --git a/nip34/patch.go b/nip34/patch.go index 0aa81ba..11bbdc2 100644 --- a/nip34/patch.go +++ b/nip34/patch.go @@ -4,7 +4,7 @@ import ( "strings" "github.com/bluekeyes/go-gitdiff/gitdiff" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type Patch struct { diff --git a/nip34/repository.go b/nip34/repository.go index 3601533..7e60300 100644 --- a/nip34/repository.go +++ b/nip34/repository.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type Repository struct { diff --git a/nip34/state.go b/nip34/state.go index bc08a1e..6417fdb 100644 --- a/nip34/state.go +++ b/nip34/state.go @@ -3,7 +3,7 @@ package nip34 import ( "strings" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type RepositoryState struct { diff --git a/nip40/nip40.go b/nip40/nip40.go index 7d83e03..5128f68 100644 --- a/nip40/nip40.go +++ b/nip40/nip40.go @@ -3,7 +3,7 @@ package nip40 import ( "strconv" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) // GetExpiration returns the expiration timestamp for this event, or -1 if no "expiration" tag exists or diff --git a/nip42/nip42.go b/nip42/nip42.go index d0448a7..8ac02f4 100644 --- a/nip42/nip42.go +++ b/nip42/nip42.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) // CreateUnsignedAuthEvent creates an event which should be sent via an "AUTH" command. diff --git a/nip44/nip44.go b/nip44/nip44.go index 253dab2..b29506b 100644 --- a/nip44/nip44.go +++ b/nip44/nip44.go @@ -12,6 +12,7 @@ import ( "io" "math" + "fiatjaf.com/nostr" "github.com/btcsuite/btcd/btcec/v2" "github.com/decred/dcrd/dcrec/secp256k1/v4" "golang.org/x/crypto/chacha20" @@ -153,10 +154,12 @@ func Decrypt(b64ciphertextWrapped string, conversationKey [32]byte) (string, err return string(unpadded), nil } -func GenerateConversationKey(pub string, sk string) ([32]byte, error) { +var maxThreshold, _ = hex.DecodeString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") + +func GenerateConversationKey(pub nostr.PubKey, sk [32]byte) ([32]byte, error) { var ck [32]byte - if sk >= "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" || sk == "0000000000000000000000000000000000000000000000000000000000000000" { + if bytes.Compare(sk[:], maxThreshold) != -1 || sk == [32]byte{} { return ck, fmt.Errorf("invalid private key: x coordinate %s is not on the secp256k1 curve", sk) } @@ -220,20 +223,13 @@ func calcPadding(sLen int) int { } // code adapted from nip04.ComputeSharedSecret() -func computeSharedSecret(pub string, sk string) (sharedSecret [32]byte, err error) { - privKeyBytes, err := hex.DecodeString(sk) - if err != nil { - return sharedSecret, fmt.Errorf("error decoding sender private key: %w", err) - } - privKey, _ := btcec.PrivKeyFromBytes(privKeyBytes) +func computeSharedSecret(pub nostr.PubKey, sk [32]byte) (sharedSecret [32]byte, err error) { + privKey, _ := btcec.PrivKeyFromBytes(sk[:]) - pubKeyBytes, err := hex.DecodeString("02" + pub) + pubKey, err := btcec.ParsePubKey(append([]byte{2}, pub[:]...)) if err != nil { - return sharedSecret, fmt.Errorf("error decoding hex string of receiver public key '%s': %w", "02"+pub, err) - } - pubKey, err := btcec.ParsePubKey(pubKeyBytes) - if err != nil { - return sharedSecret, fmt.Errorf("error parsing receiver public key '%s': %w", "02"+pub, err) + return sharedSecret, fmt.Errorf("error parsing receiver public key '%s': %w", + "02"+hex.EncodeToString(pub[:]), err) } var point, result secp256k1.JacobianPoint diff --git a/nip44/nip44_test.go b/nip44/nip44_test.go index 34abb00..4755af7 100644 --- a/nip44/nip44_test.go +++ b/nip44/nip44_test.go @@ -8,14 +8,22 @@ import ( "strings" "testing" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" "github.com/stretchr/testify/require" ) -func assertCryptPriv(t *testing.T, sk1 string, sk2 string, conversationKey string, salt string, plaintext string, expected string) { +func assertCryptPriv(t *testing.T, skh1 string, skh2 string, conversationKey string, salt string, plaintext string, expected string) { + sk1 := [32]byte{} + hex.Decode(sk1[:], []byte(skh1)) + + sk2 := [32]byte{} + hex.Decode(sk2[:], []byte(skh2)) + k1, err := hexDecode32Array(conversationKey) require.NoErrorf(t, err, "hex decode failed for conversation key: %v", err) - assertConversationKeyGenerationSec(t, sk1, sk2, conversationKey) + + pub2 := nostr.GetPublicKey(sk2) + assertConversationKeyGenerationPub(t, skh1, hex.EncodeToString(pub2[:]), conversationKey) customNonce, err := hex.DecodeString(salt) require.NoErrorf(t, err, "hex decode failed for salt: %v", err) @@ -39,7 +47,13 @@ func assertDecryptFail(t *testing.T, conversationKey string, _ string, ciphertex } func assertConversationKeyFail(t *testing.T, priv string, pub string, msg string) { - _, err := GenerateConversationKey(pub, priv) + var pub32 [32]byte + hex.Decode(pub32[:], []byte(pub)) + + var priv32 [32]byte + hex.Decode(priv32[:], []byte(priv)) + + _, err := GenerateConversationKey(pub32, priv32) require.ErrorContains(t, err, msg) } @@ -47,18 +61,18 @@ func assertConversationKeyGenerationPub(t *testing.T, priv string, pub string, c expectedConversationKey, err := hexDecode32Array(conversationKey) require.NoErrorf(t, err, "hex decode failed for conversation key: %v", err) - actualConversationKey, err := GenerateConversationKey(pub, priv) + var pub32 [32]byte + hex.Decode(pub32[:], []byte(pub)) + + var priv32 [32]byte + hex.Decode(priv32[:], []byte(priv)) + + actualConversationKey, err := GenerateConversationKey(pub32, priv32) require.NoErrorf(t, err, "conversation key generation failed: %v", err) require.Equalf(t, expectedConversationKey, actualConversationKey, "wrong conversation key") } -func assertConversationKeyGenerationSec(t *testing.T, sk1 string, sk2 string, conversationKey string) { - pub2, err := nostr.GetPublicKey(sk2) - require.NoErrorf(t, err, "failed to derive pubkey from sk2: %v", err) - assertConversationKeyGenerationPub(t, sk1, pub2, conversationKey) -} - func assertMessageKeyGeneration(t *testing.T, conversationKey string, salt string, chachaKey string, chachaSalt string, hmacKey string) bool { convKey, err := hexDecode32Array(conversationKey) require.NoErrorf(t, err, "hex decode failed for convKey: %v", err) @@ -1061,7 +1075,7 @@ func TestMessageKeyGeneration033(t *testing.T) { func TestMaxLength(t *testing.T) { sk1 := nostr.GeneratePrivateKey() sk2 := nostr.GeneratePrivateKey() - pub2, _ := nostr.GetPublicKey(sk2) + pub2 := nostr.GetPublicKey(sk2) salt := make([]byte, 32) rand.Read(salt) conversationKey, _ := GenerateConversationKey(pub2, sk1) @@ -1072,8 +1086,8 @@ func TestMaxLength(t *testing.T) { } assertCryptPub(t, - sk1, - pub2, + hex.EncodeToString(sk1[:]), + hex.EncodeToString(pub2[:]), fmt.Sprintf("%x", conversationKey), fmt.Sprintf("%x", salt), plaintext, diff --git a/nip45/hll_event.go b/nip45/hll_event.go index 26d29e8..35be1c4 100644 --- a/nip45/hll_event.go +++ b/nip45/hll_event.go @@ -4,7 +4,7 @@ import ( "iter" "strconv" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) func HyperLogLogEventPubkeyOffsetsAndReferencesForEvent(evt *nostr.Event) iter.Seq2[string, int] { diff --git a/nip45/hll_filter.go b/nip45/hll_filter.go index 9e949bc..0fab375 100644 --- a/nip45/hll_filter.go +++ b/nip45/hll_filter.go @@ -3,7 +3,7 @@ package nip45 import ( "strconv" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) // HyperLogLogEventPubkeyOffsetForFilter returns the deterministic pubkey offset that will be used diff --git a/nip46/bunker_session.go b/nip46/bunker_session.go index 15f2a28..a5e8296 100644 --- a/nip46/bunker_session.go +++ b/nip46/bunker_session.go @@ -3,15 +3,13 @@ package nip46 import ( "fmt" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip04" - "fiatjaf.com/nostrlib/nip44" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip44" ) type Session struct { - PublicKey string - SharedKey []byte // nip04 - ConversationKey [32]byte // nip44 + PublicKey nostr.PubKey + ConversationKey [32]byte } type RelayReadWrite struct { @@ -22,22 +20,18 @@ type RelayReadWrite struct { func (s Session) ParseRequest(event *nostr.Event) (Request, error) { var req Request - plain, err1 := nip44.Decrypt(event.Content, s.ConversationKey) - if err1 != nil { - var err2 error - plain, err2 = nip04.Decrypt(event.Content, s.SharedKey) - if err2 != nil { - return req, fmt.Errorf("failed to decrypt event from %s: (nip44: %w, nip04: %w)", event.PubKey, err1, err2) - } + plain, err := nip44.Decrypt(event.Content, s.ConversationKey) + if err != nil { + return req, fmt.Errorf("failed to decrypt event from %s: (nip44: %w)", event.PubKey, err) } - err := json.Unmarshal([]byte(plain), &req) + err = json.Unmarshal([]byte(plain), &req) return req, err } func (s Session) MakeResponse( id string, - requester string, + requester nostr.PubKey, result string, err error, ) (resp Response, evt nostr.Event, error error) { diff --git a/nip46/client.go b/nip46/client.go index b46ba9d..6c773c6 100644 --- a/nip46/client.go +++ b/nip46/client.go @@ -8,10 +8,10 @@ import ( "strconv" "sync/atomic" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip04" + "fiatjaf.com/nostr/nip44" "github.com/mailru/easyjson" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip04" - "fiatjaf.com/nostrlib/nip44" "github.com/puzpuzpuz/xsync/v3" ) @@ -38,7 +38,7 @@ type BunkerClient struct { // pool can be passed to reuse an existing pool, otherwise a new pool will be created. func ConnectBunker( ctx context.Context, - clientSecretKey string, + clientSecretKey nostr.PubKey, bunkerURLOrNIP05 string, pool *nostr.SimplePool, onAuth func(string), @@ -51,7 +51,7 @@ func ConnectBunker( // assume it's a bunker url (will fail later if not) secret := parsed.Query().Get("secret") relays := parsed.Query()["relay"] - targetPublicKey := parsed.Host + targetPublicKey, _ := nostr.PubKeyFromHex(parsed.Host) if parsed.Scheme == "" { // could be a NIP-05 @@ -85,8 +85,8 @@ func ConnectBunker( func NewBunker( ctx context.Context, - clientSecretKey string, - targetPublicKey string, + clientSecretKey [32]byte, + targetPublicKey nostr.PubKey, relays []string, pool *nostr.SimplePool, onAuth func(string), @@ -95,8 +95,7 @@ func NewBunker( pool = nostr.NewSimplePool(ctx) } - clientPublicKey, _ := nostr.GetPublicKey(clientSecretKey) - sharedSecret, _ := nip04.ComputeSharedSecret(targetPublicKey, clientSecretKey) + clientPublicKey := nostr.GetPublicKey(clientSecretKey) conversationKey, _ := nip44.GenerateConversationKey(targetPublicKey, clientSecretKey) bunker := &BunkerClient{ diff --git a/nip46/dynamic-signer.go b/nip46/dynamic-signer.go index f938686..6fcf40f 100644 --- a/nip46/dynamic-signer.go +++ b/nip46/dynamic-signer.go @@ -2,44 +2,41 @@ package nip46 import ( "context" + "encoding/hex" "fmt" - "slices" "sync" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip44" "github.com/mailru/easyjson" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip04" - "fiatjaf.com/nostrlib/nip44" ) var _ Signer = (*DynamicSigner)(nil) type DynamicSigner struct { - sessionKeys []string - sessions []Session + sessions map[nostr.PubKey]Session sync.Mutex - getHandlerSecretKey func(handlerPubkey string) (string, error) - getUserKeyer func(handlerPubkey string) (nostr.Keyer, error) - authorizeSigning func(event nostr.Event, from string, secret string) bool - authorizeEncryption func(from string, secret string) bool + getHandlerSecretKey func(handlerPubkey nostr.PubKey) ([32]byte, error) + getUserKeyer func(handlerPubkey nostr.PubKey) (nostr.Keyer, error) + authorizeSigning func(event nostr.Event, from nostr.PubKey, secret string) bool + authorizeEncryption func(from nostr.PubKey, secret string) bool onEventSigned func(event nostr.Event) - getRelays func(pubkey string) map[string]RelayReadWrite } func NewDynamicSigner( // the handler is the keypair we use to communicate with the NIP-46 client, decrypt requests, encrypt responses etc - getHandlerSecretKey func(handlerPubkey string) (string, error), + getHandlerSecretKey func(handlerPubkey nostr.PubKey) ([32]byte, error), // this should correspond to the actual user on behalf of which we will respond to requests - getUserKeyer func(handlerPubkey string) (nostr.Keyer, error), + getUserKeyer func(handlerPubkey nostr.PubKey) (nostr.Keyer, error), // this is called on every sign_event call, if it is nil it will be assumed that everything is authorized - authorizeSigning func(event nostr.Event, from string, secret string) bool, + authorizeSigning func(event nostr.Event, from nostr.PubKey, secret string) bool, // this is called on every encrypt or decrypt calls, if it is nil it will be assumed that everything is authorized - authorizeEncryption func(from string, secret string) bool, + authorizeEncryption func(from nostr.PubKey, secret string) bool, // unless it is nil, this is called after every event is signed onEventSigned func(event nostr.Event), @@ -53,34 +50,28 @@ func NewDynamicSigner( authorizeSigning: authorizeSigning, authorizeEncryption: authorizeEncryption, onEventSigned: onEventSigned, - getRelays: getRelays, } } -func (p *DynamicSigner) GetSession(clientPubkey string) (Session, bool) { - idx, exists := slices.BinarySearch(p.sessionKeys, clientPubkey) +func (p *DynamicSigner) GetSession(clientPubkey nostr.PubKey) (Session, bool) { + session, exists := p.sessions[clientPubkey] if exists { - return p.sessions[idx], true + return session, true } return Session{}, false } -func (p *DynamicSigner) setSession(clientPubkey string, session Session) { +func (p *DynamicSigner) setSession(clientPubkey nostr.PubKey, session Session) { p.Lock() defer p.Unlock() - idx, exists := slices.BinarySearch(p.sessionKeys, clientPubkey) + _, exists := p.sessions[clientPubkey] if exists { return } // add to pool - p.sessionKeys = append(p.sessionKeys, "") // bogus append just to increase the capacity - p.sessions = append(p.sessions, Session{}) - copy(p.sessionKeys[idx+1:], p.sessionKeys[idx:]) - copy(p.sessions[idx+1:], p.sessions[idx:]) - p.sessionKeys[idx] = clientPubkey - p.sessions[idx] = session + p.sessions[clientPubkey] = session } func (p *DynamicSigner) HandleRequest(ctx context.Context, event *nostr.Event) ( @@ -99,7 +90,10 @@ func (p *DynamicSigner) HandleRequest(ctx context.Context, event *nostr.Event) ( return req, resp, eventResponse, fmt.Errorf("invalid \"p\" tag") } - handlerPubkey := handler[1] + handlerPubkey, err := nostr.PubKeyFromHex(handler[1]) + if err != nil { + return req, resp, eventResponse, fmt.Errorf("%x is invalid pubkey: %w", handler[1], err) + } handlerSecret, err := p.getHandlerSecretKey(handlerPubkey) if err != nil { return req, resp, eventResponse, fmt.Errorf("no private key for %s: %w", handlerPubkey, err) @@ -109,18 +103,10 @@ func (p *DynamicSigner) HandleRequest(ctx context.Context, event *nostr.Event) ( return req, resp, eventResponse, fmt.Errorf("failed to get user keyer for %s: %w", handlerPubkey, err) } - var session Session - idx, exists := slices.BinarySearch(p.sessionKeys, event.PubKey) - if exists { - session = p.sessions[idx] - } else { + session, exists := p.sessions[event.PubKey] + if !exists { session = Session{} - session.SharedKey, err = nip04.ComputeSharedSecret(event.PubKey, handlerSecret) - if err != nil { - return req, resp, eventResponse, fmt.Errorf("failed to compute shared secret: %w", err) - } - session.ConversationKey, err = nip44.GenerateConversationKey(event.PubKey, handlerSecret) if err != nil { return req, resp, eventResponse, fmt.Errorf("failed to compute shared secret: %w", err) @@ -150,7 +136,7 @@ func (p *DynamicSigner) HandleRequest(ctx context.Context, event *nostr.Event) ( } result = "ack" case "get_public_key": - result = session.PublicKey + result = hex.EncodeToString(session.PublicKey[:]) case "sign_event": if len(req.Params) != 1 { resultErr = fmt.Errorf("wrong number of arguments to 'sign_event'") @@ -174,21 +160,14 @@ func (p *DynamicSigner) HandleRequest(ctx context.Context, event *nostr.Event) ( } jrevt, _ := easyjson.Marshal(evt) result = string(jrevt) - case "get_relays": - if p.getRelays == nil { - jrelays, _ := json.Marshal(p.getRelays(session.PublicKey)) - result = string(jrelays) - } else { - result = "{}" - } case "nip44_encrypt": if len(req.Params) != 2 { - resultErr = fmt.Errorf("wrong number of arguments to 'nip04_encrypt'") + resultErr = fmt.Errorf("wrong number of arguments to 'nip44_encrypt'") break } - thirdPartyPubkey := req.Params[0] - if !nostr.IsValidPublicKey(thirdPartyPubkey) { - resultErr = fmt.Errorf("first argument to 'nip04_encrypt' is not a pubkey string") + thirdPartyPubkey, err := nostr.PubKeyFromHex(req.Params[0]) + if err != nil { + resultErr = fmt.Errorf("first argument to 'nip44_encrypt' is not a valid pubkey string") break } if p.authorizeEncryption != nil && !p.authorizeEncryption(event.PubKey, secret) { @@ -208,9 +187,9 @@ func (p *DynamicSigner) HandleRequest(ctx context.Context, event *nostr.Event) ( resultErr = fmt.Errorf("wrong number of arguments to 'nip04_decrypt'") break } - thirdPartyPubkey := req.Params[0] - if !nostr.IsValidPublicKey(thirdPartyPubkey) { - resultErr = fmt.Errorf("first argument to 'nip04_decrypt' is not a pubkey string") + thirdPartyPubkey, err := nostr.PubKeyFromHex(req.Params[0]) + if err != nil { + resultErr = fmt.Errorf("first argument to 'nip04_decrypt' is not a valid pubkey string") break } if p.authorizeEncryption != nil && !p.authorizeEncryption(event.PubKey, secret) { diff --git a/nip46/nip46.go b/nip46/nip46.go index 33529fe..56b9ca7 100644 --- a/nip46/nip46.go +++ b/nip46/nip46.go @@ -5,8 +5,8 @@ import ( "net/url" "strings" + "fiatjaf.com/nostr" jsoniter "github.com/json-iterator/go" - "fiatjaf.com/nostrlib" ) var json = jsoniter.ConfigFastest @@ -34,7 +34,7 @@ func (r Response) String() string { } type Signer interface { - GetSession(clientPubkey string) (Session, bool) + GetSession(client nostr.PubKey) (Session, bool) HandleRequest(context.Context, *nostr.Event) (req Request, resp Response, eventResponse nostr.Event, err error) } @@ -46,7 +46,7 @@ func IsValidBunkerURL(input string) bool { if p.Scheme != "bunker" { return false } - if !nostr.IsValidPublicKey(p.Host) { + if _, err := nostr.PubKeyFromHex(p.Host); err != nil { return false } if !strings.Contains(p.RawQuery, "relay=") { diff --git a/nip46/static-key-signer.go b/nip46/static-key-signer.go index 70467fa..4fefbd5 100644 --- a/nip46/static-key-signer.go +++ b/nip46/static-key-signer.go @@ -2,57 +2,45 @@ package nip46 import ( "context" + "encoding/hex" "fmt" - "slices" "sync" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip04" + "fiatjaf.com/nostr/nip44" "github.com/mailru/easyjson" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip04" - "fiatjaf.com/nostrlib/nip44" ) var _ Signer = (*StaticKeySigner)(nil) type StaticKeySigner struct { - secretKey string - - sessionKeys []string - sessions []Session + secretKey [32]byte + sessions map[nostr.PubKey]Session sync.Mutex - RelaysToAdvertise map[string]RelayReadWrite - AuthorizeRequest func(harmless bool, from string, secret string) bool + AuthorizeRequest func(harmless bool, from nostr.PubKey, secret string) bool } -func NewStaticKeySigner(secretKey string) StaticKeySigner { +func NewStaticKeySigner(secretKey [32]byte) StaticKeySigner { return StaticKeySigner{ - secretKey: secretKey, - RelaysToAdvertise: make(map[string]RelayReadWrite), + secretKey: secretKey, } } -func (p *StaticKeySigner) GetSession(clientPubkey string) (Session, bool) { - idx, exists := slices.BinarySearch(p.sessionKeys, clientPubkey) - if exists { - return p.sessions[idx], true - } - return Session{}, false +func (p *StaticKeySigner) GetSession(clientPubkey nostr.PubKey) (Session, bool) { + session, ok := p.sessions[clientPubkey] + return session, ok } -func (p *StaticKeySigner) getOrCreateSession(clientPubkey string) (Session, error) { +func (p *StaticKeySigner) getOrCreateSession(clientPubkey nostr.PubKey) (Session, error) { p.Lock() defer p.Unlock() - idx, exists := slices.BinarySearch(p.sessionKeys, clientPubkey) + session, exists := p.sessions[clientPubkey] if exists { - return p.sessions[idx], nil - } - - shared, err := nip04.ComputeSharedSecret(clientPubkey, p.secretKey) - if err != nil { - return Session{}, fmt.Errorf("failed to compute shared secret: %w", err) + return session, nil } ck, err := nip44.GenerateConversationKey(clientPubkey, p.secretKey) @@ -60,24 +48,14 @@ func (p *StaticKeySigner) getOrCreateSession(clientPubkey string) (Session, erro return Session{}, fmt.Errorf("failed to compute shared secret: %w", err) } - pubkey, err := nostr.GetPublicKey(p.secretKey) - if err != nil { - return Session{}, fmt.Errorf("failed to derive public key: %w", err) - } - - session := Session{ + pubkey := nostr.GetPublicKey(p.secretKey) + session = Session{ PublicKey: pubkey, - SharedKey: shared, ConversationKey: ck, } // add to pool - p.sessionKeys = append(p.sessionKeys, "") // bogus append just to increase the capacity - p.sessions = append(p.sessions, Session{}) - copy(p.sessionKeys[idx+1:], p.sessionKeys[idx:]) - copy(p.sessions[idx+1:], p.sessions[idx:]) - p.sessionKeys[idx] = clientPubkey - p.sessions[idx] = session + p.sessions[pubkey] = session return session, nil } @@ -116,7 +94,7 @@ func (p *StaticKeySigner) HandleRequest(_ context.Context, event *nostr.Event) ( result = "ack" harmless = true case "get_public_key": - result = session.PublicKey + result = hex.EncodeToString(session.PublicKey[:]) harmless = true case "sign_event": if len(req.Params) != 1 { @@ -136,18 +114,14 @@ func (p *StaticKeySigner) HandleRequest(_ context.Context, event *nostr.Event) ( } jrevt, _ := easyjson.Marshal(evt) result = string(jrevt) - case "get_relays": - jrelays, _ := json.Marshal(p.RelaysToAdvertise) - result = string(jrelays) - harmless = true case "nip44_encrypt": if len(req.Params) != 2 { - resultErr = fmt.Errorf("wrong number of arguments to 'nip04_encrypt'") + resultErr = fmt.Errorf("wrong number of arguments to 'nip44_encrypt'") break } - thirdPartyPubkey := req.Params[0] - if !nostr.IsValidPublicKey(thirdPartyPubkey) { - resultErr = fmt.Errorf("first argument to 'nip04_encrypt' is not a pubkey string") + thirdPartyPubkey, err := nostr.PubKeyFromHex(req.Params[0]) + if err != nil { + resultErr = fmt.Errorf("first argument to 'nip04_encrypt' is not a valid pubkey string") break } plaintext := req.Params[1] @@ -168,9 +142,9 @@ func (p *StaticKeySigner) HandleRequest(_ context.Context, event *nostr.Event) ( resultErr = fmt.Errorf("wrong number of arguments to 'nip04_decrypt'") break } - thirdPartyPubkey := req.Params[0] - if !nostr.IsValidPublicKey(thirdPartyPubkey) { - resultErr = fmt.Errorf("first argument to 'nip04_decrypt' is not a pubkey string") + thirdPartyPubkey, err := nostr.PubKeyFromHex(req.Params[0]) + if err != nil { + resultErr = fmt.Errorf("first argument to 'nip04_decrypt' is not a valid pubkey string") break } ciphertext := req.Params[1] @@ -191,9 +165,9 @@ func (p *StaticKeySigner) HandleRequest(_ context.Context, event *nostr.Event) ( resultErr = fmt.Errorf("wrong number of arguments to 'nip04_encrypt'") break } - thirdPartyPubkey := req.Params[0] - if !nostr.IsValidPublicKey(thirdPartyPubkey) { - resultErr = fmt.Errorf("first argument to 'nip04_encrypt' is not a pubkey string") + thirdPartyPubkey, err := nostr.PubKeyFromHex(req.Params[0]) + if err != nil { + resultErr = fmt.Errorf("first argument to 'nip04_encrypt' is not a valid pubkey string") break } plaintext := req.Params[1] @@ -214,9 +188,9 @@ func (p *StaticKeySigner) HandleRequest(_ context.Context, event *nostr.Event) ( resultErr = fmt.Errorf("wrong number of arguments to 'nip04_decrypt'") break } - thirdPartyPubkey := req.Params[0] - if !nostr.IsValidPublicKey(thirdPartyPubkey) { - resultErr = fmt.Errorf("first argument to 'nip04_decrypt' is not a pubkey string") + thirdPartyPubkey, err := nostr.PubKeyFromHex(req.Params[0]) + if err != nil { + resultErr = fmt.Errorf("first argument to 'nip04_decrypt' is not a valid pubkey string") break } ciphertext := req.Params[1] diff --git a/nip46/wellknownnostrjson.go b/nip46/wellknownnostrjson.go index 4008b9c..2249aba 100644 --- a/nip46/wellknownnostrjson.go +++ b/nip46/wellknownnostrjson.go @@ -4,22 +4,23 @@ import ( "context" "fmt" - "fiatjaf.com/nostrlib/nip05" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip05" ) -func queryWellKnownNostrJson(ctx context.Context, fullname string) (pubkey string, relays []string, err error) { +func queryWellKnownNostrJson(ctx context.Context, fullname string) (pubkey nostr.PubKey, relays []string, err error) { result, name, err := nip05.Fetch(ctx, fullname) if err != nil { - return "", nil, err + return nostr.ZeroPK, nil, err } - pubkey, ok := result.Names[name] + pubkeyh, ok := result.Names[name] if !ok { - return "", nil, fmt.Errorf("no entry found for the '%s' name", name) + return nostr.ZeroPK, nil, fmt.Errorf("no entry found for the '%s' name", name) } - relays, _ = result.NIP46[pubkey] + relays, _ = result.NIP46[pubkeyh] if !ok { - return "", nil, fmt.Errorf("no bunker relays found for the '%s' name", name) + return nostr.ZeroPK, nil, fmt.Errorf("no bunker relays found for the '%s' name", name) } return pubkey, relays, nil diff --git a/nip52/calendar_event.go b/nip52/calendar_event.go index dddf547..71c95ae 100644 --- a/nip52/calendar_event.go +++ b/nip52/calendar_event.go @@ -4,7 +4,7 @@ import ( "strconv" "time" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type CalendarEventKind int diff --git a/nip53/nip53.go b/nip53/nip53.go index 42ba6c3..e90ee66 100644 --- a/nip53/nip53.go +++ b/nip53/nip53.go @@ -4,7 +4,7 @@ import ( "strconv" "time" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type LiveEvent struct { diff --git a/nip59/nip59.go b/nip59/nip59.go index 724c01b..0e151bb 100644 --- a/nip59/nip59.go +++ b/nip59/nip59.go @@ -5,8 +5,8 @@ import ( "math/rand" "github.com/mailru/easyjson" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip44" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip44" ) // GiftWrap takes a 'rumor', encrypts it with our own key, making a 'seal', then encrypts that with a nonce key and diff --git a/nip60/history.go b/nip60/history.go index b4fa013..05c9208 100644 --- a/nip60/history.go +++ b/nip60/history.go @@ -6,7 +6,7 @@ import ( "fmt" "strconv" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type HistoryEntry struct { diff --git a/nip60/lightning-swap.go b/nip60/lightning-swap.go index 4023b2d..5528d55 100644 --- a/nip60/lightning-swap.go +++ b/nip60/lightning-swap.go @@ -9,7 +9,7 @@ import ( "github.com/elnosh/gonuts/cashu/nuts/nut02" "github.com/elnosh/gonuts/cashu/nuts/nut04" "github.com/elnosh/gonuts/cashu/nuts/nut05" - "fiatjaf.com/nostrlib/nip60/client" + "fiatjaf.com/nostr/nip60/client" ) type lightningSwapStatus int diff --git a/nip60/pay.go b/nip60/pay.go index b6bfd76..14ba272 100644 --- a/nip60/pay.go +++ b/nip60/pay.go @@ -7,8 +7,8 @@ import ( "github.com/elnosh/gonuts/cashu" "github.com/elnosh/gonuts/cashu/nuts/nut05" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip60/client" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip60/client" ) func (w *Wallet) PayBolt11(ctx context.Context, invoice string, opts ...SendOption) (string, error) { diff --git a/nip60/receive.go b/nip60/receive.go index 79e5c77..f9c888c 100644 --- a/nip60/receive.go +++ b/nip60/receive.go @@ -7,8 +7,8 @@ import ( "github.com/elnosh/gonuts/cashu" "github.com/elnosh/gonuts/cashu/nuts/nut10" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip60/client" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip60/client" ) type receiveSettings struct { diff --git a/nip60/send-external.go b/nip60/send-external.go index 1dbb6ea..9d24a01 100644 --- a/nip60/send-external.go +++ b/nip60/send-external.go @@ -6,7 +6,7 @@ import ( "github.com/elnosh/gonuts/cashu" "github.com/elnosh/gonuts/cashu/nuts/nut04" - "fiatjaf.com/nostrlib/nip60/client" + "fiatjaf.com/nostr/nip60/client" ) func (w *Wallet) SendExternal( diff --git a/nip60/send.go b/nip60/send.go index b18220e..707b3d9 100644 --- a/nip60/send.go +++ b/nip60/send.go @@ -11,8 +11,8 @@ import ( "github.com/elnosh/gonuts/cashu/nuts/nut02" "github.com/elnosh/gonuts/cashu/nuts/nut10" "github.com/elnosh/gonuts/cashu/nuts/nut11" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip60/client" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip60/client" ) type SendOption func(opts *sendSettings) diff --git a/nip60/swap.go b/nip60/swap.go index 0842547..ded3809 100644 --- a/nip60/swap.go +++ b/nip60/swap.go @@ -10,7 +10,7 @@ import ( "github.com/elnosh/gonuts/cashu/nuts/nut02" "github.com/elnosh/gonuts/cashu/nuts/nut03" "github.com/elnosh/gonuts/cashu/nuts/nut10" - "fiatjaf.com/nostrlib/nip60/client" + "fiatjaf.com/nostr/nip60/client" ) type swapSettings struct { diff --git a/nip60/token.go b/nip60/token.go index 7580a4e..b0cc1f1 100644 --- a/nip60/token.go +++ b/nip60/token.go @@ -6,7 +6,7 @@ import ( "fmt" "github.com/elnosh/gonuts/cashu" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type Token struct { diff --git a/nip60/wallet.go b/nip60/wallet.go index fb55335..391fd4c 100644 --- a/nip60/wallet.go +++ b/nip60/wallet.go @@ -11,7 +11,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/decred/dcrd/dcrec/secp256k1/v4" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type Wallet struct { diff --git a/nip60/wallet_test.go b/nip60/wallet_test.go index b1873cd..cefb27e 100644 --- a/nip60/wallet_test.go +++ b/nip60/wallet_test.go @@ -10,8 +10,8 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/elnosh/gonuts/cashu" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/keyer" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/keyer" "github.com/stretchr/testify/require" "golang.org/x/exp/rand" ) diff --git a/nip61/info.go b/nip61/info.go index d719f5a..2ea3717 100644 --- a/nip61/info.go +++ b/nip61/info.go @@ -5,7 +5,7 @@ import ( "slices" "github.com/elnosh/gonuts/cashu" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type Info struct { diff --git a/nip61/nip61.go b/nip61/nip61.go index fef1087..330a473 100644 --- a/nip61/nip61.go +++ b/nip61/nip61.go @@ -9,8 +9,8 @@ import ( "slices" "strings" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip60" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip60" ) var NutzapsNotAccepted = errors.New("user doesn't accept nutzaps") diff --git a/nip61/verify.go b/nip61/verify.go index c3d0879..3f8f611 100644 --- a/nip61/verify.go +++ b/nip61/verify.go @@ -4,11 +4,11 @@ import ( "encoding/hex" "encoding/json" + "fiatjaf.com/nostr" "github.com/btcsuite/btcd/btcec/v2" "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/elnosh/gonuts/cashu" "github.com/elnosh/gonuts/crypto" - "github.com/nbd-wtf/go-nostr" ) func VerifyNutzap( diff --git a/nip70/nip70.go b/nip70/nip70.go index 907d965..6104bb0 100644 --- a/nip70/nip70.go +++ b/nip70/nip70.go @@ -3,7 +3,7 @@ package nip70 import ( "strings" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) func IsProtected(event nostr.Event) bool { diff --git a/nip77/envelopes.go b/nip77/envelopes.go index b77902c..0ee29b1 100644 --- a/nip77/envelopes.go +++ b/nip77/envelopes.go @@ -8,7 +8,7 @@ import ( "github.com/mailru/easyjson" jwriter "github.com/mailru/easyjson/jwriter" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" "github.com/tidwall/gjson" ) diff --git a/nip77/example/example.go b/nip77/example/example.go index e5b60c2..5753738 100644 --- a/nip77/example/example.go +++ b/nip77/example/example.go @@ -7,8 +7,8 @@ import ( "github.com/fiatjaf/eventstore" "github.com/fiatjaf/eventstore/slicestore" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip77" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip77" ) func main() { diff --git a/nip77/idlistpool.go b/nip77/idlistpool.go deleted file mode 100644 index 6f3948c..0000000 --- a/nip77/idlistpool.go +++ /dev/null @@ -1,41 +0,0 @@ -package nip77 - -import ( - "sync" -) - -type idlistpool struct { - initialsize int - pool [][]string - sync.Mutex -} - -func newidlistpool(initialsize int) *idlistpool { - ilp := idlistpool{ - initialsize: initialsize, - pool: make([][]string, 1, 2), - } - - ilp.pool[0] = make([]string, 0, initialsize) - - return &ilp -} - -func (ilp *idlistpool) grab() []string { - ilp.Lock() - defer ilp.Unlock() - - l := len(ilp.pool) - if l > 0 { - idlist := ilp.pool[l-1] - ilp.pool = ilp.pool[0 : l-1] - return idlist - } - idlist := make([]string, 0, ilp.initialsize) - return idlist -} - -func (ilp *idlistpool) giveback(idlist []string) { - idlist = idlist[:0] - ilp.pool = append(ilp.pool, idlist) -} diff --git a/nip77/idsonly.go b/nip77/idsonly.go index 0bd7781..98ad058 100644 --- a/nip77/idsonly.go +++ b/nip77/idsonly.go @@ -4,16 +4,16 @@ import ( "context" "fmt" - "github.com/nbd-wtf/go-nostr" - "github.com/nbd-wtf/go-nostr/nip77/negentropy" - "github.com/nbd-wtf/go-nostr/nip77/negentropy/storage/empty" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip77/negentropy" + "fiatjaf.com/nostr/nip77/negentropy/storage/empty" ) func FetchIDsOnly( ctx context.Context, url string, filter nostr.Filter, -) (<-chan string, error) { +) (<-chan nostr.ID, error) { id := "go-nostr-tmp" // for now we can't have more than one subscription in the same connection neg := negentropy.New(empty.Empty{}, 1024*1024) @@ -56,7 +56,7 @@ func FetchIDsOnly( return nil, fmt.Errorf("failed to write to relay: %w", err) } - ch := make(chan string) + ch := make(chan nostr.ID) go func() { for id := range neg.HaveNots { ch <- id diff --git a/nip77/negentropy/encoding.go b/nip77/negentropy/encoding.go index b77df13..f765aff 100644 --- a/nip77/negentropy/encoding.go +++ b/nip77/negentropy/encoding.go @@ -3,7 +3,7 @@ package negentropy import ( "fmt" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) func (n *Negentropy) readTimestamp(reader *StringHexReader) (nostr.Timestamp, error) { @@ -42,12 +42,12 @@ func (n *Negentropy) readBound(reader *StringHexReader) (Bound, error) { return Bound{}, fmt.Errorf("failed to decode bound length: %w", err) } - id, err := reader.ReadString(length * 2) - if err != nil { + pfb := make([]byte, length) + if err := reader.ReadHexBytes(pfb); err != nil { return Bound{}, fmt.Errorf("failed to read bound id: %w", err) } - return Bound{Item{timestamp, id}}, nil + return Bound{timestamp, pfb}, nil } func (n *Negentropy) writeTimestamp(w *StringHexWriter, timestamp nostr.Timestamp) { @@ -71,26 +71,25 @@ func (n *Negentropy) writeTimestamp(w *StringHexWriter, timestamp nostr.Timestam func (n *Negentropy) writeBound(w *StringHexWriter, bound Bound) { n.writeTimestamp(w, bound.Timestamp) - writeVarInt(w, len(bound.ID)/2) - w.WriteHex(bound.Item.ID) + writeVarInt(w, len(bound.IDPrefix)) + w.WriteBytes(bound.IDPrefix) } func getMinimalBound(prev, curr Item) Bound { if curr.Timestamp != prev.Timestamp { - return Bound{Item{curr.Timestamp, ""}} + return Bound{curr.Timestamp, nil} } sharedPrefixBytes := 0 - - for i := 0; i < 32; i += 2 { - if curr.ID[i:i+2] != prev.ID[i:i+2] { + for i := 0; i < 31; i++ { + if curr.ID[i] != prev.ID[i] { break } sharedPrefixBytes++ } // sharedPrefixBytes + 1 to include the first differing byte, or the entire ID if identical. - return Bound{Item{curr.Timestamp, curr.ID[:(sharedPrefixBytes+1)*2]}} + return Bound{curr.Timestamp, curr.ID[:(sharedPrefixBytes + 1)]} } func readVarInt(reader *StringHexReader) (int, error) { diff --git a/nip77/negentropy/fuzz_test.go b/nip77/negentropy/fuzz_test.go index d266340..094eb85 100644 --- a/nip77/negentropy/fuzz_test.go +++ b/nip77/negentropy/fuzz_test.go @@ -9,9 +9,9 @@ import ( "sync" "testing" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip77/negentropy" - "fiatjaf.com/nostrlib/nip77/negentropy/storage/vector" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip77/negentropy" + "fiatjaf.com/nostr/nip77/negentropy/storage/vector" "github.com/stretchr/testify/require" ) diff --git a/nip77/negentropy/negentropy.go b/nip77/negentropy/negentropy.go index 2dac388..6ad7e4c 100644 --- a/nip77/negentropy/negentropy.go +++ b/nip77/negentropy/negentropy.go @@ -1,12 +1,13 @@ package negentropy import ( + "encoding/hex" "fmt" "math" "strings" "unsafe" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) const ( @@ -15,7 +16,7 @@ const ( buckets = 16 ) -var InfiniteBound = Bound{Item: Item{Timestamp: maxTimestamp}} +var InfiniteBound = Bound{Timestamp: maxTimestamp} type Negentropy struct { storage Storage @@ -25,8 +26,8 @@ type Negentropy struct { lastTimestampIn nostr.Timestamp lastTimestampOut nostr.Timestamp - Haves chan string - HaveNots chan string + Haves chan nostr.ID + HaveNots chan nostr.ID } func New(storage Storage, frameSizeLimit int) *Negentropy { @@ -39,8 +40,8 @@ func New(storage Storage, frameSizeLimit int) *Negentropy { return &Negentropy{ storage: storage, frameSizeLimit: frameSizeLimit, - Haves: make(chan string, buckets*4), - HaveNots: make(chan string, buckets*4), + Haves: make(chan nostr.ID, buckets*4), + HaveNots: make(chan nostr.ID, buckets*4), } } @@ -158,9 +159,10 @@ func (n *Negentropy) reconcileAux(reader *StringHexReader) (string, error) { } // what they have - theirItems := make(map[string]struct{}, numIds) + theirItems := make(map[nostr.ID]struct{}, numIds) for i := 0; i < numIds; i++ { - if id, err := reader.ReadString(64); err != nil { + var id [32]byte + if err := reader.ReadHexBytes(id[:]); err != nil { return "", fmt.Errorf("failed to read id (#%d/%d) in list: %w", i, numIds, err) } else { theirItems[id] = struct{}{} @@ -203,11 +205,11 @@ func (n *Negentropy) reconcileAux(reader *StringHexReader) (string, error) { for index, item := range n.storage.Range(lower, upper) { if n.frameSizeLimit-200 < fullOutput.Len()/2+responseIds.Len()/2 { - endBound = Bound{item} + endBound = Bound{item.Timestamp, item.ID[:]} upper = index break } - responseIds.WriteString(item.ID) + responseIds.WriteString(hex.EncodeToString(item.ID[:])) responses++ } @@ -254,7 +256,7 @@ func (n *Negentropy) SplitRange(lower, upper int, upperBound Bound, output *Stri writeVarInt(output, numElems) for _, item := range n.storage.Range(lower, upper) { - output.WriteHex(item.ID) + output.WriteBytes(item.ID[:]) } } else { itemsPerBucket := numElems / buckets diff --git a/nip77/negentropy/storage/accumulator.go b/nip77/negentropy/storage/accumulator.go index 5c4699a..168bea1 100644 --- a/nip77/negentropy/storage/accumulator.go +++ b/nip77/negentropy/storage/accumulator.go @@ -5,7 +5,7 @@ import ( "encoding/binary" "encoding/hex" - "fiatjaf.com/nostrlib/nip77/negentropy" + "fiatjaf.com/nostr/nip77/negentropy" ) type Accumulator struct { diff --git a/nip77/negentropy/storage/empty/empty.go b/nip77/negentropy/storage/empty/empty.go index 4d651c7..8406f2c 100644 --- a/nip77/negentropy/storage/empty/empty.go +++ b/nip77/negentropy/storage/empty/empty.go @@ -3,8 +3,8 @@ package empty import ( "iter" - "github.com/nbd-wtf/go-nostr/nip77/negentropy" - "github.com/nbd-wtf/go-nostr/nip77/negentropy/storage" + "fiatjaf.com/nostr/nip77/negentropy" + "fiatjaf.com/nostr/nip77/negentropy/storage" ) var acc storage.Accumulator diff --git a/nip77/negentropy/storage/vector/vector.go b/nip77/negentropy/storage/vector/vector.go index 4f9b3b1..097dd29 100644 --- a/nip77/negentropy/storage/vector/vector.go +++ b/nip77/negentropy/storage/vector/vector.go @@ -1,7 +1,6 @@ package vector import ( - "encoding/hex" "fmt" "iter" "slices" @@ -24,7 +23,7 @@ func New() *Vector { } } -func (v *Vector) Insert(createdAt nostr.Timestamp, id string) { +func (v *Vector) Insert(createdAt nostr.Timestamp, id nostr.ID) { if len(id) != 64 { panic(fmt.Errorf("bad id size for added item: expected %d bytes, got %d", 32, len(id)/2)) } @@ -68,10 +67,8 @@ func (v *Vector) FindLowerBound(begin, end int, bound negentropy.Bound) int { func (v *Vector) Fingerprint(begin, end int) string { v.acc.Reset() - tmp := make([]byte, 32) for _, item := range v.Range(begin, end) { - hex.Decode(tmp, []byte(item.ID)) - v.acc.AddBytes(tmp) + v.acc.AddBytes(item.ID[:]) } return v.acc.GetFingerprint(end - begin) diff --git a/nip77/negentropy/types.go b/nip77/negentropy/types.go index 4088206..01018ea 100644 --- a/nip77/negentropy/types.go +++ b/nip77/negentropy/types.go @@ -1,11 +1,11 @@ package negentropy import ( + "bytes" "cmp" "fmt" - "strings" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) const FingerprintSize = 16 @@ -33,23 +33,26 @@ func (v Mode) String() string { type Item struct { Timestamp nostr.Timestamp - ID string + ID nostr.ID } func ItemCompare(a, b Item) int { if a.Timestamp == b.Timestamp { - return strings.Compare(a.ID, b.ID) + return bytes.Compare(a.ID[:], b.ID[:]) } return cmp.Compare(a.Timestamp, b.Timestamp) } -func (i Item) String() string { return fmt.Sprintf("Item<%d:%s>", i.Timestamp, i.ID) } +func (i Item) String() string { return fmt.Sprintf("Item<%d:%x>", i.Timestamp, i.ID[:]) } -type Bound struct{ Item } +type Bound struct { + Timestamp nostr.Timestamp + IDPrefix []byte +} func (b Bound) String() string { if b.Timestamp == InfiniteBound.Timestamp { return "Bound" } - return fmt.Sprintf("Bound<%d:%s>", b.Timestamp, b.ID) + return fmt.Sprintf("Bound<%d:%x>", b.Timestamp, b.IDPrefix) } diff --git a/nip77/negentropy/whatever_test.go b/nip77/negentropy/whatever_test.go index 551593f..c3750ea 100644 --- a/nip77/negentropy/whatever_test.go +++ b/nip77/negentropy/whatever_test.go @@ -6,9 +6,9 @@ import ( "sync" "testing" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip77/negentropy" - "fiatjaf.com/nostrlib/nip77/negentropy/storage/vector" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip77/negentropy" + "fiatjaf.com/nostr/nip77/negentropy/storage/vector" "github.com/stretchr/testify/require" ) diff --git a/nip77/nip77.go b/nip77/nip77.go index 40d5e11..06d888f 100644 --- a/nip77/nip77.go +++ b/nip77/nip77.go @@ -5,14 +5,14 @@ import ( "fmt" "sync" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip77/negentropy" - "fiatjaf.com/nostrlib/nip77/negentropy/storage/vector" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip77/negentropy" + "fiatjaf.com/nostr/nip77/negentropy/storage/vector" ) type direction struct { label string - items chan string + items chan nostr.ID source nostr.RelayStore target nostr.RelayStore } @@ -91,7 +91,9 @@ func NegentropySync( }() wg := sync.WaitGroup{} - pool := newidlistpool(50) + pool := sync.Pool{ + New: func() any { return make([]nostr.ID, 0, 50) }, + } // Define sync directions directions := [][]direction{ @@ -105,11 +107,11 @@ func NegentropySync( go func(dir direction) { defer wg.Done() - seen := make(map[string]struct{}) + seen := make(map[nostr.ID]struct{}) - doSync := func(ids []string) { + doSync := func(ids []nostr.ID) { defer wg.Done() - defer pool.giveback(ids) + defer pool.Put(ids) if len(ids) == 0 { return @@ -124,7 +126,7 @@ func NegentropySync( } } - ids := pool.grab() + ids := pool.Get().([]nostr.ID) for item := range dir.items { if _, ok := seen[item]; ok { continue @@ -135,7 +137,7 @@ func NegentropySync( if len(ids) == 50 { wg.Add(1) go doSync(ids) - ids = pool.grab() + ids = pool.Get().([]nostr.ID) } } wg.Add(1) diff --git a/nip86/methods.go b/nip86/methods.go index 3e9cfc9..64d1759 100644 --- a/nip86/methods.go +++ b/nip86/methods.go @@ -5,7 +5,7 @@ import ( "math" "net" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) func DecodeRequest(req Request) (MethodParams, error) { diff --git a/nip92/imeta.go b/nip92/imeta.go index ef79d70..4064185 100644 --- a/nip92/imeta.go +++ b/nip92/imeta.go @@ -4,7 +4,7 @@ import ( "strconv" "strings" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) type IMeta []IMetaEntry diff --git a/nip92/imeta_test.go b/nip92/imeta_test.go index 31660cd..1a91297 100644 --- a/nip92/imeta_test.go +++ b/nip92/imeta_test.go @@ -3,7 +3,7 @@ package nip92 import ( "testing" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" "github.com/stretchr/testify/require" ) diff --git a/nip94/nip94.go b/nip94/nip94.go index 53b25d6..fe931f6 100644 --- a/nip94/nip94.go +++ b/nip94/nip94.go @@ -3,7 +3,7 @@ package nip94 import ( "strings" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) func ParseFileMetadata(event nostr.Event) FileMetadata { diff --git a/nip96/nip96.go b/nip96/nip96.go index 5d7bd96..73162c7 100644 --- a/nip96/nip96.go +++ b/nip96/nip96.go @@ -14,7 +14,7 @@ import ( "strconv" jsoniter "github.com/json-iterator/go" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) // Upload uploads a file to the provided req.Host. diff --git a/nip96/nip96_test.go b/nip96/nip96_test.go index bf78f7c..ca87c33 100644 --- a/nip96/nip96_test.go +++ b/nip96/nip96_test.go @@ -7,7 +7,7 @@ import ( "os" "testing" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/nip96/types.go b/nip96/types.go index 2a961ac..11d86d4 100644 --- a/nip96/types.go +++ b/nip96/types.go @@ -5,7 +5,7 @@ import ( "io" "net/http" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) // UploadRequest is a NIP96 upload request. diff --git a/nipb0/blossom/check.go b/nipb0/blossom/check.go index 8000d0a..f0b14a3 100644 --- a/nipb0/blossom/check.go +++ b/nipb0/blossom/check.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) // Check checks if a file exists on the media server by its hash diff --git a/nipb0/blossom/client.go b/nipb0/blossom/client.go index 466fd44..201945d 100644 --- a/nipb0/blossom/client.go +++ b/nipb0/blossom/client.go @@ -4,7 +4,7 @@ import ( "strings" "time" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" "github.com/valyala/fasthttp" ) diff --git a/nipb0/blossom/delete.go b/nipb0/blossom/delete.go index 4a6d3fd..ec6e904 100644 --- a/nipb0/blossom/delete.go +++ b/nipb0/blossom/delete.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) // Delete deletes a file from the media server by its hash diff --git a/nipb0/blossom/download.go b/nipb0/blossom/download.go index a4f62e4..e74a507 100644 --- a/nipb0/blossom/download.go +++ b/nipb0/blossom/download.go @@ -7,7 +7,7 @@ import ( "net/http" "os" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) // Download downloads a file from the media server by its hash diff --git a/nipb0/blossom/http.go b/nipb0/blossom/http.go index 89d0e48..c31e5ee 100644 --- a/nipb0/blossom/http.go +++ b/nipb0/blossom/http.go @@ -8,7 +8,7 @@ import ( "io" "strconv" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" "github.com/valyala/fasthttp" ) diff --git a/nipb0/blossom/list.go b/nipb0/blossom/list.go index 83f36df..a379916 100644 --- a/nipb0/blossom/list.go +++ b/nipb0/blossom/list.go @@ -2,9 +2,10 @@ package blossom import ( "context" + "encoding/hex" "fmt" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) // List retrieves a list of blobs from a specific pubkey @@ -15,7 +16,7 @@ func (c *Client) List(ctx context.Context) ([]BlobDescriptor, error) { } bds := make([]BlobDescriptor, 0, 100) - err = c.httpCall(ctx, "GET", "list/"+pubkey, "", func() string { + err = c.httpCall(ctx, "GET", "list/"+hex.EncodeToString(pubkey[:]), "", func() string { return c.authorizationHeader(ctx, func(evt *nostr.Event) { evt.Tags = append(evt.Tags, nostr.Tag{"t", "list"}) }) diff --git a/nipb0/blossom/types.go b/nipb0/blossom/types.go index 7e3ae66..fb17d08 100644 --- a/nipb0/blossom/types.go +++ b/nipb0/blossom/types.go @@ -3,7 +3,7 @@ package blossom import ( "encoding/json" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) // BlobDescriptor represents metadata about a blob stored on a media server diff --git a/nipb0/blossom/upload.go b/nipb0/blossom/upload.go index 6d5907a..3e32cab 100644 --- a/nipb0/blossom/upload.go +++ b/nipb0/blossom/upload.go @@ -10,7 +10,7 @@ import ( "os" "path/filepath" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) // UploadFile uploads a file to the media server diff --git a/sdk/hints/keys.go b/sdk/hints/keys.go index e12a17f..ebb9257 100644 --- a/sdk/hints/keys.go +++ b/sdk/hints/keys.go @@ -1,6 +1,6 @@ package hints -import "fiatjaf.com/nostrlib" +import "fiatjaf.com/nostr" const END_OF_WORLD nostr.Timestamp = 2208999600 // 2040-01-01 diff --git a/sdk/hints/lmdbh/db.go b/sdk/hints/lmdbh/db.go index 15fcaa9..a47b875 100644 --- a/sdk/hints/lmdbh/db.go +++ b/sdk/hints/lmdbh/db.go @@ -2,15 +2,14 @@ package lmdbh import ( "bytes" - "encoding/hex" "fmt" "math" "os" "slices" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/sdk/hints" "github.com/PowerDNS/lmdb-go/lmdb" - "github.com/nbd-wtf/go-nostr" - "github.com/nbd-wtf/go-nostr/sdk/hints" ) var _ hints.HintsDB = (*LMDBHints)(nil) @@ -63,7 +62,7 @@ func (lh *LMDBHints) Close() { lh.env.Close() } -func (lh *LMDBHints) Save(pubkey string, relay string, hintkey hints.HintKey, ts nostr.Timestamp) { +func (lh *LMDBHints) Save(pubkey nostr.PubKey, relay string, hintkey hints.HintKey, ts nostr.Timestamp) { if now := nostr.Now(); ts > now { ts = now } @@ -91,7 +90,7 @@ func (lh *LMDBHints) Save(pubkey string, relay string, hintkey hints.HintKey, ts } } -func (lh *LMDBHints) TopN(pubkey string, n int) []string { +func (lh *LMDBHints) TopN(pubkey nostr.PubKey, n int) []string { type relayScore struct { relay string score int64 @@ -107,11 +106,10 @@ func (lh *LMDBHints) TopN(pubkey string, n int) []string { } defer cursor.Close() - prefix, _ := hex.DecodeString(pubkey) - k, v, err := cursor.Get(prefix, nil, lmdb.SetRange) + k, v, err := cursor.Get(pubkey[:], nil, lmdb.SetRange) for ; err == nil; k, v, err = cursor.Get(nil, nil, lmdb.Next) { // check if we're still in the prefix range - if len(k) < 32 || !bytes.Equal(k[:32], prefix) { + if len(k) < 32 || !bytes.Equal(k[:32], pubkey[:]) { break } @@ -182,7 +180,7 @@ func (lh *LMDBHints) PrintScores() { } } -func (lh *LMDBHints) GetDetailedScores(pubkey string, n int) []hints.RelayScores { +func (lh *LMDBHints) GetDetailedScores(pubkey nostr.PubKey, n int) []hints.RelayScores { type relayScore struct { relay string tss timestamps @@ -199,11 +197,10 @@ func (lh *LMDBHints) GetDetailedScores(pubkey string, n int) []hints.RelayScores } defer cursor.Close() - prefix, _ := hex.DecodeString(pubkey) - k, v, err := cursor.Get(prefix, nil, lmdb.SetRange) + k, v, err := cursor.Get(pubkey[:], nil, lmdb.SetRange) for ; err == nil; k, v, err = cursor.Get(nil, nil, lmdb.Next) { // check if we're still in the prefix range - if len(k) < 32 || !bytes.Equal(k[:32], prefix) { + if len(k) < 32 || !bytes.Equal(k[:32], pubkey[:]) { break } diff --git a/sdk/hints/lmdbh/keys.go b/sdk/hints/lmdbh/keys.go index 2ff5c1c..34c4854 100644 --- a/sdk/hints/lmdbh/keys.go +++ b/sdk/hints/lmdbh/keys.go @@ -4,12 +4,12 @@ import ( "encoding/binary" "encoding/hex" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" ) -func encodeKey(pubhintkey, relay string) []byte { +func encodeKey(pubhintkey nostr.PubKey, relay string) []byte { k := make([]byte, 32+len(relay)) - hex.Decode(k[0:32], []byte(pubhintkey)) + copy(k[0:32], pubhintkey[:]) copy(k[32:], relay) return k } diff --git a/sdk/hints/memoryh/db.go b/sdk/hints/memoryh/db.go index 6e31dfe..cb73576 100644 --- a/sdk/hints/memoryh/db.go +++ b/sdk/hints/memoryh/db.go @@ -6,15 +6,15 @@ import ( "slices" "sync" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/sdk/hints" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/sdk/hints" ) var _ hints.HintsDB = (*HintDB)(nil) type HintDB struct { RelayBySerial []string - OrderedRelaysByPubKey map[string][]RelayEntry + OrderedRelaysByPubKey map[nostr.PubKey][]RelayEntry sync.Mutex } @@ -22,11 +22,11 @@ type HintDB struct { func NewHintDB() *HintDB { return &HintDB{ RelayBySerial: make([]string, 0, 100), - OrderedRelaysByPubKey: make(map[string][]RelayEntry, 100), + OrderedRelaysByPubKey: make(map[nostr.PubKey][]RelayEntry, 100), } } -func (db *HintDB) Save(pubkey string, relay string, key hints.HintKey, ts nostr.Timestamp) { +func (db *HintDB) Save(pubkey nostr.PubKey, relay string, key hints.HintKey, ts nostr.Timestamp) { if now := nostr.Now(); ts > now { ts = now } @@ -67,7 +67,7 @@ func (db *HintDB) Save(pubkey string, relay string, key hints.HintKey, ts nostr. db.OrderedRelaysByPubKey[pubkey] = entries } -func (db *HintDB) TopN(pubkey string, n int) []string { +func (db *HintDB) TopN(pubkey nostr.PubKey, n int) []string { db.Lock() defer db.Unlock() @@ -104,7 +104,7 @@ func (db *HintDB) PrintScores() { } } -func (db *HintDB) GetDetailedScores(pubkey string, n int) []hints.RelayScores { +func (db *HintDB) GetDetailedScores(pubkey nostr.PubKey, n int) []hints.RelayScores { db.Lock() defer db.Unlock() diff --git a/sdk/hints/sqlh/db.go b/sdk/hints/sqlh/db.go deleted file mode 100644 index b510fb2..0000000 --- a/sdk/hints/sqlh/db.go +++ /dev/null @@ -1,272 +0,0 @@ -package sqlh - -import ( - "database/sql" - "fmt" - "strconv" - "strings" - - "github.com/jmoiron/sqlx" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/sdk/hints" -) - -type SQLHints struct { - *sqlx.DB - - interop interop - saves [7]*sqlx.Stmt - topN *sqlx.Stmt -} - -// NewSQLHints takes an sqlx.DB connection (db) and a database type name (driverName ). -// driverName must be either "postgres" or "sqlite3" -- this is so we can slightly change the queries. -func NewSQLHints(db *sql.DB, driverName string) (SQLHints, error) { - sh := SQLHints{DB: sqlx.NewDb(db, driverName)} - - switch driverName { - case "sqlite3": - sh.interop = sqliteInterop - case "postgres": - sh.interop = postgresInterop - default: - return sh, fmt.Errorf("unknown database driver '%s'", driverName) - } - - // db migrations - if txn, err := sh.Beginx(); err != nil { - return SQLHints{}, err - } else { - if _, err := txn.Exec(`CREATE TABLE IF NOT EXISTS nostr_sdk_db_version (version int)`); err != nil { - txn.Rollback() - return SQLHints{}, err - } - var version int - if err := txn.Get(&version, `SELECT version FROM nostr_sdk_db_version`); err != nil && err != sql.ErrNoRows { - txn.Rollback() - return SQLHints{}, err - } - - if version == 0 { - if _, err := txn.Exec(`INSERT INTO nostr_sdk_db_version VALUES (0)`); err != nil { - txn.Rollback() - return SQLHints{}, err - } - version = 1 - if _, err := txn.Exec( - `CREATE TABLE IF NOT EXISTS nostr_sdk_pubkey_relays (` + - `pubkey text, ` + - `relay text, ` + - `last_fetch_attempt integer, ` + - `most_recent_event_fetched integer, ` + - `last_in_relay_list integer, ` + - `last_in_tag integer, ` + - `last_in_nprofile integer, ` + - `last_in_nevent integer, ` + - `last_in_nip05 integer ` + - `)`, - ); err != nil { - txn.Rollback() - return SQLHints{}, err - } - if _, err := txn.Exec( - `CREATE UNIQUE INDEX IF NOT EXISTS pkr ON nostr_sdk_pubkey_relays (pubkey, relay)`, - ); err != nil { - txn.Rollback() - return SQLHints{}, err - } - if _, err := txn.Exec( - `CREATE INDEX IF NOT EXISTS bypk ON nostr_sdk_pubkey_relays (pubkey)`, - ); err != nil { - txn.Rollback() - return SQLHints{}, err - } - } - - if version == 1 { - version = 2 - if _, err := txn.Exec( - `ALTER TABLE nostr_sdk_pubkey_relays DROP COLUMN last_in_tag`, - ); err != nil { - txn.Rollback() - return SQLHints{}, err - } - if _, err := txn.Exec( - `ALTER TABLE nostr_sdk_pubkey_relays DROP COLUMN last_in_nprofile`, - ); err != nil { - txn.Rollback() - return SQLHints{}, err - } - if _, err := txn.Exec( - `ALTER TABLE nostr_sdk_pubkey_relays DROP COLUMN last_in_nevent`, - ); err != nil { - txn.Rollback() - return SQLHints{}, err - } - if _, err := txn.Exec( - `ALTER TABLE nostr_sdk_pubkey_relays DROP COLUMN last_in_nip05`, - ); err != nil { - txn.Rollback() - return SQLHints{}, err - } - if _, err := txn.Exec( - `ALTER TABLE nostr_sdk_pubkey_relays ADD COLUMN last_in_hint integer`, - ); err != nil { - txn.Rollback() - return SQLHints{}, err - } - } - - if _, err := txn.Exec( - fmt.Sprintf(`UPDATE nostr_sdk_db_version SET version = %d`, version), - ); err != nil { - txn.Rollback() - return SQLHints{}, err - } - if err := txn.Commit(); err != nil { - txn.Rollback() - return SQLHints{}, err - } - } - - // prepare statements - for i := range hints.KeyBasePoints { - col := hints.HintKey(i).String() - - stmt, err := sh.Preparex( - `INSERT INTO nostr_sdk_pubkey_relays (pubkey, relay, ` + col + `) VALUES (` + sh.interop.generateBindingSpots(0, 3) + `) - ON CONFLICT (pubkey, relay) DO UPDATE SET ` + col + ` = ` + sh.interop.maxFunc + `(` + sh.interop.generateBindingSpots(3, 1) + `, coalesce(excluded.` + col + `, 0))`, - ) - if err != nil { - fmt.Println( - `INSERT INTO nostr_sdk_pubkey_relays (pubkey, relay, ` + col + `) VALUES (` + sh.interop.generateBindingSpots(0, 3) + `) - ON CONFLICT (pubkey, relay) DO UPDATE SET ` + col + ` = ` + sh.interop.maxFunc + `(` + sh.interop.generateBindingSpots(3, 1) + `, coalesce(excluded.` + col + `, 0))`, - ) - return sh, fmt.Errorf("failed to prepare statement for %s: %w", col, err) - } - sh.saves[i] = stmt - } - - { - stmt, err := sh.Preparex( - `SELECT relay FROM nostr_sdk_pubkey_relays WHERE pubkey = ` + sh.interop.generateBindingSpots(0, 1) + ` ORDER BY (` + sh.scorePartialQuery() + `) DESC LIMIT ` + sh.interop.generateBindingSpots(1, 1), - ) - if err != nil { - return sh, fmt.Errorf("failed to prepare statement for querying: %w", err) - } - sh.topN = stmt - } - - return sh, nil -} - -func (sh SQLHints) TopN(pubkey string, n int) []string { - res := make([]string, 0, n) - err := sh.topN.Select(&res, pubkey, n) - if err != nil && err != sql.ErrNoRows { - nostr.InfoLogger.Printf("[sdk/hints/sql] unexpected error on query for %s: %s\n", - pubkey, err) - } - return res -} - -func (sh SQLHints) Save(pubkey string, relay string, key hints.HintKey, ts nostr.Timestamp) { - if now := nostr.Now(); ts > now { - ts = now - } - - _, err := sh.saves[key].Exec(pubkey, relay, ts, ts) - if err != nil { - nostr.InfoLogger.Printf("[sdk/hints/sql] unexpected error on insert for %s, %s, %d: %s\n", - pubkey, relay, ts, err) - } -} - -func (sh SQLHints) PrintScores() { - fmt.Println("= print scores") - - allpubkeys := make([]string, 0, 50) - if err := sh.Select(&allpubkeys, `SELECT DISTINCT pubkey FROM nostr_sdk_pubkey_relays`); err != nil { - panic(err) - } - - allrelays := make([]struct { - PubKey string `db:"pubkey"` - Relay string `db:"relay"` - Score float64 `db:"score"` - }, 0, 20) - for _, pubkey := range allpubkeys { - fmt.Println("== relay scores for", pubkey) - if err := sh.Select(&allrelays, - `SELECT pubkey, relay, coalesce(`+sh.scorePartialQuery()+`, 0) AS score - FROM nostr_sdk_pubkey_relays WHERE pubkey = `+sh.interop.generateBindingSpots(0, 1)+` ORDER BY score DESC`, pubkey); err != nil { - panic(err) - } - - for i, re := range allrelays { - fmt.Printf(" %3d :: %30s ::> %12d\n", i, re.Relay, int(re.Score)) - } - } -} - -func (sh SQLHints) GetDetailedScores(pubkey string, n int) []hints.RelayScores { - result := make([]hints.RelayScores, 0, n) - - rows, err := sh.Queryx( - `SELECT relay, last_fetch_attempt, most_recent_event_fetched, last_in_relay_list, last_in_hint, - coalesce(`+sh.scorePartialQuery()+`, 0) AS score - FROM nostr_sdk_pubkey_relays - WHERE pubkey = `+sh.interop.generateBindingSpots(0, 1)+` - ORDER BY score DESC - LIMIT `+sh.interop.generateBindingSpots(1, 1), - pubkey, n) - if err != nil { - return nil - } - defer rows.Close() - - for rows.Next() { - var rs hints.RelayScores - var scores [4]sql.NullInt64 - err := rows.Scan(&rs.Relay, &scores[0], &scores[1], &scores[2], &scores[3], &rs.Sum) - if err != nil { - continue - } - for i, s := range scores { - if s.Valid { - rs.Scores[i] = nostr.Timestamp(s.Int64) - } - } - result = append(result, rs) - } - - return result -} - -func (sh SQLHints) scorePartialQuery() string { - calc := strings.Builder{} - calc.Grow(len(hints.KeyBasePoints) * (11 + 25 + 32 + 4 + 4 + 9 + 12 + 25 + 12 + 25 + 19 + 3)) - - for i, points := range hints.KeyBasePoints { - col := hints.HintKey(i).String() - multiplier := strconv.FormatInt(points, 10) - - calc.WriteString(`(CASE WHEN `) - calc.WriteString(col) - calc.WriteString(` IS NOT NULL THEN 10000000000 * `) - calc.WriteString(multiplier) - calc.WriteString(` / power(`) - calc.WriteString(sh.interop.maxFunc) - calc.WriteString(`(1, (`) - calc.WriteString(sh.interop.getUnixEpochFunc) - calc.WriteString(` + 86400) - `) - calc.WriteString(col) - calc.WriteString(`), 1.3) ELSE 0 END)`) - - if i != len(hints.KeyBasePoints)-1 { - calc.WriteString(` + `) - } - } - - return calc.String() -} diff --git a/sdk/hints/sqlh/interop.go b/sdk/hints/sqlh/interop.go deleted file mode 100644 index 3cf787f..0000000 --- a/sdk/hints/sqlh/interop.go +++ /dev/null @@ -1,48 +0,0 @@ -package sqlh - -import ( - "strconv" - "strings" -) - -type interop struct { - maxFunc string - getUnixEpochFunc string - generateBindingSpots func(start, n int) string -} - -var sqliteInterop = interop{ - maxFunc: "max", - getUnixEpochFunc: "unixepoch()", - generateBindingSpots: func(_, n int) string { - b := strings.Builder{} - b.Grow(n * 2) - for i := range n { - if i == n-1 { - b.WriteString("?") - } else { - b.WriteString("?,") - } - } - return b.String() - }, -} - -var postgresInterop = interop{ - maxFunc: "greatest", - getUnixEpochFunc: "extract(epoch from now())", - generateBindingSpots: func(start, n int) string { - b := strings.Builder{} - b.Grow(n * 2) - end := start + n - for i := start; i < end; i++ { - v := i + 1 - b.WriteRune('$') - b.WriteString(strconv.Itoa(v)) - if i != end-1 { - b.WriteRune(',') - } - } - return b.String() - }, -} diff --git a/sdk/hints/test/badger_test.go b/sdk/hints/test/badger_test.go index 15f0bca..3caf735 100644 --- a/sdk/hints/test/badger_test.go +++ b/sdk/hints/test/badger_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - "github.com/nbd-wtf/go-nostr/sdk/hints/badgerh" + "fiatjaf.com/nostr/sdk/hints/badgerh" ) func TestBadgerHints(t *testing.T) { diff --git a/sdk/hints/test/libsql_test.go b/sdk/hints/test/libsql_test.go index 565d152..60c112a 100644 --- a/sdk/hints/test/libsql_test.go +++ b/sdk/hints/test/libsql_test.go @@ -7,7 +7,7 @@ import ( "os" "testing" - "fiatjaf.com/nostrlib/sdk/hints/sqlh" + "fiatjaf.com/nostr/sdk/hints/sqlh" "github.com/stretchr/testify/require" _ "github.com/tursodatabase/go-libsql" ) diff --git a/sdk/hints/test/lmdb_test.go b/sdk/hints/test/lmdb_test.go index 3ddd165..ae6897f 100644 --- a/sdk/hints/test/lmdb_test.go +++ b/sdk/hints/test/lmdb_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - "github.com/nbd-wtf/go-nostr/sdk/hints/lmdbh" + "fiatjaf.com/nostr/sdk/hints/lmdbh" ) func TestLMDBHints(t *testing.T) { @@ -18,4 +18,4 @@ func TestLMDBHints(t *testing.T) { defer hdb.Close() runTestWith(t, hdb) -} \ No newline at end of file +} diff --git a/sdk/hints/test/mattnsqlite_test.go b/sdk/hints/test/mattnsqlite_test.go index d61cbeb..9bcdd56 100644 --- a/sdk/hints/test/mattnsqlite_test.go +++ b/sdk/hints/test/mattnsqlite_test.go @@ -8,7 +8,7 @@ import ( "testing" _ "github.com/mattn/go-sqlite3" - "fiatjaf.com/nostrlib/sdk/hints/sqlh" + "fiatjaf.com/nostr/sdk/hints/sqlh" "github.com/stretchr/testify/require" ) diff --git a/sdk/hints/test/memory_test.go b/sdk/hints/test/memory_test.go index cd456cc..97a5b0e 100644 --- a/sdk/hints/test/memory_test.go +++ b/sdk/hints/test/memory_test.go @@ -3,7 +3,7 @@ package test import ( "testing" - "fiatjaf.com/nostrlib/sdk/hints/memoryh" + "fiatjaf.com/nostr/sdk/hints/memoryh" ) func TestMemoryHints(t *testing.T) { diff --git a/sdk/hints/test/moderncsqlite_test.go b/sdk/hints/test/moderncsqlite_test.go index 727b379..fef0508 100644 --- a/sdk/hints/test/moderncsqlite_test.go +++ b/sdk/hints/test/moderncsqlite_test.go @@ -7,7 +7,7 @@ import ( "os" "testing" - "fiatjaf.com/nostrlib/sdk/hints/sqlh" + "fiatjaf.com/nostr/sdk/hints/sqlh" "github.com/stretchr/testify/require" _ "modernc.org/sqlite" ) diff --git a/sdk/hints/test/suite.go b/sdk/hints/test/suite.go index dbbc113..f09e95e 100644 --- a/sdk/hints/test/suite.go +++ b/sdk/hints/test/suite.go @@ -4,8 +4,8 @@ import ( "testing" "time" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/sdk/hints" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/sdk/hints" "github.com/stretchr/testify/require" ) diff --git a/sdk/hints/test/wasmsqlite_test.go b/sdk/hints/test/wasmsqlite_test.go index b6c1062..fccca58 100644 --- a/sdk/hints/test/wasmsqlite_test.go +++ b/sdk/hints/test/wasmsqlite_test.go @@ -7,7 +7,7 @@ import ( "os" "testing" - "fiatjaf.com/nostrlib/sdk/hints/sqlh" + "fiatjaf.com/nostr/sdk/hints/sqlh" _ "github.com/ncruces/go-sqlite3/driver" _ "github.com/ncruces/go-sqlite3/embed" "github.com/stretchr/testify/require" diff --git a/sdk/input.go b/sdk/input.go index 17d07be..c4c08e7 100644 --- a/sdk/input.go +++ b/sdk/input.go @@ -4,9 +4,9 @@ import ( "context" "encoding/hex" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip05" - "fiatjaf.com/nostrlib/nip19" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip05" + "fiatjaf.com/nostr/nip19" ) // InputToProfile turns any npub/nprofile/hex/nip05 input into a ProfilePointer (or nil). diff --git a/sdk/kvstore/badger/store.go b/sdk/kvstore/badger/store.go index 25984cb..064a2ac 100644 --- a/sdk/kvstore/badger/store.go +++ b/sdk/kvstore/badger/store.go @@ -2,7 +2,7 @@ package badger import ( "github.com/dgraph-io/badger/v4" - "fiatjaf.com/nostrlib/sdk/kvstore" + "fiatjaf.com/nostr/sdk/kvstore" ) var _ kvstore.KVStore = (*Store)(nil) diff --git a/sdk/kvstore/lmdb/store.go b/sdk/kvstore/lmdb/store.go index de49717..405e7f1 100644 --- a/sdk/kvstore/lmdb/store.go +++ b/sdk/kvstore/lmdb/store.go @@ -4,7 +4,7 @@ import ( "os" "github.com/PowerDNS/lmdb-go/lmdb" - "fiatjaf.com/nostrlib/sdk/kvstore" + "fiatjaf.com/nostr/sdk/kvstore" ) var _ kvstore.KVStore = (*Store)(nil) diff --git a/sdk/kvstore/memory/store.go b/sdk/kvstore/memory/store.go index c8a5547..2852c36 100644 --- a/sdk/kvstore/memory/store.go +++ b/sdk/kvstore/memory/store.go @@ -3,7 +3,7 @@ package memory import ( "sync" - "fiatjaf.com/nostrlib/sdk/kvstore" + "fiatjaf.com/nostr/sdk/kvstore" ) var _ kvstore.KVStore = (*Store)(nil) diff --git a/sdk/metadata.go b/sdk/metadata.go index dc2a768..7dc9cf2 100644 --- a/sdk/metadata.go +++ b/sdk/metadata.go @@ -5,10 +5,10 @@ import ( "fmt" "time" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip05" - "fiatjaf.com/nostrlib/nip19" - "fiatjaf.com/nostrlib/sdk/hints" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip05" + "fiatjaf.com/nostr/nip19" + "fiatjaf.com/nostr/sdk/hints" ) // ProfileMetadata represents user profile information from kind 0 events. diff --git a/sdk/note.go b/sdk/note.go index 7fe73f6..af9398a 100644 --- a/sdk/note.go +++ b/sdk/note.go @@ -1,8 +1,10 @@ package sdk import ( - "github.com/nbd-wtf/go-nostr" - "github.com/nbd-wtf/go-nostr/nip27" + "encoding/hex" + + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip27" ) // PrepareNoteEvent takes an event with content that may include any number of URLs, partial URLs without the scheme, npub references with or without the "nostr:" prefix, tags and whatnot, then edits the content so it contains properly formatted URLs and references and adds the required tags based on these. @@ -23,12 +25,12 @@ func PrepareNoteEvent(evt *nostr.Event) { switch b := block.Pointer.(type) { case nostr.ProfilePointer: // add b tag if not already present - if tag := evt.Tags.FindWithValue("b", b.PublicKey); tag == nil { + if tag := evt.Tags.FindWithValue("b", hex.EncodeToString(b.PublicKey[:])); tag == nil { evt.Tags = append(evt.Tags, b.AsTag()) } case nostr.EventPointer: // add e tag if not already present - if tag := evt.Tags.FindWithValue("q", b.ID); tag == nil { + if tag := evt.Tags.FindWithValue("q", hex.EncodeToString(b.ID[:])); tag == nil { evt.Tags = append(evt.Tags, b.AsTag()) } case nostr.EntityPointer: diff --git a/sdk/note_test.go b/sdk/note_test.go index 2b7b68e..da6940c 100644 --- a/sdk/note_test.go +++ b/sdk/note_test.go @@ -3,7 +3,7 @@ package sdk import ( "testing" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" "github.com/stretchr/testify/require" ) diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index bd82fd3..01c901a 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -7,7 +7,7 @@ import ( "sync" "testing" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" "github.com/stretchr/testify/require" ) diff --git a/sdk/search.go b/sdk/search.go index ebd5c5f..ef09435 100644 --- a/sdk/search.go +++ b/sdk/search.go @@ -3,7 +3,7 @@ package sdk import ( "context" - "fiatjaf.com/nostrlib" + "fiatjaf.com/nostr" ) func (sys *System) SearchUsers(ctx context.Context, query string) []ProfileMetadata { diff --git a/sdk/specific_event.go b/sdk/specific_event.go index 27ddfdf..919aecb 100644 --- a/sdk/specific_event.go +++ b/sdk/specific_event.go @@ -6,9 +6,9 @@ import ( "slices" "sync" - "fiatjaf.com/nostrlib" - "fiatjaf.com/nostrlib/nip19" - "fiatjaf.com/nostrlib/sdk/hints" + "fiatjaf.com/nostr" + "fiatjaf.com/nostr/nip19" + "fiatjaf.com/nostr/sdk/hints" ) // FetchSpecificEventParameters contains options for fetching specific events. diff --git a/sdk/tracker.go b/sdk/tracker.go index c06c236..21cbf53 100644 --- a/sdk/tracker.go +++ b/sdk/tracker.go @@ -4,8 +4,8 @@ import ( "net/url" "fiatjaf.com/nostr" - "fiatjaf.com/nostrlib/sdk/hints" - "github.com/nbd-wtf/go-nostr/nip27" + "fiatjaf.com/nostr/nip27" + "fiatjaf.com/nostr/sdk/hints" ) func (sys *System) TrackQueryAttempts(relay string, author nostr.PubKey, kind uint16) { diff --git a/sdk/wot.go b/sdk/wot.go index dcc5d82..e840966 100644 --- a/sdk/wot.go +++ b/sdk/wot.go @@ -2,17 +2,17 @@ package sdk import ( "context" - "strconv" + "encoding/binary" "sync" "time" + "fiatjaf.com/nostr" "github.com/FastFilter/xorfilter" "golang.org/x/sync/errgroup" ) -func PubKeyToShid(pubkey string) uint64 { - shid, _ := strconv.ParseUint(pubkey[32:48], 16, 64) - return shid +func PubKeyToShid(pubkey nostr.PubKey) uint64 { + return binary.BigEndian.Uint64(pubkey[16:24]) } type wotCall struct { @@ -30,7 +30,7 @@ var ( wotCallsInPlace [wotCallsSize]*wotCall ) -func (sys *System) LoadWoTFilter(ctx context.Context, pubkey string) (WotXorFilter, error) { +func (sys *System) LoadWoTFilter(ctx context.Context, pubkey nostr.PubKey) (WotXorFilter, error) { id := PubKeyToShid(pubkey) pos := int(id % wotCallsSize) @@ -99,11 +99,11 @@ actualcall: return res, err } -func (sys *System) loadWoT(ctx context.Context, pubkey string) (chan string, error) { +func (sys *System) loadWoT(ctx context.Context, pubkey nostr.PubKey) (chan nostr.PubKey, error) { g, ctx := errgroup.WithContext(ctx) g.SetLimit(45) - res := make(chan string) + res := make(chan nostr.PubKey) // process follow lists wg := sync.WaitGroup{} @@ -139,7 +139,7 @@ func (sys *System) loadWoT(ctx context.Context, pubkey string) (chan string, err return res, nil } -func makeWoTFilter(m chan string) WotXorFilter { +func makeWoTFilter(m chan nostr.PubKey) WotXorFilter { shids := make([]uint64, 0, 60000) shidMap := make(map[uint64]struct{}, 60000) for pk := range m { @@ -159,7 +159,7 @@ type WotXorFilter struct { xorfilter.Xor8 } -func (wxf WotXorFilter) Contains(pubkey string) bool { +func (wxf WotXorFilter) Contains(pubkey nostr.PubKey) bool { if wxf.Items == 0 { return false } diff --git a/sdk/wot_test.go b/sdk/wot_test.go index b08663c..0abeb2a 100644 --- a/sdk/wot_test.go +++ b/sdk/wot_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/nbd-wtf/go-nostr" + "fiatjaf.com/nostr" "github.com/stretchr/testify/require" ) @@ -14,11 +14,11 @@ func TestLoadWoT(t *testing.T) { ctx := t.Context() // test with fiatjaf's pubkey - wotch, err := sys.loadWoT(ctx, "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d") + wotch, err := sys.loadWoT(ctx, nostr.MustPubKeyFromHex("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")) require.NoError(t, err) - wot := make([]string, 0, 100000) - wotch2 := make(chan string) + wot := make([]nostr.PubKey, 0, 100000) + wotch2 := make(chan nostr.PubKey) var filter WotXorFilter done := make(chan struct{}) @@ -60,7 +60,7 @@ func TestLoadWoTManyPeople(t *testing.T) { // these are the same pubkey go func() { - rabble, err := sys.LoadWoTFilter(ctx, "76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa") + rabble, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa")) require.NoError(t, err) diffs[0] = nostr.Now() rabble1 = rabble @@ -69,7 +69,7 @@ func TestLoadWoTManyPeople(t *testing.T) { time.Sleep(time.Millisecond * 20) go func() { - rabble, err := sys.LoadWoTFilter(ctx, "76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa") + rabble, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa")) require.NoError(t, err) diffs[1] = nostr.Now() rabble2 = rabble @@ -78,7 +78,7 @@ func TestLoadWoTManyPeople(t *testing.T) { time.Sleep(time.Millisecond * 20) go func() { - rabble, err := sys.LoadWoTFilter(ctx, "76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa") + rabble, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa")) require.NoError(t, err) diffs[2] = nostr.Now() rabble3 = rabble @@ -88,7 +88,7 @@ func TestLoadWoTManyPeople(t *testing.T) { // these should map to the same pos time.Sleep(time.Millisecond * 20) go func() { - alex, err := sys.LoadWoTFilter(ctx, "9ce71f1506ccf4b99f234af49bd6202be883a80f95a155c6e9a1c36fd7e780c7") + alex, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("9ce71f1506ccf4b99f234af49bd6202be883a80f95a155c6e9a1c36fd7e780c7")) require.NoError(t, err) diffs[3] = nostr.Now() alex1 = alex @@ -97,7 +97,7 @@ func TestLoadWoTManyPeople(t *testing.T) { time.Sleep(time.Millisecond * 20) go func() { - alex, err := sys.LoadWoTFilter(ctx, "9ce71f1506ccf4b99f234af49bd6202be883a80f95a155c6e9a1c36fd7e780c7") + alex, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("9ce71f1506ccf4b99f234af49bd6202be883a80f95a155c6e9a1c36fd7e780c7")) require.NoError(t, err) diffs[4] = nostr.Now() alex2 = alex @@ -106,18 +106,18 @@ func TestLoadWoTManyPeople(t *testing.T) { // these are independent go func() { - hodlbod, err := sys.LoadWoTFilter(ctx, "97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322") + hodlbod, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322")) require.NoError(t, err) - require.True(t, hodlbod.Contains("ee11a5dff40c19a555f41fe42b48f00e618c91225622ae37b6c2bb67b76c4e49")) - require.True(t, hodlbod.Contains("76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa")) - require.True(t, hodlbod.Contains("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")) + require.True(t, hodlbod.Contains(nostr.MustPubKeyFromHex("ee11a5dff40c19a555f41fe42b48f00e618c91225622ae37b6c2bb67b76c4e49"))) + require.True(t, hodlbod.Contains(nostr.MustPubKeyFromHex("76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa"))) + require.True(t, hodlbod.Contains(nostr.MustPubKeyFromHex("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"))) wg.Done() }() go func() { - mikedilger, err := sys.LoadWoTFilter(ctx, "ee11a5dff40c19a555f41fe42b48f00e618c91225622ae37b6c2bb67b76c4e49") + mikedilger, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("ee11a5dff40c19a555f41fe42b48f00e618c91225622ae37b6c2bb67b76c4e49")) require.NoError(t, err) - require.True(t, mikedilger.Contains("97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322")) - require.True(t, mikedilger.Contains("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")) + require.True(t, mikedilger.Contains(nostr.MustPubKeyFromHex("97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322"))) + require.True(t, mikedilger.Contains(nostr.MustPubKeyFromHex("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"))) wg.Done() }() diff --git a/types.go b/types.go index c86b2f0..16dff4e 100644 --- a/types.go +++ b/types.go @@ -6,6 +6,11 @@ import ( "unsafe" ) +var ( + ZeroID = [32]byte{} + ZeroPK = [32]byte{} +) + type PubKey [32]byte func (pk PubKey) String() string { return hex.EncodeToString(pk[:]) }