Subversion Repositories Kolibri OS

Rev

Rev 6469 | Rev 9070 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6419 hidnplayr 1
;    mpint.inc - Multi precision integer procedures
2
;
6922 hidnplayr 3
;    Copyright (C) 2015-2017 Jeffrey Amelynck
6419 hidnplayr 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
 
6922 hidnplayr 18
; Notes:
19
;
20
; These procedures work only with positive integers.
21
; For compatibility reasons, the highest bit must always be 0.
22
; However, leading 0 bytes MUST at all other times be omitted.
23
;
24
; You have been warned!
25
 
6419 hidnplayr 26
MPINT_MAX_LEN = MAX_BITS/8
27
 
28
 
6922 hidnplayr 29
;;===========================================================================;;
30
proc mpint_to_little_endian uses esi edi ecx ;///////////////////////////////;;
31
;;---------------------------------------------------------------------------;;
32
;? Convert big endian MPINT to little endian MPINT.                          ;;
33
;;---------------------------------------------------------------------------;;
34
;> esi = pointer to big endian MPINT                                         ;;
35
;> edi = pointer to buffer for little endian MPINT                           ;;
36
;;---------------------------------------------------------------------------;;
37
;< eax = MPINT number length                                                 ;;
38
;;===========================================================================;;
6419 hidnplayr 39
 
40
; Load length dword
41
        lodsd
42
; Convert to little endian
43
        bswap   eax
44
        stosd
45
        test    eax, eax
46
        jz      .zero
47
; Copy data, convert to little endian meanwhile
48
        push    eax
49
        add     esi, eax
50
        push    esi
51
        dec     esi
52
        mov     ecx, eax
53
        std
54
  @@:
55
        lodsb
56
        mov     byte[edi], al
57
        inc     edi
58
        dec     ecx
59
        jnz     @r
60
        cld
61
        pop     esi eax
62
  .zero:
63
        ret
64
 
6922 hidnplayr 65
endp
6419 hidnplayr 66
 
6922 hidnplayr 67
;;===========================================================================;;
68
proc mpint_to_big_endian uses esi edi ecx ;//////////////////////////////////;;
69
;;---------------------------------------------------------------------------;;
70
;? Convert little endian MPINT to big endian MPINT.                          ;;
71
;;---------------------------------------------------------------------------;;
72
;> esi = pointer to little endian MPINT                                      ;;
73
;> edi = pointer to buffer for big endian MPINT                              ;;
74
;;---------------------------------------------------------------------------;;
75
;< eax = MPINT number length                                                 ;;
76
;;===========================================================================;;
77
 
6419 hidnplayr 78
; Load length dword
79
        lodsd
80
        test    eax, eax
81
        jz      .zero
82
        mov     ecx, eax
6922 hidnplayr 83
        add     esi, eax
6419 hidnplayr 84
        dec     esi
6922 hidnplayr 85
        push    eax     ; we'll return length to the caller later
6419 hidnplayr 86
        bswap   eax
87
        stosd
88
; Copy data, convert to big endian meanwhile
89
        std
90
  @@:
91
        lodsb
92
        mov     byte[edi], al
93
        inc     edi
94
        dec     ecx
95
        jnz     @r
96
        cld
97
        pop     eax
98
        ret
99
 
100
  .zero:
6922 hidnplayr 101
        stosd           ; Number 0 has 0 data bytes
6419 hidnplayr 102
        ret
103
 
104
endp
105
 
6922 hidnplayr 106
;;===========================================================================;;
107
proc mpint_print uses ecx esi eax, src ;/////////////////////////////////////;;
108
;;---------------------------------------------------------------------------;;
109
;? Print MPINT to the debug board.                                           ;;
110
;;---------------------------------------------------------------------------;;
111
;> src = pointer to little endian MPINT                                      ;;
112
;;---------------------------------------------------------------------------;;
113
;< -                                                                         ;;
114
;;===========================================================================;;
6419 hidnplayr 115
 
116
        DEBUGF  1, "0x"
117
        mov     esi, [src]
118
        mov     ecx, [esi]
119
        test    ecx, ecx
120
        jz      .zero
121
        lea     esi, [esi + ecx + 4 - 1]
122
        pushf
123
        std
124
  .loop:
125
        lodsb
126
        DEBUGF  1, "%x", eax:2
127
        dec     ecx
128
        jnz     .loop
129
        DEBUGF  1, "\n"
130
        popf
131
 
132
        ret
133
 
134
  .zero:
135
        DEBUGF  1, "00\n"
136
        ret
137
 
138
endp
139
 
6922 hidnplayr 140
;;===========================================================================;;
141
proc mpint_hob uses edi ecx eax, dst ;///////////////////////////////////////;;
142
;;---------------------------------------------------------------------------;;
143
;? Return an index number giving the position of the highest order bit.      ;;
144
;;---------------------------------------------------------------------------;;
145
;> src = pointer to little endian MPINT                                      ;;
146
;;---------------------------------------------------------------------------;;
147
;< eax = highest order bit number                                            ;;
148
;;===========================================================================;;
6419 hidnplayr 149
 
150
        mov     edi, [dst]
6922 hidnplayr 151
        lodsd
152
        dec     eax                     ; total length minus one
153
        mov     cl, [edi+eax]           ; load the highest order byte
154
        shl     eax, 3                  ; multiply eax by 8 to get nr of bits
6419 hidnplayr 155
 
6922 hidnplayr 156
; Now shift bits of the highest order byte right, until the byte reaches zero, counting bits meanwhile
157
        test    cl, cl
158
        jz      .end
6419 hidnplayr 159
  @@:
160
        inc     eax
161
        shr     cl, 1
162
        jnz     @r
6922 hidnplayr 163
  .end:
6419 hidnplayr 164
        ret
165
 
166
endp
167
 
6922 hidnplayr 168
;;===========================================================================;;
169
proc mpint_cmp uses esi edi ecx eax, dst, src ;//////////////////////////////;;
170
;;---------------------------------------------------------------------------;;
171
;? Compare two mpints.                                                       ;;
172
;;---------------------------------------------------------------------------;;
173
;> dst = pointer to little endian MPINT                                      ;;
174
;> src = pointer to little endian MPINT                                      ;;
175
;;---------------------------------------------------------------------------;;
176
;< flags are set as for single precision CMP instruction                     ;;
177
;;===========================================================================;;
6419 hidnplayr 178
 
6922 hidnplayr 179
; First, check if number of significant bytes is the same
180
; If not, number with more bytes is bigger
6419 hidnplayr 181
        mov     esi, [src]
182
        mov     edi, [dst]
6922 hidnplayr 183
        mov     ecx, [esi]
184
        cmp     ecx, [edi]
185
        jne     .got_answer
186
 
187
; Numbers have equal amount of bytes, compare starting from the high order byte
188
        add     edi, ecx
189
        add     esi, ecx
6419 hidnplayr 190
        std
6922 hidnplayr 191
  .do_byte:
192
        test    ecx, 11b
193
        jz      .do_dword
194
        dec     esi
195
        dec     edi
196
        cmpsb
197
        jne     .got_answer
198
        dec     ecx
199
        jmp     .do_byte
200
  .do_dword:
201
        shr     ecx, 2
202
        jz      .got_answer
203
        sub     esi, 4
204
        sub     edi, 4
6419 hidnplayr 205
        repe cmpsd
6922 hidnplayr 206
  .got_answer:
6419 hidnplayr 207
        cld
208
        ret
209
 
210
endp
211
 
6922 hidnplayr 212
;;===========================================================================;;
213
proc mpint_mov uses esi edi ecx, dst, src ;//////////////////////////////////;;
214
;;---------------------------------------------------------------------------;;
215
;? Copy mpint.                                                               ;;
216
;;---------------------------------------------------------------------------;;
217
;> dst = pointer to buffer for little endian MPINT                           ;;
218
;> src = pointer to little endian MPINT                                      ;;
219
;;---------------------------------------------------------------------------;;
220
;< dst = src                                                                 ;;
221
;;===========================================================================;;
6419 hidnplayr 222
 
223
        mov     esi, [src]
224
        mov     edi, [dst]
6922 hidnplayr 225
        mov     ecx, [esi]
226
        push    ecx
227
        shr     ecx, 2
228
        inc     ecx             ; for length dword
6419 hidnplayr 229
        rep movsd
6922 hidnplayr 230
        pop     ecx
231
        and     ecx, 11b
232
        jz      @f
6419 hidnplayr 233
        rep movsb
234
  @@:
235
 
236
        ret
237
 
238
endp
239
 
6922 hidnplayr 240
;;===========================================================================;;
241
proc mpint_shl1 uses esi ecx, dst ;//////////////////////////////////////////;;
242
;;---------------------------------------------------------------------------;;
243
;? Shift little endian MPINT one bit to the left.                            ;;
244
;;---------------------------------------------------------------------------;;
245
;> dst = pointer to little endian MPINT                                      ;;
246
;;---------------------------------------------------------------------------;;
247
;< dst = dst SHL 1                                                           ;;
248
;;===========================================================================;;
6419 hidnplayr 249
 
6922 hidnplayr 250
        mov     esi, [dst]
251
        mov     ecx, [esi]
252
        test    ecx, ecx
253
        jz      .done
6419 hidnplayr 254
 
6922 hidnplayr 255
; Test if high order byte will overflow
256
; Remember: highest bit must never be set for positive numbers!
257
        test    byte[esi+ecx+3], 11000000b
258
        jz      @f
259
; We must grow a byte in size!
260
; TODO: check for overflow
261
        inc     ecx
262
        mov     [esi], ecx
263
        mov     byte[esi+ecx+3], 0        ; Add the new MSB
6419 hidnplayr 264
  @@:
6922 hidnplayr 265
        add     esi, 4
266
; Do the lowest order byte first
267
        shl     byte[esi], 1
6419 hidnplayr 268
        dec     ecx
6922 hidnplayr 269
        jz      .done
270
; And the remaining bytes
271
  @@:
272
        inc     esi
273
        rcl     byte[esi], 1
274
        dec     ecx
6419 hidnplayr 275
        jnz     @r
6922 hidnplayr 276
  .done:
6419 hidnplayr 277
        ret
278
 
279
endp
280
 
6922 hidnplayr 281
;;===========================================================================;;
282
proc mpint_shr1 uses edi ecx, dst ;//////////////////////////////////////////;;
283
;;---------------------------------------------------------------------------;;
284
;? Shift little endian MPINT one bit to the right.                           ;;
285
;;---------------------------------------------------------------------------;;
286
;> dst = pointer to little endian MPINT                                      ;;
287
;;---------------------------------------------------------------------------;;
288
;< dst = dst SHR 1                                                           ;;
289
;;===========================================================================;;
6419 hidnplayr 290
 
291
        mov     edi, [dst]
6922 hidnplayr 292
        mov     ecx, [edi]
293
        test    ecx, ecx
294
        jz      .done
6419 hidnplayr 295
 
6922 hidnplayr 296
; Do the highest order byte first
297
        dec     ecx
298
        shr     byte[edi+ecx+3], 1
299
; Was it 0? If so, we must decrement total length
300
        jnz     @f
301
        jc      @f
302
        mov     [edi], ecx
6419 hidnplayr 303
  @@:
6922 hidnplayr 304
        test    ecx, ecx
305
        jz      .done
306
; Now do the trailing bytes
307
        add     edi, 4
308
        add     edi, ecx
309
  @@:
310
        dec     edi
311
        rcr     byte[edi], 1
312
        dec     ecx             ; does not affect carry flag, hooray!
6419 hidnplayr 313
        jnz     @r
6922 hidnplayr 314
  .done:
6419 hidnplayr 315
        ret
316
 
317
endp
318
 
6922 hidnplayr 319
;;===========================================================================;;
320
proc mpint_shl uses eax ebx ecx edx esi edi, dst, shift ;////////////////////;;
321
;;---------------------------------------------------------------------------;;
322
;? Left shift little endian MPINT by x bits.                                 ;;
323
;;---------------------------------------------------------------------------;;
324
;> dst = pointer to little endian MPINT                                      ;;
325
;> shift = number of bits to shift the MPINT                                 ;;
326
;;---------------------------------------------------------------------------;;
327
;< -                                                                         ;;
328
;;===========================================================================;;
6419 hidnplayr 329
 
330
        mov     ecx, [shift]
331
        shr     ecx, 3                  ; 8 bits in one byte
332
        cmp     ecx, MPINT_MAX_LEN
333
        jge     .zero
334
        mov     esi, [dst]
335
        add     esi, MPINT_MAX_LEN+4-4
336
        mov     edi, esi
337
        and     ecx, not 11b
338
        sub     esi, ecx
339
        mov     edx, MPINT_MAX_LEN/4-1
340
        shr     ecx, 2                  ; 4 bytes in one dword
341
        push    ecx
342
        sub     edx, ecx
343
        mov     ecx, [shift]
344
        and     ecx, 11111b
345
        std
346
  .loop:
347
        lodsd
348
        mov     ebx, [esi]
349
        shld    eax, ebx, cl
350
        stosd
351
        dec     edx
352
        jnz     .loop
353
        lodsd
354
        shl     eax, cl
355
        stosd
356
 
357
        ; fill the lsb bytes with zeros
358
        pop     ecx
359
        test    ecx, ecx
360
        jz      @f
361
        xor     eax, eax
362
        rep stosd
363
  @@:
364
        cld
365
        ret
366
 
367
  .zero:
6922 hidnplayr 368
        mov     eax, [dst]
369
        mov     dword[eax], 0
6419 hidnplayr 370
        ret
371
 
372
endp
373
 
6922 hidnplayr 374
;;===========================================================================;;
375
proc mpint_shlmov uses eax ebx ecx edx esi edi, dst, src, shift ;////////////;;
376
;;---------------------------------------------------------------------------;;
377
;? Left shift by x bits and copy little endian MPINT.                        ;;
378
;;---------------------------------------------------------------------------;;
379
;> src = pointer to little endian MPINT                                      ;;
380
;> dst = pointer to little endian MPINT                                      ;;
381
;> shift = number of bits to shift the MPINT to the left                     ;;
382
;;---------------------------------------------------------------------------;;
383
;< dst = src SHL shift                                                       ;;
384
;;===========================================================================;;
6419 hidnplayr 385
 
386
        mov     ecx, [shift]
387
        shr     ecx, 3                  ; 8 bits in one byte
388
        cmp     ecx, MPINT_MAX_LEN
389
        jge     .zero
390
        mov     esi, [src]
391
        add     esi, MPINT_MAX_LEN+4-4
392
        mov     edi, [dst]
393
        add     edi, MPINT_MAX_LEN+4-4
394
        and     ecx, not 11b
395
        sub     esi, ecx
396
        mov     edx, MPINT_MAX_LEN/4-1
397
        shr     ecx, 2                  ; 4 bytes in one dword
398
        push    ecx
399
        sub     edx, ecx
400
        mov     ecx, [shift]
401
        and     ecx, 11111b
402
        std
403
  .loop:
404
        lodsd
405
        mov     ebx, [esi]
406
        shld    eax, ebx, cl
407
        stosd
408
        dec     edx
409
        jnz     .loop
410
        lodsd
411
        shl     eax, cl
412
        stosd
413
 
414
        ; fill the lsb bytes with zeros
415
        pop     ecx
416
        test    ecx, ecx
417
        jz      @f
418
        xor     eax, eax
419
        rep stosd
420
  @@:
421
        cld
422
        ret
423
 
424
  .zero:
6922 hidnplayr 425
        mov     eax, [dst]
426
        mov     dword[eax], 0
6419 hidnplayr 427
        ret
428
 
429
endp
430
 
6922 hidnplayr 431
;;===========================================================================;;
432
proc mpint_add uses esi edi ecx eax, dst, src ;//////////////////////////////;;
433
;;---------------------------------------------------------------------------;;
434
;? Add a little endian MPINT to another little endian MPINT.                 ;;
435
;;---------------------------------------------------------------------------;;
436
;> src = pointer to little endian MPINT                                      ;;
437
;> dst = pointer to little endian MPINT                                      ;;
438
;;---------------------------------------------------------------------------;;
439
;< dst = dst + src                                                           ;;
440
;;===========================================================================;;
6419 hidnplayr 441
 
442
        mov     esi, [src]
443
        mov     edi, [dst]
6922 hidnplayr 444
        mov     ecx, [esi]      ; source number length
445
        sub     ecx, [dst]
446
        jbe     .length_ok
447
; Length of the destination is currently smaller then the source, pad with 0 bytes
448
        add     edi, [edi]
6419 hidnplayr 449
        add     edi, 4
6922 hidnplayr 450
        mov     al, 0
451
        rep stosb
452
  .length_ok:
453
        mov     ecx, [esi]
454
        mov     edi, [dst]
455
        add     esi, 4
6419 hidnplayr 456
        add     edi, 4
6922 hidnplayr 457
; Add the first byte
458
        lodsb
459
        add     byte[edi], al
6419 hidnplayr 460
        dec     ecx
6922 hidnplayr 461
        jz      .done
462
; Add the other bytes
463
  @@:
464
        inc     edi
465
        lodsb
466
        adc     byte[edi], al
467
        dec     ecx
6419 hidnplayr 468
        jnz     @r
6922 hidnplayr 469
  .done:
470
; check if highest bit OR carry flag is set
471
; if so, add a byte if we have the buffer space
472
; TODO: check if we have the buffer space
473
        jc      .carry
474
        cmp     byte[edi], 0x80
475
        jnz     .high_bit_set
6419 hidnplayr 476
 
477
        ret
478
 
6922 hidnplayr 479
  .carry:
480
        inc     edi
481
        mov     byte[edi], 1
482
        mov     eax, [dst]
483
        inc     dword[eax]
484
 
485
        ret
486
 
487
  .high_bit_set:
488
        inc     edi
489
        mov     byte[edi], 0
490
        mov     eax, [dst]
491
        inc     dword[eax]
492
 
493
        ret
494
 
6419 hidnplayr 495
endp
496
 
6922 hidnplayr 497
;;===========================================================================;;
498
proc mpint_sub uses eax esi edi ecx, dst, src ;//////////////////////////////;;
499
;;---------------------------------------------------------------------------;;
500
;? Subtract a little endian MPINT to another little endian MPINT.            ;;
501
;;---------------------------------------------------------------------------;;
502
;> src = pointer to little endian MPINT                                      ;;
503
;> dst = pointer to little endian MPINT                                      ;;
504
;;---------------------------------------------------------------------------;;
505
;< dst = dst - src                                                           ;;
506
;;===========================================================================;;
6419 hidnplayr 507
 
508
        mov     esi, [src]
6922 hidnplayr 509
        mov     edi, [dst]
510
        mov     ecx, [esi]      ; destination number length
511
        cmp     ecx, [edi]
512
        ja      .overflow
513
 
6419 hidnplayr 514
        add     esi, 4
515
        add     edi, 4
6922 hidnplayr 516
; Subtract the first byte
517
        lodsb
518
        sub     byte[edi], al
519
        dec     ecx
520
        jz      .done
521
; Subtract the other bytes
6419 hidnplayr 522
  @@:
6922 hidnplayr 523
        inc     edi
524
        lodsb
525
        sbb     byte[edi], al
6419 hidnplayr 526
        dec     ecx
6922 hidnplayr 527
        jnz     @r
528
  .done:
529
        stdcall mpint_shrink, [dst]
6419 hidnplayr 530
        ret
531
 
6922 hidnplayr 532
  .overflow:
533
        mov     dword[edi], 0
534
        stc
535
        ret
536
 
6419 hidnplayr 537
endp
538
 
539
 
6922 hidnplayr 540
;;===========================================================================;;
541
proc mpint_shrink uses eax edi ecx, dst ;////////////////////////////////////;;
542
;;---------------------------------------------------------------------------;;
543
;? Get rid of leading zeroes on a little endian MPINT.                       ;;
544
;;---------------------------------------------------------------------------;;
545
;> src = pointer to little endian MPINT                                      ;;
546
;;---------------------------------------------------------------------------;;
547
;<                                                                           ;;
548
;;===========================================================================;;
6419 hidnplayr 549
 
6922 hidnplayr 550
        mov     edi, [dst]
551
        lodsd
6419 hidnplayr 552
        std
6922 hidnplayr 553
        mov     ecx, eax
554
        dec     eax             ; total length minus one
555
        add     edi, eax
6419 hidnplayr 556
        xor     al, al
6922 hidnplayr 557
        repe cmpsb
558
        inc     ecx
559
        mov     edi, [dst]
560
        mov     [edi], ecx
6419 hidnplayr 561
        cld
6922 hidnplayr 562
 
563
        ret
564
 
565
endp
566
 
567
;;===========================================================================;;
568
proc mpint_mul uses esi edi ecx ebx eax, dst, A, B ;/////////////////////////;;
569
;;---------------------------------------------------------------------------;;
570
;? Multiply to little endian MPINTS and store them in a new one.             ;;
571
;;---------------------------------------------------------------------------;;
572
;> A = pointer to little endian MPINT                                        ;;
573
;> B = pointer to little endian MPINT                                        ;;
574
;> dst = pointer to buffer for little endian MPINT                           ;;
575
;;---------------------------------------------------------------------------;;
576
;< dst = A * B                                                               ;;
577
;;===========================================================================;;
578
 
579
        ; Set result to zero
580
        mov     eax, [dst]
581
        mov     dword[eax], 0
582
 
583
        ; first, find the byte in A containing the highest order bit
584
        mov     edi, [A]
585
        mov     eax, [edi]
586
        test    eax, eax
587
        jz      .zero
588
        add     edi, eax
6419 hidnplayr 589
        mov     al, [edi+1]
590
        mov     esi, edi
591
        mov     bl, 8
592
  @@:
593
        shl     al, 1
594
        jc      .first_hit
595
        dec     bl
596
        jnz     @r
597
 
598
        ; Then, starting from this byte, iterate through the bits in A,
599
        ; starting from the highest order bit down to the lowest order bit.
600
  .next_byte:
601
        mov     al, [edi]
602
        dec     edi
603
        mov     bl, 8
604
  .next_bit:
605
        stdcall mpint_shl1, [dst]
606
        shl     al, 1
607
        jnc     .zero_bit
608
  .first_hit:
609
        stdcall mpint_add, [dst], [B]
610
  .zero_bit:
611
        dec     bl
612
        jnz     .next_bit
613
        dec     ecx
614
        jnz     .next_byte
615
  .zero:
616
        ret
617
 
618
endp
619
 
6922 hidnplayr 620
;;===========================================================================;;
621
proc mpint_mod uses eax ebx ecx, dst, mod ;//////////////////////////////////;;
622
;;---------------------------------------------------------------------------;;
623
;? Find the modulo (remainder after division) of dst by mod.                 ;;
624
;;---------------------------------------------------------------------------;;
625
;> dst = pointer to little endian MPINT                                      ;;
626
;> mod = pointer to little endian MPINT                                      ;;
627
;;---------------------------------------------------------------------------;;
628
;< dst = dst MOD mod                                                         ;;
629
;;===========================================================================;;
6419 hidnplayr 630
 
6922 hidnplayr 631
locals
632
        mpint_tmp       rb MPINT_MAX_LEN+4
633
endl
634
 
6419 hidnplayr 635
        ; if mod is zero, return
6922 hidnplayr 636
        mov     eax, [mod]
637
        cmp     dword[eax], 0
638
        je      .zero
6419 hidnplayr 639
 
6922 hidnplayr 640
        stdcall mpint_cmp, eax, [dst]
6419 hidnplayr 641
        jb      .done                           ; if dst < mod, dst = dst
642
        je      .zero                           ; if dst == mod, dst = 0
643
 
6922 hidnplayr 644
        lea     ebx, [mpint_tmp]
645
 
6419 hidnplayr 646
        ; left shift mod until the high order bits of mod and dst are aligned
647
        stdcall mpint_hob, [dst]
648
        mov     ecx, eax
649
        stdcall mpint_hob, [mod]
650
        sub     ecx, eax
6922 hidnplayr 651
        stdcall mpint_shlmov, ebx, [mod], ecx
6419 hidnplayr 652
        inc     ecx
653
 
654
        ; For every bit in dst (starting from the high order bit):
655
  .loop:
656
        ;   determine if dst is bigger than mpint_tmp
6922 hidnplayr 657
        stdcall mpint_cmp, [dst], ebx
6419 hidnplayr 658
        ja      @f
659
        ;   if so, subtract mpint_tmp from dst
6922 hidnplayr 660
        stdcall mpint_sub, [dst], ebx
6419 hidnplayr 661
  @@:
662
        dec     ecx
663
        jz      .done
664
        ;   shift mpint_tmp right by 1
6922 hidnplayr 665
        stdcall mpint_shr1, ebx
6419 hidnplayr 666
        jmp     .loop
667
 
668
  .zero:
6922 hidnplayr 669
        mov     eax, [dst]
670
        mov     dword[eax], 0
6419 hidnplayr 671
  .done:
672
        ret
673
 
674
endp
675
 
6922 hidnplayr 676
;;===========================================================================;;
677
proc mpint_modexp uses edi eax ebx ecx edx, dst, base, exp, mod ;////////////;;
678
;;---------------------------------------------------------------------------;;
679
;? Find the modulo (remainder after division) of dst by mod.                 ;;
680
;;---------------------------------------------------------------------------;;
681
;> dst = pointer to buffer for little endian MPINT                           ;;
682
;> base = pointer to little endian MPINT                                     ;;
683
;> exp = pointer to little endian MPINT                                      ;;
684
;> mod = pointer to little endian MPINT                                      ;;
685
;;---------------------------------------------------------------------------;;
686
;< dst = base ** exp MOD mod                                                 ;;
687
;;===========================================================================;;
6419 hidnplayr 688
 
6922 hidnplayr 689
locals
690
        mpint_tmp       rb MPINT_MAX_LEN+4
691
endl
692
 
6419 hidnplayr 693
        ; If mod is zero, return
6922 hidnplayr 694
        mov     eax, [mod]
695
        cmp     dword[eax], 0
696
        je      .mod_zero
6419 hidnplayr 697
 
698
        ; Find the highest order byte in exponent
699
        mov     edi, [exp]
700
        mov     ecx, [edi]
701
        lea     edi, [edi + 4 + ecx - 1]
702
        ; Find the highest order bit in this byte
703
        mov     al, [edi]
704
        test    al, al
705
        jz      .invalid
706
        mov     bl, 9
707
  @@:
708
        dec     bl
709
        shl     al, 1
710
        jnc     @r
711
 
6922 hidnplayr 712
        lea     edx, [mpint_tmp]
6419 hidnplayr 713
        ; Initialise result to base, to take care of the highest order bit
6922 hidnplayr 714
        stdcall mpint_mov, [dst], [base]
6419 hidnplayr 715
        dec     bl
716
        jz      .next_byte
717
  .bit_loop:
718
        ; For each bit, square result
6922 hidnplayr 719
        stdcall mpint_mov, edx, [dst]
720
        stdcall mpint_mul, [dst], edx, edx
6419 hidnplayr 721
        stdcall mpint_mod, [dst], [mod]
722
 
723
        ; If the bit is set, multiply result by the base
724
        shl     al, 1
725
        jnc     .next_bit
6922 hidnplayr 726
        stdcall mpint_mov, edx, [dst]
727
        stdcall mpint_mul, [dst], [base], edx
6419 hidnplayr 728
        stdcall mpint_mod, [dst], [mod]
729
  .next_bit:
730
        dec     bl
731
        jnz     .bit_loop
732
  .next_byte:
733
        dec     ecx
734
        jz      .done
735
        dec     edi
736
        mov     al, [edi]
737
        mov     bl, 8
738
        jmp     .bit_loop
739
  .done:
740
        ret
741
 
742
  .mod_zero:
6469 hidnplayr 743
        DEBUGF  3, "modexp with modulo 0\n"
6419 hidnplayr 744
        ; if mod is zero, result = 0
6922 hidnplayr 745
        mov     eax, [dst]
746
        mov     dword[eax], 0
6419 hidnplayr 747
        ret
748
 
749
  .exp_zero:
6469 hidnplayr 750
        DEBUGF  3, "modexp with exponent 0\n"
6419 hidnplayr 751
        ; if exponent is zero, result = 1
752
        mov     eax, [dst]
6922 hidnplayr 753
        mov     dword[eax], 1
6419 hidnplayr 754
        mov     byte[eax+4], 1
755
        ret
756
 
757
  .invalid:
6469 hidnplayr 758
        DEBUGF  3, "modexp: Invalid input!\n"
6419 hidnplayr 759
        ret
760
 
761
endp