Subversion Repositories Kolibri OS

Rev

Rev 6419 | Rev 6469 | 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-2016 Jeffrey Amelynck
  4. ;
  5. ;    This program is free software: you can redistribute it and/or modify
  6. ;    it under the terms of the GNU General Public License as published by
  7. ;    the Free Software Foundation, either version 3 of the License, or
  8. ;    (at your option) any later version.
  9. ;
  10. ;    This program is distributed in the hope that it will be useful,
  11. ;    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ;    GNU General Public License for more details.
  14. ;
  15. ;    You should have received a copy of the GNU General Public License
  16. ;    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  
  18. MPINT_MAX_LEN = MAX_BITS/8
  19.  
  20. ; TODO: make procedures use real number length instead of hardcoded maximum length (MPINT_MAX_LEN)
  21.  
  22. mpint_to_little_endian:
  23.  
  24. ; Load length dword
  25.         lodsd
  26. ; Convert to little endian
  27.         bswap   eax
  28.         stosd
  29.         test    eax, eax
  30.         jz      .zero
  31. ; Copy data, convert to little endian meanwhile
  32.         push    eax
  33.         add     esi, eax
  34.         push    esi
  35.         dec     esi
  36.         mov     ecx, eax
  37.         std
  38.   @@:
  39.         lodsb
  40.         mov     byte[edi], al
  41.         inc     edi
  42.         dec     ecx
  43.         jnz     @r
  44.         cld
  45.         pop     esi eax
  46. ; Fill the rest of the buffer with zeros.
  47.   .zero:
  48.         mov     ecx, MAX_BITS/8
  49.         sub     ecx, eax
  50.         xor     al, al
  51.         rep stosb
  52.  
  53.         ret
  54.  
  55. mpint_to_big_endian:
  56.  
  57. ; Load length dword
  58.         lodsd
  59.         test    eax, eax
  60.         jz      .zero
  61.         mov     ecx, eax
  62.         add     esi, ecx
  63.         dec     esi
  64.         test    byte[esi], 0x80   ; Is the highest bit set?
  65.         jz      @f
  66.         inc     eax
  67.   @@:
  68.         push    eax
  69.         bswap   eax
  70.         stosd
  71. ; Copy data, convert to big endian meanwhile
  72.         std
  73. ; Append zero byte if highest bit is 0
  74.         test    byte[esi], 0x80
  75.         jz      @f
  76.         mov     byte[edi], 0
  77.         inc     edi
  78.   @@:
  79.         lodsb
  80.         mov     byte[edi], al
  81.         inc     edi
  82.         dec     ecx
  83.         jnz     @r
  84.         cld
  85.         pop     eax
  86.         ret
  87.  
  88.   .zero:
  89.         stosd
  90.         ret
  91.  
  92. proc mpint_length uses edi eax ecx, mpint
  93.  
  94.         mov     edi, [mpint]
  95.         mov     ecx, MPINT_MAX_LEN
  96.         push    edi
  97.         lea     edi, [edi + ecx + 4 - 1]
  98.         xor     al, al
  99.         std
  100.         repe scasb
  101.         cld
  102.         je      @f
  103.         inc     ecx
  104.   @@:
  105.         pop     edi
  106.         mov     [edi], ecx
  107.  
  108.         ret
  109.  
  110. endp
  111.  
  112. proc mpint_print uses ecx esi eax, src
  113.  
  114.         DEBUGF  1, "0x"
  115.         mov     esi, [src]
  116.         mov     ecx, [esi]
  117.         test    ecx, ecx
  118.         jz      .zero
  119.         lea     esi, [esi + ecx + 4 - 1]
  120.         pushf
  121.         std
  122.   .loop:
  123.         lodsb
  124.         DEBUGF  1, "%x", eax:2
  125.         dec     ecx
  126.         jnz     .loop
  127.         DEBUGF  1, "\n"
  128.         popf
  129.  
  130.         ret
  131.  
  132.   .zero:
  133.         DEBUGF  1, "00\n"
  134.         ret
  135.  
  136. endp
  137.  
  138. proc mpint_zero uses edi ecx eax, dst
  139.  
  140.         mov     edi, [dst]
  141.         xor     eax, eax
  142.         mov     ecx, MPINT_MAX_LEN/4+1
  143.         rep stosd
  144.  
  145.         ret
  146.  
  147. endp
  148.  
  149. proc mpint_zero? uses edi ecx eax, dst
  150.  
  151.         mov     edi, [dst]
  152.         add     edi, 4
  153.         mov     ecx, MPINT_MAX_LEN/4
  154.         xor     eax, eax
  155.         repe scasd
  156.         ret
  157.  
  158. endp
  159.  
  160. ; return an index number giving the position of the highest order bit
  161. proc mpint_hob uses edi ecx, dst
  162.  
  163.         mov     edi, [dst]
  164.         ; start from the high order byte
  165.         add     edi, MPINT_MAX_LEN+4-1
  166.         mov     ecx, MPINT_MAX_LEN
  167.         xor     eax, eax
  168.         ; scan byte by byte for the first non-zero byte
  169.         std
  170.         repe scasb
  171.         cld
  172.         je      .zero
  173.         ; calculate how many bits this is, plus 7
  174.         lea     eax, [ecx*8-1]
  175.         ; load this high order byte into cl
  176.         mov     cl, [edi+1]
  177.         ; shift bits of this byte right, until the byte reaches zero, counting bits meanwhile
  178.   @@:
  179.         inc     eax
  180.         shr     cl, 1
  181.         jnz     @r
  182.   .zero:
  183.         ret
  184.  
  185. endp
  186.  
  187. proc mpint_cmp uses esi edi ecx, dst, src
  188.  
  189.         mov     esi, [src]
  190.         mov     edi, [dst]
  191.         ; start from the high order byte
  192.         add     esi, MPINT_MAX_LEN+4-4
  193.         add     edi, MPINT_MAX_LEN+4-4
  194.         mov     ecx, MPINT_MAX_LEN/4
  195.         std
  196.         repe cmpsd
  197.         cld
  198.         ret
  199.  
  200. endp
  201.  
  202. proc mpint_mov uses esi edi ecx, dst, src
  203.  
  204.         mov     esi, [src]
  205.         mov     edi, [dst]
  206.         mov     ecx, MPINT_MAX_LEN/4+1
  207.         rep movsd
  208.  
  209.         ret
  210.  
  211. endp
  212.  
  213. proc mpint_mov0 uses esi edi ecx eax, dst, src
  214.  
  215.         mov     esi, [src]
  216.         mov     edi, [dst]
  217.         mov     ecx, [esi]
  218.         mov     eax, ecx
  219.         neg     eax
  220.         add     esi, 4
  221.         add     edi, 4
  222.         rep movsb
  223.         add     eax, MPINT_MAX_LEN
  224.         jz      @f
  225.         mov     ecx, eax
  226.         xor     eax, eax
  227.         rep stosb
  228.   @@:
  229.  
  230.         ret
  231.  
  232. endp
  233.  
  234. proc mpint_shl1 uses edi ecx eax, dst
  235.  
  236.         mov     edi, [dst]
  237.         add     edi, 4
  238.         mov     ecx, MPINT_MAX_LEN/4-1
  239.  
  240.         shl     dword[edi], 1
  241.         lahf
  242.   @@:
  243.         add     edi, 4
  244.         sahf
  245.         rcl     dword[edi], 1
  246.         lahf
  247.         dec     ecx
  248.         jnz     @r
  249.         sahf
  250.  
  251.         ret
  252.  
  253. endp
  254.  
  255. proc mpint_shr1 uses edi ecx eax, dst
  256.  
  257.         mov     edi, [dst]
  258.         add     edi, MPINT_MAX_LEN+4-4
  259.         mov     ecx, MPINT_MAX_LEN/4-1
  260.  
  261.         shr     dword[edi], 1
  262.         lahf
  263.   @@:
  264.         sub     edi, 4
  265.         sahf
  266.         rcr     dword[edi], 1
  267.         lahf
  268.         dec     ecx
  269.         jnz     @r
  270.         sahf
  271.  
  272.         ret
  273.  
  274. endp
  275.  
  276. proc mpint_shl uses eax ebx ecx edx esi edi, dst, shift
  277.  
  278.         mov     ecx, [shift]
  279.         shr     ecx, 3                  ; 8 bits in one byte
  280.         cmp     ecx, MPINT_MAX_LEN
  281.         jge     .zero
  282.         mov     esi, [dst]
  283.         add     esi, MPINT_MAX_LEN+4-4
  284.         mov     edi, esi
  285.         and     ecx, not 11b
  286.         sub     esi, ecx
  287.         mov     edx, MPINT_MAX_LEN/4-1
  288.         shr     ecx, 2                  ; 4 bytes in one dword
  289.         push    ecx
  290.         sub     edx, ecx
  291.         mov     ecx, [shift]
  292.         and     ecx, 11111b
  293.         std
  294.   .loop:
  295.         lodsd
  296.         mov     ebx, [esi]
  297.         shld    eax, ebx, cl
  298.         stosd
  299.         dec     edx
  300.         jnz     .loop
  301.         lodsd
  302.         shl     eax, cl
  303.         stosd
  304.  
  305.         ; fill the lsb bytes with zeros
  306.         pop     ecx
  307.         test    ecx, ecx
  308.         jz      @f
  309.         xor     eax, eax
  310.         rep stosd
  311.   @@:
  312.         cld
  313.         ret
  314.  
  315.   .zero:
  316.         stdcall mpint_zero, [dst]
  317.         ret
  318.  
  319. endp
  320.  
  321. ; Left shift and copy
  322. proc mpint_shlmov uses eax ebx ecx edx esi edi, dst, src, shift
  323.  
  324.         mov     ecx, [shift]
  325.         shr     ecx, 3                  ; 8 bits in one byte
  326.         cmp     ecx, MPINT_MAX_LEN
  327.         jge     .zero
  328.         mov     esi, [src]
  329.         add     esi, MPINT_MAX_LEN+4-4
  330.         mov     edi, [dst]
  331.         add     edi, MPINT_MAX_LEN+4-4
  332.         and     ecx, not 11b
  333.         sub     esi, ecx
  334.         mov     edx, MPINT_MAX_LEN/4-1
  335.         shr     ecx, 2                  ; 4 bytes in one dword
  336.         push    ecx
  337.         sub     edx, ecx
  338.         mov     ecx, [shift]
  339.         and     ecx, 11111b
  340.         std
  341.   .loop:
  342.         lodsd
  343.         mov     ebx, [esi]
  344.         shld    eax, ebx, cl
  345.         stosd
  346.         dec     edx
  347.         jnz     .loop
  348.         lodsd
  349.         shl     eax, cl
  350.         stosd
  351.  
  352.         ; fill the lsb bytes with zeros
  353.         pop     ecx
  354.         test    ecx, ecx
  355.         jz      @f
  356.         xor     eax, eax
  357.         rep stosd
  358.   @@:
  359.         cld
  360.         ret
  361.  
  362.   .zero:
  363.         stdcall mpint_zero, [dst]
  364.         ret
  365.  
  366. endp
  367.  
  368. proc mpint_add uses esi edi ecx eax, dst, src
  369.  
  370.         mov     esi, [src]
  371.         add     esi, 4
  372.         mov     edi, [dst]
  373.         add     edi, 4
  374.         mov     ecx, MPINT_MAX_LEN/4
  375.         xor     ah, ah          ; clear flags (Carry flag most importantly)
  376.   @@:
  377.         sahf
  378.         lodsd
  379.         adc     [edi], eax
  380.         lahf
  381.         add     edi, 4
  382.         dec     ecx
  383.         jnz     @r
  384.         sahf
  385.  
  386.         ret
  387.  
  388. endp
  389.  
  390. proc mpint_sub uses eax esi edi ecx, dst, src
  391.  
  392.         mov     esi, [src]
  393.         add     esi, 4
  394.         mov     edi, [dst]
  395.         add     edi, 4
  396.         mov     ecx, MPINT_MAX_LEN/4
  397.   .loop:
  398.         lodsd
  399.         sub     [edi], eax
  400.         jnc     @f
  401.         dec     dword [edi+4]
  402.   @@:
  403.         add     edi, 4
  404.         dec     ecx
  405.         jnz     .loop
  406.         ret
  407.  
  408. endp
  409.  
  410. proc mpint_mul uses esi edi ecx ebx eax, dst, A, B
  411.  
  412.         stdcall mpint_zero, [dst]
  413.  
  414.         ; first, find the byte in A containing the highest order bit
  415.         mov     ecx, MPINT_MAX_LEN
  416.         mov     edi, [A]
  417.         add     edi, MPINT_MAX_LEN+4-1
  418.         std
  419.         xor     al, al
  420.         repe scasb
  421.         cld
  422.         je      .zero
  423.         inc     ecx
  424.         mov     al, [edi+1]
  425.         mov     esi, edi
  426.         mov     bl, 8
  427.   @@:
  428.         shl     al, 1
  429.         jc      .first_hit
  430.         dec     bl
  431.         jnz     @r
  432.  
  433.         ; Then, starting from this byte, iterate through the bits in A,
  434.         ; starting from the highest order bit down to the lowest order bit.
  435.   .next_byte:
  436.         mov     al, [edi]
  437.         dec     edi
  438.         mov     bl, 8
  439.   .next_bit:
  440.         stdcall mpint_shl1, [dst]
  441.         shl     al, 1
  442.         jnc     .zero_bit
  443.   .first_hit:
  444.         stdcall mpint_add, [dst], [B]
  445.   .zero_bit:
  446.         dec     bl
  447.         jnz     .next_bit
  448.         dec     ecx
  449.         jnz     .next_byte
  450.   .zero:
  451.         ret
  452.  
  453. endp
  454.  
  455. proc mpint_mod uses eax ecx, dst, mod
  456.  
  457.         ; if mod is zero, return
  458.         stdcall mpint_zero?, [mod]
  459.         jz      .zero
  460.  
  461.         stdcall mpint_cmp, [mod], [dst]
  462.         jb      .done                           ; if dst < mod, dst = dst
  463.         je      .zero                           ; if dst == mod, dst = 0
  464.  
  465.         ; left shift mod until the high order bits of mod and dst are aligned
  466.         stdcall mpint_hob, [dst]
  467.         mov     ecx, eax
  468.         stdcall mpint_hob, [mod]
  469.         sub     ecx, eax
  470.         stdcall mpint_shlmov, mpint_tmp, [mod], ecx
  471.         inc     ecx
  472.  
  473.         ; For every bit in dst (starting from the high order bit):
  474.   .loop:
  475.         ;   determine if dst is bigger than mpint_tmp
  476.         stdcall mpint_cmp, [dst], mpint_tmp
  477.         ja      @f
  478.         ;   if so, subtract mpint_tmp from dst
  479.         stdcall mpint_sub, [dst], mpint_tmp
  480.   @@:
  481.         dec     ecx
  482.         jz      .done
  483.         ;   shift mpint_tmp right by 1
  484.         stdcall mpint_shr1, mpint_tmp
  485.         jmp     .loop
  486.  
  487.   .zero:
  488.         stdcall mpint_zero, [dst]
  489.   .done:
  490.         ret
  491.  
  492. endp
  493.  
  494. proc mpint_modexp uses edi eax ebx ecx, dst, base, exp, mod
  495.  
  496.         ; If mod is zero, return
  497.         stdcall mpint_zero?, [mod]
  498.         jz      .mod_zero
  499.  
  500.         ; Find the highest order byte in exponent
  501.         mov     edi, [exp]
  502.         mov     ecx, [edi]
  503.         lea     edi, [edi + 4 + ecx - 1]
  504.         ; Find the highest order bit in this byte
  505.         mov     al, [edi]
  506.         test    al, al
  507.         jz      .invalid
  508.         mov     bl, 9
  509.   @@:
  510.         dec     bl
  511.         shl     al, 1
  512.         jnc     @r
  513.  
  514.         ; Initialise result to base, to take care of the highest order bit
  515.         stdcall mpint_mov0, [dst], [base]
  516.         dec     bl
  517.         jz      .next_byte
  518.   .bit_loop:
  519.         ; For each bit, square result
  520.         stdcall mpint_mov, mpint_tmp, [dst]
  521.         stdcall mpint_mul, [dst], mpint_tmp, mpint_tmp
  522.         stdcall mpint_mod, [dst], [mod]
  523.  
  524.         ; If the bit is set, multiply result by the base
  525.         shl     al, 1
  526.         jnc     .next_bit
  527.         stdcall mpint_mov, mpint_tmp, [dst]
  528.         stdcall mpint_mul, [dst], [base], mpint_tmp
  529.         stdcall mpint_mod, [dst], [mod]
  530.   .next_bit:
  531.         dec     bl
  532.         jnz     .bit_loop
  533.   .next_byte:
  534.         dec     ecx
  535.         jz      .done
  536.         dec     edi
  537.         mov     al, [edi]
  538.         mov     bl, 8
  539.         jmp     .bit_loop
  540.   .done:
  541.         ret
  542.  
  543.   .mod_zero:
  544.         DEBUGF  1, "modexp with modulo 0\n"
  545.         ; if mod is zero, result = 0
  546.         stdcall mpint_zero, [dst]
  547.         ret
  548.  
  549.   .exp_zero:
  550.         DEBUGF  1, "modexp with exponent 0\n"
  551.         ; if exponent is zero, result = 1
  552.         stdcall mpint_zero, [dst]
  553.         mov     eax, [dst]
  554.         mov     byte[eax], 1
  555.         mov     byte[eax+4], 1
  556.         ret
  557.  
  558.   .invalid:
  559.         DEBUGF  1, "modexp: Invalid input!\n"
  560.         ret
  561.  
  562. endp