static int mpr_docmp(mpr *op1, mpr *op2, int sign) { int cmp, neg; mpi prod1, prod2; neg = 0; if (sign) { /* if op1 is negative */ if (mpr_num(op1)->sign ^ mpr_den(op1)->sign) { /* if op2 is positive */ if (!(mpr_num(op2)->sign ^ mpr_den(op2)->sign)) return (-1); else neg = 1; } /* if op2 is negative */ else if (mpr_num(op2)->sign ^ mpr_den(op2)->sign) return (1); /* else same sign */ } /* if denominators are equal, compare numerators */ if (mpi_cmpabs(mpr_den(op1), mpr_den(op2)) == 0) { cmp = mpi_cmpabs(mpr_num(op1), mpr_num(op2)); if (cmp == 0) return (0); if (sign && neg) return (cmp < 0 ? 1 : -1); return (cmp); } memset(&prod1, '\0', sizeof(mpi)); memset(&prod2, '\0', sizeof(mpi)); /* "divide" op1 by op2 * if result is smaller than 1, op1 is smaller than op2 */ mpi_mul(&prod1, mpr_num(op1), mpr_den(op2)); mpi_mul(&prod2, mpr_num(op2), mpr_den(op1)); cmp = mpi_cmpabs(&prod1, &prod2); mpi_clear(&prod1); mpi_clear(&prod2); if (sign && neg) return (cmp < 0 ? 1 : -1); return (cmp); }
void mpr_subi(mpr *rop, mpr *op1, long op2) { mpi prod; memset(&prod, '\0', sizeof(mpi)); mpi_muli(&prod, mpr_den(op1), op2); mpi_sub(mpr_num(rop), mpr_num(op1), &prod); mpi_clear(&prod); }
static void mpr_addsub(mpr *rop, mpr *op1, mpr *op2, int sub) { mpi prod1, prod2; memset(&prod1, '\0', sizeof(mpi)); memset(&prod2, '\0', sizeof(mpi)); mpi_mul(&prod1, mpr_num(op1), mpr_den(op2)); mpi_mul(&prod2, mpr_num(op2), mpr_den(op1)); if (sub) mpi_sub(mpr_num(rop), &prod1, &prod2); else mpi_add(mpr_num(rop), &prod1, &prod2); mpi_clear(&prod1); mpi_clear(&prod2); mpi_mul(mpr_den(rop), mpr_den(op1), mpr_den(op2)); }
/* Set the projective coordinates from X, Y, and Z into POINT. If a coordinate is given as NULL, the value 0 is stored into point. If POINT is given as NULL a new point object is allocated. The coordinates X, Y, and Z are released. Returns POINT or the newly allocated point object. */ mpi_point_t gcry_mpi_point_snatch_set (mpi_point_t point, gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z) { if (!point) point = gcry_mpi_point_new (0); if (x) mpi_snatch (point->x, x); else mpi_clear (point->x); if (y) mpi_snatch (point->y, y); else mpi_clear (point->y); if (z) mpi_snatch (point->z, z); else mpi_clear (point->z); return point; }
void mpr_div(mpr *rop, mpr *op1, mpr *op2) { /* check if temporary storage is required */ if (op1 == op2 && rop == op1) { mpi prod; memset(&prod, '\0', sizeof(mpi)); mpi_mul(&prod, mpr_num(op1), mpr_den(op2)); mpi_mul(mpr_den(rop), mpr_num(op2), mpr_den(op1)); mpi_set(mpr_num(rop), &prod); mpi_clear(&prod); } else { mpi_mul(mpr_num(rop), mpr_num(op1), mpr_den(op2)); mpi_mul(mpr_den(rop), mpr_num(op2), mpr_den(op1)); } }
void mpr_canonicalize(mpr *op) { mpi gcd; memset(&gcd, '\0', sizeof(mpi)); mpi_gcd(&gcd, mpr_num(op), mpr_den(op)); if (mpi_cmpabsi(&gcd, 1)) { mpi_div(mpr_num(op), mpr_num(op), &gcd); mpi_div(mpr_den(op), mpr_den(op), &gcd); } if (op->den.sign) { op->num.sign = !op->num.sign; op->den.sign = 0; } mpi_clear(&gcd); }
/* Scalar point multiplication - the main function for ECC. If takes an integer SCALAR and a POINT as well as the usual context CTX. RESULT will be set to the resulting point. */ void _gcry_mpi_ec_mul_point (mpi_point_t result, gcry_mpi_t scalar, mpi_point_t point, mpi_ec_t ctx) { #if 0 /* Simple left to right binary method. GECC Algorithm 3.27 */ unsigned int nbits; int i; nbits = mpi_get_nbits (scalar); mpi_set_ui (result->x, 1); mpi_set_ui (result->y, 1); mpi_set_ui (result->z, 0); for (i=nbits-1; i >= 0; i--) { _gcry_mpi_ec_dup_point (result, result, ctx); if (mpi_test_bit (scalar, i) == 1) _gcry_mpi_ec_add_points (result, result, point, ctx); } #else gcry_mpi_t x1, y1, z1, k, h, yy; unsigned int i, loops; mpi_point_struct p1, p2, p1inv; x1 = mpi_alloc_like (ctx->p); y1 = mpi_alloc_like (ctx->p); h = mpi_alloc_like (ctx->p); k = mpi_copy (scalar); yy = mpi_copy (point->y); if ( mpi_is_neg (k) ) { k->sign = 0; ec_invm (yy, yy, ctx); } if (!mpi_cmp_ui (point->z, 1)) { mpi_set (x1, point->x); mpi_set (y1, yy); } else { gcry_mpi_t z2, z3; z2 = mpi_alloc_like (ctx->p); z3 = mpi_alloc_like (ctx->p); ec_mulm (z2, point->z, point->z, ctx); ec_mulm (z3, point->z, z2, ctx); ec_invm (z2, z2, ctx); ec_mulm (x1, point->x, z2, ctx); ec_invm (z3, z3, ctx); ec_mulm (y1, yy, z3, ctx); mpi_free (z2); mpi_free (z3); } z1 = mpi_copy (mpi_const (MPI_C_ONE)); mpi_mul (h, k, mpi_const (MPI_C_THREE)); /* h = 3k */ loops = mpi_get_nbits (h); if (loops < 2) { /* If SCALAR is zero, the above mpi_mul sets H to zero and thus LOOPs will be zero. To avoid an underflow of I in the main loop we set LOOP to 2 and the result to (0,0,0). */ loops = 2; mpi_clear (result->x); mpi_clear (result->y); mpi_clear (result->z); } else { mpi_set (result->x, point->x); mpi_set (result->y, yy); mpi_set (result->z, point->z); } mpi_free (yy); yy = NULL; p1.x = x1; x1 = NULL; p1.y = y1; y1 = NULL; p1.z = z1; z1 = NULL; point_init (&p2); point_init (&p1inv); for (i=loops-2; i > 0; i--) { _gcry_mpi_ec_dup_point (result, result, ctx); if (mpi_test_bit (h, i) == 1 && mpi_test_bit (k, i) == 0) { point_set (&p2, result); _gcry_mpi_ec_add_points (result, &p2, &p1, ctx); } if (mpi_test_bit (h, i) == 0 && mpi_test_bit (k, i) == 1) { point_set (&p2, result); /* Invert point: y = p - y mod p */ point_set (&p1inv, &p1); ec_subm (p1inv.y, ctx->p, p1inv.y, ctx); _gcry_mpi_ec_add_points (result, &p2, &p1inv, ctx); } } point_free (&p1); point_free (&p2); point_free (&p1inv); mpi_free (h); mpi_free (k); #endif }
int mpi_fromstr(MPI val, const char *str) { int hexmode = 0, sign = 0, prepend_zero = 0, i, j, c, c1, c2; unsigned nbits, nbytes, nlimbs; mpi_limb_t a; if (*str == '-') { sign = 1; str++; } if (*str == '0' && str[1] == 'x') hexmode = 1; else return -EINVAL; str += 2; nbits = strlen(str) * 4; if (nbits % 8) prepend_zero = 1; nbytes = (nbits + 7) / 8; nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; if (val->alloced < nlimbs) if (!mpi_resize(val, nlimbs)) return -ENOMEM; i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; i %= BYTES_PER_MPI_LIMB; j = val->nlimbs = nlimbs; val->sign = sign; for (; j > 0; j--) { a = 0; for (; i < BYTES_PER_MPI_LIMB; i++) { if (prepend_zero) { c1 = '0'; prepend_zero = 0; } else c1 = *str++; assert(c1); c2 = *str++; assert(c2); if (c1 >= '0' && c1 <= '9') c = c1 - '0'; else if (c1 >= 'a' && c1 <= 'f') c = c1 - 'a' + 10; else if (c1 >= 'A' && c1 <= 'F') c = c1 - 'A' + 10; else { mpi_clear(val); return 1; } c <<= 4; if (c2 >= '0' && c2 <= '9') c |= c2 - '0'; else if (c2 >= 'a' && c2 <= 'f') c |= c2 - 'a' + 10; else if (c2 >= 'A' && c2 <= 'F') c |= c2 - 'A' + 10; else { mpi_clear(val); return 1; } a <<= 8; a |= c; } i = 0; val->d[j - 1] = a; } return 0; }
/**************** * Fill the mpi VAL from the hex string in STR. */ static int mpi_fromstr (gcry_mpi_t val, const char *str) { int sign = 0; int prepend_zero = 0; int i, j, c, c1, c2; unsigned int nbits, nbytes, nlimbs; mpi_limb_t a; if ( *str == '-' ) { sign = 1; str++; } /* Skip optional hex prefix. */ if ( *str == '0' && str[1] == 'x' ) str += 2; nbits = 4 * strlen (str); if ((nbits % 8)) prepend_zero = 1; nbytes = (nbits+7) / 8; nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; if ( val->alloced < nlimbs ) mpi_resize (val, nlimbs); i = BYTES_PER_MPI_LIMB - (nbytes % BYTES_PER_MPI_LIMB); i %= BYTES_PER_MPI_LIMB; j = val->nlimbs = nlimbs; val->sign = sign; for (; j > 0; j--) { a = 0; for (; i < BYTES_PER_MPI_LIMB; i++) { if (prepend_zero) { c1 = '0'; prepend_zero = 0; } else c1 = *str++; if (!c1) { mpi_clear (val); return 1; /* Error. */ } c2 = *str++; if (!c2) { mpi_clear (val); return 1; /* Error. */ } if ( c1 >= '0' && c1 <= '9' ) c = c1 - '0'; else if ( c1 >= 'a' && c1 <= 'f' ) c = c1 - 'a' + 10; else if ( c1 >= 'A' && c1 <= 'F' ) c = c1 - 'A' + 10; else { mpi_clear (val); return 1; /* Error. */ } c <<= 4; if ( c2 >= '0' && c2 <= '9' ) c |= c2 - '0'; else if( c2 >= 'a' && c2 <= 'f' ) c |= c2 - 'a' + 10; else if( c2 >= 'A' && c2 <= 'F' ) c |= c2 - 'A' + 10; else { mpi_clear(val); return 1; /* Error. */ } a <<= 8; a |= c; } i = 0; val->d[j-1] = a; } return 0; /* Okay. */ }