rbnacl 3.1.0 → 3.1.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 +4 -4
- data/.travis.yml +1 -1
- data/CHANGES.md +6 -0
- data/lib/rbnacl.rb +1 -1
- data/lib/rbnacl/version.rb +1 -1
- data/spec/rbnacl/boxes/curve25519xsalsa20poly1305/private_key_spec.rb +6 -6
- data/spec/rbnacl/boxes/curve25519xsalsa20poly1305/public_key_spec.rb +2 -2
- data/spec/rbnacl/boxes/curve25519xsalsa20poly1305_spec.rb +2 -2
- data/spec/rbnacl/group_element_spec.rb +3 -3
- data/spec/rbnacl/hash_spec.rb +6 -6
- data/spec/rbnacl/random_spec.rb +2 -2
- data/spec/rbnacl/secret_box_spec.rb +1 -1
- data/spec/rbnacl/signatures/ed25519/signing_key_spec.rb +3 -3
- data/spec/rbnacl/signatures/ed25519/verify_key_spec.rb +3 -3
- data/spec/rbnacl/simple_box_spec.rb +5 -5
- data/spec/rbnacl/util_spec.rb +22 -22
- data/spec/shared/authenticator.rb +5 -5
- data/spec/shared/box.rb +2 -2
- data/spec/shared/key_equality.rb +6 -6
- data/tasks/rubocop.rake +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff876d588d1e3d16c902b3316141585d4172eab5
|
4
|
+
data.tar.gz: 7a22f5b8ea0fd18cdbc0a52d06880e81a53a742b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e67a5a0fdc8293c993ddcf79cf1c21e92c68a31b393b37b8684b93cda182072441321fbb2eebc3612bb4061859c0d6d750d28417534200f5276beb9d221f6c24
|
7
|
+
data.tar.gz: 80220efc75c5d404172c70e589a5446d0e6b7d560ad85f530c57747f46ce63e3e72d2bcb3daed67d9d31c43dc5f9dd972cd102e2d20c014f79466ab29e85fecc
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
data/lib/rbnacl.rb
CHANGED
data/lib/rbnacl/version.rb
CHANGED
@@ -11,11 +11,11 @@ describe RbNaCl::PrivateKey do
|
|
11
11
|
let(:secret_key) { RbNaCl::PrivateKey.generate }
|
12
12
|
|
13
13
|
it "returns a secret key" do
|
14
|
-
secret_key.
|
14
|
+
expect(secret_key).to be_a RbNaCl::PrivateKey
|
15
15
|
end
|
16
16
|
|
17
17
|
it "has the public key also set" do
|
18
|
-
secret_key.public_key.
|
18
|
+
expect(secret_key.public_key).to be_a RbNaCl::PublicKey
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -35,23 +35,23 @@ describe RbNaCl::PrivateKey do
|
|
35
35
|
|
36
36
|
context "public_key" do
|
37
37
|
it "returns a public key" do
|
38
|
-
subject.public_key.
|
38
|
+
expect(subject.public_key).to be_a RbNaCl::PublicKey
|
39
39
|
end
|
40
40
|
|
41
41
|
it "returns the correct public key" do
|
42
|
-
subject.public_key.to_s.
|
42
|
+
expect(subject.public_key.to_s).to eql bobpk
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
context "#to_bytes" do
|
47
47
|
it "returns the bytes of the key" do
|
48
|
-
subject.to_s.
|
48
|
+
expect(subject.to_s).to eq bobsk
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
context "#to_s" do
|
53
53
|
it "returns the raw bytes of the key" do
|
54
|
-
subject.to_bytes.
|
54
|
+
expect(subject.to_bytes).to eq bobsk
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -22,13 +22,13 @@ describe RbNaCl::PublicKey do
|
|
22
22
|
|
23
23
|
context "#to_bytes" do
|
24
24
|
it "returns the bytes of the key" do
|
25
|
-
subject.to_bytes.
|
25
|
+
expect(subject.to_bytes).to eq alicepk
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
29
|
context "#to_s" do
|
30
30
|
it "returns the bytes of the key" do
|
31
|
-
subject.to_s.
|
31
|
+
expect(subject.to_s).to eq alicepk
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -9,11 +9,11 @@ describe RbNaCl::Box do
|
|
9
9
|
|
10
10
|
context "new" do
|
11
11
|
it "accepts strings" do
|
12
|
-
expect { RbNaCl::Box.new(alicepk, bobsk) }.to_not raise_error
|
12
|
+
expect { RbNaCl::Box.new(alicepk, bobsk) }.to_not raise_error
|
13
13
|
end
|
14
14
|
|
15
15
|
it "accepts KeyPairs" do
|
16
|
-
expect { RbNaCl::Box.new(alice_key, bob_key) }.to_not raise_error
|
16
|
+
expect { RbNaCl::Box.new(alice_key, bob_key) }.to_not raise_error
|
17
17
|
end
|
18
18
|
|
19
19
|
it "raises TypeError on a nil public key" do
|
@@ -12,15 +12,15 @@ describe RbNaCl::GroupElement do
|
|
12
12
|
subject { described_class.new(bob_public) }
|
13
13
|
|
14
14
|
it "multiplies integers with the base point" do
|
15
|
-
described_class.base.mult(alice_private).to_s.
|
15
|
+
expect(described_class.base.mult(alice_private).to_s).to eq alice_public
|
16
16
|
end
|
17
17
|
|
18
18
|
it "multiplies integers with arbitrary points" do
|
19
|
-
described_class.new(bob_public).mult(alice_private).to_s.
|
19
|
+
expect(described_class.new(bob_public).mult(alice_private).to_s).to eq alice_mult_bob
|
20
20
|
end
|
21
21
|
|
22
22
|
it "serializes to bytes" do
|
23
|
-
subject.to_bytes.
|
23
|
+
expect(subject.to_bytes).to eq bob_public
|
24
24
|
end
|
25
25
|
|
26
26
|
include_examples "serializable"
|
data/spec/rbnacl/hash_spec.rb
CHANGED
@@ -8,15 +8,15 @@ describe RbNaCl::Hash do
|
|
8
8
|
let(:empty_string_hash) { vector :sha256_empty }
|
9
9
|
|
10
10
|
it "calculates the correct hash for a reference string" do
|
11
|
-
RbNaCl::Hash.sha256(reference_string).
|
11
|
+
expect(RbNaCl::Hash.sha256(reference_string)).to eq reference_string_hash
|
12
12
|
end
|
13
13
|
|
14
14
|
it "calculates the correct hash for an empty string" do
|
15
|
-
RbNaCl::Hash.sha256("").
|
15
|
+
expect(RbNaCl::Hash.sha256("")).to eq empty_string_hash
|
16
16
|
end
|
17
17
|
|
18
18
|
it "doesn't raise on a null byte" do
|
19
|
-
expect { RbNaCl::Hash.sha256("\0") }.to_not raise_error
|
19
|
+
expect { RbNaCl::Hash.sha256("\0") }.to_not raise_error
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -26,15 +26,15 @@ describe RbNaCl::Hash do
|
|
26
26
|
let(:empty_string_hash) { vector :sha512_empty }
|
27
27
|
|
28
28
|
it "calculates the correct hash for a reference string" do
|
29
|
-
RbNaCl::Hash.sha512(reference_string).
|
29
|
+
expect(RbNaCl::Hash.sha512(reference_string)).to eq reference_string_hash
|
30
30
|
end
|
31
31
|
|
32
32
|
it "calculates the correct hash for an empty string" do
|
33
|
-
RbNaCl::Hash.sha512("").
|
33
|
+
expect(RbNaCl::Hash.sha512("")).to eq empty_string_hash
|
34
34
|
end
|
35
35
|
|
36
36
|
it "doesn't raise on a null byte" do
|
37
|
-
expect { RbNaCl::Hash.sha512("\0") }.to_not raise_error
|
37
|
+
expect { RbNaCl::Hash.sha512("\0") }.to_not raise_error
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
data/spec/rbnacl/random_spec.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# encoding: binary
|
2
2
|
describe RbNaCl::Random do
|
3
3
|
it "produces random bytes" do
|
4
|
-
RbNaCl::Random.random_bytes(16).bytesize.
|
4
|
+
expect(RbNaCl::Random.random_bytes(16).bytesize).to eq(16)
|
5
5
|
end
|
6
6
|
it "produces different random bytes" do
|
7
|
-
RbNaCl::Random.random_bytes(16).
|
7
|
+
expect(RbNaCl::Random.random_bytes(16)).not_to eq(RbNaCl::Random.random_bytes(16))
|
8
8
|
end
|
9
9
|
end
|
@@ -9,15 +9,15 @@ describe RbNaCl::SigningKey do
|
|
9
9
|
subject { described_class.new(signing_key) }
|
10
10
|
|
11
11
|
it "generates keys" do
|
12
|
-
described_class.generate.
|
12
|
+
expect(described_class.generate).to be_a described_class
|
13
13
|
end
|
14
14
|
|
15
15
|
it "signs messages as bytes" do
|
16
|
-
subject.sign(message).
|
16
|
+
expect(subject.sign(message)).to eq signature
|
17
17
|
end
|
18
18
|
|
19
19
|
it "serializes to bytes" do
|
20
|
-
subject.to_bytes.
|
20
|
+
expect(subject.to_bytes).to eq signing_key
|
21
21
|
end
|
22
22
|
|
23
23
|
include_examples "key equality" do
|
@@ -10,7 +10,7 @@ describe RbNaCl::VerifyKey do
|
|
10
10
|
subject { RbNaCl::SigningKey.new(signing_key).verify_key }
|
11
11
|
|
12
12
|
it "verifies correct signatures" do
|
13
|
-
subject.verify(signature, message).
|
13
|
+
expect(subject.verify(signature, message)).to eq true
|
14
14
|
end
|
15
15
|
|
16
16
|
it "raises when asked to verify a bad signature" do
|
@@ -22,11 +22,11 @@ describe RbNaCl::VerifyKey do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
it "serializes to bytes" do
|
25
|
-
subject.to_bytes.
|
25
|
+
expect(subject.to_bytes).to eq verify_key
|
26
26
|
end
|
27
27
|
|
28
28
|
it "initializes from bytes" do
|
29
|
-
described_class.new(verify_key).to_s.
|
29
|
+
expect(described_class.new(verify_key).to_s).to eq verify_key
|
30
30
|
end
|
31
31
|
|
32
32
|
include_examples "key equality" do
|
@@ -15,7 +15,7 @@ describe RbNaCl::SimpleBox do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it "can be instantiated from a secret key" do
|
18
|
-
described_class.from_secret_key(secret_key).
|
18
|
+
expect(described_class.from_secret_key(secret_key)).to be_a described_class
|
19
19
|
end
|
20
20
|
|
21
21
|
it "raises TypeError when given a nil secret key" do
|
@@ -23,7 +23,7 @@ describe RbNaCl::SimpleBox do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
it "can be instantiated from a key-pair" do
|
26
|
-
described_class.from_keypair(alicepk, bobsk).
|
26
|
+
expect(described_class.from_keypair(alicepk, bobsk)).to be_a described_class
|
27
27
|
end
|
28
28
|
|
29
29
|
it "raises TypeError when given nil secret keys in the pair" do
|
@@ -42,16 +42,16 @@ describe RbNaCl::SimpleBox do
|
|
42
42
|
describe "bob" do
|
43
43
|
it "decrypts a message from alice" do
|
44
44
|
alices_ciphertext = alice.encrypt(message)
|
45
|
-
bob.decrypt(alices_ciphertext).
|
45
|
+
expect(bob.decrypt(alices_ciphertext)).to eql message
|
46
46
|
end
|
47
47
|
|
48
48
|
it "decrypts own message" do
|
49
49
|
bobs_ciphertext = bob.encrypt(message)
|
50
|
-
bob.decrypt(bobs_ciphertext).
|
50
|
+
expect(bob.decrypt(bobs_ciphertext)).to eql message
|
51
51
|
end
|
52
52
|
|
53
53
|
it "decrypts a message with a 'random' nonce" do
|
54
|
-
bob.decrypt(nonce+ciphertext).
|
54
|
+
expect(bob.decrypt(nonce+ciphertext)).to eql message
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
data/spec/rbnacl/util_spec.rb
CHANGED
@@ -8,12 +8,12 @@ describe RbNaCl::Util do
|
|
8
8
|
let (:long_msg) { RbNaCl::Util.zeros(33) }
|
9
9
|
|
10
10
|
it "confirms identical messages are identical" do
|
11
|
-
RbNaCl::Util.verify32!(msg, identical_msg).
|
11
|
+
expect(RbNaCl::Util.verify32!(msg, identical_msg)).to be true
|
12
12
|
end
|
13
13
|
|
14
14
|
it "confirms non-identical messages are non-identical" do
|
15
|
-
RbNaCl::Util.verify32!(msg, other_msg).
|
16
|
-
RbNaCl::Util.verify32!(other_msg, msg).
|
15
|
+
expect(RbNaCl::Util.verify32!(msg, other_msg)).to be false
|
16
|
+
expect(RbNaCl::Util.verify32!(other_msg, msg)).to be false
|
17
17
|
end
|
18
18
|
|
19
19
|
it "raises descriptively on a short message in position 1" do
|
@@ -38,16 +38,16 @@ describe RbNaCl::Util do
|
|
38
38
|
let (:long_msg) { RbNaCl::Util.zeros(33) }
|
39
39
|
|
40
40
|
it "confirms identical messages are identical" do
|
41
|
-
RbNaCl::Util.verify32(msg, identical_msg).
|
41
|
+
expect(RbNaCl::Util.verify32(msg, identical_msg)).to be true
|
42
42
|
end
|
43
43
|
|
44
44
|
it "confirms non-identical messages are non-identical" do
|
45
|
-
RbNaCl::Util.verify32(msg, other_msg).
|
46
|
-
RbNaCl::Util.verify32(other_msg, msg).
|
47
|
-
RbNaCl::Util.verify32(short_msg, msg).
|
48
|
-
RbNaCl::Util.verify32(msg, short_msg).
|
49
|
-
RbNaCl::Util.verify32(long_msg, msg).
|
50
|
-
RbNaCl::Util.verify32(msg, long_msg).
|
45
|
+
expect(RbNaCl::Util.verify32(msg, other_msg)).to be false
|
46
|
+
expect(RbNaCl::Util.verify32(other_msg, msg)).to be false
|
47
|
+
expect(RbNaCl::Util.verify32(short_msg, msg)).to be false
|
48
|
+
expect(RbNaCl::Util.verify32(msg, short_msg)).to be false
|
49
|
+
expect(RbNaCl::Util.verify32(long_msg, msg)).to be false
|
50
|
+
expect(RbNaCl::Util.verify32(msg, long_msg)).to be false
|
51
51
|
end
|
52
52
|
|
53
53
|
end
|
@@ -60,12 +60,12 @@ describe RbNaCl::Util do
|
|
60
60
|
let (:long_msg) { RbNaCl::Util.zeros(17) }
|
61
61
|
|
62
62
|
it "confirms identical messages are identical" do
|
63
|
-
RbNaCl::Util.verify16!(msg, identical_msg).
|
63
|
+
expect(RbNaCl::Util.verify16!(msg, identical_msg)).to be true
|
64
64
|
end
|
65
65
|
|
66
66
|
it "confirms non-identical messages are non-identical" do
|
67
|
-
RbNaCl::Util.verify16!(msg, other_msg).
|
68
|
-
RbNaCl::Util.verify16!(other_msg, msg).
|
67
|
+
expect(RbNaCl::Util.verify16!(msg, other_msg)).to be false
|
68
|
+
expect(RbNaCl::Util.verify16!(other_msg, msg)).to be false
|
69
69
|
end
|
70
70
|
|
71
71
|
it "raises descriptively on a short message in position 1" do
|
@@ -90,16 +90,16 @@ describe RbNaCl::Util do
|
|
90
90
|
let (:long_msg) { RbNaCl::Util.zeros(17) }
|
91
91
|
|
92
92
|
it "confirms identical messages are identical" do
|
93
|
-
RbNaCl::Util.verify16(msg, identical_msg).
|
93
|
+
expect(RbNaCl::Util.verify16(msg, identical_msg)).to be true
|
94
94
|
end
|
95
95
|
|
96
96
|
it "confirms non-identical messages are non-identical" do
|
97
|
-
RbNaCl::Util.verify16(msg, other_msg).
|
98
|
-
RbNaCl::Util.verify16(other_msg, msg).
|
99
|
-
RbNaCl::Util.verify16(short_msg, msg).
|
100
|
-
RbNaCl::Util.verify16(msg, short_msg).
|
101
|
-
RbNaCl::Util.verify16(long_msg, msg).
|
102
|
-
RbNaCl::Util.verify16(msg, long_msg).
|
97
|
+
expect(RbNaCl::Util.verify16(msg, other_msg)).to be false
|
98
|
+
expect(RbNaCl::Util.verify16(other_msg, msg)).to be false
|
99
|
+
expect(RbNaCl::Util.verify16(short_msg, msg)).to be false
|
100
|
+
expect(RbNaCl::Util.verify16(msg, short_msg)).to be false
|
101
|
+
expect(RbNaCl::Util.verify16(long_msg, msg)).to be false
|
102
|
+
expect(RbNaCl::Util.verify16(msg, long_msg)).to be false
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
@@ -133,11 +133,11 @@ describe RbNaCl::Util do
|
|
133
133
|
let (:hex) { "deadbeef" }
|
134
134
|
|
135
135
|
it "encodes to hex with bin2hex" do
|
136
|
-
RbNaCl::Util.bin2hex(bytes).
|
136
|
+
expect(RbNaCl::Util.bin2hex(bytes)).to eq hex
|
137
137
|
end
|
138
138
|
|
139
139
|
it "decodes from hex with hex2bin" do
|
140
|
-
RbNaCl::Util.hex2bin(hex).
|
140
|
+
expect(RbNaCl::Util.hex2bin(hex)).to eq bytes
|
141
141
|
end
|
142
142
|
end
|
143
143
|
end
|
@@ -5,7 +5,7 @@ shared_examples "authenticator" do
|
|
5
5
|
|
6
6
|
context ".new" do
|
7
7
|
it "accepts a key" do
|
8
|
-
expect { described_class.new(key) }.to_not raise_error
|
8
|
+
expect { described_class.new(key) }.to_not raise_error
|
9
9
|
end
|
10
10
|
|
11
11
|
it "requires a key" do
|
@@ -27,7 +27,7 @@ shared_examples "authenticator" do
|
|
27
27
|
|
28
28
|
context ".auth" do
|
29
29
|
it "produces an authenticator" do
|
30
|
-
described_class.auth(key, message).
|
30
|
+
expect(described_class.auth(key, message)).to eq tag
|
31
31
|
end
|
32
32
|
|
33
33
|
it "raises TypeError on a nil key" do
|
@@ -41,7 +41,7 @@ shared_examples "authenticator" do
|
|
41
41
|
|
42
42
|
context ".verify" do
|
43
43
|
it "verify an authenticator" do
|
44
|
-
described_class.verify(key, tag, message).
|
44
|
+
expect(described_class.verify(key, tag, message)).to eq true
|
45
45
|
end
|
46
46
|
|
47
47
|
it "raises TypeError on a nil key" do
|
@@ -70,13 +70,13 @@ shared_examples "authenticator" do
|
|
70
70
|
|
71
71
|
context "#auth" do
|
72
72
|
it "produces an authenticator" do
|
73
|
-
authenticator.auth(message).
|
73
|
+
expect(authenticator.auth(message)).to eq tag
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
77
|
context "#verify" do
|
78
78
|
it "verifies an authenticator" do
|
79
|
-
authenticator.verify(tag, message).
|
79
|
+
expect(authenticator.verify(tag, message)).to be true
|
80
80
|
end
|
81
81
|
|
82
82
|
it "fails to validate an invalid authenticator" do
|
data/spec/shared/box.rb
CHANGED
@@ -12,7 +12,7 @@ shared_examples "box" do
|
|
12
12
|
context "box" do
|
13
13
|
|
14
14
|
it "encrypts a message" do
|
15
|
-
box.box(nonce, message).
|
15
|
+
expect(box.box(nonce, message)).to eq ciphertext
|
16
16
|
end
|
17
17
|
|
18
18
|
it "raises on a short nonce" do
|
@@ -27,7 +27,7 @@ shared_examples "box" do
|
|
27
27
|
context "open" do
|
28
28
|
|
29
29
|
it "decrypts a message" do
|
30
|
-
box.open(nonce, ciphertext).
|
30
|
+
expect(box.open(nonce, ciphertext)).to eq message
|
31
31
|
end
|
32
32
|
|
33
33
|
it "raises on a truncated message to decrypt" do
|
data/spec/shared/key_equality.rb
CHANGED
@@ -2,25 +2,25 @@
|
|
2
2
|
shared_examples "key equality" do
|
3
3
|
context "equality" do
|
4
4
|
it "equal keys are equal" do
|
5
|
-
(described_class.new(key_bytes) == key).
|
5
|
+
expect(described_class.new(key_bytes) == key).to be true
|
6
6
|
end
|
7
7
|
it "equal keys are equal to the string" do
|
8
|
-
(key == key_bytes).
|
8
|
+
expect(key == key_bytes).to be true
|
9
9
|
end
|
10
10
|
it "keys are not equal to zero" do
|
11
|
-
(key == RbNaCl::Util.zeros(32)).
|
11
|
+
expect(key == RbNaCl::Util.zeros(32)).to be false
|
12
12
|
end
|
13
13
|
it "keys are not equal to another key" do
|
14
|
-
(key == other_key).
|
14
|
+
expect(key == other_key).to be false
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
context "lexicographic sorting" do
|
19
19
|
it "can be compared lexicographically to a key smaller than it" do
|
20
|
-
(key > RbNaCl::Util.zeros(32)).
|
20
|
+
expect(key > RbNaCl::Util.zeros(32)).to be true
|
21
21
|
end
|
22
22
|
it "can be compared lexicographically to a key larger than it" do
|
23
|
-
(described_class.new(RbNaCl::Util.zeros(32)) < key).
|
23
|
+
expect(described_class.new(RbNaCl::Util.zeros(32)) < key).to be true
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
data/tasks/rubocop.rake
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbnacl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Arcieri
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain:
|
12
12
|
- bascule.cert
|
13
|
-
date: 2014-
|
13
|
+
date: 2014-06-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: ffi
|