quorum_sdk 0.1.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.
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuorumSdk
4
+ # Wrapper for some useful methods
5
+ module Utils
6
+ class << self
7
+ def parse_seed_url(url)
8
+ url = Addressable::URI.parse(url.gsub(/\\u([a-f0-9]{4})/i) { [::Regexp.last_match(1).hex].pack('U') })
9
+ query_values = url.query_values
10
+
11
+ group_name = query_values['a']
12
+ group_id = uuid_from_base64 query_values['g']
13
+ block_id = uuid_from_base64 query_values['b']
14
+ signature = Base64.strict_encode64 Base64.urlsafe_decode64(query_values['s'])
15
+ owner_pubkey = query_values['k']
16
+ cipher_key = Base64.urlsafe_decode64(query_values['c']).unpack1('H*')
17
+ app_key = query_values['y']
18
+ consensus_type = query_values['n'].to_s == '1' ? 'pos' : 'poa'
19
+ encryption_type = query_values['e'].to_s == '0' ? 'public' : 'private'
20
+ chain_urls = query_values['u'].split('|')
21
+
22
+ {
23
+ group_id:,
24
+ group_name:,
25
+ block_id:,
26
+ signature:,
27
+ owner_pubkey:,
28
+ cipher_key:,
29
+ app_key:,
30
+ consensus_type:,
31
+ encryption_type:,
32
+ chain_urls:
33
+ }
34
+ end
35
+
36
+ def uuid_from_base64(str)
37
+ hex = Base64.urlsafe_decode64(str).unpack1('H*')
38
+ format(
39
+ '%<first>s-%<second>s-%<third>s-%<forth>s-%<fifth>s',
40
+ first: hex[0..7],
41
+ second: hex[8..11],
42
+ third: hex[12..15],
43
+ forth: hex[16..19],
44
+ fifth: hex[20..]
45
+ )
46
+ end
47
+
48
+ ARGUMENTS_FOR_ENCRYPT_TRX = %i[private_key group_id cipher_key data].freeze
49
+ def encrypt_trx(**kwargs)
50
+ raise ArgumentError, "Keyword arguments #{ARGUMENTS_FOR_ENCRYPT_TRX} must be provided" unless ARGUMENTS_FOR_ENCRYPT_TRX.all?(&->(arg) { arg.in? kwargs.keys })
51
+ raise ArgumentError, 'data should be instance of Google::Protobuf::MessageExts' unless kwargs[:data].is_a?(Google::Protobuf::MessageExts)
52
+
53
+ data = Google::Protobuf::Any.new(
54
+ type_url: "type.googleapis.com/#{kwargs[:data].class.descriptor.name}",
55
+ value: kwargs[:data].to_proto
56
+ ).to_proto
57
+ encrypted_data = aes_encrypt data, key: kwargs[:cipher_key]
58
+
59
+ account = QuorumSdk::Account.new priv: kwargs[:private_key]
60
+
61
+ msg =
62
+ Quorum::Pb::Trx.new(
63
+ TrxId: (kwargs[:trx_id] || SecureRandom.uuid),
64
+ GroupId: kwargs[:group_id],
65
+ Data: encrypted_data,
66
+ TimeStamp: (kwargs[:timestamp].to_i || (Time.now.to_f * 1e9).to_i),
67
+ Version: (kwargs[:version] || '1.0.0'),
68
+ Expired: (kwargs[:expired].to_i || (30.seconds.from_now.to_f * 1e9).to_i),
69
+ Nonce: (kwargs[:nonce] || 1),
70
+ SenderPubkey: Base64.urlsafe_encode64(account.public_bytes_compressed, padding: false)
71
+ )
72
+
73
+ hash = Digest::SHA256.hexdigest msg.to_proto
74
+ signature = account.sign [hash].pack('H*')
75
+ msg.SenderSign = [signature].pack('H*')
76
+ trx_json = {
77
+ TrxBytes: Base64.strict_encode64(msg.to_proto)
78
+ }
79
+ encrypted = aes_encrypt trx_json.to_json, key: kwargs[:cipher_key]
80
+ Base64.strict_encode64 encrypted
81
+ end
82
+
83
+ def decrypt_trx(cipher, key:)
84
+ cipher = Base64.strict_decode64 cipher
85
+ trx_json = JSON.parse aes_decrypt(cipher, key:)
86
+ trx_bytes = Base64.strict_decode64 trx_json['TrxBytes']
87
+ trx = Quorum::Pb::Trx.decode trx_bytes
88
+
89
+ trx_without_sig = trx.dup
90
+ trx_without_sig.clear_SenderSign
91
+ hash = Digest::SHA256.hexdigest Quorum::Pb::Trx.encode(trx_without_sig)
92
+
93
+ signature = trx.SenderSign.unpack1('H*')
94
+ public_key_compressed = Base64.urlsafe_decode64(trx.SenderPubkey).unpack1('H*')
95
+ public_key_uncompressed = Eth::Signature.recover [hash].pack('H*'), signature
96
+ raise QuorumSdk::Error, 'Signature not verified' if public_key_uncompressed[2...66] != public_key_compressed[2...]
97
+
98
+ data = decrypt_trx_data(trx.Data, key:)
99
+
100
+ trx = JSON.parse Quorum::Pb::Trx.encode_json(trx)
101
+ trx['Data'] = data
102
+ trx.with_indifferent_access
103
+ end
104
+
105
+ def decrypt_trx_data(cipher, key:)
106
+ decrypted_data = aes_decrypt(cipher, key:)
107
+ obj = Google::Protobuf::Any.decode decrypted_data
108
+ msgclass = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(obj.type_url.split('/').last).msgclass
109
+ JSON.parse msgclass.encode_json(msgclass.decode(obj.value))
110
+ end
111
+
112
+ def aes_encrypt(data, key:)
113
+ encipher = OpenSSL::Cipher.new('aes-256-gcm').encrypt
114
+ encipher.key = [key].pack('H*')
115
+ iv = encipher.random_iv
116
+ encipher.iv = iv
117
+ encrypted = encipher.update(data) + encipher.final
118
+ [
119
+ iv,
120
+ encrypted,
121
+ encipher.auth_tag
122
+ ].join
123
+ end
124
+
125
+ def aes_decrypt(cipher, key:)
126
+ decipher = OpenSSL::Cipher.new('aes-256-gcm').decrypt
127
+ decipher.key = [key].pack('H*')
128
+ decipher.iv = cipher[...12]
129
+ decipher.auth_tag = cipher[-16...]
130
+ decipher.update(cipher[12...-16]) + decipher.final
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuorumSdk
4
+ VERSION = '0.1.0'
5
+ end
data/lib/quorum_sdk.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'addressable/uri'
4
+ require 'active_support/all'
5
+ require 'base64'
6
+ require 'bcrypt'
7
+ require 'eth'
8
+ require 'faraday'
9
+ require 'faraday/retry'
10
+ require 'google/protobuf/well_known_types'
11
+
12
+ require_relative 'proto/activity_stream_pb'
13
+ require_relative 'proto/chain_pb'
14
+ require_relative 'quorum_sdk/account'
15
+ require_relative 'quorum_sdk/api'
16
+ require_relative 'quorum_sdk/utils'
17
+ require_relative 'quorum_sdk/version'
18
+
19
+ module QuorumSdk
20
+ class Error < StandardError; end
21
+ class ArgumentError < Error; end
22
+ end
@@ -0,0 +1,4 @@
1
+ module QuorumSdk
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,181 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quorum_sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - an-lee
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-01-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: addressable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bcrypt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: eth
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.5'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: faraday-retry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: google-protobuf
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3'
111
+ - !ruby/object:Gem::Dependency
112
+ name: sha3
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
125
+ description: A API wrapper for Quorum
126
+ email:
127
+ - an.lee.work@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".rubocop.yml"
133
+ - CHANGELOG.md
134
+ - CODE_OF_CONDUCT.md
135
+ - Gemfile
136
+ - Gemfile.lock
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - activity_stream_pb.rb
141
+ - lib/proto/activity_stream.proto
142
+ - lib/proto/activity_stream_pb.rb
143
+ - lib/proto/chain.proto
144
+ - lib/proto/chain_pb.rb
145
+ - lib/quorum_sdk.rb
146
+ - lib/quorum_sdk/account.rb
147
+ - lib/quorum_sdk/api.rb
148
+ - lib/quorum_sdk/api/chain.rb
149
+ - lib/quorum_sdk/api/light_node.rb
150
+ - lib/quorum_sdk/client.rb
151
+ - lib/quorum_sdk/utils.rb
152
+ - lib/quorum_sdk/version.rb
153
+ - sig/quorum_sdk.rbs
154
+ homepage: https://github.com/an-lee/quorum_sdk
155
+ licenses:
156
+ - MIT
157
+ metadata:
158
+ homepage_uri: https://github.com/an-lee/quorum_sdk
159
+ source_code_uri: https://github.com/an-lee/quorum_sdk
160
+ changelog_uri: https://github.com/an-lee/quorum_sdk/CHANGELOG.md
161
+ rubygems_mfa_required: 'true'
162
+ post_install_message:
163
+ rdoc_options: []
164
+ require_paths:
165
+ - lib
166
+ required_ruby_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '3.1'
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ requirements: []
177
+ rubygems_version: 3.4.2
178
+ signing_key:
179
+ specification_version: 4
180
+ summary: A Quorum SDK implemented in Ruby
181
+ test_files: []