/** Add two ECC points @param P The point to add @param Q The point to add @param R [out] The destination of the double @param modulus The modulus of the field the ECC curve is in @param mp The "b" value from montgomery_setup() @return CRYPT_OK on success */ static int tfm_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *Mp) { fp_int t1, t2, x, y, z; fp_digit mp; LTC_ARGCHK(P != NULL); LTC_ARGCHK(Q != NULL); LTC_ARGCHK(R != NULL); LTC_ARGCHK(modulus != NULL); LTC_ARGCHK(Mp != NULL); mp = *((fp_digit*)Mp); fp_init(&t1); fp_init(&t2); fp_init(&x); fp_init(&y); fp_init(&z); /* should we dbl instead? */ fp_sub(modulus, Q->y, &t1); if ( (fp_cmp(P->x, Q->x) == FP_EQ) && (Q->z != NULL && fp_cmp(P->z, Q->z) == FP_EQ) && (fp_cmp(P->y, Q->y) == FP_EQ || fp_cmp(P->y, &t1) == FP_EQ)) { return tfm_ecc_projective_dbl_point(P, R, modulus, Mp); } fp_copy(P->x, &x); fp_copy(P->y, &y); fp_copy(P->z, &z); /* if Z is one then these are no-operations */ if (Q->z != NULL) { /* T1 = Z' * Z' */ fp_sqr(Q->z, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* X = X * T1 */ fp_mul(&t1, &x, &x); fp_montgomery_reduce(&x, modulus, mp); /* T1 = Z' * T1 */ fp_mul(Q->z, &t1, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* Y = Y * T1 */ fp_mul(&t1, &y, &y); fp_montgomery_reduce(&y, modulus, mp); } /* T1 = Z*Z */ fp_sqr(&z, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* T2 = X' * T1 */ fp_mul(Q->x, &t1, &t2); fp_montgomery_reduce(&t2, modulus, mp); /* T1 = Z * T1 */ fp_mul(&z, &t1, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* T1 = Y' * T1 */ fp_mul(Q->y, &t1, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* Y = Y - T1 */ fp_sub(&y, &t1, &y); if (fp_cmp_d(&y, 0) == FP_LT) { fp_add(&y, modulus, &y); } /* T1 = 2T1 */ fp_add(&t1, &t1, &t1); if (fp_cmp(&t1, modulus) != FP_LT) { fp_sub(&t1, modulus, &t1); } /* T1 = Y + T1 */ fp_add(&t1, &y, &t1); if (fp_cmp(&t1, modulus) != FP_LT) { fp_sub(&t1, modulus, &t1); } /* X = X - T2 */ fp_sub(&x, &t2, &x); if (fp_cmp_d(&x, 0) == FP_LT) { fp_add(&x, modulus, &x); } /* T2 = 2T2 */ fp_add(&t2, &t2, &t2); if (fp_cmp(&t2, modulus) != FP_LT) { fp_sub(&t2, modulus, &t2); } /* T2 = X + T2 */ fp_add(&t2, &x, &t2); if (fp_cmp(&t2, modulus) != FP_LT) { fp_sub(&t2, modulus, &t2); } /* if Z' != 1 */ if (Q->z != NULL) { /* Z = Z * Z' */ fp_mul(&z, Q->z, &z); fp_montgomery_reduce(&z, modulus, mp); } /* Z = Z * X */ fp_mul(&z, &x, &z); fp_montgomery_reduce(&z, modulus, mp); /* T1 = T1 * X */ fp_mul(&t1, &x, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* X = X * X */ fp_sqr(&x, &x); fp_montgomery_reduce(&x, modulus, mp); /* T2 = T2 * x */ fp_mul(&t2, &x, &t2); fp_montgomery_reduce(&t2, modulus, mp); /* T1 = T1 * X */ fp_mul(&t1, &x, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* X = Y*Y */ fp_sqr(&y, &x); fp_montgomery_reduce(&x, modulus, mp); /* X = X - T2 */ fp_sub(&x, &t2, &x); if (fp_cmp_d(&x, 0) == FP_LT) { fp_add(&x, modulus, &x); } /* T2 = T2 - X */ fp_sub(&t2, &x, &t2); if (fp_cmp_d(&t2, 0) == FP_LT) { fp_add(&t2, modulus, &t2); } /* T2 = T2 - X */ fp_sub(&t2, &x, &t2); if (fp_cmp_d(&t2, 0) == FP_LT) { fp_add(&t2, modulus, &t2); } /* T2 = T2 * Y */ fp_mul(&t2, &y, &t2); fp_montgomery_reduce(&t2, modulus, mp); /* Y = T2 - T1 */ fp_sub(&t2, &t1, &y); if (fp_cmp_d(&y, 0) == FP_LT) { fp_add(&y, modulus, &y); } /* Y = Y/2 */ if (fp_isodd(&y)) { fp_add(&y, modulus, &y); } fp_div_2(&y, &y); fp_copy(&x, R->x); fp_copy(&y, R->y); fp_copy(&z, R->z); return CRYPT_OK; }
/* c = 1/a (mod b) for odd b only */ int fp_invmod(fp_int *a, fp_int *b, fp_int *c) { fp_int x, y, u, v, B, D; int neg; /* 2. [modified] b must be odd */ if (fp_iseven (b) == FP_YES) { return fp_invmod_slow(a,b,c); } /* init all our temps */ fp_init(&x); fp_init(&y); fp_init(&u); fp_init(&v); fp_init(&B); fp_init(&D); /* x == modulus, y == value to invert */ fp_copy(b, &x); /* we need y = |a| */ fp_abs(a, &y); /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ fp_copy(&x, &u); fp_copy(&y, &v); fp_set (&D, 1); top: /* 4. while u is even do */ while (fp_iseven (&u) == FP_YES) { /* 4.1 u = u/2 */ fp_div_2 (&u, &u); /* 4.2 if B is odd then */ if (fp_isodd (&B) == FP_YES) { fp_sub (&B, &x, &B); } /* B = B/2 */ fp_div_2 (&B, &B); } /* 5. while v is even do */ while (fp_iseven (&v) == FP_YES) { /* 5.1 v = v/2 */ fp_div_2 (&v, &v); /* 5.2 if D is odd then */ if (fp_isodd (&D) == FP_YES) { /* D = (D-x)/2 */ fp_sub (&D, &x, &D); } /* D = D/2 */ fp_div_2 (&D, &D); } /* 6. if u >= v then */ if (fp_cmp (&u, &v) != FP_LT) { /* u = u - v, B = B - D */ fp_sub (&u, &v, &u); fp_sub (&B, &D, &B); } else { /* v - v - u, D = D - B */ fp_sub (&v, &u, &v); fp_sub (&D, &B, &D); } /* if not zero goto step 4 */ if (fp_iszero (&u) == FP_NO) { goto top; } /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (fp_cmp_d (&v, 1) != FP_EQ) { return FP_VAL; } /* b is now the inverse */ neg = a->sign; while (D.sign == FP_NEG) { fp_add (&D, b, &D); } fp_copy (&D, c); c->sign = neg; return FP_OKAY; }
static int tfm_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *Mp) { fp_int t1, t2; fp_digit mp; LTC_ARGCHK(P != NULL); LTC_ARGCHK(R != NULL); LTC_ARGCHK(modulus != NULL); LTC_ARGCHK(Mp != NULL); mp = *((fp_digit*)Mp); fp_init(&t1); fp_init(&t2); if (P != R) { fp_copy(P->x, R->x); fp_copy(P->y, R->y); fp_copy(P->z, R->z); } /* t1 = Z * Z */ fp_sqr(R->z, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* Z = Y * Z */ fp_mul(R->z, R->y, R->z); fp_montgomery_reduce(R->z, modulus, mp); /* Z = 2Z */ fp_add(R->z, R->z, R->z); if (fp_cmp(R->z, modulus) != FP_LT) { fp_sub(R->z, modulus, R->z); } /* &t2 = X - T1 */ fp_sub(R->x, &t1, &t2); if (fp_cmp_d(&t2, 0) == FP_LT) { fp_add(&t2, modulus, &t2); } /* T1 = X + T1 */ fp_add(&t1, R->x, &t1); if (fp_cmp(&t1, modulus) != FP_LT) { fp_sub(&t1, modulus, &t1); } /* T2 = T1 * T2 */ fp_mul(&t1, &t2, &t2); fp_montgomery_reduce(&t2, modulus, mp); /* T1 = 2T2 */ fp_add(&t2, &t2, &t1); if (fp_cmp(&t1, modulus) != FP_LT) { fp_sub(&t1, modulus, &t1); } /* T1 = T1 + T2 */ fp_add(&t1, &t2, &t1); if (fp_cmp(&t1, modulus) != FP_LT) { fp_sub(&t1, modulus, &t1); } /* Y = 2Y */ fp_add(R->y, R->y, R->y); if (fp_cmp(R->y, modulus) != FP_LT) { fp_sub(R->y, modulus, R->y); } /* Y = Y * Y */ fp_sqr(R->y, R->y); fp_montgomery_reduce(R->y, modulus, mp); /* T2 = Y * Y */ fp_sqr(R->y, &t2); fp_montgomery_reduce(&t2, modulus, mp); /* T2 = T2/2 */ if (fp_isodd(&t2)) { fp_add(&t2, modulus, &t2); } fp_div_2(&t2, &t2); /* Y = Y * X */ fp_mul(R->y, R->x, R->y); fp_montgomery_reduce(R->y, modulus, mp); /* X = T1 * T1 */ fp_sqr(&t1, R->x); fp_montgomery_reduce(R->x, modulus, mp); /* X = X - Y */ fp_sub(R->x, R->y, R->x); if (fp_cmp_d(R->x, 0) == FP_LT) { fp_add(R->x, modulus, R->x); } /* X = X - Y */ fp_sub(R->x, R->y, R->x); if (fp_cmp_d(R->x, 0) == FP_LT) { fp_add(R->x, modulus, R->x); } /* Y = Y - X */ fp_sub(R->y, R->x, R->y); if (fp_cmp_d(R->y, 0) == FP_LT) { fp_add(R->y, modulus, R->y); } /* Y = Y * T1 */ fp_mul(R->y, &t1, R->y); fp_montgomery_reduce(R->y, modulus, mp); /* Y = Y - T2 */ fp_sub(R->y, &t2, R->y); if (fp_cmp_d(R->y, 0) == FP_LT) { fp_add(R->y, modulus, R->y); } return CRYPT_OK; }
static int fp_invmod_slow (fp_int * a, fp_int * b, fp_int * c) { fp_int x, y, u, v, A, B, C, D; int res; /* b cannot be negative */ if (b->sign == FP_NEG || fp_iszero(b) == 1) { return FP_VAL; } /* init temps */ fp_init(&x); fp_init(&y); fp_init(&u); fp_init(&v); fp_init(&A); fp_init(&B); fp_init(&C); fp_init(&D); /* x = a, y = b */ if ((res = fp_mod(a, b, &x)) != FP_OKAY) { return res; } fp_copy(b, &y); /* 2. [modified] if x,y are both even then return an error! */ if (fp_iseven (&x) == 1 && fp_iseven (&y) == 1) { return FP_VAL; } /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ fp_copy (&x, &u); fp_copy (&y, &v); fp_set (&A, 1); fp_set (&D, 1); top: /* 4. while u is even do */ while (fp_iseven (&u) == 1) { /* 4.1 u = u/2 */ fp_div_2 (&u, &u); /* 4.2 if A or B is odd then */ if (fp_isodd (&A) == 1 || fp_isodd (&B) == 1) { /* A = (A+y)/2, B = (B-x)/2 */ fp_add (&A, &y, &A); fp_sub (&B, &x, &B); } /* A = A/2, B = B/2 */ fp_div_2 (&A, &A); fp_div_2 (&B, &B); } /* 5. while v is even do */ while (fp_iseven (&v) == 1) { /* 5.1 v = v/2 */ fp_div_2 (&v, &v); /* 5.2 if C or D is odd then */ if (fp_isodd (&C) == 1 || fp_isodd (&D) == 1) { /* C = (C+y)/2, D = (D-x)/2 */ fp_add (&C, &y, &C); fp_sub (&D, &x, &D); } /* C = C/2, D = D/2 */ fp_div_2 (&C, &C); fp_div_2 (&D, &D); } /* 6. if u >= v then */ if (fp_cmp (&u, &v) != FP_LT) { /* u = u - v, A = A - C, B = B - D */ fp_sub (&u, &v, &u); fp_sub (&A, &C, &A); fp_sub (&B, &D, &B); } else { /* v - v - u, C = C - A, D = D - B */ fp_sub (&v, &u, &v); fp_sub (&C, &A, &C); fp_sub (&D, &B, &D); } /* if not zero goto step 4 */ if (fp_iszero (&u) == 0) goto top; /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (fp_cmp_d (&v, 1) != FP_EQ) { return FP_VAL; } /* if its too low */ while (fp_cmp_d(&C, 0) == FP_LT) { fp_add(&C, b, &C); } /* too big */ while (fp_cmp_mag(&C, b) != FP_LT) { fp_sub(&C, b, &C); } /* C is now the inverse */ fp_copy(&C, c); return FP_OKAY; }