blob: e40615fb8d09acdea49fa0f8a33cbfe11662258c [file] [log] [blame]
Guido van Rossum50098201992-07-31 15:10:13 +00001/***********************************************************
2Copyright 1992 by Lance Ellinghouse (lance@markv.com).
3
4Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
5Netherlands.
6
7 All Rights Reserved
8
9Permission to use, copy, modify, and distribute this software and its
10documentation for any purpose and without fee is hereby granted,
11provided that the above copyright notice appear in all copies and that
12both that copyright notice and this permission notice appear in
13supporting documentation, and that the names of Stichting Mathematisch
14Centrum or CWI not be used in advertising or publicity pertaining to
15distribution of the software without specific, written prior permission.
16
17STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
18THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
19FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
20FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
22ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
23OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25******************************************************************/
26
27/* This creates an encryption and decryption engine I am calling
28 a rotor due to the original design was a harware rotor with
29 contacts used in Germany during WWII.
30
31Rotor Module:
32
33- rotor.newrotor('key') -> rotorobject (default of 6 rotors)
34- rotor.newrotor('key', num_rotors) -> rotorobject
35
36Rotor Objects:
37
38- ro.encrypt('string') -> encrypted string
39- ro.decrypt('encrypted string') -> unencrypted string
40
41NOTE: you MUST use the SAME key in rotor.newrotor()
42 if you wish to decrypt an encrypted string.
43 Also, the encrypted string is NOT 0-127 ASCII.
44 It is considered BINARY data.
45
46*/
47
48/* Rotor objects */
49
50#include "allobjects.h"
51#include "modsupport.h"
52#include <stdio.h>
53#include <math.h>
54
55typedef struct {
56 OB_HEAD
57 int seed[3];
58 short key[5];
59 int size;
60 int size_mask;
61 int rotors;
62 unsigned char *e_rotor; /* [num_rotors][size] */
63 unsigned char *d_rotor; /* [num_rotors][size] */
64 unsigned char *positions; /* [num_rotors] */
65 unsigned char *advances; /* [num_rotors] */
66} rotorobject;
67
68extern typeobject Rotortype; /* Really static, forward */
69
70#define is_rotorobject(v) ((v)->ob_type == &Rotortype)
71
72/*
73 This defines the necessary routines to manage rotor objects
74*/
75
76static void set_seed( r )
77rotorobject *r;
78{
79 r->seed[0] = r->key[0];
80 r->seed[1] = r->key[1];
81 r->seed[2] = r->key[2];
82}
83
84/* Return the next random number in the range [0.0 .. 1.0) */
85static float r_random( r )
86rotorobject *r;
87{
88 int x, y, z;
89 float val, term;
90
91 x = r->seed[0];
92 y = r->seed[1];
93 z = r->seed[2];
94
95 x = 171 * (x % 177) - 2 * (x/177);
96 y = 172 * (y % 176) - 35 * (y/176);
97 z = 170 * (z % 178) - 63 * (z/178);
98
99 if (x < 0) x = x + 30269;
100 if (y < 0) y = y + 30307;
101 if (z < 0) z = z + 30323;
102
103 r->seed[0] = x;
104 r->seed[1] = y;
105 r->seed[2] = z;
106
107 term = (float)(
108 (((float)x)/(float)30269.0) +
109 (((float)y)/(float)30307.0) +
110 (((float)z)/(float)30323.0)
111 );
112 val = term - (float)floor((double)term);
113
114 if (val >= 1.0) val = 0.0;
115
116 return val;
117}
118
119static short r_rand(r,s)
120rotorobject *r;
121short s;
122{
123 short tmp = (short)((short)(r_random(r) * (float)s) % s);
124 return tmp;
125}
126
127static void set_key(r, key)
128rotorobject *r;
129char *key;
130{
131 int k1=995, k2=576, k3=767, k4=671, k5=463;
132 int i;
133 int len=strlen(key);
134 for (i=0;i<len;i++) {
135 k1 = (((k1<<3 | k1<<-13) + key[i]) & 65535);
136 k2 = (((k2<<3 | k2<<-13) ^ key[i]) & 65535);
137 k3 = (((k3<<3 | k3<<-13) - key[i]) & 65535);
138 k4 = ((key[i] - (k4<<3 | k4<<-13)) & 65535);
139 k5 = (((k5<<3 | k5<<-13) ^ ~key[i]) & 65535);
140 }
141 r->key[0] = (short)k1;
142 r->key[1] = (short)(k2|1);
143 r->key[2] = (short)k3;
144 r->key[3] = (short)k4;
145 r->key[4] = (short)k5;
146
147 set_seed(r);
148}
149
150/* These define the interface to a rotor object */
151static rotorobject *
152newrotorobject(num_rotors, key)
153 int num_rotors;
154 char *key;
155{
156 rotorobject *xp;
157 xp = NEWOBJ(rotorobject, &Rotortype);
158 if (xp == NULL)
159 return NULL;
Guido van Rossume6e9fe11992-07-31 15:11:01 +0000160 set_key(xp, key);
Guido van Rossum50098201992-07-31 15:10:13 +0000161
162 xp->size = 256;
163 xp->size_mask = xp->size - 1;
164 xp->size_mask = 0;
165 xp->rotors = num_rotors;
Guido van Rossume6e9fe11992-07-31 15:11:01 +0000166 xp->e_rotor = NULL;
167 xp->d_rotor = NULL;
168 xp->positions = NULL;
169 xp->advances = NULL;
Guido van Rossum50098201992-07-31 15:10:13 +0000170
Guido van Rossume6e9fe11992-07-31 15:11:01 +0000171 xp->e_rotor =
172 (unsigned char *)malloc((num_rotors * (xp->size * sizeof(char))));
173 if (xp->e_rotor == (unsigned char *)NULL)
174 goto fail;
175 xp->d_rotor =
176 (unsigned char *)malloc((num_rotors * (xp->size * sizeof(char))));
177 if (xp->d_rotor == (unsigned char *)NULL)
178 goto fail;
Guido van Rossum50098201992-07-31 15:10:13 +0000179 xp->positions = (unsigned char *)malloc(num_rotors * sizeof(char));
Guido van Rossume6e9fe11992-07-31 15:11:01 +0000180 if (xp->positions == (unsigned char *)NULL)
181 goto fail;
Guido van Rossum50098201992-07-31 15:10:13 +0000182 xp->advances = (unsigned char *)malloc(num_rotors * sizeof(char));
Guido van Rossume6e9fe11992-07-31 15:11:01 +0000183 if (xp->advances == (unsigned char *)NULL)
184 goto fail;
Guido van Rossum50098201992-07-31 15:10:13 +0000185 return xp;
Guido van Rossume6e9fe11992-07-31 15:11:01 +0000186fail:
187 DECREF(xp);
188 return (rotorobject *)err_nomem();
Guido van Rossum50098201992-07-31 15:10:13 +0000189}
190
191/* These routines impliment the rotor itself */
192
193/* Here is a fairly sofisticated {en,de}cryption system. It is bassed
194on the idea of a "rotor" machine. A bunch of rotors, each with a
195different permutation of the alphabet, rotate around a different
196amount after encrypting one character. The current state of the
197rotors is used to encrypt one character.
198
199 The code is smart enought to tell if your alphabet has a number of
200characters equal to a power of two. If it does, it uses logical
201operations, if not it uses div and mod (both require a division).
202
203 You will need to make two changes to the code 1) convert to c, and
204customize for an alphabet of 255 chars 2) add a filter at the
205begining, and end, which subtracts one on the way in, and adds one on
206the way out.
207
208 You might wish to do some timing studies. Another viable
209alternative is to "byte stuff" the encrypted data of a normal (perhaps
210this one) encryption routine.
211
212j'
213*/
214
215/*(defun RTR-make-id-rotor (rotor)
216 "Set ROTOR to the identity permutation"
217 (let ((j 0))
218 (while (< j RTR-size)
219 (aset rotor j j)
220 (setq j (+ 1 j)))
221 rotor))*/
222static void RTR_make_id_rotor(r, rtr)
223 rotorobject *r;
224 unsigned char *rtr;
225{
226 register int j;
227 register int size = r->size;
228 for (j=0;j<size;j++) {
229 rtr[j] = (unsigned char)j;
230 }
231}
232
233
234/*(defvar RTR-e-rotors
235 (let ((rv (make-vector RTR-number-of-rotors 0))
236 (i 0)
237 tr)
238 (while (< i RTR-number-of-rotors)
239 (setq tr (make-vector RTR-size 0))
240 (RTR-make-id-rotor tr)
241 (aset rv i tr)
242 (setq i (+ 1 i)))
243 rv)
244 "The current set of encryption rotors")*/
245static void RTR_e_rotors(r)
246 rotorobject *r;
247{
248 int i;
249 for (i=0;i<r->rotors;i++) {
250 RTR_make_id_rotor(r,&(r->e_rotor[(i*r->size)]));
251 }
252}
253
254/*(defvar RTR-d-rotors
255 (let ((rv (make-vector RTR-number-of-rotors 0))
256 (i 0)
257 tr)
258 (while (< i RTR-number-of-rotors)
259 (setq tr (make-vector RTR-size 0))
260 (setq j 0)
261 (while (< j RTR-size)
262 (aset tr j j)
263 (setq j (+ 1 j)))
264 (aset rv i tr)
265 (setq i (+ 1 i)))
266 rv)
267 "The current set of decryption rotors")*/
268static void RTR_d_rotors(r)
269 rotorobject *r;
270{
271 register int i, j;
272 for (i=0;i<r->rotors;i++) {
273 for (j=0;j<r->size;j++) {
274 r->d_rotor[((i*r->size)+j)] = (unsigned char)j;
275 }
276 }
277}
278
279/*(defvar RTR-positions (make-vector RTR-number-of-rotors 1)
280 "The positions of the rotors at this time")*/
281static void RTR_positions(r)
282 rotorobject *r;
283{
284 int i;
285 for (i=0;i<r->rotors;i++) {
286 r->positions[i] = 1;
287 }
288}
289
290/*(defvar RTR-advances (make-vector RTR-number-of-rotors 1)
291 "The number of positions to advance the rotors at a time")*/
292static void RTR_advances(r)
293 rotorobject *r;
294{
295 int i;
296 for (i=0;i<r->rotors;i++) {
297 r->advances[i] = 1;
298 }
299}
300
301/*(defun RTR-permute-rotor (e d)
302 "Permute the E rotor, and make the D rotor its inverse"
303 ;; see Knuth for explaination of algorythm.
304 (RTR-make-id-rotor e)
305 (let ((i RTR-size)
306 q j)
307 (while (<= 2 i)
308 (setq q (fair16 i)) ; a little tricky, decrement here
309 (setq i (- i 1)) ; since we have origin 0 array's
310 (setq j (aref e q))
311 (aset e q (aref e i))
312 (aset e i j)
313 (aset d j i))
314 (aset e 0 (aref e 0)) ; don't forget e[0] and d[0]
315 (aset d (aref e 0) 0)))*/
316static void RTR_permute_rotor(r, e, d)
317 rotorobject *r;
318 unsigned char *e;
319 unsigned char *d;
320{
321 short i = r->size;
322 short q;
323 unsigned char j;
324 RTR_make_id_rotor(r,e);
325 while (2 <= i) {
326 q = r_rand(r,i);
327 i--;
328 j = e[q];
329 e[q] = (unsigned char)e[i];
330 e[i] = (unsigned char)j;
331 d[j] = (unsigned char)i;
332 }
333 e[0] = (unsigned char)e[0];
334 d[(e[0])] = (unsigned char)0;
335}
336
337/*(defun RTR-init (key)
338 "Given KEY (a list of 5 16 bit numbers), initialize the rotor machine.
339Set the advancement, position, and permutation of the rotors"
340 (R16-set-state key)
341 (let (i)
342 (setq i 0)
343 (while (< i RTR-number-of-rotors)
344 (aset RTR-positions i (fair16 RTR-size))
345 (aset RTR-advances i (+ 1 (* 2 (fair16 (/ RTR-size 2)))))
346 (message "Initializing rotor %d..." i)
347 (RTR-permute-rotor (aref RTR-e-rotors i) (aref RTR-d-rotors i))
348 (setq i (+ 1 i)))))*/
349static void RTR_init(r)
350 rotorobject *r;
351{
352 int i;
353 set_seed(r);
354 RTR_positions(r);
355 RTR_advances(r);
356 RTR_e_rotors(r);
357 RTR_d_rotors(r);
358 for(i=0;i<r->rotors;i++) {
359 r->positions[i] = r_rand(r,r->size);
360 r->advances[i] = (1+(2*(r_rand(r,r->size/2))));
361 RTR_permute_rotor(r,&(r->e_rotor[(i*r->size)]),&(r->d_rotor[(i*r->size)]));
362 }
363}
364
365/*(defun RTR-advance ()
366 "Change the RTR-positions vector, using the RTR-advances vector"
367 (let ((i 0)
368 (temp 0))
369 (if RTR-size-mask
370 (while (< i RTR-number-of-rotors)
371 (setq temp (+ (aref RTR-positions i) (aref RTR-advances i)))
372 (aset RTR-positions i (logand temp RTR-size-mask))
373 (if (and (>= temp RTR-size)
374 (< i (- RTR-number-of-rotors 1)))
375 (aset RTR-positions (+ i 1)
376 (+ 1 (aref RTR-positions (+ i 1)))))
377 (setq i (+ i 1)))
378 (while (< i RTR-number-of-rotors)
379 (setq temp (+ (aref RTR-positions i) (aref RTR-advances i)))
380 (aset RTR-positions i (% temp RTR-size))
381 (if (and (>= temp RTR-size)
382 (< i (- RTR-number-of-rotors 1)))
383 (aset RTR-positions (+ i 1)
384 (+ 1 (aref RTR-positions (+ i 1)))))
385 (setq i (+ i 1))))))*/
386static void RTR_advance(r)
387 rotorobject *r;
388{
389 register int i=0, temp=0;
390 if (r->size_mask) {
391 while (i<r->rotors) {
392 temp = r->positions[i] + r->advances[i];
393 r->positions[i] = temp & r->size_mask;
394 if ((temp >= r->size) && (i < (r->rotors - 1))) {
395 r->positions[(i+1)] = 1 + r->positions[(i+1)];
396 }
397 i++;
398 }
399 } else {
400 while (i<r->rotors) {
401 temp = r->positions[i] + r->advances[i];
402 r->positions[i] = temp%r->size;
403 if ((temp >= r->size) && (i < (r->rotors - 1))) {
404 r->positions[(i+1)] = 1 + r->positions[(i+1)];
405 }
406 i++;
407 }
408 }
409}
410
411/*(defun RTR-e-char (p)
412 "Encrypt the character P with the current rotor machine"
413 (let ((i 0))
414 (if RTR-size-mask
415 (while (< i RTR-number-of-rotors)
416 (setq p (aref (aref RTR-e-rotors i)
417 (logand (logxor (aref RTR-positions i)
418 p)
419 RTR-size-mask)))
420 (setq i (+ 1 i)))
421 (while (< i RTR-number-of-rotors)
422 (setq p (aref (aref RTR-e-rotors i)
423 (% (logxor (aref RTR-positions i)
424 p)
425 RTR-size)))
426 (setq i (+ 1 i))))
427 (RTR-advance)
428 p))*/
429static unsigned char RTR_e_char(r, p)
430 rotorobject *r;
431 unsigned char p;
432{
433 register int i=0;
434 register unsigned char tp=p;
435 if (r->size_mask) {
436 while (i < r->rotors) {
437 tp = r->e_rotor[(i*r->size)+(((r->positions[i] ^ tp) & r->size_mask))];
438 i++;
439 }
440 } else {
441 while (i < r->rotors) {
442 tp = r->e_rotor[(i*r->size)+(((r->positions[i] ^ tp) % r->size))];
443 i++;
444 }
445 }
446 RTR_advance(r);
447 return ((unsigned char)tp);
448}
449
450/*(defun RTR-d-char (c)
451 "Decrypt the character C with the current rotor machine"
452 (let ((i (- RTR-number-of-rotors 1)))
453 (if RTR-size-mask
454 (while (<= 0 i)
455 (setq c (logand (logxor (aref RTR-positions i)
456 (aref (aref RTR-d-rotors i)
457 c))
458 RTR-size-mask))
459 (setq i (- i 1)))
460 (while (<= 0 i)
461 (setq c (% (logxor (aref RTR-positions i)
462 (aref (aref RTR-d-rotors i)
463 c))
464 RTR-size))
465 (setq i (- i 1))))
466 (RTR-advance)
467 c))*/
468static unsigned char RTR_d_char(r, c)
469 rotorobject *r;
470 unsigned char c;
471{
472 register int i=r->rotors - 1;
473 register unsigned char tc=c;
474 if (r->size_mask) {
475 while (0 <= i) {
476 tc = (r->positions[i] ^ r->d_rotor[(i*r->size)+tc]) & r->size_mask;
477 i--;
478 }
479 } else {
480 while (0 <= i) {
481 tc = (r->positions[i] ^ r->d_rotor[(i*r->size)+tc]) % r->size;
482 i--;
483 }
484 }
485 RTR_advance(r);
486 return(tc);
487}
488
489/*(defun RTR-e-region (beg end key)
490 "Perform a rotor encryption of the region from BEG to END by KEY"
491 (save-excursion
492 (let ((tenth (/ (- end beg) 10)))
493 (RTR-init key)
494 (goto-char beg)
495 ;; ### make it stop evry 10% or so to tell us
496 (while (< (point) end)
497 (let ((fc (following-char)))
498 (insert-char (RTR-e-char fc) 1)
499 (delete-char 1))))))*/
500static void RTR_e_region(r, beg, len)
501 rotorobject *r;
502 unsigned char *beg;
503 int len;
504{
505 register int i;
506 RTR_init(r);
507 for (i=0;i<len;i++) {
508 beg[i]=RTR_e_char(r,beg[i]);
509 }
510}
511
512/*(defun RTR-d-region (beg end key)
513 "Perform a rotor decryption of the region from BEG to END by KEY"
514 (save-excursion
515 (progn
516 (RTR-init key)
517 (goto-char beg)
518 (while (< (point) end)
519 (let ((fc (following-char)))
520 (insert-char (RTR-d-char fc) 1)
521 (delete-char 1))))))*/
522void static RTR_d_region(r, beg, len)
523 rotorobject *r;
524 unsigned char *beg;
525 int len;
526{
527 register int i;
528 RTR_init(r);
529 for (i=0;i<len;i++) {
530 beg[i]=RTR_d_char(r,beg[i]);
531 }
532}
533
534
535/*(defun RTR-key-string-to-ints (key)
536 "Convert a string into a list of 4 numbers"
537 (let ((k1 995)
538 (k2 576)
539 (k3 767)
540 (k4 671)
541 (k5 463)
542 (i 0))
543 (while (< i (length key))
544 (setq k1 (logand (+ (logior (lsh k1 3) (lsh k1 -13)) (aref key i)) 65535))
545 (setq k2 (logand (logxor (logior (lsh k2 3) (lsh k2 -13)) (aref key i)) 65535))
546 (setq k3 (logand (- (logior (lsh k3 3) (lsh k3 -13)) (aref key i)) 65535))
547 (setq k4 (logand (- (aref key i) (logior (lsh k4 3) (lsh k4 -13))) 65535))
548 (setq k5 (logand (logxor (logior (lsh k5 3) (lsh k5 -13)) (lognot (aref key i))) 65535))
549 (setq i (+ i 1)))
550 (list k1 (logior 1 k2) k3 k4 k5)))*/
551/* This is done in set_key() above */
552
553/*(defun encrypt-region (beg end key)
554 "Interactivly encrypt the region"
555 (interactive "r\nsKey:")
556 (RTR-e-region beg end (RTR-key-string-to-ints key)))*/
557static void encrypt_region(r, region, len)
558 rotorobject *r;
559 unsigned char *region;
560 int len;
561{
562 RTR_e_region(r,region,len);
563}
564
565/*(defun decrypt-region (beg end key)
566 "Interactivly decrypt the region"
567 (interactive "r\nsKey:")
568 (RTR-d-region beg end (RTR-key-string-to-ints key)))*/
569static void decrypt_region(r, region, len)
570 rotorobject *r;
571 unsigned char *region;
572 int len;
573{
574 RTR_d_region(r,region,len);
575}
576
577/* Rotor methods */
578
579static void
580rotor_dealloc(xp)
581 rotorobject *xp;
582{
Guido van Rossume6e9fe11992-07-31 15:11:01 +0000583 XDEL(xp->e_rotor);
584 XDEL(xp->d_rotor);
585 XDEL(xp->positions);
586 XDEL(xp->advances);
Guido van Rossum50098201992-07-31 15:10:13 +0000587 DEL(xp);
588}
589
590static object *
591rotor_encrypt(self, args)
592 rotorobject *self;
593 object *args;
594{
595 char *string = (char *)NULL;
596 int len = 0;
597 object *rtn = (object *)NULL;
598 char *tmp;
599
600 if (!getargs(args,"s#",&string, &len))
601 return NULL;
602 if (!(tmp = (char *)malloc(len+5))) {
603 err_nomem();
604 return NULL;
605 }
606 memset(tmp,'\0',len+1);
607 memcpy(tmp,string,len);
608 RTR_e_region(self,tmp,len);
609 rtn = newsizedstringobject(tmp,len);
610 free(tmp);
611 return(rtn);
612}
613
614static object *
615rotor_decrypt(self, args)
616 rotorobject *self;
617 object *args;
618{
619 char *string = (char *)NULL;
620 int len = 0;
621 object *rtn = (object *)NULL;
622 char *tmp;
623
624 if (!getargs(args,"s#",&string, &len))
625 return NULL;
626 if (!(tmp = (char *)malloc(len+5))) {
627 err_nomem();
628 return NULL;
629 }
630 memset(tmp,'\0',len+1);
631 memcpy(tmp,string,len);
632 RTR_d_region(self,tmp,len);
633 rtn = newsizedstringobject(tmp,len);
634 free(tmp);
635 return(rtn);
636}
637
638static object *
639rotor_setkey(self, args)
640 rotorobject *self;
641 object *args;
642{
643 char *key;
644 char *string;
645
646 if (getargs(args,"s",&string))
647 set_key(self,string);
648 INCREF(None);
649 return None;
650}
651
652static struct methodlist rotor_methods[] = {
653 {"encrypt", rotor_encrypt},
654 {"decrypt", rotor_decrypt},
655 {"setkey", rotor_setkey},
656 {NULL, NULL} /* sentinel */
657};
658
659
660/* Return a rotor object's named attribute. */
661static object *
662rotor_getattr(s, name)
663 rotorobject *s;
664 char *name;
665{
666 return findmethod(rotor_methods, (object *) s, name);
667}
668
669static typeobject Rotortype = {
670 OB_HEAD_INIT(&Typetype)
671 0, /*ob_size*/
672 "rotor", /*tp_name*/
673 sizeof(rotorobject), /*tp_size*/
674 0, /*tp_itemsize*/
675 /* methods */
676 rotor_dealloc, /*tp_dealloc*/
677 0, /*tp_print*/
678 rotor_getattr, /*tp_getattr*/
679 0, /*tp_setattr*/
680 0, /*tp_compare*/
681 0, /*tp_repr*/
682};
683
684
685object *rotor_rotor(self, args)
686object *args;
687{
688 char *string;
689 rotorobject *r;
690 int len;
691 int num_rotors;
692
693 if (getargs(args,"s#", &string, &len)) {
694 num_rotors = 6;
695 } else {
696 err_clear();
697 if (!getargs(args,"(s#i)", &string, &len, &num_rotors))
698 return NULL;
699 }
700 r = newrotorobject(num_rotors, string);
701 return (object *)r;
702}
703
704static struct methodlist rotor_rotor_methods[] = {
705 {"newrotor", rotor_rotor},
706 {NULL, NULL} /* Sentinel */
707};
708
709
710/* Initialize this module.
711 This is called when the first 'import rotor' is done,
712 via a table in config.c, if config.c is compiled with USE_ROTOR
713 defined. */
714
715void
716initrotor()
717{
718 object *m;
719
720 m = initmodule("rotor", rotor_rotor_methods);
721}