Subversion Repositories Kolibri OS

Rev

Rev 6423 | Rev 6922 | 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
;
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
6423 pathoswith 397
  .loop:
398
        lodsd
399
        sub     [edi], eax
400
        jnc     @f
401
        dec     dword [edi+4]
6419 hidnplayr 402
  @@:
403
        add     edi, 4
404
        dec     ecx
6423 pathoswith 405
        jnz     .loop
6419 hidnplayr 406
        ret
407
 
408
endp
409
 
410
proc mpint_mul uses esi edi ecx ebx eax, dst, A, B
411
 
412
        stdcall mpint_zero, [dst]
413
 
414
        ; first, find the byte in A containing the highest order bit
415
        mov     ecx, MPINT_MAX_LEN
416
        mov     edi, [A]
417
        add     edi, MPINT_MAX_LEN+4-1
418
        std
419
        xor     al, al
420
        repe scasb
421
        cld
422
        je      .zero
423
        inc     ecx
424
        mov     al, [edi+1]
425
        mov     esi, edi
426
        mov     bl, 8
427
  @@:
428
        shl     al, 1
429
        jc      .first_hit
430
        dec     bl
431
        jnz     @r
432
 
433
        ; Then, starting from this byte, iterate through the bits in A,
434
        ; starting from the highest order bit down to the lowest order bit.
435
  .next_byte:
436
        mov     al, [edi]
437
        dec     edi
438
        mov     bl, 8
439
  .next_bit:
440
        stdcall mpint_shl1, [dst]
441
        shl     al, 1
442
        jnc     .zero_bit
443
  .first_hit:
444
        stdcall mpint_add, [dst], [B]
445
  .zero_bit:
446
        dec     bl
447
        jnz     .next_bit
448
        dec     ecx
449
        jnz     .next_byte
450
  .zero:
451
        ret
452
 
453
endp
454
 
455
proc mpint_mod uses eax ecx, dst, mod
456
 
457
        ; if mod is zero, return
458
        stdcall mpint_zero?, [mod]
459
        jz      .zero
460
 
461
        stdcall mpint_cmp, [mod], [dst]
462
        jb      .done                           ; if dst < mod, dst = dst
463
        je      .zero                           ; if dst == mod, dst = 0
464
 
465
        ; left shift mod until the high order bits of mod and dst are aligned
466
        stdcall mpint_hob, [dst]
467
        mov     ecx, eax
468
        stdcall mpint_hob, [mod]
469
        sub     ecx, eax
470
        stdcall mpint_shlmov, mpint_tmp, [mod], ecx
471
        inc     ecx
472
 
473
        ; For every bit in dst (starting from the high order bit):
474
  .loop:
475
        ;   determine if dst is bigger than mpint_tmp
476
        stdcall mpint_cmp, [dst], mpint_tmp
477
        ja      @f
478
        ;   if so, subtract mpint_tmp from dst
479
        stdcall mpint_sub, [dst], mpint_tmp
480
  @@:
481
        dec     ecx
482
        jz      .done
483
        ;   shift mpint_tmp right by 1
484
        stdcall mpint_shr1, mpint_tmp
485
        jmp     .loop
486
 
487
  .zero:
488
        stdcall mpint_zero, [dst]
489
  .done:
490
        ret
491
 
492
endp
493
 
494
proc mpint_modexp uses edi eax ebx ecx, dst, base, exp, mod
495
 
496
        ; If mod is zero, return
497
        stdcall mpint_zero?, [mod]
498
        jz      .mod_zero
499
 
500
        ; Find the highest order byte in exponent
501
        mov     edi, [exp]
502
        mov     ecx, [edi]
503
        lea     edi, [edi + 4 + ecx - 1]
504
        ; Find the highest order bit in this byte
505
        mov     al, [edi]
506
        test    al, al
507
        jz      .invalid
508
        mov     bl, 9
509
  @@:
510
        dec     bl
511
        shl     al, 1
512
        jnc     @r
513
 
514
        ; Initialise result to base, to take care of the highest order bit
515
        stdcall mpint_mov0, [dst], [base]
516
        dec     bl
517
        jz      .next_byte
518
  .bit_loop:
519
        ; For each bit, square result
520
        stdcall mpint_mov, mpint_tmp, [dst]
521
        stdcall mpint_mul, [dst], mpint_tmp, mpint_tmp
522
        stdcall mpint_mod, [dst], [mod]
523
 
524
        ; If the bit is set, multiply result by the base
525
        shl     al, 1
526
        jnc     .next_bit
527
        stdcall mpint_mov, mpint_tmp, [dst]
528
        stdcall mpint_mul, [dst], [base], mpint_tmp
529
        stdcall mpint_mod, [dst], [mod]
530
  .next_bit:
531
        dec     bl
532
        jnz     .bit_loop
533
  .next_byte:
534
        dec     ecx
535
        jz      .done
536
        dec     edi
537
        mov     al, [edi]
538
        mov     bl, 8
539
        jmp     .bit_loop
540
  .done:
541
        ret
542
 
543
  .mod_zero:
6469 hidnplayr 544
        DEBUGF  3, "modexp with modulo 0\n"
6419 hidnplayr 545
        ; if mod is zero, result = 0
546
        stdcall mpint_zero, [dst]
547
        ret
548
 
549
  .exp_zero:
6469 hidnplayr 550
        DEBUGF  3, "modexp with exponent 0\n"
6419 hidnplayr 551
        ; if exponent is zero, result = 1
552
        stdcall mpint_zero, [dst]
553
        mov     eax, [dst]
554
        mov     byte[eax], 1
555
        mov     byte[eax+4], 1
556
        ret
557
 
558
  .invalid:
6469 hidnplayr 559
        DEBUGF  3, "modexp: Invalid input!\n"
6419 hidnplayr 560
        ret
561
 
562
endp