gmp 0.2.2 → 0.4.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.
- 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
|
+
}
|