package nostr import ( "bytes" "encoding/hex" "testing" ) func TestBech32Encode(t *testing.T) { // Test vector: 32 bytes of data data, _ := hex.DecodeString("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef") encoded, err := Bech32Encode("npub", data) if err != nil { t.Fatalf("Bech32Encode() error = %v", err) } if encoded[:5] != "npub1" { t.Errorf("Encoded string should start with 'npub1', got %s", encoded[:5]) } // Decode it back hrp, decoded, err := Bech32Decode(encoded) if err != nil { t.Fatalf("Bech32Decode() error = %v", err) } if hrp != "npub" { t.Errorf("HRP = %s, want npub", hrp) } if !bytes.Equal(decoded, data) { t.Errorf("Round-trip failed: got %x, want %x", decoded, data) } } func TestBech32EncodeNsec(t *testing.T) { data, _ := hex.DecodeString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") encoded, err := Bech32Encode("nsec", data) if err != nil { t.Fatalf("Bech32Encode() error = %v", err) } if encoded[:5] != "nsec1" { t.Errorf("Encoded string should start with 'nsec1', got %s", encoded[:5]) } // Decode it back hrp, decoded, err := Bech32Decode(encoded) if err != nil { t.Fatalf("Bech32Decode() error = %v", err) } if hrp != "nsec" { t.Errorf("HRP = %s, want nsec", hrp) } if !bytes.Equal(decoded, data) { t.Errorf("Round-trip failed") } } func TestBech32DecodeErrors(t *testing.T) { tests := []struct { name string input string }{ {"no separator", "npubabcdef"}, {"empty data", "npub1"}, {"invalid character", "npub1o"}, // 'o' is not in bech32 alphabet {"invalid checksum", "npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqqqqq"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, _, err := Bech32Decode(tt.input) if err == nil { t.Error("Bech32Decode() expected error, got nil") } }) } } func TestBech32KnownVectors(t *testing.T) { // Test with known nostr npub/nsec values // These can be verified with other nostr tools // Generate a key and verify round-trip key, err := GenerateKey() if err != nil { t.Fatalf("GenerateKey() error = %v", err) } npub := key.Npub() nsec := key.Nsec() // Verify npub decodes to public key hrp, pubBytes, err := Bech32Decode(npub) if err != nil { t.Fatalf("Bech32Decode(npub) error = %v", err) } if hrp != "npub" { t.Errorf("npub HRP = %s, want npub", hrp) } if hex.EncodeToString(pubBytes) != key.Public() { t.Error("npub does not decode to correct public key") } // Verify nsec decodes to private key hrp, privBytes, err := Bech32Decode(nsec) if err != nil { t.Fatalf("Bech32Decode(nsec) error = %v", err) } if hrp != "nsec" { t.Errorf("nsec HRP = %s, want nsec", hrp) } if hex.EncodeToString(privBytes) != key.Private() { t.Error("nsec does not decode to correct private key") } } func TestBech32CaseInsensitive(t *testing.T) { data, _ := hex.DecodeString("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef") encoded, _ := Bech32Encode("npub", data) // Test uppercase upper := "NPUB1" + encoded[5:] hrp, decoded, err := Bech32Decode(upper) if err != nil { t.Fatalf("Bech32Decode(uppercase) error = %v", err) } if hrp != "npub" { t.Errorf("HRP = %s, want npub", hrp) } if !bytes.Equal(decoded, data) { t.Error("Uppercase decode failed") } }