nip19.mx raw

   1  package bech32encoding
   2  
   3  import (
   4  	"bytes"
   5  	"crypto/sha256"
   6  	"encoding/binary"
   7  
   8  	"smesh.lol/pkg/nostr/ec/bech32"
   9  	"smesh.lol/pkg/nostr/ec/schnorr"
  10  	"smesh.lol/pkg/nostr/bech32encoding/pointers"
  11  	"smesh.lol/pkg/nostr/bech32encoding/tlv"
  12  	"smesh.lol/pkg/nostr/hex"
  13  	"smesh.lol/pkg/nostr/kind"
  14  	"smesh.lol/pkg/lol/chk"
  15  	"smesh.lol/pkg/lol/errorf"
  16  	"smesh.lol/pkg/lol/log"
  17  )
  18  
  19  var (
  20  	NoteHRP    = []byte("note")
  21  	NsecHRP    = []byte("nsec")
  22  	NpubHRP    = []byte("npub")
  23  	NprofileHRP = []byte("nprofile")
  24  	NeventHRP  = []byte("nevent")
  25  	NentityHRP = []byte("naddr")
  26  )
  27  
  28  func Decode(bech32string []byte) (prefix []byte, value any, err error) {
  29  	var bits5 []byte
  30  	if prefix, bits5, err = bech32.DecodeNoLimit(bech32string); chk.D(err) {
  31  		return
  32  	}
  33  	var data []byte
  34  	if data, err = bech32.ConvertBits(bits5, 5, 8, false); chk.D(err) {
  35  		return prefix, nil, errorf.E([]byte("failed translating data into 8 bits: %s"), err.Error())
  36  	}
  37  	buf := bytes.NewBuffer(data)
  38  	switch {
  39  	case bytes.Equal(prefix, NpubHRP) ||
  40  		bytes.Equal(prefix, NsecHRP) ||
  41  		bytes.Equal(prefix, NoteHRP):
  42  		if len(data) < 32 {
  43  			return prefix, nil, errorf.E([]byte("data is less than 32 bytes (%d)"), len(data))
  44  		}
  45  		b := []byte{:schnorr.PubKeyBytesLen*2}
  46  		hex.EncBytes(b, data[:32])
  47  		return prefix, b, nil
  48  	case bytes.Equal(prefix, NprofileHRP):
  49  		var result pointers.Profile
  50  		for {
  51  			t, v := tlv.ReadEntry(buf)
  52  			if len(v) == 0 {
  53  				if len(result.PublicKey) < 1 {
  54  					return prefix, result, errorf.E([]byte("no pubkey found for nprofile"))
  55  				}
  56  				return prefix, result, nil
  57  			}
  58  			switch t {
  59  			case tlv.Default:
  60  				if len(v) < 32 {
  61  					return prefix, nil, errorf.E([]byte("pubkey is less than 32 bytes (%d)"), len(v))
  62  				}
  63  				result.PublicKey = []byte{:schnorr.PubKeyBytesLen*2}
  64  				hex.EncBytes(result.PublicKey, v)
  65  			case tlv.Relay:
  66  				result.Relays = append(result.Relays, v)
  67  			}
  68  		}
  69  	case bytes.Equal(prefix, NeventHRP):
  70  		var result pointers.Event
  71  		for {
  72  			t, v := tlv.ReadEntry(buf)
  73  			if v == nil {
  74  				if len(result.ID) == 0 {
  75  					return prefix, result, errorf.E([]byte("no id found for nevent"))
  76  				}
  77  				return prefix, result, nil
  78  			}
  79  			switch t {
  80  			case tlv.Default:
  81  				if len(v) < 32 {
  82  					return prefix, nil, errorf.E([]byte("id is less than 32 bytes (%d)"), len(v))
  83  				}
  84  				result.ID = v
  85  			case tlv.Relay:
  86  				result.Relays = append(result.Relays, v)
  87  			case tlv.Author:
  88  				if len(v) < 32 {
  89  					return prefix, nil, errorf.E([]byte("author is less than 32 bytes (%d)"), len(v))
  90  				}
  91  				result.Author = []byte{:schnorr.PubKeyBytesLen*2}
  92  				hex.EncBytes(result.Author, v)
  93  			case tlv.Kind:
  94  				result.Kind = kind.New(binary.BigEndian.Uint32(v))
  95  			}
  96  		}
  97  	case bytes.Equal(prefix, NentityHRP):
  98  		var result pointers.Entity
  99  		for {
 100  			t, v := tlv.ReadEntry(buf)
 101  			if v == nil {
 102  				if result.Kind.ToU16() == 0 ||
 103  					len(result.Identifier) < 1 ||
 104  					len(result.PublicKey) < 1 {
 105  					return prefix, result, errorf.E([]byte("incomplete naddr"))
 106  				}
 107  				return prefix, result, nil
 108  			}
 109  			switch t {
 110  			case tlv.Default:
 111  				result.Identifier = v
 112  			case tlv.Relay:
 113  				result.Relays = append(result.Relays, v)
 114  			case tlv.Author:
 115  				if len(v) < 32 {
 116  					return prefix, nil, errorf.E([]byte("author is less than 32 bytes (%d)"), len(v))
 117  				}
 118  				result.PublicKey = []byte{:schnorr.PubKeyBytesLen*2}
 119  				hex.EncBytes(result.PublicKey, v)
 120  			case tlv.Kind:
 121  				result.Kind = kind.New(binary.BigEndian.Uint32(v))
 122  			default:
 123  				log.D.Ln([]byte("got a bogus TLV type code %d"), t)
 124  			}
 125  		}
 126  	}
 127  	return prefix, data, errorf.E([]byte("unknown tag %s"), prefix)
 128  }
 129  
 130  func EncodeNote(eventIDHex []byte) (s []byte, err error) {
 131  	b := []byte{:sha256.Size}
 132  	if _, err = hex.DecBytes(b, eventIDHex); chk.D(err) {
 133  		return
 134  	}
 135  	var bits5 []byte
 136  	if bits5, err = bech32.ConvertBits(b, 8, 5, true); chk.D(err) {
 137  		return
 138  	}
 139  	return bech32.Encode(NoteHRP, bits5)
 140  }
 141  
 142  func EncodeProfile(publicKeyHex []byte, relays [][]byte) (s []byte, err error) {
 143  	buf := &bytes.Buffer{}
 144  	pb := []byte{:schnorr.PubKeyBytesLen}
 145  	if _, err = hex.DecBytes(pb, publicKeyHex); chk.D(err) {
 146  		return
 147  	}
 148  	tlv.WriteEntry(buf, tlv.Default, pb)
 149  	for _, url := range relays {
 150  		tlv.WriteEntry(buf, tlv.Relay, url)
 151  	}
 152  	var bits5 []byte
 153  	if bits5, err = bech32.ConvertBits(buf.Bytes(), 8, 5, true); chk.D(err) {
 154  		return
 155  	}
 156  	return bech32.Encode(NprofileHRP, bits5)
 157  }
 158  
 159  func EncodeEvent(eventIDHex []byte, relays [][]byte, author []byte) (s []byte, err error) {
 160  	buf := &bytes.Buffer{}
 161  	id := []byte{:sha256.Size}
 162  	if _, err = hex.DecBytes(id, eventIDHex); chk.D(err) || len(id) != 32 {
 163  		return nil, errorf.E([]byte("invalid id %d '%s': %v"), len(id), eventIDHex, err)
 164  	}
 165  	tlv.WriteEntry(buf, tlv.Default, id)
 166  	for _, url := range relays {
 167  		tlv.WriteEntry(buf, tlv.Relay, url)
 168  	}
 169  	pubkey := []byte{:schnorr.PubKeyBytesLen}
 170  	if _, err = hex.DecBytes(pubkey, author); len(pubkey) == 32 {
 171  		tlv.WriteEntry(buf, tlv.Author, pubkey)
 172  	}
 173  	var bits5 []byte
 174  	if bits5, err = bech32.ConvertBits(buf.Bytes(), 8, 5, true); chk.D(err) {
 175  		return
 176  	}
 177  	return bech32.Encode(NeventHRP, bits5)
 178  }
 179  
 180  func EncodeEntity(pk []byte, k *kind.K, id []byte, relays [][]byte) (s []byte, err error) {
 181  	buf := &bytes.Buffer{}
 182  	tlv.WriteEntry(buf, tlv.Default, id)
 183  	for _, url := range relays {
 184  		tlv.WriteEntry(buf, tlv.Relay, url)
 185  	}
 186  	pb := []byte{:schnorr.PubKeyBytesLen}
 187  	if _, err = hex.DecBytes(pb, pk); chk.D(err) {
 188  		return nil, errorf.E([]byte("invalid pubkey '%s': %w"), pb, err)
 189  	}
 190  	tlv.WriteEntry(buf, tlv.Author, pb)
 191  	kindBytes := []byte{:4}
 192  	binary.BigEndian.PutUint32(kindBytes, uint32(k.K))
 193  	tlv.WriteEntry(buf, tlv.Kind, kindBytes)
 194  	var bits5 []byte
 195  	if bits5, err = bech32.ConvertBits(buf.Bytes(), 8, 5, true); chk.D(err) {
 196  		return nil, errorf.E([]byte("failed to convert bits: %w"), err)
 197  	}
 198  	return bech32.Encode(NentityHRP, bits5)
 199  }
 200