ope-rb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|