Update to elliptic curve signature verification
This commit is contained in:
parent
e29438461e
commit
a4a90fac05
4 changed files with 85 additions and 57 deletions
|
|
@ -249,6 +249,9 @@ target_link_libraries( udt_client fc udt )
|
|||
add_executable( lzma_test tests/lzma_test.cpp )
|
||||
target_link_libraries( lzma_test fc )
|
||||
|
||||
add_executable( ecc_test tests/ecc_test.cpp )
|
||||
target_link_libraries( ecc_test fc )
|
||||
|
||||
#add_executable( test_compress tests/compress.cpp )
|
||||
#target_link_libraries( test_compress fc )
|
||||
#add_executable( test_aes tests/aes_test.cpp )
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace fc {
|
|||
|
||||
public_key( const public_key_data& v );
|
||||
public_key( const public_key_point_data& v );
|
||||
public_key( const compact_signature& c, const fc::sha256& digest );
|
||||
public_key( const compact_signature& c, const fc::sha256& digest, bool check_cannonical = true );
|
||||
|
||||
bool valid()const;
|
||||
public_key mult( const fc::sha256& offset );
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ namespace fc { namespace ecc {
|
|||
{
|
||||
}
|
||||
|
||||
public_key::public_key( const compact_signature& c, const fc::sha256& digest )
|
||||
public_key::public_key( const compact_signature& c, const fc::sha256& digest, bool check_cannonical )
|
||||
{
|
||||
int nV = c.data[0];
|
||||
if (nV<27 || nV>=35)
|
||||
|
|
@ -491,6 +491,14 @@ namespace fc { namespace ecc {
|
|||
BN_bin2bn(&c.data[1],32,sig->r);
|
||||
BN_bin2bn(&c.data[33],32,sig->s);
|
||||
|
||||
if( check_cannonical )
|
||||
{
|
||||
FC_ASSERT( !(c.data[1] & 0x80), "signature is not cannonical" );
|
||||
FC_ASSERT( !(c.data[1] == 0 && !(c.data[2] & 0x80)), "signature is not cannonical" );
|
||||
FC_ASSERT( !(c.data[33] & 0x80), "signature is not cannonical" );
|
||||
FC_ASSERT( !(c.data[33] == 0 && !(c.data[34] & 0x80)), "signature is not cannonical" );
|
||||
}
|
||||
|
||||
my->_key = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
|
||||
if (nV >= 31)
|
||||
|
|
@ -515,59 +523,65 @@ namespace fc { namespace ecc {
|
|||
FC_ASSERT( my->_key != nullptr );
|
||||
auto my_pub_key = get_public_key().serialize(); // just for good measure
|
||||
//ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&digest, sizeof(digest), my->_key);
|
||||
ecdsa_sig sig = ECDSA_do_sign((unsigned char*)&digest, sizeof(digest), my->_key);
|
||||
|
||||
if (sig==nullptr)
|
||||
FC_THROW_EXCEPTION( exception, "Unable to sign" );
|
||||
|
||||
compact_signature csig;
|
||||
// memset( csig.data, 0, sizeof(csig) );
|
||||
|
||||
int nBitsR = BN_num_bits(sig->r);
|
||||
int nBitsS = BN_num_bits(sig->s);
|
||||
if (nBitsR <= 256 && nBitsS <= 256)
|
||||
while( true )
|
||||
{
|
||||
int nRecId = -1;
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
public_key keyRec;
|
||||
keyRec.my->_key = EC_KEY_new_by_curve_name( NID_secp256k1 );
|
||||
// keyRec.fSet = true;
|
||||
// if (fCompressedPubKey) keyRec.SetCompressedPubKey();
|
||||
if (ECDSA_SIG_recover_key_GFp(keyRec.my->_key, sig, (unsigned char*)&digest, sizeof(digest), i, 1) == 1)
|
||||
{
|
||||
if (keyRec.serialize() == my_pub_key )
|
||||
{
|
||||
nRecId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ecdsa_sig sig = ECDSA_do_sign((unsigned char*)&digest, sizeof(digest), my->_key);
|
||||
|
||||
if (nRecId == -1)
|
||||
{
|
||||
FC_THROW_EXCEPTION( exception, "unable to construct recoverable key");
|
||||
}
|
||||
|
||||
csig.data[0] = nRecId+27+4;//(fCompressedPubKey ? 4 : 0);
|
||||
BN_bn2bin(sig->r,&csig.data[33-(nBitsR+7)/8]);
|
||||
BN_bn2bin(sig->s,&csig.data[65-(nBitsS+7)/8]);
|
||||
if (sig==nullptr)
|
||||
FC_THROW_EXCEPTION( exception, "Unable to sign" );
|
||||
|
||||
/*try {
|
||||
auto pubk = public_key( csig, digest ).serialize();
|
||||
FC_ASSERT( pubk == my_pub_key, "", ("pubk",pubk)("my_pub_key",my_pub_key)("private_key", *this) );
|
||||
} catch ( fc::exception& e)
|
||||
{
|
||||
wlog( "${e}", ("e", e.to_detail_string() ) );
|
||||
csig = sign_compact( digest );
|
||||
elog( "it worked the second time!" );
|
||||
exit(1);
|
||||
}
|
||||
*/
|
||||
}
|
||||
// TODO: memory leak if exception thrown!
|
||||
//ECDSA_SIG_free(sig);
|
||||
return csig;
|
||||
compact_signature csig;
|
||||
// memset( csig.data, 0, sizeof(csig) );
|
||||
|
||||
int nBitsR = BN_num_bits(sig->r);
|
||||
int nBitsS = BN_num_bits(sig->s);
|
||||
if (nBitsR <= 256 && nBitsS <= 256)
|
||||
{
|
||||
int nRecId = -1;
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
public_key keyRec;
|
||||
keyRec.my->_key = EC_KEY_new_by_curve_name( NID_secp256k1 );
|
||||
if (ECDSA_SIG_recover_key_GFp(keyRec.my->_key, sig, (unsigned char*)&digest, sizeof(digest), i, 1) == 1)
|
||||
{
|
||||
if (keyRec.serialize() == my_pub_key )
|
||||
{
|
||||
nRecId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nRecId == -1)
|
||||
{
|
||||
FC_THROW_EXCEPTION( exception, "unable to construct recoverable key");
|
||||
}
|
||||
unsigned char* result = nullptr;
|
||||
auto bytes = i2d_ECDSA_SIG( sig, &result );
|
||||
auto lenR = result[3];
|
||||
auto lenS = result[5+lenR];
|
||||
//idump( (result[0])(result[1])(result[2])(result[3])(result[3+lenR])(result[4+lenR])(bytes)(lenR)(lenS) );
|
||||
if( lenR != 32 ) { free(result); continue; }
|
||||
if( lenS != 32 ) { free(result); continue; }
|
||||
//idump( (33-(nBitsR+7)/8) );
|
||||
//idump( (65-(nBitsS+7)/8) );
|
||||
//idump( (sizeof(csig) ) );
|
||||
memcpy( &csig.data[1], &result[4], lenR );
|
||||
memcpy( &csig.data[33], &result[6+lenR], lenS );
|
||||
//idump( (csig.data[33]) );
|
||||
//idump( (csig.data[1]) );
|
||||
free(result);
|
||||
//idump( (nRecId) );
|
||||
csig.data[0] = nRecId+27+4;//(fCompressedPubKey ? 4 : 0);
|
||||
/*
|
||||
idump( (csig) );
|
||||
auto rlen = BN_bn2bin(sig->r,&csig.data[33-(nBitsR+7)/8]);
|
||||
auto slen = BN_bn2bin(sig->s,&csig.data[65-(nBitsS+7)/8]);
|
||||
idump( (rlen)(slen) );
|
||||
*/
|
||||
}
|
||||
return csig;
|
||||
} // while true
|
||||
} FC_RETHROW_EXCEPTIONS( warn, "sign ${digest}", ("digest", digest)("private_key",*this) );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,34 @@
|
|||
#include <fc/crypto/elliptic.hpp>
|
||||
#include <bts/address.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
for( uint32_t i = 0; i < 3000; ++ i )
|
||||
{
|
||||
try {
|
||||
FC_ASSERT( argc > 1 );
|
||||
|
||||
std::string pass(argv[1]);
|
||||
fc::sha256 h = fc::sha256::hash( pass.c_str(), pass.size() );
|
||||
fc::ecc::private_key priv = fc::ecc::private_key::generate_from_seed(h);
|
||||
fc::ecc::public_key pub = priv.get_public_key();
|
||||
std::cerr<<"oroginal master pubkey1: "<<std::string(bts::address(pub))<<"\n";
|
||||
|
||||
pass += "1";
|
||||
fc::sha256 h2 = fc::sha256::hash( pass.c_str(), pass.size() );
|
||||
fc::ecc::public_key pub1 = pub.mult( h2 );
|
||||
fc::ecc::private_key priv1 = fc::ecc::private_key::generate_from_seed(h, h2);
|
||||
|
||||
std::cerr<<"master pubkey: "<<std::string(bts::address(pub))<<"\n";
|
||||
std::cerr<<"derived pubkey1: "<<std::string(bts::address(pub1))<<"\n";
|
||||
std::cerr<<"actual pubkey1: "<<std::string(bts::address(priv1.get_public_key()))<<"\n";
|
||||
auto sig = priv.sign_compact( h );
|
||||
auto recover = fc::ecc::public_key( sig, h );
|
||||
FC_ASSERT( recover == priv.get_public_key() );
|
||||
}
|
||||
catch ( const fc::exception& e )
|
||||
{
|
||||
edump( (e.to_detail_string()) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue