cmll-x86.pl 33 KB

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