Subversion Repositories Kolibri OS

Rev

Rev 6469 | Rev 9090 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 6469 Rev 6922
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.
9
;
9
;
10
;    This program is distributed in the hope that it will be useful,
10
;    This program is distributed in the hope that it will be useful,
11
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
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 .
-
 
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
 
18
MPINT_MAX_LEN = MAX_BITS/8
-
 
-
 
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                           ;;
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
 
24
; Load length dword
40
; Load length dword
25
        lodsd
41
        lodsd
26
; Convert to little endian
42
; Convert to little endian
27
        bswap   eax
43
        bswap   eax
28
        stosd
44
        stosd
29
        test    eax, eax
45
        test    eax, eax
30
        jz      .zero
46
        jz      .zero
31
; Copy data, convert to little endian meanwhile
47
; Copy data, convert to little endian meanwhile
32
        push    eax
48
        push    eax
33
        add     esi, eax
49
        add     esi, eax
34
        push    esi
50
        push    esi
35
        dec     esi
51
        dec     esi
36
        mov     ecx, eax
52
        mov     ecx, eax
37
        std
53
        std
38
  @@:
54
  @@:
39
        lodsb
55
        lodsb
40
        mov     byte[edi], al
56
        mov     byte[edi], al
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
-
 
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                                                 ;;
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
84
        dec     esi
64
        test    byte[esi], 0x80   ; Is the highest bit set?
85
        push    eax     ; we'll return length to the caller later
65
        jz      @f
-
 
66
        inc     eax
-
 
67
  @@:
-
 
68
        push    eax
-
 
69
        bswap   eax
86
        bswap   eax
70
        stosd
87
        stosd
71
; Copy data, convert to big endian meanwhile
88
; Copy data, convert to big endian meanwhile
72
        std
89
        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
  @@:
90
  @@:
79
        lodsb
91
        lodsb
80
        mov     byte[edi], al
92
        mov     byte[edi], al
81
        inc     edi
93
        inc     edi
82
        dec     ecx
94
        dec     ecx
83
        jnz     @r
95
        jnz     @r
84
        cld
96
        cld
85
        pop     eax
97
        pop     eax
86
        ret
98
        ret
87
 
99
 
88
  .zero:
100
  .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]
101
        stosd           ; Number 0 has 0 data bytes
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
102
        ret
109
 
103
 
110
endp
104
endp
-
 
105
 
111
 
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
;< -                                                                         ;;
112
proc mpint_print uses ecx esi eax, src
114
;;===========================================================================;;
113
 
115
 
114
        DEBUGF  1, "0x"
116
        DEBUGF  1, "0x"
115
        mov     esi, [src]
117
        mov     esi, [src]
116
        mov     ecx, [esi]
118
        mov     ecx, [esi]
117
        test    ecx, ecx
119
        test    ecx, ecx
118
        jz      .zero
120
        jz      .zero
119
        lea     esi, [esi + ecx + 4 - 1]
121
        lea     esi, [esi + ecx + 4 - 1]
120
        pushf
122
        pushf
121
        std
123
        std
122
  .loop:
124
  .loop:
123
        lodsb
125
        lodsb
124
        DEBUGF  1, "%x", eax:2
126
        DEBUGF  1, "%x", eax:2
125
        dec     ecx
127
        dec     ecx
126
        jnz     .loop
128
        jnz     .loop
127
        DEBUGF  1, "\n"
129
        DEBUGF  1, "\n"
128
        popf
130
        popf
129
 
131
 
130
        ret
132
        ret
131
 
133
 
132
  .zero:
134
  .zero:
133
        DEBUGF  1, "00\n"
135
        DEBUGF  1, "00\n"
134
        ret
136
        ret
135
 
137
 
136
endp
138
endp
-
 
139
 
137
 
140
;;===========================================================================;;
138
proc mpint_zero uses edi ecx eax, dst
-
 
139
 
141
proc mpint_hob uses edi ecx eax, dst ;///////////////////////////////////////;;
140
        mov     edi, [dst]
142
;;---------------------------------------------------------------------------;;
141
        xor     eax, eax
143
;? Return an index number giving the position of the highest order bit.      ;;
142
        mov     ecx, MPINT_MAX_LEN/4+1
-
 
143
        rep stosd
-
 
144
 
-
 
145
        ret
-
 
146
 
-
 
147
endp
-
 
148
 
144
;;---------------------------------------------------------------------------;;
149
proc mpint_zero? uses edi ecx eax, dst
-
 
150
 
-
 
151
        mov     edi, [dst]
-
 
152
        add     edi, 4
145
;> src = pointer to little endian MPINT                                      ;;
153
        mov     ecx, MPINT_MAX_LEN/4
-
 
154
        xor     eax, eax
-
 
155
        repe scasd
-
 
156
        ret
-
 
157
 
-
 
158
endp
-
 
159
 
146
;;---------------------------------------------------------------------------;;
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
151
        lodsd
165
        add     edi, MPINT_MAX_LEN+4-1
-
 
166
        mov     ecx, MPINT_MAX_LEN
152
        dec     eax                     ; total length minus one
167
        xor     eax, eax
-
 
168
        ; scan byte by byte for the first non-zero byte
-
 
169
        std
153
        mov     cl, [edi+eax]           ; load the highest order byte
170
        repe scasb
-
 
171
        cld
154
        shl     eax, 3                  ; multiply eax by 8 to get nr of bits
172
        je      .zero
155
 
173
        ; calculate how many bits this is, plus 7
-
 
174
        lea     eax, [ecx*8-1]
156
; Now shift bits of the highest order byte right, until the byte reaches zero, counting bits meanwhile
175
        ; load this high order byte into cl
-
 
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
181
        jnz     @r
162
        jnz     @r
182
  .zero:
163
  .end:
183
        ret
164
        ret
184
 
165
 
185
endp
166
endp
-
 
167
 
186
 
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
;;===========================================================================;;
-
 
178
 
187
proc mpint_cmp uses esi edi ecx, dst, src
179
; First, check if number of significant bytes is the same
188
 
180
; If not, number with more bytes is bigger
189
        mov     esi, [src]
181
        mov     esi, [src]
190
        mov     edi, [dst]
182
        mov     edi, [dst]
-
 
183
        mov     ecx, [esi]
-
 
184
        cmp     ecx, [edi]
-
 
185
        jne     .got_answer
191
        ; start from the high order byte
186
 
192
        add     esi, MPINT_MAX_LEN+4-4
187
; Numbers have equal amount of bytes, compare starting from the high order byte
193
        add     edi, MPINT_MAX_LEN+4-4
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
-
 
199
        jmp     .do_byte
-
 
200
  .do_dword:
-
 
201
        shr     ecx, 2
-
 
202
        jz      .got_answer
194
        mov     ecx, MPINT_MAX_LEN/4
203
        sub     esi, 4
-
 
204
        sub     edi, 4
195
        std
205
        repe cmpsd
196
        repe cmpsd
206
  .got_answer:
197
        cld
207
        cld
198
        ret
208
        ret
199
 
209
 
200
endp
210
endp
-
 
211
 
201
 
212
;;===========================================================================;;
202
proc mpint_mov uses esi edi ecx, dst, src
-
 
-
 
213
proc mpint_mov uses esi edi ecx, dst, src ;//////////////////////////////////;;
203
 
214
;;---------------------------------------------------------------------------;;
-
 
215
;? Copy mpint.                                                               ;;
204
        mov     esi, [src]
216
;;---------------------------------------------------------------------------;;
205
        mov     edi, [dst]
217
;> dst = pointer to buffer for little endian MPINT                           ;;
-
 
218
;> src = pointer to little endian MPINT                                      ;;
206
        mov     ecx, MPINT_MAX_LEN/4+1
219
;;---------------------------------------------------------------------------;;
207
        rep movsd
-
 
208
 
-
 
209
        ret
-
 
210
 
-
 
211
endp
-
 
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]
224
        mov     edi, [dst]
217
        mov     ecx, [esi]
225
        mov     ecx, [esi]
218
        mov     eax, ecx
226
        push    ecx
219
        neg     eax
227
        shr     ecx, 2
220
        add     esi, 4
228
        inc     ecx             ; for length dword
221
        add     edi, 4
229
        rep movsd
222
        rep movsb
230
        pop     ecx
223
        add     eax, MPINT_MAX_LEN
231
        and     ecx, 11b
224
        jz      @f
232
        jz      @f
225
        mov     ecx, eax
-
 
226
        xor     eax, eax
-
 
227
        rep stosb
233
        rep movsb
228
  @@:
234
  @@:
229
 
235
 
230
        ret
236
        ret
231
 
237
 
232
endp
238
endp
-
 
239
 
233
 
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                                                           ;;
234
proc mpint_shl1 uses edi ecx eax, dst
248
;;===========================================================================;;
235
 
249
 
236
        mov     edi, [dst]
250
        mov     esi, [dst]
-
 
251
        mov     ecx, [esi]
-
 
252
        test    ecx, ecx
-
 
253
        jz      .done
237
        add     edi, 4
254
 
238
        mov     ecx, MPINT_MAX_LEN/4-1
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
239
 
261
        inc     ecx
240
        shl     dword[edi], 1
262
        mov     [esi], ecx
-
 
263
        mov     byte[esi+ecx+3], 0        ; Add the new MSB
-
 
264
  @@:
241
        lahf
265
        add     esi, 4
242
  @@:
266
; Do the lowest order byte first
-
 
267
        shl     byte[esi], 1
-
 
268
        dec     ecx
243
        add     edi, 4
269
        jz      .done
-
 
270
; And the remaining bytes
244
        sahf
271
  @@:
245
        rcl     dword[edi], 1
272
        inc     esi
246
        lahf
273
        rcl     byte[esi], 1
247
        dec     ecx
-
 
248
        jnz     @r
274
        dec     ecx
249
        sahf
275
        jnz     @r
250
 
276
  .done:
251
        ret
277
        ret
252
 
278
 
253
endp
279
endp
-
 
280
 
254
 
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                                                           ;;
255
proc mpint_shr1 uses edi ecx eax, dst
289
;;===========================================================================;;
256
 
290
 
257
        mov     edi, [dst]
291
        mov     edi, [dst]
-
 
292
        mov     ecx, [edi]
258
        add     edi, MPINT_MAX_LEN+4-4
293
        test    ecx, ecx
259
        mov     ecx, MPINT_MAX_LEN/4-1
-
 
260
 
-
 
261
        shr     dword[edi], 1
-
 
262
        lahf
-
 
263
  @@:
-
 
264
        sub     edi, 4
-
 
265
        sahf
294
        jz      .done
-
 
295
 
-
 
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
-
 
303
  @@:
-
 
304
        test    ecx, ecx
-
 
305
        jz      .done
-
 
306
; Now do the trailing bytes
-
 
307
        add     edi, 4
-
 
308
        add     edi, ecx
-
 
309
  @@:
266
        rcr     dword[edi], 1
310
        dec     edi
267
        lahf
311
        rcr     byte[edi], 1
268
        dec     ecx
-
 
269
        jnz     @r
312
        dec     ecx             ; does not affect carry flag, hooray!
270
        sahf
313
        jnz     @r
271
 
314
  .done:
272
        ret
315
        ret
273
 
316
 
274
endp
317
endp
-
 
318
 
275
 
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
;< -                                                                         ;;
276
proc mpint_shl uses eax ebx ecx edx esi edi, dst, shift
328
;;===========================================================================;;
277
 
329
 
278
        mov     ecx, [shift]
330
        mov     ecx, [shift]
279
        shr     ecx, 3                  ; 8 bits in one byte
331
        shr     ecx, 3                  ; 8 bits in one byte
280
        cmp     ecx, MPINT_MAX_LEN
332
        cmp     ecx, MPINT_MAX_LEN
281
        jge     .zero
333
        jge     .zero
282
        mov     esi, [dst]
334
        mov     esi, [dst]
283
        add     esi, MPINT_MAX_LEN+4-4
335
        add     esi, MPINT_MAX_LEN+4-4
284
        mov     edi, esi
336
        mov     edi, esi
285
        and     ecx, not 11b
337
        and     ecx, not 11b
286
        sub     esi, ecx
338
        sub     esi, ecx
287
        mov     edx, MPINT_MAX_LEN/4-1
339
        mov     edx, MPINT_MAX_LEN/4-1
288
        shr     ecx, 2                  ; 4 bytes in one dword
340
        shr     ecx, 2                  ; 4 bytes in one dword
289
        push    ecx
341
        push    ecx
290
        sub     edx, ecx
342
        sub     edx, ecx
291
        mov     ecx, [shift]
343
        mov     ecx, [shift]
292
        and     ecx, 11111b
344
        and     ecx, 11111b
293
        std
345
        std
294
  .loop:
346
  .loop:
295
        lodsd
347
        lodsd
296
        mov     ebx, [esi]
348
        mov     ebx, [esi]
297
        shld    eax, ebx, cl
349
        shld    eax, ebx, cl
298
        stosd
350
        stosd
299
        dec     edx
351
        dec     edx
300
        jnz     .loop
352
        jnz     .loop
301
        lodsd
353
        lodsd
302
        shl     eax, cl
354
        shl     eax, cl
303
        stosd
355
        stosd
304
 
356
 
305
        ; fill the lsb bytes with zeros
357
        ; fill the lsb bytes with zeros
306
        pop     ecx
358
        pop     ecx
307
        test    ecx, ecx
359
        test    ecx, ecx
308
        jz      @f
360
        jz      @f
309
        xor     eax, eax
361
        xor     eax, eax
310
        rep stosd
362
        rep stosd
311
  @@:
363
  @@:
312
        cld
364
        cld
313
        ret
365
        ret
314
 
366
 
315
  .zero:
367
  .zero:
316
        stdcall mpint_zero, [dst]
368
        mov     eax, [dst]
-
 
369
        mov     dword[eax], 0
317
        ret
370
        ret
318
 
371
 
319
endp
372
endp
320
 
373
 
321
; Left shift and copy
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                                                       ;;
322
proc mpint_shlmov uses eax ebx ecx edx esi edi, dst, src, shift
384
;;===========================================================================;;
323
 
385
 
324
        mov     ecx, [shift]
386
        mov     ecx, [shift]
325
        shr     ecx, 3                  ; 8 bits in one byte
387
        shr     ecx, 3                  ; 8 bits in one byte
326
        cmp     ecx, MPINT_MAX_LEN
388
        cmp     ecx, MPINT_MAX_LEN
327
        jge     .zero
389
        jge     .zero
328
        mov     esi, [src]
390
        mov     esi, [src]
329
        add     esi, MPINT_MAX_LEN+4-4
391
        add     esi, MPINT_MAX_LEN+4-4
330
        mov     edi, [dst]
392
        mov     edi, [dst]
331
        add     edi, MPINT_MAX_LEN+4-4
393
        add     edi, MPINT_MAX_LEN+4-4
332
        and     ecx, not 11b
394
        and     ecx, not 11b
333
        sub     esi, ecx
395
        sub     esi, ecx
334
        mov     edx, MPINT_MAX_LEN/4-1
396
        mov     edx, MPINT_MAX_LEN/4-1
335
        shr     ecx, 2                  ; 4 bytes in one dword
397
        shr     ecx, 2                  ; 4 bytes in one dword
336
        push    ecx
398
        push    ecx
337
        sub     edx, ecx
399
        sub     edx, ecx
338
        mov     ecx, [shift]
400
        mov     ecx, [shift]
339
        and     ecx, 11111b
401
        and     ecx, 11111b
340
        std
402
        std
341
  .loop:
403
  .loop:
342
        lodsd
404
        lodsd
343
        mov     ebx, [esi]
405
        mov     ebx, [esi]
344
        shld    eax, ebx, cl
406
        shld    eax, ebx, cl
345
        stosd
407
        stosd
346
        dec     edx
408
        dec     edx
347
        jnz     .loop
409
        jnz     .loop
348
        lodsd
410
        lodsd
349
        shl     eax, cl
411
        shl     eax, cl
350
        stosd
412
        stosd
351
 
413
 
352
        ; fill the lsb bytes with zeros
414
        ; fill the lsb bytes with zeros
353
        pop     ecx
415
        pop     ecx
354
        test    ecx, ecx
416
        test    ecx, ecx
355
        jz      @f
417
        jz      @f
356
        xor     eax, eax
418
        xor     eax, eax
357
        rep stosd
419
        rep stosd
358
  @@:
420
  @@:
359
        cld
421
        cld
360
        ret
422
        ret
361
 
423
 
362
  .zero:
424
  .zero:
363
        stdcall mpint_zero, [dst]
425
        mov     eax, [dst]
-
 
426
        mov     dword[eax], 0
364
        ret
427
        ret
365
 
428
 
366
endp
429
endp
-
 
430
 
367
 
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                                                           ;;
368
proc mpint_add uses esi edi ecx eax, dst, src
440
;;===========================================================================;;
369
 
-
 
370
        mov     esi, [src]
441
 
-
 
442
        mov     esi, [src]
-
 
443
        mov     edi, [dst]
-
 
444
        mov     ecx, [esi]      ; source number length
-
 
445
        sub     ecx, [dst]
-
 
446
        jbe     .length_ok
371
        add     esi, 4
447
; Length of the destination is currently smaller then the source, pad with 0 bytes
372
        mov     edi, [dst]
448
        add     edi, [edi]
373
        add     edi, 4
-
 
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:
378
        lodsd
453
        mov     ecx, [esi]
379
        adc     [edi], eax
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
-
 
463
  @@:
-
 
464
        inc     edi
380
        lahf
465
        lodsb
381
        add     edi, 4
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
-
 
473
        jc      .carry
-
 
474
        cmp     byte[edi], 0x80
382
        dec     ecx
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:
-
 
488
        inc     edi
-
 
489
        mov     byte[edi], 0
383
        jnz     @r
490
        mov     eax, [dst]
384
        sahf
491
        inc     dword[eax]
385
 
492
 
386
        ret
493
        ret
387
 
494
 
388
endp
495
endp
-
 
496
 
389
 
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                                                           ;;
390
proc mpint_sub uses eax esi edi ecx, dst, src
506
;;===========================================================================;;
391
 
-
 
392
        mov     esi, [src]
507
 
-
 
508
        mov     esi, [src]
-
 
509
        mov     edi, [dst]
-
 
510
        mov     ecx, [esi]      ; destination number length
-
 
511
        cmp     ecx, [edi]
-
 
512
        ja      .overflow
393
        add     esi, 4
513
 
394
        mov     edi, [dst]
514
        add     esi, 4
395
        add     edi, 4
-
 
396
        mov     ecx, MPINT_MAX_LEN/4
515
        add     edi, 4
397
  .loop:
516
; Subtract the first byte
398
        lodsd
517
        lodsb
399
        sub     [edi], eax
518
        sub     byte[edi], al
-
 
519
        dec     ecx
400
        jnc     @f
520
        jz      .done
401
        dec     dword [edi+4]
521
; Subtract the other bytes
-
 
522
  @@:
-
 
523
        inc     edi
402
  @@:
524
        lodsb
403
        add     edi, 4
525
        sbb     byte[edi], al
-
 
526
        dec     ecx
-
 
527
        jnz     @r
-
 
528
  .done:
-
 
529
        stdcall mpint_shrink, [dst]
-
 
530
        ret
-
 
531
 
-
 
532
  .overflow:
404
        dec     ecx
533
        mov     dword[edi], 0
405
        jnz     .loop
534
        stc
406
        ret
535
        ret
407
 
536
 
408
endp
537
endp
409
 
-
 
-
 
538
 
-
 
539
 
-
 
540
;;===========================================================================;;
410
proc mpint_mul uses esi edi ecx ebx eax, dst, A, B
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
;;---------------------------------------------------------------------------;;
411
 
-
 
412
        stdcall mpint_zero, [dst]
-
 
413
 
547
;<                                                                           ;;
414
        ; first, find the byte in A containing the highest order bit
548
;;===========================================================================;;
415
        mov     ecx, MPINT_MAX_LEN
549
 
-
 
550
        mov     edi, [dst]
-
 
551
        lodsd
-
 
552
        std
416
        mov     edi, [A]
553
        mov     ecx, eax
417
        add     edi, MPINT_MAX_LEN+4-1
554
        dec     eax             ; total length minus one
418
        std
-
 
419
        xor     al, al
-
 
420
        repe scasb
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                                                               ;;
-
 
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]
421
        cld
586
        test    eax, eax
422
        je      .zero
587
        jz      .zero
423
        inc     ecx
588
        add     edi, eax
424
        mov     al, [edi+1]
589
        mov     al, [edi+1]
425
        mov     esi, edi
590
        mov     esi, edi
426
        mov     bl, 8
591
        mov     bl, 8
427
  @@:
592
  @@:
428
        shl     al, 1
593
        shl     al, 1
429
        jc      .first_hit
594
        jc      .first_hit
430
        dec     bl
595
        dec     bl
431
        jnz     @r
596
        jnz     @r
432
 
597
 
433
        ; Then, starting from this byte, iterate through the bits in A,
598
        ; Then, starting from this byte, iterate through the bits in A,
434
        ; starting from the highest order bit down to the lowest order bit.
599
        ; starting from the highest order bit down to the lowest order bit.
435
  .next_byte:
600
  .next_byte:
436
        mov     al, [edi]
601
        mov     al, [edi]
437
        dec     edi
602
        dec     edi
438
        mov     bl, 8
603
        mov     bl, 8
439
  .next_bit:
604
  .next_bit:
440
        stdcall mpint_shl1, [dst]
605
        stdcall mpint_shl1, [dst]
441
        shl     al, 1
606
        shl     al, 1
442
        jnc     .zero_bit
607
        jnc     .zero_bit
443
  .first_hit:
608
  .first_hit:
444
        stdcall mpint_add, [dst], [B]
609
        stdcall mpint_add, [dst], [B]
445
  .zero_bit:
610
  .zero_bit:
446
        dec     bl
611
        dec     bl
447
        jnz     .next_bit
612
        jnz     .next_bit
448
        dec     ecx
613
        dec     ecx
449
        jnz     .next_byte
614
        jnz     .next_byte
450
  .zero:
615
  .zero:
451
        ret
616
        ret
452
 
617
 
453
endp
618
endp
-
 
619
 
454
 
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
-
 
632
        mpint_tmp       rb MPINT_MAX_LEN+4
455
proc mpint_mod uses eax ecx, dst, mod
633
endl
456
 
634
 
-
 
635
        ; if mod is zero, return
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
460
 
639
 
461
        stdcall mpint_cmp, [mod], [dst]
640
        stdcall mpint_cmp, eax, [dst]
462
        jb      .done                           ; if dst < mod, dst = dst
641
        jb      .done                           ; if dst < mod, dst = dst
463
        je      .zero                           ; if dst == mod, dst = 0
642
        je      .zero                           ; if dst == mod, dst = 0
-
 
643
 
-
 
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]
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
480
  @@:
661
  @@:
481
        dec     ecx
662
        dec     ecx
482
        jz      .done
663
        jz      .done
483
        ;   shift mpint_tmp right by 1
664
        ;   shift mpint_tmp right by 1
484
        stdcall mpint_shr1, mpint_tmp
665
        stdcall mpint_shr1, ebx
485
        jmp     .loop
666
        jmp     .loop
486
 
667
 
487
  .zero:
668
  .zero:
488
        stdcall mpint_zero, [dst]
669
        mov     eax, [dst]
-
 
670
        mov     dword[eax], 0
489
  .done:
671
  .done:
490
        ret
672
        ret
491
 
673
 
492
endp
674
endp
-
 
675
 
493
 
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
;;===========================================================================;;
-
 
688
 
-
 
689
locals
-
 
690
        mpint_tmp       rb MPINT_MAX_LEN+4
494
proc mpint_modexp uses edi eax ebx ecx, dst, base, exp, mod
691
endl
495
 
692
 
-
 
693
        ; If mod is zero, return
496
        ; If mod is zero, return
694
        mov     eax, [mod]
497
        stdcall mpint_zero?, [mod]
695
        cmp     dword[eax], 0
498
        jz      .mod_zero
696
        je      .mod_zero
499
 
697
 
500
        ; Find the highest order byte in exponent
698
        ; Find the highest order byte in exponent
501
        mov     edi, [exp]
699
        mov     edi, [exp]
502
        mov     ecx, [edi]
700
        mov     ecx, [edi]
503
        lea     edi, [edi + 4 + ecx - 1]
701
        lea     edi, [edi + 4 + ecx - 1]
504
        ; Find the highest order bit in this byte
702
        ; Find the highest order bit in this byte
505
        mov     al, [edi]
703
        mov     al, [edi]
506
        test    al, al
704
        test    al, al
507
        jz      .invalid
705
        jz      .invalid
508
        mov     bl, 9
706
        mov     bl, 9
509
  @@:
707
  @@:
510
        dec     bl
708
        dec     bl
511
        shl     al, 1
709
        shl     al, 1
512
        jnc     @r
710
        jnc     @r
-
 
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
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
532
        jnz     .bit_loop
731
        jnz     .bit_loop
533
  .next_byte:
732
  .next_byte:
534
        dec     ecx
733
        dec     ecx
535
        jz      .done
734
        jz      .done
536
        dec     edi
735
        dec     edi
537
        mov     al, [edi]
736
        mov     al, [edi]
538
        mov     bl, 8
737
        mov     bl, 8
539
        jmp     .bit_loop
738
        jmp     .bit_loop
540
  .done:
739
  .done:
541
        ret
740
        ret
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
546
        stdcall mpint_zero, [dst]
745
        mov     eax, [dst]
-
 
746
        mov     dword[eax], 0
547
        ret
747
        ret
548
 
748
 
549
  .exp_zero:
749
  .exp_zero:
550
        DEBUGF  3, "modexp with exponent 0\n"
750
        DEBUGF  3, "modexp with exponent 0\n"
551
        ; if exponent is zero, result = 1
751
        ; if exponent is zero, result = 1
552
        stdcall mpint_zero, [dst]
-
 
553
        mov     eax, [dst]
752
        mov     eax, [dst]
554
        mov     byte[eax], 1
753
        mov     dword[eax], 1
555
        mov     byte[eax+4], 1
754
        mov     byte[eax+4], 1
556
        ret
755
        ret
557
 
756
 
558
  .invalid:
757
  .invalid:
559
        DEBUGF  3, "modexp: Invalid input!\n"
758
        DEBUGF  3, "modexp: Invalid input!\n"
560
        ret
759
        ret
561
 
760
 
562
endp
761
endp