Update to elliptic curve signature verification

This commit is contained in:
Daniel Larimer 2014-12-10 22:43:37 -08:00
parent e29438461e
commit a4a90fac05
4 changed files with 85 additions and 57 deletions

View file

@ -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 )

View file

@ -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 );

View file

@ -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) );
}

View file

@ -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;
}