Subversion Repositories Kolibri OS

Rev

Rev 6922 | Rev 9090 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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