5 #include <openssl/ecdsa.h>
6 #include <openssl/rand.h>
7 #include <openssl/obj_mac.h>
16 int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
20 EC_POINT *pub_key = NULL;
24 const EC_GROUP *group = EC_KEY_get0_group(eckey);
26 if ((ctx = BN_CTX_new()) == NULL)
29 pub_key = EC_POINT_new(group);
34 if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
37 EC_KEY_set_private_key(eckey,priv_key);
38 EC_KEY_set_public_key(eckey,pub_key);
45 EC_POINT_free(pub_key);
55 int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig,
const unsigned char *msg,
int msglen,
int recid,
int check)
76 const EC_GROUP *group = EC_KEY_get0_group(eckey);
77 if ((ctx = BN_CTX_new()) == NULL) { ret = -1;
goto err; }
79 order = BN_CTX_get(ctx);
80 if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2;
goto err; }
82 if (!BN_copy(x, order)) { ret=-1;
goto err; }
83 if (!BN_mul_word(x, i)) { ret=-1;
goto err; }
84 if (!BN_add(x, x, ecsig->r)) { ret=-1;
goto err; }
85 field = BN_CTX_get(ctx);
86 if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2;
goto err; }
87 if (BN_cmp(x, field) >= 0) { ret=0;
goto err; }
88 if ((R = EC_POINT_new(group)) == NULL) { ret = -2;
goto err; }
89 if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0;
goto err; }
92 if ((O = EC_POINT_new(group)) == NULL) { ret = -2;
goto err; }
93 if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2;
goto err; }
94 if (!EC_POINT_is_at_infinity(group, O)) { ret = 0;
goto err; }
96 if ((Q = EC_POINT_new(group)) == NULL) { ret = -2;
goto err; }
97 n = EC_GROUP_get_degree(group);
99 if (!BN_bin2bn(msg, msglen, e)) { ret=-1;
goto err; }
100 if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
101 zero = BN_CTX_get(ctx);
102 if (!BN_zero(zero)) { ret=-1;
goto err; }
103 if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1;
goto err; }
104 rr = BN_CTX_get(ctx);
105 if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1;
goto err; }
106 sor = BN_CTX_get(ctx);
107 if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1;
goto err; }
108 eor = BN_CTX_get(ctx);
109 if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1;
goto err; }
110 if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2;
goto err; }
111 if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2;
goto err; }
120 if (R != NULL) EC_POINT_free(R);
121 if (O != NULL) EC_POINT_free(O);
122 if (Q != NULL) EC_POINT_free(Q);
133 pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
134 assert(pkey != NULL);
141 void GetSecretBytes(
unsigned char vch[32])
const {
142 const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
144 int nBytes = BN_num_bytes(bn);
145 int n=BN_bn2bin(bn,&vch[32 - nBytes]);
147 memset(vch, 0, 32 - nBytes);
150 void SetSecretBytes(
const unsigned char vch[32]) {
153 assert(BN_bin2bn(vch, 32, &bn));
154 assert(EC_KEY_regenerate_key(pkey, &bn));
158 void GetPrivKey(
CPrivKey &privkey,
bool fCompressed) {
159 EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
160 int nSize = i2d_ECPrivateKey(pkey, NULL);
162 privkey.resize(nSize);
163 unsigned char* pbegin = &privkey[0];
164 int nSize2 = i2d_ECPrivateKey(pkey, &pbegin);
165 assert(nSize == nSize2);
168 bool SetPrivKey(
const CPrivKey &privkey) {
169 const unsigned char* pbegin = &privkey[0];
170 if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) {
173 if (EC_KEY_check_key(pkey))
179 void GetPubKey(
CPubKey &pubkey,
bool fCompressed) {
180 EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
181 int nSize = i2o_ECPublicKey(pkey, NULL);
185 unsigned char *pbegin = c;
186 int nSize2 = i2o_ECPublicKey(pkey, &pbegin);
187 assert(nSize == nSize2);
188 pubkey.
Set(&c[0], &c[nSize]);
191 bool SetPubKey(
const CPubKey &pubkey) {
192 const unsigned char* pbegin = pubkey.
begin();
193 return o2i_ECPublicKey(&pkey, &pbegin, pubkey.
size());
196 bool Sign(
const uint256 &
hash, std::vector<unsigned char>& vchSig) {
197 unsigned int nSize = ECDSA_size(pkey);
198 vchSig.resize(nSize);
199 assert(ECDSA_sign(0, (
unsigned char*)&hash,
sizeof(hash), &vchSig[0], &nSize, pkey));
200 vchSig.resize(nSize);
204 bool Verify(
const uint256 &hash,
const std::vector<unsigned char>& vchSig) {
206 if (ECDSA_verify(0, (
unsigned char*)&hash,
sizeof(hash), &vchSig[0], vchSig.
size(), pkey) != 1)
211 bool SignCompact(
const uint256 &hash,
unsigned char *p64,
int &rec) {
213 ECDSA_SIG *sig = ECDSA_do_sign((
unsigned char*)&hash,
sizeof(hash), pkey);
217 int nBitsR = BN_num_bits(sig->r);
218 int nBitsS = BN_num_bits(sig->s);
219 if (nBitsR <= 256 && nBitsS <= 256) {
221 GetPubKey(pubkey,
true);
222 for (
int i=0; i<4; i++) {
224 if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (
unsigned char*)&hash,
sizeof(hash), i, 1) == 1) {
226 keyRec.GetPubKey(pubkeyRec,
true);
227 if (pubkeyRec == pubkey) {
235 BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]);
236 BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]);
246 bool Recover(
const uint256 &hash,
const unsigned char *p64,
int rec)
250 ECDSA_SIG *sig = ECDSA_SIG_new();
251 BN_bin2bn(&p64[0], 32, sig->r);
252 BN_bin2bn(&p64[32], 32, sig->s);
253 bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (
unsigned char*)&hash,
sizeof(hash), rec, 0) == 1;
264 static const unsigned char vchMax[32] = {
265 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
266 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
267 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
268 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
271 for (
int i=0; i<32 && fIsZero; i++)
276 for (
int i=0; i<32; i++) {
277 if (vch[i] < vchMax[i])
279 if (vch[i] > vchMax[i])
287 RAND_bytes(vch,
sizeof(vch));
288 }
while (!
Check(vch));
290 fCompressed = fCompressedIn;
295 if (!key.SetPrivKey(privkey))
297 key.GetSecretBytes(vch);
298 fCompressed = fCompressedIn;
306 key.SetSecretBytes(vch);
308 key.GetPrivKey(privkey, fCompressed);
315 key.SetSecretBytes(vch);
317 key.GetPubKey(pubkey, fCompressed);
325 key.SetSecretBytes(vch);
326 return key.Sign(hash, vchSig);
333 key.SetSecretBytes(vch);
336 if (!key.SignCompact(hash, &vchSig[1], rec))
339 vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
347 if (!key.SetPubKey(*
this))
349 if (!key.Verify(hash, vchSig))
355 if (vchSig.size() != 65)
358 if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
360 key.GetPubKey(*
this, (vchSig[0] - 27) & 4);
367 if (vchSig.size() != 65)
370 if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
374 if (*
this != pubkeyRec)
383 if (!key.SetPubKey(*
this))
392 if (!key.SetPubKey(*
this))
394 key.GetPubKey(*
this,
false);
bool VerifyCompact(const uint256 &hash, const std::vector< unsigned char > &vchSig) const
unsigned int size() const
void Set(const T pbegin, const T pend)
bool Sign(const uint256 &hash, std::vector< unsigned char > &vchSig) const
std::vector< unsigned char, secure_allocator< unsigned char > > CPrivKey
CPubKey GetPubKey() const
CPrivKey GetPrivKey() const
bool RecoverCompact(const uint256 &hash, const std::vector< unsigned char > &vchSig)
An encapsulated public key.
void MakeNewKey(bool fCompressed)
const unsigned char * begin() const
bool IsCompressed() const
bool SetPrivKey(const CPrivKey &vchPrivKey, bool fCompressed)
bool SignCompact(const uint256 &hash, std::vector< unsigned char > &vchSig) const
bool IsFullyValid() const
static bool Check(const unsigned char *vch)
bool Verify(const uint256 &hash, const std::vector< unsigned char > &vchSig) const
unsigned int size() const