~ubuntu-branches/ubuntu/lucid/openssl/lucid-proposed

« back to all changes in this revision

Viewing changes to crypto/camellia/asm/cmll-x86.pl

  • Committer: Bazaar Package Importer
  • Author(s): Kurt Roeckx
  • Date: 2009-06-13 18:15:46 UTC
  • mto: (11.1.5 squeeze)
  • mto: This revision was merged to the branch mainline in revision 34.
  • Revision ID: james.westby@ubuntu.com-20090613181546-vbfntai3b009dl1u
Tags: upstream-0.9.8k
ImportĀ upstreamĀ versionĀ 0.9.8k

Show diffs side-by-side

added added

removed removed

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