bech32 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +2 -3
- data/README.md +75 -15
- data/exe/bech32 +24 -5
- data/lib/bech32/nostr/entity.rb +163 -0
- data/lib/bech32/nostr/nip19.rb +44 -0
- data/lib/bech32/nostr.rb +8 -0
- data/lib/bech32/version.rb +1 -1
- data/lib/bech32.rb +1 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5c153cf694b5bcfc8e09c9aff4439771137dbb558ef082e05f6330763c3eda4
|
4
|
+
data.tar.gz: a7397025e69d847ab649a9f276bf0582d11c1f70ab447b60fd1073fdec6c8c63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9619a2d66ee0f18b6ef974365cba1a2475506a25a369ff6a426b034ed1eae01b1a6566c572481019ec84e2fcf34f0dae143a8d6a8edbb9d27e0bf343f1d4180f
|
7
|
+
data.tar.gz: 22550c98747a96c87eb9007ad8e6f99730f7e205574afddd97b296c5338dfc91bd50618ab012853bde479ceea86bc93ff8bfb056555401d2bf5a7de86d433373
|
data/.github/workflows/main.yml
CHANGED
@@ -19,15 +19,14 @@ jobs:
|
|
19
19
|
runs-on: ubuntu-latest
|
20
20
|
strategy:
|
21
21
|
matrix:
|
22
|
-
ruby-version: ['
|
22
|
+
ruby-version: ['3.0', '3.1', '3.2']
|
23
23
|
|
24
24
|
steps:
|
25
25
|
- uses: actions/checkout@v2
|
26
26
|
- name: Set up Ruby
|
27
27
|
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
28
28
|
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
29
|
-
|
30
|
-
uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
|
29
|
+
uses: ruby/setup-ruby@v1
|
31
30
|
with:
|
32
31
|
ruby-version: ${{ matrix.ruby-version }}
|
33
32
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Bech32 [](https://github.com/azuchi/bech32rb/actions/workflows/main.yml) [](https://badge.fury.io/rb/bech32) [](LICENSE) <img src="http://segwit.co/static/public/images/logo.png" width="100">
|
2
2
|
|
3
3
|
The implementation of the Bech32/Bech32m encoder and decoder for Ruby.
|
4
4
|
|
@@ -50,17 +50,6 @@ hrp, data, spec = Bech32.decode('BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4')
|
|
50
50
|
# spec is whether Bech32::Encoding::BECH32 or Bech32::Encoding::BECH32M
|
51
51
|
```
|
52
52
|
|
53
|
-
Decode Bech32-encoded Segwit address into `Bech32::SegwitAddr` instance.
|
54
|
-
|
55
|
-
```ruby
|
56
|
-
addr = 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4'
|
57
|
-
segwit_addr = Bech32::SegwitAddr.new(addr)
|
58
|
-
|
59
|
-
# generate script pubkey
|
60
|
-
segwit_addr.to_script_pubkey
|
61
|
-
=> 0014751e76e8199196d454941c45d1b3a323f1433bd6
|
62
|
-
```
|
63
|
-
|
64
53
|
#### Advanced
|
65
54
|
|
66
55
|
The maximum number of characters of Bech32 defined in [BIP-173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) is limited to 90 characters.
|
@@ -84,7 +73,20 @@ hrp = 'bc'
|
|
84
73
|
data = [0, 14, 20, 15, 7, 13, 26, 0, 25, 18, 6, 11, 13, 8, 21, 4, 20, 3, 17, 2, 29, 3, 12, 29, 3, 4, 15, 24, 20, 6, 14, 30, 22]
|
85
74
|
|
86
75
|
bech = Bech32.encode(hrp, data, Bech32::Encoding::BECH32)
|
87
|
-
=> bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
|
76
|
+
=> 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
|
77
|
+
```
|
78
|
+
|
79
|
+
### Segwit
|
80
|
+
|
81
|
+
Decode Bech32-encoded Segwit address into `Bech32::SegwitAddr` instance.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
addr = 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4'
|
85
|
+
segwit_addr = Bech32::SegwitAddr.new(addr)
|
86
|
+
|
87
|
+
# generate script pubkey
|
88
|
+
segwit_addr.to_script_pubkey
|
89
|
+
=> '0014751e76e8199196d454941c45d1b3a323f1433bd6'
|
88
90
|
```
|
89
91
|
|
90
92
|
Encode Segwit script into Bech32 Segwit address.
|
@@ -95,7 +97,43 @@ segwit_addr.script_pubkey = '0014751e76e8199196d454941c45d1b3a323f1433bd6'
|
|
95
97
|
|
96
98
|
# generate addr
|
97
99
|
segwit_addr.addr
|
98
|
-
=> bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
|
100
|
+
=> 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
|
101
|
+
```
|
102
|
+
|
103
|
+
### Nostr
|
104
|
+
|
105
|
+
Supports encoding/decoding of Nostr's [NIP-19](https://github.com/nostr-protocol/nips/blob/master/19.md) entities.
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
# Decode bare entity
|
109
|
+
bech32 = 'npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg'
|
110
|
+
entity = Bech32::Nostr::NIP19.parse(bech32)
|
111
|
+
entity.hrp
|
112
|
+
=> 'npub'
|
113
|
+
entity.data
|
114
|
+
=> '7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e'
|
115
|
+
|
116
|
+
# Decode tlv entity
|
117
|
+
bech32 = 'nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p'
|
118
|
+
entity = Bech32::Nostr::NIP19.parse(bech32)
|
119
|
+
entity.hrp
|
120
|
+
=> 'nprofile'
|
121
|
+
entity.entries[0].value
|
122
|
+
=> '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d'
|
123
|
+
entity.entries[1].value
|
124
|
+
=> 'wss://r.x.com'
|
125
|
+
|
126
|
+
# Encode bare entity
|
127
|
+
entity = Bech32::Nostr::BareEntity.new('npub', '7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e')
|
128
|
+
entity.encode
|
129
|
+
=> 'npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg'
|
130
|
+
|
131
|
+
# Encode tlv entity
|
132
|
+
entry_relay = Bech32::Nostr::TLVEntry.new(Bech32::Nostr::TLVEntity::TYPE_RELAY, 'wss://relay.nostr.example')
|
133
|
+
entry_author = Bech32::Nostr::TLVEntry.new(Bech32::Nostr::TLVEntity::TYPE_AUTHOR, '97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322')
|
134
|
+
entity = Bech32::Nostr::TLVEntity.new(Bech32::Nostr::NIP19::HRP_EVENT, [entry_relay, entry_author])
|
135
|
+
entity.encode
|
136
|
+
=> 'nevent1qyvhwumn8ghj7un9d3shjtnwdaehgu3wv4uxzmtsd3jsygyhcu9ygdn2v56uz3dnx0uh865xmlwz675emfsccsxxguz6mx8rygstv78u'
|
99
137
|
```
|
100
138
|
|
101
139
|
### CLI
|
@@ -115,8 +153,30 @@ The `decode` command takes bech32/bech32m string as arguments and outputs `HRP`,
|
|
115
153
|
|
116
154
|
$ bech32 decode genesis1qyfe883hey6jrgj2xvk5g3dfmfqfzm7a4wez4pd2krf7ltsxffd6u6nrvjvv0uzda6whtuhzscj72zuj6udkmknakfn0anc07gaya2303dnngu3sxqctqvg5v7nw0fvkwqce7auqkxv3sj5j7e8d6vu4zy5qlssvffxqccxqcfgwc98zenr3qrzk5msfgkvjnj0ejpl8zunedeqhvajry08ueg99ynwgd2sdntrq22gensffcj03r3yjv4cv4j20ee8vujxve3fssj2demyvknzwe3glqt6t954vknpdvurthpc9fpex7t97nvqryeqpjrpscap6q0zvfpgv3nxzpy6wmx24k9xcu35vuatm5zvn7t084ec7tlw2gh0av9xwumwkv02hats66l5hkwd55rwkm2q8fsd4zvqwpvqqqqtdc6rp
|
117
155
|
HRP: genesis
|
118
|
-
DATA:
|
156
|
+
DATA: [0, 4, 9, 25, 7, 7, 17, 23, 25, 4, 26, 18, 3, 8, 18, 10, 6, 12, 22, 20, 8, 17, 13, 9, 27, 9, 0, 9, 2, 27, 30, 29, 21, 14, 25, 2, 21, 1, 13, 10, 22, 3, 9, 30, 31, 11, 16, 6, 9, 9, 13, 26, 28, 26, 19, 3, 12, 18, 12, 12, 15, 28, 2, 13, 29, 26, 14, 23, 11, 28, 23, 2, 16, 24, 18, 30, 10, 2, 28, 18, 26, 28, 13, 22, 27, 22, 19, 29, 22, 9, 19, 15, 29, 19, 24, 15, 30, 8, 29, 4, 29, 10, 17, 15, 17, 13, 19, 19, 8, 28, 17, 16, 6, 0, 24, 11, 0, 12, 8, 20, 12, 30, 19, 14, 15, 9, 12, 22, 14, 0, 24, 25, 30, 29, 28, 0, 22, 6, 12, 17, 16, 18, 20, 18, 30, 25, 7, 13, 26, 12, 28, 21, 2, 4, 20, 0, 31, 16, 16, 12, 9, 9, 6, 0, 24, 24, 6, 0, 24, 9, 8, 14, 24, 5, 7, 2, 25, 19, 3, 17, 0, 3, 2, 22, 20, 27, 16, 9, 8, 22, 12, 18, 19, 18, 15, 25, 18, 1, 31, 7, 2, 28, 19, 25, 13, 25, 0, 23, 12, 29, 18, 3, 4, 15, 7, 28, 25, 8, 5, 5, 4, 19, 14, 8, 13, 10, 16, 13, 19, 11, 3, 0, 10, 10, 8, 25, 19, 16, 9, 9, 24, 18, 15, 17, 3, 17, 4, 18, 12, 21, 24, 12, 21, 18, 10, 15, 25, 25, 7, 12, 28, 18, 6, 12, 25, 17, 9, 16, 16, 18, 10, 13, 25, 27, 4, 12, 22, 19, 2, 14, 25, 17, 8, 31, 0, 11, 26, 11, 5, 20, 21, 12, 22, 19, 1, 13, 12, 28, 3, 11, 23, 1, 24, 5, 9, 1, 25, 6, 30, 11, 5, 30, 19, 12, 0, 3, 4, 25, 0, 1, 18, 3, 1, 16, 24, 29, 1, 26, 0, 15, 2, 12, 9, 1, 8, 12, 17, 19, 6, 2, 1, 4, 26, 14, 27, 6, 10, 21, 22, 5, 6, 24, 28, 17, 20, 12, 28, 29, 11, 27, 20, 2, 12, 19, 30, 11, 15, 7, 21, 25, 24, 30, 11, 31, 14, 10, 8, 23, 15, 29, 12, 5, 6, 14, 28, 27, 14, 22, 12, 15, 10, 23, 29, 11, 16, 26, 26, 31, 20, 23, 22, 14, 13, 20, 20, 3, 14, 22, 27, 10, 0, 7, 9, 16, 13, 21, 2, 12, 0, 14, 1, 12, 0, 0, 0, 0]
|
157
|
+
TYPE: bech32
|
158
|
+
|
159
|
+
Note: `DATA` is not bit-converted.
|
160
|
+
|
161
|
+
If bech32 string has segwit hrp, it will also output witness version and witness program:
|
162
|
+
|
163
|
+
$ bech32 decode bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y
|
164
|
+
HRP: bc
|
165
|
+
DATA: [1, 14, 20, 15, 7, 13, 26, 0, 25, 18, 6, 11, 13, 8, 21, 4, 20, 3, 17, 2, 29, 3, 12, 29, 3, 4, 15, 24, 20, 6, 14, 30, 22, 14, 20, 15, 7, 13, 26, 0, 25, 18, 6, 11, 13, 8, 21, 4, 20, 3, 17, 2, 29, 3, 12, 29, 3, 4, 15, 24, 20, 6, 14, 30, 22]
|
166
|
+
TYPE: bech32m
|
167
|
+
WITNESS VERSION: 1
|
168
|
+
WITNESS PROGRAM: 751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6
|
169
|
+
|
170
|
+
If bech32 string has NIP-19 hrp, it will also output NIP-19 entry:
|
171
|
+
|
172
|
+
$ bech32 decode nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p
|
173
|
+
HRP: nprofile
|
174
|
+
DATA: [0, 0, 16, 3, 23, 28, 6, 6, 7, 31, 5, 25, 6, 17, 17, 20, 0, 30, 23, 25, 15, 9, 15, 5, 29, 25, 18, 15, 21, 2, 1, 29, 2, 1, 31, 15, 19, 25, 10, 24, 8, 28, 22, 4, 29, 14, 13, 10, 21, 27, 29, 4, 11, 7, 8, 1, 1, 21, 27, 23, 6, 28, 25, 26, 5, 28, 23, 23, 4, 11, 19, 24, 5, 25, 17, 22, 30, 27, 8, 1, 2, 21, 27, 23, 6, 28, 25, 26, 5, 28, 23, 22, 8, 26, 19, 2, 12, 5, 25, 18, 28, 28, 27, 1, 12, 17, 21, 22, 4, 11, 19, 3, 13, 29, 22, 16]
|
119
175
|
TYPE: bech32
|
176
|
+
NIP19 Entities:
|
177
|
+
special: 3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d
|
178
|
+
relay: wss://r.x.com
|
179
|
+
relay: wss://djbas.sadkb.com
|
120
180
|
|
121
181
|
## License
|
122
182
|
|
data/exe/bech32
CHANGED
@@ -18,13 +18,32 @@ class CLI < Thor
|
|
18
18
|
|
19
19
|
desc 'decode "bech32string"', 'Decoding bech32/bech32m string.'
|
20
20
|
def decode(bech32_str)
|
21
|
-
|
22
|
-
if
|
21
|
+
hrp, data, spec = Bech32.decode(bech32_str, bech32_str.length)
|
22
|
+
if hrp
|
23
23
|
puts <<~EOS
|
24
|
-
HRP: #{
|
25
|
-
DATA: #{
|
26
|
-
TYPE: #{
|
24
|
+
HRP: #{hrp}
|
25
|
+
DATA: #{data}
|
26
|
+
TYPE: #{spec == Bech32::Encoding::BECH32 ? 'bech32' : 'bech32m'}
|
27
27
|
EOS
|
28
|
+
if [Bech32::SegwitAddr::HRP_MAINNET, Bech32::SegwitAddr::HRP_TESTNET, Bech32::SegwitAddr::HRP_REGTEST].include?(hrp)
|
29
|
+
addr = Bech32::SegwitAddr.new(bech32_str)
|
30
|
+
puts <<~EOS
|
31
|
+
WITNESS VERSION: #{addr.ver}
|
32
|
+
WITNESS PROGRAM: #{addr.prog.pack('C*').unpack1('H*')}
|
33
|
+
EOS
|
34
|
+
elsif Bech32::Nostr::NIP19::ALL_PREFIXES.include?(hrp)
|
35
|
+
entity = Bech32::Nostr::NIP19.decode(bech32_str)
|
36
|
+
if entity.is_a?(Bech32::Nostr::BareEntity)
|
37
|
+
puts <<~EOS
|
38
|
+
NIP19 Entity: #{entity.data}
|
39
|
+
EOS
|
40
|
+
else
|
41
|
+
puts 'NIP19 Entities:'
|
42
|
+
entity.entries.each do |entry|
|
43
|
+
puts " #{entry.to_s}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
28
47
|
else
|
29
48
|
puts 'Can not decode.'
|
30
49
|
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module Bech32
|
2
|
+
module Nostr
|
3
|
+
class BareEntity
|
4
|
+
attr_reader :hrp
|
5
|
+
attr_reader :data
|
6
|
+
|
7
|
+
# Initialize bare entity.
|
8
|
+
# @param [String] hrp human-readable part.
|
9
|
+
# @param [String] data Entity data(hex string).
|
10
|
+
def initialize(hrp, data)
|
11
|
+
raise ArgumentError, "HRP #{hrp} is unsupported." unless NIP19::BARE_PREFIXES.include?(hrp)
|
12
|
+
raise ArgumentError, "Data whose HRP is #{hrp} must be 32 bytes." unless [data].pack('H*').bytesize == 32
|
13
|
+
@hrp = hrp
|
14
|
+
@data = data
|
15
|
+
end
|
16
|
+
|
17
|
+
# Encode bare entity to bech32 string.
|
18
|
+
# @return [String] bech32 string.
|
19
|
+
def encode
|
20
|
+
Bech32.encode(hrp, Bech32.convert_bits([data].pack('H*').unpack('C*'), 8, 5), Bech32::Encoding::BECH32)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class TLVEntry
|
25
|
+
|
26
|
+
attr_reader :type
|
27
|
+
attr_reader :label
|
28
|
+
attr_reader :value
|
29
|
+
|
30
|
+
def initialize(type, value, label = nil)
|
31
|
+
raise ArgumentError, "Type #{type} unsupported." unless TLVEntity::TYPES.include?(type)
|
32
|
+
|
33
|
+
@type = type
|
34
|
+
@value = value
|
35
|
+
@label = label
|
36
|
+
end
|
37
|
+
|
38
|
+
# Convert to binary data.
|
39
|
+
# @return [String] binary data.
|
40
|
+
def to_payload
|
41
|
+
data = if value.is_a?(Integer)
|
42
|
+
[value].pack('N')
|
43
|
+
else
|
44
|
+
hex_string?(value) ? [value].pack('H*') : value
|
45
|
+
end
|
46
|
+
len = data.bytesize
|
47
|
+
[type, len].pack('CC') + data
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
type_label = case type
|
52
|
+
when TLVEntity::TYPE_SPECIAL
|
53
|
+
'special'
|
54
|
+
when TLVEntity::TYPE_RELAY
|
55
|
+
'relay'
|
56
|
+
when TLVEntity::TYPE_AUTHOR
|
57
|
+
'author'
|
58
|
+
when TLVEntity::TYPE_KIND
|
59
|
+
'kind'
|
60
|
+
else
|
61
|
+
'unknown'
|
62
|
+
end
|
63
|
+
"#{type_label}: #{value}"
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Check whether +str+ is hex string or not.
|
69
|
+
# @param [String] str string.
|
70
|
+
# @return [Boolean]
|
71
|
+
def hex_string?(str)
|
72
|
+
return false if str.bytes.any? { |b| b > 127 }
|
73
|
+
return false if str.length % 2 != 0
|
74
|
+
hex_chars = str.chars.to_a
|
75
|
+
hex_chars.all? { |c| c =~ /[0-9a-fA-F]/ }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class TLVEntity
|
80
|
+
|
81
|
+
TYPE_SPECIAL = 0
|
82
|
+
TYPE_RELAY = 1
|
83
|
+
TYPE_AUTHOR = 2
|
84
|
+
TYPE_KIND = 3
|
85
|
+
|
86
|
+
TYPES = [TYPE_SPECIAL, TYPE_RELAY, TYPE_AUTHOR, TYPE_KIND]
|
87
|
+
|
88
|
+
attr_reader :hrp
|
89
|
+
attr_reader :entries
|
90
|
+
|
91
|
+
# Initialize TLV entity.
|
92
|
+
# @param [String] hrp human-readable part.
|
93
|
+
# @param [Array<TLVEntry>] entries TLV entries.
|
94
|
+
# @return [TLVEntity]
|
95
|
+
def initialize(hrp, entries)
|
96
|
+
raise ArgumentError, "HRP #{hrp} is unsupported." unless NIP19::TLV_PREFIXES.include?(hrp)
|
97
|
+
entries.each do |e|
|
98
|
+
raise ArgumentError, "Entries must be TLVEntry. #{e.class} given." unless e.is_a?(TLVEntry)
|
99
|
+
end
|
100
|
+
|
101
|
+
@hrp = hrp
|
102
|
+
@entries = entries
|
103
|
+
end
|
104
|
+
|
105
|
+
# Parse TLV entity from data.
|
106
|
+
# @param [String] hrp human-readable part.
|
107
|
+
# @param [String] data Entity data(binary format).
|
108
|
+
# @return [TLVEntity]
|
109
|
+
def self.parse(hrp, data)
|
110
|
+
buf = ::StringIO.new(data)
|
111
|
+
entries = []
|
112
|
+
until buf.eof?
|
113
|
+
type, len = buf.read(2).unpack('CC')
|
114
|
+
case type
|
115
|
+
when TYPE_SPECIAL # special
|
116
|
+
case hrp
|
117
|
+
when NIP19::HRP_PROFILE
|
118
|
+
entries << TLVEntry.new(type, buf.read(len).unpack1('H*'), 'pubkey')
|
119
|
+
when NIP19::HRP_RELAY
|
120
|
+
entries << TLVEntry.new(type, buf.read(len), 'relay')
|
121
|
+
when NIP19::HRP_EVENT
|
122
|
+
entries << TLVEntry.new(type, buf.read(len).unpack1('H*'), 'id')
|
123
|
+
when NIP19::HRP_EVENT_COORDINATE
|
124
|
+
entries << TLVEntry.new(type, buf.read(len), 'identifier')
|
125
|
+
end
|
126
|
+
when TYPE_RELAY # relay
|
127
|
+
case hrp
|
128
|
+
when NIP19::HRP_PROFILE, NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
|
129
|
+
entries << TLVEntry.new(type, buf.read(len), 'relay')
|
130
|
+
else
|
131
|
+
raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
|
132
|
+
end
|
133
|
+
when TYPE_AUTHOR # author
|
134
|
+
case hrp
|
135
|
+
when NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
|
136
|
+
entries << TLVEntry.new(type, buf.read(len).unpack1('H*'), 'author')
|
137
|
+
else
|
138
|
+
raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
|
139
|
+
end
|
140
|
+
when TYPE_KIND # kind
|
141
|
+
case hrp
|
142
|
+
when NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
|
143
|
+
entries << TLVEntry.new(type, buf.read(len).unpack1('H*').to_i(16), 'kind')
|
144
|
+
else
|
145
|
+
raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
|
146
|
+
end
|
147
|
+
else
|
148
|
+
raise ArgumentError, "Unknown TLV type: #{type}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
TLVEntity.new(hrp, entries)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Encode tlv entity to bech32 string.
|
156
|
+
# @return [String] bech32 string.
|
157
|
+
def encode
|
158
|
+
data = entries.map(&:to_payload).join
|
159
|
+
Bech32.encode(hrp, Bech32.convert_bits(data.unpack('C*'), 8, 5), Bech32::Encoding::BECH32)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "stringio"
|
2
|
+
|
3
|
+
module Bech32
|
4
|
+
module Nostr
|
5
|
+
module NIP19
|
6
|
+
|
7
|
+
HRP_PUBKEY = 'npub'
|
8
|
+
HRP_PRIVATE_KEY = 'nsec'
|
9
|
+
HRP_NOTE_ID = 'note'
|
10
|
+
HRP_PROFILE = 'nprofile'
|
11
|
+
HRP_EVENT = 'nevent'
|
12
|
+
HRP_RELAY = 'nrelay'
|
13
|
+
HRP_EVENT_COORDINATE = 'naddr'
|
14
|
+
|
15
|
+
BARE_PREFIXES = [HRP_PUBKEY, HRP_PRIVATE_KEY, HRP_NOTE_ID]
|
16
|
+
TLV_PREFIXES = [HRP_PROFILE, HRP_EVENT, HRP_RELAY, HRP_EVENT_COORDINATE]
|
17
|
+
ALL_PREFIXES = BARE_PREFIXES + TLV_PREFIXES
|
18
|
+
|
19
|
+
module_function
|
20
|
+
|
21
|
+
# Decode nip19 string.
|
22
|
+
# @param [String] string Bech32 string.
|
23
|
+
# @return [BareEntity]
|
24
|
+
# @return [TLVEntity]
|
25
|
+
def decode(string)
|
26
|
+
hrp, data, spec = Bech32.decode(string, string.length)
|
27
|
+
|
28
|
+
raise ArgumentError, 'Invalid nip19 string.' if hrp.nil?
|
29
|
+
raise ArgumentError, 'Invalid bech32 spec.' unless spec == Bech32::Encoding::BECH32
|
30
|
+
|
31
|
+
entity = Bech32.convert_bits(data, 5, 8, false).pack('C*')
|
32
|
+
raise ArgumentError, "Data whose HRP is #{hrp} must be 32 bytes." if BARE_PREFIXES.include?(hrp) && entity.bytesize != 32
|
33
|
+
if BARE_PREFIXES.include?(hrp)
|
34
|
+
BareEntity.new(hrp, entity.unpack1('H*'))
|
35
|
+
elsif TLV_PREFIXES.include?(hrp)
|
36
|
+
TLVEntity.parse(hrp, entity)
|
37
|
+
else
|
38
|
+
raise ArgumentError, "HRP #{hrp} is unsupported."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/bech32/nostr.rb
ADDED
data/lib/bech32/version.rb
CHANGED
data/lib/bech32.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bech32
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shigeyuki Azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -75,6 +75,9 @@ files:
|
|
75
75
|
- bin/setup
|
76
76
|
- exe/bech32
|
77
77
|
- lib/bech32.rb
|
78
|
+
- lib/bech32/nostr.rb
|
79
|
+
- lib/bech32/nostr/entity.rb
|
80
|
+
- lib/bech32/nostr/nip19.rb
|
78
81
|
- lib/bech32/segwit_addr.rb
|
79
82
|
- lib/bech32/version.rb
|
80
83
|
homepage: https://github.com/azuchi/bech32rb
|