This change alters the CurveParam methods to upgrade from the generic
curve implementation to the specific P224 or P256 implementations when
called on the embedded CurveParams. This removes the trap of using
elliptic.P224().Params() instead of elliptic.P224(), for example, which
results in using the generic implementation instead of the optimized
constant time one. For P224 this is done for all of the CurveParams
methods, except Params, as the optimized implementation covers all
these methods. For P256 this is only done for ScalarMult and
ScalarBaseMult, as despite having implementations of addition and
doubling they aren't exposed and instead the generic implementation is
used. For P256 an additional check that there actually is a specific
implementation is added, as unlike the P224 implementation the P256 one
is only available on certain platforms.
This change takes the simple, fast approach to checking this, it simply
compares pointers. This removes the most obvious class of mistakes
people make, but still allows edge cases where the embedded CurveParams
pointer has been dereferenced (as seen in the unit tests) or when someone
has manually constructed their own CurveParams that matches one of the
standard curves. A more complex approach could be taken to also address
these cases, but it would require directly comparing all of the
CurveParam fields which would, in the worst case, require comparing
against two standard CurveParam sets in the ScalarMult and
ScalarBaseMult paths, which are likely to be the hottest already.
Updates #34648
Change-Id: I82d752f979260394632905c15ffe4f65f4ffa376
Reviewed-on: https://go-review.googlesource.com/c/go/+/233939
Trust: Roland Shoemaker <roland@golang.org>
Trust: Katie Hockman <katie@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>
Fiat Cryptography (https://github.com/mit-plv/fiat-crypto) is a project
that produces prime order field implementations (the code that does
arithmetic modulo a prime number) based on a formally verified model.
The formal verification covers some of the most subtle and hard to test
parts of an elliptic curve implementation, like carry chains. It would
probably have prevented #20040 and #43786.
This CL imports a 64-bit implementation of the P-521 base field,
replacing the horribly slow and catastrophically variable time big.Int
CurveParams implementation.
The code in p521_fiat64.go is generated reproducibly by fiat-crypto,
building and running the Dockerfile according to the README.
The code in fiat/p521.go is a thin and idiomatic wrapper around the
fiat-crypto code. It includes an Invert method generated with the help
of github.com/mmcloughlin/addchain.
The code in elliptic/p521.go is a line-by-line port of the CurveParams
implementation. Lsh(x, N) was replaced with repeated Add(x, x) calls.
Mul(x, x) was replaced with Square(x). Mod calls were removed, as all
operations are modulo P. Likewise, Add calls to bring values back to
positive were removed. The ScalarMult ladder implementation is now
constant time, copied from p224ScalarMult. Only other notable changes
are adding a p512Point type to keep (x, y, z) together, and making
addJacobian and doubleJacobian methods on that type, with the usual
receiver semantics to save 4 allocations per step.
This amounts to a proof of concept, and is far from a mature elliptic
curve implementation. Here's a non-exhaustive list of things that need
improvement, most of which are pre-existing issues with crypto/elliptic.
Some of these can be fixed without API change, so can't.
- Marshal and Unmarshal still use the slow, variable time big.Int
arithmetic. The Curve interface does not expose field operations, so
we'll have to make our own abstraction.
- Point addition uses an incomplete Jacobian formula, which has variable
time behaviors for points at infinity and equal points. There are
better, complete formulae these days, but I wanted to keep this CL
reviewable against the existing code.
- The scalar multiplication ladder is still heavily variable time. This
is easy to fix and I'll do it in a follow-up CL, but I wanted to keep
this one easier to review.
- Fundamentally, values have to go in and out of big.Int representation
when they pass through the Curve interface, which is both slow and
slightly variable-time.
- There is no scalar field implementation, so crypto/ecdsa ends up using
big.Int for signing.
- Extending this to P-384 would involve either duplicating all P-521
code, or coming up with some lower-level interfaces for the base
field. Even better, generics, which would maybe let us save heap
allocations due to virtual calls.
- The readability and idiomaticity of the autogenerated code can
improve, although we have a clear abstraction and well-enforced
contract, which makes it unlikely we'll have to resort to manually
modifying the code. See mit-plv/fiat-crypto#949.
- We could also have a 32-bit implementation, since it's almost free to
have fiat-crypto generate one.
Anyway, it's definitely better than CurveParams, and definitely faster.
name old time/op new time/op delta
pkg:crypto/elliptic goos:darwin goarch:arm64
ScalarBaseMult/P521-8 4.18ms ± 3% 0.86ms ± 2% -79.50% (p=0.000 n=10+9)
ScalarMult/P521-8 4.17ms ± 2% 0.85ms ± 6% -79.68% (p=0.000 n=10+10)
pkg:crypto/ecdsa goos:darwin goarch:arm64
Sign/P521-8 4.23ms ± 1% 0.94ms ± 0% -77.70% (p=0.000 n=9+8)
Verify/P521-8 8.31ms ± 2% 1.75ms ± 4% -78.99% (p=0.000 n=9+10)
GenerateKey/P521-8 4.15ms ± 2% 0.85ms ± 2% -79.49% (p=0.000 n=10+9)
name old alloc/op new alloc/op delta
pkg:crypto/elliptic goos:darwin goarch:arm64
ScalarBaseMult/P521-8 3.06MB ± 3% 0.00MB ± 0% -99.97% (p=0.000 n=10+10)
ScalarMult/P521-8 3.05MB ± 1% 0.00MB ± 0% -99.97% (p=0.000 n=9+10)
pkg:crypto/ecdsa goos:darwin goarch:arm64
Sign/P521-8 3.03MB ± 0% 0.01MB ± 0% -99.74% (p=0.000 n=10+8)
Verify/P521-8 6.06MB ± 1% 0.00MB ± 0% -99.93% (p=0.000 n=9+9)
GenerateKey/P521-8 3.02MB ± 0% 0.00MB ± 0% -99.96% (p=0.000 n=9+10)
name old allocs/op new allocs/op delta
pkg:crypto/elliptic goos:darwin goarch:arm64
ScalarBaseMult/P521-8 19.8k ± 3% 0.0k ± 0% -99.95% (p=0.000 n=10+10)
ScalarMult/P521-8 19.7k ± 1% 0.0k ± 0% -99.95% (p=0.000 n=9+10)
pkg:crypto/ecdsa goos:darwin goarch:arm64
Sign/P521-8 19.6k ± 0% 0.1k ± 0% -99.63% (p=0.000 n=10+10)
Verify/P521-8 39.2k ± 1% 0.1k ± 0% -99.84% (p=0.000 n=9+10)
GenerateKey/P521-8 19.5k ± 0% 0.0k ± 0% -99.91% (p=0.000 n=9+10)
Updates #40171
Change-Id: Ic898b09a2388382bf51ec007d9a79d72d44efe10
Reviewed-on: https://go-review.googlesource.com/c/go/+/315271
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>
Trust: Katie Hockman <katie@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>
Replaced almost every use of Bytes with FillBytes.
Note that the approved proposal was for
func (*Int) FillBytes(buf []byte)
while this implements
func (*Int) FillBytes(buf []byte) []byte
because the latter was far nicer to use in all callsites.
Fixes#35833
Change-Id: Ia912df123e5d79b763845312ea3d9a8051343c0a
Reviewed-on: https://go-review.googlesource.com/c/go/+/230397
Reviewed-by: Robert Griesemer <gri@golang.org>
See https://tools.ietf.org/html/rfc8422#appendix-A for a helpful table.
Also, commit to keeping them singletons, as that assumption is already
made all over the place in the ecosystem.
Fixes#34193
Change-Id: I2ec50fa18bb80e11d6101f2562df60b5e27d4f66
Reviewed-on: https://go-review.googlesource.com/c/go/+/218921
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
If beta8 is unusually large, the addition loop might take a very long
time to bring x3-beta8 back positive.
This would lead to a DoS vulnerability in the implementation of the
P-521 and P-384 elliptic curves that may let an attacker craft inputs
to ScalarMult that consume excessive amounts of CPU.
This fixes CVE-2019-6486.
Fixes#29903
Change-Id: Ia969e8b5bf5ac4071a00722de9d5e4d856d8071a
Reviewed-on: https://team-review.git.corp.google.com/c/399777
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-by: Julie Qiu <julieqiu@google.com>
Reviewed-on: https://go-review.googlesource.com/c/159218
Reviewed-by: Julie Qiu <julie@golang.org>
Each URL was manually verified to ensure it did not serve up incorrect
content.
Change-Id: I4dc846227af95a73ee9a3074d0c379ff0fa955df
Reviewed-on: https://go-review.googlesource.com/115798
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
ANSI X9.62 specifies that Unmarshal should fail if the a given coordinate is
not smaller than the prime of the elliptic curve. This change makes Unmarshal
ANSI X9.62 compliant and explicitly documents that the Marshal/Unmarshal only
supports uncompressed points.
Fixes#20482
Change-Id: I161a73da8279cae505c9ba0b3022021709fe8145
Reviewed-on: https://go-review.googlesource.com/44312
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-by: Filippo Valsorda <hi@filippo.io>
Run-TryBot: Adam Langley <agl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
The orders of the curves in crypto/elliptic are all very close to a
power of two. None the less, there is a tiny bias in the private key
selection.
This change makes the distribution uniform by resampling in the case
that a private key is >= to the order of the curve. (It also switches
from using BitSize to Params().N.BitLen() because, although they're the
same value here, the latter is technically the correct thing to do.)
The private key sampling and nonce sampling in crypto/ecdsa don't have
this issue.
Fixes#11082.
Change-Id: Ie2aad563209a529fa1cab522abaf5fd505c7269a
Reviewed-on: https://go-review.googlesource.com/17460
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
At present, Unmarshal does not check that the point it unmarshals
is actually *on* the curve. (It may be on the curve's twist.)
This can, as Daniel Bernstein has pointed out at great length,
lead to quite devastating attacks. And 3 out of the 4 curves
supported by crypto/elliptic have twists with cofactor != 1;
P-224, in particular, has a sufficiently large cofactor that it
is likely that conventional dlog attacks might be useful.
This closes#2445, filed by Watson Ladd.
To explain why this was (partially) rejected before being accepted:
In the general case, for curves with cofactor != 1, verifying subgroup
membership is required. (This is expensive and hard-to-implement.)
But, as recent discussion during the CFRG standardization process
has brought out, small-subgroup attacks are much less damaging than
a twist attack.
Change-Id: I284042eb9954ff9b7cde80b8b693b1d468c7e1e8
Reviewed-on: https://go-review.googlesource.com/2421
Reviewed-by: Adam Langley <agl@golang.org>
And add names for the curve implemented in crypto/elliptic.
This permits a safer alternative to switching on BitSize
for code that implements curve-dependent cryptosystems.
(E.g., ECDSA on P-xxx curves with the matched SHA-2
instances.)
Change-Id: I653c8f47506648028a99a96ebdff8389b2a95fc1
Reviewed-on: https://go-review.googlesource.com/2133
Reviewed-by: Adam Langley <agl@golang.org>