/* This is a program which calculates and makes the tables used by
   the RNG core
   Written by Sam Trenholme
 * Copyright (c) 2002,2003 Sam Trenholme
 *
 * TERMS
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This software is provided 'as is' with no guarantees of correctness or
 * fitness for purpose.
 */

#include <stdio.h>
#include <stdlib.h>

/* Multiply two elements together for any GF(2^n), where n is less than 30
   Input: The two elements to multiply together, the degree to
          multiply by, the reducing polynomial for the degree in question
   Output: The product of the two elements
*/
int gmul(int i1, int i2, int degree, int field) {
    int result = 0;
    int counter;
    int hibit = 1;
    for(counter = 0; counter < degree; counter++) 
        hibit <<= 1;
    for(counter = 0; counter < degree; counter++) {
        if((i2 & 1) == 1)
            result ^= i1;
        i2 >>= 1;
        i1 <<= 1;
        if((i1 & hibit) == hibit)
            i1 ^= field;
        }
    return result;
    }
    
/* Multiply two elements together in a galois field of 2^8
   Input: The two elements to multiply together
   Output: The product of the two elements 
*/
int mul(int i1, int i2) {
    return gmul(i1,i2,8,0x11b);
    }

/* Multiply two elements together in the field of 2^4
   Input: The two elements to multiply together
   Output: The product of the two elements 
*/
unsigned char mul_4(unsigned char i1, unsigned char i2) {
    return gmul(i1,i2,4,0x13);
    }

/* sbox: calculate, on the fly, the sbox 
   Input: The byte to calculate the sbox for
   Output: The sbox for the byte in question
*/
unsigned char sbox(unsigned char in) {
   /* The sboxes */
   unsigned char rbox[16] = {0x7,0xc,0xb,0xd,0xe,0x4,0x9,0xf,
                             0x6,0x3,0x8,0xa,0x2,0x5,0x1,0x0};
   unsigned char ebox[16],iebox[16];
   /* The two nibbles of this byte */
   unsigned char lnib, rnib, ivalue;
   int counter;

   /* Generate the ebox */
   ebox[0] = 1;
   for(counter = 1; counter < 15; counter++)
      ebox[counter] = mul_4(ebox[counter - 1],0xb) & 0xf;
   ebox[0xf] = 0;

   /* Generate the inverse ebox */
   for(counter = 0; counter < 16; counter++) 
      iebox[ebox[counter]] = counter;
  
   lnib = (in & 0xf0) >> 4;
   rnib = in & 0x0f;
   lnib = ebox[lnib];
   rnib = iebox[rnib];
   ivalue = lnib ^ rnib;
   ivalue = rbox[ivalue];
   lnib ^= ivalue;
   rnib ^= ivalue;
   lnib = ebox[lnib];
   rnib = iebox[rnib];
   return (lnib << 4) | rnib;
   }


/* Make one table: Make a single one of the four tables
   Input: four multiply constants 
   Output: Displays table on stdout
*/

void one_en_table(int m1, int m2, int m3, int m4) {
     int counter;
     unsigned char s;
     for(counter = 0; counter < 256; counter++) {
         if(counter % 4 == 0)
	     printf("\n");
         s = sbox(counter);
	 printf("0x%02x%02x%02x%02xU, ",
	        mul(s,m1),mul(s,m2),mul(s,m3),mul(s,m4));
         }
     printf("\n};\n");
     }

int main() {
    int a[4] = {19,77,6,16};
    printf("/* This file is automatically generated by the program ");
    printf("make_32bit_tables.c */\n\n");
    printf("static const u32 Te0[256] = {");
    one_en_table(a[0],a[1],a[2],a[3]);
    printf("static const u32 Te1[256] = {");
    one_en_table(a[3],a[0],a[1],a[2]);
    printf("static const u32 Te2[256] = {");
    one_en_table(a[2],a[3],a[0],a[1]);
    printf("static const u32 Te3[256] = {");
    one_en_table(a[1],a[2],a[3],a[0]);
    printf("static const u32 Te4[256] = {");
    one_en_table(1,1,1,1);
    exit(0);
    }

