55553f719b521a0bb4deab6efc944cd30c1a56aada# ====================================================================
55553f719b521a0bb4deab6efc944cd30c1a56aada# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
55553f719b521a0bb4deab6efc944cd30c1a56aada# project. The module is, however, dual licensed under OpenSSL and
55553f719b521a0bb4deab6efc944cd30c1a56aada# CRYPTOGAMS licenses depending on where you obtain it. For further
55553f719b521a0bb4deab6efc944cd30c1a56aada# ====================================================================
55553f719b521a0bb4deab6efc944cd30c1a56aada# 2.22x RC4 tune-up:-) It should be noted though that my hand [as in
55553f719b521a0bb4deab6efc944cd30c1a56aada# "hand-coded assembler"] doesn't stand for the whole improvement
55553f719b521a0bb4deab6efc944cd30c1a56aada# coefficient. It turned out that eliminating RC4_CHAR from config
55553f719b521a0bb4deab6efc944cd30c1a56aada# line results in ~40% improvement (yes, even for C implementation).
55553f719b521a0bb4deab6efc944cd30c1a56aada# Presumably it has everything to do with AMD cache architecture and
55553f719b521a0bb4deab6efc944cd30c1a56aada# RAW or whatever penalties. Once again! The module *requires* config
55553f719b521a0bb4deab6efc944cd30c1a56aada# line *without* RC4_CHAR! As for coding "secret," I bet on partial
55553f719b521a0bb4deab6efc944cd30c1a56aada# register arithmetics. For example instead of 'inc %r8; and $255,%r8'
55553f719b521a0bb4deab6efc944cd30c1a56aada# I simply 'inc %r8b'. Even though optimization manual discourages
55553f719b521a0bb4deab6efc944cd30c1a56aada# to operate on partial registers, it turned out to be the best bet.
55553f719b521a0bb4deab6efc944cd30c1a56aada# At least for AMD... How IA32E would perform remains to be seen...
55553f719b521a0bb4deab6efc944cd30c1a56aada# As was shown by Marc Bevand reordering of couple of load operations
55553f719b521a0bb4deab6efc944cd30c1a56aada# results in even higher performance gain of 3.3x:-) At least on
55553f719b521a0bb4deab6efc944cd30c1a56aada# Opteron... For reference, 1x in this case is RC4_CHAR C-code
55553f719b521a0bb4deab6efc944cd30c1a56aada# compiled with gcc 3.3.2, which performs at ~54MBps per 1GHz clock.
55553f719b521a0bb4deab6efc944cd30c1a56aada# Latter means that if you want to *estimate* what to expect from
55553f719b521a0bb4deab6efc944cd30c1a56aada# *your* Opteron, then multiply 54 by 3.3 and clock frequency in GHz.
55553f719b521a0bb4deab6efc944cd30c1a56aada# Intel P4 EM64T core was found to run the AMD64 code really slow...
55553f719b521a0bb4deab6efc944cd30c1a56aada# The only way to achieve comparable performance on P4 was to keep
55553f719b521a0bb4deab6efc944cd30c1a56aada# RC4_CHAR. Kind of ironic, huh? As it's apparently impossible to
55553f719b521a0bb4deab6efc944cd30c1a56aada# compose blended code, which would perform even within 30% marginal
55553f719b521a0bb4deab6efc944cd30c1a56aada# on either AMD and Intel platforms, I implement both cases. See
55553f719b521a0bb4deab6efc944cd30c1a56aada# rc4_skey.c for further details...
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# P4 EM64T core appears to be "allergic" to 64-bit inc/dec. Replacing
55553f719b521a0bb4deab6efc944cd30c1a56aada# those with add/sub results in 50% performance improvement of folded
55553f719b521a0bb4deab6efc944cd30c1a56aada# As was shown by Zou Nanhai loop unrolling can improve Intel EM64T
55553f719b521a0bb4deab6efc944cd30c1a56aada# performance by >30% [unlike P4 32-bit case that is]. But this is
55553f719b521a0bb4deab6efc944cd30c1a56aada# provided that loads are reordered even more aggressively! Both code
55553f719b521a0bb4deab6efc944cd30c1a56aada# pathes, AMD64 and EM64T, reorder loads in essentially same manner
55553f719b521a0bb4deab6efc944cd30c1a56aada# as my IA-64 implementation. On Opteron this resulted in modest 5%
55553f719b521a0bb4deab6efc944cd30c1a56aada# improvement [I had to test it], while final Intel P4 performance
55553f719b521a0bb4deab6efc944cd30c1a56aada# achieves respectful 432MBps on 2.8GHz processor now. For reference.
55553f719b521a0bb4deab6efc944cd30c1a56aada# If executed on Xeon, current RC4_CHAR code-path is 2.7x faster than
55553f719b521a0bb4deab6efc944cd30c1a56aada# RC4_INT code-path. While if executed on Opteron, it's only 25%
55553f719b521a0bb4deab6efc944cd30c1a56aada# slower than the RC4_INT one [meaning that if CPU �-arch detection
55553f719b521a0bb4deab6efc944cd30c1a56aada# is not implemented, then this final RC4_CHAR code-path should be
55553f719b521a0bb4deab6efc944cd30c1a56aada# preferred, as it provides better *all-round* performance].
55553f719b521a0bb4deab6efc944cd30c1a56aada# Intel Core2 was observed to perform poorly on both code paths:-( It
55553f719b521a0bb4deab6efc944cd30c1a56aada# apparently suffers from some kind of partial register stall, which
55553f719b521a0bb4deab6efc944cd30c1a56aada# occurs in 64-bit mode only [as virtually identical 32-bit loop was
55553f719b521a0bb4deab6efc944cd30c1a56aada# observed to outperform 64-bit one by almost 50%]. Adding two movzb to
55553f719b521a0bb4deab6efc944cd30c1a56aada# cloop1 boosts its performance by 80%! This loop appears to be optimal
55553f719b521a0bb4deab6efc944cd30c1a56aada# fit for Core2 and therefore the code was modified to skip cloop8 on
55553f719b521a0bb4deab6efc944cd30c1a56aada# this CPU.
55553f719b521a0bb4deab6efc944cd30c1a56aada# OpenSolaris OS modifications
55553f719b521a0bb4deab6efc944cd30c1a56aada# Sun elects to use this software under the BSD license.
55553f719b521a0bb4deab6efc944cd30c1a56aada# This source originates from OpenSSL file rc4-x86_64.pl at
55553f719b521a0bb4deab6efc944cd30c1a56aada# ftp://ftp.openssl.org/snapshot/openssl-0.9.8-stable-SNAP-20080131.tar.gz
55553f719b521a0bb4deab6efc944cd30c1a56aada# (presumably for future OpenSSL release 0.9.8h), with these changes:
55553f719b521a0bb4deab6efc944cd30c1a56aada# 1. Added some comments, "use strict", and declared all variables.
55553f719b521a0bb4deab6efc944cd30c1a56aada# 2. Added OpenSolaris ENTRY_NP/SET_SIZE macros from
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# 3. Changed function name from RC4() to arcfour_crypt_asm() and RC4_set_key()
55553f719b521a0bb4deab6efc944cd30c1a56aada# to arcfour_key_init(), and changed the parameter order for both to that
55553f719b521a0bb4deab6efc944cd30c1a56aada# used by OpenSolaris.
55553f719b521a0bb4deab6efc944cd30c1a56aada# 4. The current method of using cpuid feature bits 20 (NX) or 28 (HTT) from
55553f719b521a0bb4deab6efc944cd30c1a56aada# function OPENSSL_ia32_cpuid() to distinguish Intel/AMD does not work for
55553f719b521a0bb4deab6efc944cd30c1a56aada# some newer AMD64 processors, as these bits are set on both Intel EM64T
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# processors and newer AMD64 processors. I replaced this with C code
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# (function arcfour_crypt_on_intel()) to call cpuid_getvendor()
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# when executing in the kernel and getisax() when executing in userland.
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# 5. Set a new field in the key structure, key->flag to 0 for AMD AMD64
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# and 1 for Intel EM64T. This is to select the most-efficient arcfour_crypt()
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# function to use.
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# 6. Removed x86_64-xlate.pl script (not needed for as(1) or gas(1) assemblers).
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# 7. Removed unused RC4_CHAR, Lcloop1, and Lcloop8 code.
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# 8. Added C function definitions for use by lint(1B).
55553f719b521a0bb4deab6efc944cd30c1a56aadause strict;
55553f719b521a0bb4deab6efc944cd30c1a56aadamy ($code, $dat, $inp, $out, $len, $idx, $ido, $i, @XX, @TX, $YY, $TY);
55553f719b521a0bb4deab6efc944cd30c1a56aadamy $output = shift;
55553f719b521a0bb4deab6efc944cd30c1a56aada# Parameters
55553f719b521a0bb4deab6efc944cd30c1a56aada# void RC4(RC4_KEY *key, unsigned long len, const unsigned char *indata,
55553f719b521a0bb4deab6efc944cd30c1a56aada# unsigned char *outdata);
55553f719b521a0bb4deab6efc944cd30c1a56aada#$dat="%rdi"; # arg1
55553f719b521a0bb4deab6efc944cd30c1a56aada#$len="%rsi"; # arg2
55553f719b521a0bb4deab6efc944cd30c1a56aada#$inp="%rdx"; # arg3
55553f719b521a0bb4deab6efc944cd30c1a56aada#$out="%rcx"; # arg4
55553f719b521a0bb4deab6efc944cd30c1a56aada# OpenSolaris:
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson# void arcfour_crypt_asm(ARCFour_key *key, uchar_t *in, uchar_t *out,
55553f719b521a0bb4deab6efc944cd30c1a56aada# Register variables
55553f719b521a0bb4deab6efc944cd30c1a56aada# $XX[0] is key->i (aka key->x), $XX[1] is a temporary.
55553f719b521a0bb4deab6efc944cd30c1a56aada# $TX[0] and $TX[1] are temporaries.
55553f719b521a0bb4deab6efc944cd30c1a56aada# $YY is key->j (aka key->y).
55553f719b521a0bb4deab6efc944cd30c1a56aada# $TY is a temporary.
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson#if defined(lint) || defined(__lint)
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson#include "arcfour.h"
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Andersonarcfour_crypt_asm(ARCFour_key *key, uchar_t *in, uchar_t *out, size_t len)
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Andersonarcfour_key_init(ARCFour_key *key, uchar_t *keyval, int keyvallen)
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson / Use a 4-byte key schedule element array
55553f719b521a0bb4deab6efc944cd30c1a56aadapush(@TX,shift(@TX)); push(@XX,shift(@XX)); # "rotate" registers
55553f719b521a0bb4deab6efc944cd30c1a56aada# Parameters
55553f719b521a0bb4deab6efc944cd30c1a56aada# void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data);
55553f719b521a0bb4deab6efc944cd30c1a56aada#$dat="%rdi"; # arg1
55553f719b521a0bb4deab6efc944cd30c1a56aada#$len="%rsi"; # arg2
55553f719b521a0bb4deab6efc944cd30c1a56aada#$inp="%rdx"; # arg3
55553f719b521a0bb4deab6efc944cd30c1a56aada# OpenSolaris:
55553f719b521a0bb4deab6efc944cd30c1a56aada# void arcfour_key_init(ARCFour_key *key, uchar_t *keyval, int keyvallen);
55553f719b521a0bb4deab6efc944cd30c1a56aada# Temporaries
55553f719b521a0bb4deab6efc944cd30c1a56aada / Find out if we're running on Intel or something else (e.g., AMD64).
92a8e44d7a50507b89a65e1e3226edb5b90fd363Dan OpenSolaris Anderson / Save return value in key->flag (1=Intel, 0=AMD)
55553f719b521a0bb4deab6efc944cd30c1a56aada.asciz "RC4 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
55553f719b521a0bb4deab6efc944cd30c1a56aada#endif /* !lint && !__lint */