#include #include #include #include #include #include #include #include #include "_elliptic_impl_priv.hpp" namespace fc { namespace ecc { namespace detail { static int init_secp256k1() { secp256k1_start(SECP256K1_START_VERIFY | SECP256K1_START_SIGN); return 1; } void _init_lib() { static int init_s = init_secp256k1(); static int init_o = init_openssl(); } class public_key_impl { public: public_key_impl() noexcept { _init_lib(); } public_key_impl( const public_key_impl& cpy ) noexcept : _key( cpy._key ) { _init_lib(); } public_key_data _key; }; } static const public_key_data empty_pub; static const private_key_secret empty_priv; fc::sha512 private_key::get_shared_secret( const public_key& other )const { FC_ASSERT( my->_key != empty_priv ); FC_ASSERT( other.my->_key != empty_pub ); public_key_data pub(other.my->_key); FC_ASSERT( secp256k1_ec_pubkey_tweak_mul( (unsigned char*) pub.begin(), pub.size(), (unsigned char*) my->_key.data() ) ); return fc::sha512::hash( pub.begin() + 1, pub.size() - 1 ); } public_key::public_key() {} public_key::public_key( const public_key &pk ) : my( pk.my ) {} public_key::public_key( public_key &&pk ) : my( std::move( pk.my ) ) {} public_key::~public_key() {} public_key& public_key::operator=( const public_key& pk ) { my = pk.my; return *this; } public_key& public_key::operator=( public_key&& pk ) { my = pk.my; return *this; } bool public_key::valid()const { return my->_key != empty_pub; } public_key public_key::add( const fc::sha256& digest )const { FC_ASSERT( my->_key != empty_pub ); public_key_data new_key; memcpy( new_key.begin(), my->_key.begin(), new_key.size() ); FC_ASSERT( secp256k1_ec_pubkey_tweak_add( (unsigned char*) new_key.begin(), new_key.size(), (unsigned char*) digest.data() ) ); return public_key( new_key ); } std::string public_key::to_base58() const { FC_ASSERT( my->_key != empty_pub ); return to_base58( my->_key ); } public_key_data public_key::serialize()const { FC_ASSERT( my->_key != empty_pub ); return my->_key; } public_key_point_data public_key::serialize_ecc_point()const { FC_ASSERT( my->_key != empty_pub ); public_key_point_data dat; unsigned int pk_len = my->_key.size(); memcpy( dat.begin(), my->_key.begin(), pk_len ); FC_ASSERT( secp256k1_ec_pubkey_decompress( (unsigned char *) dat.begin(), (int*) &pk_len ) ); FC_ASSERT( pk_len == dat.size() ); return dat; } public_key::public_key( const public_key_point_data& dat ) { const char* front = &dat.data[0]; if( *front == 0 ){} else { EC_KEY *key = EC_KEY_new_by_curve_name( NID_secp256k1 ); key = o2i_ECPublicKey( &key, (const unsigned char**)&front, sizeof(dat) ); FC_ASSERT( key ); EC_KEY_set_conv_form( key, POINT_CONVERSION_COMPRESSED ); unsigned char* buffer = (unsigned char*) my->_key.begin(); i2o_ECPublicKey( key, &buffer ); // FIXME: questionable memory handling EC_KEY_free( key ); } } public_key::public_key( const public_key_data& dat ) { my->_key = dat; } public_key::public_key( const compact_signature& c, const fc::sha256& digest, bool check_canonical ) { int nV = c.data[0]; if (nV<27 || nV>=35) FC_THROW_EXCEPTION( exception, "unable to reconstruct public key from signature" ); if( check_canonical ) { FC_ASSERT( is_canonical( c ), "signature is not canonical" ); } unsigned int pk_len; FC_ASSERT( secp256k1_ecdsa_recover_compact( (unsigned char*) digest.data(), (unsigned char*) c.begin() + 1, (unsigned char*) my->_key.begin(), (int*) &pk_len, 1, (*c.begin() - 27) & 3 ) ); FC_ASSERT( pk_len == my->_key.size() ); } } }