iota-ruby 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/README.md +2 -2
- data/Rakefile +15 -1
- data/examples/multisig.rb +13 -1
- data/ext/ccurl/ccurl.c +125 -0
- data/ext/ccurl/extconf.rb +23 -0
- data/iota-ruby.gemspec +2 -0
- data/lib/iota/api/wrappers.rb +20 -1
- data/lib/iota/crypto/converter.rb +1 -1
- data/lib/iota/crypto/curl.rb +11 -67
- data/lib/iota/crypto/curl_c.rb +15 -0
- data/lib/iota/crypto/curl_ruby.rb +70 -0
- data/lib/iota/utils/utils.rb +5 -7
- data/lib/iota/version.rb +1 -1
- data/test/curl_c_test.rb +31 -0
- data/test/curl_ruby_test.rb +27 -0
- metadata +27 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e15da20a0b19ab615e650922f5e5182d0ccae186
|
4
|
+
data.tar.gz: a6749e1c32299500485799903b203e9d6688960f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e9495318e52b2b1d1c5279a5c572819c59a3408f27794e9aa4f2bf3a24b2cc3acd8e454b0c6e0cf287745b8d0b8d04a6d391b88dd6ba709fbcb9495a7564261
|
7
|
+
data.tar.gz: 7185c56ed47281120f6ddba2d39c29d7f6d437b2331b871f97ac678e8c4a45d776b96a7bc2f456416b949a89df0b1620277b19ab1ed7901b3739e3e44f9324a6
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -13,7 +13,7 @@ This gem is a **beta release**. If you find any bug or face issue, please [post
|
|
13
13
|
Add this line to your application's Gemfile:
|
14
14
|
|
15
15
|
```ruby
|
16
|
-
gem 'iota-ruby',
|
16
|
+
gem 'iota-ruby', require: 'iota'
|
17
17
|
```
|
18
18
|
|
19
19
|
And then execute:
|
@@ -55,7 +55,7 @@ Overall, there are currently four subclasses that are accessible from the IOTA o
|
|
55
55
|
- **`api`**: Core API functionality for interacting with the IOTA core.
|
56
56
|
- **`utils`**: Utility related functions for conversions, validation and so on
|
57
57
|
- **`validator`**: Validator functions that can help with determining whether the inputs or results that you get are valid.
|
58
|
-
- **`multisig`**:
|
58
|
+
- **`multisig`**: Functions for creating and signing multi-signature addresses and transactions.
|
59
59
|
|
60
60
|
|
61
61
|
## How to use the Library
|
data/Rakefile
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rake/testtask"
|
3
|
+
require "rake/extensiontask"
|
3
4
|
|
4
5
|
Rake::TestTask.new(:test) do |t|
|
5
6
|
t.libs << "test"
|
@@ -7,4 +8,17 @@ Rake::TestTask.new(:test) do |t|
|
|
7
8
|
t.test_files = FileList["test/**/*_test.rb"]
|
8
9
|
end
|
9
10
|
|
10
|
-
|
11
|
+
Rake::ExtensionTask.new "ccurl" do |ext|
|
12
|
+
ext.lib_dir = "lib"
|
13
|
+
end
|
14
|
+
|
15
|
+
def can_compile_extensions
|
16
|
+
return false if RUBY_DESCRIPTION =~ /jruby/
|
17
|
+
return true
|
18
|
+
end
|
19
|
+
|
20
|
+
if can_compile_extensions
|
21
|
+
task :default => [:compile, :test]
|
22
|
+
else
|
23
|
+
task :default => [:test]
|
24
|
+
end
|
data/examples/multisig.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "bundler/setup"
|
2
2
|
require "iota"
|
3
3
|
|
4
|
-
iota = IOTA::Client.new(provider: 'http://
|
4
|
+
iota = IOTA::Client.new(provider: 'http://localhost:14265')
|
5
5
|
|
6
6
|
# First co-signer uses index 0 and security level 3
|
7
7
|
digestOne = iota.multisig.getDigest('ABCDFG', 0, 3)
|
@@ -55,3 +55,15 @@ firstSignedBundle = iota.multisig.addSignature(initiatedBundle, finalAddress, io
|
|
55
55
|
finalBundle = iota.multisig.addSignature(firstSignedBundle, finalAddress, iota.multisig.getKey('FDSAG', 0, 3))
|
56
56
|
|
57
57
|
puts "IS VALID SIGNATURE: #{iota.utils.validateSignatures(finalBundle, finalAddress)}"
|
58
|
+
|
59
|
+
# Send signed transction
|
60
|
+
# Uncomment following lines if you want to send transaction
|
61
|
+
# trytes = finalBundle.map do |tx|
|
62
|
+
# iota.utils.transactionTrytes(tx)
|
63
|
+
# end
|
64
|
+
|
65
|
+
# iota.api.sendTrytes(trytes.reverse, 10, 14) do |st1, transactions|
|
66
|
+
# if st1
|
67
|
+
# puts data
|
68
|
+
# end
|
69
|
+
# end
|
data/ext/ccurl/ccurl.c
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <stdint.h>
|
3
|
+
|
4
|
+
#define HASH_LENGTH 243
|
5
|
+
#define NUMBER_OF_ROUNDS 81
|
6
|
+
#define STATE_LENGTH 3 * HASH_LENGTH
|
7
|
+
|
8
|
+
typedef int64_t trit_t;
|
9
|
+
|
10
|
+
#define __TRUTH_TABLE 1, 0, -1, 1, -1, 0, -1, 1, 0
|
11
|
+
|
12
|
+
static const trit_t TRUTH_TABLE[9] = {__TRUTH_TABLE};
|
13
|
+
|
14
|
+
typedef struct {
|
15
|
+
int rounds;
|
16
|
+
trit_t state[STATE_LENGTH];
|
17
|
+
} Curl;
|
18
|
+
|
19
|
+
static VALUE ccurl_transform(VALUE self);
|
20
|
+
|
21
|
+
static VALUE ccurl_alloc(VALUE klass) {
|
22
|
+
Curl *ctx = ALLOC(Curl);
|
23
|
+
return Data_Wrap_Struct(klass, 0, RUBY_DEFAULT_FREE, ctx);
|
24
|
+
}
|
25
|
+
|
26
|
+
static VALUE ccurl_init(VALUE self, VALUE rounds) {
|
27
|
+
Curl *ctx;
|
28
|
+
int requested = NUMBER_OF_ROUNDS;
|
29
|
+
|
30
|
+
if (TYPE(rounds) != T_NIL) {
|
31
|
+
requested = NUM2INT(rounds);
|
32
|
+
}
|
33
|
+
|
34
|
+
Data_Get_Struct(self, Curl, ctx);
|
35
|
+
|
36
|
+
ctx->rounds = requested;
|
37
|
+
memset(ctx->state, (trit_t)0, STATE_LENGTH * sizeof(trit_t));
|
38
|
+
|
39
|
+
return self;
|
40
|
+
}
|
41
|
+
|
42
|
+
static VALUE ccurl_absorb(VALUE self, VALUE data) {
|
43
|
+
Curl *ctx;
|
44
|
+
Data_Get_Struct(self, Curl, ctx);
|
45
|
+
|
46
|
+
trit_t *trits;
|
47
|
+
|
48
|
+
int offset = 0;
|
49
|
+
int length = NUM2INT(rb_funcall(data, rb_intern("length"), 0, 0));
|
50
|
+
|
51
|
+
trits = (trit_t*)malloc(length * sizeof(trit_t));
|
52
|
+
|
53
|
+
for (int i = 0; i < length; ++i) {
|
54
|
+
trits[i] = (trit_t)(NUM2LONG(rb_ary_entry(data, i)));
|
55
|
+
}
|
56
|
+
|
57
|
+
do {
|
58
|
+
memcpy(ctx->state, trits + offset, (length < HASH_LENGTH ? length : HASH_LENGTH) * sizeof(trit_t));
|
59
|
+
ccurl_transform(self);
|
60
|
+
offset += HASH_LENGTH;
|
61
|
+
} while ((length -= HASH_LENGTH) > 0);
|
62
|
+
|
63
|
+
free(trits);
|
64
|
+
|
65
|
+
return Qnil;
|
66
|
+
}
|
67
|
+
|
68
|
+
static VALUE ccurl_squeeze(VALUE self, VALUE data) {
|
69
|
+
Curl *ctx;
|
70
|
+
Data_Get_Struct(self, Curl, ctx);
|
71
|
+
|
72
|
+
int incoming_count, length = NUM2INT(rb_funcall(data, rb_intern("length"), 0, 0));
|
73
|
+
|
74
|
+
for(incoming_count = length; length < HASH_LENGTH; length++) {
|
75
|
+
rb_ary_push(data, LONG2NUM(0));
|
76
|
+
}
|
77
|
+
|
78
|
+
for (int i = 0; i < HASH_LENGTH; i++) {
|
79
|
+
rb_ary_store(data, i, LONG2NUM(ctx->state[i]));
|
80
|
+
}
|
81
|
+
|
82
|
+
ccurl_transform(self);
|
83
|
+
|
84
|
+
return Qnil;
|
85
|
+
}
|
86
|
+
|
87
|
+
static VALUE ccurl_transform(VALUE self) {
|
88
|
+
Curl *ctx;
|
89
|
+
Data_Get_Struct(self, Curl, ctx);
|
90
|
+
|
91
|
+
trit_t scratchpad[STATE_LENGTH];
|
92
|
+
int round, scratchpadIndex=0, scratchpadIndexSave, stateIndex;
|
93
|
+
|
94
|
+
for (round = 0; round < NUMBER_OF_ROUNDS; round++) {
|
95
|
+
memcpy(scratchpad, ctx->state, STATE_LENGTH * sizeof(trit_t));
|
96
|
+
|
97
|
+
for (stateIndex = 0; stateIndex < STATE_LENGTH; stateIndex++) {
|
98
|
+
scratchpadIndexSave = scratchpadIndex;
|
99
|
+
scratchpadIndex += (scratchpadIndex < 365 ? 364 : -365);
|
100
|
+
ctx->state[stateIndex] = TRUTH_TABLE[scratchpad[scratchpadIndexSave ] + scratchpad[scratchpadIndex ] * 3 + 4];
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
return Qnil;
|
105
|
+
}
|
106
|
+
|
107
|
+
static VALUE ccurl_reset(VALUE self) {
|
108
|
+
Curl *ctx;
|
109
|
+
Data_Get_Struct(self, Curl, ctx);
|
110
|
+
memset(ctx->state, 0, STATE_LENGTH * sizeof(char));
|
111
|
+
return Qnil;
|
112
|
+
}
|
113
|
+
|
114
|
+
void Init_ccurl(void) {
|
115
|
+
VALUE iota = rb_define_module("IOTA");
|
116
|
+
VALUE iotaCrypto = rb_define_module_under(iota, "Crypto");
|
117
|
+
VALUE cCurl = rb_define_class_under(iotaCrypto, "CCurl", rb_cObject);
|
118
|
+
|
119
|
+
rb_define_alloc_func(cCurl, ccurl_alloc);
|
120
|
+
rb_define_method(cCurl, "initialize", ccurl_init, 1);
|
121
|
+
rb_define_method(cCurl, "absorb", ccurl_absorb, 1);
|
122
|
+
rb_define_method(cCurl, "squeeze", ccurl_squeeze, 1);
|
123
|
+
rb_define_method(cCurl, "transform", ccurl_transform, 0);
|
124
|
+
rb_define_method(cCurl, "reset", ccurl_reset, 0);
|
125
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
can_compile_extensions = false
|
2
|
+
want_extensions = true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'mkmf'
|
6
|
+
can_compile_extensions = true
|
7
|
+
rescue Exception
|
8
|
+
# This will appear only in verbose mode.
|
9
|
+
$stderr.puts "Could not require 'mkmf'. Not fatal, the extensions are optional."
|
10
|
+
end
|
11
|
+
|
12
|
+
if can_compile_extensions && want_extensions
|
13
|
+
extension_name = 'ccurl'
|
14
|
+
dir_config(extension_name) # The destination
|
15
|
+
create_makefile(extension_name) # Create Makefile
|
16
|
+
else
|
17
|
+
# Create a dummy Makefile, to satisfy Gem::Installer#install
|
18
|
+
mfile = open("Makefile", "wb")
|
19
|
+
mfile.puts '.PHONY: install'
|
20
|
+
mfile.puts 'install:'
|
21
|
+
mfile.puts "\t" + '@echo "Extensions not installed, falling back to pure Ruby version."'
|
22
|
+
mfile.close
|
23
|
+
end
|
data/iota-ruby.gemspec
CHANGED
@@ -17,9 +17,11 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = `git ls-files -- test/*`.split("\n")
|
18
18
|
spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ["lib"]
|
20
|
+
spec.extensions = ["ext/ccurl/extconf.rb"]
|
20
21
|
|
21
22
|
spec.add_development_dependency "bundler", "~> 1.15"
|
22
23
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
24
|
spec.add_development_dependency "minitest", "~> 5.0"
|
25
|
+
spec.add_development_dependency "rake-compiler", "~> 1.0.4"
|
24
26
|
spec.add_dependency "digest-sha3", "~> 1.1"
|
25
27
|
end
|
data/lib/iota/api/wrappers.rb
CHANGED
@@ -10,7 +10,7 @@ module IOTA
|
|
10
10
|
ret_status = false
|
11
11
|
ret_data = nil
|
12
12
|
# get the trytes of the transaction hashes
|
13
|
-
|
13
|
+
getTrytesInBatches(hashes) do |status, trytes|
|
14
14
|
ret_status = status
|
15
15
|
if status
|
16
16
|
transactionObjects = []
|
@@ -397,6 +397,25 @@ module IOTA
|
|
397
397
|
end
|
398
398
|
end
|
399
399
|
end
|
400
|
+
|
401
|
+
def getTrytesInBatches(hashes, batchSize = 500, &callback)
|
402
|
+
if !@validator.isArrayOfHashes(hashes)
|
403
|
+
return sendData(false, "Invalid Trytes provided", &callback)
|
404
|
+
end
|
405
|
+
|
406
|
+
data = []
|
407
|
+
|
408
|
+
hashes.in_groups_of(batchSize, false) do |group|
|
409
|
+
getTrytes(group) do |status, trytes|
|
410
|
+
if !status
|
411
|
+
return sendData(false, trytes, &callback)
|
412
|
+
end
|
413
|
+
data += trytes
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
sendData(true, data, &callback)
|
418
|
+
end
|
400
419
|
end
|
401
420
|
end
|
402
421
|
end
|
data/lib/iota/crypto/curl.rb
CHANGED
@@ -1,73 +1,17 @@
|
|
1
|
+
if !Dir.glob(File.join(File.dirname(__FILE__), '../../ccurl.*')).empty?
|
2
|
+
require "iota/crypto/curl_c"
|
3
|
+
BaseCurl = IOTA::Crypto::CCurl
|
4
|
+
else
|
5
|
+
require "iota/crypto/curl_ruby"
|
6
|
+
BaseCurl = IOTA::Crypto::RubyCurl
|
7
|
+
end
|
8
|
+
|
1
9
|
module IOTA
|
2
10
|
module Crypto
|
3
|
-
class Curl
|
4
|
-
NUMBER_OF_ROUNDS = 81
|
5
|
-
HASH_LENGTH = 243
|
6
|
-
STATE_LENGTH = 3 * HASH_LENGTH
|
7
|
-
|
11
|
+
class Curl < BaseCurl
|
8
12
|
def initialize(rounds = nil)
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
def setup(state = nil)
|
14
|
-
if state
|
15
|
-
@state = state
|
16
|
-
else
|
17
|
-
@state = []
|
18
|
-
STATE_LENGTH.times {|a| @state << 0}
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def reset
|
23
|
-
setup
|
24
|
-
end
|
25
|
-
|
26
|
-
def absorb(trits, offset, length)
|
27
|
-
loop do
|
28
|
-
i = 0
|
29
|
-
limit = length < HASH_LENGTH ? length : HASH_LENGTH
|
30
|
-
|
31
|
-
while i < limit
|
32
|
-
@state[i] = trits[offset]
|
33
|
-
i += 1
|
34
|
-
offset += 1
|
35
|
-
end
|
36
|
-
|
37
|
-
transform
|
38
|
-
length -= HASH_LENGTH
|
39
|
-
|
40
|
-
break if length <= 0
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def squeeze(trits, offset, length)
|
45
|
-
loop do
|
46
|
-
i = 0
|
47
|
-
limit = length < HASH_LENGTH ? length : HASH_LENGTH
|
48
|
-
while i < limit
|
49
|
-
trits[offset] = @state[i]
|
50
|
-
i += 1
|
51
|
-
offset += 1
|
52
|
-
end
|
53
|
-
|
54
|
-
transform
|
55
|
-
length -= HASH_LENGTH
|
56
|
-
|
57
|
-
break if length <= 0
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def transform
|
62
|
-
stateCopy = []
|
63
|
-
index = 0
|
64
|
-
|
65
|
-
(0...@rounds).step(1) do |_|
|
66
|
-
stateCopy = @state.slice(0, @state.length)
|
67
|
-
(0...STATE_LENGTH).step(1) do |i|
|
68
|
-
@state[i] = @truthTable[stateCopy[index].to_i + (stateCopy[index += (index < 365 ? 364 : -365)].to_i << 2) + 5]
|
69
|
-
end
|
70
|
-
end
|
13
|
+
rounds ||= NUMBER_OF_ROUNDS
|
14
|
+
super(rounds)
|
71
15
|
end
|
72
16
|
end
|
73
17
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module IOTA
|
2
|
+
module Crypto
|
3
|
+
class RubyCurl
|
4
|
+
NUMBER_OF_ROUNDS = 81
|
5
|
+
HASH_LENGTH = 243
|
6
|
+
STATE_LENGTH = 3 * HASH_LENGTH
|
7
|
+
TRUTH_TABLE = [1, 0, -1, 1, -1, 0, -1, 1, 0]
|
8
|
+
|
9
|
+
def initialize(rounds = nil)
|
10
|
+
@rounds = rounds || NUMBER_OF_ROUNDS
|
11
|
+
reset
|
12
|
+
end
|
13
|
+
|
14
|
+
def reset
|
15
|
+
@state = [0] * STATE_LENGTH
|
16
|
+
end
|
17
|
+
|
18
|
+
def absorb(trits)
|
19
|
+
length = trits.length
|
20
|
+
offset = 0
|
21
|
+
|
22
|
+
while offset < length
|
23
|
+
start = offset
|
24
|
+
stop = [start + HASH_LENGTH, length].min
|
25
|
+
|
26
|
+
@state[0...stop-start] = trits.slice(start, stop-start)
|
27
|
+
transform
|
28
|
+
|
29
|
+
offset += HASH_LENGTH
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def squeeze(trits)
|
34
|
+
trits[0...HASH_LENGTH] = @state.slice(0, HASH_LENGTH)
|
35
|
+
transform
|
36
|
+
end
|
37
|
+
|
38
|
+
def transform
|
39
|
+
previousState = @state.slice(0, @state.length)
|
40
|
+
newState = @state.slice(0, @state.length)
|
41
|
+
|
42
|
+
index = 0
|
43
|
+
round = 0
|
44
|
+
while round < @rounds
|
45
|
+
previousTrit = previousState[index].to_i
|
46
|
+
|
47
|
+
pos = 0
|
48
|
+
while true
|
49
|
+
index += (index < 365) ? 364 : -365
|
50
|
+
newTrit = previousState[index].to_i
|
51
|
+
newState[pos] = TRUTH_TABLE[previousTrit + (3 * newTrit) + 4]
|
52
|
+
previousTrit = newTrit
|
53
|
+
pos += 1
|
54
|
+
break if pos >= STATE_LENGTH
|
55
|
+
end
|
56
|
+
|
57
|
+
previousState = newState
|
58
|
+
newState = newState.slice(0, newState.length)
|
59
|
+
round += 1
|
60
|
+
end
|
61
|
+
|
62
|
+
@state = newState
|
63
|
+
end
|
64
|
+
|
65
|
+
def version
|
66
|
+
"Ruby"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/iota/utils/utils.rb
CHANGED
@@ -62,23 +62,21 @@ module IOTA
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def transactionObject(trytes)
|
65
|
-
return if !trytes
|
65
|
+
return nil if !trytes
|
66
66
|
|
67
67
|
# validity check
|
68
68
|
(2279...2295).step(1) do |i|
|
69
|
-
|
69
|
+
return nil if trytes[i] != "9"
|
70
70
|
end
|
71
71
|
|
72
72
|
trx = {}
|
73
73
|
transactionTrits = IOTA::Crypto::Converter.trits(trytes)
|
74
74
|
hash = []
|
75
75
|
|
76
|
-
curl = IOTA::Crypto::Curl.new
|
77
|
-
|
78
76
|
# generate the correct transaction hash
|
79
|
-
curl.
|
80
|
-
curl.absorb(transactionTrits
|
81
|
-
curl.squeeze(hash
|
77
|
+
curl = IOTA::Crypto::Curl.new
|
78
|
+
curl.absorb(transactionTrits)
|
79
|
+
curl.squeeze(hash)
|
82
80
|
|
83
81
|
trx['hash'] = IOTA::Crypto::Converter.trytes(hash)
|
84
82
|
trx['signatureMessageFragment'] = trytes.slice(0, 2187)
|
data/lib/iota/version.rb
CHANGED
data/test/curl_c_test.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
if !Dir.glob(File.join(File.dirname(__FILE__), '../lib/ccurl.*')).empty?
|
3
|
+
require "iota/crypto/curl_c"
|
4
|
+
|
5
|
+
class CcurlTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@converter = IOTA::Crypto::Converter
|
8
|
+
@curl = IOTA::Crypto::CCurl.new(81)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_that_hash_works
|
12
|
+
trytes = "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999G9AIBZPUUIXPRDTUJNGAUSWPJMLJOCSJSPVGP9KDCABPQIWXYOAXJVMDYSCPAAIJNWOHUIUNKKOVJJASCHJYTXA999999999999999999999FOINFALCON99999999999999999RJFYLXD99999999999D99999999WCKBQGFJRFIYVJAZDYLNQZIUQGG9EKZKNUOBEEASPPJXUGCTAGHGWLQSWJKC9DRVEKKHDOUJLNEQCGYK9HKFPGUUIXFOZBXZIJAFPWBYUTIAZMYHGAC9QMRDJCGOW9VXVLVQKTKRLQFITNLDHPDXHDWIVRZQGZ9999OEMEOVATRLZWXXDXIX9AVNDCHRLC9WHB9IAUUYKHUGIFBKCCYN9LRGTTQISBQYPDHTXRTOYVZTLU99999COINFALCON99999999999999999Z9PSAGQJE999999999L99999999IQXMVTRNAQVADDX9ET9IAMVJDZV"
|
13
|
+
expected_hash = "QLMNETEZDOYSBQLRPRJIZNRRDZ9EKY9LCOLNIDQEZNUFWOVYR9SJLBCVIJWIOKGNPMPGWYTNFMOW99999"
|
14
|
+
|
15
|
+
transactionTrits = @converter.trits(trytes)
|
16
|
+
hash = []
|
17
|
+
|
18
|
+
start = Time.now
|
19
|
+
# generate the correct transaction hash
|
20
|
+
@curl.reset
|
21
|
+
@curl.absorb(transactionTrits)
|
22
|
+
@curl.squeeze(hash)
|
23
|
+
hash = @converter.trytes(hash)
|
24
|
+
puts "C Curl time: #{(Time.now - start) * 1000.0}ms"
|
25
|
+
|
26
|
+
assert expected_hash == hash
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
puts "C extension is not available. Skipping tests for it."
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "iota/crypto/curl_ruby"
|
3
|
+
|
4
|
+
class RubyCurlTest < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@converter = IOTA::Crypto::Converter
|
7
|
+
@curl = IOTA::Crypto::RubyCurl.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_that_hash_works
|
11
|
+
trytes = "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999G9AIBZPUUIXPRDTUJNGAUSWPJMLJOCSJSPVGP9KDCABPQIWXYOAXJVMDYSCPAAIJNWOHUIUNKKOVJJASCHJYTXA999999999999999999999FOINFALCON99999999999999999RJFYLXD99999999999D99999999WCKBQGFJRFIYVJAZDYLNQZIUQGG9EKZKNUOBEEASPPJXUGCTAGHGWLQSWJKC9DRVEKKHDOUJLNEQCGYK9HKFPGUUIXFOZBXZIJAFPWBYUTIAZMYHGAC9QMRDJCGOW9VXVLVQKTKRLQFITNLDHPDXHDWIVRZQGZ9999OEMEOVATRLZWXXDXIX9AVNDCHRLC9WHB9IAUUYKHUGIFBKCCYN9LRGTTQISBQYPDHTXRTOYVZTLU99999COINFALCON99999999999999999Z9PSAGQJE999999999L99999999IQXMVTRNAQVADDX9ET9IAMVJDZV"
|
12
|
+
expected_hash = "QLMNETEZDOYSBQLRPRJIZNRRDZ9EKY9LCOLNIDQEZNUFWOVYR9SJLBCVIJWIOKGNPMPGWYTNFMOW99999"
|
13
|
+
|
14
|
+
transactionTrits = @converter.trits(trytes)
|
15
|
+
hash = []
|
16
|
+
|
17
|
+
start = Time.now
|
18
|
+
# generate the correct transaction hash
|
19
|
+
@curl.reset
|
20
|
+
@curl.absorb(transactionTrits)
|
21
|
+
@curl.squeeze(hash)
|
22
|
+
hash = @converter.trytes(hash)
|
23
|
+
puts "Ruby Curl time: #{(Time.now - start) * 1000.0}ms"
|
24
|
+
|
25
|
+
assert expected_hash == hash
|
26
|
+
end
|
27
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iota-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vivek Marakana
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-12-
|
11
|
+
date: 2017-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '5.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake-compiler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.4
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.0.4
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: digest-sha3
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -71,7 +85,8 @@ email:
|
|
71
85
|
- vivek.marakana@gmail.com
|
72
86
|
executables:
|
73
87
|
- iota-console
|
74
|
-
extensions:
|
88
|
+
extensions:
|
89
|
+
- ext/ccurl/extconf.rb
|
75
90
|
extra_rdoc_files: []
|
76
91
|
files:
|
77
92
|
- ".editorconfig"
|
@@ -83,6 +98,8 @@ files:
|
|
83
98
|
- Rakefile
|
84
99
|
- bin/iota-console
|
85
100
|
- examples/multisig.rb
|
101
|
+
- ext/ccurl/ccurl.c
|
102
|
+
- ext/ccurl/extconf.rb
|
86
103
|
- iota-ruby.gemspec
|
87
104
|
- lib/iota.rb
|
88
105
|
- lib/iota/api/api.rb
|
@@ -91,6 +108,8 @@ files:
|
|
91
108
|
- lib/iota/crypto/bundle.rb
|
92
109
|
- lib/iota/crypto/converter.rb
|
93
110
|
- lib/iota/crypto/curl.rb
|
111
|
+
- lib/iota/crypto/curl_c.rb
|
112
|
+
- lib/iota/crypto/curl_ruby.rb
|
94
113
|
- lib/iota/crypto/hmac.rb
|
95
114
|
- lib/iota/crypto/kerl.rb
|
96
115
|
- lib/iota/crypto/private_key.rb
|
@@ -111,6 +130,8 @@ files:
|
|
111
130
|
- lib/iota/utils/utils.rb
|
112
131
|
- lib/iota/version.rb
|
113
132
|
- test/ascii_test.rb
|
133
|
+
- test/curl_c_test.rb
|
134
|
+
- test/curl_ruby_test.rb
|
114
135
|
- test/kerl_test.rb
|
115
136
|
- test/test_helper.rb
|
116
137
|
- test/utils_test.rb
|
@@ -133,12 +154,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
154
|
version: '0'
|
134
155
|
requirements: []
|
135
156
|
rubyforge_project:
|
136
|
-
rubygems_version: 2.6.
|
157
|
+
rubygems_version: 2.6.14
|
137
158
|
signing_key:
|
138
159
|
specification_version: 4
|
139
160
|
summary: IOTA API wrapper for Ruby
|
140
161
|
test_files:
|
141
162
|
- test/ascii_test.rb
|
163
|
+
- test/curl_c_test.rb
|
164
|
+
- test/curl_ruby_test.rb
|
142
165
|
- test/kerl_test.rb
|
143
166
|
- test/test_helper.rb
|
144
167
|
- test/utils_test.rb
|