iota-ruby 1.0.1 → 1.1.0
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/.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
|