/* * Prove knowledge of x * Note that p->gx has already been calculated */ static void generate_zkp(JPAKE_STEP_PART *p, const BIGNUM *x, const BIGNUM *zkpg, JPAKE_CTX *ctx) { BIGNUM *r = BN_new(); BIGNUM *h = BN_new(); BIGNUM *t = BN_new(); /* * r in [0,q) * XXX: Java chooses r in [0, 2^160) - i.e. distribution not uniform */ BN_rand_range(r, ctx->p.q); /* g^r */ BN_mod_exp(p->zkpx.gr, zkpg, r, ctx->p.p, ctx->ctx); /* h=hash... */ zkp_hash(h, zkpg, p, ctx->p.name); /* b = r - x*h */ BN_mod_mul(t, x, h, ctx->p.q, ctx->ctx); BN_mod_sub(p->zkpx.b, r, t, ctx->p.q, ctx->ctx); /* cleanup */ BN_free(t); BN_free(h); BN_free(r); }
BIGNUM *ClientSide::Calc_S(BIGNUM *B,BIGNUM *k,BIGNUM *g,BIGNUM *a,BIGNUM *u,BIGNUM *x,BIGNUM *N) { //S = (B - kg^x) ^ (a + ux) (computes session key) BIGNUM *tmp = NULL, *tmp2 = NULL, *tmp3 = NULL, *S = NULL; BN_CTX *bn_ctx; if (u == NULL || B == NULL || N == NULL || g == NULL || x == NULL || a == NULL || (bn_ctx = BN_CTX_new()) == NULL || k == NULL) return NULL; if ((tmp = BN_new()) == NULL || (tmp2 = BN_new()) == NULL || (tmp3 = BN_new()) == NULL || (S = BN_new()) == NULL) { BN_CTX_free(bn_ctx); BN_clear_free(tmp); BN_clear_free(tmp2); BN_clear_free(tmp3); BN_free(S); return NULL; } if(BN_mod_exp(tmp, g, x, N, bn_ctx)) if(BN_mod_mul(tmp2, tmp, k, N, bn_ctx)) if(BN_mod_sub(tmp, B, tmp2, N, bn_ctx)) if(BN_mod_mul(tmp3, u, x, N, bn_ctx)) if(BN_mod_add(tmp2, a, tmp3, N, bn_ctx)) if(BN_mod_exp(S, tmp, tmp2, N, bn_ctx)) ; BN_CTX_free(bn_ctx); BN_clear_free(tmp); BN_clear_free(tmp2); BN_clear_free(tmp3); return S; }
int Omega_sign_online(void *inner, char *msg) { assert(inner!=NULL); OmegaInner *self = (OmegaInner*)inner; int ret; /* compute d1 = h1 xor m */ int i; for (i=0; i<self->bytelen_rec; i++) self->d1[i] = self->h1[i]^msg[i]; /* Convert d1 to e1 */ BIGNUM *rbn = BN_bin2bn(self->d1, self->bytelen_q, self->e1); assert(rbn!=NULL); /* Compute z=re0w - e1*w */ ret = BN_mod_mul(self->e1w, self->e1, self->w, self->q, self->bnctx); assert(ret==1); ret = BN_mod_sub(self->z, self->re0w, self->e1w, self->q, self->bnctx); assert(ret==1); /*Convert z to z_bytes */ ret = BN2LenBin(self->z, self->z_bytes, self->bytelen_q); assert(ret==0); return 0; }
void test_lehmer_thm(void) { BIGNUM *v = BN_new(), *v2 = BN_new(), *h = BN_new(), *n = BN_new(), *p = BN_new(), *q = BN_new(), *g = BN_new(); BN_CTX *ctx = BN_CTX_new(); BN_dec2bn(&v, "2"); BN_dec2bn(&p, "181857351165158586099319592412492032999818333818932850952491024" "131283899677766672100915923041329384157985577418702469610834914" "6296393743554494871840505599"); BN_dec2bn(&q, "220481921324130321200060036818685031159071785249502660004347524" "831733577485433929892260897846567483448177204481081755191897197" "38283711758138566145322943999"); BN_mul(n, p, q, ctx); /* p + 1 */ BN_dec2bn(&h, "181857351165158586099319592412492032999818333818932850952491024" "131283899677766672100915923041329384157985577418702469610834914" "6296393743554494871840505600"); lucas(v, h, n, ctx); BN_sub(v2, v, BN_value_two()); BN_gcd(g, v2, n, ctx); assert(!BN_is_one(g)); /* another test */ BN_dec2bn(&v, "3"); BN_dec2bn(&p, "181857351165158586099319592412492032999818333818932850952491024" "131283899677766672100915923041329384157985577418702469610834914" "62963937435544948718405055999"); BN_generate_prime(q, 512, 1, NULL, NULL, NULL, NULL); BN_mul(n, p, q, ctx); BN_sub(h, p, BN_value_one()); BN_mul(h, h, BN_value_two(), ctx); lucas(v, h, n, ctx); BN_mod_sub(v2, v, BN_value_two(), n, ctx); BN_gcd(g, v2, n, ctx); assert(!BN_is_one(g)); assert(BN_cmp(g, n)); BN_free(q); BN_free(p); BN_free(v); BN_free(v2); BN_free(h); BN_CTX_free(ctx); }
int Omega_sign_offline(void *inner) { assert(inner!=NULL); OmegaInner *self = (OmegaInner*)inner; int ret; BIGNUM *rbn; /* Pick r */ ret = BN_rand_range(self->r, self->q); assert(ret==1); /* Compute a:=g^r mod p */ ret = BN_mod_exp(self->a, self->g, self->r, self->p, self->bnctx); assert(ret==1); /* Convert a into bytes */ int bytelen_a = BN_num_bytes(self->a); assert(bytelen_a <= self->bytelen_p); BN2LenBin(self->a, self->a_bytes, self->bytelen_p); /* Compute h0 = H0(a) = H(a||0x00) */ self->a_bytes[self->bytelen_p] = 0x00; ret = VHash(self->a_bytes, self->bytelen_p+1, self->h0, self->bytelen_red); assert(ret==0); /* Compute h1 = H1(a) = H(a||0x01) */ self->a_bytes[self->bytelen_p] = 0x01; ret = VHash(self->a_bytes, self->bytelen_p+1, self->h1, self->bytelen_rec); assert(ret==0); /* Convert h0(bytes) to e0*/ rbn = BN_bin2bn(self->h0, self->bytelen_q, self->e0); assert(rbn!=NULL); /* Compute re0w = r-e0*w */ ret = BN_mod_mul(self->e0w, self->e0, self->w, self->q, self->bnctx); assert(ret==1); ret = BN_mod_sub(self->re0w, self->r, self->e0w, self->q, self->bnctx); assert(ret==1); return 0; }
int AO_sign_online(void *inner, char *msg) { assert(inner!=NULL); AOInner *self = (AOInner*)inner; int ret; /* h1 := H1(a_bytes||msg) */ memcpy(&self->am_bytes[self->bytelen_p], msg, self->bytelen_rec); VHash(self->am_bytes, self->bytelen_p+self->bytelen_rec, self->n, self->bytelen_red); /* h2 := H2(a_bytes||h1) xor msg*/ memcpy(&self->am_bytes[self->bytelen_p], self->n, self->bytelen_red); VHash(self->am_bytes, self->bytelen_p+self->bytelen_red, &self->n[self->bytelen_red], self->bytelen_rec); { int i; for (i=0; i<self->bytelen_rec; i++) self->n[self->bytelen_red+i]^=msg[i]; } /* n := h1||h2 * Already done. */ /* e_bytes := H(n) */ ret = VHash(self->n, self->bytelen_rec+self->bytelen_red, self->e_bytes, self->bytelen_q); assert(ret==0); /* e := int(e_bytes) */ BN_bin2bn(self->e_bytes, self->bytelen_q, self->e); /* Compute z = r-e*w */ ret = BN_mod_mul(self->ew, self->e, self->w, self->q, self->bnctx); assert(ret==1); ret = BN_mod_sub(self->z, self->r, self->ew, self->q, self->bnctx); assert(ret==1); /*Convert z to z_bytes */ ret = BN2LenBin(self->z, self->z_bytes, self->bytelen_q); assert(ret==0); return 0; }
BIGNUM *SRP_Calc_client_key(BIGNUM *N, BIGNUM *B, BIGNUM *g, BIGNUM *x, BIGNUM *a, BIGNUM *u) { BIGNUM *tmp = NULL, *tmp2 = NULL, *tmp3 = NULL, *k = NULL, *K = NULL; BN_CTX *bn_ctx; if (u == NULL || B == NULL || N == NULL || g == NULL || x == NULL || a == NULL || (bn_ctx = BN_CTX_new()) == NULL) return NULL; if ((tmp = BN_new()) == NULL || (tmp2 = BN_new()) == NULL || (tmp3 = BN_new()) == NULL || (K = BN_new()) == NULL) goto err; if (!BN_mod_exp(tmp, g, x, N, bn_ctx)) goto err; if ((k = srp_Calc_k(N, g)) == NULL) goto err; if (!BN_mod_mul(tmp2, tmp, k, N, bn_ctx)) goto err; if (!BN_mod_sub(tmp, B, tmp2, N, bn_ctx)) goto err; if (!BN_mod_mul(tmp3, u, x, N, bn_ctx)) goto err; if (!BN_mod_add(tmp2, a, tmp3, N, bn_ctx)) goto err; if (!BN_mod_exp(K, tmp, tmp2, N, bn_ctx)) goto err; err: BN_CTX_free(bn_ctx); BN_clear_free(tmp); BN_clear_free(tmp2); BN_clear_free(tmp3); BN_free(k); return K; }
// Prove knowledge of x // Note that we don't send g^x because, as it happens, we've always // sent it elsewhere. Also note that because of that, we could avoid // calculating it here, but we don't, for clarity... static void CreateZKP(JPakeZKP * zkp, const BIGNUM *x, const JPakeUser * us, const BIGNUM *zkpg, const JPakeParameters * params, int n, const char *suffix) { BIGNUM *r = BN_new(); BIGNUM *gx = BN_new(); BIGNUM *h = BN_new(); BIGNUM *t = BN_new(); // r in [0,q) // XXX: Java chooses r in [0, 2^160) - i.e. distribution not uniform BN_rand_range(r, params->q); // g^r zkp->gr = BN_new(); BN_mod_exp(zkp->gr, zkpg, r, params->p, params->ctx); // g^x BN_mod_exp(gx, zkpg, x, params->p, params->ctx); // h=hash... zkpHash(h, zkp, gx, &us->p, params); // b = r - x*h BN_mod_mul(t, x, h, params->q, params->ctx); zkp->b = BN_new(); BN_mod_sub(zkp->b, r, t, params->q, params->ctx); // show printf(" ZKP(x%d%s)\n", n, suffix); showbn(" zkpg", zkpg); showbn(" g^x", gx); showbn(" g^r", zkp->gr); showbn(" b", zkp->b); // cleanup BN_free(t); BN_free(h); BN_free(gx); BN_free(r); }
static SM9Signature *SM9_do_sign_type1curve(SM9PublicParameters *mpk, const unsigned char *dgst, size_t dgstlen, SM9PrivateKey *sk) { int e = 1; SM9Signature *ret = NULL; BN_CTX *bn_ctx = NULL; EC_GROUP *group = NULL; EC_POINT *point = NULL; BN_GFP2 *w = NULL; unsigned char *buf = NULL; BIGNUM *r; BIGNUM *l; const EVP_MD *md; int point_form = POINT_CONVERSION_UNCOMPRESSED; size_t size; if (!mpk || !dgst || dgstlen <= 0 || !sk) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_PASSED_NULL_PARAMETER); return NULL; } if (dgstlen > EVP_MAX_MD_SIZE) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, SM9_R_INVALID_DIGEST); return NULL; } /* BN_CTX */ if (!(bn_ctx = BN_CTX_new())) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_MALLOC_FAILURE); goto end; } BN_CTX_start(bn_ctx); /* EC_GROUP */ if (!(group = EC_GROUP_new_type1curve_ex(mpk->p, mpk->a, mpk->b, mpk->pointP1->data, mpk->pointP1->length, mpk->order, mpk->cofactor, bn_ctx))) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, SM9_R_INVALID_TYPE1CURVE); goto end; } /* malloc */ ret = SM9Signature_new(); point = EC_POINT_new(group); r = BN_CTX_get(bn_ctx); l = BN_CTX_get(bn_ctx); if (!ret || !point || !r || !l) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_MALLOC_FAILURE); goto end; } /* md = mpk->hashfcn */ if (!(md = EVP_get_digestbyobj(mpk->hashfcn))) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, SM9_R_INVALID_MD); goto end; } do { /* rand r in [1, mpk->order - 1] */ do { if (!BN_rand_range(r, mpk->order)) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_BN_LIB); goto end; } } while (BN_is_zero(r)); /* get w = mpk->g = e(mpk->pointP1, mpk->pointPpub) */ if (!BN_bn2gfp2(mpk->g1, w, mpk->p, bn_ctx)) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_BN_LIB); goto end; } /* w = w^r = (mpk->g)^r in F_p^2 */ if (!BN_GFP2_exp(w, w, r, mpk->p, bn_ctx)) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_BN_LIB); goto end; } /* prepare w buf and canonical(w, order=0) */ if (!BN_GFP2_canonical(w, NULL, &size, 0, mpk->p, bn_ctx)) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_BN_LIB); goto end; } if (!(buf = OPENSSL_malloc(size))) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_MALLOC_FAILURE); goto end; } if (!BN_GFP2_canonical(w, buf, &size, 0, mpk->p, bn_ctx)) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_BN_LIB); goto end; } /* ret->h = H2(H(m)||w) in range defined by mpk->order */ if (!SM9_hash2(md, &ret->h, dgst, dgstlen, buf, size, mpk->order, bn_ctx)) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_SM9_LIB); goto end; } /* l = (r - ret->h) (mod mpk->order) */ if (!BN_mod_sub(l, r, ret->h, mpk->order, bn_ctx)) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_BN_LIB); goto end; } /* if l == 0, re-generate r */ } while (BN_is_zero(l)); /* point = sk->prointPoint */ if (!EC_POINT_oct2point(group, point, sk->privatePoint->data, sk->privatePoint->length, bn_ctx)) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_EC_LIB); goto end; } /* sig->pointS = sk->privatePoint * l */ if (!EC_POINT_mul(group, point, NULL, point, l, bn_ctx)) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_EC_LIB); goto end; } if (!(size = EC_POINT_point2oct(group, point, point_form, NULL, 0, bn_ctx))) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_EC_LIB); goto end; } if (!ASN1_OCTET_STRING_set(ret->pointS, NULL, size)) { SM9err(SM9_F_SM9_DO_SIGN_TYPE1CURVE, ERR_R_EC_LIB); goto end; } if (!EC_POINT_point2oct(group, point, point_form, ret->pointS->data, ret->pointS->length, bn_ctx)) { goto end; } e = 0; end: if (e && ret) { SM9Signature_free(ret); ret = NULL; } if (bn_ctx) { BN_CTX_end(bn_ctx); } BN_CTX_free(bn_ctx); EC_GROUP_free(group); EC_POINT_free(point); BN_GFP2_free(w); OPENSSL_free(buf); return NULL; }
int BN_X931_derive_prime_ex(BIGNUM *p, BIGNUM *p1, BIGNUM *p2, const BIGNUM *Xp, const BIGNUM *Xp1, const BIGNUM *Xp2, const BIGNUM *e, BN_CTX *ctx, BN_GENCB *cb) { int ret = 0; BIGNUM *t, *p1p2, *pm1; /* Only even e supported */ if (!BN_is_odd(e)) return 0; BN_CTX_start(ctx); if (p1 == NULL) { if ((p1 = BN_CTX_get(ctx)) == NULL) goto err; } if (p2 == NULL) { if ((p2 = BN_CTX_get(ctx)) == NULL) goto err; } if ((t = BN_CTX_get(ctx)) == NULL) goto err; if ((p1p2 = BN_CTX_get(ctx)) == NULL) goto err; if ((pm1 = BN_CTX_get(ctx)) == NULL) goto err; if (!bn_x931_derive_pi(p1, Xp1, ctx, cb)) goto err; if (!bn_x931_derive_pi(p2, Xp2, ctx, cb)) goto err; if (!BN_mul(p1p2, p1, p2, ctx)) goto err; /* First set p to value of Rp */ if (!BN_mod_inverse(p, p2, p1, ctx)) goto err; if (!BN_mul(p, p, p2, ctx)) goto err; if (!BN_mod_inverse(t, p1, p2, ctx)) goto err; if (!BN_mul(t, t, p1, ctx)) goto err; if (!BN_sub(p, p, t)) goto err; if (p->neg && !BN_add(p, p, p1p2)) goto err; /* p now equals Rp */ if (!BN_mod_sub(p, p, Xp, p1p2, ctx)) goto err; if (!BN_add(p, p, Xp)) goto err; /* p now equals Yp0 */ for (;;) { int i = 1; BN_GENCB_call(cb, 0, i++); if (!BN_copy(pm1, p)) goto err; if (!BN_sub_word(pm1, 1)) goto err; if (!BN_gcd(t, pm1, e, ctx)) goto err; if (BN_is_one(t) /* X9.31 specifies 8 MR and 1 Lucas test or any prime test * offering similar or better guarantees 50 MR is considerably * better. */ && BN_is_prime_fasttest_ex(p, 50, ctx, 1, cb)) break; if (!BN_add(p, p, p1p2)) goto err; } BN_GENCB_call(cb, 3, 0); ret = 1; err: BN_CTX_end(ctx); return ret; }
static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp, const unsigned char *dgst, int dlen) { BN_CTX *ctx = NULL; BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL; EC_POINT *tmp_point = NULL; const EC_GROUP *group; int ret = 0; if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (ctx_in == NULL) { if ((ctx = BN_CTX_new()) == NULL) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE); return 0; } } else ctx = ctx_in; k = BN_new(); /* this value is later returned in *kinvp */ r = BN_new(); /* this value is later returned in *rp */ order = BN_new(); X = BN_new(); if (k == NULL || r == NULL || order == NULL || X == NULL) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE); goto err; } if ((tmp_point = EC_POINT_new(group)) == NULL) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } if (!EC_GROUP_get_order(group, order, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } do { /* get random k */ do if (dgst != NULL) { if (!BN_generate_dsa_nonce (k, order, EC_KEY_get0_private_key(eckey), dgst, dlen, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, EC_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } } else { if (!BN_rand_range(k, order)) { ECerr(EC_F_ECDSA_SIGN_SETUP, EC_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } } while (BN_is_zero(k)); /* * We do not want timing information to leak the length of k, so we * compute G*k using an equivalent scalar of fixed bit-length. */ if (!BN_add(k, k, order)) goto err; if (BN_num_bits(k) <= BN_num_bits(order)) if (!BN_add(k, k, order)) goto err; /* compute r the x-coordinate of generator * k */ if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { if (!EC_POINT_get_affine_coordinates_GFp (group, tmp_point, X, NULL, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } } #ifndef OPENSSL_NO_EC2M else { /* NID_X9_62_characteristic_two_field */ if (!EC_POINT_get_affine_coordinates_GF2m(group, tmp_point, X, NULL, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } } #endif if (!BN_nnmod(r, X, order, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } while (BN_is_zero(r)); /* compute the inverse of k */ if (EC_GROUP_get_mont_data(group) != NULL) { /* * We want inverse in constant time, therefore we utilize the fact * order must be prime and use Fermats Little Theorem instead. */ if (!BN_set_word(X, 2)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } if (!BN_mod_sub(X, order, X, order, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } BN_set_flags(X, BN_FLG_CONSTTIME); if (!BN_mod_exp_mont_consttime (k, k, X, order, ctx, EC_GROUP_get_mont_data(group))) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } else { if (!BN_mod_inverse(k, k, order, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } /* clear old values if necessary */ BN_clear_free(*rp); BN_clear_free(*kinvp); /* save the pre-computed values */ *rp = r; *kinvp = k; ret = 1; err: if (!ret) { BN_clear_free(k); BN_clear_free(r); } if (ctx != ctx_in) BN_CTX_free(ctx); BN_free(order); EC_POINT_free(tmp_point); BN_clear_free(X); return (ret); }
/* * Generate Schnorr signature to prove knowledge of private value 'x' used * in public exponent g^x, under group defined by 'grp_p', 'grp_q' and 'grp_g' * using the hash function "hash_alg". * 'idlen' bytes from 'id' will be included in the signature hash as an anti- * replay salt. * * On success, 0 is returned. The signature values are returned as *e_p * (g^v mod p) and *r_p (v - xh mod q). The caller must free these values. * On failure, -1 is returned. */ int schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, int hash_alg, const BIGNUM *x, const BIGNUM *g_x, const u_char *id, u_int idlen, BIGNUM **r_p, BIGNUM **e_p) { int success = -1; BIGNUM *h, *tmp, *v, *g_v, *r; BN_CTX *bn_ctx; SCHNORR_DEBUG_BN((x, "%s: x = ", __func__)); SCHNORR_DEBUG_BN((g_x, "%s: g_x = ", __func__)); /* Avoid degenerate cases: g^0 yields a spoofable signature */ if (BN_cmp(g_x, BN_value_one()) <= 0) { error("%s: g_x < 1", __func__); return -1; } if (BN_cmp(g_x, grp_p) >= 0) { error("%s: g_x > g", __func__); return -1; } h = g_v = r = tmp = v = NULL; if ((bn_ctx = BN_CTX_new()) == NULL) { error("%s: BN_CTX_new", __func__); goto out; } if ((g_v = BN_new()) == NULL || (r = BN_new()) == NULL || (tmp = BN_new()) == NULL) { error("%s: BN_new", __func__); goto out; } /* * v must be a random element of Zq, so 1 <= v < q * we also exclude v = 1, since g^1 looks dangerous */ if ((v = bn_rand_range_gt_one(grp_p)) == NULL) { error("%s: bn_rand_range2", __func__); goto out; } SCHNORR_DEBUG_BN((v, "%s: v = ", __func__)); /* g_v = g^v mod p */ if (BN_mod_exp(g_v, grp_g, v, grp_p, bn_ctx) == -1) { error("%s: BN_mod_exp (g^v mod p)", __func__); goto out; } SCHNORR_DEBUG_BN((g_v, "%s: g_v = ", __func__)); /* h = H(g || g^v || g^x || id) */ if ((h = schnorr_hash(grp_p, grp_q, grp_g, hash_alg, g_v, g_x, id, idlen)) == NULL) { error("%s: schnorr_hash failed", __func__); goto out; } /* r = v - xh mod q */ if (BN_mod_mul(tmp, x, h, grp_q, bn_ctx) == -1) { error("%s: BN_mod_mul (tmp = xv mod q)", __func__); goto out; } if (BN_mod_sub(r, v, tmp, grp_q, bn_ctx) == -1) { error("%s: BN_mod_mul (r = v - tmp)", __func__); goto out; } SCHNORR_DEBUG_BN((g_v, "%s: e = ", __func__)); SCHNORR_DEBUG_BN((r, "%s: r = ", __func__)); *e_p = g_v; *r_p = r; success = 0; out: BN_CTX_free(bn_ctx); if (h != NULL) BN_clear_free(h); if (v != NULL) BN_clear_free(v); BN_clear_free(tmp); return success; }
static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp) { BN_CTX *ctx = NULL; BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL; EC_POINT *tmp_point = NULL; const EC_GROUP *group; int ret = 0; int order_bits; if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (ctx_in == NULL) { if ((ctx = BN_CTX_new()) == NULL) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE); return 0; } } else ctx = ctx_in; k = BN_new(); /* this value is later returned in *kinvp */ r = BN_new(); /* this value is later returned in *rp */ order = BN_new(); X = BN_new(); if (!k || !r || !order || !X) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE); goto err; } if ((tmp_point = EC_POINT_new(group)) == NULL) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } if (!EC_GROUP_get_order(group, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } /* Preallocate space */ order_bits = BN_num_bits(order); if (!BN_set_bit(k, order_bits) || !BN_set_bit(r, order_bits) || !BN_set_bit(X, order_bits)) goto err; do { /* get random k */ do if (!BN_rand_range(k, order)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } while (BN_is_zero(k)) ; /* * We do not want timing information to leak the length of k, so we * compute G*k using an equivalent scalar of fixed bit-length. * * We unconditionally perform both of these additions to prevent a * small timing information leakage. We then choose the sum that is * one bit longer than the order. This guarantees the code * path used in the constant time implementations elsewhere. * * TODO: revisit the BN_copy aiming for a memory access agnostic * conditional copy. */ if (!BN_add(r, k, order) || !BN_add(X, r, order) || !BN_copy(k, BN_num_bits(r) > order_bits ? r : X)) goto err; /* compute r the x-coordinate of generator * k */ if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { if (!EC_POINT_get_affine_coordinates_GFp (group, tmp_point, X, NULL, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } } #ifndef OPENSSL_NO_EC2M else { /* NID_X9_62_characteristic_two_field */ if (!EC_POINT_get_affine_coordinates_GF2m(group, tmp_point, X, NULL, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } } #endif if (!BN_nnmod(r, X, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } while (BN_is_zero(r)); /* compute the inverse of k */ if (EC_GROUP_get_mont_data(group) != NULL) { /* * We want inverse in constant time, therefore we utilize the fact * order must be prime and use Fermats Little Theorem instead. */ if (!BN_set_word(X, 2)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } if (!BN_mod_sub(X, order, X, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } BN_set_flags(X, BN_FLG_CONSTTIME); if (!BN_mod_exp_mont_consttime (k, k, X, order, ctx, EC_GROUP_get_mont_data(group))) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } else { if (!BN_mod_inverse(k, k, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } /* clear old values if necessary */ if (*rp != NULL) BN_clear_free(*rp); if (*kinvp != NULL) BN_clear_free(*kinvp); /* save the pre-computed values */ *rp = r; *kinvp = k; ret = 1; err: if (!ret) { if (k != NULL) BN_clear_free(k); if (r != NULL) BN_clear_free(r); } if (ctx_in == NULL) BN_CTX_free(ctx); if (order != NULL) BN_free(order); if (tmp_point != NULL) EC_POINT_free(tmp_point); if (X) BN_clear_free(X); return (ret); }
/* Shared parts of key derivation and confirmation calculation */ void jpake_key_confirm(struct modp_group *grp, BIGNUM *s, BIGNUM *step2_val, BIGNUM *mypriv2, BIGNUM *mypub1, BIGNUM *mypub2, BIGNUM *theirpub1, BIGNUM *theirpub2, const u_char *my_id, u_int my_id_len, const u_char *their_id, u_int their_id_len, const u_char *sess_id, u_int sess_id_len, const u_char *theirpriv2_s_proof, u_int theirpriv2_s_proof_len, BIGNUM **k, u_char **confirm_hash, u_int *confirm_hash_len) { BN_CTX *bn_ctx; BIGNUM *tmp; if ((bn_ctx = BN_CTX_new()) == NULL) fatal("%s: BN_CTX_new", __func__); if ((tmp = BN_new()) == NULL || (*k = BN_new()) == NULL) fatal("%s: BN_new", __func__); /* Validate step 2 values */ if (BN_cmp(step2_val, BN_value_one()) <= 0) fatal("%s: step2_val <= 1", __func__); if (BN_cmp(step2_val, grp->p) >= 0) fatal("%s: step2_val >= p", __func__); /* * theirpriv2_s_proof is calculated with a different generator: * tmp = g^(mypriv1+mypriv2+theirpub1) = g^mypub1*g^mypub2*g^theirpub1 * Calculate it here so we can check the signature. */ if (BN_mod_mul(tmp, mypub1, mypub2, grp->p, bn_ctx) != 1) fatal("%s: BN_mod_mul (tmp = mypub1 * mypub2 mod p)", __func__); if (BN_mod_mul(tmp, tmp, theirpub1, grp->p, bn_ctx) != 1) fatal("%s: BN_mod_mul (tmp = tmp * theirpub1 mod p)", __func__); JPAKE_DEBUG_BN((tmp, "%s: tmp = ", __func__)); if (schnorr_verify_buf(grp->p, grp->q, tmp, step2_val, their_id, their_id_len, theirpriv2_s_proof, theirpriv2_s_proof_len) != 1) fatal("%s: schnorr_verify theirpriv2_s_proof failed", __func__); /* * Derive shared key: * client: k = (b / g^(x2*x4*s))^x2 = g^((x1+x3)*x2*x4*s) * server: k = (a / g^(x2*x4*s))^x4 = g^((x1+x3)*x2*x4*s) * * Computed as: * client: k = (g_x4^(q - (x2 * s)) * b)^x2 mod p * server: k = (g_x2^(q - (x4 * s)) * b)^x4 mod p */ if (BN_mul(tmp, mypriv2, s, bn_ctx) != 1) fatal("%s: BN_mul (tmp = mypriv2 * s)", __func__); if (BN_mod_sub(tmp, grp->q, tmp, grp->q, bn_ctx) != 1) fatal("%s: BN_mod_sub (tmp = q - tmp mod q)", __func__); if (BN_mod_exp(tmp, theirpub2, tmp, grp->p, bn_ctx) != 1) fatal("%s: BN_mod_exp (tmp = theirpub2^tmp) mod p", __func__); if (BN_mod_mul(tmp, tmp, step2_val, grp->p, bn_ctx) != 1) fatal("%s: BN_mod_mul (tmp = tmp * step2_val) mod p", __func__); if (BN_mod_exp(*k, tmp, mypriv2, grp->p, bn_ctx) != 1) fatal("%s: BN_mod_exp (k = tmp^mypriv2) mod p", __func__); BN_CTX_free(bn_ctx); BN_clear_free(tmp); jpake_confirm_hash(*k, my_id, my_id_len, sess_id, sess_id_len, confirm_hash, confirm_hash_len); }
ProductEvidence ProductEvidence_New(ProductStatement st, const BIGNUM *a, const BIGNUM *r_a, const BIGNUM *r_b, const BIGNUM *r_c) { ProductEvidence ev = safe_malloc(sizeof(*ev)); const BIGNUM* g = IntegerGroup_GetG(st->group); const BIGNUM* h = IntegerGroup_GetH(st->group); const BIGNUM* q = IntegerGroup_GetQ(st->group); BN_CTX* ctx = IntegerGroup_GetCtx(st->group); // A = g^a h^{r_a} // B = g^b h^{r_b} // C = g^{ab} h^{r_c} // r_prod = r_c - a*r_b BIGNUM* r_prod; CHECK_CALL(r_prod = BN_dup(a)); CHECK_CALL(BN_mod_mul(r_prod, r_prod, r_b, q, ctx)); CHECK_CALL(BN_mod_sub(r_prod, r_c, r_prod, q, ctx)); // == Commitment == // x, s1, s2 in [0, q) BIGNUM *x = IntegerGroup_RandomExponent(st->group); BIGNUM *s1 = IntegerGroup_RandomExponent(st->group); BIGNUM *s2 = IntegerGroup_RandomExponent(st->group); CHECK_CALL(x); CHECK_CALL(s1); CHECK_CALL(s2); // m1 = g^x h^s1 BIGNUM* m1 = IntegerGroup_CascadeExponentiate(st->group, g, x, h, s1); CHECK_CALL(m1); // m2 = B^x h^s2 BIGNUM* m2 = IntegerGroup_CascadeExponentiate(st->group, st->commit_b, x, h, s2); CHECK_CALL(m2); // == Challenge == // c = H(g, h, q, p, A, B, C, m1, m2) ev->c = Commit(st, m1, m2); // == Response == // z = x + ca mod q ev->z = BN_dup(ev->c); CHECK_CALL(ev->z); CHECK_CALL(BN_mod_mul(ev->z, ev->z, a, q, ctx)); CHECK_CALL(BN_mod_add(ev->z, ev->z, x, q, ctx)); // w1 = s1 + (c r_a) mod q ev->w1 = BN_dup(r_a); CHECK_CALL(ev->w1); CHECK_CALL(BN_mod_mul(ev->w1, ev->w1, ev->c, q, ctx)); CHECK_CALL(BN_mod_add(ev->w1, ev->w1, s1, q, ctx)); // w2 = s2 + (c r_prod) mod q ev->w2 = BN_dup(r_prod); CHECK_CALL(ev->w2); CHECK_CALL(BN_mod_mul(ev->w2, ev->w2, ev->c, q, ctx)); CHECK_CALL(BN_mod_add(ev->w2, ev->w2, s2, q, ctx)); // proof is (c, z, w1, w2) BN_free(m1); BN_free(m2); BN_clear_free(x); BN_clear_free(s1); BN_clear_free(s2); BN_clear_free(r_prod); return ev; }
int verifyRingSignatureAB(data_chunk &keyImage, uint256 &txnHash, int nRingSize, const uint8_t *pPubkeys, const data_chunk &sigC, const uint8_t *pSigS) { // https://bitcointalk.org/index.php?topic=972541.msg10619684 // forall_{i=1..n} compute e_i=s_i*G+c_i*P_i and E_i=s_i*H(P_i)+c_i*I_j and c_{i+1}=h(P_1,...,P_n,e_i,E_i) // check c_{n+1}=c_1 if (fDebugRingSig) { //LogPrintf("%s size %d\n", __func__, nRingSize); // happens often }; if (sigC.size() != EC_SECRET_SIZE) return errorN(1, "%s: sigC size != EC_SECRET_SIZE.", __func__); if (keyImage.size() != EC_COMPRESSED_SIZE) return errorN(1, "%s: keyImage size != EC_COMPRESSED_SIZE.", __func__); int rv = 0; uint256 tmpPkHash; uint256 tmpHash; uint8_t tempData[66]; // hold raw point data to hash CHashWriter ssPkHash(SER_GETHASH, PROTOCOL_VERSION); CHashWriter ssCjHash(SER_GETHASH, PROTOCOL_VERSION); for (int i = 0; i < nRingSize; ++i) { ssPkHash.write((const char*)&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE); }; tmpPkHash = ssPkHash.GetHash(); BN_CTX_start(bnCtx); BIGNUM *bnC = BN_CTX_get(bnCtx); BIGNUM *bnC1 = BN_CTX_get(bnCtx); BIGNUM *bnT = BN_CTX_get(bnCtx); BIGNUM *bnS = BN_CTX_get(bnCtx); EC_POINT *ptKi = NULL; EC_POINT *ptT1 = NULL; EC_POINT *ptT2 = NULL; EC_POINT *ptT3 = NULL; EC_POINT *ptPk = NULL; EC_POINT *ptSi = NULL; if ( !(ptKi = EC_POINT_new(ecGrp)) || !(ptT1 = EC_POINT_new(ecGrp)) || !(ptT2 = EC_POINT_new(ecGrp)) || !(ptT3 = EC_POINT_new(ecGrp)) || !(ptPk = EC_POINT_new(ecGrp)) || !(ptSi = EC_POINT_new(ecGrp))) { LogPrintf("%s: EC_POINT_new failed.\n", __func__); rv = 1; goto End; }; // get keyimage as point if (!EC_POINT_oct2point(ecGrp, ptKi, &keyImage[0], EC_COMPRESSED_SIZE, bnCtx)) { LogPrintf("%s: extract ptKi failed.\n", __func__); rv = 1; goto End; }; if (!bnC1 || !BN_bin2bn(&sigC[0], EC_SECRET_SIZE, bnC1)) { LogPrintf("%s: BN_bin2bn failed.\n", __func__); rv = 1; goto End; }; if (!BN_copy(bnC, bnC1)) { LogPrintf("%s: BN_copy failed.\n", __func__); rv = 1; goto End; }; for (int i = 0; i < nRingSize; ++i) { if (!bnS || !(BN_bin2bn(&pSigS[i * EC_SECRET_SIZE], EC_SECRET_SIZE, bnS))) { LogPrintf("%s: BN_bin2bn failed.\n", __func__); rv = 1; goto End; }; // ptT2 <- pk if (!EC_POINT_oct2point(ecGrp, ptPk, &pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnCtx)) { LogPrintf("%s: EC_POINT_oct2point failed.\n", __func__); rv = 1; goto End; }; // ptT1 = e_i=s_i*G+c_i*P_i if (!EC_POINT_mul(ecGrp, ptT1, bnS, ptPk, bnC, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; if (!(EC_POINT_point2oct(ecGrp, ptT1, POINT_CONVERSION_COMPRESSED, &tempData[0], 33, bnCtx) == (int) EC_COMPRESSED_SIZE)) { LogPrintf("%s: extract ptT1 failed.\n", __func__); rv = 1; goto End; }; // ptT2 =E_i=s_i*H(P_i)+c_i*I_j // ptT2 =H(P_i) if (hashToEC(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT, ptT2) != 0) { LogPrintf("%s: hashToEC failed.\n", __func__); rv = 1; goto End; }; // DEBUGGING: ------- check if we can find the signer... // ptSi = Pi * bnT if ((!EC_POINT_mul(ecGrp, ptSi, NULL, ptPk, bnT, bnCtx) || false) && (rv = errorN(1, "%s: EC_POINT_mul failed.", __func__))) goto End; if (0 == EC_POINT_cmp(ecGrp, ptSi, ptKi, bnCtx) ) LogPrintf("signer is index %d\n", i); // DEBUGGING: - End - check if we can find the signer... // ptT3 = s_i*ptT2 if (!EC_POINT_mul(ecGrp, ptT3, NULL, ptT2, bnS, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT1 = c_i*I_j if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptKi, bnC, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT2 = ptT3 + ptT1 if (!EC_POINT_add(ecGrp, ptT2, ptT3, ptT1, bnCtx)) { LogPrintf("%s: EC_POINT_add failed.\n", __func__); rv = 1; goto End; }; if (!(EC_POINT_point2oct(ecGrp, ptT2, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE)) { LogPrintf("%s: extract ptT2 failed.\n", __func__); rv = 1; goto End; }; CHashWriter ssCHash(SER_GETHASH, PROTOCOL_VERSION); ssCHash.write((const char*)tmpPkHash.begin(), 32); ssCHash.write((const char*)&tempData[0], 66); tmpHash = ssCHash.GetHash(); if (!bnC || !(BN_bin2bn(tmpHash.begin(), EC_SECRET_SIZE, bnC)) || !BN_mod(bnC, bnC, bnOrder, bnCtx)) { LogPrintf("%s: tmpHash -> bnC failed.\n", __func__); rv = 1; goto End; }; }; // bnT = (bnC - bnC1) % N if (!BN_mod_sub(bnT, bnC, bnC1, bnOrder, bnCtx)) { LogPrintf("%s: BN_mod_sub failed.\n", __func__); rv = 1; goto End; }; // test bnT == 0 (bnC == bnC1) if (!BN_is_zero(bnT)) { LogPrintf("%s: signature does not verify.\n", __func__); rv = 2; }; End: BN_CTX_end(bnCtx); EC_POINT_free(ptKi); EC_POINT_free(ptT1); EC_POINT_free(ptT2); EC_POINT_free(ptT3); EC_POINT_free(ptPk); EC_POINT_free(ptSi); return rv; };
int ecdh_im_compute_key(PACE_CTX * ctx, const BUF_MEM * s, const BUF_MEM * in, BN_CTX *bn_ctx) { int ret = 0; BUF_MEM * x_mem = NULL; BIGNUM * a = NULL, *b = NULL, *p = NULL; BIGNUM * x = NULL, *y = NULL, *v = NULL, *u = NULL; BIGNUM * tmp = NULL, *tmp2 = NULL, *bn_inv = NULL; BIGNUM * two = NULL, *three = NULL, *four = NULL, *six = NULL; BIGNUM * twentyseven = NULL; EC_KEY *static_key = NULL, *ephemeral_key = NULL; EC_POINT *g = NULL; BN_CTX_start(bn_ctx); check((ctx && ctx->static_key && s && ctx->ka_ctx), "Invalid arguments"); static_key = EVP_PKEY_get1_EC_KEY(ctx->static_key); if (!static_key) goto err; /* Setup all the variables*/ a = BN_CTX_get(bn_ctx); b = BN_CTX_get(bn_ctx); p = BN_CTX_get(bn_ctx); x = BN_CTX_get(bn_ctx); y = BN_CTX_get(bn_ctx); v = BN_CTX_get(bn_ctx); two = BN_CTX_get(bn_ctx); three = BN_CTX_get(bn_ctx); four = BN_CTX_get(bn_ctx); six = BN_CTX_get(bn_ctx); twentyseven = BN_CTX_get(bn_ctx); tmp = BN_CTX_get(bn_ctx); tmp2 = BN_CTX_get(bn_ctx); bn_inv = BN_CTX_get(bn_ctx); if (!bn_inv) goto err; /* Encrypt the Nonce using the symmetric key in */ x_mem = cipher_no_pad(ctx->ka_ctx, NULL, in, s, 1); if (!x_mem) goto err; /* Fetch the curve parameters */ if (!EC_GROUP_get_curve_GFp(EC_KEY_get0_group(static_key), p, a, b, bn_ctx)) goto err; /* Assign constants */ if ( !BN_set_word(two,2)|| !BN_set_word(three,3)|| !BN_set_word(four,4)|| !BN_set_word(six,6)|| !BN_set_word(twentyseven,27) ) goto err; /* Check prerequisites for curve parameters */ check( /* p > 3;*/ (BN_cmp(p, three) == 1) && /* p mod 3 = 2; (p has the form p=q^n, q prime) */ BN_nnmod(tmp, p, three, bn_ctx) && (BN_cmp(tmp, two) == 0), "Unsuited curve"); /* Convert encrypted nonce to BIGNUM */ u = BN_bin2bn((unsigned char *) x_mem->data, x_mem->length, u); if (!u) goto err; if ( /* v = (3a - u^4) / 6u mod p */ !BN_mod_mul(tmp, three, a, p, bn_ctx) || !BN_mod_exp(tmp2, u, four, p, bn_ctx) || !BN_mod_sub(v, tmp, tmp2, p, bn_ctx) || !BN_mod_mul(tmp, u, six, p, bn_ctx) || /* For division within a galois field we need to compute * the multiplicative inverse of a number */ !BN_mod_inverse(bn_inv, tmp, p, bn_ctx) || !BN_mod_mul(v, v, bn_inv, p, bn_ctx) || /* x = (v^2 - b - ((u^6)/27)) */ !BN_mod_sqr(tmp, v, p, bn_ctx) || !BN_mod_sub(tmp2, tmp, b, p, bn_ctx) || !BN_mod_exp(tmp, u, six, p, bn_ctx) || !BN_mod_inverse(bn_inv, twentyseven, p, bn_ctx) || !BN_mod_mul(tmp, tmp, bn_inv, p, bn_ctx) || !BN_mod_sub(x, tmp2, tmp, p, bn_ctx) || /* x -> x^(1/3) = x^((2p^n -1)/3) */ !BN_mul(tmp, two, p, bn_ctx) || !BN_sub(tmp, tmp, BN_value_one()) || /* Division is defined, because p^n = 2 mod 3 */ !BN_div(tmp, y, tmp, three, bn_ctx) || !BN_mod_exp(tmp2, x, tmp, p, bn_ctx) || !BN_copy(x, tmp2) || /* x += (u^2)/3 */ !BN_mod_sqr(tmp, u, p, bn_ctx) || !BN_mod_inverse(bn_inv, three, p, bn_ctx) || !BN_mod_mul(tmp2, tmp, bn_inv, p, bn_ctx) || !BN_mod_add(tmp, x, tmp2, p, bn_ctx) || !BN_copy(x, tmp) || /* y = ux + v */ !BN_mod_mul(y, u, x, p, bn_ctx) || !BN_mod_add(tmp, y, v, p, bn_ctx) || !BN_copy(y, tmp) ) goto err; /* Initialize ephemeral parameters with parameters from the static key */ ephemeral_key = EC_KEY_dup(static_key); if (!ephemeral_key) goto err; EVP_PKEY_set1_EC_KEY(ctx->ka_ctx->key, ephemeral_key); /* configure the new EC_KEY */ g = EC_POINT_new(EC_KEY_get0_group(ephemeral_key)); if (!g) goto err; if (!EC_POINT_set_affine_coordinates_GFp(EC_KEY_get0_group(ephemeral_key), g, x, y, bn_ctx)) goto err; ret = 1; err: if (x_mem) BUF_MEM_free(x_mem); if (u) BN_free(u); BN_CTX_end(bn_ctx); if (g) EC_POINT_clear_free(g); /* Decrement reference count, keys are still available via PACE_CTX */ if (static_key) EC_KEY_free(static_key); if (ephemeral_key) EC_KEY_free(ephemeral_key); return ret; }
int generateRingSignatureAB(data_chunk &keyImage, uint256 &txnHash, int nRingSize, int nSecretOffset, ec_secret secret, const uint8_t *pPubkeys, data_chunk &sigC, uint8_t *pSigS) { // https://bitcointalk.org/index.php?topic=972541.msg10619684 if (fDebugRingSig) LogPrintf("%s: Ring size %d.\n", __func__, nRingSize); assert(nRingSize < 200); RandAddSeedPerfmon(); memset(pSigS, 0, EC_SECRET_SIZE * nRingSize); int rv = 0; int nBytes; uint256 tmpPkHash; uint256 tmpHash; uint8_t tempData[66]; // hold raw point data to hash ec_secret sAlpha; if (0 != GenerateRandomSecret(sAlpha)) return errorN(1, "%s: GenerateRandomSecret failed.", __func__); CHashWriter ssPkHash(SER_GETHASH, PROTOCOL_VERSION); CHashWriter ssCjHash(SER_GETHASH, PROTOCOL_VERSION); uint256 test; for (int i = 0; i < nRingSize; ++i) { ssPkHash.write((const char*)&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE); if (i == nSecretOffset) continue; int k; // NOTE: necessary to clamp? for (k = 0; k < 32; ++k) { if (1 != RAND_bytes(&pSigS[i * EC_SECRET_SIZE], 32)) return errorN(1, "%s: RAND_bytes ERR_get_error %u.", __func__, ERR_get_error()); memcpy(test.begin(), &pSigS[i * EC_SECRET_SIZE], 32); if (test > MIN_SECRET && test < MAX_SECRET) break; }; if (k > 31) return errorN(1, "%s: Failed to generate a valid key.", __func__); }; tmpPkHash = ssPkHash.GetHash(); BN_CTX_start(bnCtx); BIGNUM *bnT = BN_CTX_get(bnCtx); BIGNUM *bnT2 = BN_CTX_get(bnCtx); BIGNUM *bnS = BN_CTX_get(bnCtx); BIGNUM *bnC = BN_CTX_get(bnCtx); BIGNUM *bnCj = BN_CTX_get(bnCtx); BIGNUM *bnA = BN_CTX_get(bnCtx); EC_POINT *ptKi = NULL; EC_POINT *ptPk = NULL; EC_POINT *ptT1 = NULL; EC_POINT *ptT2 = NULL; EC_POINT *ptT3 = NULL; EC_POINT *ptT4 = NULL; if ( !(ptKi = EC_POINT_new(ecGrp)) || !(ptPk = EC_POINT_new(ecGrp)) || !(ptT1 = EC_POINT_new(ecGrp)) || !(ptT2 = EC_POINT_new(ecGrp)) || !(ptT3 = EC_POINT_new(ecGrp)) || !(ptT4 = EC_POINT_new(ecGrp))) { LogPrintf("%s: EC_POINT_new failed.\n", __func__); rv = 1; goto End; }; // get keyimage as point if (!EC_POINT_oct2point(ecGrp, ptKi, &keyImage[0], EC_COMPRESSED_SIZE, bnCtx)) { LogPrintf("%s: extract ptKi failed.\n", __func__); rv = 1; goto End; }; // c_{j+1} = h(P_1,...,P_n,alpha*G,alpha*H(P_j)) if (!bnA || !(BN_bin2bn(&sAlpha.e[0], EC_SECRET_SIZE, bnA))) { LogPrintf("%s: BN_bin2bn failed.\n", __func__); rv = 1; goto End; }; // ptT1 = alpha * G if (!EC_POINT_mul(ecGrp, ptT1, bnA, NULL, NULL, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT3 = H(Pj) if (hashToEC(&pPubkeys[nSecretOffset * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT2, ptT3) != 0) { LogPrintf("%s: hashToEC failed.\n", __func__); rv = 1; goto End; }; ssCjHash.write((const char*)tmpPkHash.begin(), 32); // ptT2 = alpha * H(P_j) // ptT2 = alpha * ptT3 if (!EC_POINT_mul(ecGrp, ptT2, NULL, ptT3, bnA, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; if ( !(EC_POINT_point2oct(ecGrp, ptT1, POINT_CONVERSION_COMPRESSED, &tempData[0], 33, bnCtx) == (int) EC_COMPRESSED_SIZE) || !(EC_POINT_point2oct(ecGrp, ptT2, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE)) { LogPrintf("%s: extract ptL and ptR failed.\n", __func__); rv = 1; goto End; }; ssCjHash.write((const char*)&tempData[0], 66); tmpHash = ssCjHash.GetHash(); if (!bnC || !(BN_bin2bn(tmpHash.begin(), EC_SECRET_SIZE, bnC)) // bnC lags i by 1 || !BN_mod(bnC, bnC, bnOrder, bnCtx)) { LogPrintf("%s: hash -> bnC failed.\n", __func__); rv = 1; goto End; }; // c_{j+2} = h(P_1,...,P_n,s_{j+1}*G+c_{j+1}*P_{j+1},s_{j+1}*H(P_{j+1})+c_{j+1}*I_j) for (int k = 0, ib = (nSecretOffset + 1) % nRingSize, i = (nSecretOffset + 2) % nRingSize; k < nRingSize; ++k, ib=i, i=(i+1) % nRingSize) { if (k == nRingSize - 1) { // s_j = alpha - c_j*x_j mod n. if (!bnT || !BN_bin2bn(&secret.e[0], EC_SECRET_SIZE, bnT)) { LogPrintf("%s: BN_bin2bn failed.\n", __func__); rv = 1; goto End; }; if (!BN_mul(bnT2, bnCj, bnT, bnCtx)) { LogPrintf("%s: BN_mul failed.\n", __func__); rv = 1; goto End; }; if (!BN_mod_sub(bnS, bnA, bnT2, bnOrder, bnCtx)) { LogPrintf("%s: BN_mod_sub failed.\n", __func__); rv = 1; goto End; }; if (!bnS || (nBytes = BN_num_bytes(bnS)) > (int) EC_SECRET_SIZE || BN_bn2bin(bnS, &pSigS[nSecretOffset * EC_SECRET_SIZE + (EC_SECRET_SIZE-nBytes)]) != nBytes) { LogPrintf("%s: bnS -> pSigS failed.\n", __func__); rv = 1; goto End; }; if (nSecretOffset != nRingSize - 1) break; }; if (!bnS || !(BN_bin2bn(&pSigS[ib * EC_SECRET_SIZE], EC_SECRET_SIZE, bnS))) { LogPrintf("%s: BN_bin2bn failed.\n", __func__); rv = 1; goto End; }; // bnC is from last round (ib) if (!EC_POINT_oct2point(ecGrp, ptPk, &pPubkeys[ib * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnCtx)) { LogPrintf("%s: EC_POINT_oct2point failed.\n", __func__); rv = 1; goto End; }; // ptT1 = s_{j+1}*G+c_{j+1}*P_{j+1} if (!EC_POINT_mul(ecGrp, ptT1, bnS, ptPk, bnC, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; //s_{j+1}*H(P_{j+1})+c_{j+1}*I_j if (hashToEC(&pPubkeys[ib * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT2, ptT2) != 0) { LogPrintf("%s: hashToEC failed.\n", __func__); rv = 1; goto End; }; // ptT3 = s_{j+1}*H(P_{j+1}) if (!EC_POINT_mul(ecGrp, ptT3, NULL, ptT2, bnS, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT4 = c_{j+1}*I_j if (!EC_POINT_mul(ecGrp, ptT4, NULL, ptKi, bnC, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT2 = ptT3 + ptT4 if (!EC_POINT_add(ecGrp, ptT2, ptT3, ptT4, bnCtx)) { LogPrintf("%s: EC_POINT_add failed.\n", __func__); rv = 1; goto End; }; if ( !(EC_POINT_point2oct(ecGrp, ptT1, POINT_CONVERSION_COMPRESSED, &tempData[0], 33, bnCtx) == (int) EC_COMPRESSED_SIZE) || !(EC_POINT_point2oct(ecGrp, ptT2, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE)) { LogPrintf("%s: extract ptL and ptR failed.\n", __func__); rv = 1; goto End; }; CHashWriter ssCHash(SER_GETHASH, PROTOCOL_VERSION); ssCHash.write((const char*)tmpPkHash.begin(), 32); ssCHash.write((const char*)&tempData[0], 66); tmpHash = ssCHash.GetHash(); if (!bnC || !(BN_bin2bn(tmpHash.begin(), EC_SECRET_SIZE, bnC)) // bnC lags i by 1 || !BN_mod(bnC, bnC, bnOrder, bnCtx)) { LogPrintf("%s: hash -> bnC failed.\n", __func__); rv = 1; goto End; }; if (i == nSecretOffset && !BN_copy(bnCj, bnC)) { LogPrintf("%s: BN_copy failed.\n", __func__); rv = 1; goto End; }; if (i == 0) { memset(tempData, 0, EC_SECRET_SIZE); if ((nBytes = BN_num_bytes(bnC)) > (int) EC_SECRET_SIZE || BN_bn2bin(bnC, &tempData[0 + (EC_SECRET_SIZE-nBytes)]) != nBytes) { LogPrintf("%s: bnC -> sigC failed.\n", __func__); rv = 1; goto End; }; try { sigC.resize(32); } catch (std::exception& e) { LogPrintf("%s: sigC.resize failed.\n", __func__); rv = 1; goto End; }; memcpy(&sigC[0], tempData, EC_SECRET_SIZE); }; }; End: EC_POINT_free(ptKi); EC_POINT_free(ptPk); EC_POINT_free(ptT1); EC_POINT_free(ptT2); EC_POINT_free(ptT3); EC_POINT_free(ptT4); BN_CTX_end(bnCtx); return rv; };
int verifyRingSignature(data_chunk &keyImage, uint256 &txnHash, int nRingSize, const uint8_t *pPubkeys, const uint8_t *pSigc, const uint8_t *pSigr) { if (fDebugRingSig) { // LogPrintf("%s size %d\n", __func__, nRingSize); // happens often }; int rv = 0; BN_CTX_start(bnCtx); BIGNUM *bnT = BN_CTX_get(bnCtx); BIGNUM *bnH = BN_CTX_get(bnCtx); BIGNUM *bnC = BN_CTX_get(bnCtx); BIGNUM *bnR = BN_CTX_get(bnCtx); BIGNUM *bnSum = BN_CTX_get(bnCtx); EC_POINT *ptT1 = NULL; EC_POINT *ptT2 = NULL; EC_POINT *ptT3 = NULL; EC_POINT *ptPk = NULL; EC_POINT *ptKi = NULL; EC_POINT *ptL = NULL; EC_POINT *ptR = NULL; EC_POINT *ptSi = NULL; uint8_t tempData[66]; // hold raw point data to hash uint256 commitHash; CHashWriter ssCommitHash(SER_GETHASH, PROTOCOL_VERSION); ssCommitHash << txnHash; // zero sum if (!bnSum || !(BN_zero(bnSum))) { LogPrintf("%s: BN_zero failed.\n", __func__); rv = 1; goto End; }; if ( !(ptT1 = EC_POINT_new(ecGrp)) || !(ptT2 = EC_POINT_new(ecGrp)) || !(ptT3 = EC_POINT_new(ecGrp)) || !(ptPk = EC_POINT_new(ecGrp)) || !(ptKi = EC_POINT_new(ecGrp)) || !(ptL = EC_POINT_new(ecGrp)) || !(ptSi = EC_POINT_new(ecGrp)) || !(ptR = EC_POINT_new(ecGrp))) { LogPrintf("%s: EC_POINT_new failed.\n", __func__); rv = 1; goto End; }; // get keyimage as point if (!(bnT = BN_bin2bn(&keyImage[0], EC_COMPRESSED_SIZE, bnT)) || !(ptKi) || !(ptKi = EC_POINT_bn2point(ecGrp, bnT, ptKi, bnCtx))) { LogPrintf("%s: extract ptKi failed.\n", __func__); rv = 1; goto End; }; for (int i = 0; i < nRingSize; ++i) { // Li = ci * Pi + ri * G // Ri = ci * I + ri * Hp(Pi) if ( !bnC || !(bnC = BN_bin2bn(&pSigc[i * EC_SECRET_SIZE], EC_SECRET_SIZE, bnC)) || !bnR || !(bnR = BN_bin2bn(&pSigr[i * EC_SECRET_SIZE], EC_SECRET_SIZE, bnR))) { LogPrintf("%s: extract bnC and bnR failed.\n", __func__); rv = 1; goto End; }; // get Pk i as point if (!(bnT = BN_bin2bn(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT)) || !(ptPk) || !(ptPk = EC_POINT_bn2point(ecGrp, bnT, ptPk, bnCtx))) { LogPrintf("%s: extract ptPk failed.\n", __func__); rv = 1; goto End; }; // ptT1 = ci * Pi if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptPk, bnC, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT2 = ri * G if (!EC_POINT_mul(ecGrp, ptT2, bnR, NULL, NULL, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptL = ptT1 + ptT2 if (!EC_POINT_add(ecGrp, ptL, ptT1, ptT2, bnCtx)) { LogPrintf("%s: EC_POINT_add failed.\n", __func__); rv = 1; goto End; }; // ptT3 = Hp(Pi) if (hashToEC(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT, ptT3) != 0) { LogPrintf("%s: hashToEC failed.\n", __func__); rv = 1; goto End; }; // DEBUGGING: ------- check if we can find the signer... // ptSi = Pi * bnT if ((!EC_POINT_mul(ecGrp, ptSi, NULL, ptPk, bnT, bnCtx) || false) && (rv = errorN(1, "%s: EC_POINT_mul failed.1", __func__))) goto End; if (0 == EC_POINT_cmp(ecGrp, ptSi, ptKi, bnCtx) ) LogPrintf("signer is index %d\n", i); // DEBUGGING: - End - check if we can find the signer... // ptT1 = k1 * I if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptKi, bnC, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT2 = k2 * ptT3 if (!EC_POINT_mul(ecGrp, ptT2, NULL, ptT3, bnR, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptR = ptT1 + ptT2 if (!EC_POINT_add(ecGrp, ptR, ptT1, ptT2, bnCtx)) { LogPrintf("%s: EC_POINT_add failed.\n", __func__); rv = 1; goto End; }; // sum = (sum + ci) % N if (!BN_mod_add(bnSum, bnSum, bnC, bnOrder, bnCtx)) { LogPrintf("%s: BN_mod_add failed.\n", __func__); rv = 1; goto End; }; // -- add ptL and ptR to hash if ( !(EC_POINT_point2oct(ecGrp, ptL, POINT_CONVERSION_COMPRESSED, &tempData[0], 33, bnCtx) == (int) EC_COMPRESSED_SIZE) || !(EC_POINT_point2oct(ecGrp, ptR, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE)) { LogPrintf("%s: extract ptL and ptR failed.\n", __func__); rv = 1; goto End; }; ssCommitHash.write((const char*)&tempData[0], 66); }; commitHash = ssCommitHash.GetHash(); if (!(bnH) || !(bnH = BN_bin2bn(commitHash.begin(), EC_SECRET_SIZE, bnH))) { LogPrintf("%s: commitHash -> bnH failed.\n", __func__); rv = 1; goto End; }; if (!BN_mod(bnH, bnH, bnOrder, bnCtx)) { LogPrintf("%s: BN_mod failed.\n", __func__); rv = 1; goto End; }; // bnT = (bnH - bnSum) % N if (!BN_mod_sub(bnT, bnH, bnSum, bnOrder, bnCtx)) { LogPrintf("%s: BN_mod_sub failed.\n", __func__); rv = 1; goto End; }; // test bnT == 0 (bnSum == bnH) if (!BN_is_zero(bnT)) { LogPrintf("%s: signature does not verify.\n", __func__); rv = 2; }; End: EC_POINT_free(ptT1); EC_POINT_free(ptT2); EC_POINT_free(ptT3); EC_POINT_free(ptPk); EC_POINT_free(ptKi); EC_POINT_free(ptL); EC_POINT_free(ptR); EC_POINT_free(ptSi); BN_CTX_end(bnCtx); return rv; };
int generateRingSignature(data_chunk &keyImage, uint256 &txnHash, int nRingSize, int nSecretOffset, ec_secret secret, const uint8_t *pPubkeys, uint8_t *pSigc, uint8_t *pSigr) { if (fDebugRingSig) LogPrintf("%s: Ring size %d.\n", __func__, nRingSize); int rv = 0; int nBytes; BN_CTX_start(bnCtx); BIGNUM *bnKS = BN_CTX_get(bnCtx); BIGNUM *bnK1 = BN_CTX_get(bnCtx); BIGNUM *bnK2 = BN_CTX_get(bnCtx); BIGNUM *bnT = BN_CTX_get(bnCtx); BIGNUM *bnH = BN_CTX_get(bnCtx); BIGNUM *bnSum = BN_CTX_get(bnCtx); EC_POINT *ptT1 = NULL; EC_POINT *ptT2 = NULL; EC_POINT *ptT3 = NULL; EC_POINT *ptPk = NULL; EC_POINT *ptKi = NULL; EC_POINT *ptL = NULL; EC_POINT *ptR = NULL; uint8_t tempData[66]; // hold raw point data to hash uint256 commitHash; ec_secret scData1, scData2; CHashWriter ssCommitHash(SER_GETHASH, PROTOCOL_VERSION); ssCommitHash << txnHash; // zero signature memset(pSigc, 0, EC_SECRET_SIZE * nRingSize); memset(pSigr, 0, EC_SECRET_SIZE * nRingSize); // ks = random 256 bit int mod P if (GenerateRandomSecret(scData1) && (rv = errorN(1, "%s: GenerateRandomSecret failed.", __func__))) goto End; if (!bnKS || !(BN_bin2bn(&scData1.e[0], EC_SECRET_SIZE, bnKS))) { LogPrintf("%s: BN_bin2bn failed.\n", __func__); rv = 1; goto End; }; // zero sum if (!bnSum || !(BN_zero(bnSum))) { LogPrintf("%s: BN_zero failed.\n", __func__); rv = 1; goto End; }; if ( !(ptT1 = EC_POINT_new(ecGrp)) || !(ptT2 = EC_POINT_new(ecGrp)) || !(ptT3 = EC_POINT_new(ecGrp)) || !(ptPk = EC_POINT_new(ecGrp)) || !(ptKi = EC_POINT_new(ecGrp)) || !(ptL = EC_POINT_new(ecGrp)) || !(ptR = EC_POINT_new(ecGrp))) { LogPrintf("%s: EC_POINT_new failed.\n", __func__); rv = 1; goto End; }; // get keyimage as point if (!(bnT = BN_bin2bn(&keyImage[0], EC_COMPRESSED_SIZE, bnT)) || !(ptKi) || !(ptKi = EC_POINT_bn2point(ecGrp, bnT, ptKi, bnCtx))) { LogPrintf("%s: extract ptKi failed.\n", __func__); rv = 1; goto End; }; for (int i = 0; i < nRingSize; ++i) { if (i == nSecretOffset) { // k = random 256 bit int mod P // L = k * G // R = k * HashToEC(PKi) if (!EC_POINT_mul(ecGrp, ptL, bnKS, NULL, NULL, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; if (hashToEC(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT, ptT1) != 0) { LogPrintf("%s: hashToEC failed.\n", __func__); rv = 1; goto End; }; if (!EC_POINT_mul(ecGrp, ptR, NULL, ptT1, bnKS, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; } else { // k1 = random 256 bit int mod P // k2 = random 256 bit int mod P // Li = k1 * Pi + k2 * G // Ri = k1 * I + k2 * Hp(Pi) // ci = k1 // ri = k2 if (GenerateRandomSecret(scData1) != 0 || !bnK1 || !(BN_bin2bn(&scData1.e[0], EC_SECRET_SIZE, bnK1)) || GenerateRandomSecret(scData2) != 0 || !bnK2 || !(BN_bin2bn(&scData2.e[0], EC_SECRET_SIZE, bnK2))) { LogPrintf("%s: k1 and k2 failed.\n", __func__); rv = 1; goto End; }; // get Pk i as point if (!(bnT = BN_bin2bn(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT)) || !(ptPk) || !(ptPk = EC_POINT_bn2point(ecGrp, bnT, ptPk, bnCtx))) { LogPrintf("%s: extract ptPk failed.\n", __func__); rv = 1; goto End; }; // ptT1 = k1 * Pi if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptPk, bnK1, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT2 = k2 * G if (!EC_POINT_mul(ecGrp, ptT2, bnK2, NULL, NULL, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptL = ptT1 + ptT2 if (!EC_POINT_add(ecGrp, ptL, ptT1, ptT2, bnCtx)) { LogPrintf("%s: EC_POINT_add failed.\n", __func__); rv = 1; goto End; }; // ptT3 = Hp(Pi) if (hashToEC(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT, ptT3) != 0) { LogPrintf("%s: hashToEC failed.\n", __func__); rv = 1; goto End; }; // ptT1 = k1 * I if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptKi, bnK1, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT2 = k2 * ptT3 if (!EC_POINT_mul(ecGrp, ptT2, NULL, ptT3, bnK2, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptR = ptT1 + ptT2 if (!EC_POINT_add(ecGrp, ptR, ptT1, ptT2, bnCtx)) { LogPrintf("%s: EC_POINT_add failed.\n", __func__); rv = 1; goto End; }; memcpy(&pSigc[i * EC_SECRET_SIZE], &scData1.e[0], EC_SECRET_SIZE); memcpy(&pSigr[i * EC_SECRET_SIZE], &scData2.e[0], EC_SECRET_SIZE); // sum = (sum + sigc) % N , sigc == bnK1 if (!BN_mod_add(bnSum, bnSum, bnK1, bnOrder, bnCtx)) { LogPrintf("%s: BN_mod_add failed.\n", __func__); rv = 1; goto End; }; }; // -- add ptL and ptR to hash if ( !(EC_POINT_point2oct(ecGrp, ptL, POINT_CONVERSION_COMPRESSED, &tempData[0], 33, bnCtx) == (int) EC_COMPRESSED_SIZE) || !(EC_POINT_point2oct(ecGrp, ptR, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE)) { LogPrintf("%s: extract ptL and ptR failed.\n", __func__); rv = 1; goto End; }; ssCommitHash.write((const char*)&tempData[0], 66); }; commitHash = ssCommitHash.GetHash(); if (!(bnH) || !(bnH = BN_bin2bn(commitHash.begin(), EC_SECRET_SIZE, bnH))) { LogPrintf("%s: commitHash -> bnH failed.\n", __func__); rv = 1; goto End; }; if (!BN_mod(bnH, bnH, bnOrder, bnCtx)) // this is necessary { LogPrintf("%s: BN_mod failed.\n", __func__); rv = 1; goto End; }; // sigc[nSecretOffset] = (bnH - bnSum) % N if (!BN_mod_sub(bnT, bnH, bnSum, bnOrder, bnCtx)) { LogPrintf("%s: BN_mod_sub failed.\n", __func__); rv = 1; goto End; }; if ((nBytes = BN_num_bytes(bnT)) > (int)EC_SECRET_SIZE || BN_bn2bin(bnT, &pSigc[nSecretOffset * EC_SECRET_SIZE + (EC_SECRET_SIZE-nBytes)]) != nBytes) { LogPrintf("%s: bnT -> pSigc failed.\n", __func__); rv = 1; goto End; }; // sigr[nSecretOffset] = (bnKS - sigc[nSecretOffset] * bnSecret) % N // reuse bnH for bnSecret if (!bnH || !(BN_bin2bn(&secret.e[0], EC_SECRET_SIZE, bnH))) { LogPrintf("%s: BN_bin2bn failed.\n", __func__); rv = 1; goto End; }; // bnT = sigc[nSecretOffset] * bnSecret , TODO: mod N ? if (!BN_mul(bnT, bnT, bnH, bnCtx)) { LogPrintf("%s: BN_mul failed.\n", __func__); rv = 1; goto End; }; if (!BN_mod_sub(bnT, bnKS, bnT, bnOrder, bnCtx)) { LogPrintf("%s: BN_mod_sub failed.\n", __func__); rv = 1; goto End; }; if ((nBytes = BN_num_bytes(bnT)) > (int) EC_SECRET_SIZE || BN_bn2bin(bnT, &pSigr[nSecretOffset * EC_SECRET_SIZE + (EC_SECRET_SIZE-nBytes)]) != nBytes) { LogPrintf("%s: bnT -> pSigr failed.\n", __func__); rv = 1; goto End; }; End: EC_POINT_free(ptT1); EC_POINT_free(ptT2); EC_POINT_free(ptT3); EC_POINT_free(ptPk); EC_POINT_free(ptKi); EC_POINT_free(ptL); EC_POINT_free(ptR); BN_CTX_end(bnCtx); return rv; };
// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields // recid selects which key is recovered // if check is nonzero, additional checks are performed int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) { if (!eckey) return 0; int ret = 0; BN_CTX *ctx = NULL; BIGNUM *x = NULL; BIGNUM *e = NULL; BIGNUM *order = NULL; BIGNUM *sor = NULL; BIGNUM *eor = NULL; BIGNUM *field = NULL; EC_POINT *R = NULL; EC_POINT *O = NULL; EC_POINT *Q = NULL; BIGNUM *rr = NULL; BIGNUM *zero = NULL; int n = 0; int i = recid / 2; const EC_GROUP *group = EC_KEY_get0_group(eckey); if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } BN_CTX_start(ctx); order = BN_CTX_get(ctx); if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } x = BN_CTX_get(ctx); if (!BN_copy(x, order)) { ret=-1; goto err; } if (!BN_mul_word(x, i)) { ret=-1; goto err; } if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } field = BN_CTX_get(ctx); if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } if (BN_cmp(x, field) >= 0) { ret=0; goto err; } if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } if (check) { if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } } if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } n = EC_GROUP_get_degree(group); e = BN_CTX_get(ctx); if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); zero = BN_CTX_get(ctx); if (!BN_zero(zero)) { ret=-1; goto err; } if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } rr = BN_CTX_get(ctx); if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } sor = BN_CTX_get(ctx); if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } eor = BN_CTX_get(ctx); if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } ret = 1; err: if (ctx) { BN_CTX_end(ctx); BN_CTX_free(ctx); } if (R != NULL) EC_POINT_free(R); if (O != NULL) EC_POINT_free(O); if (Q != NULL) EC_POINT_free(Q); return ret; }
// unsigned char *rgbHashData, 哈希 // unsigned char *rgbKeyDb, 私钥 // unsigned char *rs 签名 void eccHashSign(unsigned char *rgbHashData, unsigned char *rgbKeyDb, unsigned char *rs) { int ok = 0; const EC_GROUP *ec_group; BIGNUM *priv_key; const BIGNUM *ck; BIGNUM *k = NULL; BN_CTX *ctx = NULL; BIGNUM *order = NULL; BIGNUM *e = NULL; BIGNUM *bn = NULL; int i; BIGNUM *r= BN_new(), *s = BN_new(); EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_sm2p256v1); ec_group = EC_KEY_get0_group(ec_key); priv_key = BN_new(); BN_bin2bn(rgbKeyDb, 32, priv_key); EC_KEY_set_private_key(ec_key, priv_key); if (!ec_group || !priv_key) { } ctx = BN_CTX_new(); order = BN_new(); e = BN_new(); bn = BN_new(); if (!ctx || !order || !e || !bn) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE); goto err; } if (!EC_GROUP_get_order(ec_group, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_EC_LIB); goto err; } /* convert dgst to e */ i = BN_num_bits(order); #if 0 if (8 * dgst_len > i) { dgst_len = (i + 7)/8; } #endif if (!BN_bin2bn(rgbHashData, 32, e)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } #if 0 if ((8 * dgst_len > i) && !BN_rshift(e, e, 8 - (i & 0x7))) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } #endif do { /* use or compute k and (kG).x */ if (!sm2_sign_setup(ec_key, ctx, &k, &r)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN,ERR_R_ECDSA_LIB); goto err; } ck = k; /* r = e + x (mod n) */ if (!BN_mod_add(r, r, e, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } if (!BN_mod_add(bn, r, ck, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } /* check r != 0 && r + k != n */ if (BN_is_zero(r) || BN_is_zero(bn)) { continue; } /* s = ((1 + d)^-1 * (k - rd)) mod n */ if (!BN_one(bn)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } if (!BN_mod_add(s, priv_key, bn, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } if (!BN_mod_inverse(s, s, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } if (!BN_mod_mul(bn, r, priv_key, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } if (!BN_mod_sub(bn, ck, bn, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } if (!BN_mod_mul(s, s, bn, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); goto err; } /* check s != 0 */ if (!BN_is_zero(s)) break; } while (1); ok = 1; BN_bn2bin(r, rs); BN_bn2bin(s, rs + 32); err: if (k) BN_free(k); if (ctx) BN_CTX_free(ctx); if (order) BN_free(order); if (e) BN_free(e); if (bn) BN_free(bn); }