//Сумма 2-х точек //a4=A //a6=B //a1,a2,a3=0 ec_point ec_point::operator +(ec_point op2){ ec_curve * ec_singleton = ec_curve::Instance(); ZZ x3,y3,lambda,nu; //Обработка случаев, если среди операндов нуль группы if (is_infinity() && op2.is_infinity()) return ec_point(true); if (is_infinity()) return ec_point(op2.x,op2.y); if (op2.is_infinity()) return ec_point(x,y); //Нулей нет, дальше всё по Вейерштрассу if ((x==op2.x) && (y==NegateMod(op2.y,ec_singleton->p))) { //Если две противоположные точки, результатом будет нуль группы return ec_point(true); } else { if (x!=op2.x) { //Если сладываем две разные точки lambda = (((op2.y-y)%ec_singleton->p) * InvMod((op2.x-x)%ec_singleton->p,ec_singleton->p))%ec_singleton->p; } else { //Если удваиваем точку lambda = ((3*x*x+ec_singleton->A)%ec_singleton->p * InvMod((2*y)%ec_singleton->p,ec_singleton->p))%ec_singleton->p; } x3 = (lambda*lambda - x - op2.x)%ec_singleton->p; y3 = (lambda*(x-x3)-y)%ec_singleton->p; return ec_point(x3,y3); } }
payment_address bidding_address(const ec_point& pubkey) { data_chunk data(pubkey.begin(), pubkey.end()); payment_address payaddr; set_public_key(payaddr, data); return payaddr; }
bool verify_public_key_fast(const ec_point& public_key) { if (public_key.size() == ec_compressed_size) return public_key[0] == 0x02 || public_key[0] == 0x03; if (public_key.size() == ec_uncompressed_size) return public_key[0] == 0x04; return false; }
bool verify_signature(const ec_point& public_key, hash_digest hash, const endorsement& signature) { init.init(); return 1 == secp256k1_ecdsa_verify(hash.data(), hash.size(), signature.data(), signature.size(), public_key.data(), public_key.size() ); }
void add_to (EC_GROUP const* group, ec_point const& a, ec_point& b, bn_ctx& ctx) { if (!EC_POINT_add (group, b.get(), a.get(), b.get(), ctx.get())) { throw std::runtime_error ("EC_POINT_add() failed"); } }
bool verify_signature(const ec_point& public_key, hash_digest hash, const data_chunk& signature) { std::reverse(hash.begin(), hash.end()); init.init(); return 1 == secp256k1_ecdsa_verify( hash.data(), hash.size(), signature.data(), signature.size(), public_key.data(), public_key.size() ); }
int main(int argc, char** argv) { if (argc != 4) { std::cerr << "Usage: pp_unlock CHUNKFILE BLOCK_HASH PUBKEY" << std::endl; return -1; } const std::string chunk_filename = argv[1]; const data_chunk hash = decode_hex(argv[2]); if (hash.empty() || hash.size() != hash_size) { std::cerr << "pp_unlock: not a valid BLOCK_HASH." << std::endl; return -1; } const ec_point pubkey = decode_hex(argv[3]); if (pubkey.empty() || pubkey.size() != ec_compressed_size) { std::cerr << "pp_unlock: not a valid PUBKEY." << std::endl; return -1; } std::ifstream infile(chunk_filename, std::ifstream::binary); infile.seekg(0, std::ifstream::end); size_t file_size = infile.tellg(); BITCOIN_ASSERT(file_size % 16 == 0); infile.seekg(0, std::ifstream::beg); // Read entire file in. data_chunk cipher(file_size); // Copy chunk to public chunk file. char* data = reinterpret_cast<char*>(cipher.data()); infile.read(data, file_size); infile.close(); // Get seed. payment_address bid_addr = bidding_address(pubkey); hash_digest seed = derive_seed(pubkey); // Decrypt chunk. aes256_context ctx; BITCOIN_ASSERT(seed.size() == 32); aes256_init(&ctx, seed.data()); BITCOIN_ASSERT(cipher.size() % 16 == 0); for (size_t i = 0; i < cipher.size(); i += 16) aes256_decrypt_ecb(&ctx, cipher.data() + i); aes256_done(&ctx); // Write out. const fs::path new_chunk_filename = (chunk_filename + ".decrypted"); std::ofstream outfile(new_chunk_filename.native(), std::ifstream::binary); char* dec_data = reinterpret_cast<char*>(cipher.data()); outfile.write(dec_data, cipher.size()); return 0; }
int generateKeyImage(ec_point &publicKey, ec_secret secret, ec_point &keyImage) { // - keyImage = secret * hash(publicKey) * G if (publicKey.size() != EC_COMPRESSED_SIZE) return errorN(1, "%s: Invalid publicKey.", __func__); BN_CTX_start(bnCtx); int rv = 0; BIGNUM *bnTmp = BN_CTX_get(bnCtx); BIGNUM *bnSec = BN_CTX_get(bnCtx); EC_POINT *hG = NULL; if (!(hG = EC_POINT_new(ecGrp)) && (rv = errorN(1, "%s: EC_POINT_new failed.", __func__))) goto End; if (hashToEC(&publicKey[0], publicKey.size(), bnTmp, hG) && (rv = errorN(1, "%s: hashToEC failed.", __func__))) goto End; if (!(BN_bin2bn(&secret.e[0], EC_SECRET_SIZE, bnSec)) && (rv = errorN(1, "%s: BN_bin2bn failed.", __func__))) goto End; if (!EC_POINT_mul(ecGrp, hG, NULL, hG, bnSec, bnCtx) && (rv = errorN(1, "%s: kimg EC_POINT_mul failed.", __func__))) goto End; try { keyImage.resize(EC_COMPRESSED_SIZE); } catch (std::exception& e) { LogPrintf("%s: keyImage.resize threw: %s.\n", __func__, e.what()); rv = 1; goto End; } if ((!(EC_POINT_point2bn(ecGrp, hG, POINT_CONVERSION_COMPRESSED, bnTmp, bnCtx)) || BN_num_bytes(bnTmp) != (int) EC_COMPRESSED_SIZE || BN_bn2bin(bnTmp, &keyImage[0]) != (int) EC_COMPRESSED_SIZE) && (rv = errorN(1, "%s: point -> keyImage failed.", __func__))) goto End; if (fDebugRingSig) LogPrintf("keyImage %s\n", HexStr(keyImage).c_str()); End: EC_POINT_free(hG); BN_CTX_end(bnCtx); return rv; };
int getOldKeyImage(CPubKey &publicKey, ec_point &keyImage) { // - PublicKey * Hash(PublicKey) if (publicKey.size() != EC_COMPRESSED_SIZE) return errorN(1, "%s: Invalid publicKey.", __func__); int rv = 0; uint256 pkHash = publicKey.GetHash(); BN_CTX_start(bnCtx); BIGNUM *bnTmp = BN_CTX_get(bnCtx); EC_POINT *ptPk = NULL; // Hash to BIGNUM if (!BN_bin2bn(pkHash.begin(), EC_SECRET_SIZE, bnTmp) && (rv = errorN(1, "%s: BN_bin2bn failed.", __func__))) goto End; // PublicKey point if (!(ptPk = EC_POINT_new(ecGrp)) && (rv = errorN(1, "%s: EC_POINT_new failed.", __func__))) goto End; if(!EC_POINT_oct2point(ecGrp, ptPk, publicKey.begin(), EC_COMPRESSED_SIZE, bnCtx) && (rv = errorN(1, "%s: EC_POINT_oct2point failed.", __func__))) goto End; // PublicKey * Hash(PublicKey) if (!EC_POINT_mul(ecGrp, ptPk, NULL, ptPk, bnTmp, bnCtx) && (rv = errorN(1, "%s: EC_POINT_mul failed.", __func__))) goto End; try { keyImage.resize(EC_COMPRESSED_SIZE); } catch (std::exception& e) { LogPrintf("%s: keyImage.resize threw: %s.\n", __func__, e.what()); rv = 1; goto End; } // Point to BIGNUM to bin if (!(EC_POINT_point2bn(ecGrp, ptPk, POINT_CONVERSION_COMPRESSED, bnTmp, bnCtx)) ||BN_num_bytes(bnTmp) != (int) EC_COMPRESSED_SIZE ||BN_bn2bin(bnTmp, &keyImage[0]) != (int) EC_COMPRESSED_SIZE) rv = errorN(1, "%s: point -> keyImage failed.", __func__); End: EC_POINT_free(ptPk); BN_CTX_end(bnCtx); return 0; }
int SecretToPublicKey(const ec_secret& secret, ec_point& out) { // -- public key = private * G int rv = 0; EC_GROUP* ecgrp = EC_GROUP_new_by_curve_name(NID_secp256k1); if (!ecgrp) { LogPrintf("SecretToPublicKey(): EC_GROUP_new_by_curve_name failed.\n"); return 1; }; BIGNUM* bnIn = BN_bin2bn(&secret.e[0], ec_secret_size, BN_new()); if (!bnIn) { EC_GROUP_free(ecgrp); LogPrintf("SecretToPublicKey(): BN_bin2bn failed\n"); return 1; }; EC_POINT* pub = EC_POINT_new(ecgrp); EC_POINT_mul(ecgrp, pub, bnIn, NULL, NULL, NULL); BIGNUM* bnOut = EC_POINT_point2bn(ecgrp, pub, POINT_CONVERSION_COMPRESSED, BN_new(), NULL); if (!bnOut) { LogPrintf("SecretToPublicKey(): point2bn failed\n"); rv = 1; } else { out.resize(ec_compressed_size); if (BN_num_bytes(bnOut) != (int) ec_compressed_size || BN_bn2bin(bnOut, &out[0]) != (int) ec_compressed_size) { LogPrintf("SecretToPublicKey(): bnOut incorrect length.\n"); rv = 1; }; BN_free(bnOut); }; EC_POINT_free(pub); BN_free(bnIn); EC_GROUP_free(ecgrp); return rv; };
void serialize_ec_point (ec_point const& point, std::uint8_t* ptr) { ec_key key = ec_key_new_secp256k1_compressed(); if (EC_KEY_set_public_key((EC_KEY*) key.get(), point.get()) <= 0) { throw std::runtime_error ("EC_KEY_set_public_key() failed"); } int const size = i2o_ECPublicKey ((EC_KEY*) key.get(), &ptr); assert (size <= 33); (void) size; }
//Функция для использования в бинарном поиске //Считает одинаковыми точку и обратную ей ( x-координаты совпадают) //Порядок задаётся сравнением x-координаты точек //Нуль группы считается меньше любой точки int ec_compare_bs(ec_point ec1, ec_point ec2) { if (!ec1.is_infinity() && !ec2.is_infinity()) { if (ec1.x>ec2.x) return 1; else if (ec1.x<ec2.x) return -1; else if (ec1.x==ec2.x) { return 0; } } else if (ec1.is_infinity() && ec2.is_infinity()) return 0; else if (ec1.is_infinity() && !ec2.is_infinity()) return -1; else if (!ec1.is_infinity() && ec2.is_infinity()) return 1; }
void tau(ec_point& X) { ZZ auxQ,auxP; if (X.get_x()<one_third) { auxQ=X.auxQ+1; auxP=X.auxP; X=X+Q; X.auxQ = auxQ%r; X.auxP = auxP%r; } else if (X.get_x()>one_third && X.get_x()<two_third) { auxQ=2*X.auxQ; auxP=2*X.auxP; X=X*to_ZZ(2); X.auxQ = auxQ%r; X.auxP = auxP%r; } else { auxQ=X.auxQ+2; auxP=X.auxP; X=X+Q*to_ZZ(2); X.auxQ = auxQ%r; X.auxP = auxP%r; } }
stealth_address::stealth_address(const binary_type& prefix, const ec_point& scan_pubkey, const pubkey_list& spend_pubkeys, uint8_t signatures, bool testnet) { // Guard against uncompressed pubkey or junk data. if (scan_pubkey.size() != compressed_pubkey_size) return; // Guard against uncompressed pubkey or junk data. for (const auto& spend_pubkey: spend_pubkeys) if (spend_pubkey.size() != compressed_pubkey_size) return; // Apply 'reuse'. auto spend_points = spend_pubkeys; if (spend_points.empty()) spend_points.push_back(scan_pubkey); // Guard against too many keys. auto spend_pubkeys_size = spend_points.size(); if (spend_pubkeys_size > max_spend_key_count) return; // Guard against prefix too long. auto prefix_number_bits = static_cast<uint8_t>(prefix.size()); if (prefix_number_bits > max_prefix_bits) return; // Coerce signatures to a valid range. if (signatures == 0 || signatures > spend_pubkeys_size) signatures_ = static_cast<uint8_t>(spend_pubkeys_size); else signatures_ = signatures; prefix_ = prefix; testnet_ = testnet; scan_pubkey_ = scan_pubkey; spend_pubkeys_ = spend_points; valid_ = true; }
int StealthSecret(ec_secret& secret, ec_point& pubkey, const ec_point& pkSpend, ec_secret& sharedSOut, ec_point& pkOut) { /* send: secret = ephem_secret, pubkey = scan_pubkey receive: secret = scan_secret, pubkey = ephem_pubkey c = H(dP) Q = public scan key (EC point, 33 bytes) d = private scan key (integer, 32 bytes) R = public spend key f = private spend key Q = dG //单次使用的私钥 R = fG Sender (has Q and R, not d or f): P = eG c = H(eQ) = H(dP) R' = R + cG Recipient gets R' and P test 0 and infinity? */ int rv = 0; std::vector<uint8_t> vchOutQ; BN_CTX* bnCtx = NULL; BIGNUM* bnEphem = NULL; BIGNUM* bnQ = NULL; EC_POINT* Q = NULL; BIGNUM* bnOutQ = NULL; BIGNUM* bnc = NULL; EC_POINT* C = NULL; BIGNUM* bnR = NULL; EC_POINT* R = NULL; EC_POINT* Rout = NULL; BIGNUM* bnOutR = NULL; EC_GROUP* ecgrp = EC_GROUP_new_by_curve_name(NID_secp256k1); if (!ecgrp) { printf("StealthSecret(): EC_GROUP_new_by_curve_name failed.\n"); return 1; }; if (!(bnCtx = BN_CTX_new())) { printf("StealthSecret(): BN_CTX_new failed.\n"); rv = 2; goto End; }; if (!(bnEphem = BN_bin2bn(&secret.e[0], ec_secret_size, BN_new()))) { printf("StealthSecret(): bnEphem BN_bin2bn failed.\n"); rv = 3; goto End; }; if (!(bnQ = BN_bin2bn(&pubkey[0], pubkey.size(), BN_new()))) { printf("StealthSecret(): bnQ BN_bin2bn failed\n"); rv = 4; goto End; }; if (!(Q = EC_POINT_bn2point(ecgrp, bnQ, NULL, bnCtx))) { printf("StealthSecret(): Q EC_POINT_bn2point failed\n"); rv = 5; goto End; }; // -- eQ // EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx); // EC_POINT_mul calculates the value generator * n + q * m and stores the result in r. The value n may be NULL in which case the result is just q * m. if (!EC_POINT_mul(ecgrp, Q, NULL, Q, bnEphem, bnCtx)) { printf("StealthSecret(): eQ EC_POINT_mul failed\n"); rv = 6; goto End; }; if (!(bnOutQ = EC_POINT_point2bn(ecgrp, Q, POINT_CONVERSION_COMPRESSED, BN_new(), bnCtx))) { printf("StealthSecret(): Q EC_POINT_bn2point failed\n"); rv = 7; goto End; }; vchOutQ.resize(ec_compressed_size); if (BN_num_bytes(bnOutQ) != (int) ec_compressed_size || BN_bn2bin(bnOutQ, &vchOutQ[0]) != (int) ec_compressed_size) { printf("StealthSecret(): bnOutQ incorrect length.\n"); rv = 8; goto End; }; SHA256(&vchOutQ[0], vchOutQ.size(), &sharedSOut.e[0]); if (!(bnc = BN_bin2bn(&sharedSOut.e[0], ec_secret_size, BN_new()))) { printf("StealthSecret(): BN_bin2bn failed\n"); rv = 9; goto End; }; // -- cG if (!(C = EC_POINT_new(ecgrp))) { printf("StealthSecret(): C EC_POINT_new failed\n"); rv = 10; goto End; }; if (!EC_POINT_mul(ecgrp, C, bnc, NULL, NULL, bnCtx)) { printf("StealthSecret(): C EC_POINT_mul failed\n"); rv = 11; goto End; }; if (!(bnR = BN_bin2bn(&pkSpend[0], pkSpend.size(), BN_new()))) { printf("StealthSecret(): bnR BN_bin2bn failed\n"); rv = 12; goto End; }; if (!(R = EC_POINT_bn2point(ecgrp, bnR, NULL, bnCtx))) { printf("StealthSecret(): R EC_POINT_bn2point failed\n"); rv = 13; goto End; }; if (!EC_POINT_mul(ecgrp, C, bnc, NULL, NULL, bnCtx)) { printf("StealthSecret(): C EC_POINT_mul failed\n"); rv = 14; goto End; }; if (!(Rout = EC_POINT_new(ecgrp))) { printf("StealthSecret(): Rout EC_POINT_new failed\n"); rv = 15; goto End; }; if (!EC_POINT_add(ecgrp, Rout, R, C, bnCtx)) { printf("StealthSecret(): Rout EC_POINT_add failed\n"); rv = 16; goto End; }; if (!(bnOutR = EC_POINT_point2bn(ecgrp, Rout, POINT_CONVERSION_COMPRESSED, BN_new(), bnCtx))) { printf("StealthSecret(): Rout EC_POINT_bn2point failed\n"); rv = 17; goto End; }; pkOut.resize(ec_compressed_size); if (BN_num_bytes(bnOutR) != (int) ec_compressed_size || BN_bn2bin(bnOutR, &pkOut[0]) != (int) ec_compressed_size) { printf("StealthSecret(): pkOut incorrect length.\n"); rv = 18; goto End; }; End: if (bnOutR) BN_free(bnOutR); if (Rout) EC_POINT_free(Rout); if (R) EC_POINT_free(R); if (bnR) BN_free(bnR); if (C) EC_POINT_free(C); if (bnc) BN_free(bnc); if (bnOutQ) BN_free(bnOutQ); if (Q) EC_POINT_free(Q); if (bnQ) BN_free(bnQ); if (bnEphem) BN_free(bnEphem); if (bnCtx) BN_CTX_free(bnCtx); EC_GROUP_free(ecgrp); return rv; };
int StealthSecretSpend(ec_secret& scanSecret, ec_point& ephemPubkey, ec_secret& spendSecret, ec_secret& secretOut) { /* c = H(dP) R' = R + cG [without decrypting wallet] = (f + c)G [after decryption of wallet] Remember: mod curve.order, pad with 0x00s where necessary? */ int rv = 0; std::vector<uint8_t> vchOutP; BN_CTX* bnCtx = NULL; BIGNUM* bnScanSecret = NULL; BIGNUM* bnP = NULL; EC_POINT* P = NULL; BIGNUM* bnOutP = NULL; BIGNUM* bnc = NULL; BIGNUM* bnOrder = NULL; BIGNUM* bnSpend = NULL; EC_GROUP* ecgrp = EC_GROUP_new_by_curve_name(NID_secp256k1); if (!ecgrp) { printf("StealthSecretSpend(): EC_GROUP_new_by_curve_name failed.\n"); return 1; }; if (!(bnCtx = BN_CTX_new())) { printf("StealthSecretSpend(): BN_CTX_new failed.\n"); rv = 1; goto End; }; if (!(bnScanSecret = BN_bin2bn(&scanSecret.e[0], ec_secret_size, BN_new()))) { printf("StealthSecretSpend(): bnScanSecret BN_bin2bn failed.\n"); rv = 1; goto End; }; if (!(bnP = BN_bin2bn(&ephemPubkey[0], ephemPubkey.size(), BN_new()))) { printf("StealthSecretSpend(): bnP BN_bin2bn failed\n"); rv = 1; goto End; }; if (!(P = EC_POINT_bn2point(ecgrp, bnP, NULL, bnCtx))) { printf("StealthSecretSpend(): P EC_POINT_bn2point failed\n"); rv = 1; goto End; }; // -- dP if (!EC_POINT_mul(ecgrp, P, NULL, P, bnScanSecret, bnCtx)) { printf("StealthSecretSpend(): dP EC_POINT_mul failed\n"); rv = 1; goto End; }; if (!(bnOutP = EC_POINT_point2bn(ecgrp, P, POINT_CONVERSION_COMPRESSED, BN_new(), bnCtx))) { printf("StealthSecretSpend(): P EC_POINT_bn2point failed\n"); rv = 1; goto End; }; vchOutP.resize(ec_compressed_size); if (BN_num_bytes(bnOutP) != (int) ec_compressed_size || BN_bn2bin(bnOutP, &vchOutP[0]) != (int) ec_compressed_size) { printf("StealthSecretSpend(): bnOutP incorrect length.\n"); rv = 1; goto End; }; uint8_t hash1[32]; SHA256(&vchOutP[0], vchOutP.size(), (uint8_t*)hash1); if (!(bnc = BN_bin2bn(&hash1[0], 32, BN_new()))) { printf("StealthSecretSpend(): BN_bin2bn failed\n"); rv = 1; goto End; }; if (!(bnOrder = BN_new()) || !EC_GROUP_get_order(ecgrp, bnOrder, bnCtx)) { printf("StealthSecretSpend(): EC_GROUP_get_order failed\n"); rv = 1; goto End; }; if (!(bnSpend = BN_bin2bn(&spendSecret.e[0], ec_secret_size, BN_new()))) { printf("StealthSecretSpend(): bnSpend BN_bin2bn failed.\n"); rv = 1; goto End; }; //if (!BN_add(r, a, b)) return 0; //return BN_nnmod(r, r, m, ctx); if (!BN_mod_add(bnSpend, bnSpend, bnc, bnOrder, bnCtx)) { printf("StealthSecretSpend(): bnSpend BN_mod_add failed.\n"); rv = 1; goto End; }; if (BN_is_zero(bnSpend)) // possible? { printf("StealthSecretSpend(): bnSpend is zero.\n"); rv = 1; goto End; }; if (BN_num_bytes(bnSpend) != (int) ec_secret_size || BN_bn2bin(bnSpend, &secretOut.e[0]) != (int) ec_secret_size) { printf("StealthSecretSpend(): bnSpend incorrect length.\n"); rv = 1; goto End; }; End: if (bnSpend) BN_free(bnSpend); if (bnOrder) BN_free(bnOrder); if (bnc) BN_free(bnc); if (bnOutP) BN_free(bnOutP); if (P) EC_POINT_free(P); if (bnP) BN_free(bnP); if (bnScanSecret) BN_free(bnScanSecret); if (bnCtx) BN_CTX_free(bnCtx); EC_GROUP_free(ecgrp); return rv; };
hash_digest derive_seed(const ec_point& pubkey) { data_chunk data(pubkey.begin(), pubkey.end()); return bitcoin_hash(data); }
bool ec_tweak_add(ec_point& a, const ec_secret& b) { init.init(); return secp256k1_ec_pubkey_tweak_add(init.getContext(), a.data(), a.size(), b.data()); }
bool ec_add(ec_point& a, const ec_secret& b) { init.init(); return secp256k1_ec_pubkey_tweak_add(a.data(), a.size(), b.data()) == 1; }
bool ec_multiply(ec_point& a, const ec_secret& b) { init.init(); return secp256k1_ecdsa_pubkey_tweak_mul(a.data(), a.size(), b.data()) == 1; }
bool verify_public_key(const ec_point& public_key) { init.init(); return secp256k1_ecdsa_pubkey_verify(public_key.data(), public_key.size()) == 1; }