// create a compact signature (65 bytes), which allows reconstructing the used public key // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, // 0x1D = second key with even y, 0x1E = second key with odd y bool CKey::SignCompact(uint256 hash, std::vector<unsigned char> &vchSig) { bool fOk = false; ECDSA_SIG *sig = ECDSA_do_sign((unsigned char *)&hash, sizeof(hash), pkey); if (sig == NULL) return false; vchSig.clear(); vchSig.resize(65, 0); int nBitsR = BN_num_bits(sig->r); int nBitsS = BN_num_bits(sig->s); if (nBitsR <= 256 && nBitsS <= 256) { int nRecId = -1; for (int i = 0; i < 4; i++) { CKey keyRec; keyRec.fSet = true; if (fCompressedPubKey) keyRec.SetCompressedPubKey(); if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char *)&hash, sizeof(hash), i, 1) == 1) if (keyRec.GetPubKey() == this->GetPubKey()) { nRecId = i; break; } } if (nRecId == -1) throw key_error("CKey::SignCompact() : unable to construct recoverable key"); vchSig[0] = nRecId + 27 + (fCompressedPubKey ? 4 : 0); BN_bn2bin(sig->r, &vchSig[33 - (nBitsR + 7) / 8]); BN_bn2bin(sig->s, &vchSig[65 - (nBitsS + 7) / 8]); fOk = true; } ECDSA_SIG_free(sig); return fOk; }
// BCPKI CKey CKey::GetDerivedKey(std::vector<unsigned char> ticket) const { BIGNUM *bn = BN_bin2bn(&ticket[0],ticket.size(),BN_new()); BN_CTX *ctx = NULL; if ((ctx = BN_CTX_new()) == NULL) throw key_error("CKey::DeriveKey() : BN_CTX_new failed"); CKey key; if (HasPrivKey()) { // privkey = privkey + ticket // snippet from ECDSA_SIG_recover_key_GFp // TODO check this again BIGNUM *order = NULL; if ((order = BN_new()) == NULL) throw key_error("CKey::DeriveKey() : BN_new failed"); // BN_CTX_start(ctx); //order = BN_CTX_get(ctx); if (!EC_GROUP_get_order(EC_KEY_get0_group(pkey), order, ctx)) throw key_error("CKey::DeriveKey() : EC_GROUP_get_order failed"); if (!BN_mod_add(bn, bn, EC_KEY_get0_private_key(pkey), order, ctx)) throw key_error("CKey::DeriveKey() : BN_mod_add failed"); if (!EC_KEY_regenerate_key(key.pkey,bn)) // sets private AND public key throw key_error("CKey::DeriveKey() : EC_KEY_regenerate_key failed"); // if (!EC_KEY_set_private_key(key.pkey, bn)) // throw key_error("CKey::DeriveKey() : EC_KEY_set_private_key failed"); if (!EC_KEY_check_key(key.pkey)) throw key_error("CKey::DeriveKey() : EC_KEY_check_key failed"); } else { // add to pub key // begin snippet from EC_KEY_regenerate_key EC_POINT *pub_key = NULL; const EC_GROUP *group = EC_KEY_get0_group(pkey); pub_key = EC_POINT_new(group); if (pub_key == NULL) throw key_error("CKey::DeriveKey() : EC_POINT_new failed"); if (!EC_POINT_mul(group, pub_key, bn, NULL, NULL, ctx)) throw key_error("CKey::DeriveKey() : EC_POINT_mul failed"); // end snippet from EC_KEY_regenerate_key // now pub_key = ticket * basepoint //const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *); //int EC_POINT_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *); if (!EC_POINT_add(group, pub_key, pub_key, EC_KEY_get0_public_key(pkey), ctx)) throw key_error("CKey::DeriveKey() : EC_POINT_add failed"); //int EC_KEY_set_public_key(EC_KEY *, const EC_POINT *); if (!EC_KEY_set_public_key(key.pkey, pub_key)) throw key_error("CKey::DeriveKey() : EC_KEY_set_public_key failed"); }; key.fSet = true; key.SetCompressedPubKey(); return key; };
// create a compact signature (65 bytes), which allows reconstructing the used public key // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, // 0x1D = second key with even y, 0x1E = second key with odd y bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig) { bool fOk = false; ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); if (sig==NULL) return false; const EC_GROUP *group = EC_KEY_get0_group(pkey); CBigNum order, halforder; EC_GROUP_get_order(group, &order, NULL); BN_rshift1(&halforder, &order); // enforce low S values, by negating the value (modulo the order) if above order/2. if (BN_cmp(sig->s, &halforder) > 0) { BN_sub(sig->s, &order, sig->s); } vchSig.clear(); vchSig.resize(65,0); int nBitsR = BN_num_bits(sig->r); int nBitsS = BN_num_bits(sig->s); if (nBitsR <= 256 && nBitsS <= 256) { int nRecId = -1; for (int i=0; i<4; i++) { CKey keyRec; keyRec.fSet = true; if (fCompressedPubKey) keyRec.SetCompressedPubKey(); if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) if (keyRec.GetPubKey() == this->GetPubKey()) { nRecId = i; break; } } if (nRecId == -1) { ECDSA_SIG_free(sig); throw key_error("CKey::SignCompact() : unable to construct recoverable key"); } vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0); BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]); fOk = true; } ECDSA_SIG_free(sig); return fOk; }