\Encryption\polynominal
eliptic_poly.c
/* eliptic_poly.c */ /************************************************************************************ * * * Polynomial version of elliptic curve functions. essentially the same as * * optimal normal basis but uses polynomial functions. Biggest difference is that * * once poly_prime is picked (see polymain.c) you need to compute the "T matrix" to * * help embed data onto a curve by solving a quadratic equation. * * * * Author = mike rosing * * date = June 27, 1997 * * * ************************************************************************************/ #include#include "field2n.h" #include "poly.h" #include "eliptic.h" /* Global parameters for polynomial math. poly_prime is the irreducible polynomial for the Galois field arithmetic. Tmatrix is used to solve quadratic equations and Smatrix is used to compute square roots. */ extern FIELD2N poly_prime; FIELD2N Tmatrix[NUMBITS], Smatrix[NUMBITS], Trace_Vector; INDEX Null_Row; /* Subroutine to invert a binary matrix. The method is brute force but simple. Start with a diagonal matrix in I, and for each row operation in mat_in that eliminates non diagonal terms, do the same in I. The result is that mat_in = 1 and I = 1/mat_in (transpose). If the input transpose is set to any value, we then have to transpose I back into mat_out to get the correct result. If transpose is zero, I is copied to mat_out and the value of error is returned to indicate any null row. Returns 0 if matrix invertible, row number of zero column if not invertible. */ INDEX poly_matrix_invert( mat_in, mat_out) FIELD2N mat_in[NUMBITS], mat_out[NUMBITS]; { INDEX row, col, i, j, rowdex, found, error; ELEMENT src_mask, dst_mask; FIELD2N dummy, Imatrix[NUMBITS]; /* Create Imatrix as diagonalized */ for ( row=0; row 0; row--) { if (row == Null_Row) continue; rowdex = NUMWORD - row/WORDSIZE; src_mask = 1L << (row % WORDSIZE); for (i = row-1; i>=0; i--) { if (Tz[i].e[rowdex] & src_mask) { SUMLOOP(j) { Tmatrix[i].e[j] ^= Tmatrix[row].e[j]; Tz[i].e[j] ^= Tz[row].e[j]; } } } } /* end column eliminate */ return(0); } /********************************************************************* * * * solve a quadratic equation over an irreducible polynomial field. * * Enter with parameters for the equation y^2 + xy + f = 0, where y * * is the unknown, x is usually the x coordinate of a point and * * f = f(x) of a curve. * * * * Assumes init_poly_math already run with Trace_Vector, Null_Row * * and Tmatrix filled out. * * * * computes c = f/x^2 and tests if the trace condition is met. If * * not returns an error code of 1. Otherwise it means we can solve * * the reduced equation z^2 + z + c = 0. The change of variable is * * y = xz. * * * * returns error code zero, y[0] = xz, y[1] = y[0] + x * *********************************************************************/ INDEX poly_quadratic( x, f, y) FIELD2N *x, *f, y[2]; { FIELD2N c, z, dummy; FIELD2N test1, test2; INDEX i, j, k; ELEMENT sum, mask; /* first check to see if x is zero */ sum = 0; SUMLOOP(i) sum |= x->e[i]; if (sum) { /* compute c = x^-2 * f */ copy (x, &c); poly_mul(&c, x, &dummy); /* get x^2 */ poly_inv(&dummy, &z); poly_mul( f, &z, &c); /* verify that trace of c = 0. If not, no solution is possible. */ sum = 0; SUMLOOP(i) sum ^= c.e[i] & Trace_Vector.e[i]; mask = ~0; for (i = WORDSIZE/2; i > 0; i >>= 1) { mask >>= i; sum = ((sum & mask) ^ (sum >> i)); } /* if last bit is set, there is no solution to equation. This eliminates half the points in the field, which might make sense to a mathematician. */ if (sum) { null( &y[0]); null( &y[1]); return(1); } /* clear out null row bit. that part of matrix will not work. */ j = NUMWORD - Null_Row / WORDSIZE; c.e[j] &= ~( 1L << (Null_Row % WORDSIZE)); /* for every bit set in c, add that row of Tmatrix to solution. */ null( &z); mask = 1; j = NUMWORD; for (i=0; i e[i]; return(0); } else { /* x input was zero. Return y = square root of f. Process involves ANDing each row of Smatrix with f and summing all bits to find coefficient for that power of x */ null( &z); for (j = 0; j e[i]; if (sum) { mask = -1L; for (i = WORDSIZE/2; i > 0; i >>= 1) { mask >>= i; sum = ((sum & mask) ^ (sum >> i)); } } if (sum) z.e[NUMWORD - j/WORDSIZE] |= (1L << j%WORDSIZE); } copy( &z, &y[0]); copy( &z, &y[1]); return(0); } } /* print field matrix. an array of FIELD2N of length NUMBITS is assumed. The bits are printed out as a 2D matrix with an extra space every 5 characters. */ void matrix_print( name, matrix, file) FIELD2N matrix[NUMBITS]; char *name; FILE *file; { INDEX i,j; fprintf(file,"%s\n",name); for (i = NUMBITS-1; i>=0; i--) { if (i%5==0) fprintf(file,"\n"); /* extra line every 5 rows */ for (j = NUMBITS-1; j>=0; j--) { if ( matrix[i].e[NUMWORD - j/WORDSIZE] & (1L<<(j%WORDSIZE))) fprintf(file,"1"); else fprintf(file,"0"); if (j%5==0) fprintf(file," "); /* extra space every 5 characters */ } fprintf(file,"\n"); } fprintf(file,"\n"); } /* compute f(x) = x^3 + a_2*x^2 + a_6 for non-supersingular elliptic curves */ void poly_fofx( x, curv, f) FIELD2N *x, *f; CURVE *curv; { FIELD2N x2, x3; INDEX i; copy ( x, &x3); poly_mul( x, &x3, &x2); /* get x^2 */ if (curv->form) poly_mul ( &x2, &curv->a2, f); else null( f); poly_mul( x, &x2, &x3); /* get x^3 */ SUMLOOP (i) f->e[i] ^= ( x3.e[i] ^ curv->a6.e[i] ); } /* embed data onto a curve. Enter with data, curve, ELEMENT offset to be used as increment, and which root (0 or 1). Returns with point having data as x and correct y value for curve. Will use y[0] for last bit of root clear, y[1] for last bit of root set. if ELEMENT offset is out of range, default is 0. */ void poly_embed( data, curv, incrmt, root, pnt) FIELD2N *data; CURVE *curv; INDEX incrmt, root; POINT *pnt; { FIELD2N f, y[2]; INDEX inc = incrmt; INDEX i; if ( (inc < 0) || (inc > NUMWORD) ) inc = 0; copy( data, &pnt->x); poly_fofx( &pnt->x, curv, &f); while (poly_quadratic( &pnt->x, &f, y)) { pnt->x.e[inc]++; poly_fofx( &pnt->x, curv, &f); } copy ( &y[root&1], &pnt->y); } /**************************************************************************** * * * Implement elliptic curve point addition for polynomial basis form. * * This follows R. Schroeppel, H. Orman, S. O'Mally, "Fast Key Exchange with* * Elliptic Curve Systems", CRYPTO '95, TR-95-03, Univ. of Arizona, Comp. * * Science Dept. * ****************************************************************************/ void poly_esum (p1, p2, p3, curv) POINT *p1, *p2, *p3; CURVE *curv; { INDEX i; FIELD2N x1, y1, theta, onex, theta2; ELEMENT check; /* check if p1 or p2 is point at infinity */ check = 0; SUMLOOP(i) check |= p1->x.e[i] | p1->y.e[i]; if (!check) { copy_point( p2, p3); return; } check = 0; SUMLOOP(i) check |= p2->x.e[i] | p2->y.e[i]; if (!check) { copy_point( p1, p3); return; } /* compute lambda = (y_1 + y_2)/(x_1 + x_2) */ null(&x1); null(&y1); check = 0; SUMLOOP(i) { x1.e[i] = p1->x.e[i] ^ p2->x.e[i]; y1.e[i] = p1->y.e[i] ^ p2->y.e[i]; check |= x1.e[i]; } if (!check) /* return point at infinity */ { /* printf("input to elliptic sum has duplicate x values\n"); */ null(&p3->x); null(&p3->y); return; } poly_inv( &x1, &onex); poly_mul( &onex, &y1, &theta); /* compute y_1/lambda */ poly_mul(&theta, &theta, &theta2); /* then lambda^2 */ /* with lambda and lamda^2, compute x_3 */ if (curv->form) SUMLOOP (i) p3->x.e[i] = theta.e[i] ^ theta2.e[i] ^ x1.e[i] ^ curv->a2.e[i]; else SUMLOOP (i) p3->x.e[i] = theta.e[i] ^ theta2.e[i] ^ x1.e[i]; /* next find y_3 */ SUMLOOP (i) x1.e[i] = p1->x.e[i] ^ p3->x.e[i]; poly_mul( &x1, &theta, &theta2); SUMLOOP (i) p3->y.e[i] = theta2.e[i] ^ p3->x.e[i] ^ p1->y.e[i]; } /* elliptic curve doubling routine for Schroeppel's algorithm over polymomial basis. Enter with p1, p3 as source and destination as well as curv to operate on. Returns p3 = 2*p1. */ void poly_edbl (p1, p3, curv) POINT *p1, *p3; CURVE *curv; { FIELD2N x1, y1, theta, theta2, t1; INDEX i; ELEMENT check; check = 0; SUMLOOP (i) check |= p1->x.e[i]; if (!check) { null(&p3->x); null(&p3->y); return; } /* first compute theta = x + y/x */ poly_inv( &p1->x, &x1); poly_mul( &x1, &p1->y, &y1); SUMLOOP (i) theta.e[i] = p1->x.e[i] ^ y1.e[i]; /* next compute x_3 */ poly_mul( &theta, &theta, &theta2); if(curv->form) SUMLOOP (i) p3->x.e[i] = theta.e[i] ^ theta2.e[i] ^ curv->a2.e[i]; else SUMLOOP (i) p3->x.e[i] = theta.e[i] ^ theta2.e[i]; /* and lastly y_3 */ theta.e[NUMWORD] ^= 1; /* theta + 1 */ poly_mul( &theta, &p3->x, &t1); poly_mul( &p1->x, &p1->x, &x1); SUMLOOP (i) p3->y.e[i] = x1.e[i] ^ t1.e[i]; } /* subtract two points on a curve. just negates p2 and does a sum. Returns p3 = p1 - p2 over curv. */ void poly_esub (p1, p2, p3, curv) POINT *p1, *p2, *p3; CURVE *curv; { POINT negp; INDEX i; copy ( &p2->x, &negp.x); null (&negp.y); SUMLOOP(i) negp.y.e[i] = p2->x.e[i] ^ p2->y.e[i]; poly_esum (p1, &negp, p3, curv); } /* need to move points around, not just values. Optimize later. */ void copy_point (p1, p2) POINT *p1, *p2; { copy (&p1->x, &p2->x); copy (&p1->y, &p2->y); } /* Routine to compute kP where k is an integer (base 2, not normal basis) and P is a point on an elliptic curve. This routine assumes that K is representable in the same bit field as x, y or z values of P. Since the field size determines the largest possible order, this makes sense. Enter with: integer k, source point P, curve to compute over (curv) Returns with: result point R. Reference: Koblitz, "CM-Curves with good Cryptografic Properties", Springer-Verlag LNCS #576, p279 (pg 284 really), 1992 */ void poly_elptic_mul(k, p, r, curv) FIELD2N *k; POINT *p, *r; CURVE *curv; { char blncd[NUMBITS+1]; INDEX bit_count, i; ELEMENT notzero; FIELD2N number; POINT temp; /* make sure input multiplier k is not zero. Return point at infinity if it is. */ copy( k, &number); notzero = 0; SUMLOOP (i) notzero |= number.e[i]; if (!notzero) { null (&r->x); null (&r->y); return; } /* convert integer k (number) to balanced representation. Called non-adjacent form in "An Improved Algorithm for Arithmetic on a Family of Elliptic Curves", J. Solinas CRYPTO '97. This follows algorithm 2 in that paper. */ bit_count = 0; while (notzero) { /* if number odd, create 1 or -1 from last 2 bits */ if ( number.e[NUMWORD] & 1 ) { blncd[bit_count] = 2 - (number.e[NUMWORD] & 3); /* if -1, then add 1 and propagate carry if needed */ if ( blncd[bit_count] < 0 ) { for (i=NUMWORD; i>=0; i--) { number.e[i]++; if (number.e[i]) break; } } } else blncd[bit_count] = 0; /* divide number by 2, increment bit counter, and see if done */ number.e[NUMWORD] &= ~0 << 1; rot_right( &number); bit_count++; notzero = 0; SUMLOOP (i) notzero |= number.e[i]; } /* now follow balanced representation and compute kP */ bit_count--; copy_point(p,r); /* first bit always set */ while (bit_count > 0) { poly_edbl(r, &temp, curv); bit_count--; switch (blncd[bit_count]) { case 1: poly_esum (p, &temp, r, curv); break; case -1: poly_esub (&temp, p, r, curv); break; case 0: copy_point (&temp, r); } } } /*void print_field( string, x) char *string; FIELD2N *x; { INDEX i; printf("%s\n",string); SUMLOOP(i) printf("%8x ",x->e[i]); printf("\n"); } void print_point( string, point) char *string; POINT *point; { INDEX i; printf("%s\n",string); printf("x: "); /* printf("%s ",string); SUMLOOP(i) printf("%8x ",point->x.e[i]); printf("\n"); printf("y: "); SUMLOOP(i) printf("%8x ",point->y.e[i]); printf("\n"); } void print_curve( string, curv) char *string; CURVE *curv; { INDEX i; printf("%s\n",string); printf("form: %d\n",curv->form); if (curv->form) { printf("a2: "); SUMLOOP(i) printf("%lx ",curv->a2.e[i]); printf("\n"); } printf("a6: "); SUMLOOP(i) printf("%lx ",curv->a6.e[i]); printf("\n\n"); } main() { FIELD2N t1, t2, test; FIELD2N q, r, y, x, y2, xy, g[3]; INDEX i, error, j, order, k, m, n; ELEMENT index, check; FILE *del; CURVE crv; POINT p2, p3, p4, p5, p6, p7; char curve_string[80]; /* del = fopen("curves_points_5","w"); if (!del) return(0); */ /* if (!irreducible(&poly_prime)) return(0); print_field("poly_prime = ", &poly_prime); if (error = init_poly_math()) { printf("Can't initialize S matrix, row = %d\n", error); return(-1); } poly_gf8( &poly_prime, g); print_field(" g_0", &g[0]); print_field("g_1", &g[1]); print_field("g_2", &g[2]); /* check solutions actually work */ /* copy (&g[0], &t1); print_field("g[0]", &t1); poly_mul( &g[0], &t1, &t2); print_field("g[0]^2", &t2); poly_mul( &g[0], &t2, &t1); print_field("g[0]^3", &t1); SUMLOOP (i) test.e[i] = g[0].e[i] ^ t1.e[i]; print_field(" one = g[0] + g[0]^3", &test); return; crv.form = 0; null(&crv.a2); null(&crv.a6); /* crv.a2.e[NUMWORD] = 5;*/ /* crv.a6.e[NUMWORD] = 9; null(&test); test.e[NUMWORD] = 5; poly_embed( &test, &crv, NUMWORD, 0, &p2); /* check that point is in fact on curve */ /* copy(&p2.y, &y); copy(&p2.x, &x); print_point("for point", &p2); poly_mul( &p2.y, &y, &y2); poly_mul( &y, &x, &xy); SUMLOOP(i) r.e[i] = y2.e[i] ^ xy.e[i]; poly_fofx( &x, &crv, &q); SUMLOOP(i) test.e[i] = r.e[i] ^ q.e[i]; print_field("rhs + lhs =",&test); /* check that elliptic multiply works */ /* print_point(" base point P", &p2); poly_edbl( &p2, &p3, &crv); print_point(" 2P ", &p3); poly_esum( &p2, &p3, &p4, &crv); print_point(" 3P ", &p4); poly_esum( &p2, &p4, &p5, &crv); print_point(" 4P ", &p5); poly_esum( &p2, &p5, &p6, &crv); print_point(" 5P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point(" 6P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point(" 7P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point(" 8P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point(" 9P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("10P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("11P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("12P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("13P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("14P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("15P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("16P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("17P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("18P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("19P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("20P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("21P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("22P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("23P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("24P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("25P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("26P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("27P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("28P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("29P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("30P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("31P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("32P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("33P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("34P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("35P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("36P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("37P ", &p6); poly_esum( &p2, &p6, &p4, &crv); print_point("38P ", &p4); poly_esum( &p2, &p4, &p6, &crv); print_point("39P ", &p6); for (i=1; i<40; i++) { null( &t1); t1.e[NUMWORD] = i; poly_elptic_mul( &t1, &p2, &p7, &crv); sprintf( curve_string, "%d*P", i); print_point( curve_string, &p7); } scanf("%c",&i); } */