gmp_ecm 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING.md ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2012 Sam Rawlins
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'gmp'
4
+
5
+ group :test do
6
+ gem 'rspec'
7
+ end
8
+
9
+ group :development do
10
+ gem 'guard'
11
+ gem 'guard-rspec'
12
+ gem 'guard-shell'
13
+ gem 'yard'
14
+ gem 'redcarpet'
15
+ end
data/Guardfile ADDED
@@ -0,0 +1,18 @@
1
+ require 'fileutils'
2
+
3
+ guard 'rspec' do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch('spec/spec_helper.rb') { "spec" }
7
+ end
8
+
9
+ guard 'shell' do
10
+ watch(/ext\/(.*)\.[c|h]$/) do |m|
11
+ system("cd ext && make; cd ..")
12
+ FileUtils.touch Dir.glob(File.join('spec', 'spec_helper.rb')).first # force the rspec guard to fire
13
+ end
14
+
15
+ # watch("manual.md") do |m|
16
+ # system("make")
17
+ # end
18
+ end
data/README.md ADDED
@@ -0,0 +1,18 @@
1
+ GMP-ECM
2
+ =======
3
+
4
+ GMP-ECM is a C implementation of the [Elliptic Curve Method](http://en.wikipedia.org/wiki/Elliptic_curve_method) for factorizing integers. This library, gmp_ecm, provides Ruby bindings to this library.
5
+
6
+ The only prerequisite to using gmp_ecm is the [gmp](https://github.com/srawlins/gmp) gem, which provides Ruby bindings to GMP, a prerequisite to using the GMP-ECM library. The gmp gem is required because most numbers (input integer, resultant factors, and various parameters) are passed around as `GMP::Z` numbers.
7
+
8
+ Usage
9
+ =====
10
+
11
+ The function of the gmp_ecm library is contained almost entirely in the `GMP::Z#ecm_factor` method (binding to GMP-ECM's `ecm_params` C function). So in order to start factorizing an integer, one must first initialize a `GMP::Z` number, and then call `#ecm_factor` against it. Just as in the C library, this method requires the `B1` parameter to be passed in. Optionally, the user can pass in a second parameter, a Hash, or an ECMParams object. This will be passed to `ecm_factor` as an `ecm_params` struct.
12
+
13
+ Just now, not all of the fields in `ecm_params` is available. The current list of supported parameters is in the docs.
14
+
15
+ License
16
+ =======
17
+
18
+ gmp_ecm is licensed under the Apache License, Version 2.0
data/ext/ecm.c ADDED
@@ -0,0 +1,200 @@
1
+ /*
2
+ * ecm.c
3
+ *
4
+ * This file contains everything you would expect from a C extension.
5
+ */
6
+
7
+ #include <ruby_ecm.h>
8
+
9
+ /*********************************************************************
10
+ * Initialization Functions *
11
+ *********************************************************************/
12
+
13
+ VALUE cECM_PARAMS;
14
+ ID ecmp_method_id;
15
+ ID ecmp_ecm_ecm_id;
16
+ ID ecmp_ecm_pm1_id;
17
+ ID ecmp_ecm_pp1_id;
18
+ ID ecmp_x_id;
19
+ ID ecmp_sigma_id;
20
+ ID ecmp_sigma_is_A_id;
21
+ ID ecmp_go_id;
22
+ ID ecmp_B1done_id;
23
+ ID ecmp_B2min_id;
24
+ ID ecmp_B2_id;
25
+ //void r_ecm_params_free(void *ptr) { ecm_clear (ptr); free (ptr); }
26
+ void r_ecm_params_free(void *ptr) { ecm_clear (ptr); }
27
+
28
+ /*
29
+ * So far, we accept the following:
30
+ *
31
+ * :method is supposed to be one of these constants: ECM_ECM, ECM_PM1, ECM_PP1.
32
+ * I am accepting :ecm_ecm, :ecm_pm1, :ecm_pp1.
33
+ *
34
+ * :x is supposed to be an mpz_t. I am accepting GMP::Z.
35
+ *
36
+ * :sigma is supposed to be an mpz_t. I am accepting Fixnum, Bignum, GMP::Z.
37
+ *
38
+ * :sigma_is_A is supposed to be 1, 0, or -1. I am accepting Fixnum.
39
+ */
40
+ int add_item_to_ecm_params (VALUE key, VALUE value, VALUE params_value) {
41
+ ECM_PARAMS *params;
42
+ ecm_params_get_struct (params_value, params);
43
+ MP_INT *params_x, *params_sigma, *params_go, *params_B2min, *params_B2;
44
+ if (rb_to_id (key) == ecmp_method_id) {
45
+ if ( rb_to_id (value) == ecmp_ecm_ecm_id) { params->method = ECM_ECM; }
46
+ else if ( rb_to_id (value) == ecmp_ecm_pm1_id) { params->method = ECM_PM1; }
47
+ else if ( rb_to_id (value) == ecmp_ecm_pp1_id) { params->method = ECM_PP1; }
48
+ } else if (rb_to_id (key) == ecmp_x_id) {
49
+ mpz_get_struct (value, params_x);
50
+ mpz_init_set (params->x, params_x);
51
+ } else if (rb_to_id (key) == ecmp_sigma_id) {
52
+ if (FIXNUM_P (value) || BIGNUM_P (value)) {
53
+ mpz_init_set_si (params->sigma, NUM2INT(value));
54
+ } else if (GMPZ_P (value)) {
55
+ mpz_get_struct (value, params_sigma);
56
+ mpz_init_set (params->sigma, params_sigma);
57
+ }
58
+ } else if (rb_to_id (key) == ecmp_sigma_is_A_id) {
59
+ params->sigma_is_A = NUM2INT(value);
60
+ } else if (rb_to_id (key) == ecmp_go_id) {
61
+ if (FIXNUM_P (value) || BIGNUM_P (value)) {
62
+ mpz_init_set_si (params->go, NUM2INT(value));
63
+ } else if (GMPZ_P (value)) {
64
+ mpz_get_struct (value, params_go);
65
+ mpz_init_set (params->go, params_go);
66
+ }
67
+ } else if (rb_to_id (key) == ecmp_B1done_id) {
68
+ if (FIXNUM_P (value)) {
69
+ params->B1done = (double) NUM2INT (value);
70
+ } else if (FLOAT_P (value)) {
71
+ params->B1done = NUM2DBL (value);
72
+ }
73
+ } else if (rb_to_id (key) == ecmp_B2min_id) {
74
+ if (FIXNUM_P (value) || BIGNUM_P (value)) {
75
+ mpz_init_set_si (params->B2min, NUM2INT(value));
76
+ } else if (GMPZ_P (value)) {
77
+ mpz_get_struct (value, params_B2min);
78
+ mpz_init_set (params->B2min, params_B2min);
79
+ }
80
+ } else if (rb_to_id (key) == ecmp_B2_id) {
81
+ if (FIXNUM_P (value) || BIGNUM_P (value)) {
82
+ mpz_init_set_si (params->B2, NUM2INT(value));
83
+ } else if (GMPZ_P (value)) {
84
+ mpz_get_struct (value, params_B2);
85
+ mpz_init_set (params->B2, params_B2);
86
+ }
87
+ }
88
+ return 1;
89
+ }
90
+
91
+ /*
92
+ * params should already be initialized
93
+ */
94
+ VALUE build_ecm_params_from_hash (VALUE params_hash) {
95
+ VALUE params_value;
96
+ ECM_PARAMS *params;
97
+ ecm_params_make_struct_init (params_value, params);
98
+ rb_hash_foreach (params_hash, add_item_to_ecm_params, params_value);
99
+ return params_value;
100
+ }
101
+
102
+ VALUE r_ecmsg_new(int argc, VALUE *argv, VALUE klass)
103
+ {
104
+ ECM_PARAMS *res;
105
+ VALUE res_value;
106
+ (void)klass;
107
+
108
+ if (argc > 1)
109
+ rb_raise (rb_eArgError, "wrong # of arguments (%d for 0 or 1)", argc);
110
+
111
+ // ecm_params_make_struct (res, res_val);
112
+ ecm_params_make_struct_init (res_value, res);
113
+ rb_obj_call_init (res_value, argc, argv);
114
+
115
+ return res_value;
116
+ }
117
+
118
+ /*
119
+ * Document-method: GMP::Z#ecm_method
120
+ *
121
+ * @overload ecm_factor(b1, ecm_params)
122
+ *
123
+ * Search for a factor of `z`, using GMP-ECM's `ecm_factor()` method.
124
+ *
125
+ * @param [Fixnum, GMP::Z] b1 the stage 1 bound
126
+ * @param [Hash] ecm_params auxiliary parameters; must be a Hash for now.
127
+ *
128
+ * * option ecm_params [Symbol] :method the factorization method (ECM_ECM for ECM, ECM_PM1 for P-1, ECM_PP1 for P+1). Default is ECM_ECM.
129
+ * * option ecm_params [Fixnum, GMP::Z] :x (if non zero) is the starting point (ECM, P-1, P+1). For ECM, we take as starting point (x0 : y0) where x0=x, y0=1; for P-1, we take x0; for P+1, we take x0 as starting point of the Lucas sequence. When ecm_factor() returns, p->x is the point obtained after stage 1.
130
+ * * option ecm_params [?] :sigma (ECM only) is the "sigma" parameter. The elliptic curve chosen is b*y^2 = x^3 + a*x^2 + x where a = (v-u)^3*(3*u+v)/(4*u^3*v)-2, u = sigma^2-5, v = 4*sigma (Suyama's parametrization). The initial point (if p->x is zero) is taken as x0=u^3/v^3, y0=1 (thus b is taken as x0^3 + a*x0^2 + x0).
131
+ * * option ecm_params [-1, 0, 1] :sigma_is_A (ECM only) indicates that p->sigma is the 'a' parameter from the elliptic curve.
132
+ * * option ecm_params [?] :go the initial group order to preload (default is 1).
133
+ * * option ecm_params [?] :B1done tells that step 1 was already done up to B1done. This means that all prime powers <= B1done were dealt with. If for example B1done=100 and B1=200, prime 2 was dealt with up to power 6, thus it remains to "multiply" once by 2 to go up to power 7. Of course, all primes p such that B1done < p <= B1 will be considered with power 1.
134
+ * * option ecm_params [Fixnum, GMP::Z] :B2min the lower bound for stage 2, which will treat all primes p such that B2min <= p <= B2. If negative, B2min will be set to B1.
135
+ * * option ecm_params [Fixnum, GMP::Z] :B2 the upper bound for stage 2 (default is automatically computed from B1, to optimize the efficiency of the method).
136
+ * * option ecm_params [?] :k the number of blocks used in stage 2 (default is ECM_DEFAULT_K).
137
+ */
138
+ VALUE r_ecm_factor (int argc, VALUE *argv, VALUE self_value) {
139
+ MP_INT *self, *res;
140
+ VALUE res_value, b1_value, params_arg, params_value;
141
+ ECM_PARAMS *params;
142
+ double b1;
143
+ int found;
144
+ (void)self;
145
+
146
+ mpz_get_struct (self_value, self);
147
+ mpz_make_struct (res_value, res);
148
+ mpz_init (res);
149
+
150
+ rb_scan_args (argc, argv, "02", &b1_value, &params_arg);
151
+ if (params_arg == Qnil) {
152
+ params = NULL;
153
+ } else if (ECM_PARAMS_P (params_arg)) {
154
+ ecm_params_get_struct (params_arg, params);
155
+ } else if (TYPE (params_arg) == T_HASH) {
156
+ params_value = build_ecm_params_from_hash (params_arg);
157
+ ecm_params_get_struct (params_value, params);
158
+ } else {
159
+ rb_raise (rb_eArgError, "Second argument must be an ECMParams");
160
+ }
161
+ if (b1_value == Qnil) {
162
+ b1 = 1000000;
163
+ } else if (FIXNUM_P (b1_value)) {
164
+ b1 = (double) NUM2INT (b1_value);
165
+ } else if (FLOAT_P (b1_value)) {
166
+ b1 = NUM2DBL (b1_value);
167
+ } else {
168
+ rb_raise (rb_eArgError, "b1 argument must be a Fixnum");
169
+ }
170
+
171
+ found = ecm_factor (res, self, b1, params);
172
+
173
+ return res_value;
174
+ }
175
+
176
+ void Init_ecm() {
177
+ ecmp_method_id = rb_intern("method");
178
+ ecmp_ecm_ecm_id = rb_intern("ecm_ecm");
179
+ ecmp_ecm_pm1_id = rb_intern("ecm_pm1");
180
+ ecmp_ecm_pp1_id = rb_intern("ecm_pp1");
181
+ ecmp_x_id = rb_intern("x");
182
+ ecmp_sigma_id = rb_intern("sigma");
183
+ ecmp_sigma_is_A_id = rb_intern("sigma_is_A");
184
+ ecmp_sigma_is_A_id = rb_intern("go");
185
+ ecmp_B1done_id = rb_intern("B1done");
186
+ ecmp_B2min_id = rb_intern("B2min");
187
+ ecmp_B2_id = rb_intern("B2");
188
+ cECM_PARAMS = rb_define_class ("ECMParams", rb_cObject);
189
+
190
+ // Initialization Functions and Assignment Functions
191
+
192
+ rb_define_singleton_method (cECM_PARAMS, "new", r_ecmsg_new, -1);
193
+ //rb_define_method (cECM_PARAMS, "initialize", r_ecm_initialize, -1);
194
+
195
+ if (0) {
196
+ mGMP = rb_define_module("GMP");
197
+ cGMP_Z = rb_define_class_under(mGMP, "Z", rb_cInteger);
198
+ }
199
+ rb_define_method(cGMP_Z, "ecm_factor", r_ecm_factor, -1);
200
+ }
data/ext/extconf.rb ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mkmf'
4
+ dir_config('ecm')
5
+ ok = true
6
+
7
+ unless have_header('gmp.h')
8
+ $stderr.puts "can't find gmp.h, try --with-gmp-include=<path>"
9
+ ok = false
10
+ end
11
+
12
+ unless have_library('gmp', '__gmpz_init')
13
+ $stderr.puts "can't find -lgmp, try --with-gmp-lib=<path>"
14
+ ok = false
15
+ end
16
+
17
+ unless have_header('ecm.h')
18
+ $stderr.puts "can't find ecm.h, try --with-ecm-include=<path>"
19
+ ok = false
20
+ end
21
+
22
+ unless have_library('ecm', 'ecm_init')
23
+ $stderr.puts "can't find -lecm, try --with-ecm-lib=<path>"
24
+ ok = false
25
+ end
26
+
27
+ $CFLAGS += ' -Wall -W -O6 -g'
28
+
29
+ if not ok
30
+ raise "Unable to build, correct above errors and rerun"
31
+ end
32
+
33
+ create_makefile('ecm')
data/ext/ruby_ecm.h ADDED
@@ -0,0 +1,31 @@
1
+ #ifndef _RUBY_ECM_H_
2
+ #define _RUBY_ECM_H_
3
+
4
+ #include <stdio.h>
5
+ #include <ruby.h>
6
+ #ifndef _GNU_SOURCE
7
+ #define _GNU_SOURCE
8
+ #endif
9
+ #include <ruby_gmp.h>
10
+ #include <ecm.h>
11
+
12
+ #include <stdlib.h>
13
+
14
+ /*
15
+ * (a comment borrowed from the Ruby GMP bindings:)
16
+ * MP_???* is used because they don't have side-effects of single-element arrays ecm_params
17
+ */
18
+ typedef __ecm_param_struct ECM_PARAMS;
19
+
20
+ #define ecm_params_get_struct(ruby_var,c_var) { Data_Get_Struct(ruby_var, ECM_PARAMS, c_var); }
21
+ #define ecm_params_make_struct(ruby_var,c_var) { ruby_var = Data_Make_Struct(cECM_PARAMS, ECM_PARAMS, 0, r_ecm_params_free, c_var); }
22
+ #define ecm_params_make_struct_init(ruby_var,c_var) { ecm_params_make_struct(ruby_var,c_var); ecm_init (c_var); }
23
+ #define ECM_PARAMS_P(value) (rb_obj_is_instance_of(value,cECM_PARAMS) == Qtrue)
24
+
25
+ extern VALUE cECM_PARAMS;
26
+
27
+ extern void ecm_params_set_value(ECM_PARAMS *target, VALUE source);
28
+
29
+ extern void r_ecm_params_free(void *ptr);
30
+
31
+ #endif /* _RUBY_ECM_H_ */
data/ext/ruby_gmp.h ADDED
@@ -0,0 +1,343 @@
1
+ #ifndef _RUBY_GMP_H_
2
+ #define _RUBY_GMP_H_
3
+
4
+ #include <stdio.h>
5
+ #include <ruby.h>
6
+ #ifndef _GNU_SOURCE
7
+ #define _GNU_SOURCE
8
+ #endif
9
+ #include <gmp.h>
10
+ #include <mpfr.h>
11
+ #include <mpf2mpfr.h>
12
+
13
+ #include <stdlib.h>
14
+
15
+ /*
16
+ MP_INT*, MP_RAT* and MP_FLOAT* are used because they don't have side-effects
17
+ of single-element arrays mp*_t
18
+
19
+ MP_FLOAT is defined here, as it's commented out in gmp.h
20
+ */
21
+ typedef __mpfr_struct MP_FLOAT;
22
+
23
+ #if __GNU_MP_VERSION < 5
24
+ typedef unsigned long int mp_bitcnt_t;
25
+ #endif
26
+
27
+ /*
28
+ I don't like this solution, because in gmp.h, all of these typedefs are
29
+ marked with "gmp 1 source compatibility". :(.
30
+ */
31
+ typedef __gmp_randstate_struct MP_RANDSTATE;
32
+
33
+ #define mpz_get_struct(ruby_var,c_var) { Data_Get_Struct(ruby_var, MP_INT, c_var); }
34
+ #define mpq_get_struct(ruby_var,c_var) { Data_Get_Struct(ruby_var, MP_RAT, c_var); }
35
+ #define mpf_get_struct(ruby_var,c_var) { Data_Get_Struct(ruby_var, MP_FLOAT, c_var); }
36
+ #define mprandstate_get_struct(ruby_var,c_var) { Data_Get_Struct(ruby_var, MP_RANDSTATE, c_var); }
37
+ #define mpz_make_struct(ruby_var,c_var) { ruby_var = Data_Make_Struct(cGMP_Z, MP_INT, 0, r_gmpz_free, c_var); }
38
+ #define mpq_make_struct(ruby_var,c_var) { ruby_var = Data_Make_Struct(cGMP_Q, MP_RAT, 0, r_gmpq_free, c_var); }
39
+ #define mpf_make_struct(ruby_var,c_var) { ruby_var = Data_Make_Struct(cGMP_F, MP_FLOAT, 0, r_gmpf_free, c_var); }
40
+ #define mprandstate_make_struct(ruby_var,c_var) { ruby_var = Data_Make_Struct(cGMP_RandState, MP_RANDSTATE, 0, r_gmprandstate_free, c_var); }
41
+ #define mpz_make_struct_init(ruby_var,c_var) { mpz_make_struct(ruby_var,c_var); mpz_init (c_var); }
42
+ #define mpq_make_struct_init(ruby_var,c_var) { mpq_make_struct(ruby_var,c_var); mpq_init (c_var); }
43
+ #define BIGNUM_P(value) (TYPE(value) == T_BIGNUM)
44
+ #define FLOAT_P(value) (TYPE(value) == T_FLOAT)
45
+ #define STRING_P(value) (TYPE(value) == T_STRING)
46
+ #define ARRAY_P(value) (TYPE(value) == T_ARRAY)
47
+ #define GMPZ_P(value) (rb_obj_is_instance_of(value, cGMP_Z) == Qtrue)
48
+ #define GMPQ_P(value) (rb_obj_is_instance_of(value, cGMP_Q) == Qtrue)
49
+ #define GMPF_P(value) (rb_obj_is_instance_of(value, cGMP_F) == Qtrue)
50
+ #define mpz_set_bignum(var_mpz,var_bignum) { \
51
+ VALUE tmp = rb_funcall (rb_funcall (var_bignum, rb_intern ("to_s"), 1, INT2FIX(32)), rb_intern("upcase"), 0); \
52
+ mpz_set_str (var_mpz, StringValuePtr (tmp), 32); \
53
+ }
54
+ /*VALUE tmp = rb_funcall (var_bignum, rb_intern ("to_s"), 1, INT2FIX(32)); \*/
55
+ /*#define mpz_set_bignum(var_mpz,var_bignum) { \
56
+ VALUE tmp = rb_funcall (var_bignum, rb_intern ("to_s"), 0); \
57
+ mpz_set_str (var_mpz, StringValuePtr (tmp), 10); \
58
+ }*/
59
+ #define mpz_temp_alloc(var) { var=malloc(sizeof(MP_INT)); }
60
+ #define mpz_temp_init(var) { mpz_temp_alloc(var); mpz_init(var); }
61
+ #define mpz_temp_from_bignum(var,var_bignum) { \
62
+ mpz_temp_alloc(var); \
63
+ VALUE tmp = rb_funcall (var_bignum, rb_intern ("to_s"), 1, INT2FIX(32)); \
64
+ mpz_init_set_str (var, StringValuePtr (tmp), 32); \
65
+ }
66
+ #define mpz_temp_free(var) { mpz_clear(var); free(var); }
67
+ #define mpf_temp_alloc(var) { var=malloc(sizeof(MP_FLOAT)); }
68
+ #if defined(MPFR) && defined(HAVE_MPFR_H)
69
+ #define prec_max(prec,var) {if(mpfr_get_prec(var) > prec) prec = mpfr_get_prec(var); }
70
+ #else
71
+ #define prec_max(prec,var) {if(mpf_get_prec(var) > prec) prec = mpf_get_prec(var); }
72
+ #endif
73
+
74
+ #define mpf_get_struct_prec(ruby_var,c_var,prec) { mpf_get_struct(ruby_var,c_var); prec = mpfr_get_prec(c_var); }
75
+ #define mpf_make_struct_init(ruby_var,c_var,prec) { mpf_make_struct(ruby_var,c_var); mpfr_init2 (c_var,prec); }
76
+ #define mpf_temp_init(var,prec) { mpf_temp_alloc(var); mpfr_init2(var,prec); }
77
+ #define mpf_temp_free(var) { mpfr_clear(var); free(var); }
78
+ #define r_mpf_init(var1) (mpfr_init(var1))
79
+ #define r_mpf_init2(var1, var2) (mpfr_init2(var1, var2))
80
+ #define r_mpf_set_z(var1, var2) (mpfr_set_z(var1, var2, __gmp_default_rounding_mode))
81
+ #define r_mpf_set_q(var1, var2) (mpfr_set_q(var1, var2, __gmp_default_rounding_mode))
82
+ #define r_mpf_set_d(var1, var2) (mpfr_set_d(var1, var2, __gmp_default_rounding_mode))
83
+ #define r_mpf_set_str(var1, var2, var3) (mpfr_set_str(var1, var2, var3, __gmp_default_rounding_mode))
84
+ #define r_mpf_cmp(var1, var2) (mpfr_cmp(var1, var2))
85
+
86
+ #ifdef FIXNUM_WIDTH /* RBX check */
87
+ #if (((8*SIZEOF_INTPTR_T) - TAG_FIXNUM_SHIFT -1) == 63) /* 64-bit */
88
+ #define FIX2NUM(x) FIX2LONG(x)
89
+ #else /* 32-bit */
90
+ #define FIX2NUM(x) FIX2INT(x)
91
+ #endif
92
+ #else /* RBX check */
93
+ #if SIZEOF_INT < SIZEOF_LONG /* 64-bit */
94
+ #define FIX2NUM(x) FIX2LONG(x)
95
+ #else /* 32-bit */
96
+ #define FIX2NUM(x) FIX2INT(x)
97
+ #endif /* MRI's 32-vs-64 check */
98
+ #endif /* RBX check */
99
+
100
+ #define EXPECTED_ZQFXBD "Expected GMP::Z, GMP::Q, GMP::F, Fixnum, Bignum or Float"
101
+ #define EXPECTED_ZQFXB "Expected GMP::Z, GMP::Q, GMP::F, Fixnum or Bignum"
102
+ #define EXPECTED_ZFXBD "Expected GMP::Z, GMP::F, Fixnum, Bignum or Float"
103
+ #define EXPECTED_ZXB "Expected GMP::Z, Fixnum or Bignum"
104
+ #define EXPECTED_ZX "Expected GMP::Z or Fixnum"
105
+ #define EXPECTED_X "Expected Fixnum"
106
+ #define EXPECTED_Z "Expected GMP::Z"
107
+ #define EXPECTED_FD "Expected GMP::F or Float"
108
+ #define typeerror(expected) rb_raise(rb_eTypeError, EXPECTED_##expected)
109
+ #define typeerror_as(expected, argname) rb_raise(rb_eTypeError, EXPECTED_##expected " as " argname)
110
+
111
+ //should change exception type
112
+ #define not_yet rb_raise(rb_eTypeError,"Not implemented yet")
113
+
114
+ #define mprnd_get_struct(ruby_var,c_var) { Data_Get_Struct(ruby_var, int, c_var); }
115
+ #define mprnd_make_struct(ruby_var,c_var) { ruby_var = Data_Make_Struct(cGMP_Rnd, int, 0, 0, c_var); }
116
+ #define GMPRND_P(value) (rb_obj_is_instance_of(value, cGMP_Rnd) == Qtrue)
117
+
118
+ extern VALUE mGMP, cGMP_Z, cGMP_Q, cGMP_F, cGMP_RandState;
119
+ extern VALUE cGMP_Rnd;
120
+
121
+ extern void r_gmpz_free(void *ptr);
122
+ extern void r_gmpq_free(void *ptr);
123
+ extern void r_gmpf_free(void *ptr);
124
+ extern void r_gmprandstate_free(void *ptr);
125
+
126
+
127
+ /* from gmpz.h */
128
+
129
+ // Initializing, Assigning Integers
130
+ extern VALUE r_gmpzsg_new(int argc, VALUE *argv, VALUE klass);
131
+ extern VALUE r_gmpz_initialize(int argc, VALUE *argv, VALUE self);
132
+ extern void mpz_set_value(MP_INT *target, VALUE source);
133
+ extern VALUE r_gmpmod_z(int argc, VALUE *argv, VALUE module);
134
+ extern VALUE r_gmpz_swap(VALUE self, VALUE arg);
135
+
136
+ // Converting Integers
137
+ extern VALUE r_gmpz_to_i(VALUE self);
138
+ extern VALUE r_gmpz_to_d(VALUE self);
139
+ extern VALUE r_gmpz_to_s(int argc, VALUE *argv, VALUE self);
140
+
141
+ // Integer Arithmetic
142
+ extern VALUE r_gmpz_add(VALUE self, VALUE arg);
143
+ extern VALUE r_gmpz_add_self(VALUE self, VALUE arg);
144
+ extern VALUE r_gmpz_sub(VALUE self, VALUE arg);
145
+ extern VALUE r_gmpz_sub_self(VALUE self, VALUE arg);
146
+ extern VALUE r_gmpz_mul(VALUE self, VALUE arg);
147
+ extern VALUE r_gmpz_div(VALUE self, VALUE arg);
148
+
149
+ // Integer Division
150
+ extern VALUE r_gmpz_mod(VALUE self, VALUE arg);
151
+
152
+ // Integer Exponentiation
153
+ extern VALUE r_gmpzsg_pow(VALUE klass, VALUE base, VALUE exp);
154
+ extern VALUE r_gmpz_powm(VALUE self, VALUE exp, VALUE mod);
155
+
156
+ // Integer Roots
157
+
158
+ // Number Theoretic Functions
159
+ extern VALUE r_gmpz_is_probab_prime(int argc, VALUE* argv, VALUE self);
160
+ extern VALUE r_gmpz_gcd(VALUE self, VALUE arg);
161
+ extern VALUE r_gmpz_invert(VALUE self, VALUE arg);
162
+ extern VALUE r_gmpz_jacobi(VALUE self, VALUE b);
163
+ extern VALUE r_gmpzsg_jacobi(VALUE klass, VALUE a, VALUE b);
164
+ extern VALUE r_gmpz_legendre(VALUE self, VALUE p);
165
+ extern VALUE r_gmpz_remove(VALUE self, VALUE arg);
166
+
167
+ // Integer Comparisons
168
+ extern VALUE r_gmpz_eq(VALUE self, VALUE arg);
169
+ extern VALUE r_gmpz_cmp(VALUE self, VALUE arg);
170
+ extern VALUE r_gmpz_cmpabs(VALUE self, VALUE arg);
171
+ extern VALUE r_gmpz_sgn(VALUE self);
172
+ extern int mpz_cmp_value(MP_INT *OP, VALUE arg);
173
+
174
+ // Integer Logic and Bit Fiddling
175
+ extern VALUE r_gmpz_popcount(VALUE self);
176
+ extern VALUE r_gmpz_scan0(VALUE self, VALUE bitnr);
177
+ extern VALUE r_gmpz_scan1(VALUE self, VALUE bitnr);
178
+ extern VALUE r_gmpz_setbit(VALUE self, VALUE bitnr, VALUE set_to);
179
+ extern VALUE r_gmpz_getbit(VALUE self, VALUE bitnr);
180
+
181
+ // Miscelaneous Integer Functions
182
+ extern VALUE r_gmpz_sizeinbase(VALUE self, VALUE base);
183
+ extern VALUE r_gmpz_size_in_bin(VALUE self);
184
+
185
+
186
+ /* from gmpq.h */
187
+
188
+ // Initializing Rationals
189
+ extern VALUE r_gmpqsg_new(int argc, VALUE *argv, VALUE klass);
190
+ extern VALUE r_gmpq_initialize(int argc, VALUE *argv, VALUE self);
191
+ extern VALUE r_gmpmod_q(int argc, VALUE *argv, VALUE module);
192
+ extern VALUE r_gmpq_swap(VALUE self, VALUE arg);
193
+
194
+ // Rational Conversions
195
+ extern VALUE r_gmpq_to_d(VALUE self);
196
+ extern VALUE r_gmpq_to_s(VALUE self);
197
+
198
+ // Rational Arithmetic
199
+ extern VALUE r_gmpq_add(VALUE self, VALUE arg);
200
+ extern VALUE r_gmpq_sub(VALUE self, VALUE arg);
201
+ extern VALUE r_gmpq_mul(VALUE self, VALUE arg);
202
+ extern VALUE r_gmpq_div(VALUE self, VALUE arg);
203
+ extern VALUE r_gmpq_inv(VALUE self);
204
+ extern VALUE r_gmpq_inv_self(VALUE self);
205
+
206
+ // Comparing Rationals
207
+ extern VALUE r_gmpq_eq(VALUE self, VALUE arg);
208
+ extern VALUE r_gmpq_cmp(VALUE self, VALUE arg);
209
+ extern int mpq_cmp_value(MP_RAT *OP, VALUE arg);
210
+ extern VALUE r_gmpq_sgn(VALUE self);
211
+
212
+ // Applying Integer Functions
213
+ extern VALUE r_gmpq_num(VALUE self);
214
+ extern VALUE r_gmpq_den(VALUE self);
215
+
216
+ // _unsorted_
217
+
218
+
219
+ /* from gmpf.h */
220
+
221
+ // Initializing, Assigning Floats
222
+ extern VALUE r_gmpfsg_new(int argc, VALUE *argv, VALUE klass);
223
+ extern VALUE r_gmpf_initialize(int argc, VALUE *argv, VALUE self);
224
+ extern void mpf_set_value(MP_FLOAT *self_val, VALUE arg);
225
+ extern VALUE r_gmpmod_f(int argc, VALUE *argv, VALUE module);
226
+ extern VALUE r_gmpf_get_prec(VALUE self);
227
+ extern VALUE r_gmpf_set_prec(VALUE self, VALUE arg);
228
+ extern VALUE r_gmpf_set_prec_raw(VALUE self, VALUE arg);
229
+
230
+ // Converting Floats
231
+ extern VALUE r_gmpf_to_d(VALUE self);
232
+ extern VALUE r_gmpf_to_s(VALUE self);
233
+
234
+ // Float Arithmetic
235
+ extern VALUE r_gmpf_add(VALUE self, VALUE arg);
236
+ extern VALUE r_gmpf_mul(VALUE self, VALUE arg);
237
+ extern VALUE r_gmpf_sub(VALUE self, VALUE arg);
238
+ extern VALUE r_gmpf_div(VALUE self, VALUE arg);
239
+
240
+ // Float Comparison
241
+ extern VALUE r_gmpf_eq(VALUE self, VALUE arg);
242
+ extern VALUE r_gmpf_cmp(VALUE self, VALUE arg);
243
+ extern int mpf_cmp_value(MP_FLOAT *OP, VALUE arg);
244
+
245
+ // MPFR
246
+ extern void mpf_set_value2(MP_FLOAT *self_val, VALUE arg, int base);
247
+
248
+ extern VALUE r_gmpfr_sqrt(int argc, VALUE *argv, VALUE self);
249
+ extern VALUE r_gmpfr_rec_sqrt(int argc, VALUE *argv, VALUE self);
250
+ extern VALUE r_gmpfr_cbrt(int argc, VALUE *argv, VALUE self);
251
+
252
+ extern VALUE r_gmpfr_log(int argc, VALUE *argv, VALUE self);
253
+ extern VALUE r_gmpfr_log2(int argc, VALUE *argv, VALUE self);
254
+ extern VALUE r_gmpfr_log10(int argc, VALUE *argv, VALUE self);
255
+ extern VALUE r_gmpfr_exp(int argc, VALUE *argv, VALUE self);
256
+ extern VALUE r_gmpfr_exp2(int argc, VALUE *argv, VALUE self);
257
+ extern VALUE r_gmpfr_exp10(int argc, VALUE *argv, VALUE self);
258
+ extern VALUE r_gmpfr_cos(int argc, VALUE *argv, VALUE self);
259
+ extern VALUE r_gmpfr_sin(int argc, VALUE *argv, VALUE self);
260
+ extern VALUE r_gmpfr_tan(int argc, VALUE *argv, VALUE self);
261
+ extern VALUE r_gmpfr_sec(int argc, VALUE *argv, VALUE self);
262
+ extern VALUE r_gmpfr_csc(int argc, VALUE *argv, VALUE self);
263
+ extern VALUE r_gmpfr_cot(int argc, VALUE *argv, VALUE self);
264
+
265
+ extern VALUE r_gmpfr_acos(int argc, VALUE *argv, VALUE self);
266
+ extern VALUE r_gmpfr_asin(int argc, VALUE *argv, VALUE self);
267
+ extern VALUE r_gmpfr_atan(int argc, VALUE *argv, VALUE self);
268
+
269
+ extern VALUE r_gmpfr_cosh(int argc, VALUE *argv, VALUE self);
270
+ extern VALUE r_gmpfr_sinh(int argc, VALUE *argv, VALUE self);
271
+ extern VALUE r_gmpfr_tanh(int argc, VALUE *argv, VALUE self);
272
+
273
+ extern VALUE r_gmpfr_sech(int argc, VALUE *argv, VALUE self);
274
+ extern VALUE r_gmpfr_csch(int argc, VALUE *argv, VALUE self);
275
+ extern VALUE r_gmpfr_coth(int argc, VALUE *argv, VALUE self);
276
+ extern VALUE r_gmpfr_acosh(int argc, VALUE *argv, VALUE self);
277
+ extern VALUE r_gmpfr_asinh(int argc, VALUE *argv, VALUE self);
278
+ extern VALUE r_gmpfr_atanh(int argc, VALUE *argv, VALUE self);
279
+
280
+ extern VALUE r_gmpfr_log1p(int argc, VALUE *argv, VALUE self);
281
+ extern VALUE r_gmpfr_expm1(int argc, VALUE *argv, VALUE self);
282
+ extern VALUE r_gmpfr_eint(int argc, VALUE *argv, VALUE self);
283
+ extern VALUE r_gmpfr_li2(int argc, VALUE *argv, VALUE self);
284
+ extern VALUE r_gmpfr_gamma(int argc, VALUE *argv, VALUE self);
285
+ extern VALUE r_gmpfr_lngamma(int argc, VALUE *argv, VALUE self);
286
+ /*extern VALUE r_gmpfr_lgamma(int argc, VALUE *argv, VALUE self);*/
287
+ #if MPFR_VERSION_MAJOR > 2
288
+ extern VALUE r_gmpfr_digamma(int argc, VALUE *argv, VALUE self);
289
+ #endif
290
+ extern VALUE r_gmpfr_zeta(int argc, VALUE *argv, VALUE self);
291
+ extern VALUE r_gmpfr_erf(int argc, VALUE *argv, VALUE self);
292
+ extern VALUE r_gmpfr_erfc(int argc, VALUE *argv, VALUE self);
293
+ extern VALUE r_gmpfr_j0(int argc, VALUE *argv, VALUE self);
294
+ extern VALUE r_gmpfr_j1(int argc, VALUE *argv, VALUE self);
295
+ extern VALUE r_gmpfr_jn(int argc, VALUE *argv, VALUE self);
296
+ extern VALUE r_gmpfr_y0(int argc, VALUE *argv, VALUE self);
297
+ extern VALUE r_gmpfr_y1(int argc, VALUE *argv, VALUE self);
298
+
299
+ extern VALUE r_gmpfrsg_const_log2();
300
+ extern VALUE r_gmpfrsg_const_pi();
301
+ extern VALUE r_gmpfrsg_const_euler();
302
+ extern VALUE r_gmpfrsg_const_catalan();
303
+
304
+ extern mp_rnd_t r_get_rounding_mode(VALUE rnd);
305
+
306
+ // _unsorted_
307
+ extern VALUE r_gmpf_sgn(VALUE self);
308
+
309
+
310
+ /* from gmprandstate.h */
311
+
312
+ // Random State Initialization
313
+ extern VALUE r_gmprandstatesg_new(int argc, VALUE *argv, VALUE klass);
314
+ extern VALUE r_gmprandstate_initialize(int argc, VALUE *argv, VALUE self);
315
+ extern VALUE r_gmpmod_randstate(int argc, VALUE *argv, VALUE module);
316
+
317
+ // Random State Seeding
318
+ extern VALUE r_gmprandstate_seed(VALUE self, VALUE arg);
319
+
320
+ // Integer Random Numbers
321
+ extern VALUE r_gmprandstate_urandomb(VALUE self, VALUE arg);
322
+ extern VALUE r_gmprandstate_urandomm(VALUE self, VALUE arg);
323
+
324
+ // Float Random Numbers
325
+ extern VALUE r_gmprandstate_mpfr_urandomb(int argc, VALUE *argv, VALUE self);
326
+
327
+
328
+ /* from gmpbench_timing.c */
329
+
330
+ // GMPbench Timing
331
+ extern VALUE r_gmpmod_cputime(VALUE self);
332
+ extern VALUE r_gmpmod_time(VALUE self);
333
+
334
+
335
+
336
+ extern void init_gmpz();
337
+ extern void init_gmpq();
338
+ extern void init_gmpf();
339
+ extern void init_gmprandstate();
340
+ extern void init_gmpbench_timing();
341
+ extern void init_gmprnd();
342
+
343
+ #endif
data/lib/ecm.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'gmp'
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'ext', 'ecm')
@@ -0,0 +1,43 @@
1
+ # I'm having trouble coming up with decent unit tests, so for now... sanity tests!
2
+ require File.join(File.dirname(__FILE__), 'spec_helper')
3
+
4
+ describe ECMParams, "new" do
5
+ before do
6
+ @z = GMP::Z(2)**255 - 1
7
+ @z2 = GMP::Z("2050449353925555290706354283")
8
+ @z3 = GMP::Z("212252637915375215854013140804296246361")
9
+ end
10
+
11
+ it "should allow a missing ECMParams" do
12
+ @z.ecm_factor(1_000_000)
13
+ end
14
+
15
+ it "should allow a simple hash with :method" do
16
+ @z.ecm_factor(1_000_000, :method => :ECM_ECM)
17
+ @z.ecm_factor(1_000_000, :method => :ECM_PM1)
18
+ @z.ecm_factor(1_000_000, :method => :ECM_PP1)
19
+ end
20
+
21
+ it "should allow a simple hash with :x" do
22
+ @z.ecm_factor(1_000_000, :z => GMP::Z(1_000))
23
+ end
24
+
25
+ it "should allow a simple hash with :sigma" do
26
+ @z2.ecm_factor 1_000_000, :sigma => 7
27
+ @z2.ecm_factor 1_000_000, :sigma => GMP::Z(7)
28
+ end
29
+
30
+ it "should allow a simple hash with :sigma_is_A" do
31
+ @z2.ecm_factor 1_000_000, :sigma_is_A => 1
32
+ @z2.ecm_factor 1_000_000, :sigma_is_A => 0
33
+ @z2.ecm_factor 1_000_000, :sigma_is_A => -1
34
+ end
35
+
36
+ it "should allow a simple hash with :go" do
37
+ @z3.ecm_factor 1_000_000, :sigma => GMP::Z(781683988), :go => GMP::Z(550232165123)
38
+ end
39
+
40
+ it "should allow a simple hash with :B1done" do
41
+ @z3.ecm_factor 1_000_000, :sigma => GMP::Z(781683988), :go => GMP::Z(550232165123), :B1done => 1000.0
42
+ end
43
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'ecm')
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gmp_ecm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - srawlins
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: gmp
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: gmp_ecm - Elliptic Curve Method Factorization on GMP::Z integers
31
+ email:
32
+ - sam.rawlins@gmail.com
33
+ executables: []
34
+ extensions:
35
+ - ext/extconf.rb
36
+ extra_rdoc_files: []
37
+ files:
38
+ - ext/ecm.c
39
+ - ext/ruby_ecm.h
40
+ - ext/ruby_gmp.h
41
+ - ext/extconf.rb
42
+ - lib/ecm.rb
43
+ - spec/sanity_spec.rb
44
+ - spec/spec_helper.rb
45
+ - README.md
46
+ - COPYING.md
47
+ - Gemfile
48
+ - Guardfile
49
+ homepage: http://github.com/srawlins/gmp-ecm
50
+ licenses: []
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: 1.8.7
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements:
68
+ - GMP-ECM compiled and working properly.
69
+ rubyforge_project:
70
+ rubygems_version: 1.8.24
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Provides Ruby bindings to the GMP-ECM library.
74
+ test_files: []
75
+ has_rdoc: yard