Sign a tx with "low s" value using OpenSSL

1

I currently try to sign a tx using OpenSSL. After some tinkering I think I got most of the tx right but Electrum complains with mandatory-script-verify-flag-failed (Non-canonical signature: S value is unnecessarily high) which is probably because of BIP62.

Is there a way to create proper signatures with OpenSSL except trying and hoping to get a small s value?

The rest of my code is in Golang and I couldn't find a proper packages for the used ECDSA curve and so wrapped around OpenSSL.

soupdiver

Posted 2017-09-21T17:38:49.177

Reputation: 155

Answers

4

Alternatively, you could use libsecp256k1. This is the code used by Bitcoin Core for signing, and will automatically create low-S signatures (disclaimer: I'm the main author of that library). Perhaps a Go wrapper exists.

If you stick to OpenSSL, it is possible to manually adjust the S value after signing. This is what Bitcoin Core used to do before v0.10. Here is what it used to do: https://github.com/bitcoin/bitcoin/blob/v0.9.0/src/key.cpp#L204L224

Pieter Wuille

Posted 2017-09-21T17:38:49.177

Reputation: 54 032

Such a disclaimer though.sr-gi 2017-09-22T18:42:20.710

1

Open SSL won't force it, you will have to do it yourself. From BIP 62:

The value S in signatures must be between 0x1 and 0x7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 5D576E73 57A4501D DFE92F46 681B20A0 (inclusive). If S is too high, simply replace it by S' = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 - S.

Source

MeshCollider

Posted 2017-09-21T17:38:49.177

Reputation: 8 735

The question then is: How can I set that s value using OpenSSL? I couldn't find a parameter to set itsoupdiver 2017-09-22T06:57:38.957

@soupdiver: those numbers are, not coincidentally, the order of the group for secp256k1 and one-half the order (rounded down). If you have an EC_GROUP for secp25k1 use EC_GROUP_get[0]_order; if you have an EC_KEY use EC_KEY_get0_group first. Once you have the order BN_dup BN_rshift1 BN_cmp and BN_sub on the value from the ECDSA_SIG should be sufficient.dave_thompson_085 2017-09-22T11:45:02.710

I don't really understand the last commentsoupdiver 2017-09-22T11:46:57.580

@soupdiver you don't need to 'set it in OpenSSL', you just use it, the s value is a component of the final signature.MeshCollider 2017-09-22T11:52:58.010

yeah I understand this. I'm wondering if there is a way to set this value if it's too big and therefor rejected by the networksoupdiver 2017-09-22T13:02:17.643

@soupdiver I've explained what to do, calculate the low s value like I explained in my question and put that in the bitcoin transaction signature. That's all you need to doMeshCollider 2017-09-22T22:50:53.993

0

Is there a way to create proper signatures with OpenSSL except trying and hoping to get a small s value?

If the speed is not significant - this is not bad idea.

update: take some pseudocode:

while ( true )
{
  signature = createOpenSslSignature ( params );
  if ( !signature.toHex ( ).contains ( "022100" ) )
    return signature;
}

amaclin

Posted 2017-09-21T17:38:49.177

Reputation: 5 763

I would prefer to create "proper" signatures directly and not having to brute force it :)soupdiver 2017-09-22T06:58:26.853

answer updated. this in not brute-forcing. and this is not best solution. but this is simplest implementation :)amaclin 2017-09-22T16:59:41.927