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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +119 -0
- data/.travis.yml +23 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/README.md +81 -0
- data/Rakefile +6 -0
- data/examples/apostille_audit.rb +22 -0
- data/examples/apostille_create.rb +31 -0
- data/examples/endpoint/account.rb +73 -0
- data/examples/endpoint/account_local.rb +21 -0
- data/examples/endpoint/block.rb +14 -0
- data/examples/endpoint/chain.rb +15 -0
- data/examples/endpoint/debug.rb +17 -0
- data/examples/endpoint/local.rb +17 -0
- data/examples/endpoint/mosaic.rb +9 -0
- data/examples/endpoint/namespace.rb +13 -0
- data/examples/endpoint/node.rb +24 -0
- data/examples/endpoint/timesync.rb +9 -0
- data/examples/endpoint/transaction.rb +42 -0
- data/examples/localnode.rb +0 -0
- data/examples/nis.rb +34 -0
- data/examples/node_pool.rb +23 -0
- data/examples/transaction/importance_transfer.rb +23 -0
- data/examples/transaction/mosaic_definition_creation.rb +52 -0
- data/examples/transaction/mosaic_supply_change.rb +25 -0
- data/examples/transaction/multisig_add_cosignatory.rb +31 -0
- data/examples/transaction/multisig_aggregate_modification.rb +29 -0
- data/examples/transaction/multisig_signature.rb +41 -0
- data/examples/transaction/multisig_transfer.rb +35 -0
- data/examples/transaction/provision_namespace.rb +20 -0
- data/examples/transaction/transfer.rb +32 -0
- data/examples/transaction/transfer_mosaic.rb +72 -0
- data/examples/transaction/transfer_with_encrypted_message.rb +40 -0
- data/examples/transaction/transfer_with_local.rb +34 -0
- data/lib/nem.rb +21 -0
- data/lib/nem/apostille.rb +104 -0
- data/lib/nem/apostille_audit.rb +47 -0
- data/lib/nem/client.rb +170 -0
- data/lib/nem/configuration.rb +29 -0
- data/lib/nem/endpoint.rb +4 -0
- data/lib/nem/endpoint/account.rb +264 -0
- data/lib/nem/endpoint/base.rb +45 -0
- data/lib/nem/endpoint/block.rb +15 -0
- data/lib/nem/endpoint/chain.rb +17 -0
- data/lib/nem/endpoint/debug.rb +54 -0
- data/lib/nem/endpoint/local/account.rb +54 -0
- data/lib/nem/endpoint/local/chain.rb +15 -0
- data/lib/nem/endpoint/mosaic.rb +13 -0
- data/lib/nem/endpoint/namespace.rb +37 -0
- data/lib/nem/endpoint/node.rb +83 -0
- data/lib/nem/endpoint/timesync.rb +9 -0
- data/lib/nem/endpoint/transaction.rb +34 -0
- data/lib/nem/error.rb +6 -0
- data/lib/nem/fee.rb +2 -0
- data/lib/nem/fee/importance_transfer.rb +24 -0
- data/lib/nem/fee/mosaic_definition_creation.rb +24 -0
- data/lib/nem/fee/mosaic_supply_change_transfer.rb +24 -0
- data/lib/nem/fee/multisig.rb +24 -0
- data/lib/nem/fee/multisig_aggregation_modification.rb +28 -0
- data/lib/nem/fee/provision_namespace.rb +34 -0
- data/lib/nem/fee/transfer.rb +66 -0
- data/lib/nem/keypair.rb +44 -0
- data/lib/nem/mixin.rb +2 -0
- data/lib/nem/mixin/assignable.rb +12 -0
- data/lib/nem/model.rb +3 -0
- data/lib/nem/model/account.rb +67 -0
- data/lib/nem/model/account_historical.rb +19 -0
- data/lib/nem/model/block.rb +33 -0
- data/lib/nem/model/chain.rb +14 -0
- data/lib/nem/model/connection.rb +23 -0
- data/lib/nem/model/experience.rb +20 -0
- data/lib/nem/model/explorer_block.rb +21 -0
- data/lib/nem/model/harvest.rb +23 -0
- data/lib/nem/model/heartbeat.rb +21 -0
- data/lib/nem/model/importance.rb +29 -0
- data/lib/nem/model/importance_transfer_transaction.rb +16 -0
- data/lib/nem/model/keypair.rb +19 -0
- data/lib/nem/model/message.rb +91 -0
- data/lib/nem/model/mosaic.rb +21 -0
- data/lib/nem/model/mosaic_attachment.rb +22 -0
- data/lib/nem/model/mosaic_definition.rb +65 -0
- data/lib/nem/model/mosaic_definition_creation_transaction.rb +18 -0
- data/lib/nem/model/mosaic_id.rb +27 -0
- data/lib/nem/model/mosaic_levy.rb +32 -0
- data/lib/nem/model/mosaic_owned.rb +22 -0
- data/lib/nem/model/mosaic_properties.rb +44 -0
- data/lib/nem/model/mosaic_supply.rb +21 -0
- data/lib/nem/model/mosaic_supply_change_transaction.rb +18 -0
- data/lib/nem/model/multisig_aggregate_modification_transaction.rb +21 -0
- data/lib/nem/model/multisig_info.rb +16 -0
- data/lib/nem/model/multisig_signature_transaction.rb +17 -0
- data/lib/nem/model/multisig_transaction.rb +21 -0
- data/lib/nem/model/namespace.rb +24 -0
- data/lib/nem/model/nem_announce_result.rb +19 -0
- data/lib/nem/model/network_time.rb +16 -0
- data/lib/nem/model/nis_node_info.rb +26 -0
- data/lib/nem/model/node.rb +41 -0
- data/lib/nem/model/provision_namespace_transaction.rb +18 -0
- data/lib/nem/model/status.rb +21 -0
- data/lib/nem/model/timer.rb +31 -0
- data/lib/nem/model/timesync.rb +19 -0
- data/lib/nem/model/transaction.rb +71 -0
- data/lib/nem/model/transfer_transaction.rb +24 -0
- data/lib/nem/model/unlocked_info.rb +24 -0
- data/lib/nem/mosaic.rb +2 -0
- data/lib/nem/mosaic/dim_coin.rb +21 -0
- data/lib/nem/mosaic/dim_token.rb +21 -0
- data/lib/nem/mosaic/ecobit_eco.rb +21 -0
- data/lib/nem/mosaic/xem.rb +21 -0
- data/lib/nem/node.rb +29 -0
- data/lib/nem/node_pool.rb +31 -0
- data/lib/nem/request.rb +2 -0
- data/lib/nem/request/announce.rb +76 -0
- data/lib/nem/transaction.rb +3 -0
- data/lib/nem/transaction/base.rb +45 -0
- data/lib/nem/transaction/importance_transfer.rb +42 -0
- data/lib/nem/transaction/mosaic_definition_creation.rb +45 -0
- data/lib/nem/transaction/mosaic_supply_change.rb +45 -0
- data/lib/nem/transaction/multisig.rb +29 -0
- data/lib/nem/transaction/multisig_aggregate_modification.rb +30 -0
- data/lib/nem/transaction/multisig_cosignatory_modification.rb +33 -0
- data/lib/nem/transaction/multisig_signature.rb +31 -0
- data/lib/nem/transaction/provision_namespace.rb +65 -0
- data/lib/nem/transaction/transfer.rb +63 -0
- data/lib/nem/util.rb +44 -0
- data/lib/nem/util/assignable.rb +51 -0
- data/lib/nem/util/convert.rb +112 -0
- data/lib/nem/util/deserializer.rb +158 -0
- data/lib/nem/util/ed25519.rb +316 -0
- data/lib/nem/util/serializer.rb +260 -0
- data/lib/nem/version.rb +3 -0
- data/nem-ruby.gemspec +46 -0
- 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
|