gmp 0.2.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +33 -0
- data/README.rdoc +117 -17
- data/benchmark/COPYING +674 -0
- data/benchmark/README +75 -0
- data/benchmark/divide +34 -0
- data/benchmark/gcd +38 -0
- data/benchmark/gexpr +0 -0
- data/benchmark/gexpr.c +359 -0
- data/benchmark/multiply +44 -0
- data/benchmark/rsa +93 -0
- data/benchmark/runbench +147 -0
- data/benchmark/version +1 -0
- data/ext/gmp.c +10 -8
- data/ext/gmpbench_timing.c +80 -0
- data/ext/gmprandstate.c +224 -0
- data/ext/gmpz.c +170 -61
- data/ext/ruby_gmp.h +43 -1
- data/manual.pdf +0 -0
- data/manual.tex +214 -20
- data/test/README +4 -11
- data/test/tc_division.rb +109 -0
- data/test/tc_random.rb +54 -0
- data/test/tc_z_gcd_lcm_invert.rb +57 -0
- data/test/test-12.rb +14 -0
- data/test/test-19.rb +13 -0
- data/test/test-20.rb +29 -0
- data/test/test-21.rb +37 -0
- data/test/test-22.rb +12 -0
- data/test/test-23.rb +11 -0
- data/test/test_helper.rb +6 -0
- data/test/unit_tests.rb +9 -94
- metadata +31 -10
data/benchmark/multiply
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require '../ext/gmp'
|
4
|
+
|
5
|
+
multiplicands = ARGV
|
6
|
+
random_state = GMP::RandState.new
|
7
|
+
|
8
|
+
if multiplicands.size > 1
|
9
|
+
m, n = multiplicands[0].to_i, multiplicands[1].to_i
|
10
|
+
x = random_state.urandomb(m)
|
11
|
+
y = random_state.urandomb(n)
|
12
|
+
else
|
13
|
+
m = multiplicands[0].to_i
|
14
|
+
x = random_state.urandomb(m)
|
15
|
+
y = x
|
16
|
+
end
|
17
|
+
|
18
|
+
t = GMP::time { z = x * y }
|
19
|
+
iterations = (1 + (1e4 / t)).to_i
|
20
|
+
|
21
|
+
if multiplicands.size > 1
|
22
|
+
print "Multiplying %i-bit number with %i-bit number %i times..." % [m, n, iterations]
|
23
|
+
else
|
24
|
+
print "Squaring a %i-bit number %i times..." % [m, iterations]
|
25
|
+
end
|
26
|
+
STDOUT.flush
|
27
|
+
|
28
|
+
t0 = GMP::cputime
|
29
|
+
iterations.times do
|
30
|
+
z = x * y
|
31
|
+
end
|
32
|
+
ti = GMP::cputime - t0
|
33
|
+
|
34
|
+
puts "done!"
|
35
|
+
ops_per_sec = 1000.0 * iterations / ti
|
36
|
+
f = 100.0
|
37
|
+
decimals = 0
|
38
|
+
while true
|
39
|
+
decimals += 1
|
40
|
+
break if ops_per_sec > f
|
41
|
+
f = f * 0.1
|
42
|
+
end
|
43
|
+
|
44
|
+
puts "RESULT: %#{decimals}f operations per second\n" % ops_per_sec
|
data/benchmark/rsa
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require '../ext/gmp'
|
4
|
+
|
5
|
+
RSA_EXP = 0x10001
|
6
|
+
|
7
|
+
def rsa_sign(msg, p, q, pq, p_i_q, dp, dq)
|
8
|
+
pr = msg.powmod(dp, p)
|
9
|
+
qr = msg.powmod(dq, q)
|
10
|
+
|
11
|
+
qr_m_pr = qr - pr
|
12
|
+
|
13
|
+
t = qr_m_pr * p_i_q
|
14
|
+
o = t % q
|
15
|
+
|
16
|
+
t = o * p
|
17
|
+
smsg = pr + t
|
18
|
+
smsg % pq
|
19
|
+
end
|
20
|
+
|
21
|
+
n = ARGV[0].to_i
|
22
|
+
random_state = GMP::RandState.new
|
23
|
+
|
24
|
+
print "Generating p, q, d..."
|
25
|
+
STDOUT.flush
|
26
|
+
|
27
|
+
pq = GMP::Z()
|
28
|
+
while pq != 1
|
29
|
+
p = random_state.urandomb(n/2)
|
30
|
+
p[n/2 - 1] = true
|
31
|
+
p[n/2 - 2] = true
|
32
|
+
p[0] = true
|
33
|
+
|
34
|
+
q = random_state.urandomb(n/2)
|
35
|
+
q[n/2 - 1] = true
|
36
|
+
q[n/2 - 2] = true
|
37
|
+
q[0] = true
|
38
|
+
|
39
|
+
pq = p.gcd(q)
|
40
|
+
end
|
41
|
+
|
42
|
+
pq = p * q
|
43
|
+
|
44
|
+
e = GMP::Z(RSA_EXP)
|
45
|
+
|
46
|
+
pm1 = p - 1
|
47
|
+
qm1 = q - 1
|
48
|
+
phi = pm1 * qm1
|
49
|
+
d = e.invert(phi)
|
50
|
+
|
51
|
+
puts "done; pq is %i bits" % pq.sizeinbase(2)
|
52
|
+
puts "Precomputing CRT constants"
|
53
|
+
|
54
|
+
p_i_q = p.invert(q)
|
55
|
+
|
56
|
+
dp = d % pm1
|
57
|
+
dq = d % qm1
|
58
|
+
|
59
|
+
puts "Generating random messages"
|
60
|
+
|
61
|
+
msg = []
|
62
|
+
(0...1024).each do |i|
|
63
|
+
msg << random_state.urandomb(n)
|
64
|
+
end
|
65
|
+
|
66
|
+
print "Calibrating CPU speed..."
|
67
|
+
STDOUT.flush
|
68
|
+
t = GMP::time { smsg = rsa_sign(msg[0], p, q, pq, p_i_q, dp, dq) }
|
69
|
+
puts "done"
|
70
|
+
|
71
|
+
iterations = (1e4 / t).to_i
|
72
|
+
iterations = 1 if iterations == 0
|
73
|
+
|
74
|
+
print "Signing random messages %i times..." % iterations
|
75
|
+
STDOUT.flush
|
76
|
+
|
77
|
+
t0 = GMP::cputime
|
78
|
+
(1..iterations).to_a.reverse.each do |i|
|
79
|
+
smsg = rsa_sign(msg[i % 1024], p, q, pq, p_i_q, dp, dq)
|
80
|
+
end
|
81
|
+
ti = GMP::cputime - t0
|
82
|
+
|
83
|
+
puts "done!"
|
84
|
+
ops_per_sec = 1000.0 * iterations / ti
|
85
|
+
f = 100.0
|
86
|
+
decimals = 0
|
87
|
+
while true
|
88
|
+
decimals += 1
|
89
|
+
break if ops_per_sec > f
|
90
|
+
f = f * 0.1
|
91
|
+
end
|
92
|
+
|
93
|
+
puts "RESULT: %#{decimals}f operations per second\n" % ops_per_sec
|
data/benchmark/runbench
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
#! /bin/sh
|
2
|
+
|
3
|
+
# Copyright 2003 Free Software Foundation, Inc.
|
4
|
+
|
5
|
+
# This file is part of the GNU GMPbench.
|
6
|
+
|
7
|
+
# This program is free software; you can redistribute it and/or modify it under
|
8
|
+
# the terms of the GNU General Public License as published by the Free Software
|
9
|
+
# Foundation; either version 2 of the License, or (at your option) any later
|
10
|
+
# version.
|
11
|
+
|
12
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
13
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
14
|
+
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
15
|
+
# details.
|
16
|
+
|
17
|
+
# You should have received a copy of the GNU General Public License along with
|
18
|
+
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
19
|
+
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
20
|
+
|
21
|
+
|
22
|
+
echo "***** GMPbench version `cat version` *****"
|
23
|
+
|
24
|
+
|
25
|
+
default=false
|
26
|
+
|
27
|
+
if [ "$1" = -n ]
|
28
|
+
then
|
29
|
+
echo "Suppressing compilation"
|
30
|
+
else
|
31
|
+
if [ -z "$CFLAGS" ]
|
32
|
+
then
|
33
|
+
CFLAGS="-O3 -fomit-frame-pointer"
|
34
|
+
echo "Using default CFLAGS = \"$CFLAGS\""
|
35
|
+
default=true
|
36
|
+
else
|
37
|
+
echo "Using CFLAGS = \"$CFLAGS\" from your environment"
|
38
|
+
fi
|
39
|
+
if [ -z "$CC" ]
|
40
|
+
then
|
41
|
+
CC="gcc"
|
42
|
+
echo "Using default CC = \"$CC\""
|
43
|
+
default=true
|
44
|
+
else
|
45
|
+
echo "Using CC = \"$CC\" from your environment"
|
46
|
+
fi
|
47
|
+
if [ -z "$LIBS" ]
|
48
|
+
then
|
49
|
+
LIBS="-static -lgmp"
|
50
|
+
echo "Using default LIBS = \"$LIBS\""
|
51
|
+
default=true
|
52
|
+
else
|
53
|
+
echo "Using LIBS = \"$LIBS\" from your environment"
|
54
|
+
fi
|
55
|
+
|
56
|
+
echo "Using compilation command: $CC $CFLAGS foo.c -o foo $LIBS"
|
57
|
+
|
58
|
+
if $default
|
59
|
+
then
|
60
|
+
echo "You may want to override CC, CFLAGS, and LIBS"
|
61
|
+
fi
|
62
|
+
|
63
|
+
$CC $CFLAGS gmpver.c $LIBS
|
64
|
+
`mv a.exe a.out`
|
65
|
+
echo "Using `./a.out`"
|
66
|
+
|
67
|
+
echo "Compiling benchmarks"
|
68
|
+
$CC $CFLAGS gcd.c -o gcd $LIBS
|
69
|
+
$CC $CFLAGS gcdext.c -o gcdext $LIBS
|
70
|
+
$CC $CFLAGS multiply.c -o multiply $LIBS
|
71
|
+
$CC $CFLAGS divide.c -o divide $LIBS
|
72
|
+
$CC $CFLAGS rsa.c -o rsa $LIBS
|
73
|
+
$CC $CFLAGS pi.c -o pi $LIBS -lm
|
74
|
+
fi
|
75
|
+
|
76
|
+
multiply_args="128 512 8192 131072 2097152 128,128 512,512 8192,8192 131072,131072 2097152,2097152 15000,10000 20000,10000 30000,10000 16777216,512 16777216,262144"
|
77
|
+
multiply_weight=1
|
78
|
+
|
79
|
+
divide_args="8192,32 8192,64 8192,128 8192,4096 131072,65536 8388608,4194304 8192,8064 16777216,262144"
|
80
|
+
divide_weight=1
|
81
|
+
|
82
|
+
gcd_args="128,128 512,512 8192,8192 131072,131072 1048576,1048576"
|
83
|
+
gcd_weight=0.5
|
84
|
+
|
85
|
+
gcdext_args="128,128 512,512 8192,8192 131072,131072 1048576,1048576"
|
86
|
+
gcdext_weight=0.5
|
87
|
+
|
88
|
+
rsa_args="512 1024 2048"
|
89
|
+
rsa_weight=1
|
90
|
+
|
91
|
+
pi_args="10000 100000 1000000"
|
92
|
+
pi_weight=1
|
93
|
+
|
94
|
+
# base_tests="multiply divide gcd gcdext"
|
95
|
+
base_tests="multiply divide gcd"
|
96
|
+
# app_tests="rsa pi"
|
97
|
+
app_tests="rsa"
|
98
|
+
|
99
|
+
tests="base app"
|
100
|
+
|
101
|
+
echo "Running benchmarks (propagated score accuracy exceeds printed intermediates)"
|
102
|
+
|
103
|
+
acc2=1
|
104
|
+
n2=0
|
105
|
+
for cat in $tests
|
106
|
+
do
|
107
|
+
echo " Category $cat"
|
108
|
+
eval tests=\$${cat}_tests
|
109
|
+
|
110
|
+
acc1=1
|
111
|
+
n1=0
|
112
|
+
for t in $tests
|
113
|
+
do
|
114
|
+
eval weight=\$${t}_weight
|
115
|
+
echo " Program $t (weight=$weight)"
|
116
|
+
eval args=\$${t}_args
|
117
|
+
|
118
|
+
acc=1
|
119
|
+
n=0
|
120
|
+
for a in $args
|
121
|
+
do
|
122
|
+
ta=`echo $a | sed 's;,; ;g'`
|
123
|
+
printf ' %-48s' "GMPbench.$cat.$t($a)"
|
124
|
+
./$t $ta >RES-$t-$a
|
125
|
+
res=`grep "^RESULT" RES-$t-$a | sed 's;^RESULT: \([0-9.]*\).*$;\1;'`
|
126
|
+
printf '%12s\n' `gexpr -prec 4 "$res"`
|
127
|
+
acc=`gexpr -prec 10 "$acc * $res"`
|
128
|
+
n=`gexpr $n+1`
|
129
|
+
done
|
130
|
+
|
131
|
+
out=`gexpr -prec 10 "$acc^(1/$n)"`
|
132
|
+
printf ' %-40s%12s\n' "GMPbench.$cat.$t" `gexpr -prec 5 "$out"`
|
133
|
+
acc1=`gexpr -prec 10 "$acc1 * $out^$weight"`
|
134
|
+
n1=`gexpr $n1+$weight`
|
135
|
+
done
|
136
|
+
|
137
|
+
out=`gexpr -prec 10 "$acc1^(1/$n1)"`
|
138
|
+
printf ' %-32s%12s\n' "GMPbench.$cat" `gexpr -prec 5 "$out"`
|
139
|
+
acc2=`gexpr -prec 10 "$acc2 * $out"`
|
140
|
+
n2=`gexpr $n2+1`
|
141
|
+
done
|
142
|
+
|
143
|
+
|
144
|
+
out=`gexpr "$acc2^(1/$n2)"`
|
145
|
+
echo "GMPbench: $out"
|
146
|
+
|
147
|
+
exit 0
|
data/benchmark/version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2
|
data/ext/gmp.c
CHANGED
@@ -6,11 +6,12 @@
|
|
6
6
|
|
7
7
|
#include <ruby_gmp.h>
|
8
8
|
|
9
|
-
VALUE mGMP, cGMP_Z, cGMP_Q, cGMP_F;
|
9
|
+
VALUE mGMP, cGMP_Z, cGMP_Q, cGMP_F, cGMP_RandState;
|
10
10
|
|
11
|
-
void r_gmpz_free(void *ptr)
|
12
|
-
void r_gmpq_free(void *ptr)
|
13
|
-
void r_gmpf_free(void *ptr)
|
11
|
+
void r_gmpz_free(void *ptr) { mpz_clear (ptr); free (ptr); }
|
12
|
+
void r_gmpq_free(void *ptr) { mpq_clear (ptr); free (ptr); }
|
13
|
+
void r_gmpf_free(void *ptr) { mpf_clear (ptr); free (ptr); }
|
14
|
+
void r_gmprandstate_free(void *ptr) { gmp_randclear (ptr); free (ptr); }
|
14
15
|
|
15
16
|
static void mpq_str_set(MP_RAT *ROP, char *str)
|
16
17
|
{
|
@@ -138,10 +139,6 @@ void Init_gmp() {
|
|
138
139
|
cGMP_Z = rb_define_class_under(mGMP, "Z", rb_cInteger);
|
139
140
|
init_gmpz();
|
140
141
|
rb_define_method(cGMP_Z, "coerce", r_gmpz_coerce, 1);
|
141
|
-
/*
|
142
|
-
rb_define_method(cGMP_Z, "gcd", r_gmpz_gcd, 1);
|
143
|
-
rb_define_method(cGMP_Z, "lcm", r_gmpz_lcm, 1);
|
144
|
-
*/
|
145
142
|
|
146
143
|
cGMP_Q = rb_define_class_under (mGMP, "Q", rb_cNumeric);
|
147
144
|
init_gmpq();
|
@@ -157,6 +154,11 @@ void Init_gmp() {
|
|
157
154
|
rb_define_method(cGMP_F, "coerce", r_gmpf_coerce, 1); // new method - testing
|
158
155
|
|
159
156
|
/* rb_define_method(cGMP_F, "cmpabs", r_gmpf_cmpabs, 1);*/
|
157
|
+
|
158
|
+
cGMP_RandState = rb_define_class_under (mGMP, "RandState", rb_cObject);
|
159
|
+
init_gmprandstate();
|
160
|
+
|
161
|
+
init_gmpbench_timing();
|
160
162
|
|
161
163
|
#ifdef MPFR
|
162
164
|
rb_define_method(cGMP_F, "exp", r_gmpfr_exp, 0);
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#include <ruby_gmp.h>
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Taken directly from GMPbench.
|
5
|
+
*/
|
6
|
+
|
7
|
+
#define TIME(t,func) \
|
8
|
+
do { \
|
9
|
+
long int __t0, __times, __t, __tmp; \
|
10
|
+
__times = 1; \
|
11
|
+
{func;} \
|
12
|
+
do { \
|
13
|
+
__times <<= 1; \
|
14
|
+
__t0 = FIX2INT(r_gmpmod_cputime ()); \
|
15
|
+
for (__t = 0; __t < __times; __t++) \
|
16
|
+
{func;} \
|
17
|
+
__tmp = FIX2INT(r_gmpmod_cputime ()) - __t0; \
|
18
|
+
} while (__tmp < 250); \
|
19
|
+
(t) = (double) __tmp / __times; \
|
20
|
+
} while (0)
|
21
|
+
|
22
|
+
/* Return user CPU time measured in milliseconds. */
|
23
|
+
#if !defined (__sun) \
|
24
|
+
&& (defined (USG) || defined (__SVR4) || defined (_UNICOS) \
|
25
|
+
|| defined (__hpux) || defined (_WIN32))
|
26
|
+
#include <time.h>
|
27
|
+
|
28
|
+
int
|
29
|
+
cputime ()
|
30
|
+
{
|
31
|
+
return (int) ((double) clock () * 1000 / CLOCKS_PER_SEC);
|
32
|
+
}
|
33
|
+
#else
|
34
|
+
#include <sys/types.h>
|
35
|
+
#include <sys/time.h>
|
36
|
+
#include <sys/resource.h>
|
37
|
+
|
38
|
+
int
|
39
|
+
cputime ()
|
40
|
+
{
|
41
|
+
struct rusage rus;
|
42
|
+
|
43
|
+
getrusage (0, &rus);
|
44
|
+
return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
|
45
|
+
}
|
46
|
+
#endif
|
47
|
+
|
48
|
+
VALUE
|
49
|
+
r_gmpmod_cputime (VALUE self)
|
50
|
+
{
|
51
|
+
(void)self;
|
52
|
+
return INT2FIX (cputime ());
|
53
|
+
}
|
54
|
+
|
55
|
+
VALUE
|
56
|
+
r_gmpmod_time (VALUE self)
|
57
|
+
{
|
58
|
+
(void)self;
|
59
|
+
long int __t0, __times, __t, __tmp;
|
60
|
+
__times = 1;
|
61
|
+
|
62
|
+
rb_need_block();
|
63
|
+
|
64
|
+
rb_yield (Qnil);
|
65
|
+
do {
|
66
|
+
__times <<= 1;
|
67
|
+
__t0 = cputime ();
|
68
|
+
for (__t = 0; __t < __times; __t++)
|
69
|
+
{rb_yield (Qnil);}
|
70
|
+
__tmp = cputime () - __t0;
|
71
|
+
} while (__tmp < 250);
|
72
|
+
return rb_float_new ((double) __tmp / __times);
|
73
|
+
}
|
74
|
+
|
75
|
+
void init_gmpbench_timing()
|
76
|
+
{
|
77
|
+
mGMP = rb_define_module("GMP");
|
78
|
+
rb_define_module_function(mGMP, "cputime", r_gmpmod_cputime, 0);
|
79
|
+
rb_define_module_function(mGMP, "time", r_gmpmod_time, 0);
|
80
|
+
}
|
data/ext/gmprandstate.c
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
#include <gmpz.h>
|
2
|
+
#include <gmpq.h>
|
3
|
+
#include <gmpf.h>
|
4
|
+
|
5
|
+
/*
|
6
|
+
* Document-class: GMP::Z
|
7
|
+
*
|
8
|
+
* GMP Multiple Precision Integer.
|
9
|
+
*
|
10
|
+
* Instances of this class can store variables of the type gmp_randstate_t.
|
11
|
+
* This class also contains many methods that act as the functions for
|
12
|
+
* gmp_randstate_t variables, as well as a few methods that attempt to make
|
13
|
+
* this library more Ruby-ish.
|
14
|
+
*
|
15
|
+
* The following list is just a simple checklist for me, really. A better
|
16
|
+
* reference should be found in the rdocs.
|
17
|
+
*
|
18
|
+
* Ruby method C Extension function GMP function
|
19
|
+
* new r_gmprandstatesg_new gmp_randinit_default
|
20
|
+
* seed r_gmprandstate_seed gmp_randseed
|
21
|
+
* \--- \------------------ gmp_randseed_ui
|
22
|
+
* urandomb r_gmprandstate_urandomb mpz_urandomb
|
23
|
+
*/
|
24
|
+
|
25
|
+
/**********************************************************************
|
26
|
+
* Random State Initialization *
|
27
|
+
**********************************************************************/
|
28
|
+
|
29
|
+
/*
|
30
|
+
* call-seq:
|
31
|
+
* GMP::RandState.new()
|
32
|
+
* GMP::RandState.new(:mt) #=> uses gmp_randinit_mt
|
33
|
+
* GMP::RandState.new(:lc_2exp, a, c, m2exp) #=> uses gmp_randinit_lc_2exp
|
34
|
+
* GMP::RandState.new(:lc_2exp_size, size) #=> uses gmp_randinit_lc_2exp_size
|
35
|
+
*
|
36
|
+
* Initializes a new Random State object. Multiple GMP::RandState objects can
|
37
|
+
* be instantiated. They may use different generators and the states
|
38
|
+
* are kept separate.
|
39
|
+
*/
|
40
|
+
VALUE r_gmprandstatesg_new(int argc, VALUE *argv, VALUE klass)
|
41
|
+
{
|
42
|
+
MP_RANDSTATE *rs_val;
|
43
|
+
VALUE rs;
|
44
|
+
VALUE algorithm, arg2, arg3, arg4;
|
45
|
+
ID algorithm_id = rb_intern("default");
|
46
|
+
MP_INT *a_val;
|
47
|
+
unsigned long c_val, m2exp_val;
|
48
|
+
unsigned long size_val;
|
49
|
+
int free_a_val = 0;
|
50
|
+
|
51
|
+
ID default_algorithm = rb_intern("default");
|
52
|
+
ID mt_algorithm = rb_intern("mt");
|
53
|
+
ID lc_2exp_algorithm = rb_intern("lc_2exp");
|
54
|
+
ID lc_2exp_size_algorithm = rb_intern("lc_2exp_size");
|
55
|
+
|
56
|
+
(void)klass;
|
57
|
+
|
58
|
+
mprandstate_make_struct(rs, rs_val);
|
59
|
+
rb_scan_args(argc, argv, "04", &algorithm, &arg2, &arg3, &arg4);
|
60
|
+
if (NIL_P(algorithm)) { algorithm_id = rb_intern("default"); } /* default value */
|
61
|
+
if (SYMBOL_P(algorithm)) { algorithm_id = rb_to_id(algorithm); }
|
62
|
+
if (algorithm_id == default_algorithm ||
|
63
|
+
algorithm_id == mt_algorithm) {
|
64
|
+
if (argc > 1)
|
65
|
+
rb_raise(rb_eArgError, "wrong # of arguments (%d for 0 or 1)", argc);
|
66
|
+
gmp_randinit_default(rs_val);
|
67
|
+
} else if (algorithm_id == lc_2exp_algorithm) {
|
68
|
+
if (argc != 4)
|
69
|
+
rb_raise(rb_eArgError, "wrong # of arguments (%d for 4)", argc);
|
70
|
+
if (GMPZ_P(arg2)) {
|
71
|
+
mpz_get_struct(arg2, a_val);
|
72
|
+
} else if (FIXNUM_P(arg2)) {
|
73
|
+
mpz_temp_alloc(a_val);
|
74
|
+
mpz_init_set_ui(a_val, FIX2INT(arg2));
|
75
|
+
free_a_val = 1;
|
76
|
+
} else if (BIGNUM_P(arg2)) {
|
77
|
+
mpz_temp_from_bignum(a_val, arg2);
|
78
|
+
free_a_val = 1;
|
79
|
+
} else {
|
80
|
+
typeerror_as(ZXB, "b");
|
81
|
+
}
|
82
|
+
c_val = NUM2LONG(arg3);
|
83
|
+
m2exp_val = NUM2LONG(arg4);
|
84
|
+
gmp_randinit_lc_2exp(rs_val, a_val, c_val, m2exp_val);
|
85
|
+
} else if (algorithm_id == lc_2exp_size_algorithm) {
|
86
|
+
if (argc != 2)
|
87
|
+
rb_raise(rb_eArgError, "wrong # of arguments (%d for 2)", argc);
|
88
|
+
size_val = NUM2LONG(arg2);
|
89
|
+
if (size_val > 128)
|
90
|
+
rb_raise(rb_eArgError, "size must be within [0..128]");
|
91
|
+
int rv = gmp_randinit_lc_2exp_size(rs_val, size_val);
|
92
|
+
if (rv == 0)
|
93
|
+
rb_raise(rb_eArgError, "could not gmp_randinit_lc_2exp_size with %d", size_val);
|
94
|
+
}
|
95
|
+
|
96
|
+
if (free_a_val) { mpz_temp_free(a_val); }
|
97
|
+
rb_obj_call_init(rs, argc, argv);
|
98
|
+
|
99
|
+
return rs;
|
100
|
+
}
|
101
|
+
|
102
|
+
VALUE r_gmprandstate_initialize(int argc, VALUE *argv, VALUE self)
|
103
|
+
{
|
104
|
+
MP_RANDSTATE *self_val;
|
105
|
+
(void)argv;
|
106
|
+
|
107
|
+
if (argc != 0) {
|
108
|
+
mprandstate_get_struct(self,self_val);
|
109
|
+
}
|
110
|
+
return Qnil;
|
111
|
+
}
|
112
|
+
|
113
|
+
/*
|
114
|
+
* call-seq:
|
115
|
+
* GMP::RandState(arg)
|
116
|
+
*
|
117
|
+
* A convenience method for +GMP::RandState.new(arg)+.
|
118
|
+
*/
|
119
|
+
VALUE r_gmpmod_randstate(int argc, VALUE *argv, VALUE module)
|
120
|
+
{
|
121
|
+
(void)module;
|
122
|
+
return r_gmprandstatesg_new(argc, argv, cGMP_RandState);
|
123
|
+
}
|
124
|
+
|
125
|
+
|
126
|
+
/**********************************************************************
|
127
|
+
* Random State Initialization *
|
128
|
+
**********************************************************************/
|
129
|
+
|
130
|
+
/*
|
131
|
+
* call-seq:
|
132
|
+
* rand_state.seed(integer)
|
133
|
+
*
|
134
|
+
* From the GMP Manual:
|
135
|
+
*
|
136
|
+
* Set an initial seed value into state.
|
137
|
+
*
|
138
|
+
* The size of a seed determines how many different sequences of random numbers
|
139
|
+
* that it's possible to generate. The �quality� of the seed is the randomness
|
140
|
+
* of a given seed compared to the previous seed used, and this affects the
|
141
|
+
* randomness of separate number sequences. The method for choosing a seed is
|
142
|
+
* critical if the generated numbers are to be used for important applications,
|
143
|
+
* such as generating cryptographic keys.
|
144
|
+
*
|
145
|
+
* Traditionally the system time has been used to seed, but care needs to be
|
146
|
+
* taken with this. If an application seeds often and the resolution of the
|
147
|
+
* system clock is low, then the same sequence of numbers might be repeated.
|
148
|
+
* Also, the system time is quite easy to guess, so if unpredictability is
|
149
|
+
* required then it should definitely not be the only source for the seed
|
150
|
+
* value. On some systems there's a special device /dev/random which provides
|
151
|
+
* random data better suited for use as a seed.
|
152
|
+
*/
|
153
|
+
VALUE r_gmprandstate_seed(VALUE self, VALUE arg)
|
154
|
+
{
|
155
|
+
MP_RANDSTATE *self_val;
|
156
|
+
MP_INT *arg_val;
|
157
|
+
|
158
|
+
mprandstate_get_struct(self,self_val);
|
159
|
+
|
160
|
+
if (GMPZ_P(arg)) {
|
161
|
+
mpz_get_struct(arg,arg_val);
|
162
|
+
gmp_randseed(self_val, arg_val);
|
163
|
+
} else if (FIXNUM_P(arg)) {
|
164
|
+
gmp_randseed_ui(self_val, FIX2INT(arg));
|
165
|
+
} else if (BIGNUM_P(arg)) {
|
166
|
+
mpz_temp_from_bignum(arg_val, arg);
|
167
|
+
gmp_randseed(self_val, arg_val);
|
168
|
+
} else {
|
169
|
+
typeerror(ZXB);
|
170
|
+
}
|
171
|
+
return arg;
|
172
|
+
}
|
173
|
+
|
174
|
+
|
175
|
+
/**********************************************************************
|
176
|
+
* Integer Random Numbers *
|
177
|
+
**********************************************************************/
|
178
|
+
|
179
|
+
/*
|
180
|
+
* call-seq:
|
181
|
+
* rand_state.urandomb(fixnum)
|
182
|
+
*
|
183
|
+
* From the GMP Manual:
|
184
|
+
*
|
185
|
+
* Generate a uniformly distributed random integer in the range 0 to
|
186
|
+
* 2^fixnum-1, inclusive.
|
187
|
+
*/
|
188
|
+
VALUE r_gmprandstate_urandomb(VALUE self, VALUE arg)
|
189
|
+
{
|
190
|
+
MP_RANDSTATE *self_val;
|
191
|
+
MP_INT *res_val;
|
192
|
+
VALUE res;
|
193
|
+
|
194
|
+
mprandstate_get_struct(self,self_val);
|
195
|
+
|
196
|
+
if (FIXNUM_P(arg)) {
|
197
|
+
mpz_make_struct_init(res, res_val);
|
198
|
+
mpz_urandomb(res_val, self_val, FIX2INT(arg));
|
199
|
+
} else {
|
200
|
+
typeerror(X);
|
201
|
+
}
|
202
|
+
|
203
|
+
return res;
|
204
|
+
}
|
205
|
+
|
206
|
+
|
207
|
+
void init_gmprandstate()
|
208
|
+
{
|
209
|
+
mGMP = rb_define_module("GMP");
|
210
|
+
rb_define_module_function(mGMP, "RandState", r_gmpmod_randstate, -1);
|
211
|
+
|
212
|
+
cGMP_RandState = rb_define_class_under(mGMP, "RandState", rb_cObject);
|
213
|
+
|
214
|
+
// Random State Initialization
|
215
|
+
rb_define_singleton_method(cGMP_RandState, "new", r_gmprandstatesg_new, -1);
|
216
|
+
rb_define_method(cGMP_RandState, "initialize", r_gmprandstate_initialize, -1);
|
217
|
+
|
218
|
+
// Random State Seeding
|
219
|
+
rb_define_method(cGMP_RandState, "seed", r_gmprandstate_seed, 1);
|
220
|
+
|
221
|
+
// Integer Random Numbers
|
222
|
+
rb_define_method(cGMP_RandState, "urandomb", r_gmprandstate_urandomb, 1);
|
223
|
+
|
224
|
+
}
|