Ed448 - Edwards-curve Digital Signature Algorithm (EdDSA) - uses Curve 443 and SHA-512 to produce an EdDSA signature. In this case we will perform the core operations in the signing and verification. With this we calculate the hash of the message (\(h\)) and have a public key (\(pk\)) and a private key (\(sk\)). We then generate a signature of (\(R,s\)). The public key (\(pk\)) and (\(R,s\)) is then used to check the signature. It is standardized RFC [RFC 8032] and is based on the Schnorr's signature scheme and uses (possibly twisted) Edwards curves. For X448 we use 57 byte values for both the private key and the public key, and 114 bytes for the signature. Overall, SHAKE256 is used as the hashing method for the signature.
EdDSA (Ed448) using Bouncy Castle and C# |
Theory
With Ed448 we use a private key to sign data, and then the public key can prove it. We use Curve 448 (the Goldilocks curve) for the generation of the public key and for the signing process. X448 is based on Curve 448, and is used for key exchange with ECDH (Elliptic Curve Diffie Hellman) as X448 and Ed448 for a digital signature. It supports a 224-bit security level, and where we use a 448-bit (56-byte) prime number of \(P = 2^{448} - 2^{224} - 1\). It has improved security over Curve 25519, and which has a 255-bit prime number (\(P = 2^{255} - 19\)). As with X25519, in X448 we use a Montgomery curve (\(v^2 = u^3 + A \times u^2 + u\)) with scalar multiplication. In X448, we use 56-byte string values, rather than 32-byte values for X25519. Overall, X448 uses a little-endian method to store an array of bytes, and has a value of \(A = 39,081\) [article]. The curve we use is:\(y^2 + x^2 ≡ 1 - 39081.x^2.y^2 \pmod {2^{448} - 2^{224} - 1} \)
This gives 112 bit security. Also, Ed448 uses the SHAKE256 hashing method, rather than SHA512 as used with Ed25519.
Code
First we create a folder named "bc_ed448", and then go into that folder.We can create a Dotnet console project for .NET 8.0 with:
dotnet new console --framework net8.0
Next we can install the Bouncy Castle library with:
dotnet add package BouncyCastle.Crypto.dll --version 1.8.1
Next some code:
namespace EdDSA { using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.OpenSsl; class Program { static void Main(string[] args) { var msg="Hello"; if (args.Length >0) msg=args[0]; try { Org.BouncyCastle.Crypto.Parameters.Ed448KeyGenerationParameters keygenParams = new Org.BouncyCastle.Crypto.Parameters.Ed448KeyGenerationParameters (new SecureRandom()); Org.BouncyCastle.Crypto.Generators.Ed448KeyPairGenerator generator = new Org.BouncyCastle.Crypto.Generators.Ed448KeyPairGenerator(); generator.Init(keygenParams); var keyPair = generator.GenerateKeyPair(); // Create signature var signer = SignerUtilities.GetSigner("Ed448"); var privateKey = (Ed448PrivateKeyParameters) keyPair.Private; var publicKey = (Ed448PublicKeyParameters) keyPair.Public; signer.Init(true, privateKey); signer.BlockUpdate(System.Text.Encoding.ASCII.GetBytes(msg), 0, msg.Length); // Verify signature var signer2 = SignerUtilities.GetSigner("Ed448"); signer2.Init(false, publicKey); signer2.BlockUpdate(System.Text.Encoding.ASCII.GetBytes(msg), 0, msg.Length); var rtn=signer2.VerifySignature(signer.GenerateSignature()); Console.WriteLine("Ed448"); Console.WriteLine("== Message: {0} ",msg); Console.WriteLine("\n== Signature === "); Console.WriteLine("== Signature: {0} [{1}] ",Convert.ToHexString(signer.GenerateSignature()),Convert.ToBase64String(signer.GenerateSignature())); Console.WriteLine("== Verified: {0} ",rtn); Console.WriteLine("\n== Private key === "); Console.WriteLine("== Private key ==={0} ",Convert.ToHexString(privateKey.GetEncoded())); Console.WriteLine("\n== Public key === "); Console.WriteLine("== Public key ==={0} ",Convert.ToHexString(publicKey.GetEncoded())); StringWriter stringWriter = new StringWriter (); PemWriter pemWriter = new PemWriter (stringWriter); pemWriter.WriteObject(keyPair.Private); pemWriter.Writer.Flush(); pemWriter.Writer.Close(); Console.WriteLine("{0}",stringWriter.ToString()); StringWriter stringWriter2 = new StringWriter (); pemWriter = new PemWriter (stringWriter2); pemWriter.WriteObject(keyPair.Public); pemWriter.Writer.Flush(); pemWriter.Writer.Close(); Console.WriteLine("{0}",stringWriter2.ToString()); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
A sample run gives:
Ed448 == Message: Hello 123 == Signature === == Signature: 0E4A0839E2D8E5EA79052E6E3306124ECCA18BBD1C8E6C86D19A77ABD4BAE30732E9A1DA854ABFB34F734A7C7D90625D7935F6E993B5A8FB00CFA2C5EFF44402AB3E07414E7C197292814D9C5C7B5EFCC4112DDF4CA0FBB8997CA8D334B05BC10F552934C4601C1E48BC24EBC4EF08771A00 [DkoIOeLY5ep5BS5uMwYSTsyhi70cjmyG0Zp3q9S64wcy6aHahUq/s09zSnx9kGJdeTX26ZO1qPsAz6LF7/REAqs+B0FOfBlykoFNnFx7XvzEES3fTKD7uJl8qNM0sFvBD1UpNMRgHB5IvCTrxO8IdxoA] == Verified: True == Private key === == Private key ===897CD58370948035795213A38514487F47857FB0B9F92A0F4BF98303D9EE2DF9D7B413C3848FD423247DC20CBF8087A1E68910B10243F61491 == Public key === == Public key ===E0D4F763ADACF45B791F7B742A2673DDA70009448BD4159B4ABE9EEB684F49F3441CD790DAB842421D6C599CE70B95FEC17C43081AA8086880 -----BEGIN PRIVATE KEY----- MIGDAgEBMAUGAytlcQQ7BDmJfNWDcJSANXlSE6OFFEh/R4V/sLn5Kg9L+YMD2e4t +de0E8OEj9QjJH3CDL+Ah6HmiRCxAkP2FJGBOgDg1Pdjraz0W3kfe3QqJnPdpwAJ RIvUFZtKvp7raE9J80Qc15DauEJCHWxZnOcLlf7BfEMIGqgIaIA= -----END PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MEMwBQYDK2VxAzoA4NT3Y62s9Ft5H3t0KiZz3acACUSL1BWbSr6e62hPSfNEHNeQ 2rhCQh1sWZznC5X+wXxDCBqoCGiA -----END PUBLIC KEY-----