The X448 method is used with the signing for the Edwards-Curve Digital Signature Algorithm (EdDSA), and is defined in RFC 8032. It uses a public key size of 57 bytes, a private key size of 57 bytes, and a signature size of 114 bytes.
X488 Signature |
Theory
The usage of Curve 25519 is well known in the industry, and is used with key exchange methods in SSL, Tor, and many other applications. Curve 25519 uses a Montgomery curve of \(y^2 = x^3 + 486662 x^2 + x\) with a prime number of \(2^{255}-19\). In its key exchange mode it integrates with ECDH, and is named X25519.But, we can also use a twisted Edwards Curve (\(x^2+y^2=1−dx^2y^2\)) to give us Ed25519. And so while Ed25519 gives 128-bit security, Ed448 enhances Ed25519 with the goldilocks prime (\(2^{448}−2^{224}−1\)) and increase the secure from aroudn 112 to 224 bits.
With Ed449, the public and the private keys are the same length, but the signature is double this length. In Ed448 we use the goldilocks version of a untwisted Edwards curve with \(x^2+y^2=1-39081x^2y^2\) and a prime of \(2^{448}-2^{224}-1\). An EdDSA private key (\(k\)) has \(b\) bits. We can then create a hash of this - and which is \(2b\) long - to created a number of hash bits (such as using SHAKE256):
\(H(k) = (h_0, h_1, ..., h_{2b-1})\)
We then calculate a value of \(s\):
s=\(2^n + \sum_{i} 2^i \times h_i\)
Now we have a base point on Edwards 448 curve of \(B\), and determine the public key point (\(A\)) of:
\(A = [s]B\)
The public key is then:
\(ENC(A)\)
and where the ENC(A) encoding format takes an integer (\(A\)) which has the length of the prime number \(p\) and encodes it into a \(b\) length bit-string.
This process generates the public key and the private key. In order to produce a signature of message of \(M\) and with a private key of \(k\), we first determine \(r\) which takes the hash bits and appends to the message:
\(r = H(h_b || \dots || h_{2b-1} || M)\)
and then compute \(R\) and \(S\):
\(R = r B\)
\(k=H(ENC(R) || ENC(A) || PH(M))\)
\(S = (r + k \times s) \pmod p\)
and where \(p\) is a prime number.
The EdDSA signature is then:
ENC(R) || ENC(S)
To verify the signature, we recover \(R\) and \(S\). As before, we compute a constant value of \(k\) (and where \(A\) is the public key, \(R\) is part of the signature and \(M\) is the message):
\(k=H(ENC(R) || ENC(A) || PH(M))\)
Now we take \(B\) (the base point), \(S\), \(R\), \(k\) and \(A\), and check that the point \(SB\) is equal to the point \((R + kA)\):
\(SB = R + kA\)
This works because \(SB = R + kA = rB + ksB = [B] S = [B] (r+ ks)\)
Note, we can also add in a context string (C), into the calculation of \(k\). We thus create a signature of a message \(M\) using a context \(C\) and prove with a public key of \(A\).
The following is an outline of the code:
package main import ( "github.com/cloudflare/circl/sign/ed448" "crypto/rand" "fmt" "os" ) func main() { msg:="Hello" cont:="Context" argCount := len(os.Args[1:]) if (argCount>0) { msg= os.Args[1]} if (argCount>1) { cont= os.Args[2]} alice, err := ed448.GenerateKey(rand.Reader) if err != nil { panic("error on generating keys") } message := []byte(msg) context := []byte(cont) signature, err := alice.SignWithContext(message, context) if err != nil { panic("error on signing message") } ok := ed448.Verify(alice.GetPublic(), message, context, signature) fmt.Printf("Message: %s\n",msg) fmt.Printf("Context: %s\n\n",cont) fmt.Printf("Alice private key: %x\nAlice Public key %x\n",alice.GetPrivate(),alice.GetPublic()) fmt.Printf("\nSignature: %x\n",signature) if (ok) { fmt.Println("\nSignature verified") } }
A sample run gives:
Message: Hello Context: None Alice private key: 6a56a7bf8ae2ebf3ac985db1aa55b25f9be38795e53e1ae4bba69d49cdffbd3c8496c1490ceeac29448f6d31b88f91ea985687cdd2f5821302 Alice Public key 9d7b6bc88eb8878c9cf0b3616c885be952dc5464c3f5a01833cfc4f50f471c677cee26a539236de11c531b883c2c0a6cbe098ca06b3a045200 Signature: b2968cc1fd3166a83eacface86116146b02b136a9aa9d94fbe0fd94c78082d24f3d90ce3160eaf1b1edbf3774298691119d6a9d1decf20c7003dd020c7a45878a99d37da4f7acaddd42e5e7a6adde3492cda0a35ac60f8b3e325c3f3f28ba79bb6a1a5c980e3437389d48870d69725b50600 Signature verified