Subversion Repositories Kolibri OS

Rev

Rev 6469 | Rev 9070 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 6469 Rev 6922
Line 1... Line 1...
1
;    mpint.inc - Multi precision integer procedures
1
;    mpint.inc - Multi precision integer procedures
2
;
2
;
3
;    Copyright (C) 2015-2016 Jeffrey Amelynck
3
;    Copyright (C) 2015-2017 Jeffrey Amelynck
4
;
4
;
5
;    This program is free software: you can redistribute it and/or modify
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
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
7
;    the Free Software Foundation, either version 3 of the License, or
8
;    (at your option) any later version.
8
;    (at your option) any later version.
Line 13... Line 13...
13
;    GNU General Public License for more details.
13
;    GNU General Public License for more details.
14
;
14
;
15
;    You should have received a copy of the GNU General Public License
15
;    You should have received a copy of the GNU General Public License
16
;    along with this program.  If not, see .
16
;    along with this program.  If not, see .
Line -... Line 17...
-
 
17
 
-
 
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!
17
 
25
 
Line 18... Line -...
18
MPINT_MAX_LEN = MAX_BITS/8
-
 
Line -... Line 26...
-
 
26
MPINT_MAX_LEN = MAX_BITS/8
19
 
27
 
-
 
28
 
-
 
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                           ;;
Line 20... Line 36...
20
; TODO: make procedures use real number length instead of hardcoded maximum length (MPINT_MAX_LEN)
36
;;---------------------------------------------------------------------------;;
21
 
37
;< eax = MPINT number length                                                 ;;
22
mpint_to_little_endian:
38
;;===========================================================================;;
23
 
39
 
Line 41... Line 57...
41
        inc     edi
57
        inc     edi
42
        dec     ecx
58
        dec     ecx
43
        jnz     @r
59
        jnz     @r
44
        cld
60
        cld
45
        pop     esi eax
61
        pop     esi eax
46
; Fill the rest of the buffer with zeros.
-
 
47
  .zero:
62
  .zero:
48
        mov     ecx, MAX_BITS/8
-
 
49
        sub     ecx, eax
-
 
50
        xor     al, al
-
 
51
        rep stosb
-
 
52
 
-
 
53
        ret
63
        ret
Line -... Line 64...
-
 
64
 
-
 
65
endp
-
 
66
 
54
 
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                                                 ;;
Line 55... Line 76...
55
mpint_to_big_endian:
76
;;===========================================================================;;
56
 
77
 
57
; Load length dword
78
; Load length dword
58
        lodsd
79
        lodsd
59
        test    eax, eax
80
        test    eax, eax
60
        jz      .zero
81
        jz      .zero
61
        mov     ecx, eax
82
        mov     ecx, eax
62
        add     esi, ecx
83
        add     esi, eax
63
        dec     esi
-
 
64
        test    byte[esi], 0x80   ; Is the highest bit set?
-
 
65
        jz      @f
-
 
66
        inc     eax
-
 
67
  @@:
84
        dec     esi
68
        push    eax
85
        push    eax     ; we'll return length to the caller later
69
        bswap   eax
86
        bswap   eax
70
        stosd
87
        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
88
; Copy data, convert to big endian meanwhile
77
        inc     edi
89
        std
78
  @@:
90
  @@:
79
        lodsb
91
        lodsb
80
        mov     byte[edi], al
92
        mov     byte[edi], al
Line 84... Line 96...
84
        cld
96
        cld
85
        pop     eax
97
        pop     eax
86
        ret
98
        ret
Line 87... Line 99...
87
 
99
 
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
100
  .zero:
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
 
101
        stosd           ; Number 0 has 0 data bytes
Line 108... Line 102...
108
        ret
102
        ret
Line -... Line 103...
-
 
103
 
109
 
104
endp
-
 
105
 
-
 
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                                      ;;
Line 110... Line 112...
110
endp
112
;;---------------------------------------------------------------------------;;
111
 
113
;< -                                                                         ;;
112
proc mpint_print uses ecx esi eax, src
114
;;===========================================================================;;
113
 
115
 
Line 133... Line 135...
133
        DEBUGF  1, "00\n"
135
        DEBUGF  1, "00\n"
134
        ret
136
        ret
Line 135... Line 137...
135
 
137
 
Line -... Line 138...
-
 
138
endp
136
endp
139
 
137
 
-
 
138
proc mpint_zero uses edi ecx eax, dst
140
;;===========================================================================;;
139
 
141
proc mpint_hob uses edi ecx eax, dst ;///////////////////////////////////////;;
140
        mov     edi, [dst]
142
;;---------------------------------------------------------------------------;;
141
        xor     eax, eax
-
 
142
        mov     ecx, MPINT_MAX_LEN/4+1
-
 
143
        rep stosd
-
 
144
 
-
 
145
        ret
-
 
146
 
-
 
147
endp
143
;? Return an index number giving the position of the highest order bit.      ;;
148
 
-
 
149
proc mpint_zero? uses edi ecx eax, dst
-
 
150
 
-
 
151
        mov     edi, [dst]
144
;;---------------------------------------------------------------------------;;
152
        add     edi, 4
-
 
153
        mov     ecx, MPINT_MAX_LEN/4
-
 
154
        xor     eax, eax
-
 
155
        repe scasd
-
 
156
        ret
-
 
157
 
-
 
158
endp
145
;> src = pointer to little endian MPINT                                      ;;
159
 
146
;;---------------------------------------------------------------------------;;
Line 160... Line 147...
160
; return an index number giving the position of the highest order bit
147
;< eax = highest order bit number                                            ;;
161
proc mpint_hob uses edi ecx, dst
148
;;===========================================================================;;
162
 
149
 
163
        mov     edi, [dst]
150
        mov     edi, [dst]
164
        ; start from the high order byte
-
 
165
        add     edi, MPINT_MAX_LEN+4-1
151
        lodsd
166
        mov     ecx, MPINT_MAX_LEN
-
 
167
        xor     eax, eax
-
 
168
        ; scan byte by byte for the first non-zero byte
152
        dec     eax                     ; total length minus one
169
        std
-
 
170
        repe scasb
153
        mov     cl, [edi+eax]           ; load the highest order byte
171
        cld
154
        shl     eax, 3                  ; multiply eax by 8 to get nr of bits
172
        je      .zero
-
 
173
        ; calculate how many bits this is, plus 7
155
 
174
        lea     eax, [ecx*8-1]
-
 
175
        ; load this high order byte into cl
156
; Now shift bits of the highest order byte right, until the byte reaches zero, counting bits meanwhile
176
        mov     cl, [edi+1]
157
        test    cl, cl
177
        ; shift bits of this byte right, until the byte reaches zero, counting bits meanwhile
158
        jz      .end
178
  @@:
159
  @@:
179
        inc     eax
160
        inc     eax
180
        shr     cl, 1
161
        shr     cl, 1
Line 181... Line 162...
181
        jnz     @r
162
        jnz     @r
Line -... Line 163...
-
 
163
  .end:
182
  .zero:
164
        ret
-
 
165
 
-
 
166
endp
-
 
167
 
-
 
168
;;===========================================================================;;
-
 
169
proc mpint_cmp uses esi edi ecx eax, dst, src ;//////////////////////////////;;
-
 
170
;;---------------------------------------------------------------------------;;
-
 
171
;? Compare two mpints.                                                       ;;
-
 
172
;;---------------------------------------------------------------------------;;
Line -... Line 173...
-
 
173
;> dst = pointer to little endian MPINT                                      ;;
-
 
174
;> src = pointer to little endian MPINT                                      ;;
183
        ret
175
;;---------------------------------------------------------------------------;;
184
 
176
;< flags are set as for single precision CMP instruction                     ;;
185
endp
177
;;===========================================================================;;
186
 
178
 
-
 
179
; First, check if number of significant bytes is the same
-
 
180
; If not, number with more bytes is bigger
-
 
181
        mov     esi, [src]
187
proc mpint_cmp uses esi edi ecx, dst, src
182
        mov     edi, [dst]
188
 
183
        mov     ecx, [esi]
189
        mov     esi, [src]
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
-
 
190
        std
-
 
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
190
        mov     edi, [dst]
199
        jmp     .do_byte
-
 
200
  .do_dword:
191
        ; start from the high order byte
201
        shr     ecx, 2
192
        add     esi, MPINT_MAX_LEN+4-4
202
        jz      .got_answer
Line 193... Line 203...
193
        add     edi, MPINT_MAX_LEN+4-4
203
        sub     esi, 4
Line -... Line 204...
-
 
204
        sub     edi, 4
194
        mov     ecx, MPINT_MAX_LEN/4
205
        repe cmpsd
195
        std
-
 
-
 
206
  .got_answer:
196
        repe cmpsd
207
        cld
-
 
208
        ret
197
        cld
209
 
198
        ret
210
endp
-
 
211
 
199
 
212
;;===========================================================================;;
200
endp
-
 
201
 
-
 
202
proc mpint_mov uses esi edi ecx, dst, src
-
 
203
 
-
 
204
        mov     esi, [src]
-
 
205
        mov     edi, [dst]
213
proc mpint_mov uses esi edi ecx, dst, src ;//////////////////////////////////;;
Line 206... Line 214...
206
        mov     ecx, MPINT_MAX_LEN/4+1
214
;;---------------------------------------------------------------------------;;
207
        rep movsd
215
;? Copy mpint.                                                               ;;
208
 
216
;;---------------------------------------------------------------------------;;
209
        ret
217
;> dst = pointer to buffer for little endian MPINT                           ;;
210
 
218
;> src = pointer to little endian MPINT                                      ;;
211
endp
219
;;---------------------------------------------------------------------------;;
212
 
220
;< dst = src                                                                 ;;
213
proc mpint_mov0 uses esi edi ecx eax, dst, src
221
;;===========================================================================;;
214
 
222
 
215
        mov     esi, [src]
223
        mov     esi, [src]
216
        mov     edi, [dst]
-
 
217
        mov     ecx, [esi]
-
 
218
        mov     eax, ecx
224
        mov     edi, [dst]
219
        neg     eax
225
        mov     ecx, [esi]
Line 220... Line 226...
220
        add     esi, 4
226
        push    ecx
Line 221... Line 227...
221
        add     edi, 4
227
        shr     ecx, 2
Line -... Line 228...
-
 
228
        inc     ecx             ; for length dword
222
        rep movsb
229
        rep movsd
-
 
230
        pop     ecx
-
 
231
        and     ecx, 11b
-
 
232
        jz      @f
-
 
233
        rep movsb
-
 
234
  @@:
-
 
235
 
-
 
236
        ret
Line 223... Line 237...
223
        add     eax, MPINT_MAX_LEN
237
 
224
        jz      @f
238
endp
225
        mov     ecx, eax
239
 
-
 
240
;;===========================================================================;;
Line -... Line 241...
-
 
241
proc mpint_shl1 uses esi ecx, dst ;//////////////////////////////////////////;;
-
 
242
;;---------------------------------------------------------------------------;;
226
        xor     eax, eax
243
;? Shift little endian MPINT one bit to the left.                            ;;
227
        rep stosb
244
;;---------------------------------------------------------------------------;;
-
 
245
;> dst = pointer to little endian MPINT                                      ;;
-
 
246
;;---------------------------------------------------------------------------;;
-
 
247
;< dst = dst SHL 1                                                           ;;
-
 
248
;;===========================================================================;;
-
 
249
 
228
  @@:
250
        mov     esi, [dst]
229
 
251
        mov     ecx, [esi]
-
 
252
        test    ecx, ecx
-
 
253
        jz      .done
230
        ret
254
 
231
 
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
232
endp
258
        jz      @f
-
 
259
; We must grow a byte in size!
233
 
260
; TODO: check for overflow
234
proc mpint_shl1 uses edi ecx eax, dst
261
        inc     ecx
235
 
262
        mov     [esi], ecx
236
        mov     edi, [dst]
-
 
237
        add     edi, 4
263
        mov     byte[esi+ecx+3], 0        ; Add the new MSB
Line 238... Line 264...
238
        mov     ecx, MPINT_MAX_LEN/4-1
264
  @@:
Line -... Line 265...
-
 
265
        add     esi, 4
239
 
266
; Do the lowest order byte first
-
 
267
        shl     byte[esi], 1
-
 
268
        dec     ecx
-
 
269
        jz      .done
-
 
270
; And the remaining bytes
-
 
271
  @@:
-
 
272
        inc     esi
-
 
273
        rcl     byte[esi], 1
Line 240... Line 274...
240
        shl     dword[edi], 1
274
        dec     ecx
241
        lahf
275
        jnz     @r
242
  @@:
276
  .done:
-
 
277
        ret
Line 243... Line 278...
243
        add     edi, 4
278
 
244
        sahf
-
 
245
        rcl     dword[edi], 1
-
 
246
        lahf
-
 
247
        dec     ecx
-
 
248
        jnz     @r
-
 
249
        sahf
-
 
250
 
279
endp
-
 
280
 
-
 
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
;;===========================================================================;;
-
 
290
 
-
 
291
        mov     edi, [dst]
-
 
292
        mov     ecx, [edi]
-
 
293
        test    ecx, ecx
-
 
294
        jz      .done
251
        ret
295
 
252
 
296
; Do the highest order byte first
253
endp
-
 
254
 
297
        dec     ecx
Line 255... Line 298...
255
proc mpint_shr1 uses edi ecx eax, dst
298
        shr     byte[edi+ecx+3], 1
Line -... Line 299...
-
 
299
; Was it 0? If so, we must decrement total length
256
 
300
        jnz     @f
-
 
301
        jc      @f
-
 
302
        mov     [edi], ecx
-
 
303
  @@:
-
 
304
        test    ecx, ecx
-
 
305
        jz      .done
-
 
306
; Now do the trailing bytes
-
 
307
        add     edi, 4
-
 
308
        add     edi, ecx
Line 257... Line 309...
257
        mov     edi, [dst]
309
  @@:
258
        add     edi, MPINT_MAX_LEN+4-4
310
        dec     edi
259
        mov     ecx, MPINT_MAX_LEN/4-1
311
        rcr     byte[edi], 1
260
 
312
        dec     ecx             ; does not affect carry flag, hooray!
Line 311... Line 363...
311
  @@:
363
  @@:
312
        cld
364
        cld
313
        ret
365
        ret
Line 314... Line 366...
314
 
366
 
315
  .zero:
367
  .zero:
-
 
368
        mov     eax, [dst]
316
        stdcall mpint_zero, [dst]
369
        mov     dword[eax], 0
Line 317... Line 370...
317
        ret
370
        ret
Line 318... Line 371...
318
 
371
 
319
endp
372
endp
-
 
373
 
-
 
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                     ;;
Line 320... Line 382...
320
 
382
;;---------------------------------------------------------------------------;;
321
; Left shift and copy
383
;< dst = src SHL shift                                                       ;;
322
proc mpint_shlmov uses eax ebx ecx edx esi edi, dst, src, shift
384
;;===========================================================================;;
323
 
385
 
Line 358... Line 420...
358
  @@:
420
  @@:
359
        cld
421
        cld
360
        ret
422
        ret
Line 361... Line 423...
361
 
423
 
362
  .zero:
424
  .zero:
-
 
425
        mov     eax, [dst]
363
        stdcall mpint_zero, [dst]
426
        mov     dword[eax], 0
Line 364... Line 427...
364
        ret
427
        ret
Line -... Line 428...
-
 
428
 
365
 
429
endp
-
 
430
 
-
 
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                                      ;;
Line 366... Line 438...
366
endp
438
;;---------------------------------------------------------------------------;;
367
 
-
 
368
proc mpint_add uses esi edi ecx eax, dst, src
439
;< dst = dst + src                                                           ;;
-
 
440
;;===========================================================================;;
-
 
441
 
-
 
442
        mov     esi, [src]
-
 
443
        mov     edi, [dst]
-
 
444
        mov     ecx, [esi]      ; source number length
369
 
445
        sub     ecx, [dst]
370
        mov     esi, [src]
446
        jbe     .length_ok
371
        add     esi, 4
-
 
372
        mov     edi, [dst]
447
; Length of the destination is currently smaller then the source, pad with 0 bytes
373
        add     edi, 4
448
        add     edi, [edi]
374
        mov     ecx, MPINT_MAX_LEN/4
449
        add     edi, 4
375
        xor     ah, ah          ; clear flags (Carry flag most importantly)
450
        mov     al, 0
376
  @@:
451
        rep stosb
377
        sahf
452
  .length_ok:
-
 
453
        mov     ecx, [esi]
-
 
454
        mov     edi, [dst]
-
 
455
        add     esi, 4
-
 
456
        add     edi, 4
-
 
457
; Add the first byte
-
 
458
        lodsb
-
 
459
        add     byte[edi], al
-
 
460
        dec     ecx
-
 
461
        jz      .done
-
 
462
; Add the other bytes
378
        lodsd
463
  @@:
379
        adc     [edi], eax
464
        inc     edi
-
 
465
        lodsb
-
 
466
        adc     byte[edi], al
-
 
467
        dec     ecx
-
 
468
        jnz     @r
-
 
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
380
        lahf
473
        jc      .carry
-
 
474
        cmp     byte[edi], 0x80
-
 
475
        jnz     .high_bit_set
-
 
476
 
-
 
477
        ret
-
 
478
 
-
 
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:
Line 381... Line 488...
381
        add     edi, 4
488
        inc     edi
Line 382... Line 489...
382
        dec     ecx
489
        mov     byte[edi], 0
Line -... Line 490...
-
 
490
        mov     eax, [dst]
383
        jnz     @r
491
        inc     dword[eax]
-
 
492
 
-
 
493
        ret
-
 
494
 
-
 
495
endp
-
 
496
 
-
 
497
;;===========================================================================;;
-
 
498
proc mpint_sub uses eax esi edi ecx, dst, src ;//////////////////////////////;;
-
 
499
;;---------------------------------------------------------------------------;;
Line 384... Line 500...
384
        sahf
500
;? Subtract a little endian MPINT to another little endian MPINT.            ;;
385
 
-
 
386
        ret
501
;;---------------------------------------------------------------------------;;
-
 
502
;> src = pointer to little endian MPINT                                      ;;
-
 
503
;> dst = pointer to little endian MPINT                                      ;;
-
 
504
;;---------------------------------------------------------------------------;;
-
 
505
;< dst = dst - src                                                           ;;
-
 
506
;;===========================================================================;;
387
 
507
 
388
endp
508
        mov     esi, [src]
389
 
-
 
390
proc mpint_sub uses eax esi edi ecx, dst, src
509
        mov     edi, [dst]
391
 
510
        mov     ecx, [esi]      ; destination number length
392
        mov     esi, [src]
511
        cmp     ecx, [edi]
393
        add     esi, 4
512
        ja      .overflow
-
 
513
 
394
        mov     edi, [dst]
514
        add     esi, 4
395
        add     edi, 4
515
        add     edi, 4
-
 
516
; Subtract the first byte
-
 
517
        lodsb
396
        mov     ecx, MPINT_MAX_LEN/4
518
        sub     byte[edi], al
397
  .loop:
519
        dec     ecx
-
 
520
        jz      .done
-
 
521
; Subtract the other bytes
-
 
522
  @@:
-
 
523
        inc     edi
-
 
524
        lodsb
-
 
525
        sbb     byte[edi], al
-
 
526
        dec     ecx
398
        lodsd
527
        jnz     @r
Line 399... Line 528...
399
        sub     [edi], eax
528
  .done:
Line 400... Line -...
400
        jnc     @f
-
 
Line -... Line 529...
-
 
529
        stdcall mpint_shrink, [dst]
-
 
530
        ret
-
 
531
 
401
        dec     dword [edi+4]
532
  .overflow:
-
 
533
        mov     dword[edi], 0
-
 
534
        stc
-
 
535
        ret
-
 
536
 
-
 
537
endp
Line 402... Line -...
402
  @@:
-
 
403
        add     edi, 4
-
 
404
        dec     ecx
538
 
405
        jnz     .loop
539
 
406
        ret
540
;;===========================================================================;;
-
 
541
proc mpint_shrink uses eax edi ecx, dst ;////////////////////////////////////;;
-
 
542
;;---------------------------------------------------------------------------;;
-
 
543
;? Get rid of leading zeroes on a little endian MPINT.                       ;;
407
 
544
;;---------------------------------------------------------------------------;;
408
endp
545
;> src = pointer to little endian MPINT                                      ;;
409
 
-
 
410
proc mpint_mul uses esi edi ecx ebx eax, dst, A, B
-
 
411
 
546
;;---------------------------------------------------------------------------;;
-
 
547
;<                                                                           ;;
-
 
548
;;===========================================================================;;
-
 
549
 
-
 
550
        mov     edi, [dst]
-
 
551
        lodsd
-
 
552
        std
-
 
553
        mov     ecx, eax
-
 
554
        dec     eax             ; total length minus one
-
 
555
        add     edi, eax
-
 
556
        xor     al, al
-
 
557
        repe cmpsb
-
 
558
        inc     ecx
-
 
559
        mov     edi, [dst]
-
 
560
        mov     [edi], ecx
-
 
561
        cld
-
 
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                                                               ;;
412
        stdcall mpint_zero, [dst]
577
;;===========================================================================;;
413
 
578
 
414
        ; first, find the byte in A containing the highest order bit
579
        ; Set result to zero
415
        mov     ecx, MPINT_MAX_LEN
580
        mov     eax, [dst]
416
        mov     edi, [A]
581
        mov     dword[eax], 0
Line 450... Line 615...
450
  .zero:
615
  .zero:
451
        ret
616
        ret
Line 452... Line 617...
452
 
617
 
Line -... Line 618...
-
 
618
endp
453
endp
619
 
-
 
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
;;===========================================================================;;
-
 
630
 
-
 
631
locals
Line 454... Line 632...
454
 
632
        mpint_tmp       rb MPINT_MAX_LEN+4
455
proc mpint_mod uses eax ecx, dst, mod
633
endl
-
 
634
 
456
 
635
        ; if mod is zero, return
Line 457... Line 636...
457
        ; if mod is zero, return
636
        mov     eax, [mod]
458
        stdcall mpint_zero?, [mod]
637
        cmp     dword[eax], 0
459
        jz      .zero
638
        je      .zero
Line -... Line 639...
-
 
639
 
-
 
640
        stdcall mpint_cmp, eax, [dst]
460
 
641
        jb      .done                           ; if dst < mod, dst = dst
461
        stdcall mpint_cmp, [mod], [dst]
642
        je      .zero                           ; if dst == mod, dst = 0
462
        jb      .done                           ; if dst < mod, dst = dst
643
 
463
        je      .zero                           ; if dst == mod, dst = 0
644
        lea     ebx, [mpint_tmp]
464
 
645
 
465
        ; left shift mod until the high order bits of mod and dst are aligned
646
        ; left shift mod until the high order bits of mod and dst are aligned
466
        stdcall mpint_hob, [dst]
647
        stdcall mpint_hob, [dst]
Line 467... Line 648...
467
        mov     ecx, eax
648
        mov     ecx, eax
468
        stdcall mpint_hob, [mod]
649
        stdcall mpint_hob, [mod]
469
        sub     ecx, eax
650
        sub     ecx, eax
470
        stdcall mpint_shlmov, mpint_tmp, [mod], ecx
651
        stdcall mpint_shlmov, ebx, [mod], ecx
471
        inc     ecx
652
        inc     ecx
472
 
653
 
473
        ; For every bit in dst (starting from the high order bit):
654
        ; For every bit in dst (starting from the high order bit):
474
  .loop:
655
  .loop:
475
        ;   determine if dst is bigger than mpint_tmp
656
        ;   determine if dst is bigger than mpint_tmp
476
        stdcall mpint_cmp, [dst], mpint_tmp
657
        stdcall mpint_cmp, [dst], ebx
477
        ja      @f
658
        ja      @f
478
        ;   if so, subtract mpint_tmp from dst
659
        ;   if so, subtract mpint_tmp from dst
479
        stdcall mpint_sub, [dst], mpint_tmp
660
        stdcall mpint_sub, [dst], ebx
Line 480... Line 661...
480
  @@:
661
  @@:
481
        dec     ecx
662
        dec     ecx
-
 
663
        jz      .done
482
        jz      .done
664
        ;   shift mpint_tmp right by 1
483
        ;   shift mpint_tmp right by 1
665
        stdcall mpint_shr1, ebx
Line 484... Line 666...
484
        stdcall mpint_shr1, mpint_tmp
666
        jmp     .loop
Line -... Line 667...
-
 
667
 
485
        jmp     .loop
668
  .zero:
-
 
669
        mov     eax, [dst]
-
 
670
        mov     dword[eax], 0
-
 
671
  .done:
-
 
672
        ret
-
 
673
 
-
 
674
endp
-
 
675
 
-
 
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                                     ;;
Line 486... Line 683...
486
 
683
;> exp = pointer to little endian MPINT                                      ;;
487
  .zero:
684
;> mod = pointer to little endian MPINT                                      ;;
-
 
685
;;---------------------------------------------------------------------------;;
488
        stdcall mpint_zero, [dst]
686
;< dst = base ** exp MOD mod                                                 ;;
Line 489... Line 687...
489
  .done:
687
;;===========================================================================;;
490
        ret
688
 
491
 
689
locals
492
endp
690
        mpint_tmp       rb MPINT_MAX_LEN+4
Line 509... Line 707...
509
  @@:
707
  @@:
510
        dec     bl
708
        dec     bl
511
        shl     al, 1
709
        shl     al, 1
512
        jnc     @r
710
        jnc     @r
Line -... Line 711...
-
 
711
 
513
 
712
        lea     edx, [mpint_tmp]
514
        ; Initialise result to base, to take care of the highest order bit
713
        ; Initialise result to base, to take care of the highest order bit
515
        stdcall mpint_mov0, [dst], [base]
714
        stdcall mpint_mov, [dst], [base]
516
        dec     bl
715
        dec     bl
517
        jz      .next_byte
716
        jz      .next_byte
518
  .bit_loop:
717
  .bit_loop:
519
        ; For each bit, square result
718
        ; For each bit, square result
520
        stdcall mpint_mov, mpint_tmp, [dst]
719
        stdcall mpint_mov, edx, [dst]
521
        stdcall mpint_mul, [dst], mpint_tmp, mpint_tmp
720
        stdcall mpint_mul, [dst], edx, edx
Line 522... Line 721...
522
        stdcall mpint_mod, [dst], [mod]
721
        stdcall mpint_mod, [dst], [mod]
523
 
722
 
524
        ; If the bit is set, multiply result by the base
723
        ; If the bit is set, multiply result by the base
525
        shl     al, 1
724
        shl     al, 1
526
        jnc     .next_bit
725
        jnc     .next_bit
527
        stdcall mpint_mov, mpint_tmp, [dst]
726
        stdcall mpint_mov, edx, [dst]
528
        stdcall mpint_mul, [dst], [base], mpint_tmp
727
        stdcall mpint_mul, [dst], [base], edx
529
        stdcall mpint_mod, [dst], [mod]
728
        stdcall mpint_mod, [dst], [mod]
530
  .next_bit:
729
  .next_bit:
531
        dec     bl
730
        dec     bl
Line 541... Line 740...
541
        ret
740
        ret
Line 542... Line 741...
542
 
741
 
543
  .mod_zero:
742
  .mod_zero:
544
        DEBUGF  3, "modexp with modulo 0\n"
743
        DEBUGF  3, "modexp with modulo 0\n"
545
        ; if mod is zero, result = 0
744
        ; if mod is zero, result = 0
-
 
745
        mov     eax, [dst]
546
        stdcall mpint_zero, [dst]
746
        mov     dword[eax], 0
Line 547... Line 747...
547
        ret
747
        ret
548
 
748
 
549
  .exp_zero:
749
  .exp_zero:
550
        DEBUGF  3, "modexp with exponent 0\n"
-
 
551
        ; if exponent is zero, result = 1
750
        DEBUGF  3, "modexp with exponent 0\n"
552
        stdcall mpint_zero, [dst]
751
        ; if exponent is zero, result = 1
553
        mov     eax, [dst]
752
        mov     eax, [dst]
554
        mov     byte[eax], 1
753
        mov     dword[eax], 1
Line 555... Line 754...
555
        mov     byte[eax+4], 1
754
        mov     byte[eax+4], 1
556
        ret
755
        ret