END_TEST /* Random unit test for ec_mul and ec_add */ START_TEST (test_random_addmul) { FF_NUM a, b, c; EC_POINT P, Q, R, T1, T2; for (int passes = 0; passes < 10; ++passes) { ff_rand (&a, &ec_n); ff_rand (&b, &ec_n); ff_add (&c, &a, &b, &ec_n); ec_mul (&P, &a, &ec_G); ec_mul (&Q, &b, &ec_G); ec_mul (&R, &c, &ec_G); ec_add (&T1, &P, &Q); ec_add (&T2, &Q, &P); if (ff_compare (&(T1.x), &(R.x)) != 0 || ff_compare (&(T1.y), &(R.y)) != 0 || ff_compare (&(T2.x), &(R.x)) != 0 || ff_compare (&(T2.y), &(R.y)) != 0) { printf ("a: "); print_ff (&a); printf ("\nb: "); print_ff (&b); printf ("\nc: "); print_ff (&c); printf ("\nP: 04"); print_ff (&(P.x)); print_ff (&(P.y)); printf ("\nQ: 04"); print_ff (&(Q.x)); print_ff (&(Q.y)); printf ("\nR: 04"); print_ff (&(R.x)); print_ff (&(R.y)); printf ("\nT1: 04"); print_ff (&(T1.x)); print_ff (&(T1.y)); printf ("\nT2: 04"); print_ff (&(T2.x)); print_ff (&(T2.y)); printf ("\n"); return "If c = a + b is true then the following should be true: aG + bG == cG and bG + aG == cG."; } } }
BCW_API hd_private_key hd_private_key::generate_private_key(uint32_t i) const { if (!valid_) return hd_private_key(); data_chunk data; data.reserve(33 + 4); if (first_hardened_key <= i) { data.push_back(0x00); extend_data(data, k_); extend_data(data, to_big_endian(i)); } else { extend_data(data, K_); extend_data(data, to_big_endian(i)); } auto I = split(hmac_sha512_hash(data, to_data_chunk(c_))); // The child key ki is (parse256(IL) + kpar) mod n: ec_secret ki = k_; if (!ec_add(ki, I.L)) return hd_private_key(); hd_key_lineage lineage { lineage_.testnet, static_cast<uint8_t>(lineage_.depth + 1), fingerprint(), i }; return hd_private_key(ki, I.R, lineage); }
hd_private_key hd_private_key::generate_private_key(uint32_t i) const { if (!valid_) return hd_private_key(); data_chunk data; if (first_hardened_key <= i) data = build_data({to_byte(0x00), k_, to_big_endian(i)}); else data = build_data({K_, to_big_endian(i)}); const auto I = split(hmac_sha512_hash(data, c_)); // The child key ki is (parse256(IL) + kpar) mod n: ec_secret ki = k_; if (!ec_add(ki, I.L)) return hd_private_key(); hd_key_lineage lineage { lineage_.testnet, static_cast<uint8_t>(lineage_.depth + 1), fingerprint(), i }; return hd_private_key(ki, I.R, lineage); }
void sccd_ec_add(sccd_ec_t result, const sccd_ec_t a, const sccd_ec_t b) { #if defined(SCCD_BACKEND_C25519) ed25519_add(result, a, b); #elif defined(SCCD_BACKEND_RELIC) ec_add(result, a, b); #endif }
void ec_multiply (ec_point *p, const vl_point k) /* sets p := k*p */ { vl_point h; int z, hi, ki; word16 i; ec_point r; gf_copy (r.x, p->x); p->x[0] = 0; gf_copy (r.y, p->y); p->y[0] = 0; vl_shortmultiply (h, k, 3); z = vl_numbits (h) - 1; /* so vl_takebit (h, z) == 1 */ i = 1; for (;;) { hi = vl_takebit (h, i); ki = vl_takebit (k, i); if (hi == 1 && ki == 0) { ec_add (p, &r); } if (hi == 0 && ki == 1) { ec_sub (p, &r); } if (i >= z) { break; } i++; ec_double (&r); } } /* ec_multiply */
void ec_sub (ec_point *p, const ec_point *r) /* sets p := p - r */ { ec_point t; gf_copy (t.x, r->x); gf_add (t.y, r->x, r->y); ec_add (p, &t); } /* ec_sub */
int main() { ec_point x, y, z; mpl_int p, a; char buf[80]; if (ec_initv(&x, &y, &z, NULL) != MPL_OK) { printf("can't init points"); return 1; } if (mpl_initv(&p, &a, NULL) != MPL_OK) { printf("can't init ints\n"); goto err_init; } mpl_set_sint(&(x.x), XX); mpl_set_sint(&(x.y), XY); mpl_set_sint(&(y.x), YX); mpl_set_sint(&(y.y), YY); mpl_set_sint(&p, 5); mpl_set_sint(&a, 4); if (ec_add(&z, &x, &y, &a, &p) != MPL_OK) { printf("addition error\n"); goto error; } printf("(%i,%i) + (%i,%i) = ", XX, XY, YX, YY); if (mpl_to_str(&(z.x), buf, 10, 80) != MPL_OK) { printf("can't convert mpl_int\n"); goto error; } printf("(%s,", buf); if (mpl_to_str(&(z.y), buf, 10, 80) != MPL_OK) { printf("can't convert mpl_int\n"); goto error; } printf("%s)\n", buf); error: mpl_clearv(&p, &a, NULL); err_init: ec_clearv(&x, &y, &z, NULL); return 0; }
void ecc_ec_mult(const uint32_t *px, const uint32_t *py, const uint32_t *secret, uint32_t *resultx, uint32_t *resulty){ uint32_t Qx[8]; uint32_t Qy[8]; setZero(Qx, 8); setZero(Qy, 8); uint32_t tempx[8]; uint32_t tempy[8]; int i; for (i = 256;i--;){ ec_double(Qx, Qy, tempx, tempy); copy(tempx, Qx,arrayLength); copy(tempy, Qy,arrayLength); if (((secret[i / 32]) & ((uint32_t)1 << (i % 32)))) { ec_add(Qx, Qy, px, py, tempx, tempy); //eccAdd copy(tempx, Qx,arrayLength); copy(tempy, Qy,arrayLength); } } copy(Qx, resultx,arrayLength); copy(Qy, resulty,arrayLength); }
hd_public_key hd_public_key::generate_public_key(uint32_t i) const { if (!valid_) return hd_private_key(); if (first_hardened_key <= i) return hd_public_key(); auto data = build_data({K_, to_big_endian(i)}); const auto I = split(hmac_sha512_hash(data, c_)); // The returned child key Ki is point(parse256(IL)) + Kpar. ec_point Ki = K_; if (!ec_add(Ki, I.L)) return hd_public_key(); hd_key_lineage lineage { lineage_.testnet, static_cast<uint8_t>(lineage_.depth + 1), fingerprint(), i }; return hd_public_key(Ki, I.R, lineage); }
/** * Verifies a ecdsa signature. * * For a description of this algorithm see * https://en.wikipedia.org/wiki/Elliptic_Curve_DSA#Signature_verification_algorithm * * input: * x: x coordinate of the public key (32 bytes) * y: y coordinate of the public key (32 bytes) * e: hash to verify the signature of (32 bytes) * r: r value of the signature (32 bytes) * s: s value of the signature (32 bytes) * * return: * 0: signature is ok * -1: signature check failed the signature is invalid */ int ecc_ecdsa_validate(const uint32_t *x, const uint32_t *y, const uint32_t *e, const uint32_t *r, const uint32_t *s) { uint32_t w[8]; uint32_t tmp[16]; uint32_t u1[9]; uint32_t u2[9]; uint32_t tmp1_x[8]; uint32_t tmp1_y[8]; uint32_t tmp2_x[8]; uint32_t tmp2_y[8]; uint32_t tmp3_x[8]; uint32_t tmp3_y[8]; // 3. Calculate w = s^{-1} \pmod{n} fieldInv(s, ecc_order_m, ecc_order_r, w); // 4. Calculate u_1 = zw \pmod{n} fieldMult(e, w, tmp, arrayLength); fieldModO(tmp, u1, 16); // 4. Calculate u_2 = rw \pmod{n} fieldMult(r, w, tmp, arrayLength); fieldModO(tmp, u2, 16); // 5. Calculate the curve point (x_1, y_1) = u_1 * G + u_2 * Q_A. // tmp1 = u_1 * G ecc_ec_mult(ecc_g_point_x, ecc_g_point_y, u1, tmp1_x, tmp1_y); // tmp2 = u_2 * Q_A ecc_ec_mult(x, y, u2, tmp2_x, tmp2_y); // tmp3 = tmp1 + tmp2 ec_add(tmp1_x, tmp1_y, tmp2_x, tmp2_y, tmp3_x, tmp3_y); // TODO: this u_1 * G + u_2 * Q_A could be optimiced with Straus's algorithm. return isSame(tmp3_x, r, arrayLength) ? 0 : -1; }
void ecc_ec_add(const uint32_t *px, const uint32_t *py, const uint32_t *qx, const uint32_t *qy, uint32_t *Sx, uint32_t *Sy) { ec_add(px, py, qx, qy, Sx, Sy); }
int ecpp_test(unsigned long n) { mpz_t a, b, x0, y0, xt, yt, tmp; int z; int is_prime = 0; if (n <= USHRT_MAX) { return sieve_test(n); } mpz_init(a); mpz_init(b); mpz_init(x0); mpz_init(y0); mpz_init(xt); mpz_init(yt); mpz_init(tmp); #ifdef DEBUG gmp_fprintf(stderr, "\nTesting %d with ECPP...\n", n); #endif /* DEBUG */ for (;;) /* keep trying while the curve order factoring fails */ { for (;;) /* keep trying while n divides curve discriminant */ { /* initialise a random point P = (x0, y0) * and a random elliptic curve E(a, b): y^2 = x^3 + a*x + b * with b expressed in terms of (a, x0, y0) so the point lies on the curve */ mpz_set_ui(a, rand() % n); mpz_set_ui(x0, rand() % n); mpz_set_ui(y0, rand() % n); mpz_init(b); mpz_mul(b, y0, y0); mpz_mul(tmp, x0, x0); mpz_submul(b, tmp, x0); mpz_submul(b, a, x0); mpz_mod_ui(b, b, n); #ifdef DEBUG gmp_fprintf(stderr, "\n\tn = %d\n", n); gmp_fprintf(stderr, "\tE: y^2 = x^3 + %Zd * x + %Zd\n", a, b); gmp_fprintf(stderr, "\tP = (%Zd,%Zd,1)\n", x0, y0); #endif /* DEBUG */ /* the discriminant of the curve and n are required to be coprimes * -- if not, then either * A) n divides the discriminant -- a new curve must be generated * B) n is composite and a proper factor is found -- the algorithm can * terminate */ ec_discriminant(tmp, a, b); #ifdef DEBUG mpz_mod_ui(tmp, tmp, n); gmp_fprintf(stderr, "\tdelta(E/GF(n)) = %Zd\n", tmp); #endif /* DEBUG */ mpz_gcd_ui(tmp, tmp, n); #ifdef DEBUG gmp_fprintf(stderr, "\tgcd(delta, n) = %Zd\n", tmp); #endif /* DEBUG */ if (0 == mpz_cmp_ui(tmp, 1)) { break; } else if (0 != mpz_cmp_ui(tmp, n)) { #ifdef DEBUG gmp_fprintf(stderr, "\tfound a proper factor, %d is composite\n", n); #endif /* DEBUG */ is_prime = 0; goto cleanup_and_return; } } /* P + P != 0, or a new curve is generated */ z = ec_add(xt, yt, x0, y0, 1, x0, y0, 1, n, a); #ifdef DEBUG gmp_fprintf(stderr, "\t2 * P = (%Zd,%Zd,%d)\n", xt, yt, z); #endif /* DEBUG */ if (0 == z) { continue; } /* the curve order algorithm failing indicates n is composite */ if (!(ec_order(tmp, a, b, n))) { #ifdef DEBUG gmp_fprintf(stderr, "\tcurve order algorithm failed, %d must be composite\n", n); #endif /* DEBUG */ is_prime = 0; break; } #ifdef DEBUG gmp_fprintf(stderr, "\t|E/GF(n)| = %Zd\n", tmp); #endif /* DEBUG */ /* the curve order should be the multiple of 2 and a "probable prime" n -- * if the order is not even, a new curve is generated */ if (!mpz_even_p(tmp)) { #ifdef DEBUG gmp_fprintf(stderr, "\t|E/GF(n)| is odd, generating new curve...\n"); #endif /* DEBUG */ continue; } /* order * P = 0, or n is composite */ z = ec_times(xt, yt, x0, y0, 1, tmp, n, a); #ifdef DEBUG gmp_fprintf(stderr, "\t|E| * P = (%Zd,%Zd,%d)\n", xt, yt, z); #endif /* DEBUG */ if (0 != z) { #ifdef DEBUG gmp_fprintf(stderr, "\t|E| * P is non-zero, %d is composite\n", n); #endif /* DEBUG */ is_prime = 0; break; } /* at this point, order/2 being a prime implies n is a prime -- * a recursive call to ecpp_test is used to test order/2 for primality */ mpz_div_ui(tmp, tmp, 2); if (ecpp_test(mpz_get_ui(tmp))) { is_prime = 1; break; } } cleanup_and_return: mpz_clear(a); mpz_clear(b); mpz_clear(x0); mpz_clear(y0); mpz_clear(xt); mpz_clear(yt); mpz_clear(tmp); return is_prime; }
static int ec_times(mpz_t xr, mpz_t yr, mpz_t x, mpz_t y, int z, mpz_t factor, unsigned long n, mpz_t a) { /* multiply a point of an elliptic curve by a scalar using a non-memoising * "Egyptian multiplication". */ int sign; mpz_t x1, y1, xt, yt, k; int z1 = 0, zt; mpz_init(x1); mpz_init(y1); mpz_init(xt); mpz_init(yt); mpz_init(k); mpz_set_ui(xt, 0); mpz_set_ui(yt, 1); zt = 0; if (0 != z || mpz_cmp_ui(factor, 0) == 0) /* k * 0 = 0 * P = 0 */ { sign = mpz_sgn(factor); mpz_abs(k, factor); while (mpz_cmp_ui(k, 0) > 0) { int pow; mpz_set(x1, x); mpz_set(y1, y); for (pow = 0; mpz_cmp_ui(k, 2 << pow) >= 0; ++pow) { z1 = ec_add(x1, y1, x1, y1, z1, x1, y1, z1, n, a); } mpz_sub_ui(k, k, 1 << pow); zt = ec_add(xt, yt, xt, yt, zt, x1, y1, z1, n, a); } if (-1 == sign) { mpz_neg(yt, yt); } } mpz_set(xr, xt); mpz_set(yr, yt); mpz_clear(x1); mpz_clear(y1); mpz_clear(xt); mpz_clear(yt); mpz_clear(k); return zt; }
bool ec_add(ec_uncompressed& point, const ec_secret& secret) { const auto context = verification.context(); return ec_add(context, point, secret); }
ec_t ec_sub(ec_t ying, ec_t yang) { return ec_add(ying, -yang); }