1403 lines
38 KiB
Text
1403 lines
38 KiB
Text
|
|
||
|
|
||
|
[Docs] [txt|pdf] [Tracker] [Email] [Diff1] [Diff2] [Nits]
|
||
|
|
||
|
Versions: 00 01 02
|
||
|
|
||
|
Network Working Group S. Josefsson
|
||
|
Internet-Draft SJD AB
|
||
|
Intended status: Informational N. Moeller
|
||
|
Expires: August 26, 2015
|
||
|
February 22, 2015
|
||
|
|
||
|
|
||
|
EdDSA and Ed25519
|
||
|
|
||
|
draft-josefsson-eddsa-ed25519-02
|
||
|
|
||
|
|
||
|
Abstract
|
||
|
|
||
|
The elliptic curve signature scheme EdDSA and one instance of it
|
||
|
called Ed25519 is described. An example implementation and test
|
||
|
vectors are provided.
|
||
|
|
||
|
Status of This Memo
|
||
|
|
||
|
This Internet-Draft is submitted in full conformance with the
|
||
|
provisions of BCP 78 and BCP 79.
|
||
|
|
||
|
Internet-Drafts are working documents of the Internet Engineering
|
||
|
Task Force (IETF). Note that other groups may also distribute
|
||
|
working documents as Internet-Drafts. The list of current Internet-
|
||
|
Drafts is at http://datatracker.ietf.org/drafts/current/.
|
||
|
|
||
|
Internet-Drafts are draft documents valid for a maximum of six months
|
||
|
and may be updated, replaced, or obsoleted by other documents at any
|
||
|
time. It is inappropriate to use Internet-Drafts as reference
|
||
|
material or to cite them other than as "work in progress."
|
||
|
|
||
|
This Internet-Draft will expire on August 26, 2015.
|
||
|
|
||
|
Copyright Notice
|
||
|
|
||
|
Copyright (c) 2015 IETF Trust and the persons identified as the
|
||
|
document authors. All rights reserved.
|
||
|
|
||
|
This document is subject to BCP 78 and the IETF Trust's Legal
|
||
|
Provisions Relating to IETF Documents
|
||
|
(http://trustee.ietf.org/license-info) in effect on the date of
|
||
|
publication of this document. Please review these documents
|
||
|
carefully, as they describe your rights and restrictions with respect
|
||
|
to this document. Code Components extracted from this document must
|
||
|
include Simplified BSD License text as described in Section 4.e of
|
||
|
the Trust Legal Provisions and are provided without warranty as
|
||
|
described in the Simplified BSD License.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 1]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
Table of Contents
|
||
|
|
||
|
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
|
||
|
2. Notation . . . . . . . . . . . . . . . . . . . . . . . . . . 3
|
||
|
3. Background . . . . . . . . . . . . . . . . . . . . . . . . . 3
|
||
|
4. EdDSA . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
|
||
|
4.1. Encoding . . . . . . . . . . . . . . . . . . . . . . . . 4
|
||
|
4.2. Keys . . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||
|
4.3. Sign . . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||
|
4.4. Verify . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||
|
5. Ed25519 . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||
|
5.1. Modular arithmetic . . . . . . . . . . . . . . . . . . . 6
|
||
|
5.2. Encoding . . . . . . . . . . . . . . . . . . . . . . . . 6
|
||
|
5.3. Decoding . . . . . . . . . . . . . . . . . . . . . . . . 6
|
||
|
5.4. Point addition . . . . . . . . . . . . . . . . . . . . . 7
|
||
|
5.5. Key Generation . . . . . . . . . . . . . . . . . . . . . 8
|
||
|
5.6. Sign . . . . . . . . . . . . . . . . . . . . . . . . . . 8
|
||
|
5.7. Verify . . . . . . . . . . . . . . . . . . . . . . . . . 9
|
||
|
5.8. Python illustration . . . . . . . . . . . . . . . . . . . 9
|
||
|
6. Test Vectors for Ed25519 . . . . . . . . . . . . . . . . . . 14
|
||
|
7. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 17
|
||
|
8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 18
|
||
|
9. Security Considerations . . . . . . . . . . . . . . . . . . . 18
|
||
|
9.1. Side-channel leaks . . . . . . . . . . . . . . . . . . . 18
|
||
|
10. References . . . . . . . . . . . . . . . . . . . . . . . . . 18
|
||
|
10.1. Normative References . . . . . . . . . . . . . . . . . . 18
|
||
|
10.2. Informative References . . . . . . . . . . . . . . . . . 18
|
||
|
Appendix A. Ed25519 Python Library . . . . . . . . . . . . . . . 19
|
||
|
Appendix B. Library driver . . . . . . . . . . . . . . . . . . . 23
|
||
|
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 24
|
||
|
|
||
|
1. Introduction
|
||
|
|
||
|
|
||
|
The Edwards-curve Digital Signature Algorithm (EdDSA) is a variant of
|
||
|
Schnorr's signature system with Twisted Edwards curves. EdDSA needs
|
||
|
to be instantiated with certain parameters and this document describe
|
||
|
Ed25519 - an instantiation of EdDSA in a curve over GF(2^255-19). To
|
||
|
facilitate adoption in the Internet community of Ed25519, this
|
||
|
document describe the signature scheme in an implementation-oriented
|
||
|
way, and we provide sample code and test vectors.
|
||
|
|
||
|
The advantages with EdDSA and Ed25519 include:
|
||
|
|
||
|
1. High-performance on a variety of platforms.
|
||
|
|
||
|
2. Does not require the use of a unique random number for each
|
||
|
signature.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 2]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
3. More resilient to side-channel attacks.
|
||
|
|
||
|
4. Small public keys (32 bytes) and signatures (64 bytes).
|
||
|
|
||
|
5. The formulas are "strongly unified", i.e., they are valid for all
|
||
|
points on the curve, with no exceptions. This obviates the need
|
||
|
for EdDSA to perform expensive point validation on untrusted
|
||
|
public values.
|
||
|
|
||
|
6. Collision resilience, meaning that hash-function collisions do
|
||
|
not break this system.
|
||
|
|
||
|
For further background, see the original EdDSA paper [EDDSA].
|
||
|
|
||
|
2. Notation
|
||
|
|
||
|
|
||
|
The following notation is used throughout the document:
|
||
|
|
||
|
GF(p) finite field with p elements
|
||
|
|
||
|
x^y x multiplied by itself y times
|
||
|
|
||
|
B generator of the group or subgroup of interest
|
||
|
|
||
|
n B B added to itself n times.
|
||
|
|
||
|
h_i the i'th bit of h
|
||
|
|
||
|
a || b (bit-)string a concatenated with (bit-)string b
|
||
|
|
||
|
3. Background
|
||
|
|
||
|
|
||
|
EdDSA is defined using an elliptic curve over GF(p) of the form
|
||
|
|
||
|
-x^2 + y^2 = 1 + d x^2 y^2
|
||
|
|
||
|
In general, p could be a prime power, but it is usually chosen as a
|
||
|
prime number. It is required that p = 1 modulo 4 (which implies that
|
||
|
-1 is a square modulo p) and that d is a non-square modulo p. For
|
||
|
Ed25519, the curve used is equivalent to Curve25519 [CURVE25519],
|
||
|
under a change of coordinates, which means that the difficulty of the
|
||
|
discrete logarithm problem is the same as for Curve25519.
|
||
|
|
||
|
Points on this curve form a group under addition, (x3, y3) = (x1, y1)
|
||
|
+ (x2, y2), with the formulas
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 3]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
x1 y2 + x2 y1 y1 y2 + x1 x2
|
||
|
x3 = -------------------, y3 = -------------------
|
||
|
1 + d x1 x2 y1 y2 1 - d x1 x2 y1 y2
|
||
|
|
||
|
The neutral element in the group is (0, 1).
|
||
|
|
||
|
Unlike manyy other curves used for cryptographic applications, these
|
||
|
formulas are "strongly unified": they are valid for all points on the
|
||
|
curve, with no exceptions. In particular, the denominators are non-
|
||
|
zero for all input points.
|
||
|
|
||
|
There are more efficient formulas, which are still strongly unified,
|
||
|
which use homogeneous coordinates to avoid the expensive modulo p
|
||
|
inversions. See [Faster-ECC] and [Edwards-revisited].
|
||
|
|
||
|
4. EdDSA
|
||
|
|
||
|
|
||
|
EdDSA is a digital signature system with several parameters. The
|
||
|
generic EdDSA digital signature system is normally not implemented
|
||
|
directly, but instead a particular instance of EdDSA (like Ed25519)
|
||
|
is implemented. A precise explanation of the generic EdDSA is thus
|
||
|
not particulary useful for implementers, but for background and
|
||
|
completeness, a succint description of the generic EdDSA algorithm is
|
||
|
given here.
|
||
|
|
||
|
EdDSA has seven parameters:
|
||
|
|
||
|
1. an integer b >= 10.
|
||
|
|
||
|
2. a cryptographic hash function H producing 2b-bit outputs.
|
||
|
|
||
|
3. a prime power p congruent to 1 modulo 4.
|
||
|
|
||
|
4. a (b-1)-bit encoding of elements of the finite field GF(p).
|
||
|
|
||
|
5. a non-square element d of GF(p)
|
||
|
|
||
|
6. an element B != (0,1) of the set E = { (x,y) is a member of GF(p)
|
||
|
x GF(p) such that -x^2 + y^2 = 1 + dx^2y^2 }.
|
||
|
|
||
|
7. a prime q, of size b-3 bits, such that qB = (0, 1), i.e., q is
|
||
|
the order of B or a multiple thereof.
|
||
|
|
||
|
4.1. Encoding
|
||
|
|
||
|
|
||
|
An element (x,y) of E is encoded as a b-bit string called ENC(x,y)
|
||
|
which is the (b-1)-bit encoding of y concatenated with one bit that
|
||
|
is 1 if x is negative and 0 if x is not negative. Negative elements
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 4]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
of GF(q) are those x which the (b-1)-bit encoding of x is
|
||
|
lexicographically larger than the (b-1)-bit encoding of -x.
|
||
|
|
||
|
4.2. Keys
|
||
|
|
||
|
|
||
|
An EdDSA secret key is a b-bit string k. Let the hash H(k) = (h_0,
|
||
|
h_1, ..., h_(2b-1)) determine an integer a which is 2^(b-2) plus the
|
||
|
sum of m = 2^i * h_i for all i equal or larger than 3 and equal to or
|
||
|
less than b-3 such that m is a member of the set { 2^(b-2), 2^(b-2) +
|
||
|
8, ..., 2^(b-1) - 8 }. The EdDSA public key is ENC(A) = ENC(aB).
|
||
|
The bits h_b, ..., h_(2b-1) is used below during signing.
|
||
|
|
||
|
4.3. Sign
|
||
|
|
||
|
|
||
|
The signature of a message M under a secret key k is the 2b-bit
|
||
|
string ENC(R) || ENC'(S), where ENC'(S) is defined as the b-bit
|
||
|
little-endian encoding of S. R and S are derived as follows. First
|
||
|
define r = H(h_b, ... h_(2b-1)), M) interpreting 2b-bit strings in
|
||
|
little-endian form as integers in {0, 1, ..., 2^(2b)-1}. Let R=rB
|
||
|
and S=(r+H(ENC(R) || ENC(A) || M)a) mod l.
|
||
|
|
||
|
4.4. Verify
|
||
|
|
||
|
|
||
|
To verify a signature ENC(R) || ENC'(S) on a message M under a public
|
||
|
key ENC(A), proceed as follows. Parse the inputs so that A and R is
|
||
|
an element of E, and S is a member of the set {0, 1, ..., l-1 }.
|
||
|
Compute H' = H(ENC(R) || ENC(A) || M) and check the group equation
|
||
|
8SB = 8R + 8H'A in E. Verification is rejected if parsing fails or
|
||
|
the group equation does not hold.
|
||
|
|
||
|
5. Ed25519
|
||
|
|
||
|
|
||
|
Theoretically, Ed25519 is EdDSA instantiated with b=256, H being
|
||
|
SHA-512 [RFC4634], p is the prime 2^255-19, the 255-bit encoding of
|
||
|
GF(2^255-19) being the little-endian encoding of {0, 1, ...,
|
||
|
2^255-20}, q is the prime 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed,
|
||
|
d = -121665/121666 which is a member of GF(p), and B is the unique
|
||
|
point (x, 4/5) in E for which x is "positive", which with the
|
||
|
encoding used simply means that the least significant bit of x is 0.
|
||
|
The curve p, prime q, d and B follows from [I-D.irtf-cfrg-curves].
|
||
|
|
||
|
Written out explicitly, B is the point (15112221349535400772501151409
|
||
|
588531511454012693041857206046113283949847762202, 4631683569492647816
|
||
|
9428394003475163141307993866256225615783033603165251855960).
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 5]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
5.1. Modular arithmetic
|
||
|
|
||
|
|
||
|
For advise on how to implement arithmetic modulo p = 2^255 - 1
|
||
|
efficiently and securely, see Curve25519 [CURVE25519]. For inversion
|
||
|
modulo p, it is recommended to use the identity x^-1 = x^(p-2) (mod
|
||
|
p).
|
||
|
|
||
|
For point decoding or "decompression", square roots modulo p are
|
||
|
needed. They can be computed using the Tonelli-Shanks algorithm, or
|
||
|
the special case for p = 5 (mod 8). To find a square root of a,
|
||
|
first compute the candidate root x = a^((p+3)/8) (mod p). Then there
|
||
|
are three cases:
|
||
|
|
||
|
x^2 = a (mod p). Then x is a square root.
|
||
|
|
||
|
x^2 = -a (mod p). Then 2^((p-1)/4) x is a square root.
|
||
|
|
||
|
a is not a square modulo p.
|
||
|
|
||
|
5.2. Encoding
|
||
|
|
||
|
|
||
|
All values are coded as octet strings, and integers are coded using
|
||
|
little endian convention. I.e., a 32-octet string h h[0],...h[31]
|
||
|
represents the integer h[0] + 2^8 h[1] + ... + 2^248 h[31].
|
||
|
|
||
|
A curve point (x,y), with coordiantes in the range 0 <= x,y < p, is
|
||
|
coded as follows. First encode the y-coordinate as a little-endian
|
||
|
string of 32 octets. The most significant bit of the final octet is
|
||
|
always zero. To form the encoding of the point, copy the least
|
||
|
significant bit of the x-coordinate to the most significant bit of
|
||
|
the final octet.
|
||
|
|
||
|
5.3. Decoding
|
||
|
|
||
|
|
||
|
Decoding a point, given as a 32-octet string, is a little more
|
||
|
complicated.
|
||
|
|
||
|
1. First interpret the string as an integer in little-endian
|
||
|
representation. Bit 255 of this number is the least significant
|
||
|
bit of the x-coordinate, and denote this value x_0. The
|
||
|
y-coordinate is recovered simply by clearing this bit. If the
|
||
|
resulting value is >= p, decoding fails.
|
||
|
|
||
|
2. To recover the x coordinate, the curve equation implies x^2 =
|
||
|
(y^2 - 1) / (d y^2 + 1) (mod p). Since d is a non-square and -1
|
||
|
is a square, the numerator, (d y^2 + 1), is always invertible
|
||
|
modulo p. Let u = y^2 - 1 and v = d y^2 + 1. To compute the
|
||
|
square root of (u/v), the first step is to compute the candidate
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 6]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
root x = (u/v)^((p+3)/8). This can be done using the following
|
||
|
trick, to use a single modular powering for both the inversion of
|
||
|
v and the square root:
|
||
|
|
||
|
(p+3)/8 3 (p-5)/8
|
||
|
x = (u/v) = u v (u v^7) (mod p)
|
||
|
|
||
|
3. Again, there are three cases:
|
||
|
|
||
|
1. If v x^2 = u (mod p), x is a square root.
|
||
|
|
||
|
2. If v x^2 = -u (mod p), set x <-- x 2^((p-1)/4), which is a
|
||
|
square root.
|
||
|
|
||
|
3. Otherwise, no square root exists modulo p, and decoding
|
||
|
fails.
|
||
|
|
||
|
4. Finally, use the x_0 bit to select the right square root. If x =
|
||
|
0, and x_0 = 1, decoding fails. Otherwise, if x_0 != x mod 2,
|
||
|
set x <-- p - x. Return the decoded point (x,y).
|
||
|
|
||
|
5.4. Point addition
|
||
|
|
||
|
|
||
|
For point addition, the following method is recommended. A point
|
||
|
(x,y) is represented in extended homogeneous coordinates (X, Y, Z,
|
||
|
T), with x = X/Z, y = Y/Z, x y = T/Z.
|
||
|
|
||
|
The following formulas for adding two points, (x3,y3) =
|
||
|
(x1,y1)+(x2,y2) are described in [Edwards-revisited], section 3.1.
|
||
|
They are strongly unified, i.e., they work for any pair of valid
|
||
|
input points.
|
||
|
|
||
|
A = (Y1-X1)*(Y2-X2)
|
||
|
B = (Y1+X1)*(Y2+X2)
|
||
|
C = T1*2*d*T2
|
||
|
D = Z1*2*Z2
|
||
|
E = B-A
|
||
|
F = D-C
|
||
|
G = D+C
|
||
|
H = B+A
|
||
|
X3 = E*F
|
||
|
Y3 = G*H
|
||
|
T3 = E*H
|
||
|
Z3 = F*G
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 7]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
5.5. Key Generation
|
||
|
|
||
|
|
||
|
The secret is 32 octets (256 bits, corresponding to b) of
|
||
|
cryptographically-secure random data. See [RFC4086] for a discussion
|
||
|
about randomness.
|
||
|
|
||
|
The 32-byte public key is generated by the following steps.
|
||
|
|
||
|
1. Hash the 32-byte secret using SHA-512, storing the digest in a
|
||
|
64-octet large buffer, denoted h. Only the lower 32 bytes are
|
||
|
used for generating the public key.
|
||
|
|
||
|
2. Prune the buffer. In C terminology:
|
||
|
|
||
|
h[0] &= ~0x07;
|
||
|
h[31] &= 0x7F;
|
||
|
h[31] |= 0x40;
|
||
|
|
||
|
3. Interpret the buffer as the little-endian integer, forming a
|
||
|
secret scalar a. Perform a known-base-point scalar
|
||
|
multiplication a B.
|
||
|
|
||
|
4. The public key A is the encoding of the point aB. First encode
|
||
|
the y coordinate (in the range 0 <= y < p) as a little-endian
|
||
|
string of 32 octets. The most significant bit of the final octet
|
||
|
is always zero. To form the encoding of the point aB, copy the
|
||
|
least significant bit of the x coordinate to the most significant
|
||
|
bit of the final octet. The result is the public key.
|
||
|
|
||
|
5.6. Sign
|
||
|
|
||
|
|
||
|
The imputs to the signing procedure is the secret key, a 32-octet
|
||
|
string, and a message M of arbitrary size.
|
||
|
|
||
|
1. Hash the secret key, 32-octets, using SHA-512. Let h denote the
|
||
|
resulting digest. Construct the secret scalar a from the first
|
||
|
half of the digest, and the corresponding public key A, as
|
||
|
described in the previous section. Let prefix denote the second
|
||
|
half of the hash digest, h[32],...,h[63].
|
||
|
|
||
|
2. Compute SHA-512(prefix || M), where M is the message to be
|
||
|
signed. Interpret the 64-octet digest as a little-endian integer
|
||
|
r.
|
||
|
|
||
|
3. Compute the point rB. For efficiency, do this by first reducing
|
||
|
r modulo q, the group order of B. Let the string R be the
|
||
|
encoding of this point.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 8]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
4. Compute SHA512(R || A || M), and interpret the 64-octet digest as
|
||
|
a little-endian integer k.
|
||
|
|
||
|
5. Compute s = (r + k a) mod q. For efficiency, again reduce k
|
||
|
modulo q first.
|
||
|
|
||
|
6. Form the signature of the concatenation of R (32 octets) and the
|
||
|
little-endian encoding of s (32 octets, three most significant
|
||
|
bits of the final octets always zero).
|
||
|
|
||
|
5.7. Verify
|
||
|
|
||
|
|
||
|
1. To verify a signature on a message M, first split the signature
|
||
|
into two 32-octet halves. Decode the first half as a point R,
|
||
|
and the second half as an integer s, in the range 0 <= s < q. If
|
||
|
the decoding fails, the signature is invalid.
|
||
|
|
||
|
2. Compute SHA512(R || A || M), and interpret the 64-octet digest as
|
||
|
a little-endian integer k.
|
||
|
|
||
|
3. Check the group equation 8s B = 8 R + 8k A. It's sufficient, but
|
||
|
not required, to instead check s B = R + k A.
|
||
|
|
||
|
5.8. Python illustration
|
||
|
|
||
|
|
||
|
The rest of this section describes how Ed25519 can be implemented in
|
||
|
Python (version 3.2 or later) for illustration. See appendix A for
|
||
|
the complete implementation and appendix B for a test-driver to run
|
||
|
it through some test vectors.
|
||
|
|
||
|
First some preliminaries that will be needed.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 9]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
import hashlib
|
||
|
|
||
|
def sha512(s):
|
||
|
return hashlib.sha512(s).digest()
|
||
|
|
||
|
# Base field Z_p
|
||
|
p = 2**255 - 19
|
||
|
|
||
|
def modp_inv(x):
|
||
|
return pow(x, p-2, p)
|
||
|
|
||
|
# Curve constant
|
||
|
d = -121665 * modp_inv(121666) % p
|
||
|
|
||
|
# Group order
|
||
|
q = 2**252 + 27742317777372353535851937790883648493
|
||
|
|
||
|
def sha512_modq(s):
|
||
|
return int.from_bytes(sha512(s), "little") % q
|
||
|
|
||
|
Then follows functions to perform point operations.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 10]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
# Points are represented as tuples (X, Y, Z, T) of extended coordinates,
|
||
|
# with x = X/Z, y = Y/Z, x*y = T/Z
|
||
|
|
||
|
def point_add(P, Q):
|
||
|
A = (P[1]-P[0])*(Q[1]-Q[0]) % p
|
||
|
B = (P[1]+P[0])*(Q[1]+Q[0]) % p
|
||
|
C = 2 * P[3] * Q[3] * d % p
|
||
|
D = 2 * P[2] * Q[2] % p
|
||
|
E = B-A
|
||
|
F = D-C
|
||
|
G = D+C
|
||
|
H = B+A
|
||
|
return (E*F, G*H, F*G, E*H)
|
||
|
|
||
|
# Computes Q = s * Q
|
||
|
def point_mul(s, P):
|
||
|
Q = (0, 1, 1, 0) # Neutral element
|
||
|
while s > 0:
|
||
|
# Is there any bit-set predicate?
|
||
|
if s & 1:
|
||
|
Q = point_add(Q, P)
|
||
|
P = point_add(P, P)
|
||
|
s >>= 1
|
||
|
return Q
|
||
|
|
||
|
def point_equal(P, Q):
|
||
|
# x1 / z1 == x2 / z2 <==> x1 * z2 == x2 * z1
|
||
|
if (P[0] * Q[2] - Q[0] * P[2]) % p != 0:
|
||
|
return False
|
||
|
if (P[1] * Q[2] - Q[1] * P[2]) % p != 0:
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
Now follows functions for point compression.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 11]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
# Square root of -1
|
||
|
modp_sqrt_m1 = pow(2, (p-1) // 4, p)
|
||
|
|
||
|
# Compute corresponding x coordinate, with low bit corresponding to sign,
|
||
|
# or return None on failure
|
||
|
def recover_x(y, sign):
|
||
|
x2 = (y*y-1) * modp_inv(d*y*y+1)
|
||
|
if x2 == 0:
|
||
|
if sign:
|
||
|
return None
|
||
|
else:
|
||
|
return 0
|
||
|
|
||
|
# Compute square root of x2
|
||
|
x = pow(x2, (p+3) // 8, p)
|
||
|
if (x*x - x2) % p != 0:
|
||
|
x = x * modp_sqrt_m1 % p
|
||
|
if (x*x - x2) % p != 0:
|
||
|
return None
|
||
|
|
||
|
if (x & 1) != sign:
|
||
|
x = p - x
|
||
|
return x
|
||
|
|
||
|
# Base point
|
||
|
g_y = 4 * modp_inv(5) % p
|
||
|
g_x = recover_x(g_y, 0)
|
||
|
G = (g_x, g_y, 1, g_x * g_y % p)
|
||
|
|
||
|
def point_compress(P):
|
||
|
zinv = modp_inv(P[2])
|
||
|
x = P[0] * zinv % p
|
||
|
y = P[1] * zinv % p
|
||
|
return int.to_bytes(y | ((x & 1) << 255), 32, "little")
|
||
|
|
||
|
def point_decompress(s):
|
||
|
if len(s) != 32:
|
||
|
raise Exception("Invalid input length for decompression")
|
||
|
y = int.from_bytes(s, "little")
|
||
|
sign = y >> 255
|
||
|
y &= (1 << 255) - 1
|
||
|
|
||
|
x = recover_x(y, sign)
|
||
|
if x is None:
|
||
|
return None
|
||
|
else:
|
||
|
return (x, y, 1, x*y % p)
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 12]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
These are functions for manipulating the secret.
|
||
|
|
||
|
def secret_expand(secret):
|
||
|
if len(secret) != 32:
|
||
|
raise Exception("Bad size of private key")
|
||
|
h = sha512(secret)
|
||
|
a = int.from_bytes(h[:32], "little")
|
||
|
a &= (1 << 254) - 8
|
||
|
a |= (1 << 254)
|
||
|
return (a, h[32:])
|
||
|
|
||
|
def secret_to_public(secret):
|
||
|
(a, dummy) = secret_expand(secret)
|
||
|
return point_compress(point_mul(a, G))
|
||
|
|
||
|
The signature function works as below.
|
||
|
|
||
|
def sign(secret, msg):
|
||
|
a, prefix = secret_expand(secret)
|
||
|
A = point_compress(point_mul(a, G))
|
||
|
r = sha512_modq(prefix + msg)
|
||
|
R = point_mul(r, G)
|
||
|
Rs = point_compress(R)
|
||
|
h = sha512_modq(Rs + A + msg)
|
||
|
s = (r + h * a) % q
|
||
|
return Rs + int.to_bytes(s, 32, "little")
|
||
|
|
||
|
And finally the verification function.
|
||
|
|
||
|
def verify(public, msg, signature):
|
||
|
if len(public) != 32:
|
||
|
raise Exception("Bad public-key length")
|
||
|
if len(signature) != 64:
|
||
|
Exception("Bad signature length")
|
||
|
A = point_decompress(public)
|
||
|
if not A:
|
||
|
return False
|
||
|
Rs = signature[:32]
|
||
|
R = point_decompress(Rs)
|
||
|
if not R:
|
||
|
return False
|
||
|
s = int.from_bytes(signature[32:], "little")
|
||
|
h = sha512_modq(Rs + public + msg)
|
||
|
sB = point_mul(s, G)
|
||
|
hA = point_mul(h, A)
|
||
|
return point_equal(sB, point_add(R, hA))
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 13]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
6. Test Vectors for Ed25519
|
||
|
|
||
|
|
||
|
Below is a sequence of octets with test vectors for the the Ed25519
|
||
|
signature algorithm. The octets are hex encoded and whitespace is
|
||
|
inserted for readability. Private keys are 64 bytes, public keys 32
|
||
|
bytes, message of arbitrary length, and signatures are 64 bytes. The
|
||
|
test vectors are taken from [ED25519-TEST-VECTORS] (but we removed
|
||
|
the public key as a suffix of the secret key, and removed the message
|
||
|
from the signature) and [ED25519-LIBGCRYPT-TEST-VECTORS].
|
||
|
|
||
|
-----TEST 1
|
||
|
SECRET KEY:
|
||
|
9d61b19deffd5a60ba844af492ec2cc4
|
||
|
4449c5697b326919703bac031cae7f60
|
||
|
|
||
|
PUBLIC KEY:
|
||
|
d75a980182b10ab7d54bfed3c964073a
|
||
|
0ee172f3daa62325af021a68f707511a
|
||
|
|
||
|
MESSAGE (length 0 bytes):
|
||
|
|
||
|
SIGNATURE:
|
||
|
e5564300c360ac729086e2cc806e828a
|
||
|
84877f1eb8e5d974d873e06522490155
|
||
|
5fb8821590a33bacc61e39701cf9b46b
|
||
|
d25bf5f0595bbe24655141438e7a100b
|
||
|
|
||
|
-----TEST 2
|
||
|
SECRET KEY:
|
||
|
4ccd089b28ff96da9db6c346ec114e0f
|
||
|
5b8a319f35aba624da8cf6ed4fb8a6fb
|
||
|
|
||
|
PUBLIC KEY:
|
||
|
3d4017c3e843895a92b70aa74d1b7ebc
|
||
|
9c982ccf2ec4968cc0cd55f12af4660c
|
||
|
|
||
|
MESSAGE (length 1 byte):
|
||
|
72
|
||
|
|
||
|
SIGNATURE:
|
||
|
92a009a9f0d4cab8720e820b5f642540
|
||
|
a2b27b5416503f8fb3762223ebdb69da
|
||
|
085ac1e43e15996e458f3613d0f11d8c
|
||
|
387b2eaeb4302aeeb00d291612bb0c00
|
||
|
|
||
|
-----TEST 3
|
||
|
SECRET KEY:
|
||
|
c5aa8df43f9f837bedb7442f31dcb7b1
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 14]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
66d38535076f094b85ce3a2e0b4458f7
|
||
|
|
||
|
PUBLIC KEY:
|
||
|
fc51cd8e6218a1a38da47ed00230f058
|
||
|
0816ed13ba3303ac5deb911548908025
|
||
|
|
||
|
MESSAGE (length 2 bytes):
|
||
|
af82
|
||
|
|
||
|
SIGNATURE:
|
||
|
6291d657deec24024827e69c3abe01a3
|
||
|
0ce548a284743a445e3680d7db5ac3ac
|
||
|
18ff9b538d16f290ae67f760984dc659
|
||
|
4a7c15e9716ed28dc027beceea1ec40a
|
||
|
|
||
|
-----TEST 1024
|
||
|
SECRET KEY:
|
||
|
f5e5767cf153319517630f226876b86c
|
||
|
8160cc583bc013744c6bf255f5cc0ee5
|
||
|
|
||
|
PUBLIC KEY:
|
||
|
278117fc144c72340f67d0f2316e8386
|
||
|
ceffbf2b2428c9c51fef7c597f1d426e
|
||
|
|
||
|
MESSAGE:
|
||
|
08b8b2b733424243760fe426a4b54908
|
||
|
632110a66c2f6591eabd3345e3e4eb98
|
||
|
fa6e264bf09efe12ee50f8f54e9f77b1
|
||
|
e355f6c50544e23fb1433ddf73be84d8
|
||
|
79de7c0046dc4996d9e773f4bc9efe57
|
||
|
38829adb26c81b37c93a1b270b20329d
|
||
|
658675fc6ea534e0810a4432826bf58c
|
||
|
941efb65d57a338bbd2e26640f89ffbc
|
||
|
1a858efcb8550ee3a5e1998bd177e93a
|
||
|
7363c344fe6b199ee5d02e82d522c4fe
|
||
|
ba15452f80288a821a579116ec6dad2b
|
||
|
3b310da903401aa62100ab5d1a36553e
|
||
|
06203b33890cc9b832f79ef80560ccb9
|
||
|
a39ce767967ed628c6ad573cb116dbef
|
||
|
efd75499da96bd68a8a97b928a8bbc10
|
||
|
3b6621fcde2beca1231d206be6cd9ec7
|
||
|
aff6f6c94fcd7204ed3455c68c83f4a4
|
||
|
1da4af2b74ef5c53f1d8ac70bdcb7ed1
|
||
|
85ce81bd84359d44254d95629e9855a9
|
||
|
4a7c1958d1f8ada5d0532ed8a5aa3fb2
|
||
|
d17ba70eb6248e594e1a2297acbbb39d
|
||
|
502f1a8c6eb6f1ce22b3de1a1f40cc24
|
||
|
554119a831a9aad6079cad88425de6bd
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 15]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
e1a9187ebb6092cf67bf2b13fd65f270
|
||
|
88d78b7e883c8759d2c4f5c65adb7553
|
||
|
878ad575f9fad878e80a0c9ba63bcbcc
|
||
|
2732e69485bbc9c90bfbd62481d9089b
|
||
|
eccf80cfe2df16a2cf65bd92dd597b07
|
||
|
07e0917af48bbb75fed413d238f5555a
|
||
|
7a569d80c3414a8d0859dc65a46128ba
|
||
|
b27af87a71314f318c782b23ebfe808b
|
||
|
82b0ce26401d2e22f04d83d1255dc51a
|
||
|
ddd3b75a2b1ae0784504df543af8969b
|
||
|
e3ea7082ff7fc9888c144da2af58429e
|
||
|
c96031dbcad3dad9af0dcbaaaf268cb8
|
||
|
fcffead94f3c7ca495e056a9b47acdb7
|
||
|
51fb73e666c6c655ade8297297d07ad1
|
||
|
ba5e43f1bca32301651339e22904cc8c
|
||
|
42f58c30c04aafdb038dda0847dd988d
|
||
|
cda6f3bfd15c4b4c4525004aa06eeff8
|
||
|
ca61783aacec57fb3d1f92b0fe2fd1a8
|
||
|
5f6724517b65e614ad6808d6f6ee34df
|
||
|
f7310fdc82aebfd904b01e1dc54b2927
|
||
|
094b2db68d6f903b68401adebf5a7e08
|
||
|
d78ff4ef5d63653a65040cf9bfd4aca7
|
||
|
984a74d37145986780fc0b16ac451649
|
||
|
de6188a7dbdf191f64b5fc5e2ab47b57
|
||
|
f7f7276cd419c17a3ca8e1b939ae49e4
|
||
|
88acba6b965610b5480109c8b17b80e1
|
||
|
b7b750dfc7598d5d5011fd2dcc5600a3
|
||
|
2ef5b52a1ecc820e308aa342721aac09
|
||
|
43bf6686b64b2579376504ccc493d97e
|
||
|
6aed3fb0f9cd71a43dd497f01f17c0e2
|
||
|
cb3797aa2a2f256656168e6c496afc5f
|
||
|
b93246f6b1116398a346f1a641f3b041
|
||
|
e989f7914f90cc2c7fff357876e506b5
|
||
|
0d334ba77c225bc307ba537152f3f161
|
||
|
0e4eafe595f6d9d90d11faa933a15ef1
|
||
|
369546868a7f3a45a96768d40fd9d034
|
||
|
12c091c6315cf4fde7cb68606937380d
|
||
|
b2eaaa707b4c4185c32eddcdd306705e
|
||
|
4dc1ffc872eeee475a64dfac86aba41c
|
||
|
0618983f8741c5ef68d3a101e8a3b8ca
|
||
|
c60c905c15fc910840b94c00a0b9d0
|
||
|
|
||
|
SIGNATURE:
|
||
|
0aab4c900501b3e24d7cdf4663326a3a
|
||
|
87df5e4843b2cbdb67cbf6e460fec350
|
||
|
aa5371b1508f9f4528ecea23c436d94b
|
||
|
5e8fcd4f681e30a6ac00a9704a188a03
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 16]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
-----TEST 1A
|
||
|
-----An additional test with the data from test 1 but using an
|
||
|
-----uncompressed public key.
|
||
|
SECRET KEY:
|
||
|
9d61b19deffd5a60ba844af492ec2cc4
|
||
|
4449c5697b326919703bac031cae7f60
|
||
|
|
||
|
PUBLIC KEY:
|
||
|
0455d0e09a2b9d34292297e08d60d0f6
|
||
|
20c513d47253187c24b12786bd777645
|
||
|
ce1a5107f7681a02af2523a6daf372e1
|
||
|
0e3a0764c9d3fe4bd5b70ab18201985a
|
||
|
d7
|
||
|
|
||
|
MSG (length 0 bytes):
|
||
|
|
||
|
SIGNATURE:
|
||
|
e5564300c360ac729086e2cc806e828a
|
||
|
84877f1eb8e5d974d873e06522490155
|
||
|
5fb8821590a33bacc61e39701cf9b46b
|
||
|
d25bf5f0595bbe24655141438e7a100b
|
||
|
|
||
|
-----TEST 1B
|
||
|
-----An additional test with the data from test 1 but using an
|
||
|
-----compressed prefix.
|
||
|
SECRET KEY:
|
||
|
9d61b19deffd5a60ba844af492ec2cc4
|
||
|
4449c5697b326919703bac031cae7f60
|
||
|
|
||
|
PUBLIC KEY:
|
||
|
40d75a980182b10ab7d54bfed3c96407
|
||
|
3a0ee172f3daa62325af021a68f70751
|
||
|
1a
|
||
|
|
||
|
MESSAGE (length 0 bytes):
|
||
|
|
||
|
SIGNATURE:
|
||
|
e5564300c360ac729086e2cc806e828a
|
||
|
84877f1eb8e5d974d873e06522490155
|
||
|
5fb8821590a33bacc61e39701cf9b46b
|
||
|
d25bf5f0595bbe24655141438e7a100b
|
||
|
-----
|
||
|
|
||
|
7. Acknowledgements
|
||
|
|
||
|
|
||
|
Feedback on this document was received from Werner Koch and Damien
|
||
|
Miller.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 17]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
8. IANA Considerations
|
||
|
|
||
|
|
||
|
None.
|
||
|
|
||
|
9. Security Considerations
|
||
|
|
||
|
|
||
|
9.1. Side-channel leaks
|
||
|
|
||
|
|
||
|
For implementations performing signatures, secrecy of the key is
|
||
|
fundamental. It is possible to protect against some side-channel
|
||
|
attacks by ensuring that the implementation executes exactly the same
|
||
|
sequence of instructions and performs exactly the same memory
|
||
|
accesses, for any value of the secret key.
|
||
|
|
||
|
To make an implementation side-channel silent in this way, the modulo
|
||
|
p arithmetic must not use any data-dependent branches, e.g., related
|
||
|
to carry propagation. Side channel-silent point addition is
|
||
|
straight-forward, thanks to the unified formulas.
|
||
|
|
||
|
Scalar multiplication, multiplying a point by an integer, needs some
|
||
|
additional effort to implement in a side-channel silent manner. One
|
||
|
simple approach is to implement a side-channel silent conditional
|
||
|
assignment, and use together with the binary algorithm to examine one
|
||
|
bit of the integer at a time.
|
||
|
|
||
|
Note that the example implementation in this document does not
|
||
|
attempt to be side-channel silent.
|
||
|
|
||
|
10. References
|
||
|
|
||
|
|
||
|
10.1. Normative References
|
||
|
|
||
|
|
||
|
[RFC4634] Eastlake, D. and T. Hansen, "US Secure Hash Algorithms
|
||
|
(SHA and HMAC-SHA)", RFC 4634, July 2006.
|
||
|
|
||
|
[I-D.irtf-cfrg-curves]
|
||
|
Langley, A., Salz, R., and S. Turner, "Elliptic Curves for
|
||
|
Security", draft-irtf-cfrg-curves-01 (work in progress),
|
||
|
January 2015.
|
||
|
|
||
|
10.2. Informative References
|
||
|
|
||
|
|
||
|
[RFC4086] Eastlake, D., Schiller, J., and S. Crocker, "Randomness
|
||
|
Requirements for Security", BCP 106, RFC 4086, June 2005.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 18]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
[EDDSA] Bernstein, D., Duif, N., Lange, T., Schwabe, P., and B.
|
||
|
Yang, "High-speed high-security signatures", WWW
|
||
|
http://ed25519.cr.yp.to/ed25519-20110926.pdf, September
|
||
|
2011.
|
||
|
|
||
|
[Faster-ECC]
|
||
|
Bernstein, D. and T. Lange, "Faster addition and doubling
|
||
|
on elliptic curves", WWW http://eprint.iacr.org/2007/286,
|
||
|
July 2007.
|
||
|
|
||
|
[Edwards-revisited]
|
||
|
Hisil, H., Wong, K., Carter, G., and E. Dawson, "Twisted
|
||
|
Edwards Curves Revisited", WWW
|
||
|
http://eprint.iacr.org/2008/522, December 2008.
|
||
|
|
||
|
[CURVE25519]
|
||
|
Bernstein, D., "Curve25519: new Diffie-Hellman speed
|
||
|
records", WWW http://cr.yp.to/ecdh.html, February 2006.
|
||
|
|
||
|
[ED25519-TEST-VECTORS]
|
||
|
Bernstein, D., Duif, N., Lange, T., Schwabe, P., and B.
|
||
|
Yang, "Ed25519 test vectors", WWW
|
||
|
http://ed25519.cr.yp.to/python/sign.input, July 2011.
|
||
|
|
||
|
[ED25519-LIBGCRYPT-TEST-VECTORS]
|
||
|
Koch, W., "Ed25519 Libgcrypt test vectors", WWW
|
||
|
http://git.gnupg.org/cgi-
|
||
|
bin/gitweb.cgi?p=libgcrypt.git;a=blob;f=tests/t-ed25519.in
|
||
|
p;h=e13566f826321eece65e02c593bc7d885b3dbe23;hb=refs/
|
||
|
heads/master, July 2014.
|
||
|
|
||
|
Appendix A. Ed25519 Python Library
|
||
|
|
||
|
|
||
|
Below is an example implementation of Ed25519 written in Python,
|
||
|
version 3.2 or higher is required.
|
||
|
|
||
|
# Loosely based on the public domain code at
|
||
|
# http://ed25519.cr.yp.to/software.html
|
||
|
#
|
||
|
# Needs python-3.2
|
||
|
|
||
|
import hashlib
|
||
|
|
||
|
|
||
|
def sha512(s):
|
||
|
return hashlib.sha512(s).digest()
|
||
|
|
||
|
# Base field Z_p
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 19]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
p = 2**255 - 19
|
||
|
|
||
|
|
||
|
def modp_inv(x):
|
||
|
return pow(x, p-2, p)
|
||
|
|
||
|
# Curve constant
|
||
|
d = -121665 * modp_inv(121666) % p
|
||
|
|
||
|
# Group order
|
||
|
q = 2**252 + 27742317777372353535851937790883648493
|
||
|
|
||
|
|
||
|
def sha512_modq(s):
|
||
|
return int.from_bytes(sha512(s), "little") % q
|
||
|
|
||
|
# Points are represented as tuples (X, Y, Z, T) of extended coordinates,
|
||
|
# with x = X/Z, y = Y/Z, x*y = T/Z
|
||
|
|
||
|
|
||
|
def point_add(P, Q):
|
||
|
A = (P[1]-P[0])*(Q[1]-Q[0]) % p
|
||
|
B = (P[1]+P[0])*(Q[1]+Q[0]) % p
|
||
|
C = 2 * P[3] * Q[3] * d % p
|
||
|
D = 2 * P[2] * Q[2] % p
|
||
|
E = B-A
|
||
|
F = D-C
|
||
|
G = D+C
|
||
|
H = B+A
|
||
|
return (E*F, G*H, F*G, E*H)
|
||
|
|
||
|
|
||
|
# Computes Q = s * Q
|
||
|
def point_mul(s, P):
|
||
|
Q = (0, 1, 1, 0) # Neutral element
|
||
|
while s > 0:
|
||
|
# Is there any bit-set predicate?
|
||
|
if s & 1:
|
||
|
Q = point_add(Q, P)
|
||
|
P = point_add(P, P)
|
||
|
s >>= 1
|
||
|
return Q
|
||
|
|
||
|
|
||
|
def point_equal(P, Q):
|
||
|
# x1 / z1 == x2 / z2 <==> x1 * z2 == x2 * z1
|
||
|
if (P[0] * Q[2] - Q[0] * P[2]) % p != 0:
|
||
|
return False
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 20]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
if (P[1] * Q[2] - Q[1] * P[2]) % p != 0:
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
# Square root of -1
|
||
|
modp_sqrt_m1 = pow(2, (p-1) // 4, p)
|
||
|
|
||
|
|
||
|
# Compute corresponding x coordinate, with low bit corresponding to sign,
|
||
|
# or return None on failure
|
||
|
def recover_x(y, sign):
|
||
|
x2 = (y*y-1) * modp_inv(d*y*y+1)
|
||
|
if x2 == 0:
|
||
|
if sign:
|
||
|
return None
|
||
|
else:
|
||
|
return 0
|
||
|
|
||
|
# Compute square root of x2
|
||
|
x = pow(x2, (p+3) // 8, p)
|
||
|
if (x*x - x2) % p != 0:
|
||
|
x = x * modp_sqrt_m1 % p
|
||
|
if (x*x - x2) % p != 0:
|
||
|
return None
|
||
|
|
||
|
if (x & 1) != sign:
|
||
|
x = p - x
|
||
|
return x
|
||
|
|
||
|
# Base point
|
||
|
g_y = 4 * modp_inv(5) % p
|
||
|
g_x = recover_x(g_y, 0)
|
||
|
G = (g_x, g_y, 1, g_x * g_y % p)
|
||
|
|
||
|
|
||
|
def point_compress(P):
|
||
|
zinv = modp_inv(P[2])
|
||
|
x = P[0] * zinv % p
|
||
|
y = P[1] * zinv % p
|
||
|
return int.to_bytes(y | ((x & 1) << 255), 32, "little")
|
||
|
|
||
|
|
||
|
def point_decompress(s):
|
||
|
if len(s) != 32:
|
||
|
raise Exception("Invalid input length for decompression")
|
||
|
y = int.from_bytes(s, "little")
|
||
|
sign = y >> 255
|
||
|
y &= (1 << 255) - 1
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 21]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
x = recover_x(y, sign)
|
||
|
if x is None:
|
||
|
return None
|
||
|
else:
|
||
|
return (x, y, 1, x*y % p)
|
||
|
|
||
|
|
||
|
def secret_expand(secret):
|
||
|
if len(secret) != 32:
|
||
|
raise Exception("Bad size of private key")
|
||
|
h = sha512(secret)
|
||
|
a = int.from_bytes(h[:32], "little")
|
||
|
a &= (1 << 254) - 8
|
||
|
a |= (1 << 254)
|
||
|
return (a, h[32:])
|
||
|
|
||
|
|
||
|
def secret_to_public(secret):
|
||
|
(a, dummy) = secret_expand(secret)
|
||
|
return point_compress(point_mul(a, G))
|
||
|
|
||
|
|
||
|
def sign(secret, msg):
|
||
|
a, prefix = secret_expand(secret)
|
||
|
A = point_compress(point_mul(a, G))
|
||
|
r = sha512_modq(prefix + msg)
|
||
|
R = point_mul(r, G)
|
||
|
Rs = point_compress(R)
|
||
|
h = sha512_modq(Rs + A + msg)
|
||
|
s = (r + h * a) % q
|
||
|
return Rs + int.to_bytes(s, 32, "little")
|
||
|
|
||
|
|
||
|
def verify(public, msg, signature):
|
||
|
if len(public) != 32:
|
||
|
raise Exception("Bad public-key length")
|
||
|
if len(signature) != 64:
|
||
|
Exception("Bad signature length")
|
||
|
A = point_decompress(public)
|
||
|
if not A:
|
||
|
return False
|
||
|
Rs = signature[:32]
|
||
|
R = point_decompress(Rs)
|
||
|
if not R:
|
||
|
return False
|
||
|
s = int.from_bytes(signature[32:], "little")
|
||
|
h = sha512_modq(Rs + public + msg)
|
||
|
sB = point_mul(s, G)
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 22]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
hA = point_mul(h, A)
|
||
|
return point_equal(sB, point_add(R, hA))
|
||
|
|
||
|
Appendix B. Library driver
|
||
|
|
||
|
|
||
|
Below is a command-line tool that uses the library above to perform
|
||
|
computations, for interactive use or for self-checking.
|
||
|
|
||
|
import sys
|
||
|
import binascii
|
||
|
|
||
|
from ed25519 import *
|
||
|
|
||
|
def point_valid(P):
|
||
|
zinv = modp_inv(P[2])
|
||
|
x = P[0] * zinv % p
|
||
|
y = P[1] * zinv % p
|
||
|
assert (x*y - P[3]*zinv) % p == 0
|
||
|
return (-x*x + y*y - 1 - d*x*x*y*y) % p == 0
|
||
|
|
||
|
assert point_valid(G)
|
||
|
Z = (0, 1, 1, 0)
|
||
|
assert point_valid(Z)
|
||
|
|
||
|
assert point_equal(Z, point_add(Z, Z))
|
||
|
assert point_equal(G, point_add(Z, G))
|
||
|
assert point_equal(Z, point_mul(0, G))
|
||
|
assert point_equal(G, point_mul(1, G))
|
||
|
assert point_equal(point_add(G, G), point_mul(2, G))
|
||
|
for i in range(0, 100):
|
||
|
assert point_valid(point_mul(i, G))
|
||
|
assert point_equal(Z, point_mul(q, G))
|
||
|
|
||
|
def munge_string(s, pos, change):
|
||
|
return (s[:pos] +
|
||
|
int.to_bytes(s[pos] ^ change, 1, "little") +
|
||
|
s[pos+1:])
|
||
|
|
||
|
# Read a file in the format of
|
||
|
# http://ed25519.cr.yp.to/python/sign.input
|
||
|
lineno = 0
|
||
|
while True:
|
||
|
line = sys.stdin.readline()
|
||
|
if not line:
|
||
|
break
|
||
|
lineno = lineno + 1
|
||
|
print(lineno)
|
||
|
fields = line.split(":")
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 23]
|
||
|
|
||
|
|
||
|
Internet-Draft EdDSA & Ed25519 February 2015
|
||
|
|
||
|
|
||
|
secret = (binascii.unhexlify(fields[0]))[:32]
|
||
|
public = binascii.unhexlify(fields[1])
|
||
|
msg = binascii.unhexlify(fields[2])
|
||
|
signature = binascii.unhexlify(fields[3])[:64]
|
||
|
|
||
|
assert public == secret_to_public(secret)
|
||
|
assert signature == sign(secret, msg)
|
||
|
assert verify(public, msg, signature)
|
||
|
if len(msg) == 0:
|
||
|
bad_msg = b"x"
|
||
|
else:
|
||
|
bad_msg = munge_string(msg, len(msg) // 3, 4)
|
||
|
assert not verify(public, bad_msg, signature)
|
||
|
bad_signature = munge_string(signature, 20, 8)
|
||
|
assert not verify(public, msg, bad_signature)
|
||
|
bad_signature = munge_string(signature, 40, 16)
|
||
|
assert not verify(public, msg, bad_signature)
|
||
|
|
||
|
Authors' Addresses
|
||
|
|
||
|
Simon Josefsson
|
||
|
SJD AB
|
||
|
|
||
|
Email: simon@josefsson.org
|
||
|
URI: http://josefsson.org/
|
||
|
|
||
|
|
||
|
Niels Moeller
|
||
|
|
||
|
Email: nisse@lysator.liu.se
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Josefsson & Moeller Expires August 26, 2015 [Page 24]
|
||
|
|
||
|
|
||
|
|
||
|
Html markup produced by rfcmarkup 1.113, available from https://tools.ietf.org/tools/rfcmarkup/
|