1/*
2 * $Id: ossl_bn.c 40113 2013-04-04 15:56:00Z nagachika $
3 * 'OpenSSL for Ruby' project
4 * Copyright (C) 2001-2002  Technorama team <oss-ruby@technorama.net>
5 * All rights reserved.
6 */
7/*
8 * This program is licenced under the same licence as Ruby.
9 * (See the file 'LICENCE'.)
10 */
11/* modified by Michal Rokos <m.rokos@sh.cvut.cz> */
12#include "ossl.h"
13
14#define WrapBN(klass, obj, bn) do { \
15  if (!(bn)) { \
16    ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
17  } \
18  (obj) = Data_Wrap_Struct((klass), 0, BN_clear_free, (bn)); \
19} while (0)
20
21#define GetBN(obj, bn) do { \
22  Data_Get_Struct((obj), BIGNUM, (bn)); \
23  if (!(bn)) { \
24    ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
25  } \
26} while (0)
27
28#define SafeGetBN(obj, bn) do { \
29  OSSL_Check_Kind((obj), cBN); \
30  GetBN((obj), (bn)); \
31} while (0)
32
33/*
34 * Classes
35 */
36VALUE cBN;
37VALUE eBNError;
38
39/*
40 * Public
41 */
42VALUE
43ossl_bn_new(const BIGNUM *bn)
44{
45    BIGNUM *newbn;
46    VALUE obj;
47
48    newbn = bn ? BN_dup(bn) : BN_new();
49    if (!newbn) {
50	ossl_raise(eBNError, NULL);
51    }
52    WrapBN(cBN, obj, newbn);
53
54    return obj;
55}
56
57BIGNUM *
58GetBNPtr(VALUE obj)
59{
60    BIGNUM *bn = NULL;
61
62    if (RTEST(rb_obj_is_kind_of(obj, cBN))) {
63	GetBN(obj, bn);
64    } else switch (TYPE(obj)) {
65    case T_FIXNUM:
66    case T_BIGNUM:
67	obj = rb_String(obj);
68	if (!BN_dec2bn(&bn, StringValuePtr(obj))) {
69	    ossl_raise(eBNError, NULL);
70	}
71	WrapBN(cBN, obj, bn); /* Handle potencial mem leaks */
72	break;
73    case T_NIL:
74	break;
75    default:
76	ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
77    }
78    return bn;
79}
80
81/*
82 * Private
83 */
84/*
85 * BN_CTX - is used in more difficult math. ops
86 * (Why just 1? Because Ruby itself isn't thread safe,
87 *  we don't need to care about threads)
88 */
89BN_CTX *ossl_bn_ctx;
90
91static VALUE
92ossl_bn_alloc(VALUE klass)
93{
94    BIGNUM *bn;
95    VALUE obj;
96
97    if (!(bn = BN_new())) {
98	ossl_raise(eBNError, NULL);
99    }
100    WrapBN(klass, obj, bn);
101
102    return obj;
103}
104
105/*
106 * call-seq:
107 *    BN.new => aBN
108 *    BN.new(bn) => aBN
109 *    BN.new(string) => aBN
110 *    BN.new(string, 0 | 2 | 10 | 16) => aBN
111 */
112static VALUE
113ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
114{
115    BIGNUM *bn;
116    VALUE str, bs;
117    int base = 10;
118
119    if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
120	base = NUM2INT(bs);
121    }
122
123    if (RTEST(rb_obj_is_kind_of(str, cBN))) {
124	BIGNUM *other;
125
126	GetBN(self, bn);
127	GetBN(str, other); /* Safe - we checked kind_of? above */
128	if (!BN_copy(bn, other)) {
129	    ossl_raise(eBNError, NULL);
130	}
131	return self;
132    }
133
134    StringValue(str);
135    GetBN(self, bn);
136    switch (base) {
137    case 0:
138	if (!BN_mpi2bn((unsigned char *)RSTRING_PTR(str), RSTRING_LENINT(str), bn)) {
139	    ossl_raise(eBNError, NULL);
140	}
141	break;
142    case 2:
143	if (!BN_bin2bn((unsigned char *)RSTRING_PTR(str), RSTRING_LENINT(str), bn)) {
144	    ossl_raise(eBNError, NULL);
145	}
146	break;
147    case 10:
148	if (!BN_dec2bn(&bn, RSTRING_PTR(str))) {
149	    ossl_raise(eBNError, NULL);
150	}
151	break;
152    case 16:
153	if (!BN_hex2bn(&bn, RSTRING_PTR(str))) {
154	    ossl_raise(eBNError, NULL);
155	}
156	break;
157    default:
158	ossl_raise(rb_eArgError, "invalid radix %d", base);
159    }
160    return self;
161}
162
163/*
164 * call-seq:
165 *    bn.to_s => string
166 *    bn.to_s(base) => string
167 *
168 * === Parameters
169 * * +base+ - integer
170 * * * Valid values:
171 * * * * 0 - MPI
172 * * * * 2 - binary
173 * * * * 10 - the default
174 * * * * 16 - hex
175 */
176static VALUE
177ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
178{
179    BIGNUM *bn;
180    VALUE str, bs;
181    int base = 10, len;
182    char *buf;
183
184    if (rb_scan_args(argc, argv, "01", &bs) == 1) {
185	base = NUM2INT(bs);
186    }
187    GetBN(self, bn);
188    switch (base) {
189    case 0:
190	len = BN_bn2mpi(bn, NULL);
191        str = rb_str_new(0, len);
192	if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
193	    ossl_raise(eBNError, NULL);
194	break;
195    case 2:
196	len = BN_num_bytes(bn);
197        str = rb_str_new(0, len);
198	if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
199	    ossl_raise(eBNError, NULL);
200	break;
201    case 10:
202	if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
203	str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
204	break;
205    case 16:
206	if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
207	str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
208	break;
209    default:
210	ossl_raise(rb_eArgError, "invalid radix %d", base);
211    }
212
213    return str;
214}
215
216/*
217 * call-seq:
218 *    bn.to_i => integer
219 */
220static VALUE
221ossl_bn_to_i(VALUE self)
222{
223    BIGNUM *bn;
224    char *txt;
225    VALUE num;
226
227    GetBN(self, bn);
228
229    if (!(txt = BN_bn2dec(bn))) {
230	ossl_raise(eBNError, NULL);
231    }
232    num = rb_cstr_to_inum(txt, 10, Qtrue);
233    OPENSSL_free(txt);
234
235    return num;
236}
237
238static VALUE
239ossl_bn_to_bn(VALUE self)
240{
241    return self;
242}
243
244static VALUE
245ossl_bn_coerce(VALUE self, VALUE other)
246{
247    switch(TYPE(other)) {
248    case T_STRING:
249	self = ossl_bn_to_s(0, NULL, self);
250	break;
251    case T_FIXNUM:
252    case T_BIGNUM:
253	self = ossl_bn_to_i(self);
254	break;
255    default:
256	if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
257	    ossl_raise(rb_eTypeError, "Don't know how to coerce");
258	}
259    }
260    return rb_assoc_new(other, self);
261}
262
263#define BIGNUM_BOOL1(func)				\
264    /*							\
265     * call-seq:					\
266     *   bn.##func -> true | false			\
267     *							\
268     */							\
269    static VALUE					\
270    ossl_bn_##func(VALUE self)				\
271    {							\
272	BIGNUM *bn;					\
273	GetBN(self, bn);				\
274	if (BN_##func(bn)) {				\
275	    return Qtrue;				\
276	}						\
277	return Qfalse;					\
278    }
279BIGNUM_BOOL1(is_zero)
280BIGNUM_BOOL1(is_one)
281BIGNUM_BOOL1(is_odd)
282
283#define BIGNUM_1c(func)					\
284    /*							\
285     * call-seq:					\
286     *   bn.##func -> aBN				\
287     *							\
288     */							\
289    static VALUE					\
290    ossl_bn_##func(VALUE self)				\
291    {							\
292	BIGNUM *bn, *result;				\
293	VALUE obj;					\
294	GetBN(self, bn);				\
295	if (!(result = BN_new())) {			\
296	    ossl_raise(eBNError, NULL);			\
297	}						\
298	if (!BN_##func(result, bn, ossl_bn_ctx)) {	\
299	    BN_free(result);				\
300	    ossl_raise(eBNError, NULL);			\
301	}						\
302	WrapBN(CLASS_OF(self), obj, result);		\
303	return obj;					\
304    }
305BIGNUM_1c(sqr)
306
307#define BIGNUM_2(func)					\
308    /*							\
309     * call-seq:					\
310     *   bn.##func(bn2) -> aBN				\
311     *							\
312     */							\
313    static VALUE					\
314    ossl_bn_##func(VALUE self, VALUE other)		\
315    {							\
316	BIGNUM *bn1, *bn2 = GetBNPtr(other), *result;	\
317	VALUE obj;					\
318	GetBN(self, bn1);				\
319	if (!(result = BN_new())) {			\
320	    ossl_raise(eBNError, NULL);			\
321	}						\
322	if (!BN_##func(result, bn1, bn2)) {		\
323	    BN_free(result);				\
324	    ossl_raise(eBNError, NULL);			\
325	}						\
326	WrapBN(CLASS_OF(self), obj, result);		\
327	return obj;					\
328    }
329BIGNUM_2(add)
330BIGNUM_2(sub)
331
332#define BIGNUM_2c(func)						\
333    /*								\
334     * call-seq:						\
335     *   bn.##func(bn2) -> aBN					\
336     *								\
337     */								\
338    static VALUE						\
339    ossl_bn_##func(VALUE self, VALUE other)			\
340    {								\
341	BIGNUM *bn1, *bn2 = GetBNPtr(other), *result;		\
342	VALUE obj;						\
343	GetBN(self, bn1);					\
344	if (!(result = BN_new())) {				\
345	    ossl_raise(eBNError, NULL);				\
346	}							\
347	if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) {	\
348	    BN_free(result);					\
349	    ossl_raise(eBNError, NULL);				\
350	}							\
351	WrapBN(CLASS_OF(self), obj, result);			\
352	return obj;						\
353    }
354BIGNUM_2c(mul)
355BIGNUM_2c(mod)
356BIGNUM_2c(exp)
357BIGNUM_2c(gcd)
358BIGNUM_2c(mod_sqr)
359BIGNUM_2c(mod_inverse)
360
361/*
362 * call-seq:
363 *    bn1 / bn2 => [result, remainder]
364 */
365static VALUE
366ossl_bn_div(VALUE self, VALUE other)
367{
368    BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2;
369    VALUE obj1, obj2;
370
371    GetBN(self, bn1);
372
373    if (!(r1 = BN_new())) {
374	ossl_raise(eBNError, NULL);
375    }
376    if (!(r2 = BN_new())) {
377	BN_free(r1);
378	ossl_raise(eBNError, NULL);
379    }
380    if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {
381	BN_free(r1);
382	BN_free(r2);
383	ossl_raise(eBNError, NULL);
384    }
385    WrapBN(CLASS_OF(self), obj1, r1);
386    WrapBN(CLASS_OF(self), obj2, r2);
387
388    return rb_ary_new3(2, obj1, obj2);
389}
390
391#define BIGNUM_3c(func)						\
392    /*								\
393     * call-seq:						\
394     *   bn.##func(bn1, bn2) -> aBN				\
395     *								\
396     */								\
397    static VALUE						\
398    ossl_bn_##func(VALUE self, VALUE other1, VALUE other2)	\
399    {								\
400	BIGNUM *bn1, *bn2 = GetBNPtr(other1);			\
401	BIGNUM *bn3 = GetBNPtr(other2), *result;		\
402	VALUE obj;						\
403	GetBN(self, bn1);					\
404	if (!(result = BN_new())) {				\
405	    ossl_raise(eBNError, NULL);				\
406	}							\
407	if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) {	\
408	    BN_free(result);					\
409	    ossl_raise(eBNError, NULL);				\
410	}							\
411	WrapBN(CLASS_OF(self), obj, result);			\
412	return obj;						\
413    }
414BIGNUM_3c(mod_add)
415BIGNUM_3c(mod_sub)
416BIGNUM_3c(mod_mul)
417BIGNUM_3c(mod_exp)
418
419#define BIGNUM_BIT(func)				\
420    /*							\
421     * call-seq:					\
422     *   bn.##func(bit) -> self				\
423     *							\
424     */							\
425    static VALUE					\
426    ossl_bn_##func(VALUE self, VALUE bit)		\
427    {							\
428	BIGNUM *bn;					\
429	GetBN(self, bn);				\
430	if (!BN_##func(bn, NUM2INT(bit))) {		\
431	    ossl_raise(eBNError, NULL);			\
432	}						\
433	return self;					\
434    }
435BIGNUM_BIT(set_bit)
436BIGNUM_BIT(clear_bit)
437BIGNUM_BIT(mask_bits)
438
439/*
440 * call-seq:
441 *    bn.bit_set?(bit) => true | false
442 */
443static VALUE
444ossl_bn_is_bit_set(VALUE self, VALUE bit)
445{
446    int b;
447    BIGNUM *bn;
448
449    b = NUM2INT(bit);
450    GetBN(self, bn);
451    if (BN_is_bit_set(bn, b)) {
452	return Qtrue;
453    }
454    return Qfalse;
455}
456
457#define BIGNUM_SHIFT(func)				\
458    /*							\
459     * call-seq:					\
460     *   bn.##func(bits) -> aBN				\
461     *							\
462     */							\
463    static VALUE					\
464    ossl_bn_##func(VALUE self, VALUE bits)		\
465    {							\
466	BIGNUM *bn, *result;				\
467	int b;						\
468	VALUE obj;					\
469	b = NUM2INT(bits);				\
470	GetBN(self, bn);				\
471	if (!(result = BN_new())) {			\
472		ossl_raise(eBNError, NULL);		\
473	}						\
474	if (!BN_##func(result, bn, b)) {		\
475		BN_free(result);			\
476		ossl_raise(eBNError, NULL);		\
477	}						\
478	WrapBN(CLASS_OF(self), obj, result);		\
479	return obj;					\
480    }
481BIGNUM_SHIFT(lshift)
482BIGNUM_SHIFT(rshift)
483
484#define BIGNUM_SELF_SHIFT(func)				\
485    /*							\
486     * call-seq:					\
487     *   bn.##func!(bits) -> self			\
488     *							\
489     */							\
490    static VALUE					\
491    ossl_bn_self_##func(VALUE self, VALUE bits)		\
492    {							\
493	BIGNUM *bn;					\
494	int b;						\
495	b = NUM2INT(bits);				\
496	GetBN(self, bn);				\
497	if (!BN_##func(bn, bn, b))			\
498		ossl_raise(eBNError, NULL);		\
499	return self;					\
500    }
501BIGNUM_SELF_SHIFT(lshift)
502BIGNUM_SELF_SHIFT(rshift)
503
504#define BIGNUM_RAND(func)					\
505    /*								\
506     * call-seq:						\
507     *   BN.##func(bits [, fill [, odd]]) -> aBN		\
508     *								\
509     */								\
510    static VALUE						\
511    ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass)	\
512    {								\
513	BIGNUM *result;						\
514	int bottom = 0, top = 0, b;				\
515	VALUE bits, fill, odd, obj;				\
516								\
517	switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) {	\
518	case 3:							\
519	    bottom = (odd == Qtrue) ? 1 : 0;			\
520	    /* FALLTHROUGH */					\
521	case 2:							\
522	    top = NUM2INT(fill);				\
523	}							\
524	b = NUM2INT(bits);					\
525	if (!(result = BN_new())) {				\
526	    ossl_raise(eBNError, NULL);				\
527	}							\
528	if (!BN_##func(result, b, top, bottom)) {		\
529	    BN_free(result);					\
530	    ossl_raise(eBNError, NULL);				\
531	}							\
532	WrapBN(klass, obj, result);				\
533	return obj;						\
534    }
535BIGNUM_RAND(rand)
536BIGNUM_RAND(pseudo_rand)
537
538#define BIGNUM_RAND_RANGE(func)					\
539    /*								\
540     * call-seq:						\
541     *   BN.##func(range) -> aBN				\
542     *								\
543     */								\
544    static VALUE						\
545    ossl_bn_s_##func##_range(VALUE klass, VALUE range)		\
546    {								\
547	BIGNUM *bn = GetBNPtr(range), *result;			\
548	VALUE obj;						\
549	if (!(result = BN_new())) {				\
550	    ossl_raise(eBNError, NULL);				\
551	}							\
552	if (!BN_##func##_range(result, bn)) {			\
553	    BN_free(result);					\
554	    ossl_raise(eBNError, NULL);				\
555	}							\
556	WrapBN(klass, obj, result);				\
557	return obj;						\
558    }
559BIGNUM_RAND_RANGE(rand)
560BIGNUM_RAND_RANGE(pseudo_rand)
561
562/*
563 * call-seq:
564 *    BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn
565 *
566 * === Parameters
567 * * +bits+ - integer
568 * * +safe+ - boolean
569 * * +add+ - BN
570 * * +rem+ - BN
571 */
572static VALUE
573ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
574{
575    BIGNUM *add = NULL, *rem = NULL, *result;
576    int safe = 1, num;
577    VALUE vnum, vsafe, vadd, vrem, obj;
578
579    rb_scan_args(argc, argv, "13", &vnum, &vsafe, &vadd, &vrem);
580
581    num = NUM2INT(vnum);
582
583    if (vsafe == Qfalse) {
584	safe = 0;
585    }
586    if (!NIL_P(vadd)) {
587	add = GetBNPtr(vadd);
588	rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
589    }
590    if (!(result = BN_new())) {
591	ossl_raise(eBNError, NULL);
592    }
593    if (!BN_generate_prime(result, num, safe, add, rem, NULL, NULL)) {
594	BN_free(result);
595	ossl_raise(eBNError, NULL);
596    }
597    WrapBN(klass, obj, result);
598
599    return obj;
600}
601
602#define BIGNUM_NUM(func)			\
603    /*							\
604     * call-seq:					\
605     *   bn.##func -> integer				\
606     *							\
607     */							\
608    static VALUE 				\
609    ossl_bn_##func(VALUE self)			\
610    {						\
611	BIGNUM *bn;				\
612	GetBN(self, bn);			\
613	return INT2FIX(BN_##func(bn));		\
614    }
615BIGNUM_NUM(num_bytes)
616BIGNUM_NUM(num_bits)
617
618static VALUE
619ossl_bn_copy(VALUE self, VALUE other)
620{
621    BIGNUM *bn1, *bn2;
622
623    rb_check_frozen(self);
624
625    if (self == other) return self;
626
627    GetBN(self, bn1);
628    bn2 = GetBNPtr(other);
629
630    if (!BN_copy(bn1, bn2)) {
631	ossl_raise(eBNError, NULL);
632    }
633    return self;
634}
635
636#define BIGNUM_CMP(func)				\
637    /*							\
638     * call-seq:					\
639     *   bn.##func(bn2) -> integer			\
640     *							\
641     */							\
642    static VALUE					\
643    ossl_bn_##func(VALUE self, VALUE other)		\
644    {							\
645	BIGNUM *bn1, *bn2 = GetBNPtr(other);		\
646	GetBN(self, bn1);				\
647	return INT2FIX(BN_##func(bn1, bn2));		\
648    }
649BIGNUM_CMP(cmp)
650BIGNUM_CMP(ucmp)
651
652static VALUE
653ossl_bn_eql(VALUE self, VALUE other)
654{
655    if (ossl_bn_cmp(self, other) == INT2FIX(0)) {
656	return Qtrue;
657    }
658    return Qfalse;
659}
660
661/*
662 * call-seq:
663 *    bn.prime? => true | false
664 *    bn.prime?(checks) => true | false
665 *
666 * === Parameters
667 * * +checks+ - integer
668 */
669static VALUE
670ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
671{
672    BIGNUM *bn;
673    VALUE vchecks;
674    int checks = BN_prime_checks;
675
676    if (rb_scan_args(argc, argv, "01", &vchecks) == 1) {
677	checks = NUM2INT(vchecks);
678    }
679    GetBN(self, bn);
680    switch (BN_is_prime(bn, checks, NULL, ossl_bn_ctx, NULL)) {
681    case 1:
682	return Qtrue;
683    case 0:
684	return Qfalse;
685    default:
686	ossl_raise(eBNError, NULL);
687    }
688    /* not reachable */
689    return Qnil;
690}
691
692/*
693 * call-seq:
694 *    bn.prime_fasttest? => true | false
695 *    bn.prime_fasttest?(checks) => true | false
696 *    bn.prime_fasttest?(checks, trial_div) => true | false
697 *
698 * === Parameters
699 * * +checks+ - integer
700 * * +trial_div+ - boolean
701 */
702static VALUE
703ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
704{
705    BIGNUM *bn;
706    VALUE vchecks, vtrivdiv;
707    int checks = BN_prime_checks, do_trial_division = 1;
708
709    rb_scan_args(argc, argv, "02", &vchecks, &vtrivdiv);
710
711    if (!NIL_P(vchecks)) {
712	checks = NUM2INT(vchecks);
713    }
714    GetBN(self, bn);
715    /* handle true/false */
716    if (vtrivdiv == Qfalse) {
717	do_trial_division = 0;
718    }
719    switch (BN_is_prime_fasttest(bn, checks, NULL, ossl_bn_ctx, NULL, do_trial_division)) {
720    case 1:
721	return Qtrue;
722    case 0:
723	return Qfalse;
724    default:
725	ossl_raise(eBNError, NULL);
726    }
727    /* not reachable */
728    return Qnil;
729}
730
731/*
732 * INIT
733 * (NOTE: ordering of methods is the same as in 'man bn')
734 */
735void
736Init_ossl_bn()
737{
738#if 0
739    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
740#endif
741
742    if (!(ossl_bn_ctx = BN_CTX_new())) {
743	ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
744    }
745
746    eBNError = rb_define_class_under(mOSSL, "BNError", eOSSLError);
747
748    cBN = rb_define_class_under(mOSSL, "BN", rb_cObject);
749
750    rb_define_alloc_func(cBN, ossl_bn_alloc);
751    rb_define_method(cBN, "initialize", ossl_bn_initialize, -1);
752
753    rb_define_copy_func(cBN, ossl_bn_copy);
754    rb_define_method(cBN, "copy", ossl_bn_copy, 1);
755
756    /* swap (=coerce?) */
757
758    rb_define_method(cBN, "num_bytes", ossl_bn_num_bytes, 0);
759    rb_define_method(cBN, "num_bits", ossl_bn_num_bits, 0);
760    /* num_bits_word */
761
762    rb_define_method(cBN, "+", ossl_bn_add, 1);
763    rb_define_method(cBN, "-", ossl_bn_sub, 1);
764    rb_define_method(cBN, "*", ossl_bn_mul, 1);
765    rb_define_method(cBN, "sqr", ossl_bn_sqr, 0);
766    rb_define_method(cBN, "/", ossl_bn_div, 1);
767    rb_define_method(cBN, "%", ossl_bn_mod, 1);
768    /* nnmod */
769
770    rb_define_method(cBN, "mod_add", ossl_bn_mod_add, 2);
771    rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 2);
772    rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 2);
773    rb_define_method(cBN, "mod_sqr", ossl_bn_mod_sqr, 1);
774    rb_define_method(cBN, "**", ossl_bn_exp, 1);
775    rb_define_method(cBN, "mod_exp", ossl_bn_mod_exp, 2);
776    rb_define_method(cBN, "gcd", ossl_bn_gcd, 1);
777
778    /* add_word
779     * sub_word
780     * mul_word
781     * div_word
782     * mod_word */
783
784    rb_define_method(cBN, "cmp", ossl_bn_cmp, 1);
785    rb_define_alias(cBN, "<=>", "cmp");
786    rb_define_method(cBN, "ucmp", ossl_bn_ucmp, 1);
787    rb_define_method(cBN, "eql?", ossl_bn_eql, 1);
788    rb_define_alias(cBN, "==", "eql?");
789    rb_define_alias(cBN, "===", "eql?");
790    rb_define_method(cBN, "zero?", ossl_bn_is_zero, 0);
791    rb_define_method(cBN, "one?", ossl_bn_is_one, 0);
792    /* is_word */
793    rb_define_method(cBN, "odd?", ossl_bn_is_odd, 0);
794
795    /* zero
796     * one
797     * value_one - DON'T IMPL.
798     * set_word
799     * get_word */
800
801    rb_define_singleton_method(cBN, "rand", ossl_bn_s_rand, -1);
802    rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, -1);
803    rb_define_singleton_method(cBN, "rand_range", ossl_bn_s_rand_range, 1);
804    rb_define_singleton_method(cBN, "pseudo_rand_range", ossl_bn_s_pseudo_rand_range, 1);
805
806    rb_define_singleton_method(cBN, "generate_prime", ossl_bn_s_generate_prime, -1);
807    rb_define_method(cBN, "prime?", ossl_bn_is_prime, -1);
808
809    rb_define_method(cBN, "set_bit!", ossl_bn_set_bit, 1);
810    rb_define_method(cBN, "clear_bit!", ossl_bn_clear_bit, 1);
811    rb_define_method(cBN, "bit_set?", ossl_bn_is_bit_set, 1);
812    rb_define_method(cBN, "mask_bits!", ossl_bn_mask_bits, 1);
813    rb_define_method(cBN, "<<", ossl_bn_lshift, 1);
814    rb_define_method(cBN, ">>", ossl_bn_rshift, 1);
815    rb_define_method(cBN, "lshift!", ossl_bn_self_lshift, 1);
816    rb_define_method(cBN, "rshift!", ossl_bn_self_rshift, 1);
817    /* lshift1 - DON'T IMPL. */
818    /* rshift1 - DON'T IMPL. */
819
820    /*
821     * bn2bin
822     * bin2bn
823     * bn2hex
824     * bn2dec
825     * hex2bn
826     * dec2bn - all these are implemented in ossl_bn_initialize, and ossl_bn_to_s
827     * print - NOT IMPL.
828     * print_fp - NOT IMPL.
829     * bn2mpi
830     * mpi2bn
831     */
832    rb_define_method(cBN, "to_s", ossl_bn_to_s, -1);
833    rb_define_method(cBN, "to_i", ossl_bn_to_i, 0);
834    rb_define_alias(cBN, "to_int", "to_i");
835    rb_define_method(cBN, "to_bn", ossl_bn_to_bn, 0);
836    rb_define_method(cBN, "coerce", ossl_bn_coerce, 1);
837
838    /*
839     * TODO:
840     * But how to: from_bin, from_mpi? PACK?
841     * to_bin
842     * to_mpi
843     */
844
845    rb_define_method(cBN, "mod_inverse", ossl_bn_mod_inverse, 1);
846
847    /* RECiProcal
848     * MONTgomery */
849
850    /*
851     * TODO:
852     * Where to belong these?
853     */
854    rb_define_method(cBN, "prime_fasttest?", ossl_bn_is_prime_fasttest, -1);
855}
856
857