bech32 1.2.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +2 -3
- data/README.md +52 -14
- data/lib/bech32/nostr/entity.rb +147 -0
- data/lib/bech32/nostr/nip19.rb +41 -0
- data/lib/bech32/nostr.rb +8 -0
- data/lib/bech32/segwit_addr.rb +3 -26
- data/lib/bech32/version.rb +1 -1
- data/lib/bech32.rb +30 -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: 1e52ce0d1cc8ab59a97a220fc50e134c3c70fcc5beebd83b86631f4a3c6fc39d
|
4
|
+
data.tar.gz: cbf75c9c25a349c048ee2ad3503d3db8f6631babccdbfb8a7608dd7de9a60ce0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 399a572833d9f651037a7e49c17917bf1e82521fac556c8cc47e14422ef96b200797124e95d51ac2ac760947fdf6b10c39485cbd1228529b72ad3b46e063f5f0
|
7
|
+
data.tar.gz: 6cd811fad6a9a6da5853230ff4501be650afc3a1efeb8208b098774f9bd83676e79ad7be433911774f3005b61054f43671623176bfec1a37835d5f24557e1755
|
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 [![Build Status](https://
|
1
|
+
# Bech32 [![Build Status](https://github.com/azuchi/bech32rb/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/azuchi/bech32rb/actions/workflows/main.yml) [![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
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
|
@@ -0,0 +1,147 @@
|
|
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
|
+
private
|
51
|
+
|
52
|
+
# Check whether +str+ is hex string or not.
|
53
|
+
# @param [String] str string.
|
54
|
+
# @return [Boolean]
|
55
|
+
def hex_string?(str)
|
56
|
+
return false if str.bytes.any? { |b| b > 127 }
|
57
|
+
return false if str.length % 2 != 0
|
58
|
+
hex_chars = str.chars.to_a
|
59
|
+
hex_chars.all? { |c| c =~ /[0-9a-fA-F]/ }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class TLVEntity
|
64
|
+
|
65
|
+
TYPE_SPECIAL = 0
|
66
|
+
TYPE_RELAY = 1
|
67
|
+
TYPE_AUTHOR = 2
|
68
|
+
TYPE_KIND = 3
|
69
|
+
|
70
|
+
TYPES = [TYPE_SPECIAL, TYPE_RELAY, TYPE_AUTHOR, TYPE_KIND]
|
71
|
+
|
72
|
+
attr_reader :hrp
|
73
|
+
attr_reader :entries
|
74
|
+
|
75
|
+
# Initialize TLV entity.
|
76
|
+
# @param [String] hrp human-readable part.
|
77
|
+
# @param [Array<TLVEntry>] entries TLV entries.
|
78
|
+
# @return [TLVEntity]
|
79
|
+
def initialize(hrp, entries)
|
80
|
+
raise ArgumentError, "HRP #{hrp} is unsupported." unless NIP19::TLV_PREFIXES.include?(hrp)
|
81
|
+
entries.each do |e|
|
82
|
+
raise ArgumentError, "Entries must be TLVEntry. #{e.class} given." unless e.is_a?(TLVEntry)
|
83
|
+
end
|
84
|
+
|
85
|
+
@hrp = hrp
|
86
|
+
@entries = entries
|
87
|
+
end
|
88
|
+
|
89
|
+
# Parse TLV entity from data.
|
90
|
+
# @param [String] hrp human-readable part.
|
91
|
+
# @param [String] data Entity data(binary format).
|
92
|
+
# @return [TLVEntity]
|
93
|
+
def self.parse(hrp, data)
|
94
|
+
buf = StringIO.new(data)
|
95
|
+
entries = []
|
96
|
+
until buf.eof?
|
97
|
+
type, len = buf.read(2).unpack('CC')
|
98
|
+
case type
|
99
|
+
when TYPE_SPECIAL # special
|
100
|
+
case hrp
|
101
|
+
when NIP19::HRP_PROFILE
|
102
|
+
entries << TLVEntry.new(type, buf.read(len).unpack1('H*'), 'pubkey')
|
103
|
+
when NIP19::HRP_RELAY
|
104
|
+
entries << TLVEntry.new(type, buf.read(len), 'relay')
|
105
|
+
when NIP19::HRP_EVENT
|
106
|
+
entries << TLVEntry.new(type, buf.read(len).unpack1('H*'), 'id')
|
107
|
+
when NIP19::HRP_EVENT_COORDINATE
|
108
|
+
entries << TLVEntry.new(type, buf.read(len), 'identifier')
|
109
|
+
end
|
110
|
+
when TYPE_RELAY # relay
|
111
|
+
case hrp
|
112
|
+
when NIP19::HRP_PROFILE, NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
|
113
|
+
entries << TLVEntry.new(type, buf.read(len), 'relay')
|
114
|
+
else
|
115
|
+
raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
|
116
|
+
end
|
117
|
+
when TYPE_AUTHOR # author
|
118
|
+
case hrp
|
119
|
+
when NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
|
120
|
+
entries << TLVEntry.new(type, buf.read(len).unpack1('H*'), 'author')
|
121
|
+
else
|
122
|
+
raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
|
123
|
+
end
|
124
|
+
when TYPE_KIND # kind
|
125
|
+
case hrp
|
126
|
+
when NIP19::HRP_EVENT, NIP19::HRP_EVENT_COORDINATE
|
127
|
+
entries << TLVEntry.new(type, buf.read(len).unpack1('H*').to_i(16), 'kind')
|
128
|
+
else
|
129
|
+
raise ArgumentError, "Type: #{type} does not supported for HRP: #{hrp}"
|
130
|
+
end
|
131
|
+
else
|
132
|
+
raise ArgumentError, "Unknown TLV type: #{type}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
TLVEntity.new(hrp, entries)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Encode tlv entity to bech32 string.
|
140
|
+
# @return [String] bech32 string.
|
141
|
+
def encode
|
142
|
+
data = entries.map(&:to_payload).join
|
143
|
+
Bech32.encode(hrp, Bech32.convert_bits(data.unpack('C*'), 8, 5), Bech32::Encoding::BECH32)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Bech32
|
2
|
+
module Nostr
|
3
|
+
module NIP19
|
4
|
+
|
5
|
+
HRP_PUBKEY = 'npub'
|
6
|
+
HRP_PRIVATE_KEY = 'nsec'
|
7
|
+
HRP_NOTE_ID = 'note'
|
8
|
+
HRP_PROFILE = 'nprofile'
|
9
|
+
HRP_EVENT = 'nevent'
|
10
|
+
HRP_RELAY = 'nrelay'
|
11
|
+
HRP_EVENT_COORDINATE = 'naddr'
|
12
|
+
|
13
|
+
BARE_PREFIXES = [HRP_PUBKEY, HRP_PRIVATE_KEY, HRP_NOTE_ID]
|
14
|
+
TLV_PREFIXES = [HRP_PROFILE, HRP_EVENT, HRP_RELAY, HRP_EVENT_COORDINATE]
|
15
|
+
ALL_PREFIXES = BARE_PREFIXES + TLV_PREFIXES
|
16
|
+
|
17
|
+
module_function
|
18
|
+
|
19
|
+
# Decode nip19 string.
|
20
|
+
# @param [String] string Bech32 string.
|
21
|
+
# @return [BareEntity | TLVEntity]
|
22
|
+
def decode(string)
|
23
|
+
hrp, data, spec = Bech32.decode(string, string.length)
|
24
|
+
|
25
|
+
raise ArgumentError, 'Invalid nip19 string.' if hrp.nil?
|
26
|
+
raise ArgumentError, 'Invalid bech32 spec.' unless spec == Bech32::Encoding::BECH32
|
27
|
+
|
28
|
+
entity = Bech32.convert_bits(data, 5, 8, false).pack('C*')
|
29
|
+
raise ArgumentError, "Data whose HRP is #{hrp} must be 32 bytes." if BARE_PREFIXES.include?(hrp) && entity.bytesize != 32
|
30
|
+
if BARE_PREFIXES.include?(hrp)
|
31
|
+
BareEntity.new(hrp, entity.unpack1('H*'))
|
32
|
+
elsif TLV_PREFIXES.include?(hrp)
|
33
|
+
TLVEntity.parse(hrp, entity)
|
34
|
+
else
|
35
|
+
raise ArgumentError, "HRP #{hrp} is unsupported."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/bech32/nostr.rb
ADDED
data/lib/bech32/segwit_addr.rb
CHANGED
@@ -18,7 +18,7 @@ module Bech32
|
|
18
18
|
# Returns segwit script pubkey which generated from witness version and witness program.
|
19
19
|
def to_script_pubkey
|
20
20
|
v = ver == 0 ? ver : ver + 0x50
|
21
|
-
([v, prog.length]
|
21
|
+
([v, prog.length] + prog).pack('C*').unpack("H*").first
|
22
22
|
end
|
23
23
|
|
24
24
|
# parse script pubkey into witness version and witness program
|
@@ -31,7 +31,7 @@ module Bech32
|
|
31
31
|
# Returns segwit address string which generated from hrp, witness version and witness program.
|
32
32
|
def addr
|
33
33
|
spec = (ver == 0 ? Bech32::Encoding::BECH32 : Bech32::Encoding::BECH32M)
|
34
|
-
Bech32.encode(hrp, [ver] + convert_bits(prog, 8, 5), spec)
|
34
|
+
Bech32.encode(hrp, [ver] + Bech32.convert_bits(prog, 8, 5), spec)
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
@@ -41,34 +41,11 @@ module Bech32
|
|
41
41
|
raise 'Invalid address.' if hrp.nil? || data[0].nil? || ![HRP_MAINNET, HRP_TESTNET, HRP_REGTEST].include?(hrp)
|
42
42
|
@ver = data[0]
|
43
43
|
raise 'Invalid witness version' if @ver > 16
|
44
|
-
@prog = convert_bits(data[1..-1], 5, 8, false)
|
44
|
+
@prog = Bech32.convert_bits(data[1..-1], 5, 8, false)
|
45
45
|
raise 'Invalid witness program' if @prog.nil? || @prog.length < 2 || @prog.length > 40
|
46
46
|
raise 'Invalid witness program with version 0' if @ver == 0 && (@prog.length != 20 && @prog.length != 32)
|
47
47
|
raise 'Witness version and encoding spec do not match' if (@ver == 0 && spec != Bech32::Encoding::BECH32) || (@ver != 0 && spec != Bech32::Encoding::BECH32M)
|
48
48
|
end
|
49
49
|
|
50
|
-
def convert_bits(data, from, to, padding=true)
|
51
|
-
acc = 0
|
52
|
-
bits = 0
|
53
|
-
ret = []
|
54
|
-
maxv = (1 << to) - 1
|
55
|
-
max_acc = (1 << (from + to - 1)) - 1
|
56
|
-
data.each do |v|
|
57
|
-
return nil if v < 0 || (v >> from) != 0
|
58
|
-
acc = ((acc << from) | v) & max_acc
|
59
|
-
bits += from
|
60
|
-
while bits >= to
|
61
|
-
bits -= to
|
62
|
-
ret << ((acc >> bits) & maxv)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
if padding
|
66
|
-
ret << ((acc << (to - bits)) & maxv) unless bits == 0
|
67
|
-
elsif bits >= from || ((acc << (to - bits)) & maxv) != 0
|
68
|
-
return nil
|
69
|
-
end
|
70
|
-
ret
|
71
|
-
end
|
72
|
-
|
73
50
|
end
|
74
51
|
end
|
data/lib/bech32/version.rb
CHANGED
data/lib/bech32.rb
CHANGED
@@ -6,6 +6,7 @@ module Bech32
|
|
6
6
|
end
|
7
7
|
|
8
8
|
autoload :SegwitAddr, 'bech32/segwit_addr'
|
9
|
+
autoload :Nostr, 'bech32/nostr'
|
9
10
|
|
10
11
|
SEPARATOR = '1'
|
11
12
|
|
@@ -86,6 +87,35 @@ module Bech32
|
|
86
87
|
hrp.each_char.map{|c|c.ord >> 5} + [0] + hrp.each_char.map{|c|c.ord & 31}
|
87
88
|
end
|
88
89
|
|
90
|
+
# Convert a +data+ where each byte is encoding +from+ bits to a byte slice where each byte is encoding +to+ bits.
|
91
|
+
# @param [Array] data
|
92
|
+
# @param [Integer] from
|
93
|
+
# @param [Integer] to
|
94
|
+
# @param [Boolean] padding
|
95
|
+
# @return [Array]
|
96
|
+
def convert_bits(data, from, to, padding=true)
|
97
|
+
acc = 0
|
98
|
+
bits = 0
|
99
|
+
ret = []
|
100
|
+
maxv = (1 << to) - 1
|
101
|
+
max_acc = (1 << (from + to - 1)) - 1
|
102
|
+
data.each do |v|
|
103
|
+
return nil if v < 0 || (v >> from) != 0
|
104
|
+
acc = ((acc << from) | v) & max_acc
|
105
|
+
bits += from
|
106
|
+
while bits >= to
|
107
|
+
bits -= to
|
108
|
+
ret << ((acc >> bits) & maxv)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
if padding
|
112
|
+
ret << ((acc << (to - bits)) & maxv) unless bits == 0
|
113
|
+
elsif bits >= from || ((acc << (to - bits)) & maxv) != 0
|
114
|
+
return nil
|
115
|
+
end
|
116
|
+
ret
|
117
|
+
end
|
118
|
+
|
89
119
|
# Compute Bech32 checksum
|
90
120
|
def polymod(values)
|
91
121
|
generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
|
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.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: 2023-08-26 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
|