Module: Lightning::Invoice

Defined in:
lib/lightning/invoice.rb,
lib/lightning/invoice/version.rb,
lib/lightning/invoice/routing_info.rb

Defined Under Namespace

Classes: Message, RoutingInfo

Constant Summary collapse

PREFIX =
'lnbc'
MAX_LENGTH =
2 ** 64
VERSION =
"0.1.2"

Class Method Summary collapse

Class Method Details

.buffer_to_word(buffer) ⇒ Object



186
187
188
189
# File 'lib/lightning/invoice.rb', line 186

def self.buffer_to_word(buffer)
  words = convert(buffer.unpack('C*'), 8, 5, true)
  return words
end

.convert(data, inbits, outbits, padding) ⇒ Object



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/lightning/invoice.rb', line 191

def self.convert(data, inbits, outbits, padding)
  value = 0
  bits = 0
  max = (1 << outbits) - 1

  result = []
  n = data.length
  n.times do |i|
    value = (value << inbits) | data[i]
    bits += inbits
    while bits >= outbits
      bits -= outbits
      result << ((value >> bits) & max)
    end
  end

  if padding && bits > 0
    result << ((value << (outbits - bits)) & max)
  end

  return result
end

.int_to_array(i, bits = 5, padding = 2) ⇒ Object



220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/lightning/invoice.rb', line 220

def self.int_to_array(i, bits = 5, padding = 2)
  array = []
  return [0] if i.nil? || i == 0
  while i > 0
    array << (i & (2**bits - 1))
    i = (i / (2**bits)).to_i
  end
  if padding > array.size
    array += [0] * (padding - array.size)
  end
  array.reverse
end

.parse(str) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/lightning/invoice.rb', line 111

def self.parse(str)
  human, data_part = Bech32.decode(str, MAX_LENGTH)
  return nil unless human
  prefix, amount, multiplier = parse_human_readable(human)
  message = Message.new
  message.prefix = prefix
  message.amount = amount.to_i if !amount&.empty?
  message.multiplier = multiplier
  message.timestamp = to_int(data_part[0...7])
  tags = data_part[7...data_part.size - 104]
  index = 0
  if tags
    while index < tags.size
      type = tags[index]
      data_length = (tags[index + 1].to_i << 5) + tags[index + 2].to_i
      data = tags[index + 3 ... index + 3 + data_length]
      bytes = to_bytes(data)
      index += 3 + data_length
      case type
      when 1
        message.payment_hash = bytes[0...64].pack("C*").bth
      when 13
        message.description = bytes.pack("C*").force_encoding('utf-8')
      when 19
        message.pubkey = bytes[0...66].pack("C*").bth
      when 23
        message.description_hash = bytes[0...64].pack("C*").bth
      when 6
        message.expiry = to_int(data)
      when 24
        message.min_final_cltv_expiry = to_int(data)
      when 9
        address = to_bytes(data[1..-1])
        hex = address.pack("C*").unpack("H*").first
        case data[0]
        when 0
          message.fallback_address = Bitcoin::Script.to_p2wpkh(hex).addresses.first
        when 17
          message.fallback_address = Bitcoin.encode_base58_address(hex, Bitcoin.chain_params.address_version)
        when 18
          message.fallback_address = Bitcoin.encode_base58_address(hex, Bitcoin.chain_params.p2sh_version)
        else
        end
      when 3
        offset = 0
        while offset < bytes.size
          message.routing_info << Lightning::Invoice::RoutingInfo.new(
            bytes[offset...offset + 33].pack("C*").bth,
            bytes[offset + 33...offset + 41].pack("C*").bth,
            to_int(bytes[offset + 41...offset + 45]),
            to_int(bytes[offset + 45...offset + 49]),
            to_int(bytes[offset + 49...offset + 51])
          )
          offset += 51
        end
      else
      end
    end
  end
  sig = data_part[data_part.size - 104..-1]
  if sig
    message.signature = word_to_buffer(sig).bth
  end
  message
end

.parse_human_readable(human) ⇒ Object



177
178
179
# File 'lib/lightning/invoice.rb', line 177

def self.parse_human_readable(human)
  human.scan(/^([a-zA-Z]+)(\d*)([munp]?)$/)&.first
end

.to_bytes(data) ⇒ Object



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/lightning/invoice.rb', line 233

def self.to_bytes(data)
  buf = []
  (data.size * 5).times do |i|
    loc5 = (i / 5).to_i
    loc8 = i >> 3
    if i % 8 == 0
      buf[loc8] = 0
    end
    buf[loc8] |= ((data[loc5] >> (4 - (i % 5))) & 1) << (7 - (i % 8))
  end
  if data.size % 8 != 0
    buf = buf[0...-1]
  end
  buf
end

.to_int(data) ⇒ Object



214
215
216
217
218
# File 'lib/lightning/invoice.rb', line 214

def self.to_int(data)
  data.inject(0) do |i, sum|
    sum + (i << 5)
  end
end

.word_to_buffer(data) ⇒ Object



181
182
183
184
# File 'lib/lightning/invoice.rb', line 181

def self.word_to_buffer(data)
  buffer = convert(data, 5, 8, false)
  return buffer.pack("C*")
end