bsv-sdk 0.19.1 → 0.22.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 +4 -4
- data/CHANGELOG.md +89 -0
- data/README.md +2 -2
- data/lib/bsv/auth/transport.rb +1 -1
- data/lib/bsv/mcp/tools/broadcast_p2pkh.rb +5 -3
- data/lib/bsv/network/protocol.rb +4 -5
- data/lib/bsv/network/protocols/arc.rb +4 -30
- data/lib/bsv/network/protocols/arcade.rb +163 -0
- data/lib/bsv/network/protocols/chaintracks.rb +6 -3
- data/lib/bsv/network/protocols/jungle_bus.rb +6 -0
- data/lib/bsv/network/protocols.rb +1 -0
- data/lib/bsv/network/provider.rb +7 -9
- data/lib/bsv/network/providers/gorilla_pool.rb +18 -18
- data/lib/bsv/network/util.rb +44 -0
- data/lib/bsv/network.rb +1 -0
- data/lib/bsv/overlay/lookup_resolver.rb +0 -1
- data/lib/bsv/overlay/topic_broadcaster.rb +0 -1
- data/lib/bsv/primitives/curve.rb +1 -11
- data/lib/bsv/primitives/ecies.rb +1 -8
- data/lib/bsv/primitives/hex.rb +1 -1
- data/lib/bsv/script/script.rb +1 -1
- data/lib/bsv/transaction/beef.rb +0 -2
- data/lib/bsv/transaction/chain_tracker.rb +74 -13
- data/lib/bsv/transaction/chain_trackers/whats_on_chain.rb +3 -3
- data/lib/bsv/transaction/chain_trackers.rb +0 -10
- data/lib/bsv/transaction/fee_models/live_policy.rb +10 -8
- data/lib/bsv/transaction/merkle_path.rb +0 -2
- data/lib/bsv/version.rb +1 -1
- data/lib/bsv/wallet/errors.rb +65 -21
- data/lib/bsv/wallet/proto_wallet/validators.rb +7 -49
- data/lib/bsv/wallet/proto_wallet.rb +15 -8
- data/lib/bsv/wallet/serializer/abort_action.rb +38 -0
- data/lib/bsv/wallet/serializer/acquire_certificate.rb +171 -0
- data/lib/bsv/wallet/serializer/certificate.rb +184 -0
- data/lib/bsv/wallet/serializer/common.rb +207 -0
- data/lib/bsv/wallet/serializer/create_action_args.rb +259 -0
- data/lib/bsv/wallet/serializer/create_action_result.rb +85 -0
- data/lib/bsv/wallet/serializer/create_hmac.rb +67 -0
- data/lib/bsv/wallet/serializer/create_signature.rb +90 -0
- data/lib/bsv/wallet/serializer/decrypt.rb +60 -0
- data/lib/bsv/wallet/serializer/discover_by_attributes.rb +61 -0
- data/lib/bsv/wallet/serializer/discover_by_identity_key.rb +49 -0
- data/lib/bsv/wallet/serializer/discover_certificates_result.rb +39 -0
- data/lib/bsv/wallet/serializer/encrypt.rb +60 -0
- data/lib/bsv/wallet/serializer/get_header_for_height.rb +71 -0
- data/lib/bsv/wallet/serializer/get_height.rb +46 -0
- data/lib/bsv/wallet/serializer/get_network.rb +65 -0
- data/lib/bsv/wallet/serializer/get_public_key.rb +86 -0
- data/lib/bsv/wallet/serializer/get_version.rb +44 -0
- data/lib/bsv/wallet/serializer/internalize_action.rb +151 -0
- data/lib/bsv/wallet/serializer/list_actions.rb +348 -0
- data/lib/bsv/wallet/serializer/list_certificates.rb +124 -0
- data/lib/bsv/wallet/serializer/list_outputs.rb +167 -0
- data/lib/bsv/wallet/serializer/prove_certificate.rb +146 -0
- data/lib/bsv/wallet/serializer/relinquish_certificate.rb +56 -0
- data/lib/bsv/wallet/serializer/relinquish_output.rb +44 -0
- data/lib/bsv/wallet/serializer/reveal_counterparty_key_linkage.rb +108 -0
- data/lib/bsv/wallet/serializer/reveal_specific_key_linkage.rb +116 -0
- data/lib/bsv/wallet/serializer/sign_action_args.rb +94 -0
- data/lib/bsv/wallet/serializer/sign_action_result.rb +49 -0
- data/lib/bsv/wallet/serializer/status.rb +85 -0
- data/lib/bsv/wallet/serializer/verify_hmac.rb +67 -0
- data/lib/bsv/wallet/serializer/verify_signature.rb +101 -0
- data/lib/bsv/wallet/serializer.rb +180 -0
- data/lib/bsv/wallet/substrates/http_wallet_json.rb +129 -0
- data/lib/bsv/wallet/substrates/http_wallet_wire.rb +99 -0
- data/lib/bsv/wallet/wallet_wire.rb +20 -0
- data/lib/bsv/wallet/wallet_wire_processor.rb +61 -0
- data/lib/bsv/wallet/wallet_wire_transceiver.rb +61 -0
- data/lib/bsv/wallet/wire/calls.rb +79 -0
- data/lib/bsv/wallet/wire/frame.rb +181 -0
- data/lib/bsv/wallet/wire/reader_writer.rb +402 -0
- data/lib/bsv/wallet/wire/validation.rb +213 -0
- data/lib/bsv/wallet/wire.rb +13 -0
- data/lib/bsv/wallet.rb +17 -0
- metadata +47 -3
- data/lib/bsv/transaction/chain_trackers/chaintracks.rb +0 -83
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
|
|
5
|
+
module BSV
|
|
6
|
+
module Wallet
|
|
7
|
+
module Serializer
|
|
8
|
+
# BRC-103 wire codec for the +prove_certificate+ call (call byte 19).
|
|
9
|
+
#
|
|
10
|
+
# Args wire layout (matches go-sdk SerializeProveCertificateArgs):
|
|
11
|
+
# [32 bytes: cert.type]
|
|
12
|
+
# [33 bytes: cert.subject pubkey]
|
|
13
|
+
# [32 bytes: cert.serial_number]
|
|
14
|
+
# [33 bytes: cert.certifier pubkey]
|
|
15
|
+
# [36 bytes: cert.revocation_outpoint]
|
|
16
|
+
# [varint-int: cert.signature bytes] (0-length if nil)
|
|
17
|
+
# [varint: field_count] per field: [varint-int name_bytes][varint-int value_bytes]
|
|
18
|
+
# [varint: fields_to_reveal_count] per field: [varint-int name_bytes]
|
|
19
|
+
# [33 bytes: verifier pubkey]
|
|
20
|
+
# [privileged params]
|
|
21
|
+
#
|
|
22
|
+
# Result wire layout:
|
|
23
|
+
# [varint: keyring_count] per entry: [varint-int key_bytes][varint-int base64 bytes]
|
|
24
|
+
module ProveCertificate
|
|
25
|
+
CERT_TYPE_SIZE = 32
|
|
26
|
+
SERIAL_SIZE = 32
|
|
27
|
+
PUBKEY_SIZE = 33
|
|
28
|
+
|
|
29
|
+
module_function
|
|
30
|
+
|
|
31
|
+
def serialize_args(args)
|
|
32
|
+
w = Wire::Writer.new
|
|
33
|
+
cert = args[:certificate] || {}
|
|
34
|
+
|
|
35
|
+
type_bytes = Base64.strict_decode64(cert[:type].to_s)
|
|
36
|
+
w.write_bytes(type_bytes.ljust(CERT_TYPE_SIZE, "\x00").byteslice(0, CERT_TYPE_SIZE))
|
|
37
|
+
w.write_bytes([cert[:subject].to_s].pack('H*'))
|
|
38
|
+
|
|
39
|
+
serial_bytes = Base64.strict_decode64(cert[:serial_number].to_s)
|
|
40
|
+
w.write_bytes(serial_bytes.ljust(SERIAL_SIZE, "\x00").byteslice(0, SERIAL_SIZE))
|
|
41
|
+
w.write_bytes([cert[:certifier].to_s].pack('H*'))
|
|
42
|
+
|
|
43
|
+
outpoint_str = cert[:revocation_outpoint].to_s
|
|
44
|
+
if outpoint_str.empty? || outpoint_str == '.'
|
|
45
|
+
w.write_outpoint(Certificate::NULL_TXID_HEX, 0)
|
|
46
|
+
else
|
|
47
|
+
txid_hex, vout = outpoint_str.split('.', 2)
|
|
48
|
+
w.write_outpoint(txid_hex.to_s, vout.to_i)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
sig = cert[:signature]
|
|
52
|
+
if sig && !sig.to_s.empty?
|
|
53
|
+
w.write_int_bytes([sig.to_s].pack('H*'))
|
|
54
|
+
else
|
|
55
|
+
w.write_int_bytes(''.b)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
fields = cert[:fields] || {}
|
|
59
|
+
w.write_varint(fields.length)
|
|
60
|
+
fields.keys.sort.each do |k|
|
|
61
|
+
w.write_int_bytes(k.b)
|
|
62
|
+
w.write_int_bytes(fields[k].to_s.b)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
fields_to_reveal = args[:fields_to_reveal] || []
|
|
66
|
+
w.write_varint(fields_to_reveal.length)
|
|
67
|
+
fields_to_reveal.each { |f| w.write_int_bytes(f.to_s.b) }
|
|
68
|
+
|
|
69
|
+
w.write_bytes([args[:verifier].to_s].pack('H*'))
|
|
70
|
+
|
|
71
|
+
Common.write_privileged_params(w, args[:privileged], args[:privileged_reason])
|
|
72
|
+
w.buf
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def deserialize_args(bytes)
|
|
76
|
+
r = Wire::Reader.new(bytes)
|
|
77
|
+
|
|
78
|
+
type_raw = r.read_bytes(CERT_TYPE_SIZE)
|
|
79
|
+
subject = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
|
|
80
|
+
serial_raw = r.read_bytes(SERIAL_SIZE)
|
|
81
|
+
certifier = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
|
|
82
|
+
|
|
83
|
+
outpoint_data = r.read_outpoint
|
|
84
|
+
revocation_outpoint = "#{outpoint_data[:txid_hex]}.#{outpoint_data[:vout]}"
|
|
85
|
+
|
|
86
|
+
sig_bytes = r.read_int_bytes
|
|
87
|
+
signature = sig_bytes.empty? ? nil : sig_bytes.unpack1('H*')
|
|
88
|
+
|
|
89
|
+
field_count = r.read_varint
|
|
90
|
+
fields = {}
|
|
91
|
+
field_count.times do
|
|
92
|
+
k = r.read_int_bytes.force_encoding('UTF-8')
|
|
93
|
+
v = r.read_int_bytes.force_encoding('UTF-8')
|
|
94
|
+
fields[k] = v
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
fields_to_reveal_count = r.read_varint
|
|
98
|
+
fields_to_reveal = fields_to_reveal_count.times.map do
|
|
99
|
+
r.read_int_bytes.force_encoding('UTF-8')
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
verifier = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
|
|
103
|
+
privileged, privileged_reason = Common.read_privileged_params(r)
|
|
104
|
+
|
|
105
|
+
{
|
|
106
|
+
certificate: {
|
|
107
|
+
type: Base64.strict_encode64(type_raw),
|
|
108
|
+
subject: subject,
|
|
109
|
+
serial_number: Base64.strict_encode64(serial_raw),
|
|
110
|
+
certifier: certifier,
|
|
111
|
+
revocation_outpoint: revocation_outpoint,
|
|
112
|
+
signature: signature,
|
|
113
|
+
fields: fields
|
|
114
|
+
},
|
|
115
|
+
fields_to_reveal: fields_to_reveal,
|
|
116
|
+
verifier: verifier,
|
|
117
|
+
privileged: privileged,
|
|
118
|
+
privileged_reason: privileged_reason
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def serialize_result(result)
|
|
123
|
+
w = Wire::Writer.new
|
|
124
|
+
keyring = result[:keyring_for_verifier] || {}
|
|
125
|
+
w.write_varint(keyring.length)
|
|
126
|
+
keyring.keys.sort.each do |k|
|
|
127
|
+
w.write_int_bytes(k.to_s.b)
|
|
128
|
+
w.write_int_from_base64(keyring[k].to_s)
|
|
129
|
+
end
|
|
130
|
+
w.buf
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def deserialize_result(bytes)
|
|
134
|
+
r = Wire::Reader.new(bytes)
|
|
135
|
+
count = r.read_varint
|
|
136
|
+
keyring = {}
|
|
137
|
+
count.times do
|
|
138
|
+
k = r.read_int_bytes.force_encoding('UTF-8')
|
|
139
|
+
keyring[k] = r.read_base64_int
|
|
140
|
+
end
|
|
141
|
+
{ keyring_for_verifier: keyring }
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
|
|
5
|
+
module BSV
|
|
6
|
+
module Wallet
|
|
7
|
+
module Serializer
|
|
8
|
+
# BRC-103 wire codec for the +relinquish_certificate+ call (call byte 20).
|
|
9
|
+
#
|
|
10
|
+
# Args wire layout:
|
|
11
|
+
# [32 bytes: type]
|
|
12
|
+
# [32 bytes: serial_number]
|
|
13
|
+
# [33 bytes: certifier pubkey]
|
|
14
|
+
#
|
|
15
|
+
# Result wire layout:
|
|
16
|
+
# [empty — relinquished is implicit from the frame error byte]
|
|
17
|
+
module RelinquishCertificate
|
|
18
|
+
CERT_TYPE_SIZE = 32
|
|
19
|
+
SERIAL_SIZE = 32
|
|
20
|
+
PUBKEY_SIZE = 33
|
|
21
|
+
|
|
22
|
+
module_function
|
|
23
|
+
|
|
24
|
+
def serialize_args(args)
|
|
25
|
+
w = Wire::Writer.new
|
|
26
|
+
type_bytes = Base64.strict_decode64(args[:type].to_s)
|
|
27
|
+
w.write_bytes(type_bytes.ljust(CERT_TYPE_SIZE, "\x00").byteslice(0, CERT_TYPE_SIZE))
|
|
28
|
+
serial_bytes = Base64.strict_decode64(args[:serial_number].to_s)
|
|
29
|
+
w.write_bytes(serial_bytes.ljust(SERIAL_SIZE, "\x00").byteslice(0, SERIAL_SIZE))
|
|
30
|
+
w.write_bytes([args[:certifier].to_s].pack('H*'))
|
|
31
|
+
w.buf
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def deserialize_args(bytes)
|
|
35
|
+
r = Wire::Reader.new(bytes)
|
|
36
|
+
type_raw = r.read_bytes(CERT_TYPE_SIZE)
|
|
37
|
+
serial_raw = r.read_bytes(SERIAL_SIZE)
|
|
38
|
+
certifier = r.read_bytes(PUBKEY_SIZE).unpack1('H*')
|
|
39
|
+
{
|
|
40
|
+
type: Base64.strict_encode64(type_raw),
|
|
41
|
+
serial_number: Base64.strict_encode64(serial_raw),
|
|
42
|
+
certifier: certifier
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def serialize_result(_result)
|
|
47
|
+
''.b
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def deserialize_result(_bytes)
|
|
51
|
+
{ relinquished: true }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +relinquish_output+ call (call byte 7).
|
|
7
|
+
#
|
|
8
|
+
# Args wire layout:
|
|
9
|
+
# [varint-str: basket]
|
|
10
|
+
# [32-byte wire txid][varint vout]
|
|
11
|
+
#
|
|
12
|
+
# Result wire layout:
|
|
13
|
+
# [empty — relinquished is implicit from the frame error byte]
|
|
14
|
+
module RelinquishOutput
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def serialize_args(args)
|
|
18
|
+
Wire::Validation.outpoint_string!('output', args[:output].to_s)
|
|
19
|
+
txid_hex, vout = args[:output].to_s.split('.', 2)
|
|
20
|
+
w = Wire::Writer.new
|
|
21
|
+
w.write_str_with_varint_len(args.fetch(:basket, ''))
|
|
22
|
+
w.write_outpoint(txid_hex, vout.to_i)
|
|
23
|
+
w.buf
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def deserialize_args(bytes)
|
|
27
|
+
r = Wire::Reader.new(bytes)
|
|
28
|
+
basket = r.read_str_with_varint_len
|
|
29
|
+
outpoint_data = r.read_outpoint
|
|
30
|
+
output = "#{outpoint_data[:txid_hex]}.#{outpoint_data[:vout]}"
|
|
31
|
+
{ basket: basket, output: output }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def serialize_result(_result)
|
|
35
|
+
''.b
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def deserialize_result(_bytes)
|
|
39
|
+
{ relinquished: true }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +reveal_counterparty_key_linkage+ call (call byte 9).
|
|
7
|
+
#
|
|
8
|
+
# Port of go-sdk/wallet/serializer/reveal_counterparty_key_linkage.go.
|
|
9
|
+
module RevealCounterpartyKeyLinkage
|
|
10
|
+
PUBKEY_SIZE = 33
|
|
11
|
+
|
|
12
|
+
# Args wire layout:
|
|
13
|
+
# [privileged params]
|
|
14
|
+
# [33 bytes: counterparty compressed pubkey]
|
|
15
|
+
# [33 bytes: verifier compressed pubkey]
|
|
16
|
+
module Args
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
def serialize(args)
|
|
20
|
+
counterparty = args[:counterparty]
|
|
21
|
+
verifier = args[:verifier]
|
|
22
|
+
raise BSV::Wallet::InvalidParameterError.new('counterparty', 'a 33-byte binary pubkey or 66-char hex') unless counterparty
|
|
23
|
+
raise BSV::Wallet::InvalidParameterError.new('verifier', 'a 33-byte binary pubkey or 66-char hex') unless verifier
|
|
24
|
+
|
|
25
|
+
w = BSV::Wallet::Wire::Writer.new
|
|
26
|
+
Common.write_privileged_params(w, args[:privileged], args[:privileged_reason])
|
|
27
|
+
w.write_bytes(pubkey_bytes(counterparty))
|
|
28
|
+
w.write_bytes(pubkey_bytes(verifier))
|
|
29
|
+
w.buf
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def deserialize(bytes)
|
|
33
|
+
r = BSV::Wallet::Wire::Reader.new(bytes)
|
|
34
|
+
privileged, reason = Common.read_privileged_params(r)
|
|
35
|
+
counterparty = r.read_bytes(PUBKEY_SIZE)
|
|
36
|
+
verifier = r.read_bytes(PUBKEY_SIZE)
|
|
37
|
+
{
|
|
38
|
+
privileged: privileged,
|
|
39
|
+
privileged_reason: reason,
|
|
40
|
+
counterparty: counterparty,
|
|
41
|
+
verifier: verifier
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def pubkey_bytes(value)
|
|
46
|
+
return value.b if value.is_a?(String) && value.bytesize == PUBKEY_SIZE
|
|
47
|
+
|
|
48
|
+
[value.to_s].pack('H*')
|
|
49
|
+
end
|
|
50
|
+
private_class_method :pubkey_bytes
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Result wire layout:
|
|
54
|
+
# [33 bytes: prover pubkey]
|
|
55
|
+
# [33 bytes: verifier pubkey]
|
|
56
|
+
# [33 bytes: counterparty pubkey]
|
|
57
|
+
# [VarInt revelation_time_len][revelation_time bytes]
|
|
58
|
+
# [VarInt encrypted_linkage_len][encrypted_linkage bytes]
|
|
59
|
+
# [VarInt encrypted_linkage_proof_len][encrypted_linkage_proof bytes]
|
|
60
|
+
module Result
|
|
61
|
+
module_function
|
|
62
|
+
|
|
63
|
+
def serialize(result)
|
|
64
|
+
w = BSV::Wallet::Wire::Writer.new
|
|
65
|
+
w.write_bytes(pubkey_bytes(result[:prover]))
|
|
66
|
+
w.write_bytes(pubkey_bytes(result[:verifier]))
|
|
67
|
+
w.write_bytes(pubkey_bytes(result[:counterparty]))
|
|
68
|
+
w.write_str_with_varint_len(result[:revelation_time].to_s)
|
|
69
|
+
encrypted_linkage = Common.to_binary(result[:encrypted_linkage])
|
|
70
|
+
w.write_varint(encrypted_linkage.bytesize)
|
|
71
|
+
w.write_bytes(encrypted_linkage)
|
|
72
|
+
encrypted_linkage_proof = Common.to_binary(result[:encrypted_linkage_proof])
|
|
73
|
+
w.write_varint(encrypted_linkage_proof.bytesize)
|
|
74
|
+
w.write_bytes(encrypted_linkage_proof)
|
|
75
|
+
w.buf
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def deserialize(bytes)
|
|
79
|
+
r = BSV::Wallet::Wire::Reader.new(bytes)
|
|
80
|
+
prover = r.read_bytes(PUBKEY_SIZE)
|
|
81
|
+
verifier = r.read_bytes(PUBKEY_SIZE)
|
|
82
|
+
counterparty = r.read_bytes(PUBKEY_SIZE)
|
|
83
|
+
revelation_time = r.read_str_with_varint_len
|
|
84
|
+
el_len = r.read_varint
|
|
85
|
+
encrypted_linkage = r.read_bytes(el_len)
|
|
86
|
+
elp_len = r.read_varint
|
|
87
|
+
encrypted_linkage_proof = r.read_bytes(elp_len)
|
|
88
|
+
{
|
|
89
|
+
prover: prover,
|
|
90
|
+
verifier: verifier,
|
|
91
|
+
counterparty: counterparty,
|
|
92
|
+
revelation_time: revelation_time,
|
|
93
|
+
encrypted_linkage: encrypted_linkage,
|
|
94
|
+
encrypted_linkage_proof: encrypted_linkage_proof
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def pubkey_bytes(value)
|
|
99
|
+
return value.b if value.is_a?(String) && value.bytesize == PUBKEY_SIZE
|
|
100
|
+
|
|
101
|
+
[value.to_s].pack('H*')
|
|
102
|
+
end
|
|
103
|
+
private_class_method :pubkey_bytes
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 wire codec for the +reveal_specific_key_linkage+ call (call byte 10).
|
|
7
|
+
#
|
|
8
|
+
# Port of go-sdk/wallet/serializer/reveal_specific_key_linkage.go.
|
|
9
|
+
module RevealSpecificKeyLinkage
|
|
10
|
+
PUBKEY_SIZE = 33
|
|
11
|
+
|
|
12
|
+
# Args wire layout:
|
|
13
|
+
# [key-related params: protocol + key_id + counterparty + privileged]
|
|
14
|
+
# [33 bytes: verifier compressed pubkey]
|
|
15
|
+
module Args
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
def serialize(args)
|
|
19
|
+
verifier = args[:verifier]
|
|
20
|
+
raise BSV::Wallet::InvalidParameterError.new('verifier', 'a 33-byte binary pubkey or 66-char hex') unless verifier
|
|
21
|
+
|
|
22
|
+
w = BSV::Wallet::Wire::Writer.new
|
|
23
|
+
Common.write_key_related_params(
|
|
24
|
+
w,
|
|
25
|
+
protocol_id: args[:protocol_id],
|
|
26
|
+
key_id: args[:key_id],
|
|
27
|
+
counterparty: args[:counterparty],
|
|
28
|
+
privileged: args[:privileged],
|
|
29
|
+
privileged_reason: args[:privileged_reason]
|
|
30
|
+
)
|
|
31
|
+
w.write_bytes(pubkey_bytes(verifier))
|
|
32
|
+
w.buf
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def deserialize(bytes)
|
|
36
|
+
r = BSV::Wallet::Wire::Reader.new(bytes)
|
|
37
|
+
params = Common.read_key_related_params(r)
|
|
38
|
+
verifier = r.read_bytes(PUBKEY_SIZE)
|
|
39
|
+
params.merge(verifier: verifier)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def pubkey_bytes(value)
|
|
43
|
+
return value.b if value.is_a?(String) && value.bytesize == PUBKEY_SIZE
|
|
44
|
+
|
|
45
|
+
[value.to_s].pack('H*')
|
|
46
|
+
end
|
|
47
|
+
private_class_method :pubkey_bytes
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Result wire layout:
|
|
51
|
+
# [33 bytes: prover pubkey]
|
|
52
|
+
# [33 bytes: verifier pubkey]
|
|
53
|
+
# [33 bytes: counterparty pubkey]
|
|
54
|
+
# [1 byte: security_level][VarInt protocol_name_len][protocol_name bytes]
|
|
55
|
+
# [VarInt key_id_len][key_id bytes]
|
|
56
|
+
# [VarInt encrypted_linkage_len][encrypted_linkage bytes]
|
|
57
|
+
# [VarInt encrypted_linkage_proof_len][encrypted_linkage_proof bytes]
|
|
58
|
+
# [1 byte: proof_type]
|
|
59
|
+
module Result
|
|
60
|
+
module_function
|
|
61
|
+
|
|
62
|
+
def serialize(result)
|
|
63
|
+
w = BSV::Wallet::Wire::Writer.new
|
|
64
|
+
w.write_bytes(pubkey_bytes(result[:prover]))
|
|
65
|
+
w.write_bytes(pubkey_bytes(result[:verifier]))
|
|
66
|
+
w.write_bytes(pubkey_bytes(result[:counterparty]))
|
|
67
|
+
Common.write_protocol(w, result[:protocol_id])
|
|
68
|
+
key_id_bytes = result[:key_id].to_s.b
|
|
69
|
+
w.write_varint(key_id_bytes.bytesize)
|
|
70
|
+
w.write_bytes(key_id_bytes)
|
|
71
|
+
encrypted_linkage = Common.to_binary(result[:encrypted_linkage])
|
|
72
|
+
w.write_varint(encrypted_linkage.bytesize)
|
|
73
|
+
w.write_bytes(encrypted_linkage)
|
|
74
|
+
encrypted_linkage_proof = Common.to_binary(result[:encrypted_linkage_proof])
|
|
75
|
+
w.write_varint(encrypted_linkage_proof.bytesize)
|
|
76
|
+
w.write_bytes(encrypted_linkage_proof)
|
|
77
|
+
w.write_byte(result[:proof_type].to_i)
|
|
78
|
+
w.buf
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def deserialize(bytes)
|
|
82
|
+
r = BSV::Wallet::Wire::Reader.new(bytes)
|
|
83
|
+
prover = r.read_bytes(PUBKEY_SIZE)
|
|
84
|
+
verifier = r.read_bytes(PUBKEY_SIZE)
|
|
85
|
+
counterparty = r.read_bytes(PUBKEY_SIZE)
|
|
86
|
+
protocol_id = Common.read_protocol(r)
|
|
87
|
+
key_id_len = r.read_varint
|
|
88
|
+
key_id = r.read_bytes(key_id_len).force_encoding('UTF-8')
|
|
89
|
+
el_len = r.read_varint
|
|
90
|
+
encrypted_linkage = r.read_bytes(el_len)
|
|
91
|
+
elp_len = r.read_varint
|
|
92
|
+
encrypted_linkage_proof = r.read_bytes(elp_len)
|
|
93
|
+
proof_type = r.read_byte
|
|
94
|
+
{
|
|
95
|
+
prover: prover,
|
|
96
|
+
verifier: verifier,
|
|
97
|
+
counterparty: counterparty,
|
|
98
|
+
protocol_id: protocol_id,
|
|
99
|
+
key_id: key_id,
|
|
100
|
+
encrypted_linkage: encrypted_linkage,
|
|
101
|
+
encrypted_linkage_proof: encrypted_linkage_proof,
|
|
102
|
+
proof_type: proof_type
|
|
103
|
+
}
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def pubkey_bytes(value)
|
|
107
|
+
return value.b if value.is_a?(String) && value.bytesize == PUBKEY_SIZE
|
|
108
|
+
|
|
109
|
+
[value.to_s].pack('H*')
|
|
110
|
+
end
|
|
111
|
+
private_class_method :pubkey_bytes
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 serialiser for sign_action args (call byte 2).
|
|
7
|
+
#
|
|
8
|
+
# Wire layout (port of go-sdk/wallet/serializer/sign_action_args.go):
|
|
9
|
+
# [varint] spends count
|
|
10
|
+
# For each spend (sorted by input_index):
|
|
11
|
+
# [varint] input_index
|
|
12
|
+
# [int_bytes] unlocking_script
|
|
13
|
+
# [optional_uint32] sequence_number
|
|
14
|
+
# [int_bytes] reference
|
|
15
|
+
# [1 byte] options present flag (0=absent, 1=present)
|
|
16
|
+
# If options present:
|
|
17
|
+
# [optional_bool] accept_delayed_broadcast
|
|
18
|
+
# [optional_bool] return_txid_only
|
|
19
|
+
# [optional_bool] no_send
|
|
20
|
+
# [txid_slice] send_with
|
|
21
|
+
module SignActionArgs
|
|
22
|
+
module_function
|
|
23
|
+
|
|
24
|
+
# @param args [Hash]
|
|
25
|
+
# @return [String] binary
|
|
26
|
+
def serialize(args)
|
|
27
|
+
w = Wire::Writer.new
|
|
28
|
+
|
|
29
|
+
spends = args[:spends] || {}
|
|
30
|
+
w.write_varint(spends.length)
|
|
31
|
+
spends.keys.sort.each do |idx|
|
|
32
|
+
spend = spends[idx]
|
|
33
|
+
w.write_varint(idx)
|
|
34
|
+
w.write_int_bytes(spend[:unlocking_script])
|
|
35
|
+
w.write_optional_uint32(spend[:sequence_number])
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
w.write_int_bytes(args[:reference])
|
|
39
|
+
|
|
40
|
+
opts = args[:options]
|
|
41
|
+
if opts
|
|
42
|
+
w.write_byte(1)
|
|
43
|
+
w.write_optional_bool(opts[:accept_delayed_broadcast])
|
|
44
|
+
w.write_optional_bool(opts[:return_txid_only])
|
|
45
|
+
w.write_optional_bool(opts[:no_send])
|
|
46
|
+
w.write_txid_slice(opts[:send_with])
|
|
47
|
+
else
|
|
48
|
+
w.write_byte(0)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
w.buf
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @param bytes [String] binary
|
|
55
|
+
# @return [Hash]
|
|
56
|
+
def deserialize(bytes)
|
|
57
|
+
r = Wire::Reader.new(bytes)
|
|
58
|
+
|
|
59
|
+
spend_count = r.read_varint
|
|
60
|
+
spends = {}
|
|
61
|
+
spend_count.times do
|
|
62
|
+
idx = r.read_varint
|
|
63
|
+
script = r.read_int_bytes
|
|
64
|
+
seq = r.read_optional_uint32
|
|
65
|
+
spend = { unlocking_script: script }
|
|
66
|
+
spend[:sequence_number] = seq unless seq.nil?
|
|
67
|
+
spends[idx] = spend
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
reference = r.read_int_bytes
|
|
71
|
+
|
|
72
|
+
options_present = r.read_byte
|
|
73
|
+
options = if options_present == 1
|
|
74
|
+
opts = {}
|
|
75
|
+
v = r.read_optional_bool
|
|
76
|
+
opts[:accept_delayed_broadcast] = v unless v.nil?
|
|
77
|
+
v = r.read_optional_bool
|
|
78
|
+
opts[:return_txid_only] = v unless v.nil?
|
|
79
|
+
v = r.read_optional_bool
|
|
80
|
+
opts[:no_send] = v unless v.nil?
|
|
81
|
+
sw = r.read_txid_slice
|
|
82
|
+
opts[:send_with] = sw unless sw.nil?
|
|
83
|
+
opts
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
result = { spends: spends }
|
|
87
|
+
result[:reference] = reference unless reference.nil? || reference.empty?
|
|
88
|
+
result[:options] = options unless options.nil?
|
|
89
|
+
result
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 serialiser for sign_action result (call byte 2).
|
|
7
|
+
#
|
|
8
|
+
# Wire layout (port of go-sdk/wallet/serializer/sign_action_result.go):
|
|
9
|
+
# [flag + 32 bytes] txid with flag byte: 0=absent, 1=present (wire-order)
|
|
10
|
+
# [flag + int_bytes] tx (BEEF bytes) with flag byte: 0=absent, 1=present + varint_len
|
|
11
|
+
# [send_with_results] varint count + txid (32 bytes) + status_byte each
|
|
12
|
+
module SignActionResult
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
# @param result [Hash]
|
|
16
|
+
# @return [String] binary
|
|
17
|
+
def serialize(result)
|
|
18
|
+
w = Wire::Writer.new
|
|
19
|
+
|
|
20
|
+
txid_bytes = result[:txid] ? [result[:txid]].pack('H*').reverse : nil
|
|
21
|
+
w.write_optional_bytes_with_flag(txid_bytes, fixed_size: 32)
|
|
22
|
+
w.write_optional_bytes_with_flag(result[:tx])
|
|
23
|
+
|
|
24
|
+
Common.write_send_with_results(w, result[:send_with_results])
|
|
25
|
+
|
|
26
|
+
w.buf
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @param bytes [String] binary
|
|
30
|
+
# @return [Hash]
|
|
31
|
+
def deserialize(bytes)
|
|
32
|
+
r = Wire::Reader.new(bytes)
|
|
33
|
+
|
|
34
|
+
txid_raw = r.read_optional_bytes_with_flag(fixed_size: 32)
|
|
35
|
+
txid_hex = txid_raw&.reverse&.unpack1('H*')
|
|
36
|
+
tx = r.read_optional_bytes_with_flag
|
|
37
|
+
|
|
38
|
+
send_with_results = Common.read_send_with_results(r)
|
|
39
|
+
|
|
40
|
+
result = {}
|
|
41
|
+
result[:txid] = txid_hex unless txid_hex.nil?
|
|
42
|
+
result[:tx] = tx unless tx.nil?
|
|
43
|
+
result[:send_with_results] = send_with_results unless send_with_results.nil?
|
|
44
|
+
result
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BSV
|
|
4
|
+
module Wallet
|
|
5
|
+
module Serializer
|
|
6
|
+
# BRC-103 serialisers for is_authenticated (call byte 23) and
|
|
7
|
+
# wait_for_authentication (call byte 24).
|
|
8
|
+
#
|
|
9
|
+
# Both calls take no args payload (originator is in the frame header).
|
|
10
|
+
#
|
|
11
|
+
# Result wire format:
|
|
12
|
+
# is_authenticated: [1 byte] 0x01 = true, 0x00 = false
|
|
13
|
+
# wait_for_authentication: empty payload → always returns authenticated: true
|
|
14
|
+
#
|
|
15
|
+
# Port of go-sdk/wallet/serializer/authenticated.go.
|
|
16
|
+
module IsAuthenticated
|
|
17
|
+
module Args
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
def serialize(_args = {})
|
|
21
|
+
''.b
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def deserialize(_bytes)
|
|
25
|
+
{}
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module Result
|
|
30
|
+
module_function
|
|
31
|
+
|
|
32
|
+
# @param result [Hash] { authenticated: Boolean }
|
|
33
|
+
# @return [String] 1-byte binary
|
|
34
|
+
def serialize(result)
|
|
35
|
+
[result[:authenticated] ? 1 : 0].pack('C')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @param bytes [String] binary — must be exactly 1 byte
|
|
39
|
+
# @return [Hash] { authenticated: Boolean }
|
|
40
|
+
def deserialize(bytes)
|
|
41
|
+
data = bytes.b
|
|
42
|
+
unless data.bytesize == 1
|
|
43
|
+
raise BSV::Wallet::InvalidParameterError.new(
|
|
44
|
+
'is_authenticated result',
|
|
45
|
+
'exactly 1 byte'
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
{ authenticated: data.getbyte(0) == 1 }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
module WaitForAuthentication
|
|
55
|
+
module Args
|
|
56
|
+
module_function
|
|
57
|
+
|
|
58
|
+
def serialize(_args = {})
|
|
59
|
+
''.b
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def deserialize(_bytes)
|
|
63
|
+
{}
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module Result
|
|
68
|
+
module_function
|
|
69
|
+
|
|
70
|
+
# @param _result [Hash] ignored — always serialises as empty payload
|
|
71
|
+
# @return [String] empty binary
|
|
72
|
+
def serialize(_result = {})
|
|
73
|
+
''.b
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @param _bytes [String] ignored — always returns authenticated: true
|
|
77
|
+
# @return [Hash] { authenticated: true }
|
|
78
|
+
def deserialize(_bytes = nil)
|
|
79
|
+
{ authenticated: true }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|