ope-rb 0.0.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.
- data/ext/ope/extconf.rb +6 -0
- data/ext/ope/native.c +311 -0
- data/lib/ope-rb.rb +155 -0
- data/lib/ope-rb/crypto.rb +33 -0
- data/lib/ope-rb/errors.rb +55 -0
- data/lib/ope-rb/hgd.rb +267 -0
- data/lib/ope-rb/prng.rb +21 -0
- data/lib/ope-rb/version.rb +5 -0
- metadata +86 -0
data/ext/ope/extconf.rb
ADDED
data/ext/ope/native.c
ADDED
@@ -0,0 +1,311 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <math.h>
|
3
|
+
#include <openssl/rand.h>
|
4
|
+
|
5
|
+
/*
|
6
|
+
* Helper methods from Mathlib : A C Library of Special Functions
|
7
|
+
* Copyright (C) 2005 The R Foundation, released under the GPL.
|
8
|
+
*/
|
9
|
+
static double afc(int i)
|
10
|
+
{
|
11
|
+
static const double al[9] =
|
12
|
+
{
|
13
|
+
0.0,
|
14
|
+
0.0,/*ln(0!)=ln(1)*/
|
15
|
+
0.0,/*ln(1!)=ln(1)*/
|
16
|
+
0.69314718055994530941723212145817,/*ln(2) */
|
17
|
+
1.79175946922805500081247735838070,/*ln(6) */
|
18
|
+
3.17805383034794561964694160129705,/*ln(24)*/
|
19
|
+
4.78749174278204599424770093452324,
|
20
|
+
6.57925121201010099506017829290394,
|
21
|
+
8.52516136106541430016553103634712
|
22
|
+
/*, 10.60460290274525022841722740072165*/
|
23
|
+
};
|
24
|
+
double di, value;
|
25
|
+
|
26
|
+
if (i < 0) {
|
27
|
+
printf(("rhyper.c: afc(i), i=%d < 0 -- SHOULD NOT HAPPEN!\n"),
|
28
|
+
i);
|
29
|
+
return -1;/* unreached (Wall) */
|
30
|
+
} else if (i <= 7) {
|
31
|
+
value = al[i + 1];
|
32
|
+
} else {
|
33
|
+
di = i;
|
34
|
+
value = (di + 0.5) * log(di) - di + 0.08333333333333 / di
|
35
|
+
- 0.00277777777777 / di / di / di + 0.9189385332;
|
36
|
+
}
|
37
|
+
return value;
|
38
|
+
}
|
39
|
+
|
40
|
+
static int imax2(int x, int y) {
|
41
|
+
return (x < y) ? y : x;
|
42
|
+
}
|
43
|
+
|
44
|
+
static int imin2(int x, int y) {
|
45
|
+
return (x < y) ? x : y;
|
46
|
+
}
|
47
|
+
|
48
|
+
static VALUE ope_rb;
|
49
|
+
static VALUE ope_rb_hgd;
|
50
|
+
|
51
|
+
static VALUE ope_rb_rhyper(VALUE self, VALUE rbNn1in, VALUE rbNn2in, VALUE rbKkin, VALUE rbSeed) {
|
52
|
+
|
53
|
+
double nn1in, nn2in, kkin;
|
54
|
+
|
55
|
+
static const double con = 57.56462733;
|
56
|
+
static const double deltal = 0.0078;
|
57
|
+
static const double deltau = 0.0034;
|
58
|
+
static const double scale = 1e25;
|
59
|
+
|
60
|
+
int nn1, nn2, kk;
|
61
|
+
int i, ix;
|
62
|
+
int reject, setup1, setup2;
|
63
|
+
|
64
|
+
double e, f, g, p, r, t, u, v, y;
|
65
|
+
double de, dg, dr, ds, dt, gl, gu, nk, nm, ub;
|
66
|
+
double xk, xm, xn, y1, ym, yn, yk, alv;
|
67
|
+
|
68
|
+
static int ks = -1;
|
69
|
+
static int n1s = -1, n2s = -1;
|
70
|
+
|
71
|
+
static int k, m;
|
72
|
+
static int minjx, maxjx, n1, n2;
|
73
|
+
|
74
|
+
static double a, d, s, w;
|
75
|
+
static double tn, xl, xr, kl, kr, lamdl, lamdr, p1, p2, p3;
|
76
|
+
|
77
|
+
unsigned char* seed;
|
78
|
+
int seedLen;
|
79
|
+
|
80
|
+
nn1in = NUM2DBL(rbNn1in);
|
81
|
+
nn2in = NUM2DBL(rbNn2in);
|
82
|
+
kkin = NUM2DBL(rbKkin);
|
83
|
+
|
84
|
+
StringValue(rbSeed);
|
85
|
+
seed = (unsigned char*) RSTRING_PTR(rbSeed);
|
86
|
+
seedLen = RSTRING_LEN(rbSeed);
|
87
|
+
RAND_seed(seed, seedLen);
|
88
|
+
|
89
|
+
if(!isfinite(nn1in) || !isfinite(nn2in) || !isfinite(kkin))
|
90
|
+
return -1;
|
91
|
+
|
92
|
+
nn1 = (int) nn1in;
|
93
|
+
nn2 = (int) nn2in;
|
94
|
+
kk = (int) kkin;
|
95
|
+
|
96
|
+
if (nn1 < 0 || nn2 < 0 || kk < 0 || kk > nn1 + nn2) {
|
97
|
+
//rb_raise(rb_eRuntimeError, 'Incorrect arguments to HGD');
|
98
|
+
return INT2NUM(-2);
|
99
|
+
}
|
100
|
+
|
101
|
+
reject = 1;
|
102
|
+
if (nn1 != n1s || nn2 != n2s) {
|
103
|
+
setup1 = 1; setup2 = 1;
|
104
|
+
} else if (kk != ks) {
|
105
|
+
setup1 = 0; setup2 = 1;
|
106
|
+
} else {
|
107
|
+
setup1 = 0; setup2 = 0;
|
108
|
+
}
|
109
|
+
if (setup1) {
|
110
|
+
n1s = nn1;
|
111
|
+
n2s = nn2;
|
112
|
+
tn = nn1 + nn2;
|
113
|
+
if (nn1 <= nn2) {
|
114
|
+
n1 = nn1;
|
115
|
+
n2 = nn2;
|
116
|
+
} else {
|
117
|
+
n1 = nn2;
|
118
|
+
n2 = nn1;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
if (setup2) {
|
122
|
+
ks = kk;
|
123
|
+
if (kk + kk >= tn) {
|
124
|
+
k = (int)(tn - kk);
|
125
|
+
} else {
|
126
|
+
k = kk;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
if (setup1 || setup2) {
|
130
|
+
m = (int) ((k + 1.0) * (n1 + 1.0) / (tn + 2.0));
|
131
|
+
minjx = imax2(0, k - n2);
|
132
|
+
maxjx = imin2(n1, k);
|
133
|
+
}
|
134
|
+
|
135
|
+
if (minjx == maxjx) {
|
136
|
+
ix = maxjx;
|
137
|
+
|
138
|
+
if (kk + kk >= tn) {
|
139
|
+
if (nn1 > nn2) {
|
140
|
+
ix = kk - nn2 + ix;
|
141
|
+
} else {
|
142
|
+
ix = nn1 - ix;
|
143
|
+
}
|
144
|
+
} else {
|
145
|
+
if (nn1 > nn2)
|
146
|
+
ix = kk - ix;
|
147
|
+
}
|
148
|
+
|
149
|
+
return DBL2NUM(ix);
|
150
|
+
|
151
|
+
} else if (m - minjx < 10) {
|
152
|
+
if (setup1 || setup2) {
|
153
|
+
if (k < n2) {
|
154
|
+
w = exp(con + afc(n2) + afc(n1 + n2 - k)
|
155
|
+
- afc(n2 - k) - afc(n1 + n2));
|
156
|
+
} else {
|
157
|
+
w = exp(con + afc(n1) + afc(k)
|
158
|
+
- afc(k - n2) - afc(n1 + n2));
|
159
|
+
}
|
160
|
+
}
|
161
|
+
L10:
|
162
|
+
p = w;
|
163
|
+
ix = minjx;
|
164
|
+
u = unif_rand(seed, seedLen) * scale;
|
165
|
+
L20:
|
166
|
+
if (u > p) {
|
167
|
+
u -= p;
|
168
|
+
p *= (n1 - ix) * (k - ix);
|
169
|
+
ix++;
|
170
|
+
p = p / ix / (n2 - k + ix);
|
171
|
+
if (ix > maxjx)
|
172
|
+
goto L10;
|
173
|
+
goto L20;
|
174
|
+
}
|
175
|
+
} else {
|
176
|
+
|
177
|
+
if (setup1 || setup2) {
|
178
|
+
s = sqrt((tn - k) * k * n1 * n2 / (tn - 1) / tn / tn);
|
179
|
+
|
180
|
+
d = (int) (1.5 * s) + .5;
|
181
|
+
xl = m - d + .5;
|
182
|
+
xr = m + d + .5;
|
183
|
+
a = afc(m) + afc(n1 - m) + afc(k - m) + afc(n2 - k + m);
|
184
|
+
kl = exp(a - afc((int) (xl)) - afc((int) (n1 - xl))
|
185
|
+
- afc((int) (k - xl))
|
186
|
+
- afc((int) (n2 - k + xl)));
|
187
|
+
kr = exp(a - afc((int) (xr - 1))
|
188
|
+
- afc((int) (n1 - xr + 1))
|
189
|
+
- afc((int) (k - xr + 1))
|
190
|
+
- afc((int) (n2 - k + xr - 1)));
|
191
|
+
lamdl = -log(xl * (n2 - k + xl) / (n1 - xl + 1) / (k - xl + 1));
|
192
|
+
lamdr = -log((n1 - xr + 1) * (k - xr + 1) / xr / (n2 - k + xr));
|
193
|
+
p1 = d + d;
|
194
|
+
p2 = p1 + kl / lamdl;
|
195
|
+
p3 = p2 + kr / lamdr;
|
196
|
+
}
|
197
|
+
L30:
|
198
|
+
u = unif_rand(seed, seedLen) * p3;
|
199
|
+
v = unif_rand(seed, seedLen);
|
200
|
+
if (u < p1) {
|
201
|
+
ix = (int) (xl + u);
|
202
|
+
} else if (u <= p2) {
|
203
|
+
ix = (int) (xl + log(v) / lamdl);
|
204
|
+
if (ix < minjx)
|
205
|
+
goto L30;
|
206
|
+
v = v * (u - p1) * lamdl;
|
207
|
+
} else {
|
208
|
+
ix = (int) (xr - log(v) / lamdr);
|
209
|
+
if (ix > maxjx)
|
210
|
+
goto L30;
|
211
|
+
v = v * (u - p2) * lamdr;
|
212
|
+
}
|
213
|
+
|
214
|
+
if (m < 100 || ix <= 50) {
|
215
|
+
f = 1.0;
|
216
|
+
if (m < ix) {
|
217
|
+
for (i = m + 1; i <= ix; i++)
|
218
|
+
f = f * (n1 - i + 1) * (k - i + 1) / (n2 - k + i) / i;
|
219
|
+
} else if (m > ix) {
|
220
|
+
for (i = ix + 1; i <= m; i++)
|
221
|
+
f = f * i * (n2 - k + i) / (n1 - i + 1) / (k - i + 1);
|
222
|
+
}
|
223
|
+
if (v <= f) {
|
224
|
+
reject = 0;
|
225
|
+
}
|
226
|
+
} else {
|
227
|
+
/* squeeze using upper and lower bounds */
|
228
|
+
y = ix;
|
229
|
+
y1 = y + 1.0;
|
230
|
+
ym = y - m;
|
231
|
+
yn = n1 - y + 1.0;
|
232
|
+
yk = k - y + 1.0;
|
233
|
+
nk = n2 - k + y1;
|
234
|
+
r = -ym / y1;
|
235
|
+
s = ym / yn;
|
236
|
+
t = ym / yk;
|
237
|
+
e = -ym / nk;
|
238
|
+
g = yn * yk / (y1 * nk) - 1.0;
|
239
|
+
dg = 1.0;
|
240
|
+
if (g < 0.0)
|
241
|
+
dg = 1.0 + g;
|
242
|
+
gu = g * (1.0 + g * (-0.5 + g / 3.0));
|
243
|
+
gl = gu - .25 * (g * g * g * g) / dg;
|
244
|
+
xm = m + 0.5;
|
245
|
+
xn = n1 - m + 0.5;
|
246
|
+
xk = k - m + 0.5;
|
247
|
+
nm = n2 - k + xm;
|
248
|
+
ub = y * gu - m * gl + deltau
|
249
|
+
+ xm * r * (1. + r * (-0.5 + r / 3.0))
|
250
|
+
+ xn * s * (1. + s * (-0.5 + s / 3.0))
|
251
|
+
+ xk * t * (1. + t * (-0.5 + t / 3.0))
|
252
|
+
+ nm * e * (1. + e * (-0.5 + e / 3.0));
|
253
|
+
alv = log(v);
|
254
|
+
if (alv > ub) {
|
255
|
+
reject = 1;
|
256
|
+
} else {
|
257
|
+
dr = xm * (r * r * r * r);
|
258
|
+
if (r < 0.0)
|
259
|
+
dr /= (1.0 + r);
|
260
|
+
ds = xn * (s * s * s * s);
|
261
|
+
if (s < 0.0)
|
262
|
+
ds /= (1.0 + s);
|
263
|
+
dt = xk * (t * t * t * t);
|
264
|
+
if (t < 0.0)
|
265
|
+
dt /= (1.0 + t);
|
266
|
+
de = nm * (e * e * e * e);
|
267
|
+
if (e < 0.0)
|
268
|
+
de /= (1.0 + e);
|
269
|
+
if (alv < ub - 0.25 * (dr + ds + dt + de)
|
270
|
+
+ (y + m) * (gl - gu) - deltal) {
|
271
|
+
reject = 0;
|
272
|
+
}
|
273
|
+
else {
|
274
|
+
if (alv <= (a - afc(ix) - afc(n1 - ix)
|
275
|
+
- afc(k - ix) - afc(n2 - k + ix))) {
|
276
|
+
reject = 0;
|
277
|
+
} else {
|
278
|
+
reject = 1;
|
279
|
+
}
|
280
|
+
}
|
281
|
+
}
|
282
|
+
}
|
283
|
+
if (reject)
|
284
|
+
goto L30;
|
285
|
+
}
|
286
|
+
|
287
|
+
if (kk + kk >= tn) {
|
288
|
+
if (nn1 > nn2) {
|
289
|
+
ix = kk - nn2 + ix;
|
290
|
+
} else {
|
291
|
+
ix = nn1 - ix;
|
292
|
+
}
|
293
|
+
} else {
|
294
|
+
if (nn1 > nn2)
|
295
|
+
ix = kk - ix;
|
296
|
+
}
|
297
|
+
|
298
|
+
return DBL2NUM(ix);
|
299
|
+
|
300
|
+
}
|
301
|
+
|
302
|
+
void Init_native(void) {
|
303
|
+
|
304
|
+
ope_rb = rb_define_module("OPE");
|
305
|
+
|
306
|
+
ope_rb_hgd = rb_define_class_under(ope_rb, "HGD", rb_cObject);
|
307
|
+
rb_define_singleton_method(ope_rb_hgd, "rhyper_native", ope_rb_rhyper, 4);
|
308
|
+
|
309
|
+
return;
|
310
|
+
|
311
|
+
}
|
data/lib/ope-rb.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'ope-rb/native'
|
2
|
+
require 'ope-rb/version'
|
3
|
+
require 'ope-rb/prng'
|
4
|
+
require 'ope-rb/hgd'
|
5
|
+
require 'ope-rb/crypto'
|
6
|
+
require 'ope-rb/errors'
|
7
|
+
|
8
|
+
module OPE
|
9
|
+
|
10
|
+
class Cipher
|
11
|
+
|
12
|
+
OPE_KEY_SIZE = 128
|
13
|
+
|
14
|
+
include Crypto
|
15
|
+
|
16
|
+
def initialize(key, pt_len = 8, ct_len = 16)
|
17
|
+
|
18
|
+
check_key_size(key)
|
19
|
+
|
20
|
+
@key, @pt_len, @ct_len =
|
21
|
+
key, pt_len * 8, ct_len * 8
|
22
|
+
|
23
|
+
create_cipher
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_key_size(key)
|
28
|
+
|
29
|
+
valid = key.bytesize * 8 == OPE_KEY_SIZE
|
30
|
+
raise Errors::KeySizeError unless valid
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def sample_hgd(lo_d, hi_d, lo_r, hi_r, y, coins)
|
35
|
+
|
36
|
+
wb, bp = hi_d - lo_d + 1, y - lo_r
|
37
|
+
bb = hi_r - lo_r + 1 - wb
|
38
|
+
|
39
|
+
unless wb > 0 && bb >= 0 && y >= lo_r && y <= hi_r
|
40
|
+
raise Errors::HGDParameterError
|
41
|
+
end
|
42
|
+
|
43
|
+
prec = (hi_r - lo_r + 1).size * 8 + 10
|
44
|
+
|
45
|
+
lo_d + HGD.rhyper(bp, wb, bb, coins, prec)
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def tape_gen(lo_d, hi_d, y, desired_no_bits)
|
50
|
+
|
51
|
+
if desired_no_bits % 8 != 0
|
52
|
+
raise Errors::NumBitsError
|
53
|
+
elsif (desired_bytes = desired_no_bits / 8) > 16
|
54
|
+
raise Errors::DesiredBytesError
|
55
|
+
end
|
56
|
+
|
57
|
+
digest = hash_concat(lo_d, hi_d, y)
|
58
|
+
seed = get_seed(digest, desired_bytes)
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
def encrypt(m)
|
63
|
+
|
64
|
+
lo_d, hi_d = 0, (1 << @pt_len) - 1
|
65
|
+
lo_r, hi_r = 0, (1 << @ct_len) - 1
|
66
|
+
|
67
|
+
encrypt_recurse(lo_d, hi_d, lo_r, hi_r, m)
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
def decrypt(m)
|
72
|
+
|
73
|
+
lo_d, hi_d = 0, (1 << @pt_len) - 1
|
74
|
+
lo_r, hi_r = 0, (1 << @ct_len) - 1
|
75
|
+
|
76
|
+
decrypt_recurse(lo_d, hi_d, lo_r, hi_r, m)
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def get_seed(digest, desired_bytes)
|
83
|
+
|
84
|
+
# Encrypt the hash using the cipher
|
85
|
+
seed = cipher_encrypt(digest)
|
86
|
+
|
87
|
+
# Take only the desired no of bytes
|
88
|
+
seed = seed.byteslice(0, desired_bytes)
|
89
|
+
|
90
|
+
# Convert the seed to a Bignum
|
91
|
+
seed.unpack('H*')[0].hex
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
def encrypt_recurse(lo_d, hi_d, lo_r, hi_r, m)
|
96
|
+
|
97
|
+
m2, n = hi_d - lo_d + 1, hi_r - lo_r + 1
|
98
|
+
d, r = lo_d - 1, lo_r - 1; y = r + (n + 1) / 2
|
99
|
+
|
100
|
+
raise Errors::IncorrectMValueError unless m2 > 0
|
101
|
+
|
102
|
+
coins = nil
|
103
|
+
|
104
|
+
if m2 == 1
|
105
|
+
|
106
|
+
coins = tape_gen(lo_d, hi_d, m, @ct_len)
|
107
|
+
return lo_r + (coins % n)
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
coins = tape_gen(lo_d, hi_d, y, @pt_len)
|
112
|
+
|
113
|
+
x = sample_hgd(lo_d, hi_d, lo_r, hi_r, y, coins)
|
114
|
+
|
115
|
+
lo_d, hi_d = *((m <= x) ? [d + 1, x] : [x + 1, d + m2])
|
116
|
+
lo_r, hi_r = *((m <= x) ? [r + 1, y] : [y + 1, r + n])
|
117
|
+
|
118
|
+
encrypt_recurse(lo_d, hi_d, lo_r, hi_r, m)
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
def decrypt_recurse(lo_d, hi_d, lo_r, hi_r, c)
|
123
|
+
|
124
|
+
m2, n = hi_d - lo_d + 1, hi_r - lo_r + 1
|
125
|
+
d, r = lo_d - 1, lo_r - 1; y = r + (n + 1) / 2
|
126
|
+
|
127
|
+
raise Errors::IncorrectMValueError unless m2 > 0
|
128
|
+
|
129
|
+
if m2 == 1
|
130
|
+
|
131
|
+
m = lo_d.to_i
|
132
|
+
|
133
|
+
coins = tape_gen(lo_d, hi_d, m, @ct_len)
|
134
|
+
w = lo_r + coins % n
|
135
|
+
|
136
|
+
return m.to_i if w == c
|
137
|
+
|
138
|
+
raise Errors::BadDecryptError
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
coins = tape_gen(lo_d, hi_d, y, @pt_len)
|
143
|
+
|
144
|
+
x = sample_hgd(lo_d, hi_d, lo_r, hi_r, y, coins)
|
145
|
+
|
146
|
+
lo_d, hi_d = *((c <= y) ? [d + 1, x] : [x + 1, d + m2])
|
147
|
+
lo_r, hi_r = *((c <= y) ? [r + 1, y] : [y + 1, r + n])
|
148
|
+
|
149
|
+
decrypt_recurse(lo_d, hi_d, lo_r, hi_r, c)
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module OPE
|
2
|
+
|
3
|
+
module Crypto
|
4
|
+
|
5
|
+
def hash_concat(*args)
|
6
|
+
|
7
|
+
lens = args.map { |arg| [1].pack("L") }
|
8
|
+
hash((lens + args).join(''))
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
def hash(data)
|
13
|
+
|
14
|
+
OpenSSL::Digest::SHA256.digest(data)
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_cipher
|
19
|
+
|
20
|
+
@cipher = OpenSSL::Cipher::AES.new(128, :ECB)
|
21
|
+
@cipher.encrypt; @cipher.key = @key
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def cipher_encrypt(data)
|
26
|
+
|
27
|
+
@cipher.update(data) + @cipher.final
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module OPE
|
2
|
+
|
3
|
+
module Errors
|
4
|
+
|
5
|
+
class KeySizeError < StandardError
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
super('Incorrect key size')
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class HGDParameterError < StandardError
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
super('Corrupt HGD parameters')
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class NumBitsError < StandardError
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
super('Desired no bits not a multiple of 8')
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
class DesiredBytesError < StandardError
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
super('Only 64-bit output is supported for now')
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
class IncorrectMValueError < StandardError
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
super('M should not be less than or equal to 0')
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
class BadDecryptError < StandardError
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
super('Decryption failed')
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/lib/ope-rb/hgd.rb
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
module OPE
|
2
|
+
|
3
|
+
class HGD
|
4
|
+
|
5
|
+
# Random variates from the hypergeometric distribution.
|
6
|
+
#
|
7
|
+
# Returns the number of white balls drawn when kk balls
|
8
|
+
# are drawn at random from an urn containing nn1 white
|
9
|
+
# and nn2 black balls.
|
10
|
+
def self.rhyper(kk, nn1, nn2, coins, precision)
|
11
|
+
|
12
|
+
ix = nil
|
13
|
+
|
14
|
+
prng = PRNG.new(coins)
|
15
|
+
|
16
|
+
con, deltal = 57.56462733, 0.0078
|
17
|
+
deltau, scale = 0.0034, 1.0e25
|
18
|
+
|
19
|
+
# Check validity of parameters.
|
20
|
+
if [nn1, nn2, kk].include?(Float::INFINITY) ||
|
21
|
+
(nn1 < 0 || nn2 < 0 || kk < 0 || kk > (nn1 + nn2))
|
22
|
+
raise 'Invalid parameters nn1, nn2 or kk'
|
23
|
+
end
|
24
|
+
|
25
|
+
reject = true
|
26
|
+
|
27
|
+
if nn1 >= nn2
|
28
|
+
n1, n2 = nn2.to_f, nn1.to_f
|
29
|
+
else
|
30
|
+
n1, n2 = nn1.to_f, nn2.to_f
|
31
|
+
end
|
32
|
+
|
33
|
+
tn = n1 + n2
|
34
|
+
|
35
|
+
if kk + kk >= tn
|
36
|
+
k = tn - kk
|
37
|
+
else
|
38
|
+
k = kk
|
39
|
+
end
|
40
|
+
|
41
|
+
m = (k+1.0) * (n1+1.0) / (tn+2.0)
|
42
|
+
|
43
|
+
minjx = (k - n2 < 0) ? 0 : k - n2
|
44
|
+
maxjx = (n1 < k) ? n1 : k
|
45
|
+
|
46
|
+
# Degenerate distribution
|
47
|
+
if minjx == maxjx
|
48
|
+
|
49
|
+
# no, need to untangle TSL
|
50
|
+
return maxjx.floor.to_f
|
51
|
+
|
52
|
+
# Inverse transformation
|
53
|
+
elsif m-minjx < 10
|
54
|
+
|
55
|
+
w = nil
|
56
|
+
|
57
|
+
if k < n2
|
58
|
+
w = Math.exp(con + afc(n2) + afc(n1+n2-k)-afc(n2-k)-afc(n1+n2))
|
59
|
+
else
|
60
|
+
w = Math.exp(con + afc(n1) + afc(k) + afc(k-n2) -afc(n1+n2))
|
61
|
+
end
|
62
|
+
|
63
|
+
catch :l10 do
|
64
|
+
|
65
|
+
p = w
|
66
|
+
ix = minjx
|
67
|
+
u = prng.draw * scale
|
68
|
+
|
69
|
+
catch :l20 do
|
70
|
+
|
71
|
+
if u > p
|
72
|
+
u = u - p
|
73
|
+
p = p * (n1-ix)*(k-ix)
|
74
|
+
ix = ix + 1
|
75
|
+
p = p / ix / (n2-k+ix)
|
76
|
+
throw :l10 if ix > maxjx
|
77
|
+
throw :l20
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
# Hypergeometrics-2 points-exponential tails
|
85
|
+
else
|
86
|
+
|
87
|
+
s = Math.sqrt( (tn-k) * k * n1 * n2 / (tn - 1.0) / tn / tn)
|
88
|
+
|
89
|
+
# Truncation centers cell boundaries at 0.5
|
90
|
+
d = (1.5 * s).floor.to_f + 0.5
|
91
|
+
xl = m - d + 0.5
|
92
|
+
xr = m + d + 0.5
|
93
|
+
a = afc(m) + afc(n1-m) +
|
94
|
+
afc(k-m) + afc(n2-k+m)
|
95
|
+
|
96
|
+
expon = a - afc(xl) -
|
97
|
+
afc(n1 - xl) - afc(k - xl) -
|
98
|
+
afc(n2 - k + xl)
|
99
|
+
|
100
|
+
kl = Math.exp(expon)
|
101
|
+
|
102
|
+
kr = Math.exp(a - afc(xr-1) -
|
103
|
+
afc(n1-xr+1) - afc(k-xr+1) -
|
104
|
+
afc(n2-k+xr-1))
|
105
|
+
|
106
|
+
lamdl = -Math.log(xl *
|
107
|
+
(n2 - k + xl) / (n1 - xl + 1) / (k - xl + 1))
|
108
|
+
|
109
|
+
lamdr = -Math.log(
|
110
|
+
(n1 - xr + 1) * (k -xr + 1) / xr / (n2 - k + xr))
|
111
|
+
|
112
|
+
p1 = 2 * d
|
113
|
+
p2 = p1 + kl / lamdl
|
114
|
+
p3 = p2 + kr / lamdr
|
115
|
+
|
116
|
+
count_30 = 0
|
117
|
+
|
118
|
+
catch :count do
|
119
|
+
|
120
|
+
count_30 += 1
|
121
|
+
|
122
|
+
u = prng.draw * p3
|
123
|
+
v = prng.draw
|
124
|
+
|
125
|
+
# Rectangular region
|
126
|
+
if u < p1
|
127
|
+
ix = xl + u
|
128
|
+
# Left tail region
|
129
|
+
elsif u <= p2
|
130
|
+
ix = xl + Math.log(v) / lamdl
|
131
|
+
throw :count if ix < minjx
|
132
|
+
v = v * (u - p1) * lamdl
|
133
|
+
# Right tail region
|
134
|
+
else
|
135
|
+
ix = xr - Math.log(v) / lamdr
|
136
|
+
throw :count if ix > maxjx
|
137
|
+
v = v * (u - p2) * lamdr
|
138
|
+
end
|
139
|
+
|
140
|
+
f = nil
|
141
|
+
|
142
|
+
if m < 100 || ix <= 50
|
143
|
+
|
144
|
+
f = 1
|
145
|
+
|
146
|
+
if m < ix
|
147
|
+
|
148
|
+
i = m + 1
|
149
|
+
|
150
|
+
while i < ix # <= ?
|
151
|
+
|
152
|
+
f = f * (n1 - i + 1.0) *
|
153
|
+
(k - i + 1.0) /
|
154
|
+
(n2 - k + i) / i
|
155
|
+
i += 1
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
elsif m > ix
|
160
|
+
|
161
|
+
i = ix + 1
|
162
|
+
|
163
|
+
while i < m # <= ?
|
164
|
+
|
165
|
+
f = f * i * (n2 - k + i) /
|
166
|
+
(n1 - i) / (k - i) # + 1 ?
|
167
|
+
i += 1
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
reject = false if v <= f
|
174
|
+
|
175
|
+
else
|
176
|
+
|
177
|
+
y = ix; y1 = y + 1.0; ym = y - m
|
178
|
+
yn = n1 - y + 1.0; yk = k - y + 1.0
|
179
|
+
nk = n2 - k + y1; r = -ym / y1
|
180
|
+
s2 = ym / yn; t = ym / yk; e = -ym / nk
|
181
|
+
g = yn * yk / (y1 * nk) - 1.0
|
182
|
+
dg = 1.0; dg = 1.0 + g if g < 0
|
183
|
+
gu = g * (1.0 + g * (-0.5 + g / 3.0))
|
184
|
+
gl = gu - 0.25 * (g * g * g * g) / dg
|
185
|
+
xm = m + 0.5; xn = n1 - m + 0.5
|
186
|
+
xk = k - m + 0.5; nm = n2 - k + xm
|
187
|
+
|
188
|
+
ub = y * gu - m * gl + deltau + xm *
|
189
|
+
r * (1 + r * (-0.5 + r / 3)) +
|
190
|
+
xn * s2 * (1.0 + s2 * (-0.5 + s2 / 3.0)) +
|
191
|
+
xk * t * (1.0 + t * (-0.5 + t / 3.0)) +
|
192
|
+
nm * e * (1.0 + e * (-0.5 + e / 3.0))
|
193
|
+
|
194
|
+
alv = Math.log(v)
|
195
|
+
|
196
|
+
if alv > ub
|
197
|
+
reject = true
|
198
|
+
else
|
199
|
+
|
200
|
+
dr = xm * (r * r * r * r)
|
201
|
+
dr /= (1.0 + r) if r < 0
|
202
|
+
ds = xn * (s2 * s2 * s2 * s2)
|
203
|
+
ds /= (1.0 + s2) if s2 < 0
|
204
|
+
dt = xk * (t * t * t * t)
|
205
|
+
dt /= (1.0 + t) if t < 0
|
206
|
+
de = nm * (e * e * e * e)
|
207
|
+
de /= (1.0 + e) if e < 0
|
208
|
+
|
209
|
+
|
210
|
+
cand = ub - 0.25 * (dr + ds + dt + de) +
|
211
|
+
(y + m) * (gl - gu) - deltal
|
212
|
+
|
213
|
+
if alv < cand
|
214
|
+
reject = false
|
215
|
+
else
|
216
|
+
|
217
|
+
|
218
|
+
cand = a - afc(ix) - afc(n1 - ix) -
|
219
|
+
afc(k - ix) - afc(n2 - k + ix)
|
220
|
+
|
221
|
+
reject = alv > cand
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
throw :count if reject
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
if kk + kk >= tn
|
236
|
+
if nn1 > nn2
|
237
|
+
ix = kk - nn2 + ix
|
238
|
+
else
|
239
|
+
ix = nn1 - ix
|
240
|
+
end
|
241
|
+
else
|
242
|
+
ix = kk - ix if nn1 > nn2
|
243
|
+
end
|
244
|
+
|
245
|
+
jx = ix
|
246
|
+
|
247
|
+
return jx.floor.to_f
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
# Calculates logarithm of i factorial: ln(i!)
|
252
|
+
# Uses Stirling's approximation to do so.
|
253
|
+
def self.afc(i)
|
254
|
+
|
255
|
+
raise 'i should not be < 0' if i < 0
|
256
|
+
|
257
|
+
frac_12, frac_360 = 1.0 / 12.0, 1.0 / 360.0
|
258
|
+
frac_pi = 0.5 * Math.log(2 * Math::PI)
|
259
|
+
|
260
|
+
(i + 0.5) * Math.log(i) - i + frac_12 /
|
261
|
+
i - frac_360 / i / i / i + frac_pi
|
262
|
+
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
data/lib/ope-rb/prng.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module OPE
|
2
|
+
|
3
|
+
class PRNG
|
4
|
+
|
5
|
+
require 'bigdecimal'
|
6
|
+
require 'drbg-rb'
|
7
|
+
|
8
|
+
def initialize(coin)
|
9
|
+
coin = coin.to_s
|
10
|
+
coin += '0' while coin.bytesize < 24
|
11
|
+
@prng = DRBG::HMAC.new(coin, 128)
|
12
|
+
end
|
13
|
+
|
14
|
+
def draw
|
15
|
+
n = @prng.generate(4, 128).unpack('H*')[0]
|
16
|
+
n.byteslice(0, 8).hex.to_f / 2**32
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ope-rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Louis Mullie
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-05-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.12.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.12.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: ! ' '
|
47
|
+
email:
|
48
|
+
- louis.mullie@gmail.com
|
49
|
+
executables: []
|
50
|
+
extensions:
|
51
|
+
- ext/ope/extconf.rb
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- lib/ope-rb/crypto.rb
|
55
|
+
- lib/ope-rb/errors.rb
|
56
|
+
- lib/ope-rb/hgd.rb
|
57
|
+
- lib/ope-rb/prng.rb
|
58
|
+
- lib/ope-rb/version.rb
|
59
|
+
- lib/ope-rb.rb
|
60
|
+
- ext/ope/native.c
|
61
|
+
- ext/ope/extconf.rb
|
62
|
+
homepage: https://github.com/cryodex/ope-rb
|
63
|
+
licenses: []
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.8.25
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: A Ruby implementation of order-preserving encryption
|
86
|
+
test_files: []
|