bsv-sdk 0.20.0 → 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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -0
  3. data/lib/bsv/mcp/tools/broadcast_p2pkh.rb +5 -3
  4. data/lib/bsv/network/protocols/arc.rb +4 -30
  5. data/lib/bsv/network/protocols/arcade.rb +163 -0
  6. data/lib/bsv/network/protocols/chaintracks.rb +6 -3
  7. data/lib/bsv/network/protocols/jungle_bus.rb +6 -0
  8. data/lib/bsv/network/protocols.rb +1 -0
  9. data/lib/bsv/network/providers/gorilla_pool.rb +18 -18
  10. data/lib/bsv/network/util.rb +44 -0
  11. data/lib/bsv/network.rb +1 -0
  12. data/lib/bsv/transaction/chain_tracker.rb +74 -13
  13. data/lib/bsv/transaction/chain_trackers.rb +0 -10
  14. data/lib/bsv/transaction/fee_models/live_policy.rb +10 -8
  15. data/lib/bsv/version.rb +1 -1
  16. data/lib/bsv/wallet/errors.rb +65 -21
  17. data/lib/bsv/wallet/proto_wallet/validators.rb +7 -49
  18. data/lib/bsv/wallet/proto_wallet.rb +14 -1
  19. data/lib/bsv/wallet/serializer/abort_action.rb +38 -0
  20. data/lib/bsv/wallet/serializer/acquire_certificate.rb +171 -0
  21. data/lib/bsv/wallet/serializer/certificate.rb +184 -0
  22. data/lib/bsv/wallet/serializer/common.rb +207 -0
  23. data/lib/bsv/wallet/serializer/create_action_args.rb +259 -0
  24. data/lib/bsv/wallet/serializer/create_action_result.rb +85 -0
  25. data/lib/bsv/wallet/serializer/create_hmac.rb +67 -0
  26. data/lib/bsv/wallet/serializer/create_signature.rb +90 -0
  27. data/lib/bsv/wallet/serializer/decrypt.rb +60 -0
  28. data/lib/bsv/wallet/serializer/discover_by_attributes.rb +61 -0
  29. data/lib/bsv/wallet/serializer/discover_by_identity_key.rb +49 -0
  30. data/lib/bsv/wallet/serializer/discover_certificates_result.rb +39 -0
  31. data/lib/bsv/wallet/serializer/encrypt.rb +60 -0
  32. data/lib/bsv/wallet/serializer/get_header_for_height.rb +71 -0
  33. data/lib/bsv/wallet/serializer/get_height.rb +46 -0
  34. data/lib/bsv/wallet/serializer/get_network.rb +65 -0
  35. data/lib/bsv/wallet/serializer/get_public_key.rb +86 -0
  36. data/lib/bsv/wallet/serializer/get_version.rb +44 -0
  37. data/lib/bsv/wallet/serializer/internalize_action.rb +151 -0
  38. data/lib/bsv/wallet/serializer/list_actions.rb +348 -0
  39. data/lib/bsv/wallet/serializer/list_certificates.rb +124 -0
  40. data/lib/bsv/wallet/serializer/list_outputs.rb +167 -0
  41. data/lib/bsv/wallet/serializer/prove_certificate.rb +146 -0
  42. data/lib/bsv/wallet/serializer/relinquish_certificate.rb +56 -0
  43. data/lib/bsv/wallet/serializer/relinquish_output.rb +44 -0
  44. data/lib/bsv/wallet/serializer/reveal_counterparty_key_linkage.rb +108 -0
  45. data/lib/bsv/wallet/serializer/reveal_specific_key_linkage.rb +116 -0
  46. data/lib/bsv/wallet/serializer/sign_action_args.rb +94 -0
  47. data/lib/bsv/wallet/serializer/sign_action_result.rb +49 -0
  48. data/lib/bsv/wallet/serializer/status.rb +85 -0
  49. data/lib/bsv/wallet/serializer/verify_hmac.rb +67 -0
  50. data/lib/bsv/wallet/serializer/verify_signature.rb +101 -0
  51. data/lib/bsv/wallet/serializer.rb +180 -0
  52. data/lib/bsv/wallet/substrates/http_wallet_json.rb +129 -0
  53. data/lib/bsv/wallet/substrates/http_wallet_wire.rb +99 -0
  54. data/lib/bsv/wallet/wallet_wire.rb +20 -0
  55. data/lib/bsv/wallet/wallet_wire_processor.rb +61 -0
  56. data/lib/bsv/wallet/wallet_wire_transceiver.rb +61 -0
  57. data/lib/bsv/wallet/wire/calls.rb +79 -0
  58. data/lib/bsv/wallet/wire/frame.rb +181 -0
  59. data/lib/bsv/wallet/wire/reader_writer.rb +402 -0
  60. data/lib/bsv/wallet/wire/validation.rb +213 -0
  61. data/lib/bsv/wallet/wire.rb +13 -0
  62. data/lib/bsv/wallet.rb +17 -0
  63. metadata +46 -2
  64. data/lib/bsv/transaction/chain_trackers/chaintracks.rb +0 -83
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSV
4
+ module Wallet
5
+ module Serializer
6
+ # BRC-103 wire codec for the +list_outputs+ call (call byte 6).
7
+ #
8
+ # Args wire layout:
9
+ # [varint-str: basket]
10
+ # [string-slice: tags] nil → NegativeOne
11
+ # [1 byte: tag_query_mode] 1=all, 2=any, 0xFF=nil
12
+ # [1 byte: include] 1=locking_scripts, 2=entire_transactions, 0xFF=nil
13
+ # [optional_bool: include_custom_instructions]
14
+ # [optional_bool: include_tags]
15
+ # [optional_bool: include_labels]
16
+ # [optional_uint32: limit]
17
+ # [optional_uint32: offset]
18
+ # [optional_bool: seek_permission]
19
+ #
20
+ # Result wire layout:
21
+ # [varint: total_outputs]
22
+ # [varint: beef_len, or NegativeOne if nil][beef bytes]
23
+ # per output:
24
+ # [32-byte wire txid][varint vout]
25
+ # [varint: satoshis]
26
+ # [varint: locking_script_len, or NegativeOne][script bytes]
27
+ # [varint-str: custom_instructions] 0-length string if nil
28
+ # [string-slice: tags]
29
+ # [string-slice: labels]
30
+ module ListOutputs
31
+ TAG_QUERY_MODE_ALL = 1
32
+ TAG_QUERY_MODE_ANY = 2
33
+ INCLUDE_LOCKING_SCRIPTS = 1
34
+ INCLUDE_ENTIRE_TRANSACTIONS = 2
35
+ NEGATIVE_ONE_BYTE = 0xFF
36
+
37
+ module_function
38
+
39
+ def serialize_args(args)
40
+ w = Wire::Writer.new
41
+ w.write_str_with_varint_len(args.fetch(:basket, ''))
42
+ w.write_string_slice(args[:tags])
43
+
44
+ mode_byte = case args[:tag_query_mode]
45
+ when :all then TAG_QUERY_MODE_ALL
46
+ when :any then TAG_QUERY_MODE_ANY
47
+ else NEGATIVE_ONE_BYTE
48
+ end
49
+ w.write_byte(mode_byte)
50
+
51
+ include_byte = case args[:include]
52
+ when :locking_scripts then INCLUDE_LOCKING_SCRIPTS
53
+ when :entire_transactions then INCLUDE_ENTIRE_TRANSACTIONS
54
+ else NEGATIVE_ONE_BYTE
55
+ end
56
+ w.write_byte(include_byte)
57
+
58
+ w.write_optional_bool(args[:include_custom_instructions])
59
+ w.write_optional_bool(args[:include_tags])
60
+ w.write_optional_bool(args[:include_labels])
61
+ w.write_optional_uint32(args[:limit])
62
+ w.write_optional_uint32(args[:offset])
63
+ w.write_optional_bool(args[:seek_permission])
64
+ w.buf
65
+ end
66
+
67
+ def deserialize_args(bytes)
68
+ r = Wire::Reader.new(bytes)
69
+ basket = r.read_str_with_varint_len
70
+ tags = r.read_string_slice
71
+
72
+ mode = case r.read_byte
73
+ when TAG_QUERY_MODE_ALL then :all
74
+ when TAG_QUERY_MODE_ANY then :any
75
+ end
76
+
77
+ inc = case r.read_byte
78
+ when INCLUDE_LOCKING_SCRIPTS then :locking_scripts
79
+ when INCLUDE_ENTIRE_TRANSACTIONS then :entire_transactions
80
+ end
81
+
82
+ {
83
+ basket: basket,
84
+ tags: tags,
85
+ tag_query_mode: mode,
86
+ include: inc,
87
+ include_custom_instructions: r.read_optional_bool,
88
+ include_tags: r.read_optional_bool,
89
+ include_labels: r.read_optional_bool,
90
+ limit: r.read_optional_uint32,
91
+ offset: r.read_optional_uint32,
92
+ seek_permission: r.read_optional_bool
93
+ }
94
+ end
95
+
96
+ def serialize_result(result)
97
+ w = Wire::Writer.new
98
+ outputs = result[:outputs] || []
99
+ w.write_varint(outputs.length)
100
+
101
+ beef = result[:beef]
102
+ if beef
103
+ w.write_int_bytes(beef.b)
104
+ else
105
+ w.write_negative_one
106
+ end
107
+
108
+ outputs.each do |output|
109
+ outpoint = output[:outpoint] || ''
110
+ txid_hex, vout = outpoint.to_s.split('.', 2)
111
+ w.write_outpoint(txid_hex.to_s, vout.to_i)
112
+ w.write_varint(output[:satoshis].to_i)
113
+ locking_script = output[:locking_script]
114
+ if locking_script && !locking_script.empty?
115
+ w.write_int_bytes(locking_script.b)
116
+ else
117
+ w.write_negative_one
118
+ end
119
+ w.write_optional_string(output[:custom_instructions])
120
+ w.write_string_slice(output[:tags])
121
+ w.write_string_slice(output[:labels])
122
+ end
123
+ w.buf
124
+ end
125
+
126
+ def deserialize_result(bytes)
127
+ r = Wire::Reader.new(bytes)
128
+ total_outputs = r.read_varint
129
+
130
+ beef_len = r.read_varint
131
+ beef = if beef_len == 0xFFFF_FFFF_FFFF_FFFF
132
+ nil
133
+ else
134
+ r.read_bytes(beef_len)
135
+ end
136
+
137
+ outputs = total_outputs.times.map do
138
+ outpoint_data = r.read_outpoint
139
+ outpoint = "#{outpoint_data[:txid_hex]}.#{outpoint_data[:vout]}"
140
+ satoshis = r.read_varint
141
+ locking_script_len = r.read_varint
142
+ locking_script = if locking_script_len == 0xFFFF_FFFF_FFFF_FFFF
143
+ nil
144
+ else
145
+ r.read_bytes(locking_script_len)
146
+ end
147
+ custom_instructions = r.read_optional_string
148
+ tags = r.read_string_slice
149
+ labels = r.read_string_slice
150
+
151
+ {
152
+ outpoint: outpoint,
153
+ satoshis: satoshis,
154
+ locking_script: locking_script,
155
+ custom_instructions: custom_instructions,
156
+ tags: tags,
157
+ labels: labels,
158
+ spendable: true
159
+ }
160
+ end
161
+
162
+ { total_outputs: total_outputs, beef: beef, outputs: outputs }
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -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