ore-rs 0.7.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 +7 -0
- data/CODEOWNERS +2 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/CONTRIBUTING.md +10 -0
- data/LICENCE +124 -0
- data/README.md +72 -0
- data/ext/ore_rs/.gitignore +4 -0
- data/ext/ore_rs/Cargo.lock +741 -0
- data/ext/ore_rs/Cargo.toml +14 -0
- data/ext/ore_rs/extconf.rb +4 -0
- data/ext/ore_rs/src/lib.rs +142 -0
- data/lib/ore/aes128/ciphertext.rb +47 -0
- data/lib/ore/aes128.rb +204 -0
- data/lib/ore/version.rb +3 -0
- data/lib/ore-rs.rb +15 -0
- data/ore-rs.gemspec +43 -0
- metadata +236 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
[package]
|
2
|
+
name = "ore-rs"
|
3
|
+
version = "0.0.0"
|
4
|
+
edition = "2021"
|
5
|
+
|
6
|
+
[dependencies]
|
7
|
+
lazy_static = "^0.2.2"
|
8
|
+
ore-rs = "^0.6.0"
|
9
|
+
ore-encoding-rs = { git = "https://github.com/cipherstash/ore_encoding.rs" }
|
10
|
+
rb-sys = "0.8.0"
|
11
|
+
rutie = { git = "https://github.com/mpalmer/rutie", branch = "rb_sys" }
|
12
|
+
|
13
|
+
[lib]
|
14
|
+
crate-type = ["cdylib"]
|
@@ -0,0 +1,142 @@
|
|
1
|
+
#[macro_use]
|
2
|
+
extern crate rutie;
|
3
|
+
|
4
|
+
#[macro_use]
|
5
|
+
extern crate lazy_static;
|
6
|
+
|
7
|
+
use ore_encoding_rs::OrePlaintext;
|
8
|
+
use ore_rs::{CipherText, ORECipher, OREEncrypt};
|
9
|
+
use ore_rs::scheme::bit2::OREAES128;
|
10
|
+
use rutie::{Boolean, Class, Encoding, Float, Integer, Module, Object, RString, VerifiedObject, VM};
|
11
|
+
use std::cmp::Ordering;
|
12
|
+
|
13
|
+
module!(RbORE);
|
14
|
+
class!(RbOREAES128);
|
15
|
+
class!(RbOREAES128Ciphertext);
|
16
|
+
|
17
|
+
impl VerifiedObject for RbOREAES128Ciphertext {
|
18
|
+
fn is_correct_type<T: Object>(object: &T) -> bool {
|
19
|
+
let klass = Module::from_existing("ORE").get_nested_class("AES128").get_nested_class("Ciphertext");
|
20
|
+
klass.case_equals(object)
|
21
|
+
}
|
22
|
+
|
23
|
+
fn error_message() -> &'static str {
|
24
|
+
"Error converting to ORE::AES128::Ciphertext"
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
impl From<CipherText<OREAES128, 8>> for RbOREAES128Ciphertext {
|
29
|
+
fn from(ct: CipherText<OREAES128, 8>) -> Self {
|
30
|
+
let klass = Module::from_existing("ORE").get_nested_class("AES128").get_nested_class("Ciphertext");
|
31
|
+
klass.wrap_data(OreAes128Ciphertext { ct: ct.to_bytes(), n: 8 }, &*OREAES128_CIPHERTEXT_WRAPPER)
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
pub struct OreAes128 {
|
36
|
+
cipher: OREAES128
|
37
|
+
}
|
38
|
+
|
39
|
+
wrappable_struct!(OreAes128, OreAes128Wrapper, OREAES128_WRAPPER);
|
40
|
+
|
41
|
+
pub struct OreAes128Ciphertext {
|
42
|
+
#[allow(dead_code)]
|
43
|
+
n: u32,
|
44
|
+
ct: Vec<u8>
|
45
|
+
}
|
46
|
+
|
47
|
+
wrappable_struct!(OreAes128Ciphertext, OreAes128CiphertextWrapper, OREAES128_CIPHERTEXT_WRAPPER);
|
48
|
+
|
49
|
+
methods!(
|
50
|
+
RbOREAES128,
|
51
|
+
rbself,
|
52
|
+
|
53
|
+
fn ore_aes128_new(k1string: RString, k2string: RString) -> RbOREAES128 {
|
54
|
+
let mut k1: [u8; 16] = Default::default();
|
55
|
+
let mut k2: [u8; 16] = Default::default();
|
56
|
+
|
57
|
+
k1.clone_from_slice(k1string.unwrap().to_bytes_unchecked());
|
58
|
+
k2.clone_from_slice(k2string.unwrap().to_bytes_unchecked());
|
59
|
+
|
60
|
+
let cipher: OREAES128 = ORECipher::init(&k1, &k2).unwrap();
|
61
|
+
|
62
|
+
let klass = Module::from_existing("ORE").get_nested_class("AES128");
|
63
|
+
return klass.wrap_data(OreAes128 { cipher: cipher }, &*OREAES128_WRAPPER);
|
64
|
+
}
|
65
|
+
|
66
|
+
fn ore_aes128_encrypt_u64(plaintext: Integer) -> RbOREAES128Ciphertext {
|
67
|
+
let ore = rbself.get_data_mut(&*OREAES128_WRAPPER);
|
68
|
+
plaintext.unwrap().to_u64().encrypt(&mut ore.cipher).map_err(|e| VM::raise(Class::from_existing("RuntimeError"), &format!("Failed to encrypt ORE plaintext: {:?}", e))).unwrap().into()
|
69
|
+
}
|
70
|
+
|
71
|
+
fn ore_aes128_encrypt_f64(plaintext: Float) -> RbOREAES128Ciphertext {
|
72
|
+
let ore = rbself.get_data_mut(&*OREAES128_WRAPPER);
|
73
|
+
OrePlaintext::<u64>::from(plaintext.unwrap().to_f64()).0.encrypt(&mut ore.cipher).map_err(|e| VM::raise(Class::from_existing("RuntimeError"), &format!("Failed to encrypt ORE plaintext: {:?}", e))).unwrap().into()
|
74
|
+
}
|
75
|
+
|
76
|
+
fn ore_aes128_encrypt_string(plaintext: RString) -> RbOREAES128Ciphertext {
|
77
|
+
let ore = rbself.get_data_mut(&*OREAES128_WRAPPER);
|
78
|
+
OrePlaintext::<u64>::from(plaintext.unwrap().to_string_unchecked()).0.encrypt(&mut ore.cipher).map_err(|e| VM::raise(Class::from_existing("RuntimeError"), &format!("Failed to encrypt ORE plaintext: {:?}", e))).unwrap().into()
|
79
|
+
}
|
80
|
+
|
81
|
+
fn ore_aes128_encrypt_bool(plaintext: Boolean) -> RbOREAES128Ciphertext {
|
82
|
+
let ore = rbself.get_data_mut(&*OREAES128_WRAPPER);
|
83
|
+
OrePlaintext::<u64>::from(plaintext.unwrap().to_bool()).0.encrypt(&mut ore.cipher).map_err(|e| VM::raise(Class::from_existing("RuntimeError"), &format!("Failed to encrypt ORE plaintext: {:?}", e))).unwrap().into()
|
84
|
+
}
|
85
|
+
);
|
86
|
+
|
87
|
+
methods!(
|
88
|
+
RbOREAES128Ciphertext,
|
89
|
+
rbself,
|
90
|
+
|
91
|
+
fn ore_aes128_ciphertext_new(serialized_ciphertext: RString, n: Integer) -> RbOREAES128Ciphertext {
|
92
|
+
let ct = CipherText::<OREAES128, 8>::from_bytes(&serialized_ciphertext.unwrap().to_vec_u8_unchecked()).map_err(|e| VM::raise(Class::from_existing("ArgumentError"), &format!("Failed to deserialize ORE ciphertext: {:?}", e))).unwrap();
|
93
|
+
|
94
|
+
let klass = Module::from_existing("ORE").get_nested_class("AES128").get_nested_class("Ciphertext");
|
95
|
+
return klass.wrap_data(OreAes128Ciphertext { ct: ct.to_bytes(), n: n.unwrap().to_u32() }, &*OREAES128_CIPHERTEXT_WRAPPER);
|
96
|
+
}
|
97
|
+
|
98
|
+
fn ore_aes128_ciphertext_serialize() -> RString {
|
99
|
+
let obj = rbself.get_data(&*OREAES128_CIPHERTEXT_WRAPPER);
|
100
|
+
|
101
|
+
return RString::from_bytes(&obj.ct, &Encoding::find("BINARY").unwrap());
|
102
|
+
}
|
103
|
+
|
104
|
+
fn ore_aes128_ciphertext_cmp(other: RbOREAES128Ciphertext) -> Integer {
|
105
|
+
let obj = rbself.get_data(&*OREAES128_CIPHERTEXT_WRAPPER);
|
106
|
+
let real_other = other.unwrap();
|
107
|
+
let oth = real_other.get_data(&*OREAES128_CIPHERTEXT_WRAPPER);
|
108
|
+
|
109
|
+
match OREAES128::compare_raw_slices(&obj.ct, &oth.ct) {
|
110
|
+
Some(Ordering::Equal) => Integer::from(0),
|
111
|
+
Some(Ordering::Less) => Integer::from(-1),
|
112
|
+
Some(Ordering::Greater) => Integer::from(1),
|
113
|
+
None => {
|
114
|
+
VM::raise(Class::from_existing("RuntimeError"), "Comparison failed");
|
115
|
+
Integer::from(0)
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
);
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
#[allow(non_snake_case)]
|
125
|
+
#[no_mangle]
|
126
|
+
pub extern "C" fn Init_ore_rs() {
|
127
|
+
Module::from_existing("ORE").define(|oremod| {
|
128
|
+
oremod.define_nested_class("AES128", None).define(|cipher_class| {
|
129
|
+
cipher_class.singleton_class().def_private("_new", ore_aes128_new);
|
130
|
+
cipher_class.def_private("_encrypt_u64", ore_aes128_encrypt_u64);
|
131
|
+
cipher_class.def_private("_encrypt_f64", ore_aes128_encrypt_f64);
|
132
|
+
cipher_class.def_private("_encrypt_string", ore_aes128_encrypt_string);
|
133
|
+
cipher_class.def_private("_encrypt_bool", ore_aes128_encrypt_bool);
|
134
|
+
|
135
|
+
cipher_class.define_nested_class("Ciphertext", None).define(|ciphertext_class| {
|
136
|
+
ciphertext_class.singleton_class().def_private("_new", ore_aes128_ciphertext_new);
|
137
|
+
ciphertext_class.def_private("_serialize", ore_aes128_ciphertext_serialize);
|
138
|
+
ciphertext_class.def_private("_cmp", ore_aes128_ciphertext_cmp);
|
139
|
+
});
|
140
|
+
});
|
141
|
+
});
|
142
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ORE
|
2
|
+
class AES128
|
3
|
+
# An ORE ciphertext produced by an AES128 cipher.
|
4
|
+
class Ciphertext
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
# Create a ciphertext object from a serialized form.
|
8
|
+
#
|
9
|
+
# ORE ciphertexts can be serialized (using #to_s), and then deserialized by
|
10
|
+
# passing them into this constructor.
|
11
|
+
#
|
12
|
+
# @param ct [String] the serialized ciphertext. This must be a `BINARY` encoded
|
13
|
+
# string.
|
14
|
+
#
|
15
|
+
# @param n [Integer] the number of ORE blocks contained in the ciphertext. Each
|
16
|
+
# ORE block represents one octet of the plaintext. At present, only 64-bit
|
17
|
+
# plaintexts are supported, so this must always be `8`.
|
18
|
+
#
|
19
|
+
# @raises [ArgumentError] if the string passed as the ciphertext is not valid,
|
20
|
+
# or `n` is not a supported value.
|
21
|
+
#
|
22
|
+
def self.new(ct, n)
|
23
|
+
unless ct.is_a?(String)
|
24
|
+
raise ArgumentError, "Ciphertext must be a string"
|
25
|
+
end
|
26
|
+
|
27
|
+
unless n == 8
|
28
|
+
raise ArgumentError, "Only a block count of 8 is currently supported"
|
29
|
+
end
|
30
|
+
|
31
|
+
_new(ct, n)
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
_serialize
|
36
|
+
end
|
37
|
+
|
38
|
+
def <=>(other)
|
39
|
+
unless other.is_a?(ORE::AES128::Ciphertext)
|
40
|
+
raise ArgumentError, "Cannot compare an ORE ciphertext to anything other than another ciphertext"
|
41
|
+
end
|
42
|
+
|
43
|
+
_cmp(other)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/ore/aes128.rb
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
require "date"
|
2
|
+
|
3
|
+
require_relative "./aes128/ciphertext"
|
4
|
+
|
5
|
+
module ORE
|
6
|
+
class AES128
|
7
|
+
VALID_STRING_ENCODINGS = [Encoding.find("UTF-8"), Encoding.find("US-ASCII")]
|
8
|
+
private_constant :VALID_STRING_ENCODINGS
|
9
|
+
|
10
|
+
# Create a new ORE::AES128 "cipher" -- an object capable of encrypting plaintexts into ORE ciphertexts.
|
11
|
+
#
|
12
|
+
# @param k1 [String] also known as the "PRF key", this is one of the two keys required
|
13
|
+
# to encrypt with ORE. This key must be a 16 octet string in the `BINARY` encoding.
|
14
|
+
#
|
15
|
+
# @param k2 [String] also known as the "PRP key", this is the other of the two keys
|
16
|
+
# required to encrypt with ORE. This key must also be a 16 octet string in the `BINARY`
|
17
|
+
# encoding.
|
18
|
+
#
|
19
|
+
# @param b [Integer] the number of bits in each plaintext. At present, the only supported
|
20
|
+
# value for this parameter is `64`.
|
21
|
+
#
|
22
|
+
# @param n [Integer] the number of blocks to generate in the ORE ciphertext. Each block
|
23
|
+
# is derived from 8 bits of plaintext, and thus at present the only supported value
|
24
|
+
# for this parameter is `8`.
|
25
|
+
#
|
26
|
+
# @raises [ArgumentError] if any of the parameters do not meet the requirements.
|
27
|
+
#
|
28
|
+
def self.new(k1, k2, b, n)
|
29
|
+
validate_key(k1, "k1")
|
30
|
+
validate_key(k2, "k2")
|
31
|
+
|
32
|
+
unless b == 64
|
33
|
+
raise ArgumentError, "Only 64 bit ORE plaintexts are supported at present"
|
34
|
+
end
|
35
|
+
|
36
|
+
unless n == 8
|
37
|
+
raise ArgumentError, "Only 8 bit ORE blocks are supported at present"
|
38
|
+
end
|
39
|
+
|
40
|
+
_new(k1, k2, b, n)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Encrypt a plaintext into an ORE::AES128::Ciphertext.
|
44
|
+
#
|
45
|
+
# @note the type of the object you pass in as the plaintext is crucially important.
|
46
|
+
# Different types of object are encoded incompatibly, and comparisons between
|
47
|
+
# ciphertexts generated from objects of different types is not guaranteed.
|
48
|
+
# For example, `#encrypt(-3.0) < #encrypt(1)` will not necessarily be true,
|
49
|
+
# even though `#encrypt(-3.0) < #encrypt(1.0)` is guaranteed.
|
50
|
+
#
|
51
|
+
# The currently supported types are:
|
52
|
+
#
|
53
|
+
# * `Integer` -- must be in the range 0..2**64-1 (inclusive). Will be encoded as
|
54
|
+
# an ORE `uint64`.
|
55
|
+
#
|
56
|
+
# * `Float` -- can be any double precision floating-point number, except for a NaN.
|
57
|
+
#
|
58
|
+
# * `String` -- any valid UTF-8 string. Will be hashed into a 64-bit value for storage.
|
59
|
+
#
|
60
|
+
# * `Range` -- a range of Integers, Floats, Dates, or Times; both ends must be of the
|
61
|
+
# same type. Indefinite beginnings *or* ends are supported, but not both.
|
62
|
+
#
|
63
|
+
# * `Date`, `Time` -- will be converted into milliseconds relative to the UTC epoch.
|
64
|
+
#
|
65
|
+
# @param plaintext [Integer, Float] the plaintext to encrypt.
|
66
|
+
#
|
67
|
+
# @raises [ArgumentError] if the type of the plaintext is not one currently supported,
|
68
|
+
# or the value of the plaintext is not one which is valid.
|
69
|
+
#
|
70
|
+
# @raises [RuntimeError] if a float is encrypted on a platform that doesn't use
|
71
|
+
# IEEE754 double-precision floating-point numbers as its representation of a
|
72
|
+
# `Float`, or if something spectacularly wrong happens in the ORE encryption process.
|
73
|
+
#
|
74
|
+
def encrypt(plaintext)
|
75
|
+
case plaintext
|
76
|
+
when Integer
|
77
|
+
encrypt_u64(plaintext)
|
78
|
+
when Float
|
79
|
+
encrypt_f64(plaintext)
|
80
|
+
when String
|
81
|
+
encrypt_string(plaintext)
|
82
|
+
when TrueClass, FalseClass
|
83
|
+
encrypt_bool(plaintext)
|
84
|
+
when Range
|
85
|
+
encrypt_range(plaintext)
|
86
|
+
when Date
|
87
|
+
encrypt(plaintext.to_time)
|
88
|
+
when Time
|
89
|
+
encrypt_time(plaintext)
|
90
|
+
else
|
91
|
+
raise ArgumentError, "Do not know how to ORE encrypt a #{plaintext.class}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class << self
|
96
|
+
private
|
97
|
+
|
98
|
+
def validate_key(k, name)
|
99
|
+
unless k.is_a?(String) && k.encoding == Encoding::BINARY && k.bytesize == 16
|
100
|
+
raise ArgumentError, "#{name} must be a 16 octet binary string"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def encrypt_u64(plaintext)
|
108
|
+
if plaintext < 0
|
109
|
+
raise ArgumentError, "Cannot encrypt integers less than zero"
|
110
|
+
end
|
111
|
+
|
112
|
+
if plaintext >= 2**64
|
113
|
+
raise ArgumentError, "Cannot encrypt integers greater than 2^64 - 1"
|
114
|
+
end
|
115
|
+
|
116
|
+
_encrypt_u64(plaintext)
|
117
|
+
end
|
118
|
+
|
119
|
+
def encrypt_f64(plaintext)
|
120
|
+
if Float::MAX_EXP != 1024 || Float::MIN_EXP != -1021
|
121
|
+
# This is a pure sanity check, so...
|
122
|
+
#:nocov:
|
123
|
+
raise RuntimeError, "This platform does not conform to our expectations for floating-point representations. Out of an abundance of caution, we will not encrypt floats on this platform."
|
124
|
+
#:nocov:
|
125
|
+
end
|
126
|
+
|
127
|
+
if plaintext.nan?
|
128
|
+
raise ArgumentError, "Cannot ORE encrypt NaN"
|
129
|
+
end
|
130
|
+
|
131
|
+
_encrypt_f64(plaintext)
|
132
|
+
end
|
133
|
+
|
134
|
+
def encrypt_string(plaintext)
|
135
|
+
unless VALID_STRING_ENCODINGS.include?(plaintext.encoding)
|
136
|
+
raise ArgumentError, "Cannot encrypt non-UTF-8 string"
|
137
|
+
end
|
138
|
+
|
139
|
+
if !plaintext.valid_encoding?
|
140
|
+
raise ArgumentError, "Cannot encrypt invalid UTF-8 string"
|
141
|
+
end
|
142
|
+
|
143
|
+
_encrypt_string(plaintext)
|
144
|
+
end
|
145
|
+
|
146
|
+
def encrypt_bool(plaintext)
|
147
|
+
_encrypt_bool(plaintext)
|
148
|
+
end
|
149
|
+
|
150
|
+
def encrypt_range(plaintext)
|
151
|
+
min, max = plaintext.begin, plaintext.end
|
152
|
+
|
153
|
+
case [min.class, max.class]
|
154
|
+
# Integer ranges
|
155
|
+
when [Integer, Integer]
|
156
|
+
if max < min
|
157
|
+
raise ArgumentError, "Cannot encrypt a non-ascending range"
|
158
|
+
end
|
159
|
+
(encrypt_u64(min)..encrypt_u64(max))
|
160
|
+
when [Integer, NilClass]
|
161
|
+
(encrypt_u64(min)..encrypt_u64(2**64-1))
|
162
|
+
when [NilClass, Integer]
|
163
|
+
(encrypt_u64(0)..encrypt_u64(max))
|
164
|
+
|
165
|
+
# Float ranges
|
166
|
+
when [Float, Float]
|
167
|
+
if max < min
|
168
|
+
raise ArgumentError, "Cannot encrypt a non-ascending range"
|
169
|
+
end
|
170
|
+
(encrypt_f64(min)..encrypt_f64(max))
|
171
|
+
when [Float, NilClass]
|
172
|
+
(encrypt_f64(min)..encrypt_f64(Float::INFINITY))
|
173
|
+
when [NilClass, Float]
|
174
|
+
(encrypt_f64(-Float::INFINITY)..encrypt_f64(max))
|
175
|
+
|
176
|
+
# Date ranges
|
177
|
+
when [Date, Date]
|
178
|
+
encrypt_range(min.to_time..max.to_time)
|
179
|
+
when [Date, NilClass]
|
180
|
+
encrypt_range(min.to_time..)
|
181
|
+
when [NilClass, Date]
|
182
|
+
encrypt_range(..max.to_time)
|
183
|
+
|
184
|
+
# Time ranges
|
185
|
+
when [Time, Time]
|
186
|
+
(encrypt_time(min)..encrypt_time(max))
|
187
|
+
when [Time, NilClass]
|
188
|
+
(encrypt_time(min)..encrypt_u64(2**64-1))
|
189
|
+
when [NilClass, Time]
|
190
|
+
(encrypt_u64(0)..encrypt_time(max))
|
191
|
+
|
192
|
+
else
|
193
|
+
raise ArgumentError, "Cannot encrypt a range over #{min.class}..#{max.class}"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def encrypt_time(plaintext)
|
198
|
+
# Get the time in integer milliseconds, and then "shift" it so
|
199
|
+
# that times before the epoch are still positive numbers, just
|
200
|
+
# smaller than times after the epoch
|
201
|
+
encrypt_u64((plaintext.to_r * 1000).to_i + 2**63)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
data/lib/ore/version.rb
ADDED
data/lib/ore-rs.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module ORE
|
2
|
+
end
|
3
|
+
|
4
|
+
begin
|
5
|
+
RUBY_VERSION =~ /(\d+\.\d+)/
|
6
|
+
require_relative "./#{$1}/ore_rs"
|
7
|
+
rescue LoadError
|
8
|
+
begin
|
9
|
+
require_relative "./ore_rs"
|
10
|
+
rescue LoadError
|
11
|
+
raise LoadError, "Could not load ore_rs binary library"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
require_relative "./ore/aes128"
|
data/ore-rs.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative './lib/ore/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "ore-rs"
|
5
|
+
|
6
|
+
s.version = ORE::VERSION
|
7
|
+
s.date = Time.now.strftime("%Y-%m-%d")
|
8
|
+
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
|
11
|
+
s.summary = "Ruby bindings for the ore.rs Order-Revealing Encryption library"
|
12
|
+
|
13
|
+
s.authors = ["James Sadler", "Bennett Hardwick", "Drew Thomas"]
|
14
|
+
s.email = ["james@cipherstash.com", "bennett@cipherstash.com", "drew@cipherstash.com"]
|
15
|
+
s.homepage = "https://cipherstash.com/protect"
|
16
|
+
|
17
|
+
s.files = `git ls-files -z`.split("\0").reject { |f| f =~ /^(\.|G|spec|Rakefile)/ }
|
18
|
+
|
19
|
+
s.extensions = ["ext/ore_rs/extconf.rb"]
|
20
|
+
|
21
|
+
s.required_ruby_version = ">= 2.7.0"
|
22
|
+
|
23
|
+
s.metadata["homepage_uri"] = s.homepage
|
24
|
+
s.metadata["source_code_uri"] = "https://github.com/cipherstash/ruby-ore-rs"
|
25
|
+
s.metadata["changelog_uri"] = "https://github.com/cipherstash/ruby-ore-rs/releases"
|
26
|
+
s.metadata["bug_tracker_uri"] = "https://github.com/cipherstash/ruby-ore-rs/issues"
|
27
|
+
s.metadata["documentation_uri"] = "https://rubydoc.info/gems/ore-rs"
|
28
|
+
s.metadata["mailing_list_uri"] = "https://discuss.cipherstash.com"
|
29
|
+
|
30
|
+
s.add_runtime_dependency 'rb_sys', '~> 0.1'
|
31
|
+
|
32
|
+
s.add_development_dependency 'bundler'
|
33
|
+
s.add_development_dependency 'guard-rspec'
|
34
|
+
s.add_development_dependency 'rake', '~> 13.0'
|
35
|
+
s.add_development_dependency 'rake-compiler', '~> 1.2'
|
36
|
+
s.add_development_dependency 'rake-compiler-dock', '~> 1.2'
|
37
|
+
s.add_development_dependency 'rb-inotify', '~> 0.9'
|
38
|
+
s.add_development_dependency 'rb_sys', '~> 0.1'
|
39
|
+
s.add_development_dependency 'redcarpet'
|
40
|
+
s.add_development_dependency 'rspec'
|
41
|
+
s.add_development_dependency 'simplecov'
|
42
|
+
s.add_development_dependency 'yard'
|
43
|
+
end
|