/*
 * Copyright 1988 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-cpyright.h>.
 *
 * This routine calculates an effective Key schedule set of
 * permutations for des.  Beginning with the pre-defined key schedule
 * algorithm, it reduces it to a set of 16 permutations upon the
 * initial key.  Only needs to execute once to produce a header file.
 * Note that we subtract one from the values ouput to fix up for C
 * subscripts starting at 0.
 */

#include <afsconfig.h>
#include <afs/param.h>


#include "mit-cpyright.h"
#include <stdio.h>
#include <errno.h>
#include "des.h"
#include "des_internal.h"
#include "des_prototypes.h"

char *progname;

static int key_position[64 + 1];
static int C[28 + 1];
static int D[28 + 1];
static int C_temp, D_temp;

/*
 *  CONVENTIONS for numbering the bits
 *  bit 0 ==> lsb
 *  L starts at bit 0
 *  R starts at bit 64
 *
 *  BEWARE-- some stuff starts at 0, some at 1;  perhaps some bugs still?
 */

/*
 * Sequence of shifts used for the key schedule.
 */
static int const shift[16 + 1] = { 0,
    1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
};

static int const pc_1[56 + 1] = { 0,

    57, 49, 41, 33, 25, 17, 9,
    1, 58, 50, 42, 34, 26, 18,
    10, 2, 59, 51, 43, 35, 27,
    19, 11, 3, 60, 52, 44, 36,

    63, 55, 47, 39, 31, 23, 15,
    7, 62, 54, 46, 38, 30, 22,
    14, 6, 61, 53, 45, 37, 29,
    21, 13, 5, 28, 20, 12, 4,
};


/*
 * Permuted-choice 2, to pick out the bits from
 * the CD array that generate the key schedule.
 */
static int const pc_2[48 + 1] = { 0,

    14, 17, 11, 24, 1, 5,
    3, 28, 15, 6, 21, 10,
    23, 19, 12, 4, 26, 8,
    16, 7, 27, 20, 13, 2,

    41, 52, 31, 37, 47, 55,
    30, 40, 51, 45, 33, 48,
    44, 49, 39, 56, 34, 53,
    46, 42, 50, 36, 29, 32,
};

static int ks_perm[16 + 1][48 + 1];

int des_debug;

void
gen(FILE * stream)
{
    /*  Local Declarations */
    int i, j, iter;

    /*
     * initialize the key_position array s.t. key_position[i] = i;
     * that is, each element is equal to its starting position.
     *
     * Also adjust for the bit order within bytes.
     */

    for (i = 0; i < 65; i++)
	key_position[i] = swap_bit_pos_1(i);

    fprintf(stream, "static int const key_perm[16][48] = {\n");

    /*
     * apply pc_1 to initial key_position to create C[0] and D[0]
     * Start at pc_1[1], not pc_1[0]
     */
    for (i = 1; i <= 28; i++) {
	C[i] = key_position[pc_1[i]];
	D[i] = key_position[pc_1[i + 28]];
    }

    /*
     * major loop over the 16 iterations
     * start at iter = 1, not zero.
     */
    for (iter = 1; iter <= 16; iter++) {
	if (des_debug) {
	    /*  for debugging */
	    printf("/* DEBUG-- start iteration = %d  shifts = %d", iter,
		   shift[iter]);
	    printf("\nC array");
	    for (i = 1; i <= 4; i++) {
		printf("\n");
		for (j = 1; j <= 7; j++)
		    printf("%d, ", C[(i - 1) * 7 + j]);
	    }
	    printf("\n\nD array");
	    for (i = 1; i <= 4; i++) {
		printf("\n");
		for (j = 1; j <= 7; j++)
		    printf("%d, ", D[(i - 1) * 7 + j]);
	    }
	    printf("\n */");
	    fflush(stdout);
	}

	/* apply the appropriate left shifts */
	for (i = 1; i <= shift[iter]; i++) {
	    C_temp = C[1];
	    D_temp = D[1];
	    for (j = 1; j <= 27; j++) {
		C[j] = C[j + 1];
		D[j] = D[j + 1];
	    }
	    C[j] = C_temp;
	    D[j] = D_temp;
	}


	if (des_debug) {
	    /* for debugging */
	    printf("/* DEBUG:\n");
	    printf(" * after shifts, iteration = %d  shifts = %d", iter,
		   shift[iter]);
	    printf("\nC array");
	    for (i = 1; i <= 4; i++) {
		printf("\n");
		for (j = 1; j <= 7; j++)
		    printf("%d, ", C[(i - 1) * 7 + j]);
	    }
	    printf("\n\nD array");
	    for (i = 1; i <= 4; i++) {
		printf("\n");
		for (j = 1; j <= 7; j++)
		    printf("%d, ", D[(i - 1) * 7 + j]);
	    }
	    printf("\n */");
	    fflush(stdout);
	}

	/*
	 * apply pc_2
	 * Start at pc_2[1], not pc_2[0]
	 *
	 * Start stuffing ks_perm[1][1], not ks_perm[0][0]
	 *
	 * Adjust ks_perm for bit order if needed.
	 */
	for (i = 1; i <= 48; i++) {
	    if (pc_2[i] <= 28)
		ks_perm[iter][(i)] = C[pc_2[i]];
	    else
		ks_perm[iter][(i)] = D[pc_2[i] - 28];
	}

	/* now output the resulting key permutation */
	fprintf(stream, "\n    /* ks permutation iteration = %2d */", iter);
	for (i = 1; i <= 6; i++) {
	    if (i == 1)
		fprintf(stream, "\n    {");
	    fprintf(stream, "\n    ");
	    for (j = 1; j <= 8; j++) {
		/*
		 * IMPORTANT -- subtract one from value to adjust to a
		 * zero-based subscript for key
		 */
		fprintf(stream, "%d", ks_perm[iter][(i - 1) * 8 + j] - 1);
		/* omit last comma */
		if ((j != 8) || (i != 6)) {
		    fprintf(stream, ", ");
		}
	    }
	}
	if (iter != 16) {
	    fprintf(stream, "\n    }, ");
	} else {
	    fprintf(stream, "\n    }");
	}
    }
    fprintf(stream, "\n};\n");
}
