303 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			303 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /* LibTomMath, multiple-precision integer library -- Tom St Denis
 | ||
|  |  * | ||
|  |  * LibTomMath is library that provides for multiple-precision  | ||
|  |  * integer arithmetic as well as number theoretic functionality. | ||
|  |  * | ||
|  |  * This file "poly.c" provides GF(p^k) functionality on top of the  | ||
|  |  * libtommath library. | ||
|  |  *  | ||
|  |  * The library is designed directly after the MPI library by | ||
|  |  * Michael Fromberger but has been written from scratch with  | ||
|  |  * additional optimizations in place.   | ||
|  |  * | ||
|  |  * The library is free for all purposes without any express | ||
|  |  * guarantee it works. | ||
|  |  * | ||
|  |  * Tom St Denis, tomstdenis@iahu.ca, http://libtommath.iahu.ca
 | ||
|  |  */ | ||
|  | #include "poly.h"
 | ||
|  | 
 | ||
|  | #undef MIN
 | ||
|  | #define MIN(x,y) ((x)<(y)?(x):(y))
 | ||
|  | #undef MAX
 | ||
|  | #define MAX(x,y) ((x)>(y)?(x):(y))
 | ||
|  | 
 | ||
|  | static void s_free(mp_poly *a) | ||
|  | { | ||
|  |    int k; | ||
|  |    for (k = 0; k < a->alloc; k++) { | ||
|  |        mp_clear(&(a->co[k])); | ||
|  |    } | ||
|  | } | ||
|  | 
 | ||
|  | static int s_setup(mp_poly *a, int low, int high) | ||
|  | { | ||
|  |    int res, k, j; | ||
|  |    for (k = low; k < high; k++) { | ||
|  |        if ((res = mp_init(&(a->co[k]))) != MP_OKAY) { | ||
|  |           for (j = low; j < k; j++) { | ||
|  |              mp_clear(&(a->co[j])); | ||
|  |           } | ||
|  |           return MP_MEM; | ||
|  |        } | ||
|  |    } | ||
|  |    return MP_OKAY; | ||
|  | }    | ||
|  | 
 | ||
|  | int mp_poly_init(mp_poly *a, mp_int *cha) | ||
|  | { | ||
|  |    return mp_poly_init_size(a, cha, MP_POLY_PREC); | ||
|  | } | ||
|  | 
 | ||
|  | /* init a poly of a given (size) degree */ | ||
|  | int mp_poly_init_size(mp_poly *a, mp_int *cha, int size) | ||
|  | { | ||
|  |    int res; | ||
|  |     | ||
|  |    /* allocate array of mp_ints for coefficients */ | ||
|  |    a->co = malloc(size * sizeof(mp_int)); | ||
|  |    if (a->co == NULL) { | ||
|  |       return MP_MEM; | ||
|  |    } | ||
|  |    a->used  = 0; | ||
|  |    a->alloc = size; | ||
|  |     | ||
|  |    /* now init the range */ | ||
|  |    if ((res = s_setup(a, 0, size)) != MP_OKAY) { | ||
|  |       free(a->co); | ||
|  |       return res; | ||
|  |    } | ||
|  |     | ||
|  |    /* copy characteristic */ | ||
|  |    if ((res = mp_init_copy(&(a->cha), cha)) != MP_OKAY) { | ||
|  |       s_free(a); | ||
|  |       free(a->co); | ||
|  |       return res; | ||
|  |    } | ||
|  |     | ||
|  |    /* return ok at this point */ | ||
|  |    return MP_OKAY; | ||
|  | } | ||
|  | 
 | ||
|  | /* grow the size of a poly */ | ||
|  | static int mp_poly_grow(mp_poly *a, int size) | ||
|  | { | ||
|  |   int res; | ||
|  |    | ||
|  |   if (size > a->alloc) { | ||
|  |      /* resize the array of coefficients */ | ||
|  |      a->co = realloc(a->co, sizeof(mp_int) * size); | ||
|  |      if (a->co == NULL) { | ||
|  |         return MP_MEM; | ||
|  |      } | ||
|  |       | ||
|  |      /* now setup the coefficients */ | ||
|  |      if ((res = s_setup(a, a->alloc, a->alloc + size)) != MP_OKAY) { | ||
|  |         return res; | ||
|  |      } | ||
|  |       | ||
|  |      a->alloc += size; | ||
|  |   } | ||
|  |   return MP_OKAY; | ||
|  | } | ||
|  | 
 | ||
|  | /* copy, b = a */ | ||
|  | int mp_poly_copy(mp_poly *a, mp_poly *b) | ||
|  | { | ||
|  |    int res, k; | ||
|  |     | ||
|  |    /* resize b */ | ||
|  |    if ((res = mp_poly_grow(b, a->used)) != MP_OKAY) { | ||
|  |       return res; | ||
|  |    } | ||
|  |     | ||
|  |    /* now copy the used part */ | ||
|  |    b->used = a->used; | ||
|  |     | ||
|  |    /* now the cha */ | ||
|  |    if ((res = mp_copy(&(a->cha), &(b->cha))) != MP_OKAY) { | ||
|  |       return res; | ||
|  |    } | ||
|  |     | ||
|  |    /* now all the coefficients */ | ||
|  |    for (k = 0; k < b->used; k++) { | ||
|  |        if ((res = mp_copy(&(a->co[k]), &(b->co[k]))) != MP_OKAY) { | ||
|  |           return res; | ||
|  |        } | ||
|  |    } | ||
|  |     | ||
|  |    /* now zero the top */ | ||
|  |    for (k = b->used; k < b->alloc; k++) { | ||
|  |        mp_zero(&(b->co[k])); | ||
|  |    } | ||
|  |     | ||
|  |    return MP_OKAY; | ||
|  | } | ||
|  | 
 | ||
|  | /* init from a copy, a = b */ | ||
|  | int mp_poly_init_copy(mp_poly *a, mp_poly *b) | ||
|  | { | ||
|  |    int res; | ||
|  |     | ||
|  |    if ((res = mp_poly_init(a, &(b->cha))) != MP_OKAY) { | ||
|  |       return res; | ||
|  |    } | ||
|  |    return mp_poly_copy(b, a); | ||
|  | } | ||
|  | 
 | ||
|  | /* free a poly from ram */ | ||
|  | void mp_poly_clear(mp_poly *a) | ||
|  | { | ||
|  |    s_free(a); | ||
|  |    mp_clear(&(a->cha)); | ||
|  |    free(a->co); | ||
|  |     | ||
|  |    a->co = NULL; | ||
|  |    a->used = a->alloc = 0; | ||
|  | } | ||
|  | 
 | ||
|  | /* exchange two polys */ | ||
|  | void mp_poly_exch(mp_poly *a, mp_poly *b) | ||
|  | { | ||
|  |    mp_poly t; | ||
|  |    t = *a; *a = *b; *b = t; | ||
|  | } | ||
|  | 
 | ||
|  | /* clamp the # of used digits */ | ||
|  | static void mp_poly_clamp(mp_poly *a) | ||
|  | { | ||
|  |    while (a->used > 0 && mp_cmp_d(&(a->co[a->used]), 0) == MP_EQ) --(a->used); | ||
|  | }   | ||
|  | 
 | ||
|  | /* add two polynomials, c(x) = a(x) + b(x) */ | ||
|  | int mp_poly_add(mp_poly *a, mp_poly *b, mp_poly *c) | ||
|  | { | ||
|  |    mp_poly t, *x, *y; | ||
|  |    int res, k; | ||
|  |     | ||
|  |    /* ensure char's are the same */ | ||
|  |    if (mp_cmp(&(a->cha), &(b->cha)) != MP_EQ) { | ||
|  |       return MP_VAL; | ||
|  |    } | ||
|  |     | ||
|  |    /* now figure out the sizes such that x is the 
 | ||
|  |       largest degree poly and y is less or equal in degree  | ||
|  |     */ | ||
|  |    if (a->used > b->used) { | ||
|  |       x = a; | ||
|  |       y = b; | ||
|  |    } else { | ||
|  |       x = b; | ||
|  |       y = a; | ||
|  |    } | ||
|  |     | ||
|  |    /* now init the result to be a copy of the largest */ | ||
|  |    if ((res = mp_poly_init_copy(&t, x)) != MP_OKAY) { | ||
|  |       return res; | ||
|  |    } | ||
|  |     | ||
|  |    /* now add the coeffcients of the smaller one */ | ||
|  |    for (k = 0; k < y->used; k++) { | ||
|  |        if ((res = mp_addmod(&(a->co[k]), &(b->co[k]), &(a->cha), &(t.co[k]))) != MP_OKAY) { | ||
|  |           goto __T; | ||
|  |        } | ||
|  |    } | ||
|  |     | ||
|  |    mp_poly_clamp(&t); | ||
|  |    mp_poly_exch(&t, c); | ||
|  |    res = MP_OKAY; | ||
|  |         | ||
|  | __T:  mp_poly_clear(&t); | ||
|  |    return res; | ||
|  | } | ||
|  | 
 | ||
|  | /* subtracts two polynomials, c(x) = a(x) - b(x) */ | ||
|  | int mp_poly_sub(mp_poly *a, mp_poly *b, mp_poly *c) | ||
|  | { | ||
|  |    mp_poly t, *x, *y; | ||
|  |    int res, k; | ||
|  |     | ||
|  |    /* ensure char's are the same */ | ||
|  |    if (mp_cmp(&(a->cha), &(b->cha)) != MP_EQ) { | ||
|  |       return MP_VAL; | ||
|  |    } | ||
|  |     | ||
|  |    /* now figure out the sizes such that x is the 
 | ||
|  |       largest degree poly and y is less or equal in degree  | ||
|  |     */ | ||
|  |    if (a->used > b->used) { | ||
|  |       x = a; | ||
|  |       y = b; | ||
|  |    } else { | ||
|  |       x = b; | ||
|  |       y = a; | ||
|  |    } | ||
|  |     | ||
|  |    /* now init the result to be a copy of the largest */ | ||
|  |    if ((res = mp_poly_init_copy(&t, x)) != MP_OKAY) { | ||
|  |       return res; | ||
|  |    } | ||
|  |     | ||
|  |    /* now add the coeffcients of the smaller one */ | ||
|  |    for (k = 0; k < y->used; k++) { | ||
|  |        if ((res = mp_submod(&(a->co[k]), &(b->co[k]), &(a->cha), &(t.co[k]))) != MP_OKAY) { | ||
|  |           goto __T; | ||
|  |        } | ||
|  |    } | ||
|  |     | ||
|  |    mp_poly_clamp(&t); | ||
|  |    mp_poly_exch(&t, c); | ||
|  |    res = MP_OKAY; | ||
|  |         | ||
|  | __T:  mp_poly_clear(&t); | ||
|  |    return res; | ||
|  | } | ||
|  | 
 | ||
|  | /* multiplies two polynomials, c(x) = a(x) * b(x) */ | ||
|  | int mp_poly_mul(mp_poly *a, mp_poly *b, mp_poly *c) | ||
|  | { | ||
|  |    mp_poly t; | ||
|  |    mp_int  tt; | ||
|  |    int res, pa, pb, ix, iy; | ||
|  |     | ||
|  |    /* ensure char's are the same */ | ||
|  |    if (mp_cmp(&(a->cha), &(b->cha)) != MP_EQ) { | ||
|  |       return MP_VAL; | ||
|  |    } | ||
|  |     | ||
|  |    /* degrees of a and b */ | ||
|  |    pa = a->used; | ||
|  |    pb = b->used; | ||
|  |     | ||
|  |    /* now init the temp polynomial to be of degree pa+pb */ | ||
|  |    if ((res = mp_poly_init_size(&t, &(a->cha), pa+pb)) != MP_OKAY) { | ||
|  |       return res; | ||
|  |    } | ||
|  |     | ||
|  |    /* now init our temp int */ | ||
|  |    if ((res = mp_init(&tt)) != MP_OKAY) { | ||
|  |       goto __T; | ||
|  |    } | ||
|  |     | ||
|  |    /* now loop through all the digits */ | ||
|  |    for (ix = 0; ix < pa; ix++) { | ||
|  |        for (iy = 0; iy < pb; iy++) { | ||
|  |           if ((res = mp_mul(&(a->co[ix]), &(b->co[iy]), &tt)) != MP_OKAY) { | ||
|  |              goto __TT; | ||
|  |           } | ||
|  |           if ((res = mp_addmod(&tt, &(t.co[ix+iy]), &(a->cha), &(t.co[ix+iy]))) != MP_OKAY) { | ||
|  |              goto __TT; | ||
|  |           } | ||
|  |        } | ||
|  |    } | ||
|  |     | ||
|  |    mp_poly_clamp(&t); | ||
|  |    mp_poly_exch(&t, c); | ||
|  |    res = MP_OKAY; | ||
|  |     | ||
|  | __TT: mp_clear(&tt); | ||
|  | __T:  mp_poly_clear(&t); | ||
|  |    return res; | ||
|  | } | ||
|  | 
 |