Re: Twofish/AES News (bogus performance claims?)

New Message Reply About this list Date view Thread view Subject view Author view

Alex Alten (Alten@Home.Com)
Thu, 03 Dec 1998 23:21:32 -0800


At 03:24 PM 12/3/98 -0600, Bruce Schneier wrote:
>There are some new papers on the Twofish webpage.
>
>We have improved our performance numbers. On Pentium-class machines, key

I noticed you are claiming an encrypt of 400 cycles/block on a Pentium Pro
200. This translates to 8 MB/sec enciphering speed. I tried your optimized
C version and could only get 3 MB/sec (with a 128 bit key ECB mode). I was
careful to ensure that the cipher worked with test data in a main memory to
main memory encipherment. You are overstating TwoFish's real world
performance by a factor of about 2.5 . This makes me suspicious of your
assembler version speed claims, maybe it really runs at 760 c/block?

I used Microsoft MSVC 4.2. I set the optimizations for maximum speed and to
emit Pentium Pro specific assembler code. I've included my test code and a
slightly modified AES.h file, so that you can see for yourself how I tested
it. I used your TWOFISH2.C AES submission code version 1.00, dated April
1998.

- Alex

#include <windows.h>

#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <memory.h>
#include <stdlib.h>
#include <sys/timeb.h>

#define NO_AES_FUNCTS 1
#include "AES.H"

extern "C" {
extern int makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial);

extern int cipherInit(cipherInstance *cipher, BYTE mode, char *IV);

extern int blockEncrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,
                                int inputLen, BYTE *outBuffer);

extern int blockDecrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,
                                int inputLen, BYTE *outBuffer);

}; // extern "C"

static const unsigned int MAX_BUFFER_LENGTH = 0x100000*4;
//static const unsigned int MAX_BUFFER_LENGTH = 0x100000;
static const unsigned int MAX_BUFFER_LENGTH2 = MAX_BUFFER_LENGTH/4;
static const unsigned int MB = 0x100000;
//static const unsigned int LOOPS = 1024;
static const unsigned int LOOPS = 128;

main(int argc, char **argv)
{
    unsigned int status = 0;
    unsigned int q = 0;
    unsigned int r = 0;
    unsigned int s = 0;
    time_t ltime1, ltime2, ltime3;

    int status2;
    keyInstance key;
    cipherInstance cipher;

    unsigned __int8 *pFromBuffer = NULL;
    unsigned __int8 *pToBuffer = NULL;

    unsigned __int32 *pFromBuffer2 = NULL;
    unsigned __int32 *pToBuffer2 = NULL;

    printf("\nTWOFISH: initialization");
    
    srand(0x3985058);

    pFromBuffer = new unsigned __int8 [MAX_BUFFER_LENGTH];
    pToBuffer = new unsigned __int8 [MAX_BUFFER_LENGTH];

    for (q=0;q<MAX_BUFFER_LENGTH;q++)
        pFromBuffer[q]=rand();

// -------------------------------- TWOFISH -----------------------------------------

    printf("\nTWOFISH: key setup.");

    status2 = makeKey(&key, DIR_ENCRYPT, 128, "123456789ABCDEF0123456789ABCDEF0");
    if (status2 != TRUE)
    {
        printf("\nkey setup FAILED.");
    };

    printf("\nTWOFISH: cipher setup.");

    status2 = cipherInit(&cipher, MODE_ECB, "123456789ABCDEF0123456789ABCDEF0");
    if (status2 != TRUE)
    {
        printf("\ncipher setup FAILED.");
    };

    printf("\nTWOFISH: start timing.");

    for (r=256, s=LOOPS*4096;r<=MAX_BUFFER_LENGTH;r=r*4, s=s/4)
    {

        time( &ltime1 );

        for (q=0;q<s;q++) {
           status2 = blockEncrypt(&cipher, &key, pFromBuffer, r*8, pToBuffer);
           if (status2 < 0) {
                printf("\nblockEncrypt failed.");
                goto END_TEST;
            };
        };

        time( &ltime2 );

        ltime3 = (ltime2 - ltime1);

        printf("\nTWOFISH transform (buffer size = %d): ", r);
        printf("\nsec per %ld bytes = %ld", r*q, ltime3);
        if (ltime3!=0)
            printf("\nMB/s = %ld", (r*q)/(MB*ltime3));

    }; // r loop

    printf("\n-----------------------\n");

END_TEST:

    if (pToBuffer!=NULL)
        delete pToBuffer;

    if (pFromBuffer!=NULL)
        delete pFromBuffer;

    return 0;
};

/* aes.h */
/* AES Cipher header file for ANSI C Submissions
        Lawrence E. Bassham III
        Computer Security Division
        National Institute of Standards and Technology

        This sample is to assist implementers developing to the
Cryptographic API Profile for AES Candidate Algorithm Submissions.
Please consult this document as a cross-reference.
        
        ANY CHANGES, WHERE APPROPRIATE, TO INFORMATION PROVIDED IN THIS FILE
MUST BE DOCUMENTED. CHANGES ARE ONLY APPROPRIATE WHERE SPECIFIED WITH
THE STRING "CHANGE POSSIBLE". FUNCTION CALLS AND THEIR PARAMETERS
CANNOT BE CHANGED. STRUCTURES CAN BE ALTERED TO ALLOW IMPLEMENTERS TO
INCLUDE IMPLEMENTATION SPECIFIC INFORMATION.
*/

/* Includes:
        Standard include files
*/

#include <stdio.h>
#include "platform.h" /* platform-specific defines */

/* Defines:
                Add any additional defines you need
*/

#define DIR_ENCRYPT 0 /* Are we encrpyting? */
#define DIR_DECRYPT 1 /* Are we decrpyting? */
#define MODE_ECB 1 /* Are we ciphering in ECB mode? */
#define MODE_CBC 2 /* Are we ciphering in CBC mode? */
#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */

#define TRUE 1
#define FALSE 0

#define BAD_KEY_DIR -1 /* Key direction is invalid (unknown value) */
#define BAD_KEY_MAT -2 /* Key material not of correct length */
#define BAD_KEY_INSTANCE -3 /* Key passed is not valid */
#define BAD_CIPHER_MODE -4 /* Params struct passed to cipherInit invalid */
#define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */

/* CHANGE POSSIBLE: inclusion of algorithm specific defines */
/* TWOFISH specific definitions */
#define MAX_KEY_SIZE 64 /* # of ASCII chars needed to represent a key */
#define MAX_IV_SIZE 16 /* # of bytes needed to represent an IV */
#define BAD_INPUT_LEN -6 /* inputLen not a multiple of block size */
#define BAD_PARAMS -7 /* invalid parameters */
#define BAD_IV_MAT -8 /* invalid IV text */
#define BAD_ENDIAN -9 /* incorrect endianness define */
#define BAD_ALIGN32 -10 /* incorrect 32-bit alignment */

#define BLOCK_SIZE 128 /* number of bits per block */
#define MAX_ROUNDS 16 /* max # rounds (for allocating subkey array) */
#define ROUNDS_128 16 /* default number of rounds for 128-bit keys*/
#define ROUNDS_192 16 /* default number of rounds for 192-bit keys*/
#define ROUNDS_256 16 /* default number of rounds for 256-bit keys*/
#define MAX_KEY_BITS 256 /* max number of bits of key */
#define MIN_KEY_BITS 128 /* min number of bits of key (zero pad) */
#define VALID_SIG 0x48534946 /* initialization signature ('FISH') */
#define MCT_OUTER 400 /* MCT outer loop */
#define MCT_INNER 10000 /* MCT inner loop */
#define REENTRANT 1 /* nonzero forces reentrant code (slightly slower) */

#define INPUT_WHITEN 0 /* subkey array indices */
#define OUTPUT_WHITEN ( INPUT_WHITEN + BLOCK_SIZE/32)
#define ROUND_SUBKEYS (OUTPUT_WHITEN + BLOCK_SIZE/32) /* use 2 * (# rounds) */
#define TOTAL_SUBKEYS (ROUND_SUBKEYS + 2*MAX_ROUNDS)

/* Typedefs:
        Typedef'ed data storage elements. Add any algorithm specific
        parameters at the bottom of the structs as appropriate.
*/

typedef unsigned char BYTE;
typedef unsigned long DWORD; /* 32-bit unsigned quantity */
typedef DWORD fullSbox[4][256];

/* The structure for key information */
typedef struct
        {
        BYTE direction; /* Key used for encrypting or decrypting? */
#if ALIGN32
        BYTE dummyAlign[3]; /* keep 32-bit alignment */
#endif
        int keyLen; /* Length of the key */
        char keyMaterial[MAX_KEY_SIZE+4];/* Raw key data in ASCII */

        /* Twofish-specific parameters: */
        DWORD keySig; /* set to VALID_SIG by makeKey() */
        int numRounds; /* number of rounds in cipher */
        DWORD key32[MAX_KEY_BITS/32]; /* actual key bits, in dwords */
        DWORD sboxKeys[MAX_KEY_BITS/64];/* key bits used for S-boxes */
        DWORD subKeys[TOTAL_SUBKEYS]; /* round subkeys, input/output whitening bits */
#if REENTRANT
        fullSbox sBox8x32; /* fully expanded S-box */
  #if defined(COMPILE_KEY) && defined(USE_ASM)
#undef VALID_SIG
#define VALID_SIG 0x504D4F43 /* 'COMP': C is compiled with -DCOMPILE_KEY */
        void *encryptFuncPtr; /* ptr to asm encrypt function */
        void *decryptFuncPtr; /* ptr to asm decrypt function */
        DWORD codeSize; /* size of compiledCode */
        BYTE compiledCode[5000]; /* make room for the code itself */
  #endif
#endif
        } keyInstance;

/* The structure for cipher information */
typedef struct
        {
        BYTE mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */
#if ALIGN32
        BYTE dummyAlign[3]; /* keep 32-bit alignment */
#endif
        BYTE IV[MAX_IV_SIZE]; /* CFB1 iv bytes (CBC uses iv32) */

        /* Twofish-specific parameters: */
        DWORD cipherSig; /* set to VALID_SIG by cipherInit() */
        DWORD iv32[BLOCK_SIZE/32]; /* CBC IV bytes arranged as dwords */
        } cipherInstance;

/* Function protoypes */
#ifndef NO_AES_FUNCTS

int makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial);

int cipherInit(cipherInstance *cipher, BYTE mode, char *IV);

int blockEncrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,
                                int inputLen, BYTE *outBuffer);

int blockDecrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,
                                int inputLen, BYTE *outBuffer);

int reKey(keyInstance *key); /* do key schedule using modified key.keyDwords */

/* affect number of rounds for given keyLen (64,128,192, 256) */
int setRounds(int keyLen,int nRounds);

/* API to check table usage, for use in ECB_TBL KAT */
#define TAB_DISABLE 0
#define TAB_ENABLE 1
#define TAB_RESET 2
#define TAB_QUERY 3
#define TAB_MIN_QUERY 50
int TableOp(int op);

#endif // NO_AES_FUNCTS

#define CONST /* helpful C++ syntax sugar, NOP for ANSI C */

#if BLOCK_SIZE == 128 /* optimize block copies */
#define Copy1(d,s,N) ((DWORD *)(d))[N] = ((DWORD *)(s))[N]
#define BlockCopy(d,s) { Copy1(d,s,0);Copy1(d,s,1);Copy1(d,s,2);Copy1(d,s,3); }
#else
#define BlockCopy(d,s) { memcpy(d,s,BLOCK_SIZE/8); }
#endif

--

Alex Alten

Alten@Home.Com Alten@TriStrata.Com

P.O. Box 11406 Pleasanton, CA 94588 USA (925) 417-0159


New Message Reply About this list Date view Thread view Subject view Author view

 
All trademarks and copyrights are the property of their respective owners.

Other Directory Sites: SeekWonder | Directory Owners Forum

The following archive was created by hippie-mail 7.98617-22 on Sat Apr 10 1999 - 01:17:37