bech32 1.4.2 → 1.5.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 +15 -2
- data/.ruby-version +1 -1
- data/Gemfile +5 -0
- data/README.md +45 -5
- data/Steepfile +19 -0
- data/bech32.gemspec +2 -0
- data/exe/bech32 +10 -2
- data/lib/bech32/nostr/entity.rb +13 -8
- data/lib/bech32/nostr/nip19.rb +3 -1
- data/lib/bech32/silent_payment_addr.rb +59 -0
- data/lib/bech32/version.rb +1 -1
- data/lib/bech32.rb +2 -1
- data/sig/bech32/bech32.rbs +45 -0
- data/sig/bech32/nostr/entity.rbs +54 -0
- data/sig/bech32/nostr/nip19.rbs +23 -0
- data/sig/bech32/segwit_addr.rbs +28 -0
- data/sig/bech32/silent_payment_addr.rbs +21 -0
- metadata +12 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 22cba51d19b0989743f7f679f187311e735ce018dec53880ddfefebee89f688f
|
|
4
|
+
data.tar.gz: 1cd7be33ab83fd724054202a812f818ed02adb5eb7545baa27e27f6b3358da2e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dc71997f097a817224b687dc53baf048ba2954cd030f7db50523d7e45121632b7f2edf758ed78298102214c3e3407cf7c7da6b3469a3cde089ade10e8346088d
|
|
7
|
+
data.tar.gz: 6c246c4107a40193d317738bfa4637ccf6452efb48f1d36532570cec1e09681cc17fd374f47361467017e6546f36c4513f2585ed2d4b767939dcef05047ede46
|
data/.github/workflows/main.yml
CHANGED
|
@@ -19,10 +19,10 @@ jobs:
|
|
|
19
19
|
runs-on: ubuntu-latest
|
|
20
20
|
strategy:
|
|
21
21
|
matrix:
|
|
22
|
-
ruby-version: ['3.
|
|
22
|
+
ruby-version: ['3.2', '3.3', '3.4', '4.0']
|
|
23
23
|
|
|
24
24
|
steps:
|
|
25
|
-
- uses: actions/checkout@
|
|
25
|
+
- uses: actions/checkout@v4
|
|
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):
|
|
@@ -32,3 +32,16 @@ jobs:
|
|
|
32
32
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
33
33
|
- name: Run tests
|
|
34
34
|
run: bundle exec rake
|
|
35
|
+
|
|
36
|
+
typecheck:
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
- name: Set up Ruby
|
|
42
|
+
uses: ruby/setup-ruby@v1
|
|
43
|
+
with:
|
|
44
|
+
ruby-version: '3.4'
|
|
45
|
+
bundler-cache: true
|
|
46
|
+
- name: Run type check
|
|
47
|
+
run: bundle exec steep check
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
ruby-
|
|
1
|
+
ruby-4.0.0
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -100,6 +100,34 @@ segwit_addr.addr
|
|
|
100
100
|
=> 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
### Silent payment address
|
|
104
|
+
|
|
105
|
+
Decode silent payment address.
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
addr = Bech32::SilentPaymentAddr.parse('sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv')
|
|
109
|
+
|
|
110
|
+
# sp version
|
|
111
|
+
addr.version
|
|
112
|
+
=> 0
|
|
113
|
+
# scan public key
|
|
114
|
+
addr.scan_key
|
|
115
|
+
=> '0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4'
|
|
116
|
+
# spend public key
|
|
117
|
+
addr.spend_key
|
|
118
|
+
=> '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Encode sp address.
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
addr = Bech32::SilentPaymentAddr.new('sp', 0, '0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4', '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36')
|
|
125
|
+
|
|
126
|
+
# sp address
|
|
127
|
+
addr.to_s
|
|
128
|
+
=> 'sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv'
|
|
129
|
+
```
|
|
130
|
+
|
|
103
131
|
### Nostr
|
|
104
132
|
|
|
105
133
|
Supports encoding/decoding of Nostr's [NIP-19](https://github.com/nostr-protocol/nips/blob/master/19.md) entities.
|
|
@@ -147,22 +175,22 @@ The `encode` command takes `HRP`, `data`, and type (`bech32` or `bech32m`) as ar
|
|
|
147
175
|
$ bech32 encode genesis 000409190707111719041a120308120a060c161408110d091b090009021b1e1d150e190215010d0a1603091e1f0b100609090d1a1c1a13030c120c0c0f1c020d1d1a0e170b1c17021018121e0a021c121a1c0d161b16131d1609130f1d13180f1e081d041d0a110f110d1313081c11100600180b000c08140c1e130e0f090c160e0018191e1d1c0016060c11101214121e19070d1a0c1c15020414001f10100c09090600181806001809080e180507021913031100030216141b100908160c1213120f1912011f07021c13190d1900170c1d1203040f071c1908050504130e080d0a100d130b03000a0a08191310090918120f11031104120c15180c15120a0f1919070c1c12060c1911091010120a0d191b040c1613020e1911081f000b1a0b0514150c1613010d0c1c030b17011805090119061e0b051e130c00030419000112030110181d011a000f020c0901080c1113060201041a0e1b060a15160506181c11140c1c1d0b1b14020c131e0b0f071519181e0b1f0e0a08170f1d0c05060e1c1b0e160c0f0a171d0b101a1a1f1417160e0d1414030e161b0a000709100d15020c000e010c00000000 bech32
|
|
148
176
|
genesis1qyfe883hey6jrgj2xvk5g3dfmfqfzm7a4wez4pd2krf7ltsxffd6u6nrvjvv0uzda6whtuhzscj72zuj6udkmknakfn0anc07gaya2303dnngu3sxqctqvg5v7nw0fvkwqce7auqkxv3sj5j7e8d6vu4zy5qlssvffxqccxqcfgwc98zenr3qrzk5msfgkvjnj0ejpl8zunedeqhvajry08ueg99ynwgd2sdntrq22gensffcj03r3yjv4cv4j20ee8vujxve3fssj2demyvknzwe3glqt6t954vknpdvurthpc9fpex7t97nvqryeqpjrpscap6q0zvfpgv3nxzpy6wmx24k9xcu35vuatm5zvn7t084ec7tlw2gh0av9xwumwkv02hats66l5hkwd55rwkm2q8fsd4zvqwpvqqqqtdc6rp
|
|
149
177
|
|
|
178
|
+
Note: `data` must be converted from 8-bit to 5-bit units.
|
|
179
|
+
|
|
150
180
|
#### Decode
|
|
151
181
|
|
|
152
182
|
The `decode` command takes bech32/bech32m string as arguments and outputs `HRP`, `data`, and type.
|
|
153
183
|
|
|
154
184
|
$ bech32 decode genesis1qyfe883hey6jrgj2xvk5g3dfmfqfzm7a4wez4pd2krf7ltsxffd6u6nrvjvv0uzda6whtuhzscj72zuj6udkmknakfn0anc07gaya2303dnngu3sxqctqvg5v7nw0fvkwqce7auqkxv3sj5j7e8d6vu4zy5qlssvffxqccxqcfgwc98zenr3qrzk5msfgkvjnj0ejpl8zunedeqhvajry08ueg99ynwgd2sdntrq22gensffcj03r3yjv4cv4j20ee8vujxve3fssj2demyvknzwe3glqt6t954vknpdvurthpc9fpex7t97nvqryeqpjrpscap6q0zvfpgv3nxzpy6wmx24k9xcu35vuatm5zvn7t084ec7tlw2gh0av9xwumwkv02hats66l5hkwd55rwkm2q8fsd4zvqwpvqqqqtdc6rp
|
|
155
185
|
HRP: genesis
|
|
156
|
-
DATA:
|
|
186
|
+
DATA: 000409190707111719041a120308120a060c161408110d091b090009021b1e1d150e190215010d0a1603091e1f0b100609090d1a1c1a13030c120c0c0f1c020d1d1a0e170b1c17021018121e0a021c121a1c0d161b16131d1609130f1d13180f1e081d041d0a110f110d1313081c11100600180b000c08140c1e130e0f090c160e0018191e1d1c0016060c11101214121e19070d1a0c1c15020414001f10100c09090600181806001809080e180507021913031100030216141b100908160c1213120f1912011f07021c13190d1900170c1d1203040f071c1908050504130e080d0a100d130b03000a0a08191310090918120f11031104120c15180c15120a0f1919070c1c12060c1911091010120a0d191b040c1613020e1911081f000b1a0b0514150c1613010d0c1c030b17011805090119061e0b051e130c00030419000112030110181d011a000f020c0901080c1113060201041a0e1b060a15160506181c11140c1c1d0b1b14020c131e0b0f071519181e0b1f0e0a08170f1d0c05060e1c1b0e160c0f0a171d0b101a1a1f1417160e0d1414030e161b0a000709100d15020c000e010c00000000
|
|
157
187
|
TYPE: bech32
|
|
158
188
|
|
|
159
|
-
Note: `DATA` is not bit-converted.
|
|
160
|
-
|
|
161
189
|
If bech32 string has segwit hrp, it will also output witness version and witness program:
|
|
162
190
|
|
|
163
191
|
$ bech32 decode bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y
|
|
164
192
|
HRP: bc
|
|
165
|
-
DATA:
|
|
193
|
+
DATA: 010e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e160e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e16
|
|
166
194
|
TYPE: bech32m
|
|
167
195
|
WITNESS VERSION: 1
|
|
168
196
|
WITNESS PROGRAM: 751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6
|
|
@@ -171,13 +199,25 @@ If bech32 string has NIP-19 hrp, it will also output NIP-19 entry:
|
|
|
171
199
|
|
|
172
200
|
$ bech32 decode nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p
|
|
173
201
|
HRP: nprofile
|
|
174
|
-
DATA:
|
|
202
|
+
DATA: 00001003171c0606071f051906111114001e17190f090f051d19120f1502011d02011f0f13190a18081c16041d0e0d0a151b1d040b07080101151b17061c191a051c1717040b1318051911161e1b080102151b17061c191a051c1716081a13020c0519121c1c1b010c111516040b13030d1d1610
|
|
175
203
|
TYPE: bech32
|
|
176
204
|
NIP19 Entities:
|
|
177
205
|
special: 3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d
|
|
178
206
|
relay: wss://r.x.com
|
|
179
207
|
relay: wss://djbas.sadkb.com
|
|
180
208
|
|
|
209
|
+
If sp address, it will also output scan/spend public key:
|
|
210
|
+
|
|
211
|
+
$ bech32 decode sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv
|
|
212
|
+
HRP: sp
|
|
213
|
+
DATA: 000008100b191e160517060f00090b081a001b0e1f16000b0e1c041a180418041d0c021b02120714181a000d0917120d010d120b0d0800121c190602161a1b1c030e141a101c0411190f030d0a1808000c0418060b0b0d0d0e100c0806190a1c100901061c1b031e0f0618
|
|
214
|
+
TYPE: bech32m
|
|
215
|
+
version: 0
|
|
216
|
+
scan public key: 0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4
|
|
217
|
+
spend public key: 025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36
|
|
218
|
+
|
|
219
|
+
Note: `DATA` is data without bit conversion. When used, the `DATA` must be converted from 5-bit to 8-bit and padded as necessary.
|
|
220
|
+
|
|
181
221
|
## License
|
|
182
222
|
|
|
183
223
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Steepfile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Steepfile
|
|
2
|
+
target :lib do
|
|
3
|
+
signature "sig"
|
|
4
|
+
|
|
5
|
+
check "lib"
|
|
6
|
+
|
|
7
|
+
library "stringio"
|
|
8
|
+
|
|
9
|
+
# Configure diagnostic severity
|
|
10
|
+
# These errors are from Ruby code patterns that are runtime-safe but hard to express in RBS
|
|
11
|
+
configure_code_diagnostics do |hash|
|
|
12
|
+
# Suppress errors for method calls on potentially nil values
|
|
13
|
+
# The actual code handles nil cases properly at runtime
|
|
14
|
+
hash[Steep::Diagnostic::Ruby::NoMethod] = :hint
|
|
15
|
+
hash[Steep::Diagnostic::Ruby::ArgumentTypeMismatch] = :hint
|
|
16
|
+
hash[Steep::Diagnostic::Ruby::MethodBodyTypeMismatch] = :hint
|
|
17
|
+
hash[Steep::Diagnostic::Ruby::UnannotatedEmptyCollection] = :hint
|
|
18
|
+
end
|
|
19
|
+
end
|
data/bech32.gemspec
CHANGED
|
@@ -13,8 +13,10 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
spec.description = %q(The implementation of Bech32 encoder and decoder.)
|
|
14
14
|
spec.homepage = 'https://github.com/azuchi/bech32rb'
|
|
15
15
|
spec.license = 'MIT'
|
|
16
|
+
spec.metadata = { 'rubygems_mfa_required' => 'true' }
|
|
16
17
|
|
|
17
18
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
19
|
+
spec.files += Dir['sig/**/*.rbs']
|
|
18
20
|
spec.bindir = 'exe'
|
|
19
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
20
22
|
spec.require_paths = ['lib']
|
data/exe/bech32
CHANGED
|
@@ -25,13 +25,14 @@ class CLI < Thor
|
|
|
25
25
|
DATA: #{data.pack('C*').unpack1('H*')}
|
|
26
26
|
TYPE: #{spec == Bech32::Encoding::BECH32 ? 'bech32' : 'bech32m'}
|
|
27
27
|
EOS
|
|
28
|
-
|
|
28
|
+
case hrp
|
|
29
|
+
when Bech32::SegwitAddr::HRP_MAINNET, Bech32::SegwitAddr::HRP_TESTNET, Bech32::SegwitAddr::HRP_REGTEST
|
|
29
30
|
addr = Bech32::SegwitAddr.new(bech32_str)
|
|
30
31
|
puts <<~EOS
|
|
31
32
|
WITNESS VERSION: #{addr.ver}
|
|
32
33
|
WITNESS PROGRAM: #{addr.prog.pack('C*').unpack1('H*')}
|
|
33
34
|
EOS
|
|
34
|
-
|
|
35
|
+
when *Bech32::Nostr::NIP19::ALL_PREFIXES
|
|
35
36
|
entity = Bech32::Nostr::NIP19.decode(bech32_str)
|
|
36
37
|
if entity.is_a?(Bech32::Nostr::BareEntity)
|
|
37
38
|
puts <<~EOS
|
|
@@ -43,6 +44,13 @@ class CLI < Thor
|
|
|
43
44
|
puts " #{entry.to_s}"
|
|
44
45
|
end
|
|
45
46
|
end
|
|
47
|
+
when Bech32::SilentPaymentAddr::HRP_MAINNET, Bech32::SilentPaymentAddr::HRP_TESTNET
|
|
48
|
+
addr = Bech32::SilentPaymentAddr.parse(bech32_str)
|
|
49
|
+
puts <<~EOS
|
|
50
|
+
version: #{addr.version}
|
|
51
|
+
scan public key: #{addr.scan_key}
|
|
52
|
+
spend public key: #{addr.spend_key}
|
|
53
|
+
EOS
|
|
46
54
|
end
|
|
47
55
|
else
|
|
48
56
|
puts 'Can not decode.'
|
data/lib/bech32/nostr/entity.rb
CHANGED
|
@@ -110,37 +110,42 @@ module Bech32
|
|
|
110
110
|
buf = ::StringIO.new(data)
|
|
111
111
|
entries = []
|
|
112
112
|
until buf.eof?
|
|
113
|
-
|
|
113
|
+
header = buf.read(2)
|
|
114
|
+
raise ArgumentError, "Invalid TLV: truncated header." if header.nil? || header.bytesize < 2
|
|
115
|
+
type, len = header.unpack('CC')
|
|
116
|
+
value = buf.read(len)
|
|
117
|
+
raise ArgumentError, "Invalid TLV: truncated value." if value.nil? ? len > 0 : value.bytesize < len
|
|
118
|
+
value ||= ''
|
|
114
119
|
case type
|
|
115
120
|
when TYPE_SPECIAL # special
|
|
116
121
|
case hrp
|
|
117
122
|
when NIP19::HRP_PROFILE
|
|
118
|
-
entries << TLVEntry.new(type,
|
|
123
|
+
entries << TLVEntry.new(type, value.unpack1('H*'), 'pubkey')
|
|
119
124
|
when NIP19::HRP_RELAY
|
|
120
|
-
entries << TLVEntry.new(type,
|
|
125
|
+
entries << TLVEntry.new(type, value, 'relay')
|
|
121
126
|
when NIP19::HRP_EVENT
|
|
122
|
-
entries << TLVEntry.new(type,
|
|
127
|
+
entries << TLVEntry.new(type, value.unpack1('H*'), 'id')
|
|
123
128
|
when NIP19::HRP_EVENT_COORDINATE
|
|
124
|
-
entries << TLVEntry.new(type,
|
|
129
|
+
entries << TLVEntry.new(type, value, 'identifier')
|
|
125
130
|
end
|
|
126
131
|
when TYPE_RELAY # relay
|
|
127
132
|
case hrp
|
|
128
133
|
when NIP19::HRP_PROFILE, NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
|
|
129
|
-
entries << TLVEntry.new(type,
|
|
134
|
+
entries << TLVEntry.new(type, value, 'relay')
|
|
130
135
|
else
|
|
131
136
|
raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
|
|
132
137
|
end
|
|
133
138
|
when TYPE_AUTHOR # author
|
|
134
139
|
case hrp
|
|
135
140
|
when NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
|
|
136
|
-
entries << TLVEntry.new(type,
|
|
141
|
+
entries << TLVEntry.new(type, value.unpack1('H*'), 'author')
|
|
137
142
|
else
|
|
138
143
|
raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
|
|
139
144
|
end
|
|
140
145
|
when TYPE_KIND # kind
|
|
141
146
|
case hrp
|
|
142
147
|
when NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
|
|
143
|
-
entries << TLVEntry.new(type,
|
|
148
|
+
entries << TLVEntry.new(type, value.unpack1('H*').to_s.to_i(16), 'kind')
|
|
144
149
|
else
|
|
145
150
|
raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
|
|
146
151
|
end
|
data/lib/bech32/nostr/nip19.rb
CHANGED
|
@@ -28,7 +28,9 @@ module Bech32
|
|
|
28
28
|
raise ArgumentError, 'Invalid nip19 string.' if hrp.nil?
|
|
29
29
|
raise ArgumentError, 'Invalid bech32 spec.' unless spec == Bech32::Encoding::BECH32
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
converted = Bech32.convert_bits(data, 5, 8, false)
|
|
32
|
+
raise ArgumentError, 'Invalid data.' if converted.nil?
|
|
33
|
+
entity = converted.pack('C*')
|
|
32
34
|
raise ArgumentError, "Data whose HRP is #{hrp} must be 32 bytes." if BARE_PREFIXES.include?(hrp) && entity.bytesize != 32
|
|
33
35
|
if BARE_PREFIXES.include?(hrp)
|
|
34
36
|
BareEntity.new(hrp, entity.unpack1('H*'))
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Bech32
|
|
2
|
+
# BIP-352 silent payment address.
|
|
3
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#user-content-Address_encoding
|
|
4
|
+
class SilentPaymentAddr
|
|
5
|
+
HRP_MAINNET = 'sp'
|
|
6
|
+
HRP_TESTNET = 'tsp'
|
|
7
|
+
|
|
8
|
+
attr_reader :hrp
|
|
9
|
+
attr_reader :version
|
|
10
|
+
attr_reader :scan_key
|
|
11
|
+
attr_reader :spend_key
|
|
12
|
+
|
|
13
|
+
# Constructor
|
|
14
|
+
# @param [String] hrp HRP for silent payment address.
|
|
15
|
+
# @param [Integer] version The version of sp address.
|
|
16
|
+
# @param [String] scan_key The scan public key with hex format.
|
|
17
|
+
# @param [String] spend_key The spend public key with hex format.
|
|
18
|
+
def initialize(hrp, version, scan_key, spend_key)
|
|
19
|
+
raise ArgumentError, "hrp must be sp or tsp." unless [HRP_MAINNET, HRP_TESTNET].include?(hrp)
|
|
20
|
+
raise ArgumentError, "version must be Integer." unless version.is_a?(Integer)
|
|
21
|
+
raise ArgumentError, "scan_key must be String." unless scan_key.is_a?(String)
|
|
22
|
+
raise ArgumentError, "spend_key must be String." unless spend_key.is_a?(String)
|
|
23
|
+
raise ArgumentError, 'scan_key must be 33 bytes.' unless [scan_key].pack('H*').bytesize == 33
|
|
24
|
+
raise ArgumentError, 'spend_key must be 33 bytes.' unless [spend_key].pack('H*').bytesize == 33
|
|
25
|
+
@hrp = hrp
|
|
26
|
+
@version = version
|
|
27
|
+
@scan_key = scan_key
|
|
28
|
+
@spend_key = spend_key
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Parse silent payment address.
|
|
32
|
+
# @param [String] addr Silent payment address.
|
|
33
|
+
# @return [Bech32::SilentPaymentAddr]
|
|
34
|
+
# @raise [ArgumentError]
|
|
35
|
+
def self.parse(addr)
|
|
36
|
+
raise ArgumentError, "addr must be String." unless addr.is_a?(String)
|
|
37
|
+
hrp, data, spec = Bech32.decode(addr, addr.length)
|
|
38
|
+
raise ArgumentError, "addr must be encoded with bech32m." unless spec == Bech32::Encoding::BECH32M
|
|
39
|
+
raise ArgumentError, 'Invalid hrp.' if hrp.nil? || data[0].nil? || ![HRP_MAINNET, HRP_TESTNET].include?(hrp)
|
|
40
|
+
version = data[0]
|
|
41
|
+
converted = Bech32.convert_bits(data[1..-1], 5, 8, false)
|
|
42
|
+
raise ArgumentError, "Invalid data." if converted.nil?
|
|
43
|
+
keys = converted.pack('C*').unpack1('H*')
|
|
44
|
+
raise ArgumentError, "Invalid key size." unless keys.length == 132
|
|
45
|
+
scan = keys[0...66]
|
|
46
|
+
spend = keys[66..-1]
|
|
47
|
+
Bech32::SilentPaymentAddr.new(hrp, version, scan, spend)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Get silent payment address.
|
|
51
|
+
# @return [String]
|
|
52
|
+
def to_s
|
|
53
|
+
keys = scan_key + spend_key
|
|
54
|
+
data = [keys].pack('H*').unpack('C*')
|
|
55
|
+
Bech32.encode(hrp, [version] + Bech32.convert_bits(data, 8, 5), Bech32::Encoding::BECH32M)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/bech32/version.rb
CHANGED
data/lib/bech32.rb
CHANGED
|
@@ -7,6 +7,7 @@ module Bech32
|
|
|
7
7
|
|
|
8
8
|
autoload :SegwitAddr, 'bech32/segwit_addr'
|
|
9
9
|
autoload :Nostr, 'bech32/nostr'
|
|
10
|
+
autoload :SilentPaymentAddr, 'bech32/silent_payment_addr'
|
|
10
11
|
|
|
11
12
|
SEPARATOR = '1'
|
|
12
13
|
|
|
@@ -49,7 +50,7 @@ module Bech32
|
|
|
49
50
|
bech = bech.downcase
|
|
50
51
|
# check data length
|
|
51
52
|
pos = bech.rindex(SEPARATOR)
|
|
52
|
-
return nil if pos.nil? || pos + 7 > bech.length || bech.length > max_length
|
|
53
|
+
return nil if pos.nil? || pos < 1 || pos + 7 > bech.length || bech.length > max_length
|
|
53
54
|
# check valid charset
|
|
54
55
|
bech[pos+1..-1].each_char{|c|return nil unless CHARSET.include?(c)}
|
|
55
56
|
# split hrp and data
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Bech32
|
|
2
|
+
VERSION: String
|
|
3
|
+
|
|
4
|
+
module Encoding
|
|
5
|
+
BECH32: Integer
|
|
6
|
+
BECH32M: Integer
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
SEPARATOR: String
|
|
10
|
+
CHARSET: Array[String]
|
|
11
|
+
BECH32M_CONST: Integer
|
|
12
|
+
|
|
13
|
+
# Encode hrp and data to bech32/bech32m string.
|
|
14
|
+
def self.encode: (String hrp, Array[Integer] data, Integer spec) -> String
|
|
15
|
+
|
|
16
|
+
# Decode bech32/bech32m string. Returns nil if invalid.
|
|
17
|
+
def self.decode: (String bech, ?Integer max_length) -> [String, Array[Integer], Integer]?
|
|
18
|
+
|
|
19
|
+
# Convert bits from one base to another.
|
|
20
|
+
def self.convert_bits: (Array[Integer] data, Integer from, Integer to, ?bool padding) -> Array[Integer]?
|
|
21
|
+
|
|
22
|
+
# Create checksum for hrp and data.
|
|
23
|
+
def self.create_checksum: (String hrp, Array[Integer] data, Integer spec) -> Array[Integer]
|
|
24
|
+
|
|
25
|
+
# Verify checksum. Returns encoding spec if valid, nil otherwise.
|
|
26
|
+
def self.verify_checksum: (String hrp, Array[Integer] data) -> Integer?
|
|
27
|
+
|
|
28
|
+
# module_function methods are also available as instance methods
|
|
29
|
+
def encode: (String hrp, Array[Integer] data, Integer spec) -> String
|
|
30
|
+
def decode: (String bech, ?Integer max_length) -> [String, Array[Integer], Integer]?
|
|
31
|
+
def convert_bits: (Array[Integer] data, Integer from, Integer to, ?bool padding) -> Array[Integer]?
|
|
32
|
+
def create_checksum: (String hrp, Array[Integer] data, Integer spec) -> Array[Integer]
|
|
33
|
+
def verify_checksum: (String hrp, Array[Integer] data) -> Integer?
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
# Expand HRP for checksum computation.
|
|
38
|
+
def self.expand_hrp: (String hrp) -> Array[Integer]
|
|
39
|
+
|
|
40
|
+
# Compute polymod checksum.
|
|
41
|
+
def self.polymod: (Array[Integer] values) -> Integer
|
|
42
|
+
|
|
43
|
+
def expand_hrp: (String hrp) -> Array[Integer]
|
|
44
|
+
def polymod: (Array[Integer] values) -> Integer
|
|
45
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Bech32
|
|
2
|
+
module Nostr
|
|
3
|
+
class BareEntity
|
|
4
|
+
attr_reader hrp: String
|
|
5
|
+
attr_reader data: String
|
|
6
|
+
|
|
7
|
+
# Initialize bare entity.
|
|
8
|
+
def initialize: (String hrp, String data) -> void
|
|
9
|
+
|
|
10
|
+
# Encode to bech32 string.
|
|
11
|
+
def encode: () -> String
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class TLVEntry
|
|
15
|
+
attr_reader type: Integer
|
|
16
|
+
attr_reader label: String?
|
|
17
|
+
attr_reader value: String | Integer
|
|
18
|
+
|
|
19
|
+
# Initialize TLV entry.
|
|
20
|
+
def initialize: (Integer type, String | Integer value, ?String? label) -> void
|
|
21
|
+
|
|
22
|
+
# Convert to binary payload.
|
|
23
|
+
def to_payload: () -> String
|
|
24
|
+
|
|
25
|
+
# String representation.
|
|
26
|
+
def to_s: () -> String
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# Check if string is hex encoded.
|
|
31
|
+
def hex_string?: (String str) -> bool
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class TLVEntity
|
|
35
|
+
TYPE_SPECIAL: Integer
|
|
36
|
+
TYPE_RELAY: Integer
|
|
37
|
+
TYPE_AUTHOR: Integer
|
|
38
|
+
TYPE_KIND: Integer
|
|
39
|
+
TYPES: Array[Integer]
|
|
40
|
+
|
|
41
|
+
attr_reader hrp: String
|
|
42
|
+
attr_reader entries: Array[TLVEntry]
|
|
43
|
+
|
|
44
|
+
# Initialize TLV entity.
|
|
45
|
+
def initialize: (String hrp, Array[TLVEntry] entries) -> void
|
|
46
|
+
|
|
47
|
+
# Parse TLV entity from binary data.
|
|
48
|
+
def self.parse: (String hrp, String data) -> TLVEntity
|
|
49
|
+
|
|
50
|
+
# Encode to bech32 string.
|
|
51
|
+
def encode: () -> String
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Bech32
|
|
2
|
+
module Nostr
|
|
3
|
+
module NIP19
|
|
4
|
+
HRP_PUBKEY: String
|
|
5
|
+
HRP_PRIVATE_KEY: String
|
|
6
|
+
HRP_NOTE_ID: String
|
|
7
|
+
HRP_PROFILE: String
|
|
8
|
+
HRP_EVENT: String
|
|
9
|
+
HRP_RELAY: String
|
|
10
|
+
HRP_EVENT_COORDINATE: String
|
|
11
|
+
|
|
12
|
+
BARE_PREFIXES: Array[String]
|
|
13
|
+
TLV_PREFIXES: Array[String]
|
|
14
|
+
ALL_PREFIXES: Array[String]
|
|
15
|
+
|
|
16
|
+
# Decode NIP-19 bech32 string.
|
|
17
|
+
def self.decode: (String string) -> (BareEntity | TLVEntity)
|
|
18
|
+
|
|
19
|
+
# module_function methods are also available as instance methods
|
|
20
|
+
def decode: (String string) -> (BareEntity | TLVEntity)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Bech32
|
|
2
|
+
class SegwitAddr
|
|
3
|
+
HRP_MAINNET: String
|
|
4
|
+
HRP_TESTNET: String
|
|
5
|
+
HRP_REGTEST: String
|
|
6
|
+
|
|
7
|
+
attr_accessor hrp: String
|
|
8
|
+
attr_accessor ver: Integer?
|
|
9
|
+
attr_accessor prog: Array[Integer]?
|
|
10
|
+
|
|
11
|
+
# Initialize SegwitAddr. Optionally parse from address string.
|
|
12
|
+
def initialize: (?String? addr) -> void
|
|
13
|
+
|
|
14
|
+
# Generate script pubkey from witness version and program.
|
|
15
|
+
def to_script_pubkey: () -> String
|
|
16
|
+
|
|
17
|
+
# Parse script pubkey into witness version and program.
|
|
18
|
+
def script_pubkey=: (String script_pubkey) -> void
|
|
19
|
+
|
|
20
|
+
# Generate bech32/bech32m address string.
|
|
21
|
+
def addr: () -> String
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
# Parse address string into hrp, version and program.
|
|
26
|
+
def parse_addr: (String addr) -> void
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Bech32
|
|
2
|
+
# BIP-352 silent payment address.
|
|
3
|
+
class SilentPaymentAddr
|
|
4
|
+
HRP_MAINNET: String
|
|
5
|
+
HRP_TESTNET: String
|
|
6
|
+
|
|
7
|
+
attr_reader hrp: String
|
|
8
|
+
attr_reader version: Integer
|
|
9
|
+
attr_reader scan_key: String
|
|
10
|
+
attr_reader spend_key: String
|
|
11
|
+
|
|
12
|
+
# Initialize SilentPaymentAddr.
|
|
13
|
+
def initialize: (String hrp, Integer version, String scan_key, String spend_key) -> void
|
|
14
|
+
|
|
15
|
+
# Parse silent payment address string.
|
|
16
|
+
def self.parse: (String addr) -> SilentPaymentAddr
|
|
17
|
+
|
|
18
|
+
# Generate silent payment address string.
|
|
19
|
+
def to_s: () -> String
|
|
20
|
+
end
|
|
21
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bech32
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shigeyuki Azuchi
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: thor
|
|
@@ -70,6 +69,7 @@ files:
|
|
|
70
69
|
- LICENSE.txt
|
|
71
70
|
- README.md
|
|
72
71
|
- Rakefile
|
|
72
|
+
- Steepfile
|
|
73
73
|
- bech32.gemspec
|
|
74
74
|
- bin/console
|
|
75
75
|
- bin/setup
|
|
@@ -79,12 +79,18 @@ files:
|
|
|
79
79
|
- lib/bech32/nostr/entity.rb
|
|
80
80
|
- lib/bech32/nostr/nip19.rb
|
|
81
81
|
- lib/bech32/segwit_addr.rb
|
|
82
|
+
- lib/bech32/silent_payment_addr.rb
|
|
82
83
|
- lib/bech32/version.rb
|
|
84
|
+
- sig/bech32/bech32.rbs
|
|
85
|
+
- sig/bech32/nostr/entity.rbs
|
|
86
|
+
- sig/bech32/nostr/nip19.rbs
|
|
87
|
+
- sig/bech32/segwit_addr.rbs
|
|
88
|
+
- sig/bech32/silent_payment_addr.rbs
|
|
83
89
|
homepage: https://github.com/azuchi/bech32rb
|
|
84
90
|
licenses:
|
|
85
91
|
- MIT
|
|
86
|
-
metadata:
|
|
87
|
-
|
|
92
|
+
metadata:
|
|
93
|
+
rubygems_mfa_required: 'true'
|
|
88
94
|
rdoc_options: []
|
|
89
95
|
require_paths:
|
|
90
96
|
- lib
|
|
@@ -99,8 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
99
105
|
- !ruby/object:Gem::Version
|
|
100
106
|
version: '0'
|
|
101
107
|
requirements: []
|
|
102
|
-
rubygems_version:
|
|
103
|
-
signing_key:
|
|
108
|
+
rubygems_version: 4.0.3
|
|
104
109
|
specification_version: 4
|
|
105
110
|
summary: The implementation of Bech32 encoder and decoder.
|
|
106
111
|
test_files: []
|