bech32 1.0.1 → 1.1.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 +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +7 -4
- data/README.md +23 -3
- data/bech32.gemspec +3 -2
- data/lib/bech32.rb +32 -14
- data/lib/bech32/segwit_addr.rb +8 -5
- data/lib/bech32/version.rb +3 -0
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 975a0d606b86cdb7487afad52363ef284de471f1530cf7614b0a7db0728dc937
|
4
|
+
data.tar.gz: 1e3d9f3f389cbfd94a8af919a0ec842395605649138bdf3860ac9db2617e3939
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab8fdc36df45376ea1ec0e7d7553fb6309900d8db824998f327dbfe670451a00ec240bbd75fe59e1bdda2590981d174e0be086756e919582dad55ce5441fe5fb
|
7
|
+
data.tar.gz: 07bf7ac092a89c997932d380a57f30916baa809fd3adf2c86b7418e599949be6fc593b226bcdb7240247fde19d7f092ebdcdd82bfce154adde9d16b5de2df68e
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
ruby-3.0.0
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
# Bech32 [](https://travis-ci.org/azuchi/bech32rb) [](https://badge.fury.io/rb/bech32) [](LICENSE) <img src="http://segwit.co/static/public/images/logo.png" width="100">
|
2
2
|
|
3
|
-
The implementation of the Bech32 encoder and decoder for Ruby.
|
3
|
+
The implementation of the Bech32/Bech32m encoder and decoder for Ruby.
|
4
4
|
|
5
5
|
Bech32 is checksummed base32 format that is used in following Bitcoin address format.
|
6
6
|
|
7
7
|
https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
|
8
8
|
|
9
|
+
Bech32m is checksummed base32m format that is used in following Bitcoin address format.
|
10
|
+
|
11
|
+
https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
|
12
|
+
|
9
13
|
## Installation
|
10
14
|
|
11
15
|
Add this line to your application's Gemfile:
|
@@ -35,13 +39,15 @@ require 'bech32'
|
|
35
39
|
Decode Bech32-encoded data into hrp part and data part.
|
36
40
|
|
37
41
|
```ruby
|
38
|
-
hrp, data = Bech32.decode('BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4')
|
42
|
+
hrp, data, spec = Bech32.decode('BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4')
|
39
43
|
|
40
44
|
# hrp is human-readable part of Bech32 format
|
41
45
|
'bc'
|
42
46
|
|
43
47
|
# data is data part of Bech32 format
|
44
48
|
[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]
|
49
|
+
|
50
|
+
# spec is whether Bech32::Encoding::BECH32 or Bech32::Encoding::BECH32M
|
45
51
|
```
|
46
52
|
|
47
53
|
Decode Bech32-encoded Segwit address into `Bech32::SegwitAddr` instance.
|
@@ -55,6 +61,20 @@ segwit_addr.to_script_pubkey
|
|
55
61
|
=> 0014751e76e8199196d454941c45d1b3a323f1433bd6
|
56
62
|
```
|
57
63
|
|
64
|
+
#### Advanced
|
65
|
+
|
66
|
+
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.
|
67
|
+
However, LN specification [BOLT#11](https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md) has no limitation.
|
68
|
+
|
69
|
+
To decode data of more than 90 characters, specify `max_length` at decode as below. (The default value of `max_length` is 90.)
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
MAX_INTEGER = 2**31 - 1
|
73
|
+
Bech32.decode(bechString, MAX_INTEGER)
|
74
|
+
```
|
75
|
+
|
76
|
+
Note that between length of the addresses and the error-detection capabilities are [trade-off](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#checksum-design).
|
77
|
+
|
58
78
|
### Encode
|
59
79
|
|
60
80
|
Encode Bech32 human-readable part and data part into Bech32 string.
|
@@ -63,7 +83,7 @@ Encode Bech32 human-readable part and data part into Bech32 string.
|
|
63
83
|
hrp = 'bc'
|
64
84
|
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]
|
65
85
|
|
66
|
-
bech = Bech32.encode(hrp, data)
|
86
|
+
bech = Bech32.encode(hrp, data, Bech32::Encoding::BECH32)
|
67
87
|
=> bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
|
68
88
|
```
|
69
89
|
|
data/bech32.gemspec
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bech32/version'
|
4
5
|
|
5
6
|
Gem::Specification.new do |spec|
|
6
7
|
spec.name = "bech32"
|
7
|
-
spec.version =
|
8
|
+
spec.version = Bech32::VERSION
|
8
9
|
spec.authors = ["Shigeyuki Azuchi"]
|
9
10
|
spec.email = ["azuchi@haw.co.jp"]
|
10
11
|
|
@@ -18,6 +19,6 @@ Gem::Specification.new do |spec|
|
|
18
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
20
|
spec.require_paths = ["lib"]
|
20
21
|
|
21
|
-
spec.add_development_dependency "rake", "
|
22
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
22
23
|
spec.add_development_dependency "rspec", "~> 3.0"
|
23
24
|
end
|
data/lib/bech32.rb
CHANGED
@@ -1,66 +1,84 @@
|
|
1
1
|
module Bech32
|
2
2
|
|
3
|
+
module Encoding
|
4
|
+
BECH32 = 1
|
5
|
+
BECH32M = 2
|
6
|
+
end
|
7
|
+
|
3
8
|
autoload :SegwitAddr, 'bech32/segwit_addr'
|
4
9
|
|
5
10
|
SEPARATOR = '1'
|
6
11
|
|
7
12
|
CHARSET = %w(q p z r y 9 x 8 g f 2 t v d w 0 s 3 j n 5 4 k h c e 6 m u a 7 l)
|
8
13
|
|
14
|
+
BECH32M_CONST = 0x2bc830a3
|
15
|
+
|
9
16
|
module_function
|
10
17
|
|
11
18
|
# Returns the encoded Bech32 string.
|
12
19
|
#
|
13
20
|
# require 'bech32'
|
14
21
|
#
|
15
|
-
# bech = Bech32.encode('bc', [])
|
22
|
+
# bech = Bech32.encode('bc', [], Bech32::Encoding::BECH32)
|
16
23
|
#
|
17
24
|
# <i>Generates:</i>
|
18
25
|
# 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4' # bech
|
19
26
|
#
|
20
|
-
def encode(hrp, data)
|
21
|
-
checksummed = data + create_checksum(hrp, data)
|
27
|
+
def encode(hrp, data, spec)
|
28
|
+
checksummed = data + create_checksum(hrp, data, spec)
|
22
29
|
hrp + SEPARATOR + checksummed.map{|i|CHARSET[i]}.join
|
23
30
|
end
|
24
31
|
|
25
|
-
# Returns the
|
32
|
+
# Returns the Bech32 decoded hrp and data.
|
26
33
|
#
|
27
34
|
# require 'bech32'
|
28
35
|
#
|
29
36
|
# addr = 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4'
|
30
|
-
# hrp, data = Bech32.decode(addr)
|
37
|
+
# hrp, data, spec = Bech32.decode(addr)
|
31
38
|
#
|
32
39
|
# <i>Generates:</i>
|
33
40
|
# 'bc' # hrp
|
34
41
|
# [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] # data
|
42
|
+
# 1 # spec see Bech32::Encoding
|
35
43
|
#
|
36
|
-
def decode(bech)
|
44
|
+
def decode(bech, max_length = 90)
|
37
45
|
# check uppercase/lowercase
|
46
|
+
return nil if bech.bytes.index{|x| x < 33 || x > 126}
|
38
47
|
return nil if (bech.downcase != bech && bech.upcase != bech)
|
39
|
-
bech.each_char{|c|return nil if c.ord < 33 || c.ord > 126}
|
40
48
|
bech = bech.downcase
|
41
49
|
# check data length
|
42
50
|
pos = bech.rindex(SEPARATOR)
|
43
|
-
return nil if pos.nil? || pos + 7 > bech.length || bech.length >
|
51
|
+
return nil if pos.nil? || pos + 7 > bech.length || bech.length > max_length
|
44
52
|
# check valid charset
|
45
53
|
bech[pos+1..-1].each_char{|c|return nil unless CHARSET.include?(c)}
|
46
54
|
# split hrp and data
|
47
55
|
hrp = bech[0..pos-1]
|
48
56
|
data = bech[pos+1..-1].each_char.map{|c|CHARSET.index(c)}
|
49
57
|
# check checksum
|
50
|
-
|
51
|
-
[hrp, data[0..-7]]
|
58
|
+
spec = verify_checksum(hrp, data)
|
59
|
+
spec ? [hrp, data[0..-7], spec] : nil
|
52
60
|
end
|
53
61
|
|
54
62
|
# Returns computed checksum values of +hrp+ and +data+
|
55
|
-
def create_checksum(hrp, data)
|
63
|
+
def create_checksum(hrp, data, spec)
|
56
64
|
values = expand_hrp(hrp) + data
|
57
|
-
|
65
|
+
const = (spec == Bech32::Encoding::BECH32M ? Bech32::BECH32M_CONST : 1)
|
66
|
+
polymod = polymod(values + [0, 0, 0, 0, 0, 0]) ^ const
|
58
67
|
(0..5).map{|i|(polymod >> 5 * (5 - i)) & 31}
|
59
68
|
end
|
60
69
|
|
61
70
|
# Verify a checksum given Bech32 string
|
71
|
+
# @param [String] hrp hrp part.
|
72
|
+
# @param [Array[Integer]] data data array.
|
73
|
+
# @return [Integer] spec
|
62
74
|
def verify_checksum(hrp, data)
|
63
|
-
polymod(expand_hrp(hrp) + data)
|
75
|
+
const = polymod(expand_hrp(hrp) + data)
|
76
|
+
case const
|
77
|
+
when 1
|
78
|
+
Encoding::BECH32
|
79
|
+
when BECH32M_CONST
|
80
|
+
Encoding::BECH32M
|
81
|
+
end
|
64
82
|
end
|
65
83
|
|
66
84
|
# Expand the hrp into values for checksum computation.
|
@@ -82,4 +100,4 @@ module Bech32
|
|
82
100
|
|
83
101
|
private_class_method :polymod, :expand_hrp
|
84
102
|
|
85
|
-
end
|
103
|
+
end
|
data/lib/bech32/segwit_addr.rb
CHANGED
@@ -4,6 +4,7 @@ module Bech32
|
|
4
4
|
|
5
5
|
HRP_MAINNET = 'bc'
|
6
6
|
HRP_TESTNET = 'tb'
|
7
|
+
HRP_REGTEST = 'bcrt'
|
7
8
|
|
8
9
|
attr_accessor :hrp # human-readable part
|
9
10
|
attr_accessor :ver # witness version
|
@@ -16,32 +17,34 @@ module Bech32
|
|
16
17
|
|
17
18
|
# Returns segwit script pubkey which generated from witness version and witness program.
|
18
19
|
def to_script_pubkey
|
19
|
-
v = ver == 0 ? ver : ver +
|
20
|
+
v = ver == 0 ? ver : ver + 0x50
|
20
21
|
([v, prog.length].pack("CC") + prog.map{|p|[p].pack("C")}.join).unpack('H*').first
|
21
22
|
end
|
22
23
|
|
23
24
|
# parse script pubkey into witness version and witness program
|
24
25
|
def script_pubkey=(script_pubkey)
|
25
26
|
values = [script_pubkey].pack('H*').unpack("C*")
|
26
|
-
@ver = values[0]
|
27
|
+
@ver = values[0] == 0 ? values[0] : values[0] - 0x50
|
27
28
|
@prog = values[2..-1]
|
28
29
|
end
|
29
30
|
|
30
31
|
# Returns segwit address string which generated from hrp, witness version and witness program.
|
31
32
|
def addr
|
32
|
-
|
33
|
+
spec = (ver == 0 ? Bech32::Encoding::BECH32 : Bech32::Encoding::BECH32M)
|
34
|
+
Bech32.encode(hrp, [ver] + convert_bits(prog, 8, 5), spec)
|
33
35
|
end
|
34
36
|
|
35
37
|
private
|
36
38
|
|
37
39
|
def parse_addr(addr)
|
38
|
-
@hrp, data = Bech32.decode(addr)
|
39
|
-
raise 'Invalid address.' if
|
40
|
+
@hrp, data, spec = Bech32.decode(addr)
|
41
|
+
raise 'Invalid address.' if hrp.nil? || data[0].nil? || ![HRP_MAINNET, HRP_TESTNET, HRP_REGTEST].include?(hrp)
|
40
42
|
@ver = data[0]
|
41
43
|
raise 'Invalid witness version' if @ver > 16
|
42
44
|
@prog = convert_bits(data[1..-1], 5, 8, false)
|
43
45
|
raise 'Invalid witness program' if @prog.nil? || @prog.length < 2 || @prog.length > 40
|
44
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)
|
45
48
|
end
|
46
49
|
|
47
50
|
def convert_bits(data, from, to, padding=true)
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bech32
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
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: 2021-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 12.3.3
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 12.3.3
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,6 +60,7 @@ files:
|
|
60
60
|
- bin/setup
|
61
61
|
- lib/bech32.rb
|
62
62
|
- lib/bech32/segwit_addr.rb
|
63
|
+
- lib/bech32/version.rb
|
63
64
|
homepage: https://github.com/azuchi/bech32rb
|
64
65
|
licenses:
|
65
66
|
- MIT
|
@@ -79,8 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
80
|
- !ruby/object:Gem::Version
|
80
81
|
version: '0'
|
81
82
|
requirements: []
|
82
|
-
|
83
|
-
rubygems_version: 2.5.1
|
83
|
+
rubygems_version: 3.2.3
|
84
84
|
signing_key:
|
85
85
|
specification_version: 4
|
86
86
|
summary: The implementation of Bech32 encoder and decoder.
|