nem-ruby 0.0.1

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 (136) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +119 -0
  5. data/.travis.yml +23 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/README.md +81 -0
  9. data/Rakefile +6 -0
  10. data/examples/apostille_audit.rb +22 -0
  11. data/examples/apostille_create.rb +31 -0
  12. data/examples/endpoint/account.rb +73 -0
  13. data/examples/endpoint/account_local.rb +21 -0
  14. data/examples/endpoint/block.rb +14 -0
  15. data/examples/endpoint/chain.rb +15 -0
  16. data/examples/endpoint/debug.rb +17 -0
  17. data/examples/endpoint/local.rb +17 -0
  18. data/examples/endpoint/mosaic.rb +9 -0
  19. data/examples/endpoint/namespace.rb +13 -0
  20. data/examples/endpoint/node.rb +24 -0
  21. data/examples/endpoint/timesync.rb +9 -0
  22. data/examples/endpoint/transaction.rb +42 -0
  23. data/examples/localnode.rb +0 -0
  24. data/examples/nis.rb +34 -0
  25. data/examples/node_pool.rb +23 -0
  26. data/examples/transaction/importance_transfer.rb +23 -0
  27. data/examples/transaction/mosaic_definition_creation.rb +52 -0
  28. data/examples/transaction/mosaic_supply_change.rb +25 -0
  29. data/examples/transaction/multisig_add_cosignatory.rb +31 -0
  30. data/examples/transaction/multisig_aggregate_modification.rb +29 -0
  31. data/examples/transaction/multisig_signature.rb +41 -0
  32. data/examples/transaction/multisig_transfer.rb +35 -0
  33. data/examples/transaction/provision_namespace.rb +20 -0
  34. data/examples/transaction/transfer.rb +32 -0
  35. data/examples/transaction/transfer_mosaic.rb +72 -0
  36. data/examples/transaction/transfer_with_encrypted_message.rb +40 -0
  37. data/examples/transaction/transfer_with_local.rb +34 -0
  38. data/lib/nem.rb +21 -0
  39. data/lib/nem/apostille.rb +104 -0
  40. data/lib/nem/apostille_audit.rb +47 -0
  41. data/lib/nem/client.rb +170 -0
  42. data/lib/nem/configuration.rb +29 -0
  43. data/lib/nem/endpoint.rb +4 -0
  44. data/lib/nem/endpoint/account.rb +264 -0
  45. data/lib/nem/endpoint/base.rb +45 -0
  46. data/lib/nem/endpoint/block.rb +15 -0
  47. data/lib/nem/endpoint/chain.rb +17 -0
  48. data/lib/nem/endpoint/debug.rb +54 -0
  49. data/lib/nem/endpoint/local/account.rb +54 -0
  50. data/lib/nem/endpoint/local/chain.rb +15 -0
  51. data/lib/nem/endpoint/mosaic.rb +13 -0
  52. data/lib/nem/endpoint/namespace.rb +37 -0
  53. data/lib/nem/endpoint/node.rb +83 -0
  54. data/lib/nem/endpoint/timesync.rb +9 -0
  55. data/lib/nem/endpoint/transaction.rb +34 -0
  56. data/lib/nem/error.rb +6 -0
  57. data/lib/nem/fee.rb +2 -0
  58. data/lib/nem/fee/importance_transfer.rb +24 -0
  59. data/lib/nem/fee/mosaic_definition_creation.rb +24 -0
  60. data/lib/nem/fee/mosaic_supply_change_transfer.rb +24 -0
  61. data/lib/nem/fee/multisig.rb +24 -0
  62. data/lib/nem/fee/multisig_aggregation_modification.rb +28 -0
  63. data/lib/nem/fee/provision_namespace.rb +34 -0
  64. data/lib/nem/fee/transfer.rb +66 -0
  65. data/lib/nem/keypair.rb +44 -0
  66. data/lib/nem/mixin.rb +2 -0
  67. data/lib/nem/mixin/assignable.rb +12 -0
  68. data/lib/nem/model.rb +3 -0
  69. data/lib/nem/model/account.rb +67 -0
  70. data/lib/nem/model/account_historical.rb +19 -0
  71. data/lib/nem/model/block.rb +33 -0
  72. data/lib/nem/model/chain.rb +14 -0
  73. data/lib/nem/model/connection.rb +23 -0
  74. data/lib/nem/model/experience.rb +20 -0
  75. data/lib/nem/model/explorer_block.rb +21 -0
  76. data/lib/nem/model/harvest.rb +23 -0
  77. data/lib/nem/model/heartbeat.rb +21 -0
  78. data/lib/nem/model/importance.rb +29 -0
  79. data/lib/nem/model/importance_transfer_transaction.rb +16 -0
  80. data/lib/nem/model/keypair.rb +19 -0
  81. data/lib/nem/model/message.rb +91 -0
  82. data/lib/nem/model/mosaic.rb +21 -0
  83. data/lib/nem/model/mosaic_attachment.rb +22 -0
  84. data/lib/nem/model/mosaic_definition.rb +65 -0
  85. data/lib/nem/model/mosaic_definition_creation_transaction.rb +18 -0
  86. data/lib/nem/model/mosaic_id.rb +27 -0
  87. data/lib/nem/model/mosaic_levy.rb +32 -0
  88. data/lib/nem/model/mosaic_owned.rb +22 -0
  89. data/lib/nem/model/mosaic_properties.rb +44 -0
  90. data/lib/nem/model/mosaic_supply.rb +21 -0
  91. data/lib/nem/model/mosaic_supply_change_transaction.rb +18 -0
  92. data/lib/nem/model/multisig_aggregate_modification_transaction.rb +21 -0
  93. data/lib/nem/model/multisig_info.rb +16 -0
  94. data/lib/nem/model/multisig_signature_transaction.rb +17 -0
  95. data/lib/nem/model/multisig_transaction.rb +21 -0
  96. data/lib/nem/model/namespace.rb +24 -0
  97. data/lib/nem/model/nem_announce_result.rb +19 -0
  98. data/lib/nem/model/network_time.rb +16 -0
  99. data/lib/nem/model/nis_node_info.rb +26 -0
  100. data/lib/nem/model/node.rb +41 -0
  101. data/lib/nem/model/provision_namespace_transaction.rb +18 -0
  102. data/lib/nem/model/status.rb +21 -0
  103. data/lib/nem/model/timer.rb +31 -0
  104. data/lib/nem/model/timesync.rb +19 -0
  105. data/lib/nem/model/transaction.rb +71 -0
  106. data/lib/nem/model/transfer_transaction.rb +24 -0
  107. data/lib/nem/model/unlocked_info.rb +24 -0
  108. data/lib/nem/mosaic.rb +2 -0
  109. data/lib/nem/mosaic/dim_coin.rb +21 -0
  110. data/lib/nem/mosaic/dim_token.rb +21 -0
  111. data/lib/nem/mosaic/ecobit_eco.rb +21 -0
  112. data/lib/nem/mosaic/xem.rb +21 -0
  113. data/lib/nem/node.rb +29 -0
  114. data/lib/nem/node_pool.rb +31 -0
  115. data/lib/nem/request.rb +2 -0
  116. data/lib/nem/request/announce.rb +76 -0
  117. data/lib/nem/transaction.rb +3 -0
  118. data/lib/nem/transaction/base.rb +45 -0
  119. data/lib/nem/transaction/importance_transfer.rb +42 -0
  120. data/lib/nem/transaction/mosaic_definition_creation.rb +45 -0
  121. data/lib/nem/transaction/mosaic_supply_change.rb +45 -0
  122. data/lib/nem/transaction/multisig.rb +29 -0
  123. data/lib/nem/transaction/multisig_aggregate_modification.rb +30 -0
  124. data/lib/nem/transaction/multisig_cosignatory_modification.rb +33 -0
  125. data/lib/nem/transaction/multisig_signature.rb +31 -0
  126. data/lib/nem/transaction/provision_namespace.rb +65 -0
  127. data/lib/nem/transaction/transfer.rb +63 -0
  128. data/lib/nem/util.rb +44 -0
  129. data/lib/nem/util/assignable.rb +51 -0
  130. data/lib/nem/util/convert.rb +112 -0
  131. data/lib/nem/util/deserializer.rb +158 -0
  132. data/lib/nem/util/ed25519.rb +316 -0
  133. data/lib/nem/util/serializer.rb +260 -0
  134. data/lib/nem/version.rb +3 -0
  135. data/nem-ruby.gemspec +46 -0
  136. metadata +350 -0
@@ -0,0 +1,51 @@
1
+ module Nem
2
+ module Util
3
+ module Assignable
4
+ def initialize(attributes = {})
5
+ attributes.each do |k, v|
6
+ send("#{k.to_s}=", v) if respond_to?("#{k.to_s}=")
7
+ end if attributes
8
+ yield self if block_given?
9
+ end
10
+
11
+ # @param [Symbol, String] attr Attribute name
12
+ # @return [Any] Attribute value
13
+ def [](attr)
14
+ send(attr)
15
+ end
16
+
17
+ # @return [Hash] Attribute and value pairs
18
+ def to_hash
19
+ hashed_properties = instance_variables.each_with_object({}) do |var, hash|
20
+ hash[var.to_s.delete('@').to_sym] = instance_variable_get(var)
21
+ end
22
+ hashnize(hashed_properties)
23
+ end
24
+
25
+ # @return [String] JSON formatted structure
26
+ def to_json(state = nil)
27
+ to_hash.to_json(state)
28
+ end
29
+
30
+ private
31
+
32
+ def hashnize(obj)
33
+ case true
34
+ when obj.class.to_s.start_with?('Nem::Unit')
35
+ obj.to_s
36
+ when obj.class.to_s.start_with?('Nem::Struct')
37
+ obj.to_hash
38
+ when obj.is_a?(Array)
39
+ obj.map { |el| hashnize(el) }
40
+ when obj.is_a?(Hash)
41
+ obj.inject({}) do |hash, (k, v)|
42
+ hash[k] = hashnize(v)
43
+ hash
44
+ end
45
+ else
46
+ obj
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,112 @@
1
+ module Nem
2
+ module Util
3
+ module Convert
4
+ HEX_ENCODE_ARRAY = %w[0 1 2 3 4 5 6 7 8 9 a b c d e f]
5
+
6
+ # Reversed convertion of hex to Uint8Array
7
+ # @param [String] hex
8
+ # @return [Array]
9
+ def self.hex2ua_rev(hex)
10
+ hex2ua(hex).reverse
11
+ end
12
+
13
+ # Convert hex to Uint8Array
14
+ # @param [String] hex
15
+ # @return [Array]
16
+ def self.hex2ua(hex)
17
+ hex.scan(/../).map(&:hex)
18
+ end
19
+
20
+ # Convert hex to string
21
+ # @param [String] hex
22
+ # @return [String]
23
+ def self.hex2a(hex)
24
+ hex.scan(/../).inject('') { |memo, el| memo << el.hex.chr }
25
+ end
26
+
27
+ # @param [Array] bin
28
+ # @return [String]
29
+ def self.hex2bin(hex)
30
+ hex2ua(hex).pack('C*')
31
+ end
32
+
33
+ # @param [Array] bin
34
+ # @return [String]
35
+ def self.hex2bin_rev(hex)
36
+ hex2ua_rev(hex).pack('C*')
37
+ end
38
+
39
+ # @param [Array] bin
40
+ # @return [String]
41
+ def self.bin2hex(bin)
42
+ bin.map { |v| '%02x' % v }.join
43
+ end
44
+
45
+ # Convert UTF-8 to hex
46
+ # @param [string] str
47
+ # @return [string]
48
+ def self.utf8_to_hex(str)
49
+ rstr2utf8(str).bytes.inject('') { |memo, b| memo << b.to_s(16) }
50
+ end
51
+
52
+ # Convert an Array to hex
53
+ # @param [Array] ua - An Uint8Array
54
+ # @return [string]
55
+ def self.ua2hex(ua)
56
+ ua.inject('') { |memo, el| memo << "#{HEX_ENCODE_ARRAY[el >> 4]}#{HEX_ENCODE_ARRAY[el & 0x0f]}" }
57
+ end
58
+
59
+ # Convert an Uint8Array to WordArray
60
+ # @param [Array] ua - An Uint8Array
61
+ # @param [number] uaLength - The Uint8Array length
62
+ # @return [WordArray]
63
+ def self.ua2words(ua, ua_length)
64
+ ua[0, ua_length].each_slice(4).map do |chunk|
65
+ x = chunk[0] * 0x1000000 +
66
+ chunk[1] * 0x10000 +
67
+ chunk[2] * 0x100 +
68
+ chunk[3] * 0x1
69
+ x > 0x7fffffff ? x - 0x100000000 : x
70
+ end
71
+ end
72
+
73
+ # Convert a wordArray to Uint8Array
74
+ # @param [Array] destUa - A destination Uint8Array
75
+ # @param [Array] cryptowords - A wordArray
76
+ # @return [Array]
77
+ def self.words2ua(words)
78
+ words.inject([]) do |memo, v|
79
+ temp = []
80
+ v += 0x100000000 if v < 0
81
+ temp[0] = (v >> 24)
82
+ temp[1] = (v >> 16) & 0xff
83
+ temp[2] = (v >> 8) & 0xff
84
+ temp[3] = (v) & 0xff
85
+ memo + temp
86
+ end
87
+ end
88
+
89
+ # Converts a raw javascript string into a string of single byte characters using utf8 encoding.
90
+ # This makes it easier to perform other encoding operations on the string.
91
+ # @param [String] str
92
+ # @return [String]
93
+ def self.rstr2utf8(str)
94
+ str.unpack('U*').inject('') do |memo, c|
95
+ memo << case
96
+ when c < 128
97
+ c.chr
98
+ when 128 < c && c < 2048
99
+ (c >> 6 | 192).chr + (c & 63 | 128).chr
100
+ else
101
+ (c >> 12 | 224).chr + (c >> 6 & 63 | 128).chr + (c & 63 | 128).chr
102
+ end
103
+ end
104
+ end
105
+
106
+ # Does the reverse of rstr2utf8.
107
+ def utf82rstr(input)
108
+ raise 'Not implemented.'
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,158 @@
1
+ module Nem
2
+ module Util
3
+ module Deserializer
4
+ # Deserialize a transaction object
5
+ # @param [String] serialized
6
+ # @return [Hash]
7
+ def self.deserialize_transaction(serialized)
8
+ s = Nem::Util::Convert.hex2ua(serialized)
9
+ common = s[0, 60]
10
+ specific = s[60, s.size]
11
+ type = deserialize_int(common[0, 4])
12
+ method = case type
13
+ when 0x0101 then method(:deserialize_transfer)
14
+ when 0x0801 then method(:deserialize_importance_transfer)
15
+ when 0x1001 then method(:deserialize_multisig_aggregate_modification)
16
+ when 0x1002 then method(:deserialize_multisig_signature)
17
+ when 0x1004 then method(:deserialize_multisig)
18
+ when 0x2001 then method(:deserialize_provision_namespace)
19
+ when 0x4001 then method(:deserialize_mosaic_definition_creation)
20
+ when 0x4002 then method(:deserialize_mosaic_supply_change)
21
+ else raise "Not implemented entity type: #{type}"
22
+ end
23
+ deserialize_common(common).merge(method.call(specific))
24
+ end
25
+
26
+ private
27
+
28
+ # Deserialize a transfer transaction object
29
+ # @param [String] serialized
30
+ # @return [Hash]
31
+ def self.deserialize_transfer(s)
32
+ tx = {}
33
+ tx[:recipient] = deserialize_a(s[4, 40])
34
+ tx[:amount] = deserialize_int(s[44, 8])
35
+ tx[:message] = {}
36
+ message_len = deserialize_int(s[52, 4])
37
+ if message_len > 0
38
+ # s[60, 4] # length of payload
39
+ tx[:message] = {
40
+ type: deserialize_int(s[56, 4]),
41
+ payload: deserialize_hex(s[64, s.size])
42
+ }
43
+ else
44
+ tx[:message] = { type: 1, payload: '' }
45
+ end
46
+ tx
47
+ end
48
+
49
+ # Deserialize a importance transaction object
50
+ # @param [String] serialized
51
+ # @return [Hash]
52
+ def self.deserialize_importance_transfer(s)
53
+ {
54
+ mode: deserialize_int(s[0, 4]),
55
+ remoteAccount: deserialize_hex(s[8, 32])
56
+ }
57
+ end
58
+
59
+ # Deserialize a multisig aggregate modification transaction object
60
+ # @param [String] serialized
61
+ # @return [Hash]
62
+ def self.deserialize_multisig_aggregate_modification(s)
63
+ raise 'Not yet implimented.'
64
+ # TODO: deserializing
65
+ tx = {}
66
+ tx
67
+ end
68
+
69
+ # Deserialize a multisig signature transaction object
70
+ # @param [String] serialized
71
+ # @return [Hash]
72
+ def self.deserialize_multisig_signature(s)
73
+ {
74
+ otherHash: { data: deserialize_hex(s[8, 32]) },
75
+ otherAccount: deserialize_a(s[44, 40])
76
+ }
77
+ end
78
+
79
+ # Deserialize a multisig transfer transaction object
80
+ # @param [String] serialized
81
+ # @return [Hash]
82
+ def self.deserialize_multisig(s)
83
+ raise 'Not yet implimented.'
84
+ # TODO: deserializing
85
+ tx = {}
86
+ tx
87
+ end
88
+
89
+ # Deserialize a provision namespace transaction object
90
+ # @param [String] serialized
91
+ # @return [Hash]
92
+ def self.deserialize_provision_namespace(s)
93
+ tx = {}
94
+ tx[:rentalFeeSink] = deserialize_a(s[4, 40])
95
+ tx[:rentalFee] = deserialize_int(s[44, 8])
96
+ newpart_len = deserialize_int(s[52, 4])
97
+ tx[:newPart] = deserialize_a(s[56, newpart_len])
98
+ parent_len = deserialize_int(s[56 + newpart_len, 4])
99
+ parent = s[56 + newpart_len, parent_len]
100
+ unless parent.all? { |val| val == 0xff }
101
+ tx[:parent] = deserialize_a(parent)
102
+ end
103
+ tx
104
+ end
105
+
106
+ # Deserialize a mosaic definition creation transaction object
107
+ # @param [String] serialized
108
+ # @return [Hash]
109
+ def self.deserialize_mosaic_definition_creation(s)
110
+ raise 'Not yet implimented.'
111
+ # TODO: deserializing
112
+ tx = {}
113
+ tx
114
+ end
115
+
116
+ # Deserialize a mosaic supply change transaction object
117
+ # @param [String] serialized
118
+ # @return [Hash]
119
+ def self.deserialize_mosaic_supply_change(s)
120
+ tx = {}
121
+ # s[0, 4] # Length of mosaic id structure
122
+ ns_len = deserialize_int(s[4, 4])
123
+ mo_len = deserialize_int(s[8 + ns_len, 4])
124
+ tx[:mosaicId] = {
125
+ namespaceId: deserialize_a(s[8, ns_len]),
126
+ name: deserialize_a(s[8 + ns_len + mo_len, mo_len])
127
+ }
128
+ tx[:supplyType] = deserialize_int(s[8 + ns_len + 4 + mo_len, 4])
129
+ tx[:delta] = deserialize_int(s[8 + ns_len + 4 + mo_len + 4, 8])
130
+ tx
131
+ end
132
+
133
+ def self.deserialize_common(s)
134
+ {
135
+ type: deserialize_int(s[0, 4]),
136
+ version: deserialize_int(s[4, 4]),
137
+ timeStamp: deserialize_int(s[8, 4]),
138
+ # s[12,4] # length of public key,
139
+ signer: deserialize_hex(s[16, 32]),
140
+ fee: deserialize_int(s[48, 8]),
141
+ deadline: deserialize_int(s[56, 4])
142
+ }
143
+ end
144
+
145
+ def self.deserialize_int(ua)
146
+ Nem::Util::Convert.ua2hex(ua.reverse).to_i(16)
147
+ end
148
+
149
+ def self.deserialize_hex(ua)
150
+ Nem::Util::Convert.ua2hex(ua)
151
+ end
152
+
153
+ def self.deserialize_a(ua)
154
+ Nem::Util::Convert.hex2a(deserialize_hex(ua))
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,316 @@
1
+ require 'securerandom'
2
+ require 'base32'
3
+ require 'openssl'
4
+ require 'digest/sha3'
5
+
6
+ module Nem
7
+ module Util
8
+ module Ed25519
9
+ class << self
10
+ def int2byte(i)
11
+ i.chr
12
+ end
13
+
14
+ def indexbytes(buf, i)
15
+ buf[i].ord
16
+ end
17
+
18
+ def intlist2bytes(l)
19
+ l.inject('') { |memo, c| memo << c.chr }
20
+ end
21
+
22
+ # standard implement
23
+ def H(m)
24
+ OpenSSL::Digest::SHA512.digest(m)
25
+ end
26
+
27
+ def HH(m)
28
+ Digest::SHA3.digest(m)
29
+ end
30
+
31
+ def pow2(x, p)
32
+ while p > 0 do
33
+ x = x.to_bn.mod_exp(2, @@q).to_i
34
+ p -= 1
35
+ end
36
+ x
37
+ end
38
+
39
+ def inv(z)
40
+ # Adapted from curve25519_athlon.c in djb's Curve25519.
41
+ z2 = z * z % @@q # 2
42
+ z9 = pow2(z2, 2) * z % @@q # 9
43
+ z11 = z9 * z2 % @@q # 11
44
+ z2_5_0 = (z11 * z11) % @@q * z9 % @@q # 31 == 2^5 - 2^0
45
+ z2_10_0 = pow2(z2_5_0, 5) * z2_5_0 % @@q # 2^10 - 2^0
46
+ z2_20_0 = pow2(z2_10_0, 10) * z2_10_0 % @@q # ...
47
+ z2_40_0 = pow2(z2_20_0, 20) * z2_20_0 % @@q
48
+ z2_50_0 = pow2(z2_40_0, 10) * z2_10_0 % @@q
49
+ z2_100_0 = pow2(z2_50_0, 50) * z2_50_0 % @@q
50
+ z2_200_0 = pow2(z2_100_0, 100) * z2_100_0 % @@q
51
+ z2_250_0 = pow2(z2_200_0, 50) * z2_50_0 % @@q # 2^250 - 2^0
52
+ pow2(z2_250_0, 5) * z11 % @@q # 2^255 - 2^5 + 11 = q - 2
53
+ end
54
+
55
+ def xrecover(y)
56
+ xx = (y * y - 1) * inv(@@d * y * y + 1)
57
+ x = xx.to_bn.mod_exp((@@q + 3) / 8, @@q).to_i
58
+ x = (x * @@I) % @@q if (x * x - xx) % @@q != 0
59
+ x = @@q - x if x % 2 != 0
60
+ x
61
+ end
62
+
63
+ def edwards_add(_P, _Q)
64
+ # This is formula sequence 'addition-add-2008-hwcd-3' from
65
+ # http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
66
+ x1, y1, z1, t1 = _P
67
+ x2, y2, z2, t2 = _Q
68
+
69
+ a = (y1 - x1) * (y2 - x2) % @@q
70
+ b = (y1 + x1) * (y2 + x2) % @@q
71
+ c = t1 * 2 * @@d * t2 % @@q
72
+ dd = z1 * 2 * z2 % @@q
73
+ e = b - a
74
+ f = dd - c
75
+ g = dd + c
76
+ h = b + a
77
+ x3 = e * f
78
+ y3 = g * h
79
+ t3 = e * h
80
+ z3 = f * g
81
+
82
+ [x3 % @@q, y3 % @@q, z3 % @@q, t3 % @@q]
83
+ end
84
+
85
+ def edwards_double(_P)
86
+ # This is formula sequence 'dbl-2008-hwcd' from
87
+ # http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
88
+ x1, y1, z1, _t1 = _P
89
+
90
+ a = x1 * x1 % @@q
91
+ b = y1 * y1 % @@q
92
+ c = 2 * z1 * z1 % @@q
93
+ # dd = -a
94
+ e = ((x1 + y1) * (x1 + y1) - a - b) % @@q
95
+ g = -a + b # dd + b
96
+ f = g - c
97
+ h = -a - b # dd - b
98
+ x3 = e * f
99
+ y3 = g * h
100
+ t3 = e * h
101
+ z3 = f * g
102
+
103
+ [x3 % @@q, y3 % @@q, z3 % @@q, t3 % @@q]
104
+ end
105
+
106
+ def scalarmult(_P, e)
107
+ return @@ident if e == 0
108
+ _Q = scalarmult(_P, e / 2)
109
+ _Q = edwards_double(_Q)
110
+ _Q = edwards_add(_Q, _P) if (e & 1) == 1
111
+ _Q
112
+ end
113
+
114
+ def make_Bpow
115
+ _P = @@B
116
+ 253.times do
117
+ @@Bpow << _P
118
+ _P = edwards_double(_P)
119
+ end
120
+ end
121
+
122
+ # Implements scalarmult(B, e) more efficiently.
123
+ def scalarmult_B(e)
124
+ # scalarmult(B, l) is the identity
125
+ e = e % @@l
126
+ _P = @@ident
127
+ 253.times do |i|
128
+ _P = edwards_add(_P, @@Bpow[i]) if e & 1 == 1
129
+ e = e / 2
130
+ end
131
+ _P
132
+ end
133
+
134
+ def encodeint(y)
135
+ bits = (0...@@b).map { |i| (y >> i) & 1 }
136
+ (0...@@b / 8).inject('') { |memo, i| memo << int2byte((0...8).inject(0) { |sum, j| sum + (bits[i * 8 + j] << j) }) }
137
+ end
138
+
139
+ def encodepoint(_P)
140
+ x, y, z, _t = _P
141
+ zi = inv(z)
142
+ x = (x * zi) % @@q
143
+ y = (y * zi) % @@q
144
+ bits = (0...@@b - 1).map { |i| (y >> i) & 1 } + [x & 1]
145
+ (0...@@b / 8).inject('') { |memo, i| memo << int2byte((0...8).inject(0) { |sum, j| sum + (bits[i * 8 + j] << j) }) }
146
+ end
147
+
148
+ def bit(h, i)
149
+ (indexbytes(h, i / 8) >> (i % 8)) & 1
150
+ end
151
+
152
+ def publickey_unsafe(sk)
153
+ h = H(sk)
154
+ a = 2**(@@b - 2) + (3...@@b - 2).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
155
+ _A = scalarmult_B(a)
156
+ codepoint(_A)
157
+ end
158
+
159
+ def publickey_hash_unsafe(sk)
160
+ h = HH(sk)
161
+ a = 2**(@@b - 2) + (3...@@b - 2).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
162
+ _A = scalarmult_B(a)
163
+ encodepoint(_A)
164
+ end
165
+
166
+ def encrypt(sk, pk, data)
167
+ h = HH(sk)
168
+ a = 2**(@@b - 2) + (3...@@b - 2).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
169
+ _A = decodepoint(pk)
170
+ bin_g = encodepoint(scalarmult(_A, a))
171
+
172
+ bin_iv = SecureRandom.random_bytes(16)
173
+ hex_iv = bin_iv.unpack('H*').first
174
+
175
+ bin_salt = SecureRandom.random_bytes(32)
176
+ hex_salt = bin_salt.unpack('H*').first
177
+
178
+ ua_salt = Nem::Util::Convert.hex2ua(hex_salt)
179
+ ua_g = Nem::Util::Convert.hex2ua(bin_g.unpack('H*').first)
180
+
181
+ c = []
182
+ ua_salt.each_with_index { |el, idx| c << (el ^ ua_g[idx]) }
183
+ bin_key = Digest::SHA3.digest(c.pack('C*'), 256)
184
+
185
+ cipher = OpenSSL::Cipher.new('AES-256-CBC')
186
+ cipher.encrypt
187
+ cipher.key = bin_key
188
+ cipher.iv = bin_iv
189
+ encrypted_data = cipher.update(data.bytes.pack('C*')) + cipher.final
190
+ hex_salt + hex_iv + encrypted_data.unpack('H*').first
191
+ end
192
+
193
+ def decrypt(sk, pk, data)
194
+ h = HH(sk)
195
+ a = 2**(@@b - 2) + (3...@@b - 2).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
196
+ _A = decodepoint(pk)
197
+ bin_g = encodepoint(scalarmult(_A, a))
198
+
199
+ hex_salt = data[0, 64]
200
+ hex_iv = data[64, 32]
201
+ hex_encrypted = data[96, data.size]
202
+
203
+ ua_iv = Nem::Util::Convert.hex2ua(hex_iv)
204
+ bin_iv = ua_iv.pack('C*')
205
+
206
+ ua_salt = Nem::Util::Convert.hex2ua(hex_salt)
207
+ ua_g = Nem::Util::Convert.hex2ua(bin_g.unpack('H*').first)
208
+
209
+ c = []
210
+ ua_salt.each_with_index { |el, idx| c << (el ^ ua_g[idx]) }
211
+ bin_key = Digest::SHA3.digest(c.pack('C*'), 256)
212
+
213
+ bin_encrypted = Nem::Util::Convert.hex2ua(hex_encrypted).pack('C*')
214
+
215
+ cipher = OpenSSL::Cipher.new('AES-256-CBC')
216
+ cipher.decrypt
217
+ cipher.key = bin_key
218
+ cipher.iv = bin_iv
219
+ cipher.update(bin_encrypted) + cipher.final
220
+ end
221
+
222
+ def Hint(m)
223
+ h = H(m)
224
+ (0...2 * @@b).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
225
+ end
226
+
227
+ def Hint_hash(m)
228
+ h = HH(m)
229
+ (0...2 * @@b).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
230
+ end
231
+
232
+ def signature_unsafe(m, sk, pk)
233
+ h = H(sk)
234
+ a = 2**(@@b - 2) + (3...@@b - 2).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
235
+ r = Hint(
236
+ intlist2bytes((@@b / 8...@@b / 4).map { |j| indexbytes(h, j) }) + m
237
+ )
238
+ _R = scalarmult_B(r)
239
+ _S = (r + Hint(encodepoint(_R) + pk + m) * a) % @@l
240
+ encodepoint(_R) + encodeint(_S)
241
+ end
242
+
243
+ # Not safe to use with secret keys or secret data.
244
+ # This function should be used for testing only.
245
+ def signature_hash_unsafe(m, sk, pk)
246
+ h = HH(sk)
247
+ a = 2**(@@b - 2) + (3...@@b - 2).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
248
+ r = Hint_hash(
249
+ intlist2bytes((@@b / 8...@@b / 4).map { |j| indexbytes(h, j) }) + m
250
+ )
251
+ _R = scalarmult_B(r)
252
+ _S = (r + Hint_hash(encodepoint(_R) + pk + m) * a) % @@l
253
+ encodepoint(_R) + encodeint(_S)
254
+ end
255
+
256
+ def isoncurve(_P)
257
+ x, y, z, t = _P
258
+ (z % @@q != (0) &&
259
+ x * y % @@q == (z * t % @@q) &&
260
+ (y * y - x * x - z * z - @@d * t * t) % @@q == (0))
261
+ end
262
+
263
+ def decodeint(s)
264
+ (0...@@b).inject(0) { |sum, i| sum + 2**i * bit(s, i) }
265
+ end
266
+
267
+ def decodepoint(s)
268
+ y = (0...@@b - 1).inject(0) { |sum, i| sum + 2**i * bit(s, i) }
269
+ x = xrecover(y)
270
+ x = @@q - x if x & 1 != bit(s, @@b - 1)
271
+ _P = [x, y, 1, (x * y) % @@q]
272
+ raise 'decoding point that is not on curve' unless isoncurve(_P)
273
+ _P
274
+ end
275
+
276
+ class SignatureMismatch < StandardError
277
+ end
278
+
279
+ # Not safe to use when any argument is secret.
280
+ # This function should be used only for
281
+ # verifying public signatures of public messages.
282
+ def checkvalid(s, m, pk)
283
+ raise 'signature length is wrong' if s.size != @@b / 4
284
+ raise 'public-key length is wrong' if pk.size != @@b / 8
285
+
286
+ _R = decodepoint(s[0...@@b / 8])
287
+ _A = decodepoint(pk)
288
+ _S = decodeint(s[@@b / 8...@@b / 4])
289
+ h = Hint(encodepoint(_R) + pk + m)
290
+
291
+ x1, y1, z1, _t1 = _P = scalarmult_B(_S)
292
+ x2, y2, z2, _t2 = _Q = edwards_add(_R, scalarmult(_A, h))
293
+
294
+ if (!isoncurve(_P) || !isoncurve(_Q) || (x1 * z2 - x2 * z1) % q != 0 || (y1 * z2 - y2 * z1) % q != 0)
295
+ raise SignatureMismatch('signature does not pass verification')
296
+ end
297
+ end
298
+ end
299
+
300
+ @@b = 256
301
+ @@q = 2**255 - 19
302
+ @@l = 2**252 + 27742317777372353535851937790883648493
303
+
304
+ @@d = -121665 * self.inv(121666) % @@q
305
+ @@I = 2.to_bn.mod_exp((@@q - 1) / 4, @@q)
306
+
307
+ @@By = 4 * self.inv(5)
308
+ @@Bx = self.xrecover(@@By)
309
+ @@B = [@@Bx % @@q, @@By % @@q, 1, (@@Bx * @@By) % @@q]
310
+ @@ident = [0, 1, 1, 0]
311
+
312
+ @@Bpow = []
313
+ self.make_Bpow
314
+ end
315
+ end
316
+ end