This is about #68
When trying to build a decoder, one of the first snags I got tangled in was the length of the naddr, so I ended up using this, to work around the length restrictions.
public function decodeBech32(string $bech32): array
{
$charset = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
// Find the separator (1)
$pos = strrpos($bech32, '1');
if ($pos === false) {
throw new Exception('Invalid Bech32 string');
}
// Extract human-readable part (HRP)
$hrp = substr($bech32, 0, $pos);
// Extract data part
$data_part = substr($bech32, $pos + 1);
$data = [];
for ($i = 0; $i < strlen($data_part); $i++) {
$data[] = strpos($charset, $data_part[$i]);
if ($data[$i] === false) {
throw new Exception('Invalid character in Bech32 string');
}
}
return [$hrp, $data];
}
I used the following to muddle through the TLV...
public function decodeAndParseNostrBech32(string $bech32): array
{
list($hrp, $data) = $this->decodeBech32($bech32);
// Convert 5-bit data to 8-bit data
$decodedData = $this->convertBits($data, 5, 8);
if ($hrp == 'npub') {
return [$hrp, $binaryData];
}
// Step 2: Parse the binary data into TLV format
$tlvData = $this->parseTLV($binaryData);
return [$hrp, $tlvData];
}
public function parseTLV(array $binaryData): array
{
$parsedTLVs = [];
$offset = 0;
while ($offset < count($binaryData)) {
if ($offset + 1 >= count($binaryData)) {
throw new Exception("Incomplete TLV data");
}
// Read the Type (T) and Length (L)
$type = $binaryData[$offset];
$length = $binaryData[$offset + 1];
$offset += 2;
// Ensure we have enough data for the value
if ($offset + $length > count($binaryData)) {
break;
} else {
// Extract the Value (V)
$value = array_slice($binaryData, $offset, $length);
}
$offset += $length;
// Add the TLV to the parsed array
$parsedTLVs[] = [
'type' => $type,
'length' => $length,
'value' => $value,
];
}
return $parsedTLVs;
}
And this insanity, to get the TLVs into data:
// naddr - a nostr replaceable event coordinate
list($hrp, $tlv) = $bech32Decoder->decodeAndParseNostrBech32($naddr);
if ($hrp !== 'naddr') {
throw new \Exception('Not a naddr scheme link');
}
$typeSlug = 0; // slug
$typeRelays = 1; // relays
$typeAuthor = 2; // author
$typeKind = 3; // kind
$relays = [];
foreach ($tlv as $item) {
if ($item['type'] === $typeSlug) {
$slug = implode('', array_map('chr', $item['value']));
}
if ($item['type'] === $typeRelays) {
$relays[] = implode('', array_map('chr', $item['value']));
}
if ($item['type'] === $typeAuthor) {
$str = '';
foreach ($item['value'] as $byte) {
$str .= str_pad(dechex($byte), 2, '0', STR_PAD_LEFT);
}
$author = $str;
}
if ($item['type'] === $typeKind) {
// big-endian integer
$intValue = 0;
foreach ($item['value'] as $byte) {
$intValue = ($intValue << 8) | $byte;
}
$kind = (string) $intValue;
}
}
I'm just dumping this on you, but maybe you can get something out of it. Have fun 😄
This is about #68
When trying to build a decoder, one of the first snags I got tangled in was the length of the naddr, so I ended up using this, to work around the length restrictions.
I used the following to muddle through the TLV...
And this insanity, to get the TLVs into data:
I'm just dumping this on you, but maybe you can get something out of it. Have fun 😄