zilliqa 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,61 @@
1
+ require 'secp256k1'
2
+ require 'digest'
3
+
4
+ module Zilliqa
5
+ module Crypto
6
+ class KeyTool
7
+ include Secp256k1
8
+ def initialize(private_key)
9
+ is_raw = private_key.length == 32
10
+
11
+ @pk = PrivateKey.new(privkey: private_key, raw: is_raw)
12
+ end
13
+
14
+ def self.generate_private_key
15
+ Util.encode_hex KeyTool.generate_random_bytes(32)
16
+ end
17
+
18
+ def self.generate_random_bytes(size)
19
+ SecureRandom.random_bytes(size)
20
+ end
21
+
22
+ # getPubKeyFromPrivateKey
23
+ #
24
+ # takes a hex-encoded string (private key) and returns its corresponding
25
+ # hex-encoded 33-byte public key.
26
+ #
27
+ # @param {string} privateKey
28
+ # @returns {string}
29
+ def self.get_public_key_from_private_key(private_key, is_compressed = true)
30
+ is_raw = private_key.length == 32
31
+
32
+ pk = PrivateKey.new(privkey: private_key, raw: is_raw)
33
+
34
+ (Util.encode_hex pk.pubkey.serialize(compressed: is_compressed)).downcase
35
+ end
36
+
37
+ # getAddressFromPrivateKey
38
+ #
39
+ # takes a hex-encoded string (private key) and returns its corresponding
40
+ # 20-byte hex-encoded address.
41
+ #
42
+ # @param {string} privateKey
43
+ # @returns {string}
44
+ def self.get_address_from_private_key(private_key)
45
+ public_key = KeyTool.get_public_key_from_private_key(private_key)
46
+ KeyTool.get_address_from_public_key(public_key)
47
+ end
48
+
49
+ # getAddressFromPublicKey
50
+ #
51
+ # takes hex-encoded string and returns the corresponding address
52
+ #
53
+ # @param {string} public_key
54
+ # @returns {string}
55
+ def self.get_address_from_public_key(public_key)
56
+ orig_address = Digest::SHA256.hexdigest Util.decode_hex public_key
57
+ Util::Bech32.to_bech32(orig_address[24..-1].downcase)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,147 @@
1
+ require 'secp256k1'
2
+ require 'digest'
3
+ require 'openssl'
4
+
5
+ module Zilliqa
6
+ module Crypto
7
+ class Schnorr
8
+ include Secp256k1
9
+
10
+ N = OpenSSL::BN.new('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16)
11
+ G = OpenSSL::BN.new('79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 16)
12
+
13
+ def initialize
14
+ end
15
+
16
+ # sign
17
+ #
18
+ # @param {String} msg
19
+ # @param {String} key
20
+ def self.sign(message, private_key, public_key)
21
+ sig = nil
22
+ until sig
23
+ k = Util.encode_hex SecureRandom.random_bytes(32)
24
+ k_bn = OpenSSL::BN.new(k, 16)
25
+
26
+ sig = try_sign(message, private_key, k_bn, public_key)
27
+ sig = Zilliqa::Util::Validator.signature?(sig.to_s) ? sig : nil
28
+ end
29
+
30
+ sig
31
+ end
32
+
33
+ # trySign
34
+ #
35
+ # @param {String} message - the message to sign over
36
+ # @param {String} privateKey - the private key
37
+ # @param {BN} k_bn - output of the HMAC-DRBG
38
+ #
39
+ # @returns {Signature | null =>}
40
+ def self.try_sign(message, private_key, k_bn, public_key)
41
+ group = OpenSSL::PKey::EC::Group.new('secp256k1')
42
+
43
+ prikey_bn = OpenSSL::BN.new(private_key, 16)
44
+
45
+ pubkey_bn = OpenSSL::BN.new(public_key, 16)
46
+ pubkey_point = OpenSSL::PKey::EC::Point.new(group, pubkey_bn)
47
+
48
+ throw 'Bad private key.' if prikey_bn.zero? || prikey_bn >= N
49
+
50
+ # 1a. check that k is not 0
51
+ return nil if k_bn.zero?
52
+
53
+ # 1b. check that k is < the order of the group
54
+ return nil if k_bn >= N
55
+
56
+ # 2. Compute commitment Q = kG, where g is the base point
57
+ q_point = pubkey_point.mul(0, k_bn)
58
+
59
+ # 3. Compute the challenge r = H(Q || pubKey || msg)
60
+ # mod reduce the r value by the order of secp256k1, n
61
+ r_bn = hash(q_point, pubkey_point, message) % N
62
+
63
+ return nil if r_bn.zero?
64
+
65
+ # 4. Compute s = k - r * prv
66
+ # 4a. Compute r * prv
67
+ s_bn = r_bn * prikey_bn % N
68
+ # 4b. Compute s = k - r * prv mod n
69
+ s_bn = k_bn.mod_sub(s_bn, N)
70
+
71
+ return nil if s_bn.zero?
72
+
73
+ Signature.new(r_bn.to_s(16), s_bn.to_s(16))
74
+ end
75
+
76
+
77
+ # Verify signature.
78
+ #
79
+ # @param {Buffer} message
80
+ # @param {Buffer} sig
81
+ # @param {Buffer} public_key
82
+ #
83
+ # @returns {boolean}
84
+ #
85
+ # 1. Check if r,s is in [1, ..., order-1]
86
+ # 2. Compute Q = sG + r*kpub
87
+ # 3. If Q = O (the neutral point), return 0;
88
+ # 4. r' = H(Q, kpub, m)
89
+ # 5. return r' == r
90
+ def self.verify(message, sig, public_key)
91
+ pubkey = PublicKey.new
92
+ pubkey.deserialize Util.decode_hex(public_key)
93
+
94
+ r = sig.r
95
+ r_bn = OpenSSL::BN.new(r, 16)
96
+
97
+ s = sig.s
98
+ s_bn = OpenSSL::BN.new(s, 16)
99
+
100
+ throw 'Invalid signature' if (s_bn.zero? || r_bn.zero?)
101
+
102
+ throw 'Invalid signature' if (s_bn.negative? || r_bn.negative?)
103
+
104
+ throw 'Invalid signature' if (s_bn >= N || r_bn >= N)
105
+
106
+ group = OpenSSL::PKey::EC::Group.new('secp256k1')
107
+ pubkey_bn = OpenSSL::BN.new(public_key, 16)
108
+ pubkey_point = OpenSSL::PKey::EC::Point.new(group, pubkey_bn)
109
+
110
+ throw 'Invalid public key' unless pubkey_point.on_curve?
111
+
112
+ q_point = pubkey_point.mul(r_bn, s_bn)
113
+
114
+ throw 'Invalid intermediate point.' if q_point.infinity?
115
+
116
+ h_bn = self.hash(q_point, pubkey_point, message) % N
117
+
118
+ throw 'Invalid hash.' if (h_bn.zero?)
119
+
120
+ h_bn.eql?(r_bn)
121
+ end
122
+
123
+
124
+ # Hash (r | M).
125
+ def self.hash(q_point, pubkey_point, message)
126
+ sha256 = Digest::SHA256.new
127
+ sha256 << q_point.to_octet_string(:compressed)
128
+ sha256 << pubkey_point.to_octet_string(:compressed)
129
+ sha256 << Util.decode_hex(message)
130
+
131
+ OpenSSL::BN.new(sha256.hexdigest, 16)
132
+ end
133
+ end
134
+
135
+ class Signature
136
+ attr_reader :r, :s
137
+ def initialize(r, s)
138
+ @r = r
139
+ @s = s
140
+ end
141
+
142
+ def to_s
143
+ "#{@r}#{@s}"
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,31 @@
1
+ require 'jsonrpc-client'
2
+
3
+ module JSONRPC
4
+ class Base
5
+ def self.make_id
6
+ "1"
7
+ end
8
+ end
9
+ end
10
+
11
+ module Zilliqa
12
+ module Jsonrpc
13
+ class Provider
14
+ def initialize(endpoint)
15
+ conn = Faraday.new { |connection|
16
+ connection.adapter Faraday.default_adapter
17
+ }
18
+ @client = JSONRPC::Client.new(endpoint, { connection: conn })
19
+ @endpoint = endpoint
20
+ end
21
+
22
+ def method_missing(sym, *args)
23
+ @client.invoke(sym.to_s, args)
24
+ end
25
+
26
+ def testnet?
27
+ @endpoint && !@endpoint.match('dev').nil?
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,44 @@
1
+ syntax = "proto2";
2
+
3
+ package laksa.proto;
4
+
5
+ // ============================================================================
6
+ // Primitives
7
+ // ============================================================================
8
+
9
+ message ByteArray
10
+ {
11
+ required bytes data = 1;
12
+ }
13
+
14
+ message ProtoTransactionCoreInfo
15
+ {
16
+ optional uint32 version = 1;
17
+ optional uint64 nonce = 2;
18
+ optional bytes toaddr = 3;
19
+ optional ByteArray senderpubkey = 4;
20
+ optional ByteArray amount = 5;
21
+ optional ByteArray gasprice = 6;
22
+ optional uint64 gaslimit = 7;
23
+ optional bytes code = 8;
24
+ optional bytes data = 9;
25
+ }
26
+
27
+ message ProtoTransaction
28
+ {
29
+ optional bytes tranid = 1;
30
+ optional ProtoTransactionCoreInfo info = 2;
31
+ optional ByteArray signature = 3;
32
+ }
33
+
34
+ message ProtoTransactionReceipt
35
+ {
36
+ optional bytes receipt = 1;
37
+ optional uint64 cumgas = 2;
38
+ }
39
+
40
+ message ProtoTransactionWithReceipt
41
+ {
42
+ optional ProtoTransaction transaction = 1;
43
+ optional ProtoTransactionReceipt receipt = 2;
44
+ }
@@ -0,0 +1,46 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: message.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_file("message.proto", :syntax => :proto2) do
8
+ add_message "laksa.proto.ByteArray" do
9
+ required :data, :bytes, 1
10
+ end
11
+ add_message "laksa.proto.ProtoTransactionCoreInfo" do
12
+ optional :version, :uint32, 1
13
+ optional :nonce, :uint64, 2
14
+ optional :toaddr, :bytes, 3
15
+ optional :senderpubkey, :message, 4, "laksa.proto.ByteArray"
16
+ optional :amount, :message, 5, "laksa.proto.ByteArray"
17
+ optional :gasprice, :message, 6, "laksa.proto.ByteArray"
18
+ optional :gaslimit, :uint64, 7
19
+ optional :code, :bytes, 8
20
+ optional :data, :bytes, 9
21
+ end
22
+ add_message "laksa.proto.ProtoTransaction" do
23
+ optional :tranid, :bytes, 1
24
+ optional :info, :message, 2, "laksa.proto.ProtoTransactionCoreInfo"
25
+ optional :signature, :message, 3, "laksa.proto.ByteArray"
26
+ end
27
+ add_message "laksa.proto.ProtoTransactionReceipt" do
28
+ optional :receipt, :bytes, 1
29
+ optional :cumgas, :uint64, 2
30
+ end
31
+ add_message "laksa.proto.ProtoTransactionWithReceipt" do
32
+ optional :transaction, :message, 1, "laksa.proto.ProtoTransaction"
33
+ optional :receipt, :message, 2, "laksa.proto.ProtoTransactionReceipt"
34
+ end
35
+ end
36
+ end
37
+
38
+ module Zilliqa
39
+ module Proto
40
+ ByteArray = Google::Protobuf::DescriptorPool.generated_pool.lookup("laksa.proto.ByteArray").msgclass
41
+ ProtoTransactionCoreInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("laksa.proto.ProtoTransactionCoreInfo").msgclass
42
+ ProtoTransaction = Google::Protobuf::DescriptorPool.generated_pool.lookup("laksa.proto.ProtoTransaction").msgclass
43
+ ProtoTransactionReceipt = Google::Protobuf::DescriptorPool.generated_pool.lookup("laksa.proto.ProtoTransactionReceipt").msgclass
44
+ ProtoTransactionWithReceipt = Google::Protobuf::DescriptorPool.generated_pool.lookup("laksa.proto.ProtoTransactionWithReceipt").msgclass
45
+ end
46
+ end
@@ -0,0 +1,28 @@
1
+ require 'bitcoin'
2
+
3
+ module Zilliqa
4
+ module Util
5
+ class Bech32
6
+
7
+ def self.to_bech32(address)
8
+ raise 'Invalid address format.' unless Validator.address?(address)
9
+
10
+ address = address.sub('0x','')
11
+
12
+ ret = Bitcoin::Bech32.convert_bits(Util.decode_hex(address).bytes, from_bits: 8, to_bits: 5, pad: false)
13
+
14
+ Bitcoin::Bech32.encode('zil', ret);
15
+ end
16
+
17
+ def self.from_bech32(address)
18
+ data = Bitcoin::Bech32.decode(address)
19
+
20
+ raise 'Expected hrp to be zil' unless data[0] == 'zil'
21
+
22
+ ret = Bitcoin::Bech32.convert_bits(data[1], from_bits: 5, to_bits: 8, pad: false)
23
+
24
+ Zilliqa::Account::Wallet.to_checksum_address(Util.encode_hex(ret.pack('c*'))).sub('0x', '')
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,37 @@
1
+ module Zilliqa
2
+ module Util
3
+ class Unit
4
+ ZIL = 'zil'
5
+ LI = 'li'
6
+ QA = 'qa'
7
+
8
+ def self.from_qa(qa, unit, is_pack = false)
9
+ ret = case unit
10
+ when ZIL
11
+ qa / 1000000000000.0
12
+ when LI
13
+ qa / 1000000.0
14
+ when QA
15
+ qa
16
+ end
17
+
18
+ if is_pack
19
+ ret.round
20
+ else
21
+ ret
22
+ end
23
+ end
24
+
25
+ def self.to_qa(qa, unit)
26
+ case unit
27
+ when ZIL
28
+ qa * 1000000000000
29
+ when LI
30
+ qa * 1000000
31
+ when QA
32
+ qa
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ module Zilliqa
2
+ module Util
3
+ extend self
4
+
5
+ def pack(a, b)
6
+ a << 16 + b
7
+ end
8
+
9
+ def encode_hex(b)
10
+ b.unpack('H*').first
11
+ end
12
+
13
+ def decode_hex(s)
14
+ [s].pack('H*')
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ module Zilliqa
2
+ module Util
3
+ class Validator
4
+ def self.public_key?(public_key)
5
+ m = /(0x)?\h{66}/ =~ public_key
6
+ m != nil
7
+ end
8
+
9
+ def self.private_key?(private_key)
10
+ m = /(0x)?\h{64}/ =~ private_key
11
+ m != nil
12
+ end
13
+
14
+ def self.address?(address)
15
+ return true if bech32?(address)
16
+ m = /(0x)?\h{40}/ =~ address
17
+ m != nil
18
+ end
19
+
20
+ def self.signature?(signature)
21
+ m = /(0x)?\h{128}/ =~ signature
22
+ m != nil
23
+ end
24
+
25
+ # checksum_address?
26
+ #
27
+ # takes hex-encoded string and returns boolean if address is checksumed
28
+ #
29
+ # @param {string} address
30
+ # @returns {boolean}
31
+ def self.checksum_address?(address)
32
+ self.address?(address) && Zilliqa::Account::Wallet::to_checksum_address(address) == address
33
+ end
34
+
35
+ def self.bech32?(address)
36
+ m = /^zil1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38}/ =~ address
37
+ m != nil
38
+ end
39
+ end
40
+ end
41
+ end