cmll-x86.pl 33 KB

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