nis-ruby 0.0.13 → 0.0.14
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 +4 -4
- data/README.md +17 -12
- data/Rakefile +3 -0
- data/examples/transactions/transfer_mosaic.rb +48 -0
- data/lib/nis/fee/importance_transfer.rb +1 -1
- data/lib/nis/fee/mosaic_definition_creation.rb +1 -1
- data/lib/nis/fee/mosaic_supply_change_transfer.rb +1 -1
- data/lib/nis/fee/multisig.rb +1 -1
- data/lib/nis/fee/multisig_aggregation_modification.rb +2 -6
- data/lib/nis/fee/provision_namespace.rb +2 -2
- data/lib/nis/fee/transfer.rb +34 -17
- data/lib/nis/keypair.rb +4 -0
- data/lib/nis/request/announce.rb +7 -2
- data/lib/nis/request/prepare_announce.rb +7 -4
- data/lib/nis/struct/mosaic_attachment.rb +21 -0
- data/lib/nis/struct/mosaic_definition.rb +5 -1
- data/lib/nis/struct/mosaic_properties.rb +11 -1
- data/lib/nis/transaction/mosaic_definition_creation.rb +1 -1
- data/lib/nis/transaction/provision_namespace.rb +2 -2
- data/lib/nis/transaction/transfer.rb +10 -5
- data/lib/nis/unit/address.rb +1 -1
- data/lib/nis/util.rb +4 -0
- data/lib/nis/util/deserializer.rb +46 -0
- data/lib/nis/util/ed25519.rb +77 -83
- data/lib/nis/util/serializer.rb +3 -3
- data/lib/nis/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 681592f0869e7c2ff1956e2b04ad32ffcd07f002
|
4
|
+
data.tar.gz: d3f7c8660d39d09d9186c3df607e5b00682ca5d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7c4b08efb1324125b792de4df01fa6dc7aaacc355358a65e10ce337dbad2dce308a830103aa23bebb954488b673cd00ab086036c41cef5dfbdc9522bd6aa5ee
|
7
|
+
data.tar.gz: 05e7ed7f141eb73a948b3690376dc5d5b4a43ebdd343d6a68942470d46f6d5dd089b396026567f6fcf579d996332e6c9ec28bc5d62593fb4893c68a247f66bdd
|
data/README.md
CHANGED
@@ -5,9 +5,9 @@
|
|
5
5
|
[](https://codeclimate.com/github/44uk/nis-ruby)
|
6
6
|
[](https://gitter.im/44uk/nis-ruby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
7
7
|
|
8
|
-
<img src="https://cloud.githubusercontent.com/assets/370508/24320282/a332d238-1175-11e7-96dc-75bc30e562d2.png" width="
|
8
|
+
<img src="https://cloud.githubusercontent.com/assets/370508/24320282/a332d238-1175-11e7-96dc-75bc30e562d2.png" width="280" height="280" alt="nem" align="right" />
|
9
9
|
|
10
|
-
Ruby client library for the NEM Infrastructure Server API
|
10
|
+
Ruby client library for the NEM Infrastructure Server(NIS) API.
|
11
11
|
|
12
12
|
- [NEM \- Distributed Ledger Technology \(Blockchain\)](https://www.nem.io/)
|
13
13
|
- [NEM NIS API Documentation](https://nemproject.github.io/)
|
@@ -15,6 +15,9 @@ Ruby client library for the NEM Infrastructure Server API
|
|
15
15
|
|
16
16
|
*The gem is under development. Incompatible changes can be made.*
|
17
17
|
|
18
|
+
*Do a thorough test on testnet before you use this gem on production.*
|
19
|
+
|
20
|
+
- [NEM Testnet Faucet \- You can get Testnet XEM for development / testing.](http://test-nem-faucet.44uk.net/)
|
18
21
|
|
19
22
|
## Installation
|
20
23
|
|
@@ -30,6 +33,8 @@ gem 'nis-ruby'
|
|
30
33
|
|
31
34
|
## Usage
|
32
35
|
|
36
|
+
### Examples
|
37
|
+
|
33
38
|
More specific example codes are in **examples/** directory.
|
34
39
|
|
35
40
|
### Methods
|
@@ -79,7 +84,6 @@ nis.request(:post, '/account/unlock',
|
|
79
84
|
# See https://nemproject.github.io/#locking-and-unlocking-accounts
|
80
85
|
```
|
81
86
|
|
82
|
-
|
83
87
|
## Commandline
|
84
88
|
|
85
89
|
```bash
|
@@ -96,11 +100,9 @@ $ nis request get account/harvests --params=address:TALICELCD3XPH4FFI5STGGNSNSWP
|
|
96
100
|
# => [Array <HervestInfo structure>]
|
97
101
|
```
|
98
102
|
|
99
|
-
|
100
103
|
## Connection
|
101
104
|
|
102
|
-
You can find nodes here.
|
103
|
-
- [NEM Node Rewards](https://supernodes.nem.io/)
|
105
|
+
You can find nodes here. [NEM Node Rewards](https://supernodes.nem.io/)
|
104
106
|
|
105
107
|
### Hash
|
106
108
|
|
@@ -121,26 +123,29 @@ $ nis heartbeat # => {"code":1,"type":2,"message":"ok"}
|
|
121
123
|
|
122
124
|
Environment variable used as default value.
|
123
125
|
|
126
|
+
## For More Information
|
127
|
+
|
128
|
+
* [Documentation for nis-ruby - rubydoc.info](http://www.rubydoc.info/gems/nis-ruby)
|
124
129
|
|
125
130
|
## TODO
|
126
131
|
|
127
132
|
* Do more improvements
|
128
|
-
* Mosaic transferring
|
129
133
|
* Encryption message
|
134
|
+
* Failover connection
|
130
135
|
* Be more easy to use
|
131
136
|
|
137
|
+
## Contact
|
132
138
|
|
133
|
-
|
134
|
-
|
135
|
-
Available at [rubydoc.info](http://www.rubydoc.info/gems/nis-ruby).
|
139
|
+
Feel free to ask me if you have any questions.
|
136
140
|
|
141
|
+
* [@44uk_i3 - Twitter](https://twitter.com/44uk_i3)
|
142
|
+
* [44uk/nis-ruby - gitter](https://gitter.im/44uk/nis-ruby)
|
137
143
|
|
138
144
|
## Contributing
|
139
145
|
|
140
146
|
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/nis-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
141
147
|
|
142
|
-
|
143
148
|
## License
|
144
149
|
|
145
|
-
The gem is available as open source under the terms of the [MIT License](
|
150
|
+
The gem is available as open source under the terms of the [MIT License](LICENSE).
|
146
151
|
|
data/Rakefile
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'nis'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
# sender
|
5
|
+
A_PRIVATE_KEY = '260206d683962350532408e8774fd14870a173b7fba17f6b504da3dbc5f1cc9f'
|
6
|
+
|
7
|
+
# receiver
|
8
|
+
B_ADDRESS = 'TAWKJTUP4DWKLDKKS534TYP6G324CBNMXKBA4X7B'
|
9
|
+
|
10
|
+
kp = Nis::Keypair.new(A_PRIVATE_KEY)
|
11
|
+
|
12
|
+
# fetch mosaic information
|
13
|
+
nis = Nis.new(host: '104.128.226.60')
|
14
|
+
mo_dmdps = nis.namespace_mosaic_definition_page(namespace: 'sushi')
|
15
|
+
mo_def = mo_dmdps.first.mosaic
|
16
|
+
|
17
|
+
# require 'pry'; binding.pry
|
18
|
+
|
19
|
+
# mosaic_id = Nis::Struct::MosaicId.new(
|
20
|
+
# namespaceId: 'sushi',
|
21
|
+
# name: 'anago'
|
22
|
+
# )
|
23
|
+
|
24
|
+
# properties = Nis::Struct::MosaicProperties.new(
|
25
|
+
# divisibility: 0,
|
26
|
+
# initialSupply: 10_000,
|
27
|
+
# supplyMutable: true,
|
28
|
+
# transferable: true
|
29
|
+
# )
|
30
|
+
|
31
|
+
# mo_def = Nis::Struct::MosaicDefinition.new(
|
32
|
+
# id: mosaic_id,
|
33
|
+
# properties: properties,
|
34
|
+
# )
|
35
|
+
|
36
|
+
tx = Nis::Transaction::Transfer.new(B_ADDRESS, 1_000_000, 'Good luck!')
|
37
|
+
tx.mosaics << Nis::Struct::MosaicAttachment.new(mo_def, 1_000_000)
|
38
|
+
|
39
|
+
# pp tx.to_hash
|
40
|
+
|
41
|
+
nis = Nis.new
|
42
|
+
req = Nis::Request::PrepareAnnounce.new(tx, kp)
|
43
|
+
pp req.to_hash
|
44
|
+
# res = nis.transaction_prepare_announce(req)
|
45
|
+
|
46
|
+
#
|
47
|
+
# puts "Message: #{res.message}"
|
48
|
+
# puts "TransactionHash: #{res.transaction_hash}"
|
data/lib/nis/fee/multisig.rb
CHANGED
@@ -7,13 +7,9 @@ class Nis::Fee
|
|
7
7
|
# @return [Integer] fee in micro XEM
|
8
8
|
def value
|
9
9
|
if @transaction.minCosignatories == 0
|
10
|
-
|
11
|
-
0.5 * 1_000_000 :
|
12
|
-
(10 + 6 * @transaction.modifications.length) * 1_000_000
|
10
|
+
0.5 * 1_000_000
|
13
11
|
else
|
14
|
-
|
15
|
-
0.5 * 1_000_000 :
|
16
|
-
(10 + 6 * @transaction.modifications.length + 6) * 1_000_000
|
12
|
+
0.5 * 1_000_000
|
17
13
|
end
|
18
14
|
end
|
19
15
|
|
data/lib/nis/fee/transfer.rb
CHANGED
@@ -1,23 +1,19 @@
|
|
1
1
|
class Nis::Fee
|
2
2
|
class Transfer
|
3
|
+
FEE_FACTOR = 0.05
|
4
|
+
|
3
5
|
def initialize(transaction)
|
4
6
|
@transaction = transaction
|
5
7
|
end
|
6
8
|
|
7
9
|
# @return [Integer] fee in micro XEM
|
8
10
|
def value
|
9
|
-
tmp =
|
10
|
-
|
11
|
-
if @transaction.mosaics.empty?
|
12
|
-
tmp += min_fee
|
11
|
+
tmp = if @transaction.has_mosaics?
|
12
|
+
mosaics_fee
|
13
13
|
else
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
if @transaction.message.bytesize > 0
|
18
|
-
tmp += message_fee
|
14
|
+
FEE_FACTOR * minimum_fee(@transaction.amount / 1_000_000)
|
19
15
|
end
|
20
|
-
|
16
|
+
tmp += message_fee if @transaction.has_message?
|
21
17
|
tmp * 1_000_000
|
22
18
|
end
|
23
19
|
|
@@ -33,19 +29,40 @@ class Nis::Fee
|
|
33
29
|
|
34
30
|
private
|
35
31
|
|
36
|
-
def
|
37
|
-
tmp = [1,
|
38
|
-
tmp
|
39
|
-
testnet? ? 0.05 * tmp : tmp
|
32
|
+
def minimum_fee(base)
|
33
|
+
tmp = [1, base / 10_000].max
|
34
|
+
tmp > 25 ? 25 : tmp
|
40
35
|
end
|
41
36
|
|
42
37
|
def message_fee
|
43
|
-
|
44
|
-
testnet? ? 0.05 * tmp : tmp
|
38
|
+
FEE_FACTOR * [1, (@transaction.message.bytesize / 2 / 32) + 1].max
|
45
39
|
end
|
46
40
|
|
47
41
|
def mosaics_fee
|
48
|
-
|
42
|
+
FEE_FACTOR * @transaction.mosaics.inject(0) do |sum, mo_attachment|
|
43
|
+
mo = mo_attachment.mosaic_definition
|
44
|
+
quantity = mo_attachment.quantity
|
45
|
+
tmp_fee = 0
|
46
|
+
if mo.divisibility == 0 && mo.initial_supply <= 10_000
|
47
|
+
# It is called *Small Business Mosaic Fee*
|
48
|
+
supply_related_adjustment = 0
|
49
|
+
tmp_fee = 1
|
50
|
+
else
|
51
|
+
# custom mosaic fee, Max is 1.25.
|
52
|
+
max_mosaic_quantity = 9_000_000_000_000_000
|
53
|
+
total_mosaic_quantity = mo.initial_supply * (10**mo.divisibility)
|
54
|
+
supply_related_adjustment = (0.8 * (Math.log(max_mosaic_quantity / total_mosaic_quantity))).floor
|
55
|
+
|
56
|
+
num_nem = if mo.initial_supply == 0
|
57
|
+
0
|
58
|
+
else
|
59
|
+
8_999_999_999.to_f * quantity * 1_000_000 / mo.initial_supply / (10**(mo.divisibility + 6))
|
60
|
+
end
|
61
|
+
tmp_fee = minimum_fee(num_nem.ceil)
|
62
|
+
end
|
63
|
+
|
64
|
+
sum + [1, tmp_fee - supply_related_adjustment].max
|
65
|
+
end
|
49
66
|
end
|
50
67
|
end
|
51
68
|
end
|
data/lib/nis/keypair.rb
CHANGED
@@ -2,11 +2,15 @@ class Nis
|
|
2
2
|
class Keypair
|
3
3
|
attr_reader :private, :public
|
4
4
|
|
5
|
+
# @param [String] Private Key
|
6
|
+
# @option options [Strung] :public_key Public Key
|
5
7
|
def initialize(private_key, public_key: nil)
|
6
8
|
@private = private_key
|
7
9
|
@public = public_key || calc_public_key
|
8
10
|
end
|
9
11
|
|
12
|
+
# @param [String] Hex string
|
13
|
+
# @return [String] Signed hex string
|
10
14
|
def sign(data)
|
11
15
|
bin_data = data.scan(/../).map(&:hex).pack('C*')
|
12
16
|
bin_signed = Nis::Util::Ed25519.signature_hash_unsafe(bin_data, @bin_secret, @bin_public)
|
data/lib/nis/request/announce.rb
CHANGED
@@ -14,6 +14,7 @@ class Nis::Request
|
|
14
14
|
@transaction = transaction
|
15
15
|
end
|
16
16
|
|
17
|
+
# @return [Hash] Attribute and value pairs
|
17
18
|
def to_hash
|
18
19
|
if @transaction.respond_to?(:other_trans)
|
19
20
|
other_trans(@transaction)
|
@@ -22,7 +23,7 @@ class Nis::Request
|
|
22
23
|
@transaction.tap do |tx|
|
23
24
|
tx.timeStamp = Nis::Util.timestamp
|
24
25
|
tx.deadline = Nis::Util.deadline(DEADLINE)
|
25
|
-
tx.version = Nis::Util.parse_version(tx.network,
|
26
|
+
tx.version = Nis::Util.parse_version(tx.network, version(tx))
|
26
27
|
tx.signer = @keypair.public
|
27
28
|
end
|
28
29
|
|
@@ -47,9 +48,13 @@ class Nis::Request
|
|
47
48
|
transaction.other_trans.tap do |tx|
|
48
49
|
tx.timeStamp = Nis::Util.timestamp
|
49
50
|
tx.deadline = Nis::Util.deadline(DEADLINE)
|
50
|
-
tx.version = Nis::Util.parse_version(tx.network,
|
51
|
+
tx.version = Nis::Util.parse_version(tx.network, version(tx))
|
51
52
|
tx.signer = transaction.signer
|
52
53
|
end
|
53
54
|
end
|
55
|
+
|
56
|
+
def version(transaction)
|
57
|
+
transaction.respond_to?(:has_mosaics?) && transaction.has_mosaics? ? 2 : 1
|
58
|
+
end
|
54
59
|
end
|
55
60
|
end
|
@@ -14,6 +14,7 @@ class Nis::Request
|
|
14
14
|
@transaction = transaction
|
15
15
|
end
|
16
16
|
|
17
|
+
# @return [Hash] Attribute and value pairs
|
17
18
|
def to_hash
|
18
19
|
if @transaction.respond_to?(:other_trans)
|
19
20
|
other_trans(@transaction)
|
@@ -22,7 +23,7 @@ class Nis::Request
|
|
22
23
|
@transaction.tap do |tx|
|
23
24
|
tx.timeStamp = Nis::Util.timestamp
|
24
25
|
tx.deadline = Nis::Util.deadline(DEADLINE)
|
25
|
-
tx.version = Nis::Util.parse_version(tx.network,
|
26
|
+
tx.version = Nis::Util.parse_version(tx.network, version(tx))
|
26
27
|
tx.signer = @keypair.public
|
27
28
|
end
|
28
29
|
|
@@ -36,13 +37,15 @@ class Nis::Request
|
|
36
37
|
transaction.other_trans.tap do |tx|
|
37
38
|
tx.timeStamp = Nis::Util.timestamp
|
38
39
|
tx.deadline = Nis::Util.deadline(DEADLINE)
|
39
|
-
tx.version = Nis::Util.parse_version(tx.network,
|
40
|
-
|
41
|
-
# tx.signer = @keypair.public
|
40
|
+
tx.version = Nis::Util.parse_version(tx.network, version(tx))
|
42
41
|
|
43
42
|
# multisig transfer
|
44
43
|
tx.signer = transaction.signer
|
45
44
|
end
|
46
45
|
end
|
46
|
+
|
47
|
+
def version(transaction)
|
48
|
+
transaction.respond_to?(:has_mosaics?) && transaction.has_mosaics? ? 2 : 1
|
49
|
+
end
|
47
50
|
end
|
48
51
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Nis::Struct
|
2
|
+
# @attr [String] fqn ex) nem.xem
|
3
|
+
# @attr [Integer] quantity
|
4
|
+
# @see https://nemproject.github.io/#version-2-transfer-transactions
|
5
|
+
class MosaicAttachment
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@mosaic_definition, :initial_supply, :divisibility
|
8
|
+
|
9
|
+
attr_reader :mosaic_definition, :quantity
|
10
|
+
|
11
|
+
def initialize(mo_def, quantity)
|
12
|
+
@mosaic_definition = mo_def
|
13
|
+
@quantity = quantity
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_hash
|
17
|
+
{ mosaicId: @mosaic_definition.id.to_hash,
|
18
|
+
quantity: @quantity }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -9,9 +9,13 @@ class Nis::Struct
|
|
9
9
|
include Nis::Util::Assignable
|
10
10
|
attr_accessor :creator, :id, :description, :properties, :levy
|
11
11
|
|
12
|
+
extend Forwardable
|
13
|
+
def_delegators :@properties, :divisibility, :initialSupply, :supplyMutable, :transferable,
|
14
|
+
:initial_supply, :supply_mutable
|
15
|
+
|
12
16
|
def self.build(attrs)
|
13
17
|
attrs[:id] = MosaicId.build(attrs[:id])
|
14
|
-
attrs[:properties] = attrs[:properties]
|
18
|
+
attrs[:properties] = MosaicProperties.build(attrs[:properties])
|
15
19
|
attrs[:levy] = MosaicLevy.build(attrs[:levy]) if attrs[:levy]
|
16
20
|
new(attrs)
|
17
21
|
end
|
@@ -13,7 +13,17 @@ class Nis::Struct
|
|
13
13
|
alias supply_mutable supplyMutable
|
14
14
|
alias supply_mutable= supplyMutable=
|
15
15
|
|
16
|
-
def self.build(
|
16
|
+
def self.build(props)
|
17
|
+
attrs = props.inject({}) do |hash, prop|
|
18
|
+
hash[prop[:name]] = case prop[:name]
|
19
|
+
when 'divisibility' then prop[:value].to_i
|
20
|
+
when 'initialSupply' then prop[:value].to_i
|
21
|
+
when 'supplyMutable' then prop[:value] == 'true' ? true : false
|
22
|
+
when 'transferable' then prop[:value] == 'true' ? true : false
|
23
|
+
else prop[:value]
|
24
|
+
end
|
25
|
+
hash
|
26
|
+
end
|
17
27
|
new(attrs)
|
18
28
|
end
|
19
29
|
|
@@ -64,10 +64,10 @@ class Nis::Transaction
|
|
64
64
|
end
|
65
65
|
else
|
66
66
|
if root?
|
67
|
-
{ fee:
|
67
|
+
{ fee: 100 * 1_000_000 ,
|
68
68
|
sink: 'NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA' }
|
69
69
|
else
|
70
|
-
{ fee:
|
70
|
+
{ fee: 10 * 1_000_000 ,
|
71
71
|
sink: 'NAMESPACEWH4MKFMBCVFERDPOOP4FK7MTBXDPZZA' }
|
72
72
|
end
|
73
73
|
end
|
@@ -20,13 +20,14 @@ class Nis::Transaction
|
|
20
20
|
attr_reader :type, :fee
|
21
21
|
attr_accessor :recipient, :amount, :message,
|
22
22
|
:deadline, :timeStamp, :version, :signer,
|
23
|
-
:network
|
23
|
+
:network,
|
24
|
+
:mosaics
|
24
25
|
|
25
26
|
alias timestamp timeStamp
|
26
27
|
|
27
28
|
TYPE = 0x0101 # 257 (transfer transaction)
|
28
29
|
|
29
|
-
def initialize(recipient, amount, message = '', network: :testnet)
|
30
|
+
def initialize(recipient, amount, message = '', mosaics: [], network: :testnet)
|
30
31
|
@type = TYPE
|
31
32
|
@network = network
|
32
33
|
|
@@ -34,11 +35,15 @@ class Nis::Transaction
|
|
34
35
|
@amount = amount
|
35
36
|
@message = Nis::Struct::Message.new(message)
|
36
37
|
@fee = Nis::Fee::Transfer.new(self)
|
38
|
+
@mosaics = mosaics
|
37
39
|
end
|
38
40
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
41
|
+
def has_message?
|
42
|
+
@message.bytesize > 0
|
43
|
+
end
|
44
|
+
|
45
|
+
def has_mosaics?
|
46
|
+
@mosaics.size > 0
|
42
47
|
end
|
43
48
|
end
|
44
49
|
end
|
data/lib/nis/unit/address.rb
CHANGED
@@ -48,7 +48,7 @@ module Nis::Unit
|
|
48
48
|
ripe = OpenSSL::Digest::RIPEMD160.digest(public_key_hash)
|
49
49
|
|
50
50
|
if network == :testnet
|
51
|
-
version = "\x98".force_encoding(
|
51
|
+
version = "\x98".force_encoding('ASCII-8BIT') + ripe
|
52
52
|
else
|
53
53
|
version = "\x68" + ripe
|
54
54
|
end
|
data/lib/nis/util.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Nis::Util
|
2
|
+
module Deserializer
|
3
|
+
# Deserialize a transaction object
|
4
|
+
# @param [String] serialized
|
5
|
+
# @return [Hash]
|
6
|
+
def self.deserialize_transaction(serialized)
|
7
|
+
s = Nis::Util::Convert.hex2ua(serialized)
|
8
|
+
tx = {}
|
9
|
+
tx[:type] = deserialize_int(s[0, 4])
|
10
|
+
tx[:version] = deserialize_int(s[4, 4])
|
11
|
+
tx[:timeStamp] = deserialize_int(s[8, 4])
|
12
|
+
# s[12,4] # length of public key
|
13
|
+
tx[:signer] = deserialize_hex(s[16, 32])
|
14
|
+
tx[:fee] = deserialize_int(s[48, 8])
|
15
|
+
tx[:deadline] = deserialize_int(s[56, 4])
|
16
|
+
# s[60,4] # length of address
|
17
|
+
tx[:recipient] = deserialize_a(s[64, 40])
|
18
|
+
tx[:amount] = deserialize_int(s[104, 8])
|
19
|
+
|
20
|
+
tx[:message] = {}
|
21
|
+
message_len = deserialize_int(s[112, 4])
|
22
|
+
if message_len > 0
|
23
|
+
tx[:message][:type] = deserialize_int(s[116, 4])
|
24
|
+
# s[120, 4] # length of payload
|
25
|
+
tx[:message][:payload] = deserialize_hex(s[124, s.size])
|
26
|
+
else
|
27
|
+
tx[:message] = { type: 1, payload: '' }
|
28
|
+
end
|
29
|
+
tx
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def self.deserialize_int(ua)
|
35
|
+
Nis::Util::Convert.ua2hex(ua.reverse).to_i(16)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.deserialize_hex(ua)
|
39
|
+
Nis::Util::Convert.ua2hex(ua)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.deserialize_a(ua)
|
43
|
+
Nis::Util::Convert.hex2a(deserialize_hex(ua))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/nis/util/ed25519.rb
CHANGED
@@ -14,7 +14,7 @@ module Nis::Util
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def intlist2bytes(l)
|
17
|
-
l.map {|c| c.chr }.join
|
17
|
+
l.map { |c| c.chr }.join
|
18
18
|
end
|
19
19
|
|
20
20
|
# standard implement
|
@@ -27,36 +27,34 @@ module Nis::Util
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def pow2(x, p)
|
30
|
-
# """== pow(x, 2**p, q)"""
|
31
30
|
while p > 0 do
|
32
|
-
x = x * x %
|
31
|
+
x = x * x % @@q
|
33
32
|
p -= 1
|
34
33
|
end
|
35
34
|
x
|
36
35
|
end
|
37
36
|
|
38
37
|
def inv(z)
|
39
|
-
# """$= z^{-1} \mod q$, for z != 0"""
|
40
38
|
# Adapted from curve25519_athlon.c in djb's Curve25519.
|
41
|
-
z2 = z * z %
|
42
|
-
z9 = pow2(z2, 2) * z %
|
43
|
-
z11 = z9 * z2 %
|
44
|
-
z2_5_0 = (z11 * z11) %
|
45
|
-
z2_10_0 = pow2(z2_5_0, 5) * z2_5_0 %
|
46
|
-
z2_20_0 = pow2(z2_10_0, 10) * z2_10_0 %
|
47
|
-
z2_40_0 = pow2(z2_20_0, 20) * z2_20_0 %
|
48
|
-
z2_50_0 = pow2(z2_40_0, 10) * z2_10_0 %
|
49
|
-
z2_100_0 = pow2(z2_50_0, 50) * z2_50_0 %
|
50
|
-
z2_200_0 = pow2(z2_100_0, 100) * z2_100_0 %
|
51
|
-
z2_250_0 = pow2(z2_200_0, 50) * z2_50_0 %
|
52
|
-
pow2(z2_250_0, 5) * z11 %
|
39
|
+
z2 = z * z % @@q # 2
|
40
|
+
z9 = pow2(z2, 2) * z % @@q # 9
|
41
|
+
z11 = z9 * z2 % @@q # 11
|
42
|
+
z2_5_0 = (z11 * z11) % @@q * z9 % @@q # 31 == 2^5 - 2^0
|
43
|
+
z2_10_0 = pow2(z2_5_0, 5) * z2_5_0 % @@q # 2^10 - 2^0
|
44
|
+
z2_20_0 = pow2(z2_10_0, 10) * z2_10_0 % @@q # ...
|
45
|
+
z2_40_0 = pow2(z2_20_0, 20) * z2_20_0 % @@q
|
46
|
+
z2_50_0 = pow2(z2_40_0, 10) * z2_10_0 % @@q
|
47
|
+
z2_100_0 = pow2(z2_50_0, 50) * z2_50_0 % @@q
|
48
|
+
z2_200_0 = pow2(z2_100_0, 100) * z2_100_0 % @@q
|
49
|
+
z2_250_0 = pow2(z2_200_0, 50) * z2_50_0 % @@q # 2^250 - 2^0
|
50
|
+
pow2(z2_250_0, 5) * z11 % @@q # 2^255 - 2^5 + 11 = q - 2
|
53
51
|
end
|
54
52
|
|
55
53
|
def xrecover(y)
|
56
|
-
xx = (y * y - 1) * inv(
|
57
|
-
x = xx.to_bn.mod_exp((
|
58
|
-
x = (x *
|
59
|
-
x =
|
54
|
+
xx = (y * y - 1) * inv(@@d * y * y + 1)
|
55
|
+
x = xx.to_bn.mod_exp((@@q + 3) / 8, @@q)
|
56
|
+
x = (x * @@I) % @@q if (x * x - xx) % @@q != 0
|
57
|
+
x = @@q - x if x % 2 != 0
|
60
58
|
x
|
61
59
|
end
|
62
60
|
|
@@ -66,10 +64,10 @@ module Nis::Util
|
|
66
64
|
x1, y1, z1, t1 = _P
|
67
65
|
x2, y2, z2, t2 = _Q
|
68
66
|
|
69
|
-
a = (y1 - x1) * (y2 - x2) %
|
70
|
-
b = (y1 + x1) * (y2 + x2) %
|
71
|
-
c = t1 * 2 *
|
72
|
-
dd = z1 * 2 * z2 %
|
67
|
+
a = (y1 - x1) * (y2 - x2) % @@q
|
68
|
+
b = (y1 + x1) * (y2 + x2) % @@q
|
69
|
+
c = t1 * 2 * @@d * t2 % @@q
|
70
|
+
dd = z1 * 2 * z2 % @@q
|
73
71
|
e = b - a
|
74
72
|
f = dd - c
|
75
73
|
g = dd + c
|
@@ -79,7 +77,7 @@ module Nis::Util
|
|
79
77
|
t3 = e * h
|
80
78
|
z3 = f * g
|
81
79
|
|
82
|
-
[x3 %
|
80
|
+
[x3 % @@q, y3 % @@q, z3 % @@q, t3 % @@q]
|
83
81
|
end
|
84
82
|
|
85
83
|
def edwards_double(_P)
|
@@ -87,11 +85,11 @@ module Nis::Util
|
|
87
85
|
# http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
88
86
|
x1, y1, z1, _t1 = _P
|
89
87
|
|
90
|
-
a = x1 * x1 %
|
91
|
-
b = y1 * y1 %
|
92
|
-
c = 2 * z1 * z1 %
|
88
|
+
a = x1 * x1 % @@q
|
89
|
+
b = y1 * y1 % @@q
|
90
|
+
c = 2 * z1 * z1 % @@q
|
93
91
|
# dd = -a
|
94
|
-
e = ((x1 + y1) * (x1 + y1) - a - b) %
|
92
|
+
e = ((x1 + y1) * (x1 + y1) - a - b) % @@q
|
95
93
|
g = -a + b # dd + b
|
96
94
|
f = g - c
|
97
95
|
h = -a - b # dd - b
|
@@ -100,11 +98,11 @@ module Nis::Util
|
|
100
98
|
t3 = e * h
|
101
99
|
z3 = f * g
|
102
100
|
|
103
|
-
|
101
|
+
[x3 % @@q, y3 % @@q, z3 % @@q, t3 % @@q]
|
104
102
|
end
|
105
103
|
|
106
104
|
def scalarmult(_P, e)
|
107
|
-
|
105
|
+
@@ident if e == 0
|
108
106
|
_Q = scalarmult(_P, e / 2)
|
109
107
|
_Q = edwards_double(_Q)
|
110
108
|
_Q = edwards_add(_Q, _P) if e & 1
|
@@ -112,9 +110,9 @@ module Nis::Util
|
|
112
110
|
end
|
113
111
|
|
114
112
|
def make_Bpow
|
115
|
-
_P =
|
113
|
+
_P = @@B
|
116
114
|
(0...253).each do |_|
|
117
|
-
|
115
|
+
@@Bpow << _P
|
118
116
|
_P = edwards_double(_P)
|
119
117
|
end
|
120
118
|
end
|
@@ -122,27 +120,27 @@ module Nis::Util
|
|
122
120
|
# Implements scalarmult(B, e) more efficiently.
|
123
121
|
def scalarmult_B(e)
|
124
122
|
# scalarmult(B, l) is the identity
|
125
|
-
e = e %
|
126
|
-
_P =
|
123
|
+
e = e % @@l
|
124
|
+
_P = @@ident
|
127
125
|
(0...253).each do |i|
|
128
|
-
_P = edwards_add(_P,
|
126
|
+
_P = edwards_add(_P, @@Bpow[i]) if e & 1 == 1
|
129
127
|
e = e / 2
|
130
128
|
end
|
131
129
|
_P
|
132
130
|
end
|
133
131
|
|
134
132
|
def encodeint(y)
|
135
|
-
bits = (0
|
136
|
-
(0
|
133
|
+
bits = (0...@@b).map { |i| (y >> i) & 1 }
|
134
|
+
(0...@@b / 8).map { |i| int2byte((0...8).inject(0) { |sum, j| sum + (bits[i * 8 + j] << j) }) }.join
|
137
135
|
end
|
138
136
|
|
139
137
|
def encodepoint(_P)
|
140
138
|
x, y, z, _t = _P
|
141
139
|
zi = inv(z)
|
142
|
-
x = (x * zi) %
|
143
|
-
y = (y * zi) %
|
144
|
-
bits = (0
|
145
|
-
(0
|
140
|
+
x = (x * zi) % @@q
|
141
|
+
y = (y * zi) % @@q
|
142
|
+
bits = (0...@@b - 1).map { |i| (y >> i) & 1 } + [x & 1]
|
143
|
+
(0...@@b / 8).map { |i| int2byte((0...8).inject(0) { |sum, j| sum + (bits[i * 8 + j] << j) }) }.join
|
146
144
|
end
|
147
145
|
|
148
146
|
def bit(h, i)
|
@@ -151,70 +149,69 @@ module Nis::Util
|
|
151
149
|
|
152
150
|
def publickey_unsafe(sk)
|
153
151
|
h = H(sk)
|
154
|
-
a = 2
|
152
|
+
a = 2**(@@b - 2) + (3...@@b - 2).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
|
155
153
|
_A = scalarmult_B(a)
|
156
|
-
|
154
|
+
codepoint(_A)
|
157
155
|
end
|
158
156
|
|
159
157
|
def publickey_hash_unsafe(sk)
|
160
158
|
h = HH(sk)
|
161
|
-
a = 2
|
159
|
+
a = 2**(@@b - 2) + (3...@@b - 2).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
|
162
160
|
_A = scalarmult_B(a)
|
163
|
-
|
161
|
+
encodepoint(_A)
|
164
162
|
end
|
165
163
|
|
166
164
|
def Hint(m)
|
167
165
|
h = H(m)
|
168
|
-
(0...2
|
166
|
+
(0...2 * @@b).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
|
169
167
|
end
|
170
168
|
|
171
169
|
def Hint_hash(m)
|
172
170
|
h = HH(m)
|
173
|
-
(0...2
|
171
|
+
(0...2 * @@b).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
|
174
172
|
end
|
175
173
|
|
176
174
|
def signature_unsafe(m, sk, pk)
|
177
175
|
h = H(sk)
|
178
|
-
a = 2
|
176
|
+
a = 2**(@@b - 2) + (3...@@b - 2).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
|
179
177
|
r = Hint(
|
180
|
-
intlist2bytes((
|
178
|
+
intlist2bytes((@@b / 8...@@b / 4).map { |j| indexbytes(h, j) }) + m
|
181
179
|
)
|
182
180
|
_R = scalarmult_B(r)
|
183
|
-
_S = (r + Hint(encodepoint(_R) + pk + m) * a) %
|
181
|
+
_S = (r + Hint(encodepoint(_R) + pk + m) * a) % @@l
|
184
182
|
encodepoint(_R) + encodeint(_S)
|
185
183
|
end
|
186
184
|
|
187
185
|
# Not safe to use with secret keys or secret data.
|
188
|
-
#
|
189
|
-
# See module docstring. This function should be used for testing only.
|
186
|
+
# This function should be used for testing only.
|
190
187
|
def signature_hash_unsafe(m, sk, pk)
|
191
188
|
h = HH(sk)
|
192
|
-
a = 2
|
189
|
+
a = 2**(@@b - 2) + (3...@@b - 2).inject(0) { |sum, i| sum + 2**i * bit(h, i) }
|
193
190
|
r = Hint_hash(
|
194
|
-
intlist2bytes((
|
191
|
+
intlist2bytes((@@b / 8...@@b / 4).map { |j| indexbytes(h, j) }) + m
|
195
192
|
)
|
196
193
|
_R = scalarmult_B(r)
|
197
|
-
_S = (r + Hint_hash(encodepoint(_R) + pk + m) * a) %
|
194
|
+
_S = (r + Hint_hash(encodepoint(_R) + pk + m) * a) % @@l
|
198
195
|
encodepoint(_R) + encodeint(_S)
|
199
196
|
end
|
200
197
|
|
201
198
|
def isoncurve(_P)
|
202
199
|
x, y, z, t = _P
|
203
|
-
(z %
|
204
|
-
x * y %
|
205
|
-
(y * y - x * x - z * z -
|
200
|
+
(z % @@q != (0) &&
|
201
|
+
x * y % @@q == (z * t % @@q) &&
|
202
|
+
(y * y - x * x - z * z - @@d * t * t) % @@q == (0))
|
206
203
|
end
|
207
204
|
|
208
205
|
def decodeint(s)
|
209
|
-
(0
|
206
|
+
(0...@@b).inject(0) { |sum, i| sum + 2**i * bit(s, i) }
|
210
207
|
end
|
211
208
|
|
212
209
|
def decodepoint(s)
|
213
|
-
y = (0
|
210
|
+
y = (0...@@b - 1).inject(0) { |sum, i| 2**i * bit(s, i) }
|
214
211
|
x = xrecover(y)
|
215
|
-
x =
|
216
|
-
_P = [x, y, 1, (x * y) %
|
217
|
-
raise
|
212
|
+
x = @@q - x if x & 1 != bit(s, @@b - 1)
|
213
|
+
_P = [x, y, 1, (x * y) % @@q]
|
214
|
+
raise 'decoding point that is not on curve' unless isoncurve(_P)
|
218
215
|
_P
|
219
216
|
end
|
220
217
|
|
@@ -222,42 +219,39 @@ module Nis::Util
|
|
222
219
|
end
|
223
220
|
|
224
221
|
# Not safe to use when any argument is secret.
|
225
|
-
#
|
226
|
-
# See module docstring. This function should be used only for
|
222
|
+
# This function should be used only for
|
227
223
|
# verifying public signatures of public messages.
|
228
224
|
def checkvalid(s, m, pk)
|
229
|
-
raise
|
230
|
-
raise
|
225
|
+
raise 'signature length is wrong' if s.size != @@b / 4
|
226
|
+
raise 'public-key length is wrong' if pk.size != @@b / 8
|
231
227
|
|
232
|
-
|
233
|
-
_R = decodepoint(s[0...$b/8])
|
228
|
+
_R = decodepoint(s[0...@@b / 8])
|
234
229
|
_A = decodepoint(pk)
|
235
|
-
_S = decodeint(s[
|
230
|
+
_S = decodeint(s[@@b / 8...@@b / 4])
|
236
231
|
h = Hint(encodepoint(_R) + pk + m)
|
237
232
|
|
238
233
|
x1, y1, z1, _t1 = _P = scalarmult_B(_S)
|
239
234
|
x2, y2, z2, _t2 = _Q = edwards_add(_R, scalarmult(_A, h))
|
240
235
|
|
241
236
|
if (!isoncurve(_P) || !isoncurve(_Q) || (x1 * z2 - x2 * z1) % q != 0 || (y1 * z2 - y2 * z1) % q != 0)
|
242
|
-
raise SignatureMismatch(
|
237
|
+
raise SignatureMismatch('signature does not pass verification')
|
243
238
|
end
|
244
239
|
end
|
245
240
|
end
|
246
241
|
|
247
|
-
|
248
|
-
|
249
|
-
|
242
|
+
@@b = 256
|
243
|
+
@@q = 2**255 - 19
|
244
|
+
@@l = 2**252 + 27742317777372353535851937790883648493
|
250
245
|
|
251
|
-
|
252
|
-
|
246
|
+
@@d = -121665 * self.inv(121666) % @@q
|
247
|
+
@@I = 2.to_bn.mod_exp((@@q - 1) / 4, @@q)
|
253
248
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
249
|
+
@@By = 4 * self.inv(5)
|
250
|
+
@@Bx = self.xrecover(@@By)
|
251
|
+
@@B = [@@Bx % @@q, @@By % @@q, 1, (@@Bx * @@By) % @@q]
|
252
|
+
@@ident = [0, 1, 1, 0]
|
258
253
|
|
259
|
-
|
260
|
-
$Bpow = []
|
254
|
+
@@Bpow = []
|
261
255
|
self.make_Bpow
|
262
256
|
end
|
263
257
|
end
|
data/lib/nis/util/serializer.rb
CHANGED
@@ -5,8 +5,8 @@ module Nis::Util
|
|
5
5
|
# @return [Array]
|
6
6
|
def self.serialize_transaction(entity)
|
7
7
|
method = case entity[:type]
|
8
|
-
|
9
|
-
|
8
|
+
when 257 then method(:serialize_transfer)
|
9
|
+
when 4100 then method(:serialize_multisig_transfer)
|
10
10
|
else raise "Not implemented entity type: #{entity[:type]}"
|
11
11
|
end
|
12
12
|
method.call(entity)
|
@@ -54,7 +54,7 @@ module Nis::Util
|
|
54
54
|
|
55
55
|
temp = hex2ua(entity[:message][:payload])
|
56
56
|
if temp.size == 0
|
57
|
-
a += [0,0,0,0]
|
57
|
+
a += [0, 0, 0, 0]
|
58
58
|
else
|
59
59
|
a += serialize_int(temp.size + 8)
|
60
60
|
a += serialize_int(entity[:message][:type])
|
data/lib/nis/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nis-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yoshiyuki Ieyama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -213,6 +213,7 @@ files:
|
|
213
213
|
- examples/transactions/multisig_signature.rb
|
214
214
|
- examples/transactions/provision_namespace.rb
|
215
215
|
- examples/transactions/transfer.rb
|
216
|
+
- examples/transactions/transfer_mosaic.rb
|
216
217
|
- examples/transactions/transfer_remote.rb
|
217
218
|
- lib/nis.rb
|
218
219
|
- lib/nis/client.rb
|
@@ -295,6 +296,7 @@ files:
|
|
295
296
|
- lib/nis/struct/key_pair_view_model.rb
|
296
297
|
- lib/nis/struct/message.rb
|
297
298
|
- lib/nis/struct/mosaic.rb
|
299
|
+
- lib/nis/struct/mosaic_attachment.rb
|
298
300
|
- lib/nis/struct/mosaic_definition.rb
|
299
301
|
- lib/nis/struct/mosaic_definition_meta_data.rb
|
300
302
|
- lib/nis/struct/mosaic_definition_meta_data_pair.rb
|
@@ -340,6 +342,7 @@ files:
|
|
340
342
|
- lib/nis/util.rb
|
341
343
|
- lib/nis/util/assignable.rb
|
342
344
|
- lib/nis/util/convert.rb
|
345
|
+
- lib/nis/util/deserializer.rb
|
343
346
|
- lib/nis/util/ed25519.rb
|
344
347
|
- lib/nis/util/serializer.rb
|
345
348
|
- lib/nis/version.rb
|