Subversion Repositories Kolibri OS

Rev

Rev 6423 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6419 hidnplayr 1
;    mpint.inc - Multi precision integer procedures
2
;
3
;    Copyright (C) 2015-2016 Jeffrey Amelynck
4
;
5
;    This program is free software: you can redistribute it and/or modify
6
;    it under the terms of the GNU General Public License as published by
7
;    the Free Software Foundation, either version 3 of the License, or
8
;    (at your option) any later version.
9
;
10
;    This program is distributed in the hope that it will be useful,
11
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
;    GNU General Public License for more details.
14
;
15
;    You should have received a copy of the GNU General Public License
16
;    along with this program.  If not, see .
17
 
18
MPINT_MAX_LEN = MAX_BITS/8
19
 
20
; TODO: make procedures use real number length instead of hardcoded maximum length (MPINT_MAX_LEN)
21
 
22
mpint_to_little_endian:
23
 
24
; Load length dword
25
        lodsd
26
; Convert to little endian
27
        bswap   eax
28
        stosd
29
        test    eax, eax
30
        jz      .zero
31
; Copy data, convert to little endian meanwhile
32
        push    eax
33
        add     esi, eax
34
        push    esi
35
        dec     esi
36
        mov     ecx, eax
37
        std
38
  @@:
39
        lodsb
40
        mov     byte[edi], al
41
        inc     edi
42
        dec     ecx
43
        jnz     @r
44
        cld
45
        pop     esi eax
46
; Fill the rest of the buffer with zeros.
47
  .zero:
48
        mov     ecx, MAX_BITS/8
49
        sub     ecx, eax
50
        xor     al, al
51
        rep stosb
52
 
53
        ret
54
 
55
mpint_to_big_endian:
56
 
57
; Load length dword
58
        lodsd
59
        test    eax, eax
60
        jz      .zero
61
        mov     ecx, eax
62
        add     esi, ecx
63
        dec     esi
64
        test    byte[esi], 0x80   ; Is the highest bit set?
65
        jz      @f
66
        inc     eax
67
  @@:
68
        push    eax
69
        bswap   eax
70
        stosd
71
; Copy data, convert to big endian meanwhile
72
        std
73
; Append zero byte if highest bit is 0
74
        test    byte[esi], 0x80
75
        jz      @f
76
        mov     byte[edi], 0
77
        inc     edi
78
  @@:
79
        lodsb
80
        mov     byte[edi], al
81
        inc     edi
82
        dec     ecx
83
        jnz     @r
84
        cld
85
        pop     eax
86
        ret
87
 
88
  .zero:
89
        stosd
90
        ret
91
 
92
proc mpint_length uses edi eax ecx, mpint
93
 
94
        mov     edi, [mpint]
95
        mov     ecx, MPINT_MAX_LEN
96
        push    edi
97
        lea     edi, [edi + ecx + 4 - 1]
98
        xor     al, al
99
        std
100
        repe scasb
101
        cld
102
        je      @f
103
        inc     ecx
104
  @@:
105
        pop     edi
106
        mov     [edi], ecx
107
 
108
        ret
109
 
110
endp
111
 
112
proc mpint_print uses ecx esi eax, src
113
 
114
        DEBUGF  1, "0x"
115
        mov     esi, [src]
116
        mov     ecx, [esi]
117
        test    ecx, ecx
118
        jz      .zero
119
        lea     esi, [esi + ecx + 4 - 1]
120
        pushf
121
        std
122
  .loop:
123
        lodsb
124
        DEBUGF  1, "%x", eax:2
125
        dec     ecx
126
        jnz     .loop
127
        DEBUGF  1, "\n"
128
        popf
129
 
130
        ret
131
 
132
  .zero:
133
        DEBUGF  1, "00\n"
134
        ret
135
 
136
endp
137
 
138
proc mpint_zero uses edi ecx eax, dst
139
 
140
        mov     edi, [dst]
141
        xor     eax, eax
142
        mov     ecx, MPINT_MAX_LEN/4+1
143
        rep stosd
144
 
145
        ret
146
 
147
endp
148
 
149
proc mpint_zero? uses edi ecx eax, dst
150
 
151
        mov     edi, [dst]
152
        add     edi, 4
153
        mov     ecx, MPINT_MAX_LEN/4
154
        xor     eax, eax
155
        repe scasd
156
        ret
157
 
158
endp
159
 
160
; return an index number giving the position of the highest order bit
161
proc mpint_hob uses edi ecx, dst
162
 
163
        mov     edi, [dst]
164
        ; start from the high order byte
165
        add     edi, MPINT_MAX_LEN+4-1
166
        mov     ecx, MPINT_MAX_LEN
167
        xor     eax, eax
168
        ; scan byte by byte for the first non-zero byte
169
        std
170
        repe scasb
171
        cld
172
        je      .zero
173
        ; calculate how many bits this is, plus 7
174
        lea     eax, [ecx*8-1]
175
        ; load this high order byte into cl
176
        mov     cl, [edi+1]
177
        ; shift bits of this byte right, until the byte reaches zero, counting bits meanwhile
178
  @@:
179
        inc     eax
180
        shr     cl, 1
181
        jnz     @r
182
  .zero:
183
        ret
184
 
185
endp
186
 
187
proc mpint_cmp uses esi edi ecx, dst, src
188
 
189
        mov     esi, [src]
190
        mov     edi, [dst]
191
        ; start from the high order byte
192
        add     esi, MPINT_MAX_LEN+4-4
193
        add     edi, MPINT_MAX_LEN+4-4
194
        mov     ecx, MPINT_MAX_LEN/4
195
        std
196
        repe cmpsd
197
        cld
198
        ret
199
 
200
endp
201
 
202
proc mpint_mov uses esi edi ecx, dst, src
203
 
204
        mov     esi, [src]
205
        mov     edi, [dst]
206
        mov     ecx, MPINT_MAX_LEN/4+1
207
        rep movsd
208
 
209
        ret
210
 
211
endp
212
 
213
proc mpint_mov0 uses esi edi ecx eax, dst, src
214
 
215
        mov     esi, [src]
216
        mov     edi, [dst]
217
        mov     ecx, [esi]
218
        mov     eax, ecx
219
        neg     eax
220
        add     esi, 4
221
        add     edi, 4
222
        rep movsb
223
        add     eax, MPINT_MAX_LEN
224
        jz      @f
225
        mov     ecx, eax
226
        xor     eax, eax
227
        rep stosb
228
  @@:
229
 
230
        ret
231
 
232
endp
233
 
234
proc mpint_shl1 uses edi ecx eax, dst
235
 
236
        mov     edi, [dst]
237
        add     edi, 4
238
        mov     ecx, MPINT_MAX_LEN/4-1
239
 
240
        shl     dword[edi], 1
241
        lahf
242
  @@:
243
        add     edi, 4
244
        sahf
245
        rcl     dword[edi], 1
246
        lahf
247
        dec     ecx
248
        jnz     @r
249
        sahf
250
 
251
        ret
252
 
253
endp
254
 
255
proc mpint_shr1 uses edi ecx eax, dst
256
 
257
        mov     edi, [dst]
258
        add     edi, MPINT_MAX_LEN+4-4
259
        mov     ecx, MPINT_MAX_LEN/4-1
260
 
261
        shr     dword[edi], 1
262
        lahf
263
  @@:
264
        sub     edi, 4
265
        sahf
266
        rcr     dword[edi], 1
267
        lahf
268
        dec     ecx
269
        jnz     @r
270
        sahf
271
 
272
        ret
273
 
274
endp
275
 
276
proc mpint_shl uses eax ebx ecx edx esi edi, dst, shift
277
 
278
        mov     ecx, [shift]
279
        shr     ecx, 3                  ; 8 bits in one byte
280
        cmp     ecx, MPINT_MAX_LEN
281
        jge     .zero
282
        mov     esi, [dst]
283
        add     esi, MPINT_MAX_LEN+4-4
284
        mov     edi, esi
285
        and     ecx, not 11b
286
        sub     esi, ecx
287
        mov     edx, MPINT_MAX_LEN/4-1
288
        shr     ecx, 2                  ; 4 bytes in one dword
289
        push    ecx
290
        sub     edx, ecx
291
        mov     ecx, [shift]
292
        and     ecx, 11111b
293
        std
294
  .loop:
295
        lodsd
296
        mov     ebx, [esi]
297
        shld    eax, ebx, cl
298
        stosd
299
        dec     edx
300
        jnz     .loop
301
        lodsd
302
        shl     eax, cl
303
        stosd
304
 
305
        ; fill the lsb bytes with zeros
306
        pop     ecx
307
        test    ecx, ecx
308
        jz      @f
309
        xor     eax, eax
310
        rep stosd
311
  @@:
312
        cld
313
        ret
314
 
315
  .zero:
316
        stdcall mpint_zero, [dst]
317
        ret
318
 
319
endp
320
 
321
; Left shift and copy
322
proc mpint_shlmov uses eax ebx ecx edx esi edi, dst, src, shift
323
 
324
        mov     ecx, [shift]
325
        shr     ecx, 3                  ; 8 bits in one byte
326
        cmp     ecx, MPINT_MAX_LEN
327
        jge     .zero
328
        mov     esi, [src]
329
        add     esi, MPINT_MAX_LEN+4-4
330
        mov     edi, [dst]
331
        add     edi, MPINT_MAX_LEN+4-4
332
        and     ecx, not 11b
333
        sub     esi, ecx
334
        mov     edx, MPINT_MAX_LEN/4-1
335
        shr     ecx, 2                  ; 4 bytes in one dword
336
        push    ecx
337
        sub     edx, ecx
338
        mov     ecx, [shift]
339
        and     ecx, 11111b
340
        std
341
  .loop:
342
        lodsd
343
        mov     ebx, [esi]
344
        shld    eax, ebx, cl
345
        stosd
346
        dec     edx
347
        jnz     .loop
348
        lodsd
349
        shl     eax, cl
350
        stosd
351
 
352
        ; fill the lsb bytes with zeros
353
        pop     ecx
354
        test    ecx, ecx
355
        jz      @f
356
        xor     eax, eax
357
        rep stosd
358
  @@:
359
        cld
360
        ret
361
 
362
  .zero:
363
        stdcall mpint_zero, [dst]
364
        ret
365
 
366
endp
367
 
368
proc mpint_add uses esi edi ecx eax, dst, src
369
 
370
        mov     esi, [src]
371
        add     esi, 4
372
        mov     edi, [dst]
373
        add     edi, 4
374
        mov     ecx, MPINT_MAX_LEN/4
375
        xor     ah, ah          ; clear flags (Carry flag most importantly)
376
  @@:
377
        sahf
378
        lodsd
379
        adc     [edi], eax
380
        lahf
381
        add     edi, 4
382
        dec     ecx
383
        jnz     @r
384
        sahf
385
 
386
        ret
387
 
388
endp
389
 
390
proc mpint_sub uses eax esi edi ecx, dst, src
391
 
392
        mov     esi, [src]
393
        add     esi, 4
394
        mov     edi, [dst]
395
        add     edi, 4
396
        mov     ecx, MPINT_MAX_LEN/4
397
 
398
        ; dst = dst + (NOT src) + 1
399
        stc                     ; Setting CF takes care of the +1
400
        pushf
401
  @@:
402
        lodsd
403
        not     eax
404
        popf
405
        adc     [edi], eax
406
        pushf
407
        add     edi, 4
408
        dec     ecx
409
        jnz     @r
410
        popf
411
 
412
        ret
413
 
414
endp
415
 
416
proc mpint_mul uses esi edi ecx ebx eax, dst, A, B
417
 
418
        stdcall mpint_zero, [dst]
419
 
420
        ; first, find the byte in A containing the highest order bit
421
        mov     ecx, MPINT_MAX_LEN
422
        mov     edi, [A]
423
        add     edi, MPINT_MAX_LEN+4-1
424
        std
425
        xor     al, al
426
        repe scasb
427
        cld
428
        je      .zero
429
        inc     ecx
430
        mov     al, [edi+1]
431
        mov     esi, edi
432
        mov     bl, 8
433
  @@:
434
        shl     al, 1
435
        jc      .first_hit
436
        dec     bl
437
        jnz     @r
438
 
439
        ; Then, starting from this byte, iterate through the bits in A,
440
        ; starting from the highest order bit down to the lowest order bit.
441
  .next_byte:
442
        mov     al, [edi]
443
        dec     edi
444
        mov     bl, 8
445
  .next_bit:
446
        stdcall mpint_shl1, [dst]
447
        shl     al, 1
448
        jnc     .zero_bit
449
  .first_hit:
450
        stdcall mpint_add, [dst], [B]
451
  .zero_bit:
452
        dec     bl
453
        jnz     .next_bit
454
        dec     ecx
455
        jnz     .next_byte
456
  .zero:
457
        ret
458
 
459
endp
460
 
461
proc mpint_mod uses eax ecx, dst, mod
462
 
463
        ; if mod is zero, return
464
        stdcall mpint_zero?, [mod]
465
        jz      .zero
466
 
467
        stdcall mpint_cmp, [mod], [dst]
468
        jb      .done                           ; if dst < mod, dst = dst
469
        je      .zero                           ; if dst == mod, dst = 0
470
 
471
        ; left shift mod until the high order bits of mod and dst are aligned
472
        stdcall mpint_hob, [dst]
473
        mov     ecx, eax
474
        stdcall mpint_hob, [mod]
475
        sub     ecx, eax
476
        stdcall mpint_shlmov, mpint_tmp, [mod], ecx
477
        inc     ecx
478
 
479
        ; For every bit in dst (starting from the high order bit):
480
  .loop:
481
        ;   determine if dst is bigger than mpint_tmp
482
        stdcall mpint_cmp, [dst], mpint_tmp
483
        ja      @f
484
        ;   if so, subtract mpint_tmp from dst
485
        stdcall mpint_sub, [dst], mpint_tmp
486
  @@:
487
        dec     ecx
488
        jz      .done
489
        ;   shift mpint_tmp right by 1
490
        stdcall mpint_shr1, mpint_tmp
491
        jmp     .loop
492
 
493
  .zero:
494
        stdcall mpint_zero, [dst]
495
  .done:
496
        ret
497
 
498
endp
499
 
500
proc mpint_modexp uses edi eax ebx ecx, dst, base, exp, mod
501
 
502
        ; If mod is zero, return
503
        stdcall mpint_zero?, [mod]
504
        jz      .mod_zero
505
 
506
        ; Find the highest order byte in exponent
507
        mov     edi, [exp]
508
        mov     ecx, [edi]
509
        lea     edi, [edi + 4 + ecx - 1]
510
        ; Find the highest order bit in this byte
511
        mov     al, [edi]
512
        test    al, al
513
        jz      .invalid
514
        mov     bl, 9
515
  @@:
516
        dec     bl
517
        shl     al, 1
518
        jnc     @r
519
 
520
        ; Initialise result to base, to take care of the highest order bit
521
        stdcall mpint_mov0, [dst], [base]
522
        dec     bl
523
        jz      .next_byte
524
  .bit_loop:
525
        ; For each bit, square result
526
        stdcall mpint_mov, mpint_tmp, [dst]
527
        stdcall mpint_mul, [dst], mpint_tmp, mpint_tmp
528
        stdcall mpint_mod, [dst], [mod]
529
 
530
        ; If the bit is set, multiply result by the base
531
        shl     al, 1
532
        jnc     .next_bit
533
        stdcall mpint_mov, mpint_tmp, [dst]
534
        stdcall mpint_mul, [dst], [base], mpint_tmp
535
        stdcall mpint_mod, [dst], [mod]
536
  .next_bit:
537
        dec     bl
538
        jnz     .bit_loop
539
  .next_byte:
540
        dec     ecx
541
        jz      .done
542
        dec     edi
543
        mov     al, [edi]
544
        mov     bl, 8
545
        jmp     .bit_loop
546
  .done:
547
        ret
548
 
549
  .mod_zero:
550
        DEBUGF  1, "modexp with modulo 0\n"
551
        ; if mod is zero, result = 0
552
        stdcall mpint_zero, [dst]
553
        ret
554
 
555
  .exp_zero:
556
        DEBUGF  1, "modexp with exponent 0\n"
557
        ; if exponent is zero, result = 1
558
        stdcall mpint_zero, [dst]
559
        mov     eax, [dst]
560
        mov     byte[eax], 1
561
        mov     byte[eax+4], 1
562
        ret
563
 
564
  .invalid:
565
        DEBUGF  1, "modexp: Invalid input!\n"
566
        ret
567
 
568
endp