Subversion Repositories Kolibri OS

Rev

Rev 6922 | Rev 9090 | 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
;
9070 hidnplayr 3
;    Copyright (C) 2015-2021 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
;
23
; You have been warned!
24
 
6419 hidnplayr 25
MPINT_MAX_LEN = MAX_BITS/8
26
 
27
 
6922 hidnplayr 28
;;===========================================================================;;
9070 hidnplayr 29
proc mpint_to_little_endian uses esi edi ecx, dst, src ;/////////////////////;;
6922 hidnplayr 30
;;---------------------------------------------------------------------------;;
31
;? Convert big endian MPINT to little endian MPINT.                          ;;
32
;;---------------------------------------------------------------------------;;
9070 hidnplayr 33
;> src = pointer to big endian MPINT                                         ;;
34
;> dst = pointer to buffer for little endian MPINT                           ;;
6922 hidnplayr 35
;;---------------------------------------------------------------------------;;
36
;< eax = MPINT number length                                                 ;;
37
;;===========================================================================;;
6419 hidnplayr 38
 
9070 hidnplayr 39
        mov     esi, [src]
40
        mov     edi, [dst]
6419 hidnplayr 41
; Load length dword
42
        lodsd
43
; Convert to little endian
44
        bswap   eax
45
        stosd
46
        test    eax, eax
47
        jz      .zero
48
; Copy data, convert to little endian meanwhile
49
        push    eax
50
        add     esi, eax
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
9070 hidnplayr 60
 
6419 hidnplayr 61
        cld
9070 hidnplayr 62
        pop     eax
6419 hidnplayr 63
  .zero:
64
        ret
65
 
6922 hidnplayr 66
endp
6419 hidnplayr 67
 
6922 hidnplayr 68
;;===========================================================================;;
9070 hidnplayr 69
proc mpint_to_big_endian uses esi edi ecx, dst, src ;////////////////////////;;
6922 hidnplayr 70
;;---------------------------------------------------------------------------;;
71
;? Convert little endian MPINT to big endian MPINT.                          ;;
72
;;---------------------------------------------------------------------------;;
9070 hidnplayr 73
;> src = pointer to little endian MPINT                                      ;;
74
;> dst = pointer to buffer for big endian MPINT                              ;;
6922 hidnplayr 75
;;---------------------------------------------------------------------------;;
76
;< eax = MPINT number length                                                 ;;
77
;;===========================================================================;;
78
 
9070 hidnplayr 79
        mov     esi, [src]
80
        mov     edi, [dst]
6419 hidnplayr 81
; Load length dword
82
        lodsd
83
        test    eax, eax
84
        jz      .zero
85
        mov     ecx, eax
6922 hidnplayr 86
        add     esi, eax
6419 hidnplayr 87
        dec     esi
6922 hidnplayr 88
        push    eax     ; we'll return length to the caller later
6419 hidnplayr 89
        bswap   eax
90
        stosd
91
; Copy data, convert to big endian meanwhile
92
        std
93
  @@:
94
        lodsb
95
        mov     byte[edi], al
96
        inc     edi
97
        dec     ecx
98
        jnz     @r
99
        cld
100
        pop     eax
101
        ret
102
 
103
  .zero:
6922 hidnplayr 104
        stosd           ; Number 0 has 0 data bytes
6419 hidnplayr 105
        ret
106
 
107
endp
108
 
6922 hidnplayr 109
;;===========================================================================;;
110
proc mpint_print uses ecx esi eax, src ;/////////////////////////////////////;;
111
;;---------------------------------------------------------------------------;;
112
;? Print MPINT to the debug board.                                           ;;
113
;;---------------------------------------------------------------------------;;
114
;> src = pointer to little endian MPINT                                      ;;
115
;;---------------------------------------------------------------------------;;
116
;< -                                                                         ;;
117
;;===========================================================================;;
6419 hidnplayr 118
 
119
        DEBUGF  1, "0x"
120
        mov     esi, [src]
121
        mov     ecx, [esi]
122
        test    ecx, ecx
123
        jz      .zero
124
        lea     esi, [esi + ecx + 4 - 1]
125
        pushf
126
        std
127
  .loop:
128
        lodsb
129
        DEBUGF  1, "%x", eax:2
130
        dec     ecx
131
        jnz     .loop
132
        DEBUGF  1, "\n"
133
        popf
134
 
135
        ret
136
 
137
  .zero:
138
        DEBUGF  1, "00\n"
139
        ret
140
 
141
endp
142
 
6922 hidnplayr 143
;;===========================================================================;;
9070 hidnplayr 144
proc mpint_bits uses esi ecx, dst ;//////////////////////////////////////////;;
6922 hidnplayr 145
;;---------------------------------------------------------------------------;;
9070 hidnplayr 146
;? Count the number of bits in the MPINT                                     ;;
6922 hidnplayr 147
;;---------------------------------------------------------------------------;;
9070 hidnplayr 148
;> dst = pointer to little endian MPINT                                      ;;
6922 hidnplayr 149
;;---------------------------------------------------------------------------;;
9070 hidnplayr 150
;< eax = highest order bit number + 1                                        ;;
6922 hidnplayr 151
;;===========================================================================;;
6419 hidnplayr 152
 
9070 hidnplayr 153
        DEBUGF  1, "mpint_bits(0x%x): ", [dst]
6419 hidnplayr 154
 
9070 hidnplayr 155
        mov     esi, [dst]
156
        mov     eax, [esi]
157
        test    eax, eax
158
        jz      .zero
159
        add     esi, 4-1
160
; Find highest order byte
161
  .byteloop:
162
        cmp     byte[esi+eax], 0
163
        jne     .nz
164
        dec     eax
165
        jnz     .byteloop
166
  .zero:
167
        DEBUGF  1, "%u\n", eax
168
        ret
169
  .nz:
170
        mov     cl, byte[esi+eax]
171
; multiply (eax - 1) by 8 to get nr of bits before this byte
172
        dec     eax
173
        shl     eax, 3
6922 hidnplayr 174
; Now shift bits of the highest order byte right, until the byte reaches zero, counting bits meanwhile
9070 hidnplayr 175
  .bitloop:
6419 hidnplayr 176
        inc     eax
177
        shr     cl, 1
9070 hidnplayr 178
        jnz     .bitloop
179
        DEBUGF  1, "%u\n", eax
6419 hidnplayr 180
        ret
181
 
182
endp
183
 
9070 hidnplayr 184
 
6922 hidnplayr 185
;;===========================================================================;;
9070 hidnplayr 186
proc mpint_bytes uses esi, dst ;/////////////////////////////////////////////;;
6922 hidnplayr 187
;;---------------------------------------------------------------------------;;
9070 hidnplayr 188
;? Count the number of bytes in the MPINT                                    ;;
6922 hidnplayr 189
;;---------------------------------------------------------------------------;;
190
;> dst = pointer to little endian MPINT                                      ;;
9070 hidnplayr 191
;;---------------------------------------------------------------------------;;
192
;< eax = highest order byte number + 1                                       ;;
193
;;===========================================================================;;
194
 
195
        DEBUGF  1, "mpint_bytes(0x%x): ", [dst]
196
 
197
        mov     esi, [dst]
198
        mov     eax, [esi]
199
        test    eax, eax
200
        jz      .done
201
        add     esi, 4-1
202
; Find highest order byte
203
  .byteloop:
204
        cmp     byte[esi+eax], 0
205
        jne     .done
206
        dec     eax
207
        jnz     .byteloop
208
  .done:
209
        DEBUGF  1, "%u\n", eax
210
        ret
211
 
212
endp
213
 
214
;;===========================================================================;;
215
proc mpint_cmp uses esi edi ecx eax, src, dst ;//////////////////////////////;;
216
;;---------------------------------------------------------------------------;;
217
;? Compare two MPINTS.                                                       ;;
218
;;---------------------------------------------------------------------------;;
219
;> dst = pointer to little endian MPINT                                      ;;
6922 hidnplayr 220
;> src = pointer to little endian MPINT                                      ;;
221
;;---------------------------------------------------------------------------;;
222
;< flags are set as for single precision CMP instruction                     ;;
223
;;===========================================================================;;
6419 hidnplayr 224
 
9070 hidnplayr 225
        DEBUGF  1, "mpint_cmp(0x%x, 0x%x)\n", [dst], [src]
226
 
227
; First, check the size of both numbers
228
        stdcall mpint_bytes, [dst]
229
        mov     ecx, eax
230
        stdcall mpint_bytes, [src]
231
; If one number has more bytes, it is bigger
232
        cmp     eax, ecx
233
        jne     .got_answer
234
; If both numbers have 0 bytes, they are equal
235
        test    ecx, ecx
236
        jz      .got_answer
237
; Numbers have equal amount of bytes
238
; Start comparing from the MSB towards the LSB
6419 hidnplayr 239
        mov     esi, [src]
240
        mov     edi, [dst]
9070 hidnplayr 241
        add     esi, ecx
6922 hidnplayr 242
        add     edi, ecx
9070 hidnplayr 243
        add     esi, 4
244
        add     edi, 4
6419 hidnplayr 245
        std
9070 hidnplayr 246
; If remaining bytes is not divisible by 4, compare only one byte at a time
6922 hidnplayr 247
  .do_byte:
9070 hidnplayr 248
        test    ecx, 1b
6922 hidnplayr 249
        jz      .do_dword
250
        dec     esi
251
        dec     edi
9070 hidnplayr 252
        mov     al, byte[esi]
253
        cmp     al, byte[edi]
6922 hidnplayr 254
        jne     .got_answer
255
        dec     ecx
9070 hidnplayr 256
; Remaining bytes is divisable by 4, compare dwords
6922 hidnplayr 257
  .do_dword:
258
        shr     ecx, 2
259
        jz      .got_answer
260
        sub     esi, 4
261
        sub     edi, 4
6419 hidnplayr 262
        repe cmpsd
6922 hidnplayr 263
  .got_answer:
6419 hidnplayr 264
        cld
265
        ret
266
 
267
endp
268
 
6922 hidnplayr 269
;;===========================================================================;;
270
proc mpint_mov uses esi edi ecx, dst, src ;//////////////////////////////////;;
271
;;---------------------------------------------------------------------------;;
9070 hidnplayr 272
;? Copy MPINT.                                                               ;;
6922 hidnplayr 273
;;---------------------------------------------------------------------------;;
274
;> dst = pointer to buffer for little endian MPINT                           ;;
275
;> src = pointer to little endian MPINT                                      ;;
276
;;---------------------------------------------------------------------------;;
277
;< dst = src                                                                 ;;
278
;;===========================================================================;;
6419 hidnplayr 279
 
9070 hidnplayr 280
        DEBUGF  1, "mpint_mov(0x%x, 0x%x)\n", [dst], [src]
281
 
6419 hidnplayr 282
        mov     esi, [src]
283
        mov     edi, [dst]
6922 hidnplayr 284
        mov     ecx, [esi]
285
        push    ecx
286
        shr     ecx, 2
287
        inc     ecx             ; for length dword
6419 hidnplayr 288
        rep movsd
6922 hidnplayr 289
        pop     ecx
290
        and     ecx, 11b
291
        jz      @f
6419 hidnplayr 292
        rep movsb
293
  @@:
294
 
295
        ret
296
 
297
endp
298
 
6922 hidnplayr 299
;;===========================================================================;;
300
proc mpint_shl1 uses esi ecx, dst ;//////////////////////////////////////////;;
301
;;---------------------------------------------------------------------------;;
302
;? Shift little endian MPINT one bit to the left.                            ;;
303
;;---------------------------------------------------------------------------;;
304
;> dst = pointer to little endian MPINT                                      ;;
305
;;---------------------------------------------------------------------------;;
306
;< dst = dst SHL 1                                                           ;;
307
;;===========================================================================;;
6419 hidnplayr 308
 
9070 hidnplayr 309
        DEBUGF  1, "mpint_shl1(0x%x)\n", [dst]
310
 
6922 hidnplayr 311
        mov     esi, [dst]
312
        mov     ecx, [esi]
313
        test    ecx, ecx
314
        jz      .done
6419 hidnplayr 315
 
6922 hidnplayr 316
; Test if high order byte will overflow
317
; Remember: highest bit must never be set for positive numbers!
318
        test    byte[esi+ecx+3], 11000000b
319
        jz      @f
320
; We must grow a byte in size!
321
; TODO: check for overflow
322
        inc     ecx
323
        mov     [esi], ecx
324
        mov     byte[esi+ecx+3], 0        ; Add the new MSB
6419 hidnplayr 325
  @@:
6922 hidnplayr 326
        add     esi, 4
327
; Do the lowest order byte first
328
        shl     byte[esi], 1
6419 hidnplayr 329
        dec     ecx
6922 hidnplayr 330
        jz      .done
331
; And the remaining bytes
332
  @@:
333
        inc     esi
334
        rcl     byte[esi], 1
335
        dec     ecx
6419 hidnplayr 336
        jnz     @r
6922 hidnplayr 337
  .done:
6419 hidnplayr 338
        ret
339
 
340
endp
341
 
6922 hidnplayr 342
;;===========================================================================;;
343
proc mpint_shr1 uses edi ecx, dst ;//////////////////////////////////////////;;
344
;;---------------------------------------------------------------------------;;
345
;? Shift little endian MPINT one bit to the right.                           ;;
346
;;---------------------------------------------------------------------------;;
347
;> dst = pointer to little endian MPINT                                      ;;
348
;;---------------------------------------------------------------------------;;
349
;< dst = dst SHR 1                                                           ;;
350
;;===========================================================================;;
6419 hidnplayr 351
 
9070 hidnplayr 352
        DEBUGF  1, "mpint_shr1(0x%x)\n", [dst]
353
 
6419 hidnplayr 354
        mov     edi, [dst]
6922 hidnplayr 355
        mov     ecx, [edi]
356
        test    ecx, ecx
357
        jz      .done
6419 hidnplayr 358
 
6922 hidnplayr 359
; Do the highest order byte first
9070 hidnplayr 360
        add     edi, 4-1
361
        add     edi, ecx
362
        shr     byte[edi], 1
6922 hidnplayr 363
        dec     ecx
364
        jz      .done
365
; Now do the trailing bytes
366
  @@:
367
        dec     edi
368
        rcr     byte[edi], 1
369
        dec     ecx             ; does not affect carry flag, hooray!
6419 hidnplayr 370
        jnz     @r
6922 hidnplayr 371
  .done:
6419 hidnplayr 372
        ret
373
 
374
endp
375
 
6922 hidnplayr 376
;;===========================================================================;;
377
proc mpint_shl uses eax ebx ecx edx esi edi, dst, shift ;////////////////////;;
378
;;---------------------------------------------------------------------------;;
379
;? Left shift little endian MPINT by x bits.                                 ;;
380
;;---------------------------------------------------------------------------;;
381
;> dst = pointer to little endian MPINT                                      ;;
382
;> shift = number of bits to shift the MPINT                                 ;;
383
;;---------------------------------------------------------------------------;;
384
;< -                                                                         ;;
385
;;===========================================================================;;
6419 hidnplayr 386
 
9070 hidnplayr 387
        DEBUGF  1, "mpint_shl(0x%x, %u)\n", [dst], [shift]
388
 
389
; Calculate new size
390
        stdcall mpint_bits, [dst]
391
        add     eax, [shift]
392
        shr     eax, 3
393
        cmp     eax, MPINT_MAX_LEN
394
        jae     .overflow     ;;
395
        inc     eax
396
        mov     esi, [dst]
397
        mov     [esi], eax
398
 
6419 hidnplayr 399
        mov     ecx, [shift]
400
        shr     ecx, 3                  ; 8 bits in one byte
401
        add     esi, MPINT_MAX_LEN+4-4
402
        mov     edi, esi
403
        and     ecx, not 11b
404
        sub     esi, ecx
405
        mov     edx, MPINT_MAX_LEN/4-1
406
        shr     ecx, 2                  ; 4 bytes in one dword
407
        push    ecx
408
        sub     edx, ecx
409
        mov     ecx, [shift]
410
        and     ecx, 11111b
411
        std
412
  .loop:
413
        lodsd
414
        mov     ebx, [esi]
415
        shld    eax, ebx, cl
416
        stosd
417
        dec     edx
418
        jnz     .loop
419
        lodsd
420
        shl     eax, cl
421
        stosd
422
 
9070 hidnplayr 423
        ; fill the LSBs with zeros
6419 hidnplayr 424
        pop     ecx
425
        test    ecx, ecx
426
        jz      @f
427
        xor     eax, eax
428
        rep stosd
429
  @@:
430
        cld
431
        ret
432
 
433
  .zero:
6922 hidnplayr 434
        mov     eax, [dst]
435
        mov     dword[eax], 0
6419 hidnplayr 436
        ret
437
 
9070 hidnplayr 438
  .overflow:
439
        int3
440
        ret
441
 
6419 hidnplayr 442
endp
443
 
6922 hidnplayr 444
;;===========================================================================;;
445
proc mpint_shlmov uses eax ebx ecx edx esi edi, dst, src, shift ;////////////;;
446
;;---------------------------------------------------------------------------;;
447
;? Left shift by x bits and copy little endian MPINT.                        ;;
448
;;---------------------------------------------------------------------------;;
449
;> src = pointer to little endian MPINT                                      ;;
450
;> dst = pointer to little endian MPINT                                      ;;
451
;> shift = number of bits to shift the MPINT to the left                     ;;
452
;;---------------------------------------------------------------------------;;
453
;< dst = src SHL shift                                                       ;;
454
;;===========================================================================;;
6419 hidnplayr 455
 
9070 hidnplayr 456
        DEBUGF  1, "mpint_shlmov(0x%x, 0x%x, %u)\n", [dst], [src], [shift]
457
 
458
        stdcall mpint_bits, [src]
459
        test    eax, eax
460
        jz      .zero
461
        add     eax, [shift]
462
        shr     eax, 3
463
        inc     eax
464
        mov     edi, [dst]
465
        mov     [edi], eax
466
 
467
        cmp     eax, MPINT_MAX_LEN
468
        jae     .overflow        ;;;;
469
 
6419 hidnplayr 470
        mov     esi, [src]
471
        add     esi, MPINT_MAX_LEN+4-4
472
        add     edi, MPINT_MAX_LEN+4-4
9070 hidnplayr 473
        mov     ecx, [shift]
474
        shr     ecx, 3                  ; 8 bits in one byte
6419 hidnplayr 475
        and     ecx, not 11b
476
        sub     esi, ecx
477
        mov     edx, MPINT_MAX_LEN/4-1
478
        shr     ecx, 2                  ; 4 bytes in one dword
479
        push    ecx
480
        sub     edx, ecx
481
        mov     ecx, [shift]
482
        and     ecx, 11111b
483
        std
484
  .loop:
485
        lodsd
486
        mov     ebx, [esi]
487
        shld    eax, ebx, cl
488
        stosd
489
        dec     edx
490
        jnz     .loop
491
        lodsd
492
        shl     eax, cl
493
        stosd
494
 
495
        ; fill the lsb bytes with zeros
496
        pop     ecx
497
        test    ecx, ecx
498
        jz      @f
499
        xor     eax, eax
500
        rep stosd
501
  @@:
502
        cld
503
        ret
504
 
505
  .zero:
6922 hidnplayr 506
        mov     eax, [dst]
507
        mov     dword[eax], 0
6419 hidnplayr 508
        ret
509
 
9070 hidnplayr 510
  .overflow:
511
        int3
512
        ret
513
 
6419 hidnplayr 514
endp
515
 
6922 hidnplayr 516
;;===========================================================================;;
517
proc mpint_add uses esi edi ecx eax, dst, src ;//////////////////////////////;;
518
;;---------------------------------------------------------------------------;;
519
;? Add a little endian MPINT to another little endian MPINT.                 ;;
520
;;---------------------------------------------------------------------------;;
521
;> src = pointer to little endian MPINT                                      ;;
522
;> dst = pointer to little endian MPINT                                      ;;
523
;;---------------------------------------------------------------------------;;
524
;< dst = dst + src                                                           ;;
525
;;===========================================================================;;
6419 hidnplayr 526
 
9070 hidnplayr 527
        DEBUGF  1, "mpint_add(0x%x, 0x%x)\n", [dst], [src]
528
 
6419 hidnplayr 529
        mov     esi, [src]
530
        mov     edi, [dst]
9070 hidnplayr 531
        stdcall mpint_bytes, esi
532
        mov     ecx, eax
533
        stdcall mpint_bytes, edi
534
        cmp     ecx, eax
535
        jb      .grow_src
536
        ja      .grow_dst
537
        test    ecx, ecx
538
        jz      .done
539
 
6922 hidnplayr 540
  .length_ok:
9070 hidnplayr 541
        push    ecx
6922 hidnplayr 542
        add     esi, 4
6419 hidnplayr 543
        add     edi, 4
6922 hidnplayr 544
; Add the first byte
545
        lodsb
546
        add     byte[edi], al
6419 hidnplayr 547
        dec     ecx
6922 hidnplayr 548
        jz      .done
549
; Add the other bytes
550
  @@:
551
        inc     edi
552
        lodsb
553
        adc     byte[edi], al
554
        dec     ecx
6419 hidnplayr 555
        jnz     @r
6922 hidnplayr 556
  .done:
9070 hidnplayr 557
 
6922 hidnplayr 558
; check if highest bit OR carry flag is set
559
; if so, add a byte if we have the buffer space
560
; TODO: check if we have the buffer space
9070 hidnplayr 561
        pop     ecx
6922 hidnplayr 562
        jc      .carry
563
        cmp     byte[edi], 0x80
564
        jnz     .high_bit_set
6419 hidnplayr 565
 
566
        ret
567
 
6922 hidnplayr 568
  .carry:
569
        mov     eax, [dst]
9070 hidnplayr 570
        cmp     [eax], ecx
571
        ja      @f
6922 hidnplayr 572
        inc     dword[eax]
9070 hidnplayr 573
  @@:
574
        mov     byte[edi+1], 1
6922 hidnplayr 575
        ret
576
 
577
  .high_bit_set:
578
        mov     eax, [dst]
9070 hidnplayr 579
        cmp     [eax], ecx
580
        ja      @f
6922 hidnplayr 581
        inc     dword[eax]
9070 hidnplayr 582
  @@:
583
        mov     byte[edi+1], 0
6922 hidnplayr 584
        ret
585
 
9070 hidnplayr 586
  .grow_dst:
587
        stdcall mpint_grow, edi, ecx
588
        jmp     .length_ok
589
 
590
  .grow_src:
591
        mov     ecx, eax
592
        stdcall mpint_grow, esi, ecx
593
        jmp     .length_ok
594
 
6419 hidnplayr 595
endp
596
 
6922 hidnplayr 597
;;===========================================================================;;
598
proc mpint_sub uses eax esi edi ecx, dst, src ;//////////////////////////////;;
599
;;---------------------------------------------------------------------------;;
600
;? Subtract a little endian MPINT to another little endian MPINT.            ;;
601
;;---------------------------------------------------------------------------;;
602
;> src = pointer to little endian MPINT                                      ;;
603
;> dst = pointer to little endian MPINT                                      ;;
604
;;---------------------------------------------------------------------------;;
605
;< dst = dst - src                                                           ;;
606
;;===========================================================================;;
6419 hidnplayr 607
 
9070 hidnplayr 608
        DEBUGF  1, "mpint_sub(0x%x, 0x%x)\n", [dst], [src]
609
 
6419 hidnplayr 610
        mov     esi, [src]
6922 hidnplayr 611
        mov     edi, [dst]
9070 hidnplayr 612
        stdcall mpint_bytes, esi
613
        mov     ecx, eax
614
        stdcall mpint_bytes, edi
615
        cmp     ecx, eax
616
        jb      .grow_src
617
        ja      .grow_dst
618
        test    ecx, ecx
619
        jz      .done
6922 hidnplayr 620
 
9070 hidnplayr 621
  .length_ok:
6419 hidnplayr 622
        add     esi, 4
623
        add     edi, 4
6922 hidnplayr 624
; Subtract the first byte
625
        lodsb
626
        sub     byte[edi], al
627
        dec     ecx
628
        jz      .done
629
; Subtract the other bytes
6419 hidnplayr 630
  @@:
6922 hidnplayr 631
        inc     edi
632
        lodsb
633
        sbb     byte[edi], al
6419 hidnplayr 634
        dec     ecx
6922 hidnplayr 635
        jnz     @r
636
  .done:
6419 hidnplayr 637
        ret
638
 
6922 hidnplayr 639
  .overflow:
640
        mov     dword[edi], 0
641
        stc
642
        ret
643
 
9070 hidnplayr 644
  .grow_dst:
645
        stdcall mpint_grow, edi, ecx
646
        jmp     .length_ok
647
 
648
  .grow_src:
649
        mov     ecx, eax
650
        stdcall mpint_grow, esi, ecx
651
        jmp     .length_ok
652
 
6419 hidnplayr 653
endp
654
 
655
 
6922 hidnplayr 656
;;===========================================================================;;
9070 hidnplayr 657
proc mpint_shrink uses eax edi, dst ;////////////////////////////////////////;;
6922 hidnplayr 658
;;---------------------------------------------------------------------------;;
9070 hidnplayr 659
;? Get rid of unnescessary leading zeroes on a little endian MPINT.          ;;
6922 hidnplayr 660
;;---------------------------------------------------------------------------;;
661
;> src = pointer to little endian MPINT                                      ;;
662
;;---------------------------------------------------------------------------;;
663
;<                                                                           ;;
664
;;===========================================================================;;
6419 hidnplayr 665
 
9070 hidnplayr 666
        DEBUGF  1, "mpint_shrink(0x%x)\n", [dst]
667
 
668
;        mov     edi, [dst]
669
;        lodsd
670
;        std
671
;        mov     ecx, eax
672
;        dec     eax             ; total length minus one
673
;        add     edi, eax
674
;        xor     al, al
675
;        repe cmpsb
676
;        inc     ecx
677
;        mov     edi, [dst]
678
;        mov     [edi], ecx
679
;        cld
680
 
681
        stdcall mpint_bits, [dst]
682
        shr     eax, 3
683
        inc     eax
6922 hidnplayr 684
        mov     edi, [dst]
9070 hidnplayr 685
        mov     [edi], eax
686
 
687
        ret
688
 
689
endp
690
 
691
 
692
;;===========================================================================;;
693
proc mpint_grow uses eax edi ecx, dst, length ;//////////////////////////////;;
694
;;---------------------------------------------------------------------------;;
695
;? Add leading zeroes on a little endian MPINT.                              ;;
696
;;---------------------------------------------------------------------------;;
697
;> src = pointer to little endian MPINT                                      ;;
698
;> length = total length of the new MPINT in bytes                           ;;
699
;;---------------------------------------------------------------------------;;
700
;<                                                                           ;;
701
;;===========================================================================;;
702
 
703
        DEBUGF  1, "mpint_grow(0x%x, %u): ", [dst], [length]
704
 
705
        mov     edi, [dst]
706
        mov     eax, [edi]
707
        mov     ecx, [length]
708
        sub     ecx, eax
709
        jbe     .dontgrow
710
        lea     edi, [edi + 4 + eax]
6419 hidnplayr 711
        xor     al, al
9070 hidnplayr 712
        rep stosb
713
        mov     eax, [length]
6922 hidnplayr 714
        mov     edi, [dst]
9070 hidnplayr 715
        mov     [edi], eax
716
        DEBUGF  1, "ok\n"
717
        ret
6922 hidnplayr 718
 
9070 hidnplayr 719
  .dontgrow:
720
        DEBUGF  1, "already large enough!\n"
6922 hidnplayr 721
        ret
722
 
723
endp
724
 
725
;;===========================================================================;;
726
proc mpint_mul uses esi edi ecx ebx eax, dst, A, B ;/////////////////////////;;
727
;;---------------------------------------------------------------------------;;
9070 hidnplayr 728
;? Multiply two little endian MPINTS and store them in a third one.          ;;
6922 hidnplayr 729
;;---------------------------------------------------------------------------;;
730
;> A = pointer to little endian MPINT                                        ;;
731
;> B = pointer to little endian MPINT                                        ;;
732
;> dst = pointer to buffer for little endian MPINT                           ;;
733
;;---------------------------------------------------------------------------;;
734
;< dst = A * B                                                               ;;
735
;;===========================================================================;;
736
 
9070 hidnplayr 737
        DEBUGF  1, "mpint_mul(0x%x, 0x%x, 0x%x)\n", [dst], [A], [B]
738
 
6922 hidnplayr 739
        ; Set result to zero
740
        mov     eax, [dst]
741
        mov     dword[eax], 0
742
 
743
        mov     edi, [A]
9070 hidnplayr 744
        stdcall mpint_bytes, edi
6922 hidnplayr 745
        test    eax, eax
746
        jz      .zero
9070 hidnplayr 747
        add     edi, 4-1
6922 hidnplayr 748
        add     edi, eax
9070 hidnplayr 749
        mov     ecx, eax
750
; Iterate through the bits in A,
751
; starting from the highest order bit down to the lowest order bit.
6419 hidnplayr 752
  .next_byte:
753
        mov     al, [edi]
754
        dec     edi
755
        mov     bl, 8
756
  .next_bit:
757
        stdcall mpint_shl1, [dst]
758
        shl     al, 1
759
        jnc     .zero_bit
760
        stdcall mpint_add, [dst], [B]
761
  .zero_bit:
762
        dec     bl
763
        jnz     .next_bit
764
        dec     ecx
765
        jnz     .next_byte
766
  .zero:
767
        ret
768
 
769
endp
770
 
6922 hidnplayr 771
;;===========================================================================;;
772
proc mpint_mod uses eax ebx ecx, dst, mod ;//////////////////////////////////;;
773
;;---------------------------------------------------------------------------;;
774
;? Find the modulo (remainder after division) of dst by mod.                 ;;
775
;;---------------------------------------------------------------------------;;
776
;> dst = pointer to little endian MPINT                                      ;;
777
;> mod = pointer to little endian MPINT                                      ;;
778
;;---------------------------------------------------------------------------;;
779
;< dst = dst MOD mod                                                         ;;
780
;;===========================================================================;;
6419 hidnplayr 781
 
9070 hidnplayr 782
        DEBUGF  1, "mpint_mod(0x%x, 0x%x)\n", [dst], [mod]
783
 
6922 hidnplayr 784
locals
785
        mpint_tmp       rb MPINT_MAX_LEN+4
786
endl
787
 
9070 hidnplayr 788
        stdcall mpint_cmp, [mod], [dst]
789
        ja      .done                           ; if mod > dst, dst = dst    ;;;;;;;
790
        je      .zero                           ; if mod == dst, dst = 0
6419 hidnplayr 791
 
9070 hidnplayr 792
        ; left shift mod until the high order bits of mod and dst are aligned
6419 hidnplayr 793
 
9070 hidnplayr 794
        stdcall mpint_bits, [dst]
6419 hidnplayr 795
        mov     ecx, eax
9070 hidnplayr 796
        stdcall mpint_bits, [mod]
797
        test    eax, eax
798
        jz      .zero                           ; if mod is zero, return
6419 hidnplayr 799
        sub     ecx, eax
9070 hidnplayr 800
        lea     ebx, [mpint_tmp]
6922 hidnplayr 801
        stdcall mpint_shlmov, ebx, [mod], ecx
6419 hidnplayr 802
        inc     ecx
803
 
804
        ; For every bit in dst (starting from the high order bit):
9070 hidnplayr 805
  .bitloop:
806
        stdcall mpint_cmp, [dst], ebx           ; If dst > mpint_tmp
807
        jb      @f                                                       ;;;;;;;;
808
        stdcall mpint_sub, [dst], ebx           ; dst = dst - mpint_tmp
6419 hidnplayr 809
  @@:
810
        dec     ecx
811
        jz      .done
812
 
9070 hidnplayr 813
        stdcall mpint_shr1, ebx                 ; mpint = mpint >> 1
814
        jmp     .bitloop
815
 
6419 hidnplayr 816
  .zero:
6922 hidnplayr 817
        mov     eax, [dst]
818
        mov     dword[eax], 0
6419 hidnplayr 819
  .done:
820
        ret
821
 
822
endp
823
 
6922 hidnplayr 824
;;===========================================================================;;
825
proc mpint_modexp uses edi eax ebx ecx edx, dst, base, exp, mod ;////////////;;
826
;;---------------------------------------------------------------------------;;
827
;? Find the modulo (remainder after division) of dst by mod.                 ;;
828
;;---------------------------------------------------------------------------;;
829
;> dst = pointer to buffer for little endian MPINT                           ;;
830
;> base = pointer to little endian MPINT                                     ;;
831
;> exp = pointer to little endian MPINT                                      ;;
832
;> mod = pointer to little endian MPINT                                      ;;
833
;;---------------------------------------------------------------------------;;
834
;< dst = base ** exp MOD mod                                                 ;;
835
;;===========================================================================;;
6419 hidnplayr 836
 
9070 hidnplayr 837
        ;DEBUGF  1, "mpint_modexp(0x%x, 0x%x, 0x%x, 0x%x)\n", [dst], [base], [exp], [mod]
838
 
6922 hidnplayr 839
locals
840
        mpint_tmp       rb MPINT_MAX_LEN+4
841
endl
842
 
6419 hidnplayr 843
        ; If mod is zero, return
9070 hidnplayr 844
        stdcall mpint_bits, [mod]
845
        test    eax, eax
846
        jz      .mod_zero
6419 hidnplayr 847
 
9070 hidnplayr 848
        ; Find highest order byte in exponent
849
        stdcall mpint_bytes, [exp]
850
        test    eax, eax
851
        jz      .exp_zero
852
        mov     ecx, eax
6419 hidnplayr 853
        mov     edi, [exp]
854
        lea     edi, [edi + 4 + ecx - 1]
9070 hidnplayr 855
 
6419 hidnplayr 856
        ; Find the highest order bit in this byte
857
        mov     al, [edi]
858
        test    al, al
859
        jz      .invalid
860
        mov     bl, 9
861
  @@:
862
        dec     bl
863
        shl     al, 1
864
        jnc     @r
865
 
9070 hidnplayr 866
        ; Make pointer to tmp mpint for convenient access
6922 hidnplayr 867
        lea     edx, [mpint_tmp]
9070 hidnplayr 868
 
6419 hidnplayr 869
        ; Initialise result to base, to take care of the highest order bit
6922 hidnplayr 870
        stdcall mpint_mov, [dst], [base]
6419 hidnplayr 871
        dec     bl
872
        jz      .next_byte
873
  .bit_loop:
874
        ; For each bit, square result
6922 hidnplayr 875
        stdcall mpint_mov, edx, [dst]
876
        stdcall mpint_mul, [dst], edx, edx
6419 hidnplayr 877
        stdcall mpint_mod, [dst], [mod]
878
 
879
        ; If the bit is set, multiply result by the base
880
        shl     al, 1
881
        jnc     .next_bit
6922 hidnplayr 882
        stdcall mpint_mov, edx, [dst]
883
        stdcall mpint_mul, [dst], [base], edx
6419 hidnplayr 884
        stdcall mpint_mod, [dst], [mod]
885
  .next_bit:
886
        dec     bl
887
        jnz     .bit_loop
888
  .next_byte:
889
        dec     ecx
890
        jz      .done
891
        dec     edi
892
        mov     al, [edi]
893
        mov     bl, 8
894
        jmp     .bit_loop
895
  .done:
9070 hidnplayr 896
        ;stdcall mpint_print, [dst]
6419 hidnplayr 897
        ret
898
 
899
  .mod_zero:
6469 hidnplayr 900
        DEBUGF  3, "modexp with modulo 0\n"
6419 hidnplayr 901
        ; if mod is zero, result = 0
6922 hidnplayr 902
        mov     eax, [dst]
903
        mov     dword[eax], 0
6419 hidnplayr 904
        ret
905
 
906
  .exp_zero:
6469 hidnplayr 907
        DEBUGF  3, "modexp with exponent 0\n"
6419 hidnplayr 908
        ; if exponent is zero, result = 1
909
        mov     eax, [dst]
6922 hidnplayr 910
        mov     dword[eax], 1
6419 hidnplayr 911
        mov     byte[eax+4], 1
912
        ret
913
 
914
  .invalid:
6469 hidnplayr 915
        DEBUGF  3, "modexp: Invalid input!\n"
6419 hidnplayr 916
        ret
917
 
918
endp