crypto/
ed25519: replace internal/edwards25519 with filippo.io/edwards25519
This change replaces the crypto/
ed25519/internal/edwards25519 package
with code from filippo.io/edwards25519, a significantly faster, safer,
well tested (over 1600 lines of new tests, 99% test coverage), and
better documented (600 lines of new comments) implementation.
Some highlights:
* an unsaturated 51-bit limb field implementation optimized for 64-bit
architectures and math/bits.Mul64 intrinsics
* more efficient variable time scalar multiplication using multi-width
non-adjacent form with a larger lookup table for fixed-base
* a safe math/big.Int-like API for the Scalar, Point, and field.Element
types with fully abstracted reduction invariants
* a test suite including a testing/quick fuzzer that explores edge case
values that would be impossible to hit randomly, and systematic tests
for arguments and receiver aliasing
* point decoding rules that strictly match the original logic of
crypto/
ed25519/internal/edwards25519, to avoid consensus issues
* AssemblyPolicy-compliant assembly cores for arm64 and amd64, the
former under 20 lines, and the latter generated by a program based on
github.com/mmcloughlin/avo that can be reviewed line-by-line against
the generic implementation
Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz
name old time/op new time/op delta
KeyGeneration-4 59.5µs ± 1% 26.1µs ± 1% -56.20% (p=0.000 n=10+10)
NewKeyFromSeed-4 59.3µs ± 1% 25.8µs ± 1% -56.48% (p=0.000 n=9+10)
Signing-4 60.4µs ± 1% 31.4µs ± 1% -48.05% (p=0.000 n=10+10)
Verification-4 169µs ± 1% 73µs ± 2% -56.55% (p=0.000 n=10+10)
Apple M1
name old time/op new time/op delta
KeyGeneration-8 35.1µs ± 0% 20.2µs ± 2% -42.46% (p=0.000 n=8+10)
NewKeyFromSeed-8 35.1µs ± 0% 20.0µs ± 1% -42.93% (p=0.000 n=8+9)
Signing-8 36.2µs ± 0% 25.6µs ± 1% -29.25% (p=0.000 n=8+9)
Verification-8 96.1µs ± 0% 57.6µs ± 1% -40.14% (p=0.000 n=10+10)
The code in this CL is a copy of the filippo.io/edwards25519 module at
version v1.0.0-beta.3.0.
20210405211453-
c6be47d67779 with only the
following functions removed as irrelevant to crypto/
ed25519:
- (*Point).BytesMontgomery()
- (*Point).MultByCofactor()
- (*Scalar).Invert()
- (*Point).MultiScalarMult()
- (*Point).VarTimeMultiScalarMult()
This codebase took a long journey outside the standard library before
making its way back here. Its oldest parts started as a faster field
implementation rewrite by George Tankersley almost four years ago,
eventually submitted as CL 71950 but never merged. That code was then
merged into github.com/gtank/ristretto255, which also started as an
internal/edwards25519 fork. There it was worked on by me, George, and
Henry de Valence as a backend for our Go ristretto255 implementation.
Finally, I extracted the edwards25519 code into a reusable package as
filippo.io/edwards25519.
Now, we're ready for the standard library to become the source of truth
for this code again, while filippo.io/edwards25519 will become a
re-packaged and extended version for external use, since we don't want
to expose unsafe curve operations in x/crypto or the standard library.
Submitted under the Google CLA on behalf of:
- Henry de Valence
https://github.com/gtank/ristretto255/issues/34
- George Tankersley
https://golang.org/cl/71950
https://github.com/gtank/ristretto255-private/issues/28
- Luke Champine
https://github.com/FiloSottile/edwards25519/pull/7
- Adrian Hamelink
https://github.com/FiloSottile/edwards25519/pull/12
Changes
32506b5 and
18c803c are trivial and don't require a CLA.
The full history of this code since diverging from internal/edwards25519
is available at https://github.com/FiloSottile/edwards25519, and
summarized below.
+
c6be47d - edwards25519: update TestScalarSetBytesWithClamping <Filippo Valsorda>
+
c882e8e - edwards25519: rewrite amd64 assembly with avo <Filippo Valsorda>
+
8eb02eb - edwards25519: refactor feMulGeneric and feSquareGeneric <Filippo Valsorda>
+
8afd860 - edwards25519: remove Go 1.12 compatibility hack <Filippo Valsorda>
+
1765c13 - edwards25519: don't clobber BP in amd64 assembly <Filippo Valsorda>
+
b73a7c8 - edwards25519: fix ScalarMult when receiver is not the identity (FiloSottile/edwards25519#12) <Adrian Hamelink>
+
32a46d7 - edwards25519: document why this can't implement X25519 <Filippo Valsorda>
+
c547797 - edwards25519: make SqrtRatio slightly more efficient <Filippo Valsorda>
+
700f4f4 - edwards25519: panic if an uninitialized Point is used <Filippo Valsorda>
+
d791cf8 - edwards25519: use testing.AllocsPerRun for TestAllocations <Filippo Valsorda>
+
8cc8037 - edwards25519: smooth a couple test coverage rough edges <Filippo Valsorda>
+
9063a14 - edwards25519: test that operations cause zero heap allocations <Filippo Valsorda>
+
6944ac7 - edwards25519: relax the limb schedule slightly <Filippo Valsorda>
+
21ebdac - edwards25519: rewrite carryPropagate in arm64 assembly <Filippo Valsorda>
+
a260082 - edwards25519: merge carryPropagate[12] <Filippo Valsorda>
+
dbe1792 - edwards25519: add TestScalarSetBytesWithClamping <Filippo Valsorda>
+
c1fe95a - edwards25519: add MultByCofactor <Filippo Valsorda>
+
132d95c - edwards25519: sprinkle on-curve checks around tests <Filippo Valsorda>
+
ffb3e31 - edwards25519: specify the behavior of Invert(0) and I.BytesMontgomery() <Filippo Valsorda>
+
9e6a931 - edwards25519: add (*Scalar).MultiplyAdd <lukechampine>
+
3b045f3 - edwards25519: outline (*Point).Bytes (FiloSottile/edwards25519#6) <Luke Champine>
+
ec6f8a6 - edwards25519: make (*Scalar).SetCanonicalBytes return the receiver <Filippo Valsorda>
+
77d7b31 - edwards25519: add (*Point).BytesMontgomery <Filippo Valsorda>
+
6e8d645 - edwards25519: implement (*Point).Bytes and (*Point).SetBytes <Filippo Valsorda>
+
1c833da - edwards25519: clarify ScalarBaseMult docs <Filippo Valsorda>
+
3a13cf1 - edwards25519: apply gc build tag <Filippo Valsorda>
+
90c35a7 - edwards25519: hide FieldElement and (*Point).ExtendedCoords <Filippo Valsorda>
+
498fb1e - edwards25519: replace FillBytes with Bytes, again <Filippo Valsorda>
+
9c7303a - edwards25519: remove (*Point).Identity and (*Point).Generator <Filippo Valsorda>
+
2e52ce2 - edwards25519: drop unused (*Scalar).Zero <Filippo Valsorda>
+
7c14a36 - edwards25519: rename FromBytes to SetBytes <Filippo Valsorda>
+
e3d0e45 - edwards25519: ensure only test files import math/big <Filippo Valsorda>
+
daa2507 - edwards25519: minor doc and string touch-ups <Filippo Valsorda>
+
e8698cd - edwards25519: implement (*Scalar).FromBytesWithClamping <Filippo Valsorda>
+
f28d75a - edwards25519: change constructors <Filippo Valsorda>
+
36d8598 - edwards25519: test the invariant that Scalars are always reduced <Filippo Valsorda>
+
feed48c - edwards25519: cleanup the FieldElement API <Filippo Valsorda>
+
f6ee187 - edwards25519: make Point opaque <Filippo Valsorda>
+
176388b - edwards25519: cleanup Scalar API to match ristretto255 <Filippo Valsorda>
+
c5c2e9e - edwards25519: rename ProjP3 to Point and unexport other point types <Filippo Valsorda>
+
8542076 - edwards25519: add Scalar aliasing test <Filippo Valsorda>
+
1a86a9c - edwards25519: make Scalar opaque <Filippo Valsorda>
+
07a7683 - edwards25519: hide some more exposed symbols <Filippo Valsorda>
+
d3569cb - all: flatten the package and make FieldElement opaque <Filippo Valsorda>
+
6f5f582 - all: expose edwards25519, base, and scalar packages <Filippo Valsorda>
+
7ab4a68 - all: ensure compatibility with older Go versions <Filippo Valsorda>
+
e9b8baa - internal/radix51: implement (*FieldElement).Mul32 <Filippo Valsorda>
+
eac4de5 - internal/radix51: restructure according to golang.org/wiki/TargetSpecific <Filippo Valsorda>
+
32506b5 - internal/radix51: fix !amd64 build (lightReduce -> carryPropagate) (gtank/ristretto255#29) <Sunny Aggarwal>
+
d64d989 - internal/scalar: fix FromUniformBytes <Filippo Valsorda>
+
044bb44 - internal/scalar: address review comments <Filippo Valsorda>
+
7dba54f - all: apply suggestions from code review <Filippo Valsorda>
+
94bd1d9 - ristretto255: expose scalar multiplication APIs <Filippo Valsorda>
+
5bd5476 - internal/edwards25519: fix shadowing of B in TestAddSubNegOnBasePoint <Filippo Valsorda>
+
66bf647 - internal/scalar: replace FromBytes/IsCanonical with FromUniformBytes/FromCanonicalBytes <Filippo Valsorda>
+
024f3f7 - internal/edwards25519,internal/scalar: apply some Go style touches <Filippo Valsorda>
+
5e0c5c6 - internal/scalar: add scalar inversion <Henry de Valence>
+
74fd625 - internal/
ed25519: rearrange VartimeDoubleBaseMul args <Henry de Valence>
+
81ae7ea - internal/
ed25519: add benchmarks for scalar mul <Henry de Valence>
+
9f1f939 - internal/
ed25519: add variable-time multiscalar mul <Henry de Valence>
+
7a96974 - internal/
ed25519: add vartime double-base scmul <Henry de Valence>
+
2bc256c - internal/
ed25519: add precomputed NAF table for basepoint <Henry de Valence>
+
a0f0b96 - internal/
ed25519: lower quickcheck size for point ops <Henry de Valence>
+
2f385a1 - internal/
ed25519: implement MultiscalarMul <Henry de Valence>
+
8ae211b - internal/
ed25519: implement BasepointMul <Henry de Valence>
+
7b4858d - internal/
ed25519: extract common test variables <Henry de Valence>
+
16e7c48 - internal/
ed25519: add a basepoint multiple table. <Henry de Valence>
+
988e521 - internal/
ed25519: add constant-time variable-base scmul. <Henry de Valence>
+
b695f6b - internal/
ed25519: move basepoint constant & correct it <Henry de Valence>
+
ddd014e - internal/scalar: fix high bit check <Henry de Valence>
+
c88ea89 - internal/scalar: make casts clearer <Henry de Valence>
+
b75f989 - internal/scalar: add invariant checks on Scalar digits <Henry de Valence>
+
36216ca - internal/scalar: use one scMulAdd for Sub <Henry de Valence>
+
8bf40f3 - internal/scalar: fix constant-time signed radix 16 implementation <Henry de Valence>
+
e6d9ef6 - Update internal/radix51/fe_test.go <Filippo Valsorda>
+
3aa63de - Update internal/radix51/fe_test.go <Filippo Valsorda>
+
3e66ff0 - Update internal/radix51/fe_test.go <Filippo Valsorda>
+
94e6c15 - internal/
ed25519: add TODO note and doc ref <Henry de Valence>
+
3647548 - internal/
ed25519: rename twoD to D2 <Henry de Valence>
+
1cf853c - internal/
ed25519: add lookup tables for scalar mul. <Henry de Valence>
+
3af304a - internal/radix51: add a conditional swap <Henry de Valence>
+
4673217 - ristretto255: use multi-model arithmetic <Henry de Valence>
+
cca757a - internal/
ed25519: remove single-model code <Henry de Valence>
+
d26e77b - internal/
ed25519: add addition for Edwards points <Henry de Valence>
+
e0fbb35 - internal/
ed25519: use twoD <Henry de Valence>
+
fd9b37b - internal/
ed25519: add tests for multi-model point types. <Henry de Valence>
+
dacabb0 - internal/
ed25519: add multi-model point types. <Henry de Valence>
+
dddc72e - internal/scalar: add constant-time signed radix 16 <Henry de Valence>
+
92cdb35 - internal/scalar: add non-adjacent form <Henry de Valence>
+
d147963 - internal/scalar: don't zero memory that is about to be copied over <George Tankersley>
+
8da186c - internal/scalar: add scalar field implementation <George Tankersley>
+
f38e583 - internal/radix51: add a "weird" testing/quick generation strategy <Filippo Valsorda>
+
6454f61 - Move comment inside function <Henry de Valence>
+
1983365 - implement Add, Sub, Neg for
ed25519 and ristretto255 points. <Henry de Valence>
+
9f25562 - internal/group: rename to internal/edwards25519 <Filippo Valsorda>
+
48e66d3 - internal/group: restore ScalarMult code <Filippo Valsorda>
+
0078d66 - internal/radix51: rename lightReduce to carryPropagate and touch up docs <Filippo Valsorda>
+
05f4107 - internal/radix51: add benchmarks <Filippo Valsorda>
+
fd36334 - internal/radix51: test that operations don't exceed bounds <Filippo Valsorda>
+
703421d - internal/radix51: make Generate produce random light-reduced elements <Filippo Valsorda>
+
f8d8297 - internal/radix51: simplify lightReduce <Filippo Valsorda>
+
413120f - internal/radix51: minor tests cleanup <Filippo Valsorda>
+
abc8c5a - internal/radix51: make reduction an invariant and unexport Reduce <Filippo Valsorda>
+
4fd198d - internal/radix51: actually apply go:noescape <Filippo Valsorda>
+
18c803c - all: fix typos <Dimitris Apostolou>
+
bbfe059 - internal/radix51: test field encoding roundtrip with fixed vectors <George Tankersley>
+
c428b18 - internal/radix51: rename AppendBytes to Bytes <Filippo Valsorda>
+
c59bc1a - internal/radix51: rewrite FromBytes and AppendBytes with encoding/binary <Filippo Valsorda>
+
57c0cd5 - internal/radix51: add docs and some light readability refactors <Filippo Valsorda>
+
cb1b734 - internal/radix51: remove unused (and a bit broken) SetInt <Filippo Valsorda>
+
beb8abd - internal/radix51: refactor ToBig and FromBig <Filippo Valsorda>
+
87c0a53 - internal/radix51: replace ToBytes with AppendBytes <Filippo Valsorda>
+
b7e1e45 - internal/radix51: fix aliasing bug in CondNeg (gtank/ristretto255#21) <George Tankersley>
+
ed3748d - internal/radix51: actually, uhm, check the result of TestAliasing <Filippo Valsorda>
+
ec0e293 - radix51: change API of FromBytes and ToBytes to use slices <George Tankersley>
+
29f6815 - internal/radix51: test all combinations of argument and receiver aliasing <Filippo Valsorda>
+
cd53d90 - internal/radix51: add property-based tests that multiplication distributes over addition <Henry de Valence>
+
c3bc45f - radix51: use go1.12 intrinsics for 128-bit multiplications <George Tankersley>
+
7e7043e - internal/radix51: define a mask64Bits constant <Filippo Valsorda>
+
4fdd06d - internal/group: set Z to 1, not 0 in FromAffine <Filippo Valsorda>
+
ffa7be7 - internal/group: fix typo <Filippo Valsorda>
+
1f452ac - internal/group: derive twoD from D <Filippo Valsorda>
+
2424c78 - internal/radix51: add MinusOne <Filippo Valsorda>
+
76978fc - internal/group: make conversion APIs caller-allocated <Filippo Valsorda>
+
d17d202 - internal/group: rewrite DoubleZ1 because stack is cheaper than mental state <Filippo Valsorda>
+
72b97c1 - internal: make all APIs chainable <Filippo Valsorda>
+
993d979 - internal/radix51: make all APIs not consider the receiver an input <Filippo Valsorda>
+
b2a1d7d - all: refactor field API to be methods based <Filippo Valsorda>
+
cdf9b90 - internal/radix51: add constant time field operations <Filippo Valsorda>
+
e490a48 - internal/radix51: remove FeEqual <Filippo Valsorda>
+
2de114c - internal/radix51: remove FeCSwap <Filippo Valsorda>
+
08b80c1 - make things more generally presentable <George Tankersley>
+
2178536 - Cache the field representation of d <George Tankersley>
+
4135059 - Remove 32-bit code and update license. <George Tankersley>
+
5d95cb3 - Use Bits() for FeToBig. <George Tankersley>
+
146e33c - Implement ScalarMult using Montgomery pattern and dedicated extended-coordinates doubling. This will be slow. <George Tankersley>
+
12a673a - use faster FeFromBig & a horrible assortment of other random changes <George Tankersley>
+
901f40c - group logic WIP <George Tankersley>
+
a9c89cd - add equality for field elements <George Tankersley>
+
214873b - Add radix51 FieldElement implementation <George Tankersley>
+
8fd5cae - Implement an elliptic.Curve for
ed25519 <George Tankersley>
Change-Id: Ifbcdd13e8b6304f9906c0ef2b73f1fdc493a7dfa
Co-authored-by: George Tankersley <george.tankersley@gmail.com>
Co-authored-by: Henry de Valence <hdevalence@hdevalence.ca>
Reviewed-on: https://go-review.googlesource.com/c/go/+/276272
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>
Trust: Katie Hockman <katie@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>