aes-ppc.pl: 10% performance improvement on Power6.
[oweals/openssl.git] / crypto / aes / asm / aes-586.pl
index 4401cee9e353d5c92c515788de80a5176cf20843..aab40e6f1cf206c7b8912829d6beb308982150b9 100755 (executable)
@@ -2,8 +2,9 @@
 #
 # ====================================================================
 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
-# project. Rights for redistribution and usage in source and binary
-# forms are granted according to the OpenSSL license.
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
 # ====================================================================
 #
 # Version 4.3.
 # P4           56[60]          84[100]         23
 # AMD K8       48[44]          70[79]          18
 # PIII         41[50]          61[91]          24
+# Core 2       32[38]          45[70]          18.5
 # Pentium      120             160             77
 #
 # Version 4.1 switches to compact S-box even in key schedule setup.
 #
 # Version 4.3 implements switch between compact and non-compact block
 # functions in AES_cbc_encrypt depending on how much data was asked
-# to process in one stroke.
+# to be processed in one stroke.
 #
+######################################################################
 # Timing attacks are classified in two classes: synchronous when
-# attacker consciously initiates cryptographic operation and collect
+# attacker consciously initiates cryptographic operation and collects
 # timing data of various character afterwards, and asynchronous when
 # malicious code is executed on same CPU simultaneously with AES,
 # instruments itself and performs statistical analysis of this data.
 # timing. But note that *if* plain-text was concealed in such way that
 # input to block function is distributed *uniformly*, then attack
 # wouldn't apply. Now note that some encryption modes, most notably
-# CBC, do masks the plain-text in this exact way [secure cipher output
+# CBC, do mask the plain-text in this exact way [secure cipher output
 # is distributed uniformly]. Yes, one still might find input that
 # would reveal the information about given key, but if amount of
-# candidate inputs to be tried is larger than amount possible key
+# candidate inputs to be tried is larger than amount of possible key
 # combinations then attack becomes infeasible. This is why revised
 # AES_cbc_encrypt "dares" to switch to larger S-box when larger chunk
 # of data is to be processed in one stroke. The current size limit of
 # Current implementation accesses *all* cache-lines within ~50 cycles
 # window, which is actually *less* than RDTSC latency on Intel P4!
 
-push(@INC,"perlasm","../../perlasm");
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
 require "x86asm.pl";
 
 &asm_init($ARGV[0],"aes-586.pl",$x86only = $ARGV[$#ARGV] eq "386");
+&static_label("AES_Te");
+&static_label("AES_Td");
 
 $s0="eax";
 $s1="ebx";
@@ -473,11 +479,10 @@ sub enctransform()
        &mov    ($acc,$s[$i]);
        &and    ($acc,0x80808080);
        &mov    ($tmp,$acc);
-       &mov    ($r2,$s[$i]);
        &shr    ($tmp,7);
-       &and    ($r2,0x7f7f7f7f);
+       &lea    ($r2,&DWP(0,$s[$i],$s[$i]));
        &sub    ($acc,$tmp);
-       &lea    ($r2,&DWP(0,$r2,$r2));
+       &and    ($r2,0xfefefefe);
        &and    ($acc,0x1b1b1b1b);
        &mov    ($tmp,$s[$i]);
        &xor    ($acc,$r2);     # r2
@@ -491,7 +496,6 @@ sub enctransform()
        &xor    ($s[$i],$tmp);
 }
 
-&public_label("AES_Te");
 &function_begin_B("_x86_AES_encrypt_compact");
        # note that caller is expected to allocate stack frame for me!
        &mov    ($__key,$key);                  # save key
@@ -685,7 +689,6 @@ sub sse_enccompact()
 }
 
                                        if (!$x86only) {
-&public_label("AES_Te");
 &function_begin_B("_sse_AES_encrypt_compact");
        &pxor   ("mm0",&QWP(0,$key));   #  7, 6, 5, 4, 3, 2, 1, 0
        &pxor   ("mm4",&QWP(8,$key));   # 15,14,13,12,11,10, 9, 8
@@ -833,7 +836,6 @@ sub enclast()
        if ($i==3)  {   &mov    ($s[3],$acc);                   }
 }
 
-&public_label("AES_Te");
 &function_begin_B("_x86_AES_encrypt");
        if ($vertical_spin) {
                # I need high parts of volatile registers to be accessible...
@@ -1155,7 +1157,6 @@ sub enclast()
 &function_end_B("_x86_AES_encrypt");
 
 # void AES_encrypt (const void *inp,void *out,const AES_KEY *key);
-&public_label("AES_Te");
 &function_begin("AES_encrypt");
        &mov    ($acc,&wparam(0));              # load inp
        &mov    ($key,&wparam(2));              # load key
@@ -1272,59 +1273,55 @@ sub dectransform()
        &mov    ($acc,$s[$i]);
        &and    ($acc,0x80808080);
        &mov    ($tmp,$acc);
-       &mov    ($tp2,$s[$i]);
        &shr    ($tmp,7);
-       &and    ($tp2,0x7f7f7f7f);
+       &lea    ($tp2,&DWP(0,$s[$i],$s[$i]));
        &sub    ($acc,$tmp);
-       &add    ($tp2,$tp2);
+       &and    ($tp2,0xfefefefe);
        &and    ($acc,0x1b1b1b1b);
        &xor    ($acc,$tp2);
        &mov    ($tp2,$acc);
 
        &and    ($acc,0x80808080);
        &mov    ($tmp,$acc);
-       &mov    ($tp4,$tp2);
-        &xor   ($tp2,$s[$i]);  # tp2^tp1
        &shr    ($tmp,7);
-       &and    ($tp4,0x7f7f7f7f);
+       &lea    ($tp4,&DWP(0,$tp2,$tp2));
        &sub    ($acc,$tmp);
-       &add    ($tp4,$tp4);
+       &and    ($tp4,0xfefefefe);
        &and    ($acc,0x1b1b1b1b);
+        &xor   ($tp2,$s[$i]);  # tp2^tp1
        &xor    ($acc,$tp4);
        &mov    ($tp4,$acc);
 
        &and    ($acc,0x80808080);
        &mov    ($tmp,$acc);
-       &mov    ($tp8,$tp4);
-        &xor   ($tp4,$s[$i]);  # tp4^tp1
        &shr    ($tmp,7);
-       &and    ($tp8,0x7f7f7f7f);
+       &lea    ($tp8,&DWP(0,$tp4,$tp4));
        &sub    ($acc,$tmp);
-       &add    ($tp8,$tp8);
+       &and    ($tp8,0xfefefefe);
        &and    ($acc,0x1b1b1b1b);
+        &xor   ($tp4,$s[$i]);  # tp4^tp1
         &rotl  ($s[$i],8);     # = ROTATE(tp1,8)
        &xor    ($tp8,$acc);
 
        &xor    ($s[$i],$tp2);
        &xor    ($tp2,$tp8);
-       &xor    ($s[$i],$tp4);
        &rotl   ($tp2,24);
+       &xor    ($s[$i],$tp4);
        &xor    ($tp4,$tp8);
-       &xor    ($s[$i],$tp8);  # ^= tp8^(tp4^tp1)^(tp2^tp1)
        &rotl   ($tp4,16);
-       &xor    ($s[$i],$tp2);  # ^= ROTATE(tp8^tp2^tp1,24)
+       &xor    ($s[$i],$tp8);  # ^= tp8^(tp4^tp1)^(tp2^tp1)
        &rotl   ($tp8,8);
+       &xor    ($s[$i],$tp2);  # ^= ROTATE(tp8^tp2^tp1,24)
        &xor    ($s[$i],$tp4);  # ^= ROTATE(tp8^tp4^tp1,16)
+        &mov   ($s[0],$__s0)                   if($i==2); #prefetch $s0
+        &mov   ($s[1],$__s1)                   if($i==3); #prefetch $s1
+        &mov   ($s[2],$__s2)                   if($i==1);
        &xor    ($s[$i],$tp8);  # ^= ROTATE(tp8,8)
 
-       &mov    ($s[0],$__s0)                   if($i==2); #prefetch $s0
-       &mov    ($s[1],$__s1)                   if($i==3); #prefetch $s1
-       &mov    ($s[2],$__s2)                   if($i==1);
        &mov    ($s[3],$__s3)                   if($i==1);
        &mov    (&DWP(4+4*$i,"esp"),$s[$i])     if($i>=2);
 }
 
-&public_label("AES_Td");
 &function_begin_B("_x86_AES_decrypt_compact");
        # note that caller is expected to allocate stack frame for me!
        &mov    ($__key,$key);                  # save key
@@ -1477,7 +1474,6 @@ sub sse_deccompact()
 }
 
                                        if (!$x86only) {
-&public_label("AES_Td");
 &function_begin_B("_sse_AES_decrypt_compact");
        &pxor   ("mm0",&QWP(0,$key));   #  7, 6, 5, 4, 3, 2, 1, 0
        &pxor   ("mm4",&QWP(8,$key));   # 15,14,13,12,11,10, 9, 8
@@ -1662,7 +1658,6 @@ sub declast()
                        &lea    ($td,&DWP(-2048,$td));          }
 }
 
-&public_label("AES_Td");
 &function_begin_B("_x86_AES_decrypt");
        # note that caller is expected to allocate stack frame for me!
        &mov    ($__key,$key);                  # save key
@@ -1951,7 +1946,6 @@ sub declast()
 &function_end_B("_x86_AES_decrypt");
 
 # void AES_decrypt (const void *inp,void *out,const AES_KEY *key);
-&public_label("AES_Td");
 &function_begin("AES_decrypt");
        &mov    ($acc,&wparam(0));              # load inp
        &mov    ($key,&wparam(2));              # load key
@@ -2035,8 +2029,6 @@ my $ivec=&DWP(60,"esp");  # ivec[16]
 my $aes_key=&DWP(76,"esp");    # copy of aes_key
 my $mark=&DWP(76+240,"esp");   # copy of aes_key->rounds
 
-&public_label("AES_Te");
-&public_label("AES_Td");
 &function_begin("AES_cbc_encrypt");
        &mov    ($s2 eq "ecx"? $s2 : "",&wparam(2));    # load len
        &cmp    ($s2,0);
@@ -2368,6 +2360,7 @@ my $mark=&DWP(76+240,"esp");      # copy of aes_key->rounds
 
 #--------------------------- SLOW ENCRYPT ---------------------------#
        &cmp    ($s2,16);
+       &mov    ($s3,$s1);
        &jb     (&label("slow_enc_tail"));
 
                                        if (!$x86only) {
@@ -2459,7 +2452,7 @@ my $mark=&DWP(76+240,"esp");      # copy of aes_key->rounds
        &pushf  ();                     # kludge, never executed
 
     &set_label("slow_enc_tail",16);
-       &emms   ();
+       &emms   ()      if (!$x86only);
        &mov    ($key eq "edi"? $key:"",$s3);   # load out to edi
        &mov    ($s1,16);
        &sub    ($s1,$s2);
@@ -2476,7 +2469,7 @@ my $mark=&DWP(76+240,"esp");      # copy of aes_key->rounds
        &align  (4);
        &data_word(0xAAF3F689); # rep stosb     # zero tail
 
-       &lea    ($key,&DWP(-16,$s3));           # restore ivp
+       &mov    ($key,$_ivp);                   # restore ivp
        &mov    ($acc,$s3);                     # output as input
        &mov    ($s0,&DWP(0,$key));
        &mov    ($s1,&DWP(4,$key));
@@ -2595,7 +2588,6 @@ my $mark=&DWP(76+240,"esp");      # copy of aes_key->rounds
                &mov    ($acc,$_inp);           # load inp
                &lea    ($acc,&DWP(16,$acc));   # advance inp
                &mov    ($_inp,$acc);           # save inp
-               &mov    ($_len,$s2);            # save len
        &jnz    (&label("slow_dec_loop_x86"));
        &mov    ("esp",$_esp);
        &popf   ();
@@ -2658,12 +2650,9 @@ sub enckey()
        &xor    ("eax",&DWP(1024-128,$tbl,"ecx",4));    # rcon
 }
 
-# int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
-#                        AES_KEY *key)
-&public_label("AES_Te");
-&function_begin("AES_set_encrypt_key");
-       &mov    ("esi",&wparam(0));             # user supplied key
-       &mov    ("edi",&wparam(2));             # private key schedule
+&function_begin("_x86_AES_set_encrypt_key");
+       &mov    ("esi",&wparam(1));             # user supplied key
+       &mov    ("edi",&wparam(3));             # private key schedule
 
        &test   ("esi",-1);
        &jz     (&label("badpointer"));
@@ -2686,7 +2675,7 @@ sub enckey()
        &mov    ("ecx",&DWP(192-128,$tbl));
        &mov    ("edx",&DWP(224-128,$tbl));
 
-       &mov    ("ecx",&wparam(1));             # number of bits in key
+       &mov    ("ecx",&wparam(2));             # number of bits in key
        &cmp    ("ecx",128);
        &je     (&label("10rounds"));
        &cmp    ("ecx",192);
@@ -2863,7 +2852,14 @@ sub enckey()
     &set_label("badpointer");
        &mov    ("eax",-1);
     &set_label("exit");
-&function_end("AES_set_encrypt_key");
+&function_end("_x86_AES_set_encrypt_key");
+
+# int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
+#                        AES_KEY *key)
+&function_begin_B("AES_set_encrypt_key");
+       &call   ("_x86_AES_set_encrypt_key");
+       &ret    ();
+&function_end_B("AES_set_encrypt_key");
 
 sub deckey()
 { my ($i,$key,$tp1,$tp2,$tp4,$tp8) = @_;
@@ -2872,35 +2868,32 @@ sub deckey()
        &mov    ($acc,$tp1);
        &and    ($acc,0x80808080);
        &mov    ($tmp,$acc);
-       &mov    ($tp2,$tp1);
        &shr    ($tmp,7);
-       &and    ($tp2,0x7f7f7f7f);
+       &lea    ($tp2,&DWP(0,$tp1,$tp1));
        &sub    ($acc,$tmp);
-       &add    ($tp2,$tp2);
+       &and    ($tp2,0xfefefefe);
        &and    ($acc,0x1b1b1b1b);
        &xor    ($acc,$tp2);
        &mov    ($tp2,$acc);
 
        &and    ($acc,0x80808080);
        &mov    ($tmp,$acc);
-       &mov    ($tp4,$tp2);
-        &xor   ($tp2,$tp1);    # tp2^tp1
        &shr    ($tmp,7);
-       &and    ($tp4,0x7f7f7f7f);
+       &lea    ($tp4,&DWP(0,$tp2,$tp2));
        &sub    ($acc,$tmp);
-       &add    ($tp4,$tp4);
+       &and    ($tp4,0xfefefefe);
        &and    ($acc,0x1b1b1b1b);
+        &xor   ($tp2,$tp1);    # tp2^tp1
        &xor    ($acc,$tp4);
        &mov    ($tp4,$acc);
 
        &and    ($acc,0x80808080);
        &mov    ($tmp,$acc);
-       &mov    ($tp8,$tp4);
-        &xor   ($tp4,$tp1);    # tp4^tp1
        &shr    ($tmp,7);
-       &and    ($tp8,0x7f7f7f7f);
+       &lea    ($tp8,&DWP(0,$tp4,$tp4));
+        &xor   ($tp4,$tp1);    # tp4^tp1
        &sub    ($acc,$tmp);
-       &add    ($tp8,$tp8);
+       &and    ($tp8,0xfefefefe);
        &and    ($acc,0x1b1b1b1b);
         &rotl  ($tp1,8);       # = ROTATE(tp1,8)
        &xor    ($tp8,$acc);
@@ -2925,18 +2918,8 @@ sub deckey()
 
 # int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
 #                        AES_KEY *key)
-&public_label("AES_Td");
-&public_label("AES_Te");
 &function_begin_B("AES_set_decrypt_key");
-       &mov    ("eax",&wparam(0));
-       &mov    ("ecx",&wparam(1));
-       &mov    ("edx",&wparam(2));
-       &sub    ("esp",12);
-       &mov    (&DWP(0,"esp"),"eax");
-       &mov    (&DWP(4,"esp"),"ecx");
-       &mov    (&DWP(8,"esp"),"edx");
-       &call   ("AES_set_encrypt_key");
-       &add    ("esp",12);
+       &call   ("_x86_AES_set_encrypt_key");
        &cmp    ("eax",0);
        &je     (&label("proceed"));
        &ret    ();
@@ -2992,5 +2975,6 @@ sub deckey()
 
        &xor    ("eax","eax");                  # return success
 &function_end("AES_set_decrypt_key");
+&asciz("AES for x86, CRYPTOGAMS by <appro\@openssl.org>");
 
 &asm_finish();