2013-06-05 19:19:00 +00:00
|
|
|
#include <fc/crypto/elliptic.hpp>
|
2014-03-03 10:30:23 +00:00
|
|
|
|
|
|
|
|
#include <fc/crypto/base58.hpp>
|
|
|
|
|
#include <fc/crypto/openssl.hpp>
|
|
|
|
|
|
2013-06-05 19:19:00 +00:00
|
|
|
#include <fc/fwd_impl.hpp>
|
|
|
|
|
#include <fc/exception/exception.hpp>
|
|
|
|
|
#include <fc/log/logger.hpp>
|
2014-03-03 10:30:23 +00:00
|
|
|
|
2013-06-05 19:19:00 +00:00
|
|
|
#include <assert.h>
|
2015-03-07 13:48:45 +00:00
|
|
|
#include <secp256k1.h>
|
2013-06-05 19:19:00 +00:00
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
#include "_elliptic_impl_priv.hpp"
|
|
|
|
|
|
2013-06-05 19:19:00 +00:00
|
|
|
namespace fc { namespace ecc {
|
2014-12-12 00:16:02 +00:00
|
|
|
namespace detail
|
|
|
|
|
{
|
2015-03-13 17:47:31 +00:00
|
|
|
static int init_secp256k1() {
|
|
|
|
|
secp256k1_start(SECP256K1_START_VERIFY | SECP256K1_START_SIGN);
|
|
|
|
|
return 1;
|
2015-03-10 13:47:53 +00:00
|
|
|
}
|
2015-03-09 09:30:34 +00:00
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
void _init_lib() {
|
|
|
|
|
static int init_s = init_secp256k1();
|
|
|
|
|
static int init_o = init_openssl();
|
2015-03-10 13:47:53 +00:00
|
|
|
}
|
2015-03-09 09:30:34 +00:00
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
class public_key_impl
|
2015-03-10 13:47:53 +00:00
|
|
|
{
|
2015-03-13 17:47:31 +00:00
|
|
|
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;
|
|
|
|
|
};
|
2013-06-05 19:19:00 +00:00
|
|
|
}
|
2015-03-07 13:48:45 +00:00
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
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
|
2013-06-05 19:19:00 +00:00
|
|
|
{
|
2015-03-13 17:47:31 +00:00
|
|
|
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 );
|
2013-06-05 19:19:00 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
|
|
|
|
|
public_key::~public_key() {}
|
|
|
|
|
|
|
|
|
|
public_key::public_key( public_key &&pk ) : my( std::move( pk.my ) ) {}
|
|
|
|
|
|
|
|
|
|
public_key& public_key::operator=( const public_key& pk )
|
2013-06-05 19:19:00 +00:00
|
|
|
{
|
2015-03-13 17:47:31 +00:00
|
|
|
my = pk.my;
|
|
|
|
|
return *this;
|
2013-06-05 19:19:00 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
public_key& public_key::operator=( public_key&& pk )
|
2013-06-05 19:19:00 +00:00
|
|
|
{
|
2015-03-13 17:47:31 +00:00
|
|
|
my = pk.my;
|
|
|
|
|
return *this;
|
2013-06-05 19:19:00 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
public_key public_key::add( const fc::sha256& digest )const
|
2013-06-05 19:19:00 +00:00
|
|
|
{
|
2015-03-13 17:47:31 +00:00
|
|
|
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 );
|
2013-06-05 19:19:00 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
std::string public_key::to_base58() const
|
2013-06-05 19:19:00 +00:00
|
|
|
{
|
2015-03-13 17:47:31 +00:00
|
|
|
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;
|
2013-06-05 19:19:00 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
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;
|
2015-03-11 14:54:21 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
public_key::public_key( const public_key_point_data& dat )
|
2013-06-05 19:19:00 +00:00
|
|
|
{
|
2015-03-13 17:47:31 +00:00
|
|
|
const char* front = &dat.data[0];
|
|
|
|
|
if( *front == 0 ){}
|
|
|
|
|
else
|
2015-03-09 09:30:34 +00:00
|
|
|
{
|
2015-03-13 17:47:31 +00:00
|
|
|
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 );
|
|
|
|
|
}
|
2013-06-05 19:19:00 +00:00
|
|
|
}
|
2015-03-10 20:56:20 +00:00
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
public_key::public_key( const public_key_data& dat )
|
|
|
|
|
{
|
|
|
|
|
my->_key = dat;
|
|
|
|
|
}
|
2015-03-10 20:56:20 +00:00
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
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" );
|
2015-03-10 10:34:14 +00:00
|
|
|
|
2015-03-13 17:47:31 +00:00
|
|
|
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() );
|
|
|
|
|
}
|
|
|
|
|
} }
|