cmll-x86.pl 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. #!/usr/bin/env perl
  2. # ====================================================================
  3. # Copyright (c) 2008 Andy Polyakov <appro@openssl.org>
  4. #
  5. # This module may be used under the terms of either the GNU General
  6. # Public License version 2 or later, the GNU Lesser General Public
  7. # License version 2.1 or later, the Mozilla Public License version
  8. # 1.1 or the BSD License. The exact terms of either license are
  9. # distributed along with this module. For further details see
  10. # http://www.openssl.org/~appro/camellia/.
  11. # ====================================================================
  12. # Performance in cycles per processed byte (less is better) in
  13. # 'openssl speed ...' benchmark:
  14. #
  15. # AMD K8 Core2 PIII P4
  16. # -evp camellia-128-ecb 21.5 22.8 27.0 28.9
  17. # + over gcc 3.4.6 +90/11% +70/10% +53/4% +160/64%
  18. # + over icc 8.0 +48/19% +21/15% +21/17% +55/37%
  19. #
  20. # camellia-128-cbc 17.3 21.1 23.9 25.9
  21. #
  22. # 128-bit key setup 196 280 256 240 cycles/key
  23. # + over gcc 3.4.6 +30/0% +17/11% +11/0% +63/40%
  24. # + over icc 8.0 +18/3% +10/0% +10/3% +21/10%
  25. #
  26. # Pairs of numbers in "+" rows represent performance improvement over
  27. # compiler generated position-independent code, PIC, and non-PIC
  28. # respectively. PIC results are of greater relevance, as this module
  29. # is position-independent, i.e. suitable for a shared library or PIE.
  30. # Position independence "costs" one register, which is why compilers
  31. # are so close with non-PIC results, they have an extra register to
  32. # spare. CBC results are better than ECB ones thanks to "zero-copy"
  33. # private _x86_* interface, and are ~30-40% better than with compiler
  34. # generated cmll_cbc.o, and reach ~80-90% of x86_64 performance on
  35. # same CPU (where applicable).
  36. $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
  37. push(@INC,"${dir}","${dir}../../perlasm");
  38. require "x86asm.pl";
  39. $OPENSSL=1;
  40. &asm_init($ARGV[0],"cmll-586.pl",$ARGV[$#ARGV] eq "386");
  41. @T=("eax","ebx","ecx","edx");
  42. $idx="esi";
  43. $key="edi";
  44. $Tbl="ebp";
  45. # stack frame layout in _x86_Camellia_* routines, frame is allocated
  46. # by caller
  47. $__ra=&DWP(0,"esp"); # return address
  48. $__s0=&DWP(4,"esp"); # s0 backing store
  49. $__s1=&DWP(8,"esp"); # s1 backing store
  50. $__s2=&DWP(12,"esp"); # s2 backing store
  51. $__s3=&DWP(16,"esp"); # s3 backing store
  52. $__end=&DWP(20,"esp"); # pointer to end/start of key schedule
  53. # stack frame layout in Camellia_[en|crypt] routines, which differs from
  54. # above by 4 and overlaps by pointer to end/start of key schedule
  55. $_end=&DWP(16,"esp");
  56. $_esp=&DWP(20,"esp");
  57. # const unsigned int Camellia_SBOX[4][256];
  58. # Well, sort of... Camellia_SBOX[0][] is interleaved with [1][],
  59. # and [2][] - with [3][]. This is done to optimize code size.
  60. $SBOX1_1110=0; # Camellia_SBOX[0]
  61. $SBOX4_4404=4; # Camellia_SBOX[1]
  62. $SBOX2_0222=2048; # Camellia_SBOX[2]
  63. $SBOX3_3033=2052; # Camellia_SBOX[3]
  64. &static_label("Camellia_SIGMA");
  65. &static_label("Camellia_SBOX");
  66. sub Camellia_Feistel {
  67. my $i=@_[0];
  68. my $seed=defined(@_[1])?@_[1]:0;
  69. my $scale=$seed<0?-8:8;
  70. my $frame=defined(@_[2])?@_[2]:0;
  71. my $j=($i&1)*2;
  72. my $t0=@T[($j)%4],$t1=@T[($j+1)%4],$t2=@T[($j+2)%4],$t3=@T[($j+3)%4];
  73. &xor ($t0,$idx); # t0^=key[0]
  74. &xor ($t1,&DWP($seed+$i*$scale+4,$key)); # t1^=key[1]
  75. &movz ($idx,&HB($t0)); # (t0>>8)&0xff
  76. &mov ($t3,&DWP($SBOX3_3033,$Tbl,$idx,8)); # t3=SBOX3_3033[0]
  77. &movz ($idx,&LB($t0)); # (t0>>0)&0xff
  78. &xor ($t3,&DWP($SBOX4_4404,$Tbl,$idx,8)); # t3^=SBOX4_4404[0]
  79. &shr ($t0,16);
  80. &movz ($idx,&LB($t1)); # (t1>>0)&0xff
  81. &mov ($t2,&DWP($SBOX1_1110,$Tbl,$idx,8)); # t2=SBOX1_1110[1]
  82. &movz ($idx,&HB($t0)); # (t0>>24)&0xff
  83. &xor ($t3,&DWP($SBOX1_1110,$Tbl,$idx,8)); # t3^=SBOX1_1110[0]
  84. &movz ($idx,&HB($t1)); # (t1>>8)&0xff
  85. &xor ($t2,&DWP($SBOX4_4404,$Tbl,$idx,8)); # t2^=SBOX4_4404[1]
  86. &shr ($t1,16);
  87. &movz ($t0,&LB($t0)); # (t0>>16)&0xff
  88. &xor ($t3,&DWP($SBOX2_0222,$Tbl,$t0,8)); # t3^=SBOX2_0222[0]
  89. &movz ($idx,&HB($t1)); # (t1>>24)&0xff
  90. &mov ($t0,&DWP($frame+4*(($j+3)%4),"esp")); # prefetch "s3"
  91. &xor ($t2,$t3); # t2^=t3
  92. &rotr ($t3,8); # t3=RightRotate(t3,8)
  93. &xor ($t2,&DWP($SBOX2_0222,$Tbl,$idx,8)); # t2^=SBOX2_0222[1]
  94. &movz ($idx,&LB($t1)); # (t1>>16)&0xff
  95. &mov ($t1,&DWP($frame+4*(($j+2)%4),"esp")); # prefetch "s2"
  96. &xor ($t3,$t0); # t3^=s3
  97. &xor ($t2,&DWP($SBOX3_3033,$Tbl,$idx,8)); # t2^=SBOX3_3033[1]
  98. &mov ($idx,&DWP($seed+($i+1)*$scale,$key)); # prefetch key[i+1]
  99. &xor ($t3,$t2); # t3^=t2
  100. &mov (&DWP($frame+4*(($j+3)%4),"esp"),$t3); # s3=t3
  101. &xor ($t2,$t1); # t2^=s2
  102. &mov (&DWP($frame+4*(($j+2)%4),"esp"),$t2); # s2=t2
  103. }
  104. # void Camellia_EncryptBlock_Rounds(
  105. # int grandRounds,
  106. # const Byte plaintext[],
  107. # const KEY_TABLE_TYPE keyTable,
  108. # Byte ciphertext[])
  109. &function_begin("Camellia_EncryptBlock_Rounds");
  110. &mov ("eax",&wparam(0)); # load grandRounds
  111. &mov ($idx,&wparam(1)); # load plaintext pointer
  112. &mov ($key,&wparam(2)); # load key schedule pointer
  113. &mov ("ebx","esp");
  114. &sub ("esp",7*4); # place for s[0-3],keyEnd,esp and ra
  115. &and ("esp",-64);
  116. # place stack frame just "above mod 1024" the key schedule
  117. # this ensures that cache associativity of 2 suffices
  118. &lea ("ecx",&DWP(-64-63,$key));
  119. &sub ("ecx","esp");
  120. &neg ("ecx");
  121. &and ("ecx",0x3C0); # modulo 1024, but aligned to cache-line
  122. &sub ("esp","ecx");
  123. &add ("esp",4); # 4 is reserved for callee's return address
  124. &shl ("eax",6);
  125. &lea ("eax",&DWP(0,$key,"eax"));
  126. &mov ($_esp,"ebx"); # save %esp
  127. &mov ($_end,"eax"); # save keyEnd
  128. &call (&label("pic_point"));
  129. &set_label("pic_point");
  130. &blindpop($Tbl);
  131. &lea ($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
  132. &mov (@T[0],&DWP(0,$idx)); # load plaintext
  133. &mov (@T[1],&DWP(4,$idx));
  134. &mov (@T[2],&DWP(8,$idx));
  135. &bswap (@T[0]);
  136. &mov (@T[3],&DWP(12,$idx));
  137. &bswap (@T[1]);
  138. &bswap (@T[2]);
  139. &bswap (@T[3]);
  140. &call ("_x86_Camellia_encrypt");
  141. &mov ("esp",$_esp);
  142. &bswap (@T[0]);
  143. &mov ($idx,&wparam(3)); # load ciphertext pointer
  144. &bswap (@T[1]);
  145. &bswap (@T[2]);
  146. &bswap (@T[3]);
  147. &mov (&DWP(0,$idx),@T[0]); # write ciphertext
  148. &mov (&DWP(4,$idx),@T[1]);
  149. &mov (&DWP(8,$idx),@T[2]);
  150. &mov (&DWP(12,$idx),@T[3]);
  151. &function_end("Camellia_EncryptBlock_Rounds");
  152. # V1.x API
  153. &function_begin_B("Camellia_EncryptBlock");
  154. &mov ("eax",128);
  155. &sub ("eax",&wparam(0)); # load keyBitLength
  156. &mov ("eax",3);
  157. &adc ("eax",0); # keyBitLength==128?3:4
  158. &mov (&wparam(0),"eax");
  159. &jmp (&label("Camellia_EncryptBlock_Rounds"));
  160. &function_end_B("Camellia_EncryptBlock");
  161. if ($OPENSSL) {
  162. # void Camellia_encrypt(
  163. # const unsigned char *in,
  164. # unsigned char *out,
  165. # const CAMELLIA_KEY *key)
  166. &function_begin("Camellia_encrypt");
  167. &mov ($idx,&wparam(0)); # load plaintext pointer
  168. &mov ($key,&wparam(2)); # load key schedule pointer
  169. &mov ("ebx","esp");
  170. &sub ("esp",7*4); # place for s[0-3],keyEnd,esp and ra
  171. &and ("esp",-64);
  172. &mov ("eax",&DWP(272,$key)); # load grandRounds counter
  173. # place stack frame just "above mod 1024" the key schedule
  174. # this ensures that cache associativity of 2 suffices
  175. &lea ("ecx",&DWP(-64-63,$key));
  176. &sub ("ecx","esp");
  177. &neg ("ecx");
  178. &and ("ecx",0x3C0); # modulo 1024, but aligned to cache-line
  179. &sub ("esp","ecx");
  180. &add ("esp",4); # 4 is reserved for callee's return address
  181. &shl ("eax",6);
  182. &lea ("eax",&DWP(0,$key,"eax"));
  183. &mov ($_esp,"ebx"); # save %esp
  184. &mov ($_end,"eax"); # save keyEnd
  185. &call (&label("pic_point"));
  186. &set_label("pic_point");
  187. &blindpop($Tbl);
  188. &lea ($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
  189. &mov (@T[0],&DWP(0,$idx)); # load plaintext
  190. &mov (@T[1],&DWP(4,$idx));
  191. &mov (@T[2],&DWP(8,$idx));
  192. &bswap (@T[0]);
  193. &mov (@T[3],&DWP(12,$idx));
  194. &bswap (@T[1]);
  195. &bswap (@T[2]);
  196. &bswap (@T[3]);
  197. &call ("_x86_Camellia_encrypt");
  198. &mov ("esp",$_esp);
  199. &bswap (@T[0]);
  200. &mov ($idx,&wparam(1)); # load ciphertext pointer
  201. &bswap (@T[1]);
  202. &bswap (@T[2]);
  203. &bswap (@T[3]);
  204. &mov (&DWP(0,$idx),@T[0]); # write ciphertext
  205. &mov (&DWP(4,$idx),@T[1]);
  206. &mov (&DWP(8,$idx),@T[2]);
  207. &mov (&DWP(12,$idx),@T[3]);
  208. &function_end("Camellia_encrypt");
  209. }
  210. &function_begin_B("_x86_Camellia_encrypt");
  211. &xor (@T[0],&DWP(0,$key)); # ^=key[0-3]
  212. &xor (@T[1],&DWP(4,$key));
  213. &xor (@T[2],&DWP(8,$key));
  214. &xor (@T[3],&DWP(12,$key));
  215. &mov ($idx,&DWP(16,$key)); # prefetch key[4]
  216. &mov ($__s0,@T[0]); # save s[0-3]
  217. &mov ($__s1,@T[1]);
  218. &mov ($__s2,@T[2]);
  219. &mov ($__s3,@T[3]);
  220. &set_label("loop",16);
  221. for ($i=0;$i<6;$i++) { Camellia_Feistel($i,16,4); }
  222. &add ($key,16*4);
  223. &cmp ($key,$__end);
  224. &je (&label("done"));
  225. # @T[0-1] are preloaded, $idx is preloaded with key[0]
  226. &and ($idx,@T[0]);
  227. &mov (@T[3],$__s3);
  228. &rotl ($idx,1);
  229. &mov (@T[2],@T[3]);
  230. &xor (@T[1],$idx);
  231. &or (@T[2],&DWP(12,$key));
  232. &mov ($__s1,@T[1]); # s1^=LeftRotate(s0&key[0],1);
  233. &xor (@T[2],$__s2);
  234. &mov ($idx,&DWP(4,$key));
  235. &mov ($__s2,@T[2]); # s2^=s3|key[3];
  236. &or ($idx,@T[1]);
  237. &and (@T[2],&DWP(8,$key));
  238. &xor (@T[0],$idx);
  239. &rotl (@T[2],1);
  240. &mov ($__s0,@T[0]); # s0^=s1|key[1];
  241. &xor (@T[3],@T[2]);
  242. &mov ($idx,&DWP(16,$key)); # prefetch key[4]
  243. &mov ($__s3,@T[3]); # s3^=LeftRotate(s2&key[2],1);
  244. &jmp (&label("loop"));
  245. &set_label("done",8);
  246. &mov (@T[2],@T[0]); # SwapHalf
  247. &mov (@T[3],@T[1]);
  248. &mov (@T[0],$__s2);
  249. &mov (@T[1],$__s3);
  250. &xor (@T[0],$idx); # $idx is preloaded with key[0]
  251. &xor (@T[1],&DWP(4,$key));
  252. &xor (@T[2],&DWP(8,$key));
  253. &xor (@T[3],&DWP(12,$key));
  254. &ret ();
  255. &function_end_B("_x86_Camellia_encrypt");
  256. # void Camellia_DecryptBlock_Rounds(
  257. # int grandRounds,
  258. # const Byte ciphertext[],
  259. # const KEY_TABLE_TYPE keyTable,
  260. # Byte plaintext[])
  261. &function_begin("Camellia_DecryptBlock_Rounds");
  262. &mov ("eax",&wparam(0)); # load grandRounds
  263. &mov ($idx,&wparam(1)); # load ciphertext pointer
  264. &mov ($key,&wparam(2)); # load key schedule pointer
  265. &mov ("ebx","esp");
  266. &sub ("esp",7*4); # place for s[0-3],keyEnd,esp and ra
  267. &and ("esp",-64);
  268. # place stack frame just "above mod 1024" the key schedule
  269. # this ensures that cache associativity of 2 suffices
  270. &lea ("ecx",&DWP(-64-63,$key));
  271. &sub ("ecx","esp");
  272. &neg ("ecx");
  273. &and ("ecx",0x3C0); # modulo 1024, but aligned to cache-line
  274. &sub ("esp","ecx");
  275. &add ("esp",4); # 4 is reserved for callee's return address
  276. &shl ("eax",6);
  277. &mov (&DWP(4*4,"esp"),$key); # save keyStart
  278. &lea ($key,&DWP(0,$key,"eax"));
  279. &mov (&DWP(5*4,"esp"),"ebx");# save %esp
  280. &call (&label("pic_point"));
  281. &set_label("pic_point");
  282. &blindpop($Tbl);
  283. &lea ($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
  284. &mov (@T[0],&DWP(0,$idx)); # load ciphertext
  285. &mov (@T[1],&DWP(4,$idx));
  286. &mov (@T[2],&DWP(8,$idx));
  287. &bswap (@T[0]);
  288. &mov (@T[3],&DWP(12,$idx));
  289. &bswap (@T[1]);
  290. &bswap (@T[2]);
  291. &bswap (@T[3]);
  292. &call ("_x86_Camellia_decrypt");
  293. &mov ("esp",&DWP(5*4,"esp"));
  294. &bswap (@T[0]);
  295. &mov ($idx,&wparam(3)); # load plaintext pointer
  296. &bswap (@T[1]);
  297. &bswap (@T[2]);
  298. &bswap (@T[3]);
  299. &mov (&DWP(0,$idx),@T[0]); # write plaintext
  300. &mov (&DWP(4,$idx),@T[1]);
  301. &mov (&DWP(8,$idx),@T[2]);
  302. &mov (&DWP(12,$idx),@T[3]);
  303. &function_end("Camellia_DecryptBlock_Rounds");
  304. # V1.x API
  305. &function_begin_B("Camellia_DecryptBlock");
  306. &mov ("eax",128);
  307. &sub ("eax",&wparam(0)); # load keyBitLength
  308. &mov ("eax",3);
  309. &adc ("eax",0); # keyBitLength==128?3:4
  310. &mov (&wparam(0),"eax");
  311. &jmp (&label("Camellia_DecryptBlock_Rounds"));
  312. &function_end_B("Camellia_DecryptBlock");
  313. if ($OPENSSL) {
  314. # void Camellia_decrypt(
  315. # const unsigned char *in,
  316. # unsigned char *out,
  317. # const CAMELLIA_KEY *key)
  318. &function_begin("Camellia_decrypt");
  319. &mov ($idx,&wparam(0)); # load ciphertext pointer
  320. &mov ($key,&wparam(2)); # load key schedule pointer
  321. &mov ("ebx","esp");
  322. &sub ("esp",7*4); # place for s[0-3],keyEnd,esp and ra
  323. &and ("esp",-64);
  324. &mov ("eax",&DWP(272,$key)); # load grandRounds counter
  325. # place stack frame just "above mod 1024" the key schedule
  326. # this ensures that cache associativity of 2 suffices
  327. &lea ("ecx",&DWP(-64-63,$key));
  328. &sub ("ecx","esp");
  329. &neg ("ecx");
  330. &and ("ecx",0x3C0); # modulo 1024, but aligned to cache-line
  331. &sub ("esp","ecx");
  332. &add ("esp",4); # 4 is reserved for callee's return address
  333. &shl ("eax",6);
  334. &mov (&DWP(4*4,"esp"),$key); # save keyStart
  335. &lea ($key,&DWP(0,$key,"eax"));
  336. &mov (&DWP(5*4,"esp"),"ebx");# save %esp
  337. &call (&label("pic_point"));
  338. &set_label("pic_point");
  339. &blindpop($Tbl);
  340. &lea ($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
  341. &mov (@T[0],&DWP(0,$idx)); # load ciphertext
  342. &mov (@T[1],&DWP(4,$idx));
  343. &mov (@T[2],&DWP(8,$idx));
  344. &bswap (@T[0]);
  345. &mov (@T[3],&DWP(12,$idx));
  346. &bswap (@T[1]);
  347. &bswap (@T[2]);
  348. &bswap (@T[3]);
  349. &call ("_x86_Camellia_decrypt");
  350. &mov ("esp",&DWP(5*4,"esp"));
  351. &bswap (@T[0]);
  352. &mov ($idx,&wparam(1)); # load plaintext pointer
  353. &bswap (@T[1]);
  354. &bswap (@T[2]);
  355. &bswap (@T[3]);
  356. &mov (&DWP(0,$idx),@T[0]); # write plaintext
  357. &mov (&DWP(4,$idx),@T[1]);
  358. &mov (&DWP(8,$idx),@T[2]);
  359. &mov (&DWP(12,$idx),@T[3]);
  360. &function_end("Camellia_decrypt");
  361. }
  362. &function_begin_B("_x86_Camellia_decrypt");
  363. &xor (@T[0],&DWP(0,$key)); # ^=key[0-3]
  364. &xor (@T[1],&DWP(4,$key));
  365. &xor (@T[2],&DWP(8,$key));
  366. &xor (@T[3],&DWP(12,$key));
  367. &mov ($idx,&DWP(-8,$key)); # prefetch key[-2]
  368. &mov ($__s0,@T[0]); # save s[0-3]
  369. &mov ($__s1,@T[1]);
  370. &mov ($__s2,@T[2]);
  371. &mov ($__s3,@T[3]);
  372. &set_label("loop",16);
  373. for ($i=0;$i<6;$i++) { Camellia_Feistel($i,-8,4); }
  374. &sub ($key,16*4);
  375. &cmp ($key,$__end);
  376. &je (&label("done"));
  377. # @T[0-1] are preloaded, $idx is preloaded with key[2]
  378. &and ($idx,@T[0]);
  379. &mov (@T[3],$__s3);
  380. &rotl ($idx,1);
  381. &mov (@T[2],@T[3]);
  382. &xor (@T[1],$idx);
  383. &or (@T[2],&DWP(4,$key));
  384. &mov ($__s1,@T[1]); # s1^=LeftRotate(s0&key[0],1);
  385. &xor (@T[2],$__s2);
  386. &mov ($idx,&DWP(12,$key));
  387. &mov ($__s2,@T[2]); # s2^=s3|key[3];
  388. &or ($idx,@T[1]);
  389. &and (@T[2],&DWP(0,$key));
  390. &xor (@T[0],$idx);
  391. &rotl (@T[2],1);
  392. &mov ($__s0,@T[0]); # s0^=s1|key[1];
  393. &xor (@T[3],@T[2]);
  394. &mov ($idx,&DWP(-8,$key)); # prefetch key[4]
  395. &mov ($__s3,@T[3]); # s3^=LeftRotate(s2&key[2],1);
  396. &jmp (&label("loop"));
  397. &set_label("done",8);
  398. &mov (@T[2],@T[0]); # SwapHalf
  399. &mov (@T[3],@T[1]);
  400. &mov (@T[0],$__s2);
  401. &mov (@T[1],$__s3);
  402. &xor (@T[2],$idx); # $idx is preloaded with key[2]
  403. &xor (@T[3],&DWP(12,$key));
  404. &xor (@T[0],&DWP(0,$key));
  405. &xor (@T[1],&DWP(4,$key));
  406. &ret ();
  407. &function_end_B("_x86_Camellia_decrypt");
  408. # shld is very slow on Intel P4 family. Even on AMD it limits
  409. # instruction decode rate [because it's VectorPath] and consequently
  410. # performance. PIII, PM and Core[2] seem to be the only ones which
  411. # execute this code ~7% faster...
  412. sub __rotl128 {
  413. my ($i0,$i1,$i2,$i3,$rot,$rnd,@T)=@_;
  414. $rnd *= 2;
  415. if ($rot) {
  416. &mov ($idx,$i0);
  417. &shld ($i0,$i1,$rot);
  418. &shld ($i1,$i2,$rot);
  419. &shld ($i2,$i3,$rot);
  420. &shld ($i3,$idx,$rot);
  421. }
  422. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i0 eq @T[0]);
  423. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i1 eq @T[0]);
  424. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i2 eq @T[0]);
  425. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i3 eq @T[0]);
  426. }
  427. # ... Implementing 128-bit rotate without shld gives >3x performance
  428. # improvement on P4, only ~7% degradation on other Intel CPUs and
  429. # not worse performance on AMD. This is therefore preferred.
  430. sub _rotl128 {
  431. my ($i0,$i1,$i2,$i3,$rot,$rnd,@T)=@_;
  432. $rnd *= 2;
  433. if ($rot) {
  434. &mov ($Tbl,$i0);
  435. &shl ($i0,$rot);
  436. &mov ($idx,$i1);
  437. &shr ($idx,32-$rot);
  438. &shl ($i1,$rot);
  439. &or ($i0,$idx);
  440. &mov ($idx,$i2);
  441. &shl ($i2,$rot);
  442. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i0 eq @T[0]);
  443. &shr ($idx,32-$rot);
  444. &or ($i1,$idx);
  445. &shr ($Tbl,32-$rot);
  446. &mov ($idx,$i3);
  447. &shr ($idx,32-$rot);
  448. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i1 eq @T[0]);
  449. &shl ($i3,$rot);
  450. &or ($i2,$idx);
  451. &or ($i3,$Tbl);
  452. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i2 eq @T[0]);
  453. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i3 eq @T[0]);
  454. } else {
  455. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i0 eq @T[0]);
  456. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i1 eq @T[0]);
  457. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i2 eq @T[0]);
  458. &mov (&DWP(-128+4*$rnd++,$key),shift(@T)) if ($i3 eq @T[0]);
  459. }
  460. }
  461. sub _saveround {
  462. my ($rnd,$key,@T)=@_;
  463. my $bias=int(@T[0])?shift(@T):0;
  464. &mov (&DWP($bias+$rnd*8+0,$key),@T[0]);
  465. &mov (&DWP($bias+$rnd*8+4,$key),@T[1]) if ($#T>=1);
  466. &mov (&DWP($bias+$rnd*8+8,$key),@T[2]) if ($#T>=2);
  467. &mov (&DWP($bias+$rnd*8+12,$key),@T[3]) if ($#T>=3);
  468. }
  469. sub _loadround {
  470. my ($rnd,$key,@T)=@_;
  471. my $bias=int(@T[0])?shift(@T):0;
  472. &mov (@T[0],&DWP($bias+$rnd*8+0,$key));
  473. &mov (@T[1],&DWP($bias+$rnd*8+4,$key)) if ($#T>=1);
  474. &mov (@T[2],&DWP($bias+$rnd*8+8,$key)) if ($#T>=2);
  475. &mov (@T[3],&DWP($bias+$rnd*8+12,$key)) if ($#T>=3);
  476. }
  477. # void Camellia_Ekeygen(
  478. # const int keyBitLength,
  479. # const Byte *rawKey,
  480. # KEY_TABLE_TYPE keyTable)
  481. &function_begin("Camellia_Ekeygen");
  482. { my $step=0;
  483. &stack_push(4); # place for s[0-3]
  484. &mov ($Tbl,&wparam(0)); # load arguments
  485. &mov ($idx,&wparam(1));
  486. &mov ($key,&wparam(2));
  487. &mov (@T[0],&DWP(0,$idx)); # load 0-127 bits
  488. &mov (@T[1],&DWP(4,$idx));
  489. &mov (@T[2],&DWP(8,$idx));
  490. &mov (@T[3],&DWP(12,$idx));
  491. &bswap (@T[0]);
  492. &bswap (@T[1]);
  493. &bswap (@T[2]);
  494. &bswap (@T[3]);
  495. &_saveround (0,$key,@T); # KL<<<0
  496. &cmp ($Tbl,128);
  497. &je (&label("1st128"));
  498. &mov (@T[0],&DWP(16,$idx)); # load 128-191 bits
  499. &mov (@T[1],&DWP(20,$idx));
  500. &cmp ($Tbl,192);
  501. &je (&label("1st192"));
  502. &mov (@T[2],&DWP(24,$idx)); # load 192-255 bits
  503. &mov (@T[3],&DWP(28,$idx));
  504. &jmp (&label("1st256"));
  505. &set_label("1st192",4);
  506. &mov (@T[2],@T[0]);
  507. &mov (@T[3],@T[1]);
  508. &not (@T[2]);
  509. &not (@T[3]);
  510. &set_label("1st256",4);
  511. &bswap (@T[0]);
  512. &bswap (@T[1]);
  513. &bswap (@T[2]);
  514. &bswap (@T[3]);
  515. &_saveround (4,$key,@T); # temporary storage for KR!
  516. &xor (@T[0],&DWP(0*8+0,$key)); # KR^KL
  517. &xor (@T[1],&DWP(0*8+4,$key));
  518. &xor (@T[2],&DWP(1*8+0,$key));
  519. &xor (@T[3],&DWP(1*8+4,$key));
  520. &set_label("1st128",4);
  521. &call (&label("pic_point"));
  522. &set_label("pic_point");
  523. &blindpop($Tbl);
  524. &lea ($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
  525. &lea ($key,&DWP(&label("Camellia_SIGMA")."-".&label("Camellia_SBOX"),$Tbl));
  526. &mov ($idx,&DWP($step*8,$key)); # prefetch SIGMA[0]
  527. &mov (&swtmp(0),@T[0]); # save s[0-3]
  528. &mov (&swtmp(1),@T[1]);
  529. &mov (&swtmp(2),@T[2]);
  530. &mov (&swtmp(3),@T[3]);
  531. &Camellia_Feistel($step++);
  532. &Camellia_Feistel($step++);
  533. &mov (@T[2],&swtmp(2));
  534. &mov (@T[3],&swtmp(3));
  535. &mov ($idx,&wparam(2));
  536. &xor (@T[0],&DWP(0*8+0,$idx)); # ^KL
  537. &xor (@T[1],&DWP(0*8+4,$idx));
  538. &xor (@T[2],&DWP(1*8+0,$idx));
  539. &xor (@T[3],&DWP(1*8+4,$idx));
  540. &mov ($idx,&DWP($step*8,$key)); # prefetch SIGMA[4]
  541. &mov (&swtmp(0),@T[0]); # save s[0-3]
  542. &mov (&swtmp(1),@T[1]);
  543. &mov (&swtmp(2),@T[2]);
  544. &mov (&swtmp(3),@T[3]);
  545. &Camellia_Feistel($step++);
  546. &Camellia_Feistel($step++);
  547. &mov (@T[2],&swtmp(2));
  548. &mov (@T[3],&swtmp(3));
  549. &mov ($idx,&wparam(0));
  550. &cmp ($idx,128);
  551. &jne (&label("2nd256"));
  552. &mov ($key,&wparam(2));
  553. &lea ($key,&DWP(128,$key)); # size optimization
  554. ####### process KA
  555. &_saveround (2,$key,-128,@T); # KA<<<0
  556. &_rotl128 (@T,15,6,@T); # KA<<<15
  557. &_rotl128 (@T,15,8,@T); # KA<<<(15+15=30)
  558. &_rotl128 (@T,15,12,@T[0],@T[1]); # KA<<<(30+15=45)
  559. &_rotl128 (@T,15,14,@T); # KA<<<(45+15=60)
  560. push (@T,shift(@T)); # rotl128(@T,32);
  561. &_rotl128 (@T,2,20,@T); # KA<<<(60+32+2=94)
  562. &_rotl128 (@T,17,24,@T); # KA<<<(94+17=111)
  563. ####### process KL
  564. &_loadround (0,$key,-128,@T); # load KL
  565. &_rotl128 (@T,15,4,@T); # KL<<<15
  566. &_rotl128 (@T,30,10,@T); # KL<<<(15+30=45)
  567. &_rotl128 (@T,15,13,@T[2],@T[3]); # KL<<<(45+15=60)
  568. &_rotl128 (@T,17,16,@T); # KL<<<(60+17=77)
  569. &_rotl128 (@T,17,18,@T); # KL<<<(77+17=94)
  570. &_rotl128 (@T,17,22,@T); # KL<<<(94+17=111)
  571. while (@T[0] ne "eax") # restore order
  572. { unshift (@T,pop(@T)); }
  573. &mov ("eax",3); # 3 grandRounds
  574. &jmp (&label("done"));
  575. &set_label("2nd256",16);
  576. &mov ($idx,&wparam(2));
  577. &_saveround (6,$idx,@T); # temporary storage for KA!
  578. &xor (@T[0],&DWP(4*8+0,$idx)); # KA^KR
  579. &xor (@T[1],&DWP(4*8+4,$idx));
  580. &xor (@T[2],&DWP(5*8+0,$idx));
  581. &xor (@T[3],&DWP(5*8+4,$idx));
  582. &mov ($idx,&DWP($step*8,$key)); # prefetch SIGMA[8]
  583. &mov (&swtmp(0),@T[0]); # save s[0-3]
  584. &mov (&swtmp(1),@T[1]);
  585. &mov (&swtmp(2),@T[2]);
  586. &mov (&swtmp(3),@T[3]);
  587. &Camellia_Feistel($step++);
  588. &Camellia_Feistel($step++);
  589. &mov (@T[2],&swtmp(2));
  590. &mov (@T[3],&swtmp(3));
  591. &mov ($key,&wparam(2));
  592. &lea ($key,&DWP(128,$key)); # size optimization
  593. ####### process KB
  594. &_saveround (2,$key,-128,@T); # KB<<<0
  595. &_rotl128 (@T,30,10,@T); # KB<<<30
  596. &_rotl128 (@T,30,20,@T); # KB<<<(30+30=60)
  597. push (@T,shift(@T)); # rotl128(@T,32);
  598. &_rotl128 (@T,19,32,@T); # KB<<<(60+32+19=111)
  599. ####### process KR
  600. &_loadround (4,$key,-128,@T); # load KR
  601. &_rotl128 (@T,15,4,@T); # KR<<<15
  602. &_rotl128 (@T,15,8,@T); # KR<<<(15+15=30)
  603. &_rotl128 (@T,30,18,@T); # KR<<<(30+30=60)
  604. push (@T,shift(@T)); # rotl128(@T,32);
  605. &_rotl128 (@T,2,26,@T); # KR<<<(60+32+2=94)
  606. ####### process KA
  607. &_loadround (6,$key,-128,@T); # load KA
  608. &_rotl128 (@T,15,6,@T); # KA<<<15
  609. &_rotl128 (@T,30,14,@T); # KA<<<(15+30=45)
  610. push (@T,shift(@T)); # rotl128(@T,32);
  611. &_rotl128 (@T,0,24,@T); # KA<<<(45+32+0=77)
  612. &_rotl128 (@T,17,28,@T); # KA<<<(77+17=94)
  613. ####### process KL
  614. &_loadround (0,$key,-128,@T); # load KL
  615. push (@T,shift(@T)); # rotl128(@T,32);
  616. &_rotl128 (@T,13,12,@T); # KL<<<(32+13=45)
  617. &_rotl128 (@T,15,16,@T); # KL<<<(45+15=60)
  618. &_rotl128 (@T,17,22,@T); # KL<<<(60+17=77)
  619. push (@T,shift(@T)); # rotl128(@T,32);
  620. &_rotl128 (@T,2,30,@T); # KL<<<(77+32+2=111)
  621. while (@T[0] ne "eax") # restore order
  622. { unshift (@T,pop(@T)); }
  623. &mov ("eax",4); # 4 grandRounds
  624. &set_label("done");
  625. &lea ("edx",&DWP(272-128,$key)); # end of key schedule
  626. &stack_pop(4);
  627. }
  628. &function_end("Camellia_Ekeygen");
  629. if ($OPENSSL) {
  630. # int Camellia_set_key (
  631. # const unsigned char *userKey,
  632. # int bits,
  633. # CAMELLIA_KEY *key)
  634. &function_begin_B("Camellia_set_key");
  635. &push ("ebx");
  636. &mov ("ecx",&wparam(0)); # pull arguments
  637. &mov ("ebx",&wparam(1));
  638. &mov ("edx",&wparam(2));
  639. &mov ("eax",-1);
  640. &test ("ecx","ecx");
  641. &jz (&label("done")); # userKey==NULL?
  642. &test ("edx","edx");
  643. &jz (&label("done")); # key==NULL?
  644. &mov ("eax",-2);
  645. &cmp ("ebx",256);
  646. &je (&label("arg_ok")); # bits==256?
  647. &cmp ("ebx",192);
  648. &je (&label("arg_ok")); # bits==192?
  649. &cmp ("ebx",128);
  650. &jne (&label("done")); # bits!=128?
  651. &set_label("arg_ok",4);
  652. &push ("edx"); # push arguments
  653. &push ("ecx");
  654. &push ("ebx");
  655. &call ("Camellia_Ekeygen");
  656. &stack_pop(3);
  657. # eax holds grandRounds and edx points at where to put it
  658. &mov (&DWP(0,"edx"),"eax");
  659. &xor ("eax","eax");
  660. &set_label("done",4);
  661. &pop ("ebx");
  662. &ret ();
  663. &function_end_B("Camellia_set_key");
  664. }
  665. @SBOX=(
  666. 112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65,
  667. 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189,
  668. 134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26,
  669. 166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77,
  670. 139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153,
  671. 223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215,
  672. 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34,
  673. 254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80,
  674. 170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210,
  675. 16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148,
  676. 135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226,
  677. 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46,
  678. 233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89,
  679. 120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250,
  680. 114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164,
  681. 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158);
  682. sub S1110 { my $i=shift; $i=@SBOX[$i]; return $i<<24|$i<<16|$i<<8; }
  683. sub S4404 { my $i=shift; $i=($i<<1|$i>>7)&0xff; $i=@SBOX[$i]; return $i<<24|$i<<16|$i; }
  684. sub S0222 { my $i=shift; $i=@SBOX[$i]; $i=($i<<1|$i>>7)&0xff; return $i<<16|$i<<8|$i; }
  685. sub S3033 { my $i=shift; $i=@SBOX[$i]; $i=($i>>1|$i<<7)&0xff; return $i<<24|$i<<8|$i; }
  686. &set_label("Camellia_SIGMA",64);
  687. &data_word(
  688. 0xa09e667f, 0x3bcc908b, 0xb67ae858, 0x4caa73b2,
  689. 0xc6ef372f, 0xe94f82be, 0x54ff53a5, 0xf1d36f1c,
  690. 0x10e527fa, 0xde682d1d, 0xb05688c2, 0xb3e6c1fd,
  691. 0, 0, 0, 0);
  692. &set_label("Camellia_SBOX",64);
  693. # tables are interleaved, remember?
  694. for ($i=0;$i<256;$i++) { &data_word(&S1110($i),&S4404($i)); }
  695. for ($i=0;$i<256;$i++) { &data_word(&S0222($i),&S3033($i)); }
  696. # void Camellia_cbc_encrypt (const void char *inp, unsigned char *out,
  697. # size_t length, const CAMELLIA_KEY *key,
  698. # unsigned char *ivp,const int enc);
  699. {
  700. # stack frame layout
  701. # -4(%esp) # return address 0(%esp)
  702. # 0(%esp) # s0 4(%esp)
  703. # 4(%esp) # s1 8(%esp)
  704. # 8(%esp) # s2 12(%esp)
  705. # 12(%esp) # s3 16(%esp)
  706. # 16(%esp) # end of key schedule 20(%esp)
  707. # 20(%esp) # %esp backup
  708. my $_inp=&DWP(24,"esp"); #copy of wparam(0)
  709. my $_out=&DWP(28,"esp"); #copy of wparam(1)
  710. my $_len=&DWP(32,"esp"); #copy of wparam(2)
  711. my $_key=&DWP(36,"esp"); #copy of wparam(3)
  712. my $_ivp=&DWP(40,"esp"); #copy of wparam(4)
  713. my $ivec=&DWP(44,"esp"); #ivec[16]
  714. my $_tmp=&DWP(44,"esp"); #volatile variable [yes, aliases with ivec]
  715. my ($s0,$s1,$s2,$s3) = @T;
  716. &function_begin("Camellia_cbc_encrypt");
  717. &mov ($s2 eq "ecx"? $s2 : "",&wparam(2)); # load len
  718. &cmp ($s2,0);
  719. &je (&label("enc_out"));
  720. &pushf ();
  721. &cld ();
  722. &mov ($s0,&wparam(0)); # load inp
  723. &mov ($s1,&wparam(1)); # load out
  724. #&mov ($s2,&wparam(2)); # load len
  725. &mov ($s3,&wparam(3)); # load key
  726. &mov ($Tbl,&wparam(4)); # load ivp
  727. # allocate aligned stack frame...
  728. &lea ($idx,&DWP(-64,"esp"));
  729. &and ($idx,-64);
  730. # place stack frame just "above mod 1024" the key schedule
  731. # this ensures that cache associativity of 2 suffices
  732. &lea ($key,&DWP(-64-63,$s3));
  733. &sub ($key,$idx);
  734. &neg ($key);
  735. &and ($key,0x3C0); # modulo 1024, but aligned to cache-line
  736. &sub ($idx,$key);
  737. &mov ($key,&wparam(5)); # load enc
  738. &exch ("esp",$idx);
  739. &add ("esp",4); # reserve for return address!
  740. &mov ($_esp,$idx); # save %esp
  741. &mov ($_inp,$s0); # save copy of inp
  742. &mov ($_out,$s1); # save copy of out
  743. &mov ($_len,$s2); # save copy of len
  744. &mov ($_key,$s3); # save copy of key
  745. &mov ($_ivp,$Tbl); # save copy of ivp
  746. &call (&label("pic_point")); # make it PIC!
  747. &set_label("pic_point");
  748. &blindpop($Tbl);
  749. &lea ($Tbl,&DWP(&label("Camellia_SBOX")."-".&label("pic_point"),$Tbl));
  750. &mov ($idx,32);
  751. &set_label("prefetch_sbox",4);
  752. &mov ($s0,&DWP(0,$Tbl));
  753. &mov ($s1,&DWP(32,$Tbl));
  754. &mov ($s2,&DWP(64,$Tbl));
  755. &mov ($s3,&DWP(96,$Tbl));
  756. &lea ($Tbl,&DWP(128,$Tbl));
  757. &dec ($idx);
  758. &jnz (&label("prefetch_sbox"));
  759. &mov ($s0,$_key);
  760. &sub ($Tbl,4096);
  761. &mov ($idx,$_inp);
  762. &mov ($s3,&DWP(272,$s0)); # load grandRounds
  763. &cmp ($key,0);
  764. &je (&label("DECRYPT"));
  765. &mov ($s2,$_len);
  766. &mov ($key,$_ivp);
  767. &shl ($s3,6);
  768. &lea ($s3,&DWP(0,$s0,$s3));
  769. &mov ($_end,$s3);
  770. &test ($s2,0xFFFFFFF0);
  771. &jz (&label("enc_tail")); # short input...
  772. &mov ($s0,&DWP(0,$key)); # load iv
  773. &mov ($s1,&DWP(4,$key));
  774. &set_label("enc_loop",4);
  775. &mov ($s2,&DWP(8,$key));
  776. &mov ($s3,&DWP(12,$key));
  777. &xor ($s0,&DWP(0,$idx)); # xor input data
  778. &xor ($s1,&DWP(4,$idx));
  779. &xor ($s2,&DWP(8,$idx));
  780. &bswap ($s0);
  781. &xor ($s3,&DWP(12,$idx));
  782. &bswap ($s1);
  783. &mov ($key,$_key); # load key
  784. &bswap ($s2);
  785. &bswap ($s3);
  786. &call ("_x86_Camellia_encrypt");
  787. &mov ($idx,$_inp); # load inp
  788. &mov ($key,$_out); # load out
  789. &bswap ($s0);
  790. &bswap ($s1);
  791. &bswap ($s2);
  792. &mov (&DWP(0,$key),$s0); # save output data
  793. &bswap ($s3);
  794. &mov (&DWP(4,$key),$s1);
  795. &mov (&DWP(8,$key),$s2);
  796. &mov (&DWP(12,$key),$s3);
  797. &mov ($s2,$_len); # load len
  798. &lea ($idx,&DWP(16,$idx));
  799. &mov ($_inp,$idx); # save inp
  800. &lea ($s3,&DWP(16,$key));
  801. &mov ($_out,$s3); # save out
  802. &sub ($s2,16);
  803. &test ($s2,0xFFFFFFF0);
  804. &mov ($_len,$s2); # save len
  805. &jnz (&label("enc_loop"));
  806. &test ($s2,15);
  807. &jnz (&label("enc_tail"));
  808. &mov ($idx,$_ivp); # load ivp
  809. &mov ($s2,&DWP(8,$key)); # restore last dwords
  810. &mov ($s3,&DWP(12,$key));
  811. &mov (&DWP(0,$idx),$s0); # save ivec
  812. &mov (&DWP(4,$idx),$s1);
  813. &mov (&DWP(8,$idx),$s2);
  814. &mov (&DWP(12,$idx),$s3);
  815. &mov ("esp",$_esp);
  816. &popf ();
  817. &set_label("enc_out");
  818. &function_end_A();
  819. &pushf (); # kludge, never executed
  820. &set_label("enc_tail",4);
  821. &mov ($s0,$key eq "edi" ? $key : "");
  822. &mov ($key,$_out); # load out
  823. &push ($s0); # push ivp
  824. &mov ($s1,16);
  825. &sub ($s1,$s2);
  826. &cmp ($key,$idx); # compare with inp
  827. &je (&label("enc_in_place"));
  828. &align (4);
  829. &data_word(0xA4F3F689); # rep movsb # copy input
  830. &jmp (&label("enc_skip_in_place"));
  831. &set_label("enc_in_place");
  832. &lea ($key,&DWP(0,$key,$s2));
  833. &set_label("enc_skip_in_place");
  834. &mov ($s2,$s1);
  835. &xor ($s0,$s0);
  836. &align (4);
  837. &data_word(0xAAF3F689); # rep stosb # zero tail
  838. &pop ($key); # pop ivp
  839. &mov ($idx,$_out); # output as input
  840. &mov ($s0,&DWP(0,$key));
  841. &mov ($s1,&DWP(4,$key));
  842. &mov ($_len,16); # len=16
  843. &jmp (&label("enc_loop")); # one more spin...
  844. #----------------------------- DECRYPT -----------------------------#
  845. &set_label("DECRYPT",16);
  846. &shl ($s3,6);
  847. &lea ($s3,&DWP(0,$s0,$s3));
  848. &mov ($_end,$s0);
  849. &mov ($_key,$s3);
  850. &cmp ($idx,$_out);
  851. &je (&label("dec_in_place")); # in-place processing...
  852. &mov ($key,$_ivp); # load ivp
  853. &mov ($_tmp,$key);
  854. &set_label("dec_loop",4);
  855. &mov ($s0,&DWP(0,$idx)); # read input
  856. &mov ($s1,&DWP(4,$idx));
  857. &mov ($s2,&DWP(8,$idx));
  858. &bswap ($s0);
  859. &mov ($s3,&DWP(12,$idx));
  860. &bswap ($s1);
  861. &mov ($key,$_key); # load key
  862. &bswap ($s2);
  863. &bswap ($s3);
  864. &call ("_x86_Camellia_decrypt");
  865. &mov ($key,$_tmp); # load ivp
  866. &mov ($idx,$_len); # load len
  867. &bswap ($s0);
  868. &bswap ($s1);
  869. &bswap ($s2);
  870. &xor ($s0,&DWP(0,$key)); # xor iv
  871. &bswap ($s3);
  872. &xor ($s1,&DWP(4,$key));
  873. &xor ($s2,&DWP(8,$key));
  874. &xor ($s3,&DWP(12,$key));
  875. &sub ($idx,16);
  876. &jc (&label("dec_partial"));
  877. &mov ($_len,$idx); # save len
  878. &mov ($idx,$_inp); # load inp
  879. &mov ($key,$_out); # load out
  880. &mov (&DWP(0,$key),$s0); # write output
  881. &mov (&DWP(4,$key),$s1);
  882. &mov (&DWP(8,$key),$s2);
  883. &mov (&DWP(12,$key),$s3);
  884. &mov ($_tmp,$idx); # save ivp
  885. &lea ($idx,&DWP(16,$idx));
  886. &mov ($_inp,$idx); # save inp
  887. &lea ($key,&DWP(16,$key));
  888. &mov ($_out,$key); # save out
  889. &jnz (&label("dec_loop"));
  890. &mov ($key,$_tmp); # load temp ivp
  891. &set_label("dec_end");
  892. &mov ($idx,$_ivp); # load user ivp
  893. &mov ($s0,&DWP(0,$key)); # load iv
  894. &mov ($s1,&DWP(4,$key));
  895. &mov ($s2,&DWP(8,$key));
  896. &mov ($s3,&DWP(12,$key));
  897. &mov (&DWP(0,$idx),$s0); # copy back to user
  898. &mov (&DWP(4,$idx),$s1);
  899. &mov (&DWP(8,$idx),$s2);
  900. &mov (&DWP(12,$idx),$s3);
  901. &jmp (&label("dec_out"));
  902. &set_label("dec_partial",4);
  903. &lea ($key,$ivec);
  904. &mov (&DWP(0,$key),$s0); # dump output to stack
  905. &mov (&DWP(4,$key),$s1);
  906. &mov (&DWP(8,$key),$s2);
  907. &mov (&DWP(12,$key),$s3);
  908. &lea ($s2 eq "ecx" ? $s2 : "",&DWP(16,$idx));
  909. &mov ($idx eq "esi" ? $idx : "",$key);
  910. &mov ($key eq "edi" ? $key : "",$_out); # load out
  911. &data_word(0xA4F3F689); # rep movsb # copy output
  912. &mov ($key,$_inp); # use inp as temp ivp
  913. &jmp (&label("dec_end"));
  914. &set_label("dec_in_place",4);
  915. &set_label("dec_in_place_loop");
  916. &lea ($key,$ivec);
  917. &mov ($s0,&DWP(0,$idx)); # read input
  918. &mov ($s1,&DWP(4,$idx));
  919. &mov ($s2,&DWP(8,$idx));
  920. &mov ($s3,&DWP(12,$idx));
  921. &mov (&DWP(0,$key),$s0); # copy to temp
  922. &mov (&DWP(4,$key),$s1);
  923. &mov (&DWP(8,$key),$s2);
  924. &bswap ($s0);
  925. &mov (&DWP(12,$key),$s3);
  926. &bswap ($s1);
  927. &mov ($key,$_key); # load key
  928. &bswap ($s2);
  929. &bswap ($s3);
  930. &call ("_x86_Camellia_decrypt");
  931. &mov ($key,$_ivp); # load ivp
  932. &mov ($idx,$_out); # load out
  933. &bswap ($s0);
  934. &bswap ($s1);
  935. &bswap ($s2);
  936. &xor ($s0,&DWP(0,$key)); # xor iv
  937. &bswap ($s3);
  938. &xor ($s1,&DWP(4,$key));
  939. &xor ($s2,&DWP(8,$key));
  940. &xor ($s3,&DWP(12,$key));
  941. &mov (&DWP(0,$idx),$s0); # write output
  942. &mov (&DWP(4,$idx),$s1);
  943. &mov (&DWP(8,$idx),$s2);
  944. &mov (&DWP(12,$idx),$s3);
  945. &lea ($idx,&DWP(16,$idx));
  946. &mov ($_out,$idx); # save out
  947. &lea ($idx,$ivec);
  948. &mov ($s0,&DWP(0,$idx)); # read temp
  949. &mov ($s1,&DWP(4,$idx));
  950. &mov ($s2,&DWP(8,$idx));
  951. &mov ($s3,&DWP(12,$idx));
  952. &mov (&DWP(0,$key),$s0); # copy iv
  953. &mov (&DWP(4,$key),$s1);
  954. &mov (&DWP(8,$key),$s2);
  955. &mov (&DWP(12,$key),$s3);
  956. &mov ($idx,$_inp); # load inp
  957. &lea ($idx,&DWP(16,$idx));
  958. &mov ($_inp,$idx); # save inp
  959. &mov ($s2,$_len); # load len
  960. &sub ($s2,16);
  961. &jc (&label("dec_in_place_partial"));
  962. &mov ($_len,$s2); # save len
  963. &jnz (&label("dec_in_place_loop"));
  964. &jmp (&label("dec_out"));
  965. &set_label("dec_in_place_partial",4);
  966. # one can argue if this is actually required...
  967. &mov ($key eq "edi" ? $key : "",$_out);
  968. &lea ($idx eq "esi" ? $idx : "",$ivec);
  969. &lea ($key,&DWP(0,$key,$s2));
  970. &lea ($idx,&DWP(16,$idx,$s2));
  971. &neg ($s2 eq "ecx" ? $s2 : "");
  972. &data_word(0xA4F3F689); # rep movsb # restore tail
  973. &set_label("dec_out",4);
  974. &mov ("esp",$_esp);
  975. &popf ();
  976. &function_end("Camellia_cbc_encrypt");
  977. }
  978. &asciz("Camellia for x86 by <appro\@openssl.org>");
  979. &asm_finish();