Skip to content

Only create signatures with even S, and verification mode to check. #2131

Merged
merged 1 commit into from Aug 16, 2013

5 participants

@sipa
Bitcoin member
sipa commented Dec 26, 2012

To fix a minor malleability found by Sergio Lerner (reported here: https://bitcointalk.org/index.php?topic=8392.msg1245898#msg1245898)

The problem is that if (R,S) is a valid ECDSA signature for a given message and public key, (R,-S) is also valid. Modulo N (the order of the secp256k1 curve), this means that both (R,S) and (R,N-S) are valid. Given that N is odd, S and N-S have a different lowest bit. We solve the problem by forcing signatures to have an even S, excluding one of the alternatives.

This pull request just changes the signing code to always produce even S values, and adds a verification mode to check it. This code is not enabled anywhere yet. Existing tests in key_tests.cpp verify that the produced signatures are still valid.

@gavinandresen gavinandresen commented on an outdated diff Dec 27, 2012
src/key.cpp
@@ -285,13 +285,25 @@ CPubKey CKey::GetPubKey() const
bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
{
- unsigned int nSize = ECDSA_size(pkey);
- vchSig.resize(nSize); // Make sure it is big enough
- if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
- {
- vchSig.clear();
+ ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
+ if (sig == NULL)
@gavinandresen
Bitcoin member

Subtle change in semantics here: if sig == NULL, the old code cleared vchSig.

For defensive programming, I'd suggest a vchSig.clear(); as the first statement in this routine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@sipa
Bitcoin member
sipa commented Dec 28, 2012

@gavinandresen Updated.

@BitcoinPullTester

Automatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/3e4655404a8839a03c241fdcf67e063940eb462b for binaries and test log.

@BitcoinPullTester

Automatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/e1771b85af3d16e12bab2243ea50adf2d52eaf3c for binaries and test log.

@gavinandresen
Bitcoin member

I think this goes one step too far.

Some almost-baked thoughts on the problem we're actually trying to solve (we'd like transactions ids to be immutable):

I think this ties into a bunch of other almost-baked thoughts I've had surrounding bumping the transaction.version. I think it might make sense to introduce transaction.version=2 messages onto the network, with additional rules for relaying/DoS-banning. In particular, I'm imagining a signature from one of the keys used to sign the inputs (maybe.. . more thought needed on how the signing is tied to the transaction's creator) that covers the transaction id and transaction fee paid.

That should solve the "relayer modifies the signature to change the txid".

(the transaction fee paid would be to help out SPV clients, which is a separate feature)

@BitcoinPullTester

Automatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/e1771b85af3d16e12bab2243ea50adf2d52eaf3c for binaries and test log.

@gmaxwell

DOS rules don't prevent a miner from modifying a transaction. We really do need to actually remove the malleability. ... though the actual enforcement would need to be on a version=2 transaction.

@sipa
Bitcoin member
sipa commented Feb 5, 2013

@gavinandresen I really don't like the fact that this would mean rules at the transaction validation level would need knowledge about the precise inner script semantics. IMHO, we should just gradually introduce rules to remove malleabilities, and then perhaps use tx.nVersion==2 rule to enforce them in the block chain at some later point.

@luke-jr
Bitcoin member
luke-jr commented Jul 17, 2013

@sipa Needs rebase (or close if it was merged in another form?).

@sipa sipa Only create signatures with even S, and verification mode to check.
To fix a minor malleability found by Sergio Lerner (reported here:
https://bitcointalk.org/index.php?topic=8392.msg1245898#msg1245898)

The problem is that if (R,S) is a valid ECDSA signature for a given
message and public key, (R,-S) is also valid. Modulo N (the order
of the secp256k1 curve), this means that both (R,S) and (R,N-S) are
valid. Given that N is odd, S and N-S have a different lowest bit.
We solve the problem by forcing signatures to have an even S value,
excluding one of the alternatives.

This commit just changes the signing code to always produce even S
values, and adds a verification mode to check it. This code is not
enabled anywhere yet. Existing tests in key_tests.cpp verify that
the produced signatures are still valid.
a81cd96
@sipa
Bitcoin member
sipa commented Aug 15, 2013
@gmaxwell

Without this, or a substantially similar, change we cannot eliminate malleability attacks on unconfirmed transaction chains.

Though I almost wish the evenness procedure had been specified in BIP32, as now we're going to see hardware wallet deployed that produce odd signatures. They can be fixed with an after the fact mutation, so perhaps thats not the end of the world.

@BitcoinPullTester

Automatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/a81cd96805ce6b65cca3a40ebbd3b2eb428abb7b for binaries and test log.
This test script verifies pulls every time they are updated. It, however, dies sometimes and fails to test properly. If you are waiting on a test, please check timestamps to verify that the test.log is moving at http://jenkins.bluematt.me/pull-tester/current/
Contact BlueMatt on freenode if something looks broken.

@gavinandresen
Bitcoin member

ACK.

@gmaxwell gmaxwell merged commit 47491a9 into bitcoin:master Aug 16, 2013
@lunokhod lunokhod pushed a commit to lunokhod/anoncoin that referenced this pull request Feb 26, 2015
@meeh420 meeh420 Only create signatures with even S, and verification mode to check.
To fix a minor malleability found by Sergio Lerner (reported here: https://bitcointalk.org/index.php?topic=8392.msg1245898#msg1245898)

Thanks to Sipa, bitcoin#2131
35befa1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.