Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement low r signing #259

Merged

Conversation

Tibo-lg
Copy link
Contributor

@Tibo-lg Tibo-lg commented Dec 22, 2020

I needed to generate low r signature (bitcoin/bitcoin#13666) and since there is no functionality to do that in rust I ended up implementing it in rust-secp. I thought it could be useful to others, but if not I'll try to put it somewhere else.

@Tibo-lg
Copy link
Contributor Author

Tibo-lg commented Dec 22, 2020

As discussed with @apoelstra I now added a sign_grind_r method which tried different R until a signature of the desired DER length is found. As this is unfortunately not compatible with how the low r signing is implemented in bitcoin core, the sign_low_r method is kept. Happy to change naming if someone has better ideas.

Copy link
Member

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack 1d166d0

@apoelstra apoelstra merged commit a2c25f2 into rust-bitcoin:master Dec 22, 2020
@junderw
Copy link
Contributor

junderw commented Dec 26, 2020

This assumes the s value of the signature will always be 32 bytes. (low-s)

der_length_check(s, 71 - bytes_to_grind)

But one thing to keep in mind: the s value could also be 31 bytes. (1 byte shorter than normal low-s)

I am guessing this is acceptable since the main goal of low-r grinding is "to have a constant size DER signature"

It is notable that this implementation's nuance is slightly different.

@apoelstra
Copy link
Member

Yes, that is why we have two functions, one for grinding small signatures, and one for low-R.

@apoelstra
Copy link
Member

apoelstra commented Dec 26, 2020

For a bit of context -- whenever the R value has its high bit set to 1, DER encoding requires we use an extra 0 byte to encode it, as the high bit would otherwise be interpreted as a sign bit. Same for the s value. Like all the other DER noise, this byte is entirely wasted space, but it's also pretty easy to get rid of. For any given sig the chance this bit is set is only 50%, so in (on average) two tries, you can save an entire byte.

There would also be a byte to save from the s value, but the low-S rule in Bitcoin actually saves us this byte 100% of the time, without any retries.

Since signing is a fairly rare operation, even on the weakest hardware it's reasonable performance-wise to do it twice whenever you do can do it once. But it's probably not reasonable to do it 256 times, or 65536 times, etc etc. So Core implemented the low-R check, which has clear benefit for almost no cost, and didn't bother implementing general signature grinding. And even though the goal was to get short signatures, the way they implemented the grinding was to check the high bit of R and nothing else, since this is a much simpler thing to efficiently implement than doing a variable-length encoding and checking its length.

On the other hand, I would like general signature grinding, because for my own purposes I don't mind grinding through millions of signatures to save several bytes, so when @Tibo-lg showed up with an implementation of the low-R check, this seemed like a good opportunity to implement that. But since the low-R check is actually a different check than than the signature-length check, we wound up with two functions and less shared code than I'd hoped for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants