key.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. // ECOin - Copyright (c) - 2014/2021 - GPLv3 - epsylon@riseup.net (https://03c8.net)
  2. #include <map>
  3. #include <openssl/ecdsa.h>
  4. #include <openssl/obj_mac.h>
  5. #include "key.h"
  6. int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
  7. {
  8. int ok = 0;
  9. BN_CTX *ctx = NULL;
  10. EC_POINT *pub_key = NULL;
  11. if (!eckey) return 0;
  12. const EC_GROUP *group = EC_KEY_get0_group(eckey);
  13. if ((ctx = BN_CTX_new()) == NULL)
  14. goto err;
  15. pub_key = EC_POINT_new(group);
  16. if (pub_key == NULL)
  17. goto err;
  18. if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
  19. goto err;
  20. EC_KEY_set_private_key(eckey,priv_key);
  21. EC_KEY_set_public_key(eckey,pub_key);
  22. ok = 1;
  23. err:
  24. if (pub_key)
  25. EC_POINT_free(pub_key);
  26. if (ctx != NULL)
  27. BN_CTX_free(ctx);
  28. return(ok);
  29. }
  30. int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
  31. {
  32. if (!eckey) return 0;
  33. int ret = 0;
  34. BN_CTX *ctx = NULL;
  35. BIGNUM *x = NULL;
  36. BIGNUM *e = NULL;
  37. BIGNUM *order = NULL;
  38. BIGNUM *sor = NULL;
  39. BIGNUM *eor = NULL;
  40. BIGNUM *field = NULL;
  41. EC_POINT *R = NULL;
  42. EC_POINT *O = NULL;
  43. EC_POINT *Q = NULL;
  44. BIGNUM *rr = NULL;
  45. BIGNUM *zero = NULL;
  46. int n = 0;
  47. int i = recid / 2;
  48. const EC_GROUP *group = EC_KEY_get0_group(eckey);
  49. if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
  50. BN_CTX_start(ctx);
  51. order = BN_CTX_get(ctx);
  52. if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
  53. x = BN_CTX_get(ctx);
  54. if (!BN_copy(x, order)) { ret=-1; goto err; }
  55. if (!BN_mul_word(x, i)) { ret=-1; goto err; }
  56. if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
  57. field = BN_CTX_get(ctx);
  58. if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
  59. if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
  60. if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
  61. if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
  62. if (check)
  63. {
  64. if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
  65. if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
  66. if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
  67. }
  68. if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
  69. n = EC_GROUP_get_degree(group);
  70. e = BN_CTX_get(ctx);
  71. if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
  72. if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
  73. zero = BN_CTX_get(ctx);
  74. if (!BN_zero(zero)) { ret=-1; goto err; }
  75. if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
  76. rr = BN_CTX_get(ctx);
  77. if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
  78. sor = BN_CTX_get(ctx);
  79. if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
  80. eor = BN_CTX_get(ctx);
  81. if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
  82. if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
  83. if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
  84. ret = 1;
  85. err:
  86. if (ctx) {
  87. BN_CTX_end(ctx);
  88. BN_CTX_free(ctx);
  89. }
  90. if (R != NULL) EC_POINT_free(R);
  91. if (O != NULL) EC_POINT_free(O);
  92. if (Q != NULL) EC_POINT_free(Q);
  93. return ret;
  94. }
  95. void CKey::SetCompressedPubKey()
  96. {
  97. EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
  98. fCompressedPubKey = true;
  99. }
  100. void CKey::Reset()
  101. {
  102. fCompressedPubKey = false;
  103. if (pkey != NULL)
  104. EC_KEY_free(pkey);
  105. pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
  106. if (pkey == NULL)
  107. throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
  108. fSet = false;
  109. }
  110. CKey::CKey()
  111. {
  112. pkey = NULL;
  113. Reset();
  114. }
  115. CKey::CKey(const CKey& b)
  116. {
  117. pkey = EC_KEY_dup(b.pkey);
  118. if (pkey == NULL)
  119. throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
  120. fSet = b.fSet;
  121. }
  122. CKey& CKey::operator=(const CKey& b)
  123. {
  124. if (!EC_KEY_copy(pkey, b.pkey))
  125. throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
  126. fSet = b.fSet;
  127. return (*this);
  128. }
  129. CKey::~CKey()
  130. {
  131. EC_KEY_free(pkey);
  132. }
  133. bool CKey::IsNull() const
  134. {
  135. return !fSet;
  136. }
  137. bool CKey::IsCompressed() const
  138. {
  139. return fCompressedPubKey;
  140. }
  141. void CKey::MakeNewKey(bool fCompressed)
  142. {
  143. if (!EC_KEY_generate_key(pkey))
  144. throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
  145. if (fCompressed)
  146. SetCompressedPubKey();
  147. fSet = true;
  148. }
  149. bool CKey::SetPrivKey(const CPrivKey& vchPrivKey)
  150. {
  151. const unsigned char* pbegin = &vchPrivKey[0];
  152. if (d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
  153. {
  154. if (EC_KEY_check_key(pkey))
  155. {
  156. fSet = true;
  157. return true;
  158. }
  159. }
  160. pkey = NULL;
  161. Reset();
  162. return false;
  163. }
  164. bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed)
  165. {
  166. EC_KEY_free(pkey);
  167. pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
  168. if (pkey == NULL)
  169. throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
  170. if (vchSecret.size() != 32)
  171. throw key_error("CKey::SetSecret() : secret must be 32 bytes");
  172. BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
  173. if (bn == NULL)
  174. throw key_error("CKey::SetSecret() : BN_bin2bn failed");
  175. if (!EC_KEY_regenerate_key(pkey,bn))
  176. {
  177. BN_clear_free(bn);
  178. throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
  179. }
  180. BN_clear_free(bn);
  181. fSet = true;
  182. if (fCompressed || fCompressedPubKey)
  183. SetCompressedPubKey();
  184. return true;
  185. }
  186. CSecret CKey::GetSecret(bool &fCompressed) const
  187. {
  188. CSecret vchRet;
  189. vchRet.resize(32);
  190. const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
  191. int nBytes = BN_num_bytes(bn);
  192. if (bn == NULL)
  193. throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
  194. int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
  195. if (n != nBytes)
  196. throw key_error("CKey::GetSecret(): BN_bn2bin failed");
  197. fCompressed = fCompressedPubKey;
  198. return vchRet;
  199. }
  200. CPrivKey CKey::GetPrivKey() const
  201. {
  202. int nSize = i2d_ECPrivateKey(pkey, NULL);
  203. if (!nSize)
  204. throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
  205. CPrivKey vchPrivKey(nSize, 0);
  206. unsigned char* pbegin = &vchPrivKey[0];
  207. if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
  208. throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
  209. return vchPrivKey;
  210. }
  211. bool CKey::SetPubKey(const CPubKey& vchPubKey)
  212. {
  213. const unsigned char* pbegin = &vchPubKey.vchPubKey[0];
  214. if (o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size()))
  215. {
  216. fSet = true;
  217. if (vchPubKey.vchPubKey.size() == 33)
  218. SetCompressedPubKey();
  219. return true;
  220. }
  221. pkey = NULL;
  222. Reset();
  223. return false;
  224. }
  225. CPubKey CKey::GetPubKey() const
  226. {
  227. int nSize = i2o_ECPublicKey(pkey, NULL);
  228. if (!nSize)
  229. throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
  230. std::vector<unsigned char> vchPubKey(nSize, 0);
  231. unsigned char* pbegin = &vchPubKey[0];
  232. if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
  233. throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
  234. return CPubKey(vchPubKey);
  235. }
  236. bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
  237. {
  238. unsigned int nSize = ECDSA_size(pkey);
  239. vchSig.resize(nSize); // Make sure it is big enough
  240. if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
  241. {
  242. vchSig.clear();
  243. return false;
  244. }
  245. vchSig.resize(nSize); // Shrink to fit actual size
  246. return true;
  247. }
  248. bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
  249. {
  250. bool fOk = false;
  251. ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
  252. if (sig==NULL)
  253. return false;
  254. vchSig.clear();
  255. vchSig.resize(65,0);
  256. int nBitsR = BN_num_bits(sig->r);
  257. int nBitsS = BN_num_bits(sig->s);
  258. if (nBitsR <= 256 && nBitsS <= 256)
  259. {
  260. int nRecId = -1;
  261. for (int i=0; i<4; i++)
  262. {
  263. CKey keyRec;
  264. keyRec.fSet = true;
  265. if (fCompressedPubKey)
  266. keyRec.SetCompressedPubKey();
  267. if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
  268. if (keyRec.GetPubKey() == this->GetPubKey())
  269. {
  270. nRecId = i;
  271. break;
  272. }
  273. }
  274. if (nRecId == -1)
  275. {
  276. ECDSA_SIG_free(sig);
  277. throw key_error("CKey::SignCompact() : unable to construct recoverable key");
  278. }
  279. vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
  280. BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
  281. BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
  282. fOk = true;
  283. }
  284. ECDSA_SIG_free(sig);
  285. return fOk;
  286. }
  287. bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
  288. {
  289. if (vchSig.size() != 65)
  290. return false;
  291. int nV = vchSig[0];
  292. if (nV<27 || nV>=35)
  293. return false;
  294. ECDSA_SIG *sig = ECDSA_SIG_new();
  295. BN_bin2bn(&vchSig[1],32,sig->r);
  296. BN_bin2bn(&vchSig[33],32,sig->s);
  297. EC_KEY_free(pkey);
  298. pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
  299. if (nV >= 31)
  300. {
  301. SetCompressedPubKey();
  302. nV -= 4;
  303. }
  304. if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
  305. {
  306. fSet = true;
  307. ECDSA_SIG_free(sig);
  308. return true;
  309. }
  310. ECDSA_SIG_free(sig);
  311. return false;
  312. }
  313. bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
  314. {
  315. if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
  316. return false;
  317. return true;
  318. }
  319. bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
  320. {
  321. CKey key;
  322. if (!key.SetCompactSignature(hash, vchSig))
  323. return false;
  324. if (GetPubKey() != key.GetPubKey())
  325. return false;
  326. return true;
  327. }
  328. bool CKey::IsValid()
  329. {
  330. if (!fSet)
  331. return false;
  332. if (!EC_KEY_check_key(pkey))
  333. return false;
  334. bool fCompr;
  335. CSecret secret = GetSecret(fCompr);
  336. CKey key2;
  337. key2.SetSecret(secret, fCompr);
  338. return GetPubKey() == key2.GetPubKey();
  339. }