btcd icon indicating copy to clipboard operation
btcd copied to clipboard

btcec: Constant time field normalization.

Open bmperrea opened this issue 7 years ago • 10 comments

The current implementation of field.Normalize() has a timing vulnerability exposed in issue #1079. This PR solves that issue by using methods outlined in the crypto/subtle reference library.

Several constant time comparison operators that return integers for use in further bitwise operations are defined and should be used in place of other branching statements in the btcec library (even if-else statements with equal-time branches are vulnerable to timing attacks based on branch-prediction!). I think this solves #1079, but please comment if you knows of any other place following this same-time branching statements pattern. For details comparing the performance of these functions to their same-time branching counterparts see my example repo. For a more full set of constant time functions see this other branch.

Credits to @stevenroose for questioning this pattern in #621. Also, a plug for everyone to suggest there be a direct bool2int conversion function in golang!

bmperrea avatar Nov 26 '17 21:11 bmperrea

$ benchcmp old.txt new.txt
benchmark                             old ns/op     new ns/op     delta
BenchmarkAddJacobian-12               476           469           -1.47%
BenchmarkAddJacobianNotZOne-12        933           937           +0.43%
BenchmarkScalarBaseMult-12            40553         40816         +0.65%
BenchmarkScalarBaseMultLarge-12       40969         41249         +0.68%
BenchmarkScalarMult-12                131962        133058        +0.83%
BenchmarkNAF-12                       774           900           +16.28%
BenchmarkSigVerify-12                 184327        203190        +10.23%
BenchmarkFieldNormalize-12            16.3          16.3          +0.00%
BenchmarkParseCompressedPubKey-12     21344         21283         -0.29%

benchmark                             old allocs     new allocs     delta
BenchmarkParseCompressedPubKey-12     6              6              +0.00%

benchmark                             old bytes     new bytes     delta
BenchmarkParseCompressedPubKey-12     256           256           +0.00%

Unfortunately, there is a slowdown here comparable to the speedup found in a previous change to Normalize. However, as demonstrated in BenchmarkFieldNormalizeWithCarry basically all of this slowdown is due to the faster runtime of the average case of Normalize when using branching, and therefore the slowdown is unavoidable if the runtime is to be truly constant.

bmperrea avatar Nov 27 '17 03:11 bmperrea

Thanks for the credits :)

Cool that you managed to do a proper constant time, I struggled with it at that time!

This change would be compatible with https://github.com/btcsuite/btcd/pull/621, right?

stevenroose avatar Nov 27 '17 14:11 stevenroose

Also, you seem to have forgotten to run gofmt. It's always a good idea to run the goclean.sh command before committing, the Travis here runs it as well.

stevenroose avatar Nov 27 '17 14:11 stevenroose

Thanks @stevenroose. It looks like that fixed the tests.

This is compatible with my suggested branch for #621, although it will probably require a simple rebase. If I am able to get this reviewed and merged then I would want to spend some more time with #621 to improve its performance and get it finished off as well. Great work on this stuff btw.

bmperrea avatar Nov 27 '17 18:11 bmperrea

Wait until Schnorr arrives, we're gonna need you here! :)

stevenroose avatar Nov 28 '17 15:11 stevenroose

I added a commit with where I change the internals of constant_time to use int32 instead of int64. I realized we know that the 10 uint32 values in field will be less than 2^27 and thought that int32 might be more consistently performant on different architectures.

bmperrea avatar Nov 28 '17 22:11 bmperrea

Thanks for the excellent review @davecgh. I have made the updates, squashed, and renamed the commit.

bmperrea avatar Dec 02 '17 16:12 bmperrea

Any chance we can get this reviewed?

bmperrea avatar Mar 09 '18 01:03 bmperrea

Updated based on good feedback in https://github.com/gcash/bchd/pull/78 . The timing got faster than it previously was for this PR since doing so - thanks @jimpo and @markblundeberg

UPDATE: actually based on results from benchstat none of the differences in timing here or before are statistically significant so I don't want to make too strong of a claim.

bmperrea avatar Nov 18 '19 03:11 bmperrea

@jcvernaleo (as per #1530)

  • Low priority
  • Enhancement

jakesylvestre avatar Mar 04 '20 13:03 jakesylvestre