bech32 1.5.0 → 1.6.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 368eb6deb6248ddb8f5cbcba18ec90a3ed11b84f60a3de80bb59301eb5c7f1a2
4
- data.tar.gz: a0d8654790ab71f8460eecdbf17248e8acd3748bf2011b94afe32dd079b2248b
3
+ metadata.gz: 535da278f3fe4aa746212b6dbefb7bc34f691fe35cc62af48d7445f20e14510f
4
+ data.tar.gz: d01f1e5560dc1efcfc9f362b103119d72f74cf04a7cd3b5bb6e1f236ffad2dc1
5
5
  SHA512:
6
- metadata.gz: f3aad0caf6fce5ce425bd0c4e59e934ecfe96bc6fec30cd5c5c7a6ee73f266824c7f90193f4e008ea24f8a65239d13c3763d35c8211d5fa2485cb8317e56d527
7
- data.tar.gz: 4891f6c6f80b6b11cd136637c9fd204070a2fab2b170919b34c976219d9885eb8ed43ba688b2002fcc1db4df4b2755d1b169744cfaea578e64336afa327b4b65
6
+ metadata.gz: 3adb0de41823618cded9061c3c7bb4802363eea877d6ca44cf56c02e5bb6f8a7829943d171a9c91419d99ce7ff2abe6652ef3de0c907ecfee8d4b06da87d641a
7
+ data.tar.gz: bf708f4783d906e79e03dfc4ba420a8a02ed985fe23dc62d1c4024045df9d42c746f421efc9576648eb2e27213e26539606aeca85a04572e4dc2417e0cf7b72f
@@ -19,7 +19,7 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['3.0', '3.1', '3.2', '3.3', '3.4']
22
+ ruby-version: ['3.2', '3.3', '3.4', '4.0']
23
23
 
24
24
  steps:
25
25
  - uses: actions/checkout@v4
@@ -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-3.4.1
1
+ ruby-4.0.0
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in bech32.gemspec
4
4
  gemspec
5
+
6
+ group :development do
7
+ gem 'steep'
8
+ gem 'rbs'
9
+ end
data/README.md CHANGED
@@ -135,7 +135,7 @@ Supports encoding/decoding of Nostr's [NIP-19](https://github.com/nostr-protocol
135
135
  ```ruby
136
136
  # Decode bare entity
137
137
  bech32 = 'npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg'
138
- entity = Bech32::Nostr::NIP19.parse(bech32)
138
+ entity = Bech32::Nostr::NIP19.decode(bech32)
139
139
  entity.hrp
140
140
  => 'npub'
141
141
  entity.data
@@ -143,7 +143,7 @@ entity.data
143
143
 
144
144
  # Decode tlv entity
145
145
  bech32 = 'nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p'
146
- entity = Bech32::Nostr::NIP19.parse(bech32)
146
+ entity = Bech32::Nostr::NIP19.decode(bech32)
147
147
  entity.hrp
148
148
  => 'nprofile'
149
149
  entity.entries[0].value
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
@@ -7,13 +7,16 @@ class CLI < Thor
7
7
 
8
8
  desc 'encode hrp data bech32/bech32m', 'Encoding data to bech32/bech32m string.'
9
9
  def encode(hrp, data, type)
10
- if type && !['bech32', 'bech32m'].include?(type)
10
+ unless ['bech32', 'bech32m'].include?(type)
11
11
  puts 'Invalid type value. type must be bech32 or bech32m.'
12
- else
13
- spec = type.nil? || type == 'bech32' ? 1 : 2
14
- data = [data].pack('H*').unpack('C*')
15
- puts Bech32.encode(hrp, data, spec)
12
+ exit 1
16
13
  end
14
+ spec = type == 'bech32' ? Bech32::Encoding::BECH32 : Bech32::Encoding::BECH32M
15
+ data = [data].pack('H*').unpack('C*')
16
+ puts Bech32.encode(hrp, data, spec)
17
+ rescue ArgumentError => e
18
+ puts "Can not encode: #{e.message}"
19
+ exit 1
17
20
  end
18
21
 
19
22
  desc 'decode "bech32string"', 'Decoding bech32/bech32m string.'
@@ -54,7 +57,11 @@ class CLI < Thor
54
57
  end
55
58
  else
56
59
  puts 'Can not decode.'
60
+ exit 1
57
61
  end
62
+ rescue ArgumentError => e
63
+ puts "Can not decode: #{e.message}"
64
+ exit 1
58
65
  end
59
66
 
60
67
  end
@@ -1,3 +1,5 @@
1
+ require 'stringio'
2
+
1
3
  module Bech32
2
4
  module Nostr
3
5
  class BareEntity
@@ -35,15 +37,30 @@ module Bech32
35
37
  @label = label
36
38
  end
37
39
 
40
+ # Maximum byte length of a TLV value (the length field is 1 byte).
41
+ MAX_VALUE_LENGTH = 255
42
+
38
43
  # Convert to binary data.
44
+ # @param [String] hrp human-readable part of the entity this entry belongs to.
45
+ # It determines whether a special entry's value is a hex string (nprofile, nevent)
46
+ # or a raw string (nrelay, naddr). If omitted, a special value is treated as hex
47
+ # only when it looks like a hex string.
39
48
  # @return [String] binary data.
40
- def to_payload
49
+ # @raise [ArgumentError] if the value is out of range or longer than MAX_VALUE_LENGTH bytes.
50
+ def to_payload(hrp = nil)
41
51
  data = if value.is_a?(Integer)
52
+ unless value.between?(0, 0xffffffff)
53
+ raise ArgumentError, "Integer value must be between 0 and #{0xffffffff}."
54
+ end
42
55
  [value].pack('N')
56
+ elsif hex_value?(hrp)
57
+ raise ArgumentError, "Value of type #{type} must be a hex string." unless hex_string?(value)
58
+ [value].pack('H*')
43
59
  else
44
- hex_string?(value) ? [value].pack('H*') : value
60
+ value.b
45
61
  end
46
62
  len = data.bytesize
63
+ raise ArgumentError, "Value must be at most #{MAX_VALUE_LENGTH} bytes." if len > MAX_VALUE_LENGTH
47
64
  [type, len].pack('CC') + data
48
65
  end
49
66
 
@@ -65,6 +82,20 @@ module Bech32
65
82
 
66
83
  private
67
84
 
85
+ # Check whether the value of this entry is a hex-encoded string.
86
+ # @param [String] hrp human-readable part (may be nil).
87
+ # @return [Boolean]
88
+ def hex_value?(hrp)
89
+ case type
90
+ when TLVEntity::TYPE_AUTHOR
91
+ true
92
+ when TLVEntity::TYPE_SPECIAL
93
+ hrp.nil? ? hex_string?(value) : [NIP19::HRP_PROFILE, NIP19::HRP_EVENT].include?(hrp)
94
+ else
95
+ false
96
+ end
97
+ end
98
+
68
99
  # Check whether +str+ is hex string or not.
69
100
  # @param [String] str string.
70
101
  # @return [Boolean]
@@ -110,37 +141,45 @@ module Bech32
110
141
  buf = ::StringIO.new(data)
111
142
  entries = []
112
143
  until buf.eof?
113
- type, len = buf.read(2).unpack('CC')
144
+ header = buf.read(2)
145
+ raise ArgumentError, "Invalid TLV: truncated header." if header.nil? || header.bytesize < 2
146
+ type, len = header.unpack('CC')
147
+ value = buf.read(len)
148
+ raise ArgumentError, "Invalid TLV: truncated value." if value.nil? ? len > 0 : value.bytesize < len
149
+ value ||= ''
114
150
  case type
115
151
  when TYPE_SPECIAL # special
116
152
  case hrp
117
153
  when NIP19::HRP_PROFILE
118
- entries << TLVEntry.new(type, buf.read(len).unpack1('H*'), 'pubkey')
154
+ entries << TLVEntry.new(type, value.unpack1('H*'), 'pubkey')
119
155
  when NIP19::HRP_RELAY
120
- entries << TLVEntry.new(type, buf.read(len), 'relay')
156
+ entries << TLVEntry.new(type, value.force_encoding(::Encoding::UTF_8), 'relay')
121
157
  when NIP19::HRP_EVENT
122
- entries << TLVEntry.new(type, buf.read(len).unpack1('H*'), 'id')
158
+ entries << TLVEntry.new(type, value.unpack1('H*'), 'id')
123
159
  when NIP19::HRP_EVENT_COORDINATE
124
- entries << TLVEntry.new(type, buf.read(len), 'identifier')
160
+ entries << TLVEntry.new(type, value.force_encoding(::Encoding::UTF_8), 'identifier')
161
+ else
162
+ raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
125
163
  end
126
164
  when TYPE_RELAY # relay
127
165
  case hrp
128
166
  when NIP19::HRP_PROFILE, NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
129
- entries << TLVEntry.new(type, buf.read(len), 'relay')
167
+ entries << TLVEntry.new(type, value.force_encoding(::Encoding::UTF_8), 'relay')
130
168
  else
131
169
  raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
132
170
  end
133
171
  when TYPE_AUTHOR # author
134
172
  case hrp
135
173
  when NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
136
- entries << TLVEntry.new(type, buf.read(len).unpack1('H*'), 'author')
174
+ entries << TLVEntry.new(type, value.unpack1('H*'), 'author')
137
175
  else
138
176
  raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
139
177
  end
140
178
  when TYPE_KIND # kind
141
179
  case hrp
142
180
  when NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
143
- entries << TLVEntry.new(type, buf.read(len).unpack1('H*').to_i(16), 'kind')
181
+ raise ArgumentError, 'Invalid TLV: kind must be 4 bytes.' unless value.bytesize == 4
182
+ entries << TLVEntry.new(type, value.unpack1('N'), 'kind')
144
183
  else
145
184
  raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
146
185
  end
@@ -155,7 +194,7 @@ module Bech32
155
194
  # Encode tlv entity to bech32 string.
156
195
  # @return [String] bech32 string.
157
196
  def encode
158
- data = entries.map(&:to_payload).join
197
+ data = entries.map { |e| e.to_payload(hrp) }.join
159
198
  Bech32.encode(hrp, Bech32.convert_bits(data.unpack('C*'), 8, 5), Bech32::Encoding::BECH32)
160
199
  end
161
200
  end
@@ -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
- entity = Bech32.convert_bits(data, 5, 8, false).pack('C*')
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*'))
data/lib/bech32/nostr.rb CHANGED
@@ -2,6 +2,7 @@ module Bech32
2
2
  module Nostr
3
3
  autoload :NIP19, 'bech32/nostr/nip19'
4
4
  autoload :BareEntity, 'bech32/nostr/entity'
5
+ autoload :TLVEntry, 'bech32/nostr/entity'
5
6
  autoload :TLVEntity, 'bech32/nostr/entity'
6
7
  end
7
8
 
@@ -10,6 +10,8 @@ module Bech32
10
10
  attr_accessor :ver # witness version
11
11
  attr_accessor :prog # witness program
12
12
 
13
+ # @param [String] addr segwit address. If given, it is parsed into hrp, witness version and program.
14
+ # @raise [ArgumentError] if addr is not a valid segwit address.
13
15
  def initialize(addr = nil)
14
16
  @hrp = HRP_MAINNET
15
17
  parse_addr(addr) if addr
@@ -22,10 +24,26 @@ module Bech32
22
24
  end
23
25
 
24
26
  # parse script pubkey into witness version and witness program
27
+ # @param [String] script_pubkey segwit script pubkey with hex format.
28
+ # @raise [ArgumentError] if the script is not a valid segwit script pubkey.
25
29
  def script_pubkey=(script_pubkey)
26
- values = [script_pubkey].pack('H*').unpack("C*")
27
- @ver = values[0] == 0 ? values[0] : values[0] - 0x50
28
- @prog = values[2..-1]
30
+ raise ArgumentError, 'script_pubkey must be String.' unless script_pubkey.is_a?(String)
31
+ values = [script_pubkey].pack('H*').unpack('C*')
32
+ raise ArgumentError, 'Invalid segwit script pubkey.' if values.length < 2
33
+ op, push_len = values[0], values[1]
34
+ prog = values[2..-1]
35
+ ver = if op == 0
36
+ 0
37
+ elsif op.between?(0x51, 0x60) # OP_1..OP_16
38
+ op - 0x50
39
+ else
40
+ raise ArgumentError, 'Invalid segwit script pubkey.'
41
+ end
42
+ raise ArgumentError, 'Invalid segwit script pubkey.' unless push_len == prog.length
43
+ raise ArgumentError, 'Invalid witness program' if prog.length < 2 || prog.length > 40
44
+ raise ArgumentError, 'Invalid witness program with version 0' if ver == 0 && prog.length != 20 && prog.length != 32
45
+ @ver = ver
46
+ @prog = prog
29
47
  end
30
48
 
31
49
  # Returns segwit address string which generated from hrp, witness version and witness program.
@@ -38,13 +56,13 @@ module Bech32
38
56
 
39
57
  def parse_addr(addr)
40
58
  @hrp, data, spec = Bech32.decode(addr)
41
- raise 'Invalid address.' if hrp.nil? || data[0].nil? || ![HRP_MAINNET, HRP_TESTNET, HRP_REGTEST].include?(hrp)
59
+ raise ArgumentError, 'Invalid address.' if hrp.nil? || data[0].nil? || ![HRP_MAINNET, HRP_TESTNET, HRP_REGTEST].include?(hrp)
42
60
  @ver = data[0]
43
- raise 'Invalid witness version' if @ver > 16
61
+ raise ArgumentError, 'Invalid witness version' if @ver > 16
44
62
  @prog = Bech32.convert_bits(data[1..-1], 5, 8, false)
45
- raise 'Invalid witness program' if @prog.nil? || @prog.length < 2 || @prog.length > 40
46
- raise 'Invalid witness program with version 0' if @ver == 0 && (@prog.length != 20 && @prog.length != 32)
47
- raise 'Witness version and encoding spec do not match' if (@ver == 0 && spec != Bech32::Encoding::BECH32) || (@ver != 0 && spec != Bech32::Encoding::BECH32M)
63
+ raise ArgumentError, 'Invalid witness program' if @prog.nil? || @prog.length < 2 || @prog.length > 40
64
+ raise ArgumentError, 'Invalid witness program with version 0' if @ver == 0 && (@prog.length != 20 && @prog.length != 32)
65
+ raise ArgumentError, 'Witness version and encoding spec do not match' if (@ver == 0 && spec != Bech32::Encoding::BECH32) || (@ver != 0 && spec != Bech32::Encoding::BECH32M)
48
66
  end
49
67
 
50
68
  end
@@ -5,6 +5,9 @@ module Bech32
5
5
  HRP_MAINNET = 'sp'
6
6
  HRP_TESTNET = 'tsp'
7
7
 
8
+ # Maximum valid version. Version 31 is reserved as invalid by BIP-352.
9
+ MAX_VERSION = 30
10
+
8
11
  attr_reader :hrp
9
12
  attr_reader :version
10
13
  attr_reader :scan_key
@@ -18,6 +21,7 @@ module Bech32
18
21
  def initialize(hrp, version, scan_key, spend_key)
19
22
  raise ArgumentError, "hrp must be sp or tsp." unless [HRP_MAINNET, HRP_TESTNET].include?(hrp)
20
23
  raise ArgumentError, "version must be Integer." unless version.is_a?(Integer)
24
+ raise ArgumentError, "version must be between 0 and #{MAX_VERSION}." unless version.between?(0, MAX_VERSION)
21
25
  raise ArgumentError, "scan_key must be String." unless scan_key.is_a?(String)
22
26
  raise ArgumentError, "spend_key must be String." unless spend_key.is_a?(String)
23
27
  raise ArgumentError, 'scan_key must be 33 bytes.' unless [scan_key].pack('H*').bytesize == 33
@@ -38,7 +42,9 @@ module Bech32
38
42
  raise ArgumentError, "addr must be encoded with bech32m." unless spec == Bech32::Encoding::BECH32M
39
43
  raise ArgumentError, 'Invalid hrp.' if hrp.nil? || data[0].nil? || ![HRP_MAINNET, HRP_TESTNET].include?(hrp)
40
44
  version = data[0]
41
- keys = Bech32.convert_bits(data[1..-1], 5, 8, false).pack('C*').unpack1('H*')
45
+ converted = Bech32.convert_bits(data[1..-1], 5, 8, false)
46
+ raise ArgumentError, "Invalid data." if converted.nil?
47
+ keys = converted.pack('C*').unpack1('H*')
42
48
  raise ArgumentError, "Invalid key size." unless keys.length == 132
43
49
  scan = keys[0...66]
44
50
  spend = keys[66..-1]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bech32
4
- VERSION = '1.5.0'
4
+ VERSION = '1.6.0'
5
5
  end
data/lib/bech32.rb CHANGED
@@ -15,6 +15,9 @@ module Bech32
15
15
 
16
16
  BECH32M_CONST = 0x2bc830a3
17
17
 
18
+ # Maximum length of the human-readable part.
19
+ HRP_MAX_LENGTH = 83
20
+
18
21
  module_function
19
22
 
20
23
  # Returns the encoded Bech32 string.
@@ -26,7 +29,12 @@ module Bech32
26
29
  # <i>Generates:</i>
27
30
  # 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4' # bech
28
31
  #
32
+ # @param [String] hrp human-readable part (1 to 83 lowercase characters in the range 33-126).
33
+ # @param [Array<Integer>] data data values (each 0 to 31).
34
+ # @param [Integer] spec encoding spec, see Bech32::Encoding.
35
+ # @raise [ArgumentError] if hrp or data is invalid.
29
36
  def encode(hrp, data, spec)
37
+ validate_encode_args(hrp, data)
30
38
  checksummed = data + create_checksum(hrp, data, spec)
31
39
  hrp + SEPARATOR + checksummed.map{|i|CHARSET[i]}.join
32
40
  end
@@ -50,7 +58,7 @@ module Bech32
50
58
  bech = bech.downcase
51
59
  # check data length
52
60
  pos = bech.rindex(SEPARATOR)
53
- return nil if pos.nil? || pos + 7 > bech.length || bech.length > max_length
61
+ return nil if pos.nil? || pos < 1 || pos + 7 > bech.length || bech.length > max_length
54
62
  # check valid charset
55
63
  bech[pos+1..-1].each_char{|c|return nil unless CHARSET.include?(c)}
56
64
  # split hrp and data
@@ -117,6 +125,24 @@ module Bech32
117
125
  ret
118
126
  end
119
127
 
128
+ # Validate arguments of encode.
129
+ # @param [String] hrp human-readable part.
130
+ # @param [Array<Integer>] data data values.
131
+ # @raise [ArgumentError]
132
+ def validate_encode_args(hrp, data)
133
+ raise ArgumentError, 'hrp must be String.' unless hrp.is_a?(String)
134
+ unless hrp.length.between?(1, HRP_MAX_LENGTH)
135
+ raise ArgumentError, "hrp must be between 1 and #{HRP_MAX_LENGTH} characters."
136
+ end
137
+ if hrp.bytes.any? { |b| b < 33 || b > 126 } || hrp != hrp.downcase
138
+ raise ArgumentError, 'hrp must consist of lowercase characters in the range 33-126.'
139
+ end
140
+ raise ArgumentError, 'data must be Array.' unless data.is_a?(Array)
141
+ unless data.all? { |v| v.is_a?(Integer) && v.between?(0, 31) }
142
+ raise ArgumentError, 'data values must be Integer between 0 and 31.'
143
+ end
144
+ end
145
+
120
146
  # Compute Bech32 checksum
121
147
  def polymod(values)
122
148
  generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
@@ -129,6 +155,6 @@ module Bech32
129
155
  chk
130
156
  end
131
157
 
132
- private_class_method :polymod, :expand_hrp
158
+ private_class_method :polymod, :expand_hrp, :validate_encode_args
133
159
 
134
160
  end
@@ -0,0 +1,50 @@
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
+ HRP_MAX_LENGTH: Integer
13
+
14
+ # Encode hrp and data to bech32/bech32m string.
15
+ def self.encode: (String hrp, Array[Integer] data, Integer spec) -> String
16
+
17
+ # Decode bech32/bech32m string. Returns nil if invalid.
18
+ def self.decode: (String bech, ?Integer max_length) -> [String, Array[Integer], Integer]?
19
+
20
+ # Convert bits from one base to another.
21
+ def self.convert_bits: (Array[Integer] data, Integer from, Integer to, ?bool padding) -> Array[Integer]?
22
+
23
+ # Create checksum for hrp and data.
24
+ def self.create_checksum: (String hrp, Array[Integer] data, Integer spec) -> Array[Integer]
25
+
26
+ # Verify checksum. Returns encoding spec if valid, nil otherwise.
27
+ def self.verify_checksum: (String hrp, Array[Integer] data) -> Integer?
28
+
29
+ # module_function methods are also available as instance methods
30
+ def encode: (String hrp, Array[Integer] data, Integer spec) -> String
31
+ def decode: (String bech, ?Integer max_length) -> [String, Array[Integer], Integer]?
32
+ def convert_bits: (Array[Integer] data, Integer from, Integer to, ?bool padding) -> Array[Integer]?
33
+ def create_checksum: (String hrp, Array[Integer] data, Integer spec) -> Array[Integer]
34
+ def verify_checksum: (String hrp, Array[Integer] data) -> Integer?
35
+
36
+ private
37
+
38
+ # Expand HRP for checksum computation.
39
+ def self.expand_hrp: (String hrp) -> Array[Integer]
40
+
41
+ # Compute polymod checksum.
42
+ def self.polymod: (Array[Integer] values) -> Integer
43
+
44
+ # Validate arguments of encode.
45
+ def self.validate_encode_args: (String hrp, Array[Integer] data) -> void
46
+
47
+ def expand_hrp: (String hrp) -> Array[Integer]
48
+ def polymod: (Array[Integer] values) -> Integer
49
+ def validate_encode_args: (String hrp, Array[Integer] data) -> void
50
+ end
@@ -0,0 +1,59 @@
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
+ MAX_VALUE_LENGTH: Integer
16
+
17
+ attr_reader type: Integer
18
+ attr_reader label: String?
19
+ attr_reader value: String | Integer
20
+
21
+ # Initialize TLV entry.
22
+ def initialize: (Integer type, String | Integer value, ?String? label) -> void
23
+
24
+ # Convert to binary payload.
25
+ def to_payload: (?String? hrp) -> String
26
+
27
+ # String representation.
28
+ def to_s: () -> String
29
+
30
+ private
31
+
32
+ # Check if the value of this entry is hex encoded.
33
+ def hex_value?: (String? hrp) -> bool
34
+
35
+ # Check if string is hex encoded.
36
+ def hex_string?: (String str) -> bool
37
+ end
38
+
39
+ class TLVEntity
40
+ TYPE_SPECIAL: Integer
41
+ TYPE_RELAY: Integer
42
+ TYPE_AUTHOR: Integer
43
+ TYPE_KIND: Integer
44
+ TYPES: Array[Integer]
45
+
46
+ attr_reader hrp: String
47
+ attr_reader entries: Array[TLVEntry]
48
+
49
+ # Initialize TLV entity.
50
+ def initialize: (String hrp, Array[TLVEntry] entries) -> void
51
+
52
+ # Parse TLV entity from binary data.
53
+ def self.parse: (String hrp, String data) -> TLVEntity
54
+
55
+ # Encode to bech32 string.
56
+ def encode: () -> String
57
+ end
58
+ end
59
+ 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,22 @@
1
+ module Bech32
2
+ # BIP-352 silent payment address.
3
+ class SilentPaymentAddr
4
+ HRP_MAINNET: String
5
+ HRP_TESTNET: String
6
+ MAX_VERSION: Integer
7
+
8
+ attr_reader hrp: String
9
+ attr_reader version: Integer
10
+ attr_reader scan_key: String
11
+ attr_reader spend_key: String
12
+
13
+ # Initialize SilentPaymentAddr.
14
+ def initialize: (String hrp, Integer version, String scan_key, String spend_key) -> void
15
+
16
+ # Parse silent payment address string.
17
+ def self.parse: (String addr) -> SilentPaymentAddr
18
+
19
+ # Generate silent payment address string.
20
+ def to_s: () -> String
21
+ end
22
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bech32
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shigeyuki Azuchi
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-25 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: thor
@@ -69,6 +69,7 @@ files:
69
69
  - LICENSE.txt
70
70
  - README.md
71
71
  - Rakefile
72
+ - Steepfile
72
73
  - bech32.gemspec
73
74
  - bin/console
74
75
  - bin/setup
@@ -80,10 +81,16 @@ files:
80
81
  - lib/bech32/segwit_addr.rb
81
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: {}
92
+ metadata:
93
+ rubygems_mfa_required: 'true'
87
94
  rdoc_options: []
88
95
  require_paths:
89
96
  - lib
@@ -98,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
105
  - !ruby/object:Gem::Version
99
106
  version: '0'
100
107
  requirements: []
101
- rubygems_version: 3.6.3
108
+ rubygems_version: 4.0.3
102
109
  specification_version: 4
103
110
  summary: The implementation of Bech32 encoder and decoder.
104
111
  test_files: []