via-mont.pl 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #! /usr/bin/env perl
  2. # Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
  3. #
  4. # Licensed under the OpenSSL license (the "License"). You may not use
  5. # this file except in compliance with the License. You can obtain a copy
  6. # in the file LICENSE in the source distribution or at
  7. # https://www.openssl.org/source/license.html
  8. #
  9. # ====================================================================
  10. # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
  11. # project. The module is, however, dual licensed under OpenSSL and
  12. # CRYPTOGAMS licenses depending on where you obtain it. For further
  13. # details see http://www.openssl.org/~appro/cryptogams/.
  14. # ====================================================================
  15. #
  16. # Wrapper around 'rep montmul', VIA-specific instruction accessing
  17. # PadLock Montgomery Multiplier. The wrapper is designed as drop-in
  18. # replacement for OpenSSL bn_mul_mont [first implemented in 0.9.9].
  19. #
  20. # Below are interleaved outputs from 'openssl speed rsa dsa' for 4
  21. # different software configurations on 1.5GHz VIA Esther processor.
  22. # Lines marked with "software integer" denote performance of hand-
  23. # coded integer-only assembler found in OpenSSL 0.9.7. "Software SSE2"
  24. # refers to hand-coded SSE2 Montgomery multiplication procedure found
  25. # OpenSSL 0.9.9. "Hardware VIA SDK" refers to padlock_pmm routine from
  26. # Padlock SDK 2.0.1 available for download from VIA, which naturally
  27. # utilizes the magic 'repz montmul' instruction. And finally "hardware
  28. # this" refers to *this* implementation which also uses 'repz montmul'
  29. #
  30. # sign verify sign/s verify/s
  31. # rsa 512 bits 0.001720s 0.000140s 581.4 7149.7 software integer
  32. # rsa 512 bits 0.000690s 0.000086s 1450.3 11606.0 software SSE2
  33. # rsa 512 bits 0.006136s 0.000201s 163.0 4974.5 hardware VIA SDK
  34. # rsa 512 bits 0.000712s 0.000050s 1404.9 19858.5 hardware this
  35. #
  36. # rsa 1024 bits 0.008518s 0.000413s 117.4 2420.8 software integer
  37. # rsa 1024 bits 0.004275s 0.000277s 233.9 3609.7 software SSE2
  38. # rsa 1024 bits 0.012136s 0.000260s 82.4 3844.5 hardware VIA SDK
  39. # rsa 1024 bits 0.002522s 0.000116s 396.5 8650.9 hardware this
  40. #
  41. # rsa 2048 bits 0.050101s 0.001371s 20.0 729.6 software integer
  42. # rsa 2048 bits 0.030273s 0.001008s 33.0 991.9 software SSE2
  43. # rsa 2048 bits 0.030833s 0.000976s 32.4 1025.1 hardware VIA SDK
  44. # rsa 2048 bits 0.011879s 0.000342s 84.2 2921.7 hardware this
  45. #
  46. # rsa 4096 bits 0.327097s 0.004859s 3.1 205.8 software integer
  47. # rsa 4096 bits 0.229318s 0.003859s 4.4 259.2 software SSE2
  48. # rsa 4096 bits 0.233953s 0.003274s 4.3 305.4 hardware VIA SDK
  49. # rsa 4096 bits 0.070493s 0.001166s 14.2 857.6 hardware this
  50. #
  51. # dsa 512 bits 0.001342s 0.001651s 745.2 605.7 software integer
  52. # dsa 512 bits 0.000844s 0.000987s 1185.3 1013.1 software SSE2
  53. # dsa 512 bits 0.001902s 0.002247s 525.6 444.9 hardware VIA SDK
  54. # dsa 512 bits 0.000458s 0.000524s 2182.2 1909.1 hardware this
  55. #
  56. # dsa 1024 bits 0.003964s 0.004926s 252.3 203.0 software integer
  57. # dsa 1024 bits 0.002686s 0.003166s 372.3 315.8 software SSE2
  58. # dsa 1024 bits 0.002397s 0.002823s 417.1 354.3 hardware VIA SDK
  59. # dsa 1024 bits 0.000978s 0.001170s 1022.2 855.0 hardware this
  60. #
  61. # dsa 2048 bits 0.013280s 0.016518s 75.3 60.5 software integer
  62. # dsa 2048 bits 0.009911s 0.011522s 100.9 86.8 software SSE2
  63. # dsa 2048 bits 0.009542s 0.011763s 104.8 85.0 hardware VIA SDK
  64. # dsa 2048 bits 0.002884s 0.003352s 346.8 298.3 hardware this
  65. #
  66. # To give you some other reference point here is output for 2.4GHz P4
  67. # running hand-coded SSE2 bn_mul_mont found in 0.9.9, i.e. "software
  68. # SSE2" in above terms.
  69. #
  70. # rsa 512 bits 0.000407s 0.000047s 2454.2 21137.0
  71. # rsa 1024 bits 0.002426s 0.000141s 412.1 7100.0
  72. # rsa 2048 bits 0.015046s 0.000491s 66.5 2034.9
  73. # rsa 4096 bits 0.109770s 0.002379s 9.1 420.3
  74. # dsa 512 bits 0.000438s 0.000525s 2281.1 1904.1
  75. # dsa 1024 bits 0.001346s 0.001595s 742.7 627.0
  76. # dsa 2048 bits 0.004745s 0.005582s 210.7 179.1
  77. #
  78. # Conclusions:
  79. # - VIA SDK leaves a *lot* of room for improvement (which this
  80. # implementation successfully fills:-);
  81. # - 'rep montmul' gives up to >3x performance improvement depending on
  82. # key length;
  83. # - in terms of absolute performance it delivers approximately as much
  84. # as modern out-of-order 32-bit cores [again, for longer keys].
  85. $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
  86. push(@INC,"${dir}","${dir}../../perlasm");
  87. require "x86asm.pl";
  88. $output = pop;
  89. open STDOUT,">$output";
  90. &asm_init($ARGV[0]);
  91. # int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, const BN_ULONG *np,const BN_ULONG *n0, int num);
  92. $func="bn_mul_mont_padlock";
  93. $pad=16*1; # amount of reserved bytes on top of every vector
  94. # stack layout
  95. $mZeroPrime=&DWP(0,"esp"); # these are specified by VIA
  96. $A=&DWP(4,"esp");
  97. $B=&DWP(8,"esp");
  98. $T=&DWP(12,"esp");
  99. $M=&DWP(16,"esp");
  100. $scratch=&DWP(20,"esp");
  101. $rp=&DWP(24,"esp"); # these are mine
  102. $sp=&DWP(28,"esp");
  103. # &DWP(32,"esp") # 32 byte scratch area
  104. # &DWP(64+(4*$num+$pad)*0,"esp") # padded tp[num]
  105. # &DWP(64+(4*$num+$pad)*1,"esp") # padded copy of ap[num]
  106. # &DWP(64+(4*$num+$pad)*2,"esp") # padded copy of bp[num]
  107. # &DWP(64+(4*$num+$pad)*3,"esp") # padded copy of np[num]
  108. # Note that SDK suggests to unconditionally allocate 2K per vector. This
  109. # has quite an impact on performance. It naturally depends on key length,
  110. # but to give an example 1024 bit private RSA key operations suffer >30%
  111. # penalty. I allocate only as much as actually required...
  112. &function_begin($func);
  113. &xor ("eax","eax");
  114. &mov ("ecx",&wparam(5)); # num
  115. # meet VIA's limitations for num [note that the specification
  116. # expresses them in bits, while we work with amount of 32-bit words]
  117. &test ("ecx",3);
  118. &jnz (&label("leave")); # num % 4 != 0
  119. &cmp ("ecx",8);
  120. &jb (&label("leave")); # num < 8
  121. &cmp ("ecx",1024);
  122. &ja (&label("leave")); # num > 1024
  123. &pushf ();
  124. &cld ();
  125. &mov ("edi",&wparam(0)); # rp
  126. &mov ("eax",&wparam(1)); # ap
  127. &mov ("ebx",&wparam(2)); # bp
  128. &mov ("edx",&wparam(3)); # np
  129. &mov ("esi",&wparam(4)); # n0
  130. &mov ("esi",&DWP(0,"esi")); # *n0
  131. &lea ("ecx",&DWP($pad,"","ecx",4)); # ecx becomes vector size in bytes
  132. &lea ("ebp",&DWP(64,"","ecx",4)); # allocate 4 vectors + 64 bytes
  133. &neg ("ebp");
  134. &add ("ebp","esp");
  135. &and ("ebp",-64); # align to cache-line
  136. &xchg ("ebp","esp"); # alloca
  137. &mov ($rp,"edi"); # save rp
  138. &mov ($sp,"ebp"); # save esp
  139. &mov ($mZeroPrime,"esi");
  140. &lea ("esi",&DWP(64,"esp")); # tp
  141. &mov ($T,"esi");
  142. &lea ("edi",&DWP(32,"esp")); # scratch area
  143. &mov ($scratch,"edi");
  144. &mov ("esi","eax");
  145. &lea ("ebp",&DWP(-$pad,"ecx"));
  146. &shr ("ebp",2); # restore original num value in ebp
  147. &xor ("eax","eax");
  148. &mov ("ecx","ebp");
  149. &lea ("ecx",&DWP((32+$pad)/4,"ecx"));# padded tp + scratch
  150. &data_byte(0xf3,0xab); # rep stosl, bzero
  151. &mov ("ecx","ebp");
  152. &lea ("edi",&DWP(64+$pad,"esp","ecx",4));# pointer to ap copy
  153. &mov ($A,"edi");
  154. &data_byte(0xf3,0xa5); # rep movsl, memcpy
  155. &mov ("ecx",$pad/4);
  156. &data_byte(0xf3,0xab); # rep stosl, bzero pad
  157. # edi points at the end of padded ap copy...
  158. &mov ("ecx","ebp");
  159. &mov ("esi","ebx");
  160. &mov ($B,"edi");
  161. &data_byte(0xf3,0xa5); # rep movsl, memcpy
  162. &mov ("ecx",$pad/4);
  163. &data_byte(0xf3,0xab); # rep stosl, bzero pad
  164. # edi points at the end of padded bp copy...
  165. &mov ("ecx","ebp");
  166. &mov ("esi","edx");
  167. &mov ($M,"edi");
  168. &data_byte(0xf3,0xa5); # rep movsl, memcpy
  169. &mov ("ecx",$pad/4);
  170. &data_byte(0xf3,0xab); # rep stosl, bzero pad
  171. # edi points at the end of padded np copy...
  172. # let magic happen...
  173. &mov ("ecx","ebp");
  174. &mov ("esi","esp");
  175. &shl ("ecx",5); # convert word counter to bit counter
  176. &align (4);
  177. &data_byte(0xf3,0x0f,0xa6,0xc0);# rep montmul
  178. &mov ("ecx","ebp");
  179. &lea ("esi",&DWP(64,"esp")); # tp
  180. # edi still points at the end of padded np copy...
  181. &neg ("ebp");
  182. &lea ("ebp",&DWP(-$pad,"edi","ebp",4)); # so just "rewind"
  183. &mov ("edi",$rp); # restore rp
  184. &xor ("edx","edx"); # i=0 and clear CF
  185. &set_label("sub",8);
  186. &mov ("eax",&DWP(0,"esi","edx",4));
  187. &sbb ("eax",&DWP(0,"ebp","edx",4));
  188. &mov (&DWP(0,"edi","edx",4),"eax"); # rp[i]=tp[i]-np[i]
  189. &lea ("edx",&DWP(1,"edx")); # i++
  190. &loop (&label("sub")); # doesn't affect CF!
  191. &mov ("eax",&DWP(0,"esi","edx",4)); # upmost overflow bit
  192. &sbb ("eax",0);
  193. &mov ("ecx","edx"); # num
  194. &mov ("edx",0); # i=0
  195. &set_label("copy",8);
  196. &mov ("ebx",&DWP(0,"esi","edx",4));
  197. &mov ("eax",&DWP(0,"edi","edx",4));
  198. &mov (&DWP(0,"esi","edx",4),"ecx"); # zap tp
  199. &cmovc ("eax","ebx");
  200. &mov (&DWP(0,"edi","edx",4),"eax");
  201. &lea ("edx",&DWP(1,"edx")); # i++
  202. &loop (&label("copy"));
  203. &mov ("ebp",$sp);
  204. &xor ("eax","eax");
  205. &mov ("ecx",64/4);
  206. &mov ("edi","esp"); # zap frame including scratch area
  207. &data_byte(0xf3,0xab); # rep stosl, bzero
  208. # zap copies of ap, bp and np
  209. &lea ("edi",&DWP(64+$pad,"esp","edx",4));# pointer to ap
  210. &lea ("ecx",&DWP(3*$pad/4,"edx","edx",2));
  211. &data_byte(0xf3,0xab); # rep stosl, bzero
  212. &mov ("esp","ebp");
  213. &inc ("eax"); # signal "done"
  214. &popf ();
  215. &set_label("leave");
  216. &function_end($func);
  217. &asciz("Padlock Montgomery Multiplication, CRYPTOGAMS by <appro\@openssl.org>");
  218. &asm_finish();
  219. close STDOUT or die "error closing STDOUT: $!";