Find private key

1

2

I have 2 transactions.

0100000001494d40d44b9ea0d652fca9258ab7caa42551eb52975887f96fb50cd632c8b497000000008c493046022100bdc4132fbd2d9334b54531babdd1f8ecc0a37e75b04c9521684490da25e5938e022100b973d6c776f1a8db2b7bc654c7e55384422677f41928ec4c30643f383d587bfd014104cb5035b2d8fc1019146a7e4fba751a9a9bfafa2d1e35528a9397051c6e630513694ab925adc4083dcafc86c92796a2b6ae977adfc0bb47df9106a6a9263d35f6ffffffff0120030000000000001976a91468979da3812f340e577fc379c20a8f8a505f02dd88ac00000000



0100000001494d40d44b9ea0d652fca9258ab7caa42551eb52975887f96fb50cd632c8b427000000008c493046022100bdc4132fbd2d9334b54531babdd1f8ecc0a37e75b04c9521684490da25e5938e022100be1c50365d8ed4e269cb7350dee3b5fcc9f81856726a590dcdd3f538dafcd045014104cb5035b2d8fc1019146a7e4fba751a9a9bfafa2d1e35528a9397051c6e630513694ab925adc4083dcafc86c92796a2b6ae977adfc0bb47df9106a6a9263d35f6ffffffff0120030000000000001976a91468979da3812f340e577fc379c20a8f8a505f02dd88ac00000000

I know that the k values and hence the R values of both these transactions are the same.

So now how do I recover the private key from these two transactions in hex?

A detailed step by step procedure on how to arrive at the answer will be appreciated.

Archisman Dinda

Posted 2016-01-31T13:18:10.787

Reputation: 13

Answers

0

void Bitcoin::test ( )
{
  const QByteArray t1 ( QByteArray::fromHex ( "010000000...ac00000000" ) ); // strip
  const QByteArray t2 ( QByteArray::fromHex ( "010000000...ac00000000" ) ); // strip
  Stream stream1 ( t1 );
  Stream stream2 ( t2 );
  const Transaction tx1 ( stream1 );
  const Transaction tx2 ( stream2 );
  _trace ( QString ( "txid1=%1" ).arg ( tx1.getKey ( ).toString ( ) ) );
  _trace ( QString ( "txid2=%1" ).arg ( tx2.getKey ( ).toString ( ) ) );
  const TxInput in1 ( tx1.getInput ( 0 ) );
  const TxInput in2 ( tx2.getInput ( 0 ) );
  const QByteArray script1 ( in1.getScript ( ) );
  const QByteArray script2 ( in2.getScript ( ) );
  EvalScript escr1 ( script1 );
  EvalScript escr2 ( script2 );
  xassert ( escr1.evalInput ( ) == EVAL_I_SIG_PUB  );
  xassert ( escr2.evalInput ( ) == EVAL_I_SIG_PUB  );
  _trace ( QString ( "pub1=%1" ).arg ( escr1.getInPubKey ( ).toHex ( ).constData ( ) ) );
  _trace ( QString ( "pub2=%1" ).arg ( escr2.getInPubKey ( ).toHex ( ).constData ( ) ) );
  xassert ( escr1.getInPubKey ( ) == escr2.getInPubKey ( ) ); // same pubkeys?
  const MyByteArray sig1 ( escr1.getInSignature ( ) );
  const MyByteArray sig2 ( escr2.getInSignature ( ) );
  char buf [64];
  sig1.signatureRS ( buf );
  const MyKey32 R1 ( buf );
  const MyKey32 S1 ( buf + 32 );
  _trace ( QString ( "R1=%1" ).arg ( R1.toStringRev ( ) ) );
  _trace ( QString ( "S1=%1" ).arg ( S1.toStringRev ( ) ) );
  sig2.signatureRS ( buf );
  const MyKey32 R2 ( buf );
  const MyKey32 S2 ( buf + 32 );
  _trace ( QString ( "R2=%1" ).arg ( R2.toStringRev ( ) ) );
  _trace ( QString ( "S2=%1" ).arg ( S2.toStringRev ( ) ) );
  xassert ( R1 == R2 ); // are R-values really equal?
  const QByteArray xsc ( MyByteArray ( )
             .putInt8 ( OP_DUP )
             .putInt8 ( OP_HASH160 )
             .putPush ( MyKey20::calc ( escr1.getInPubKey ( ) ) )
             .putInt8 ( OP_EQUALVERIFY )
             .putInt8 ( OP_CHECKSIG ) );
  const MyKey32 Z1 ( tx1.getRawHash ( 0, xsc ) );
  const MyKey32 Z2 ( tx2.getRawHash ( 0, xsc ) );

  _trace ( QString ( "Z1=%1" ).arg ( Z1.toStringRev ( ) ) );
  _trace ( QString ( "Z2=%1" ).arg ( Z2.toStringRev ( ) ) );

  const MyKey20 address ( MyKey20::calc ( escr1.getInPubKey ( ) ) );
  const MyKey32 priv ( MyKey32::getPrivateKey ( R1, S1, Z1, S2, Z2, address ) );
  if ( priv.getAddressHashClassic ( ) == address )
    _trace ( QString ( "classic priv=%1" ).arg ( priv.toStringWif ( false ) ) );
  if ( priv.getAddressHashCompressed ( ) == address )
    _trace ( QString ( "compressed priv=%1" ).arg ( priv.toStringWif ( true ) ) );
}

and the output is:

"txid1=8c1d0dbe2fb84ec4b14ee146e3e899623b3e5c30aef4c8238cf9fe2f8406246c"
"txid2=40e334f8addc00a67209b2818ceb32e1ebd5c28133479f3e408d99f28267828d"
"pub1=04cb5035b2d8fc1019146a7e4fba751a9a9bfafa2d1e35528a9397051c6e630513694ab925adc4083dcafc86c92796a2b6ae977adfc0bb47df9106a6a9263d35f6"
"pub2=04cb5035b2d8fc1019146a7e4fba751a9a9bfafa2d1e35528a9397051c6e630513694ab925adc4083dcafc86c92796a2b6ae977adfc0bb47df9106a6a9263d35f6"
"R1=bdc4132fbd2d9334b54531babdd1f8ecc0a37e75b04c9521684490da25e5938e"
"S1=b973d6c776f1a8db2b7bc654c7e55384422677f41928ec4c30643f383d587bfd"
"R2=bdc4132fbd2d9334b54531babdd1f8ecc0a37e75b04c9521684490da25e5938e"
"S2=be1c50365d8ed4e269cb7350dee3b5fcc9f81856726a590dcdd3f538dafcd045"
"Z1=187509d80dacdd9b35f626dedd2856c7a318455e2d37bcacfe006406b60cf2fe"
"Z2=41d91692534416f8e8d6f3480bb1eae488ce4e24e3afb2c830534411ea5efb1c"
"classic priv=5K1V3pAHQ5DgALeiCC2NfgKESKEaygmCLtBRPFbw9eu1uJrDHW1"

... aaaaaaand the private key is 5K1V3pAHQ5DgALeiCC2NfgKESKEaygmCLtBRPFbw9eu1uJrDHW1

amaclin

Posted 2016-01-31T13:18:10.787

Reputation: 5 763

2

Hopefully most web wallets and wallet services are not re-using R values to sign transactions since this has been a known vulnerability for a while now. On a very low level you are turning an equation like x + y = 10 into x + 2 = 10 making it easy to find x.

First find the reused R values, in your case it's: 2100bdc4132fbd2d9334b54531babdd1f8ecc0a37e75b04c9521684490da25e5938e

Then find the signature coordinates in the two transactions:

tx1 coordinate(S1):
00b973d6c776f1a8db2b7bc654c7e55384422677f41928ec4c30643f383d587bfd
tx2 coordinate(S2):
00be1c50365d8ed4e269cb7350dee3b5fcc9f81856726a590dcdd3f538dafcd045

Now the tricky part, you can use the bitcoin secp256k1 curve to reverse calculate the private key, but you'll need also need to use a bitcoin transaction library to use op_checksig() for the missing sig hashes to find SOP1 and SOP2. I'll let one of the more advanced users explain finding the above two values, as I don't fully understand it myself. Link

p = parameter for secp256k1
Limit the secp256k1 field:
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
K = GF(p)

In the end it's:

K = (sop1*s2 - sop2*s1)/(r*(s1-s2))

This will output an integer, will need to be hexcoded, and then converted to WIF.

Source:
https://bitcointalk.org/index.php?topic=977070.msg10669517#msg10669517
https://bitcointalk.org/index.php?topic=977070.msg11161149#msg11161149

m1xolyd1an

Posted 2016-01-31T13:18:10.787

Reputation: 3 356