bech32 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://travis-ci.org/azuchi/bech32rb.svg?branch=master)](https://travis-ci.org/azuchi/bech32rb) [![Gem Version](https://badge.fury.io/rb/bech32.svg)](https://badge.fury.io/rb/bech32) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](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.
|