diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2018-09-14 17:52:34 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2018-09-14 17:52:34 +0700 |
commit | ca42ede9a2580725453c3b97d3c4b1e84cecf3dd (patch) | |
tree | 5b49d2927988be5c0b64d7159b7977d9b7510c26 | |
parent | RFC 7748: Export size constants for scalars, points (diff) | |
download | BouncyCastle.NET-ed25519-ca42ede9a2580725453c3b97d3c4b1e84cecf3dd.tar.xz |
RFC 8032: Implement Ed25519ctx, Ed25519ph, Ed448ph variants
-rw-r--r-- | crypto/src/math/ec/rfc8032/Ed25519.cs | 255 | ||||
-rw-r--r-- | crypto/src/math/ec/rfc8032/Ed448.cs | 232 | ||||
-rw-r--r-- | crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs | 281 | ||||
-rw-r--r-- | crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs | 178 |
4 files changed, 783 insertions, 163 deletions
diff --git a/crypto/src/math/ec/rfc8032/Ed25519.cs b/crypto/src/math/ec/rfc8032/Ed25519.cs index ff4587cb2..adb56ca9b 100644 --- a/crypto/src/math/ec/rfc8032/Ed25519.cs +++ b/crypto/src/math/ec/rfc8032/Ed25519.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; +using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Math.EC.Rfc7748; using Org.BouncyCastle.Math.Raw; @@ -18,11 +19,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 private const int ScalarUints = 8; private const int ScalarBytes = ScalarUints * 4; + public static readonly int PrehashSize = 64; public static readonly int PublicKeySize = PointBytes; public static readonly int SecretKeySize = 32; public static readonly int SignatureSize = PointBytes + ScalarBytes; - //private static readonly byte[] Dom2Prefix = Strings.ToByteArray("SigEd25519 no Ed25519 collisions"); + private static readonly byte[] Dom2Prefix = Strings.ToByteArray("SigEd25519 no Ed25519 collisions"); private static readonly uint[] P = { 0xFFFFFFEDU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x7FFFFFFFU }; private static readonly uint[] L = { 0x5CF5D3EDU, 0x5812631AU, 0xA2F79CD6U, 0x14DEF9DEU, 0x00000000U, 0x00000000U, 0x00000000U, 0x10000000U }; @@ -96,6 +98,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 return ReduceScalar(result); } + private static bool CheckContextVar(byte[] ctx, byte phflag) + { + return ctx == null && phflag == 0x00 + || ctx != null && ctx.Length < 256; + } + private static bool CheckPointVar(byte[] p) { uint[] t = new uint[8]; @@ -111,6 +119,16 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 return !Nat256.Gte(n, L); } + private static IDigest CreateDigest() + { + return new Sha512Digest(); + } + + public static IDigest CreatePrehash() + { + return CreateDigest(); + } + private static uint Decode24(byte[] bs, int off) { uint n = bs[off]; @@ -140,9 +158,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 { byte[] py = Arrays.CopyOfRange(p, pOff, pOff + PointBytes); if (!CheckPointVar(py)) - { return false; - } int x_0 = (py[PointBytes - 1] & 0x80) >> 7; py[PointBytes - 1] &= 0x7F; @@ -158,15 +174,11 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 X25519Field.AddOne(v); if (!X25519Field.SqrtRatioVar(u, v, r.x)) - { return false; - } X25519Field.Normalize(r.x); if (x_0 == 1 && X25519Field.IsZeroVar(r.x)) - { return false; - } if (negate ^ (x_0 != (r.x[0] & 1))) { @@ -182,6 +194,17 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 Decode32(k, kOff, n, 0, ScalarUints); } + private static void Dom2(IDigest d, byte phflag, byte[] ctx) + { + if (ctx != null) + { + d.BlockUpdate(Dom2Prefix, 0, Dom2Prefix.Length); + d.Update(phflag); + d.Update((byte)ctx.Length); + d.BlockUpdate(ctx, 0, ctx.Length); + } + } + private static void Encode24(uint n, byte[] bs, int off) { bs[off] = (byte)(n); @@ -220,7 +243,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 public static void GeneratePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff) { - Sha512Digest d = new Sha512Digest(); + IDigest d = CreateDigest(); byte[] h = new byte[d.GetDigestSize()]; d.BlockUpdate(sk, skOff, SecretKeySize); @@ -286,8 +309,10 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 return ws; } - private static void ImplSign(Sha512Digest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + private static void ImplSign(IDigest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { + Dom2(d, phflag, ctx); d.BlockUpdate(h, ScalarBytes, ScalarBytes); d.BlockUpdate(m, mOff, mLen); d.DoFinal(h, 0); @@ -296,6 +321,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 byte[] R = new byte[PointBytes]; ScalarMultBaseEncoded(r, R, 0); + Dom2(d, phflag, ctx); d.BlockUpdate(R, 0, PointBytes); d.BlockUpdate(pk, 0, PointBytes); d.BlockUpdate(m, mOff, mLen); @@ -308,6 +334,90 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 Array.Copy(S, 0, sig, sigOff + PointBytes, ScalarBytes); } + private static void ImplSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, + byte[] sig, int sigOff) + { + if (!CheckContextVar(ctx, phflag)) + throw new ArgumentException("ctx"); + + IDigest d = CreateDigest(); + byte[] h = new byte[d.GetDigestSize()]; + + d.BlockUpdate(sk, skOff, SecretKeySize); + d.DoFinal(h, 0); + + byte[] s = new byte[ScalarBytes]; + PruneScalar(h, 0, s); + + byte[] pk = new byte[PointBytes]; + ScalarMultBaseEncoded(s, pk, 0); + + ImplSign(d, h, s, pk, 0, ctx, phflag, m, mOff, mLen, sig, sigOff); + } + + private static void ImplSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + if (!CheckContextVar(ctx, phflag)) + throw new ArgumentException("ctx"); + + IDigest d = CreateDigest(); + byte[] h = new byte[d.GetDigestSize()]; + + d.BlockUpdate(sk, skOff, SecretKeySize); + d.DoFinal(h, 0); + + byte[] s = new byte[ScalarBytes]; + PruneScalar(h, 0, s); + + ImplSign(d, h, s, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } + + private static bool ImplVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen) + { + if (!CheckContextVar(ctx, phflag)) + throw new ArgumentException("ctx"); + + byte[] R = Arrays.CopyOfRange(sig, sigOff, sigOff + PointBytes); + byte[] S = Arrays.CopyOfRange(sig, sigOff + PointBytes, sigOff + SignatureSize); + + if (!CheckPointVar(R)) + return false; + + if (!CheckScalarVar(S)) + return false; + + PointExt pA = new PointExt(); + if (!DecodePointVar(pk, pkOff, true, pA)) + return false; + + IDigest d = CreateDigest(); + byte[] h = new byte[d.GetDigestSize()]; + + Dom2(d, phflag, ctx); + d.BlockUpdate(R, 0, PointBytes); + d.BlockUpdate(pk, pkOff, PointBytes); + d.BlockUpdate(m, mOff, mLen); + d.DoFinal(h, 0); + + byte[] k = ReduceScalar(h); + + uint[] nS = new uint[ScalarUints]; + DecodeScalar(S, 0, nS); + + uint[] nA = new uint[ScalarUints]; + DecodeScalar(k, 0, nA); + + PointAccum pR = new PointAccum(); + ScalarMultStraussVar(nS, nA, pA, pR); + + byte[] check = new byte[PointBytes]; + EncodePoint(pR, check, 0); + + return Arrays.AreEqual(check, R); + } + private static void PointAddVar(bool negate, PointExt p, PointAccum r) { int[] A = X25519Field.Create(); @@ -518,9 +628,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 public static void Precompute() { if (precompBase != null) - { return; - } // Precomputed table for the base point in verification ladder { @@ -795,9 +903,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 } if ((cOff -= PrecompTeeth) < 0) - { break; - } PointDouble(r); } @@ -850,9 +956,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 } if (--bit < 0) - { break; - } PointDouble(r); } @@ -860,78 +964,101 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 public static void Sign(byte[] sk, int skOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { - Sha512Digest d = new Sha512Digest(); - byte[] h = new byte[d.GetDigestSize()]; + byte[] ctx = null; + byte phflag = 0x00; - d.BlockUpdate(sk, skOff, SecretKeySize); - d.DoFinal(h, 0); + ImplSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } - byte[] s = new byte[ScalarBytes]; - PruneScalar(h, 0, s); + public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + byte[] ctx = null; + byte phflag = 0x00; - byte[] pk = new byte[PointBytes]; - ScalarMultBaseEncoded(s, pk, 0); + ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } - ImplSign(d, h, s, pk, 0, m, mOff, mLen, sig, sigOff); + public static void Sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + byte phflag = 0x00; + + ImplSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff); } - public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { - Sha512Digest d = new Sha512Digest(); - byte[] h = new byte[d.GetDigestSize()]; + byte phflag = 0x00; - d.BlockUpdate(sk, skOff, SecretKeySize); - d.DoFinal(h, 0); + ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } - byte[] s = new byte[ScalarBytes]; - PruneScalar(h, 0, s); + public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff) + { + byte phflag = 0x01; - ImplSign(d, h, s, pk, pkOff, m, mOff, mLen, sig, sigOff); + ImplSign(sk, skOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff); } - public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen) + public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff) { - byte[] R = Arrays.CopyOfRange(sig, sigOff, sigOff + PointBytes); - byte[] S = Arrays.CopyOfRange(sig, sigOff + PointBytes, sigOff + SignatureSize); + byte phflag = 0x01; - if (!CheckPointVar(R)) - { - return false; - } - if (!CheckScalarVar(S)) - { - return false; - } + ImplSign(sk, skOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff); + } - PointExt pA = new PointExt(); - if (!DecodePointVar(pk, pkOff, true, pA)) - { - return false; - } + public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, IDigest ph, byte[] sig, int sigOff) + { + byte[] m = new byte[PrehashSize]; + if (PrehashSize != ph.DoFinal(m, 0)) + throw new ArgumentException("ph"); - Sha512Digest d = new Sha512Digest(); - byte[] h = new byte[d.GetDigestSize()]; + byte phflag = 0x01; - d.BlockUpdate(R, 0, PointBytes); - d.BlockUpdate(pk, pkOff, PointBytes); - d.BlockUpdate(m, mOff, mLen); - d.DoFinal(h, 0); + ImplSign(sk, skOff, ctx, phflag, m, 0, m.Length, sig, sigOff); + } - byte[] k = ReduceScalar(h); + public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, IDigest ph, byte[] sig, int sigOff) + { + byte[] m = new byte[PrehashSize]; + if (PrehashSize != ph.DoFinal(m, 0)) + throw new ArgumentException("ph"); - uint[] nS = new uint[ScalarUints]; - DecodeScalar(S, 0, nS); + byte phflag = 0x01; - uint[] nA = new uint[ScalarUints]; - DecodeScalar(k, 0, nA); + ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, 0, m.Length, sig, sigOff); + } - PointAccum pR = new PointAccum(); - ScalarMultStraussVar(nS, nA, pA, pR); + public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen) + { + byte[] ctx = null; + byte phflag = 0x00; - byte[] check = new byte[PointBytes]; - EncodePoint(pR, check, 0); + return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen); + } - return Arrays.AreEqual(check, R); + public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen) + { + byte phflag = 0x00; + + return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen); + } + + public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff) + { + byte phflag = 0x01; + + return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize); + } + + public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, IDigest ph) + { + byte[] m = new byte[PrehashSize]; + if (PrehashSize != ph.DoFinal(m, 0)) + throw new ArgumentException("ph"); + + byte phflag = 0x01; + + return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, 0, m.Length); } } } diff --git a/crypto/src/math/ec/rfc8032/Ed448.cs b/crypto/src/math/ec/rfc8032/Ed448.cs index 52c215160..0e56b12a8 100644 --- a/crypto/src/math/ec/rfc8032/Ed448.cs +++ b/crypto/src/math/ec/rfc8032/Ed448.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; +using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Math.EC.Rfc7748; using Org.BouncyCastle.Math.Raw; @@ -18,6 +19,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 private const int ScalarUints = 14; private const int ScalarBytes = ScalarUints * 4 + 1; + public static readonly int PrehashSize = 64; public static readonly int PublicKeySize = PointBytes; public static readonly int SecretKeySize = 57; public static readonly int SignatureSize = PointBytes + ScalarBytes; @@ -103,9 +105,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 private static bool CheckPointVar(byte[] p) { if ((p[PointBytes - 1] & 0x7F) != 0x00) - { return false; - } uint[] t = new uint[14]; Decode32(p, 0, t, 0, 14); @@ -115,15 +115,23 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 private static bool CheckScalarVar(byte[] s) { if (s[ScalarBytes - 1] != 0x00) - { return false; - } uint[] n = new uint[ScalarUints]; DecodeScalar(s, 0, n); return !Nat.Gte(ScalarUints, n, L); } + public static IXof CreatePrehash() + { + return CreateXof(); + } + + private static IXof CreateXof() + { + return new ShakeDigest(256); + } + private static uint Decode16(byte[] bs, int off) { uint n = bs[off]; @@ -160,9 +168,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 { byte[] py = Arrays.CopyOfRange(p, pOff, pOff + PointBytes); if (!CheckPointVar(py)) - { return false; - } int x_0 = (py[PointBytes - 1] & 0x80) >> 7; py[PointBytes - 1] &= 0x7F; @@ -179,15 +185,11 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 X448Field.AddOne(v); if (!X448Field.SqrtRatioVar(u, v, r.x)) - { return false; - } X448Field.Normalize(r.x); if (x_0 == 1 && X448Field.IsZeroVar(r.x)) - { return false; - } if (negate ^ (x_0 != (r.x[0] & 1))) { @@ -205,7 +207,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 Decode32(k, kOff, n, 0, ScalarUints); } - private static void Dom4(ShakeDigest d, byte x, byte[] y) + private static void Dom4(IXof d, byte x, byte[] y) { d.BlockUpdate(Dom4Prefix, 0, Dom4Prefix.Length); d.Update(x); @@ -251,7 +253,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 public static void GeneratePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff) { - ShakeDigest d = new ShakeDigest(256); + IXof d = CreateXof(); byte[] h = new byte[ScalarBytes * 2]; d.BlockUpdate(sk, skOff, SecretKeySize); @@ -317,10 +319,9 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 return ws; } - private static void ImplSign(ShakeDigest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + private static void ImplSign(IXof d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { - byte phflag = 0x00; - Dom4(d, phflag, ctx); d.BlockUpdate(h, ScalarBytes, ScalarBytes); d.BlockUpdate(m, mOff, mLen); @@ -343,6 +344,90 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 Array.Copy(S, 0, sig, sigOff + PointBytes, ScalarBytes); } + private static void ImplSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, + byte[] sig, int sigOff) + { + if (!CheckContextVar(ctx)) + throw new ArgumentException("ctx"); + + IXof d = CreateXof(); + byte[] h = new byte[ScalarBytes * 2]; + + d.BlockUpdate(sk, skOff, SecretKeySize); + d.DoFinal(h, 0, h.Length); + + byte[] s = new byte[ScalarBytes]; + PruneScalar(h, 0, s); + + byte[] pk = new byte[PointBytes]; + ScalarMultBaseEncoded(s, pk, 0); + + ImplSign(d, h, s, pk, 0, ctx, phflag, m, mOff, mLen, sig, sigOff); + } + + private static void ImplSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + if (!CheckContextVar(ctx)) + throw new ArgumentException("ctx"); + + IXof d = CreateXof(); + byte[] h = new byte[ScalarBytes * 2]; + + d.BlockUpdate(sk, skOff, SecretKeySize); + d.DoFinal(h, 0, h.Length); + + byte[] s = new byte[ScalarBytes]; + PruneScalar(h, 0, s); + + ImplSign(d, h, s, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } + + private static bool ImplVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen) + { + if (!CheckContextVar(ctx)) + throw new ArgumentException("ctx"); + + byte[] R = Arrays.CopyOfRange(sig, sigOff, sigOff + PointBytes); + byte[] S = Arrays.CopyOfRange(sig, sigOff + PointBytes, sigOff + SignatureSize); + + if (!CheckPointVar(R)) + return false; + + if (!CheckScalarVar(S)) + return false; + + PointExt pA = new PointExt(); + if (!DecodePointVar(pk, pkOff, true, pA)) + return false; + + IXof d = CreateXof(); + byte[] h = new byte[ScalarBytes * 2]; + + Dom4(d, phflag, ctx); + d.BlockUpdate(R, 0, PointBytes); + d.BlockUpdate(pk, pkOff, PointBytes); + d.BlockUpdate(m, mOff, mLen); + d.DoFinal(h, 0, h.Length); + + byte[] k = ReduceScalar(h); + + uint[] nS = new uint[ScalarUints]; + DecodeScalar(S, 0, nS); + + uint[] nA = new uint[ScalarUints]; + DecodeScalar(k, 0, nA); + + PointExt pR = new PointExt(); + ScalarMultStraussVar(nS, nA, pA, pR); + + byte[] check = new byte[PointBytes]; + EncodePoint(pR, check, 0); + + return Arrays.AreEqual(check, R); + } + private static void PointAddVar(bool negate, PointExt p, PointExt r) { uint[] A = X448Field.Create(); @@ -505,9 +590,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 public static void Precompute() { if (precompBase != null) - { return; - } PointExt p = new PointExt(); X448Field.Copy(B_x, 0, p.x, 0); @@ -907,9 +990,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 } if (--cOff < 0) - { break; - } PointDouble(r); } @@ -962,9 +1043,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 } if (--bit < 0) - { break; - } PointDouble(r); } @@ -972,96 +1051,77 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 public static void Sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { - if (!CheckContextVar(ctx)) - { - throw new ArgumentException("ctx"); - } + byte phflag = 0x00; - ShakeDigest d = new ShakeDigest(256); - byte[] h = new byte[ScalarBytes * 2]; + ImplSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } - d.BlockUpdate(sk, skOff, SecretKeySize); - d.DoFinal(h, 0, h.Length); + public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + byte phflag = 0x00; - byte[] s = new byte[ScalarBytes]; - PruneScalar(h, 0, s); + ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } - byte[] pk = new byte[PointBytes]; - ScalarMultBaseEncoded(s, pk, 0); + public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff) + { + byte phflag = 0x01; - ImplSign(d, h, s, pk, 0, ctx, m, mOff, mLen, sig, sigOff); + ImplSign(sk, skOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff); } - public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff) { - if (!CheckContextVar(ctx)) - { - throw new ArgumentException("ctx"); - } + byte phflag = 0x01; - ShakeDigest d = new ShakeDigest(256); - byte[] h = new byte[ScalarBytes * 2]; + ImplSign(sk, skOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff); + } - d.BlockUpdate(sk, skOff, SecretKeySize); - d.DoFinal(h, 0, h.Length); + public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, IXof ph, byte[] sig, int sigOff) + { + byte[] m = new byte[PrehashSize]; + if (PrehashSize != ph.DoFinal(m, 0, PrehashSize)) + throw new ArgumentException("ph"); - byte[] s = new byte[ScalarBytes]; - PruneScalar(h, 0, s); + byte phflag = 0x01; - ImplSign(d, h, s, pk, pkOff, ctx, m, mOff, mLen, sig, sigOff); + ImplSign(sk, skOff, ctx, phflag, m, 0, m.Length, sig, sigOff); } - public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen) + public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, IXof ph, byte[] sig, int sigOff) { - if (!CheckContextVar(ctx)) - { - throw new ArgumentException("ctx"); - } - - byte[] R = Arrays.CopyOfRange(sig, sigOff, sigOff + PointBytes); - byte[] S = Arrays.CopyOfRange(sig, sigOff + PointBytes, sigOff + SignatureSize); + byte[] m = new byte[PrehashSize]; + if (PrehashSize != ph.DoFinal(m, 0, PrehashSize)) + throw new ArgumentException("ph"); - if (!CheckPointVar(R)) - { - return false; - } - if (!CheckScalarVar(S)) - { - return false; - } + byte phflag = 0x01; - PointExt pA = new PointExt(); - if (!DecodePointVar(pk, pkOff, true, pA)) - { - return false; - } + ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, 0, m.Length, sig, sigOff); + } + public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen) + { byte phflag = 0x00; - ShakeDigest d = new ShakeDigest(256); - byte[] h = new byte[ScalarBytes * 2]; - - Dom4(d, phflag, ctx); - d.BlockUpdate(R, 0, PointBytes); - d.BlockUpdate(pk, pkOff, PointBytes); - d.BlockUpdate(m, mOff, mLen); - d.DoFinal(h, 0, h.Length); - - byte[] k = ReduceScalar(h); + return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen); + } - uint[] nS = new uint[ScalarUints]; - DecodeScalar(S, 0, nS); + public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff) + { + byte phflag = 0x01; - uint[] nA = new uint[ScalarUints]; - DecodeScalar(k, 0, nA); + return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize); + } - PointExt pR = new PointExt(); - ScalarMultStraussVar(nS, nA, pA, pR); + public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, IXof ph) + { + byte[] m = new byte[PrehashSize]; + if (PrehashSize != ph.DoFinal(m, 0, PrehashSize)) + throw new ArgumentException("ph"); - byte[] check = new byte[PointBytes]; - EncodePoint(pR, check, 0); + byte phflag = 0x01; - return Arrays.AreEqual(check, R); + return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, 0, m.Length); } } } diff --git a/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs b/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs index 43ea23988..5a42daeae 100644 --- a/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs +++ b/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs @@ -2,6 +2,7 @@ using NUnit.Framework; +using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Encoders; @@ -40,16 +41,93 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests Ed25519.Sign(sk, 0, m, 0, mLen, sig1, 0); Ed25519.Sign(sk, 0, pk, 0, m, 0, mLen, sig2, 0); - Assert.IsTrue(Arrays.AreEqual(sig1, sig2), "Consistent signatures #" + i); + Assert.IsTrue(Arrays.AreEqual(sig1, sig2), "Ed25519 consistent signatures #" + i); bool shouldVerify = Ed25519.Verify(sig1, 0, pk, 0, m, 0, mLen); - Assert.IsTrue(shouldVerify, "Consistent sign/verify #" + i); + Assert.IsTrue(shouldVerify, "Ed25519 consistent sign/verify #" + i); sig1[Ed25519.PublicKeySize - 1] ^= 0x80; bool shouldNotVerify = Ed25519.Verify(sig1, 0, pk, 0, m, 0, mLen); - Assert.IsFalse(shouldNotVerify, "Consistent verification failure #" + i); + Assert.IsFalse(shouldNotVerify, "Ed25519 consistent verification failure #" + i); + } + } + + [Test] + public void TestEd25519ctxConsistency() + { + byte[] sk = new byte[Ed25519.SecretKeySize]; + byte[] pk = new byte[Ed25519.PublicKeySize]; + byte[] ctx = new byte[Random.Next() & 7]; + byte[] m = new byte[255]; + byte[] sig1 = new byte[Ed25519.SignatureSize]; + byte[] sig2 = new byte[Ed25519.SignatureSize]; + + Random.NextBytes(ctx); + Random.NextBytes(m); + + for (int i = 0; i < 10; ++i) + { + Random.NextBytes(sk); + Ed25519.GeneratePublicKey(sk, 0, pk, 0); + + int mLen = Random.Next() & 255; + + Ed25519.Sign(sk, 0, ctx, m, 0, mLen, sig1, 0); + Ed25519.Sign(sk, 0, pk, 0, ctx, m, 0, mLen, sig2, 0); + + Assert.IsTrue(Arrays.AreEqual(sig1, sig2), "Ed25519ctx consistent signatures #" + i); + + bool shouldVerify = Ed25519.Verify(sig1, 0, pk, 0, ctx, m, 0, mLen); + + Assert.IsTrue(shouldVerify, "Ed25519ctx consistent sign/verify #" + i); + + sig1[Ed25519.PublicKeySize - 1] ^= 0x80; + bool shouldNotVerify = Ed25519.Verify(sig1, 0, pk, 0, ctx, m, 0, mLen); + + Assert.IsFalse(shouldNotVerify, "Ed25519ctx consistent verification failure #" + i); + } + } + + [Test] + public void TestEd25519phConsistency() + { + byte[] sk = new byte[Ed25519.SecretKeySize]; + byte[] pk = new byte[Ed25519.PublicKeySize]; + byte[] ctx = new byte[Random.Next() & 7]; + byte[] m = new byte[255]; + byte[] ph = new byte[Ed25519.PrehashSize]; + byte[] sig1 = new byte[Ed25519.SignatureSize]; + byte[] sig2 = new byte[Ed25519.SignatureSize]; + + Random.NextBytes(ctx); + Random.NextBytes(m); + + for (int i = 0; i < 10; ++i) + { + Random.NextBytes(sk); + Ed25519.GeneratePublicKey(sk, 0, pk, 0); + + int mLen = Random.Next() & 255; + + IDigest prehash = Ed25519.CreatePrehash(); + prehash.BlockUpdate(m, 0, mLen); + prehash.DoFinal(ph, 0); + + Ed25519.SignPrehash(sk, 0, ctx, ph, 0, sig1, 0); + Ed25519.SignPrehash(sk, 0, pk, 0, ctx, ph, 0, sig2, 0); + + Assert.IsTrue(Arrays.AreEqual(sig1, sig2), "Ed25519ph consistent signatures #" + i); + + bool shouldVerify = Ed25519.VerifyPrehash(sig1, 0, pk, 0, ctx, ph, 0); + + Assert.IsTrue(shouldVerify, "Ed25519ph consistent sign/verify #" + i); + + sig1[Ed25519.PublicKeySize - 1] ^= 0x80; + bool shouldNotVerify = Ed25519.VerifyPrehash(sig1, 0, pk, 0, ctx, ph, 0); + + Assert.IsFalse(shouldNotVerify, "Ed25519ph consistent verification failure #" + i); } } @@ -201,18 +279,107 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests + "3dca179c138ac17ad9bef1177331a704"), "Ed25519 Vector SHA(abc)"); } - + + [Test] + public void TestEd25519ctxVector1() + { + CheckEd25519ctxVector( + ("0305334e381af78f141cb666f6199f57" + + "bc3495335a256a95bd2a55bf546663f6"), + ("dfc9425e4f968f7f0c29f0259cf5f9ae" + + "d6851c2bb4ad8bfb860cfee0ab248292"), + "f726936d19c800494e3fdaff20b276a8", + "666f6f", + ("55a4cc2f70a54e04288c5f4cd1e45a7b" + + "b520b36292911876cada7323198dd87a" + + "8b36950b95130022907a7fb7c4e9b2d5" + + "f6cca685a587b4b21f4b888e4e7edb0d"), + "Ed25519ctx Vector #1"); + } + + [Test] + public void TestEd25519ctxVector2() + { + CheckEd25519ctxVector( + ("0305334e381af78f141cb666f6199f57" + + "bc3495335a256a95bd2a55bf546663f6"), + ("dfc9425e4f968f7f0c29f0259cf5f9ae" + + "d6851c2bb4ad8bfb860cfee0ab248292"), + "f726936d19c800494e3fdaff20b276a8", + "626172", + ("fc60d5872fc46b3aa69f8b5b4351d580" + + "8f92bcc044606db097abab6dbcb1aee3" + + "216c48e8b3b66431b5b186d1d28f8ee1" + + "5a5ca2df6668346291c2043d4eb3e90d"), + "Ed25519ctx Vector #2"); + } + + [Test] + public void TestEd25519ctxVector3() + { + CheckEd25519ctxVector( + ("0305334e381af78f141cb666f6199f57" + + "bc3495335a256a95bd2a55bf546663f6"), + ("dfc9425e4f968f7f0c29f0259cf5f9ae" + + "d6851c2bb4ad8bfb860cfee0ab248292"), + "508e9e6882b979fea900f62adceaca35", + "666f6f", + ("8b70c1cc8310e1de20ac53ce28ae6e72" + + "07f33c3295e03bb5c0732a1d20dc6490" + + "8922a8b052cf99b7c4fe107a5abb5b2c" + + "4085ae75890d02df26269d8945f84b0b"), + "Ed25519ctx Vector #3"); + } + + [Test] + public void TestEd25519ctxVector4() + { + CheckEd25519ctxVector( + ("ab9c2853ce297ddab85c993b3ae14bca" + + "d39b2c682beabc27d6d4eb20711d6560"), + ("0f1d1274943b91415889152e893d80e9" + + "3275a1fc0b65fd71b4b0dda10ad7d772"), + "f726936d19c800494e3fdaff20b276a8", + "666f6f", + ("21655b5f1aa965996b3f97b3c849eafb" + + "a922a0a62992f73b3d1b73106a84ad85" + + "e9b86a7b6005ea868337ff2d20a7f5fb" + + "d4cd10b0be49a68da2b2e0dc0ad8960f"), + "Ed25519ctx Vector #4"); + } + + [Test] + public void TestEd25519phVector1() + { + CheckEd25519phVector( + ("833fe62409237b9d62ec77587520911e" + + "9a759cec1d19755b7da901b96dca3d42"), + ("ec172b93ad5e563bf4932c70e1245034" + + "c35467ef2efd4d64ebf819683467e2bf"), + "616263", + "", + ("98a70222f0b8121aa9d30f813d683f80" + + "9e462b469c7ff87639499bb94e6dae41" + + "31f85042463c2a355a2003d062adf5aa" + + "a10b8c61e636062aaad11c2a26083406"), + "Ed25519ph Vector #1"); + } + private static void CheckEd25519Vector(string sSK, string sPK, string sM, string sSig, string text) { byte[] sk = Hex.Decode(sSK); - byte[] pk = Hex.Decode(sPK); + byte[] pkGen = new byte[Ed25519.PublicKeySize]; Ed25519.GeneratePublicKey(sk, 0, pkGen, 0); Assert.IsTrue(Arrays.AreEqual(pk, pkGen), text); byte[] m = Hex.Decode(sM); byte[] sig = Hex.Decode(sSig); + + byte[] badsig = Arrays.Clone(sig); + badsig[Ed25519.SignatureSize - 1] ^= 0x80; + byte[] sigGen = new byte[Ed25519.SignatureSize]; Ed25519.Sign(sk, 0, m, 0, m.Length, sigGen, 0); Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); @@ -223,9 +390,109 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests bool shouldVerify = Ed25519.Verify(sig, 0, pk, 0, m, 0, m.Length); Assert.IsTrue(shouldVerify, text); - sig[Ed25519.SignatureSize - 1] ^= 0x80; - bool shouldNotVerify = Ed25519.Verify(sig, 0, pk, 0, m, 0, m.Length); + bool shouldNotVerify = Ed25519.Verify(badsig, 0, pk, 0, m, 0, m.Length); + Assert.IsFalse(shouldNotVerify, text); + } + + private static void CheckEd25519ctxVector(string sSK, string sPK, string sM, string sCTX, string sSig, string text) + { + byte[] sk = Hex.Decode(sSK); + byte[] pk = Hex.Decode(sPK); + + byte[] pkGen = new byte[Ed25519.PublicKeySize]; + Ed25519.GeneratePublicKey(sk, 0, pkGen, 0); + Assert.IsTrue(Arrays.AreEqual(pk, pkGen), text); + + byte[] m = Hex.Decode(sM); + byte[] ctx = Hex.Decode(sCTX); + byte[] sig = Hex.Decode(sSig); + + byte[] badsig = Arrays.Clone(sig); + badsig[Ed25519.SignatureSize - 1] ^= 0x80; + + byte[] sigGen = new byte[Ed25519.SignatureSize]; + Ed25519.Sign(sk, 0, ctx, m, 0, m.Length, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + + Ed25519.Sign(sk, 0, pk, 0, ctx, m, 0, m.Length, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + + bool shouldVerify = Ed25519.Verify(sig, 0, pk, 0, ctx, m, 0, m.Length); + Assert.IsTrue(shouldVerify, text); + + bool shouldNotVerify = Ed25519.Verify(badsig, 0, pk, 0, ctx, m, 0, m.Length); Assert.IsFalse(shouldNotVerify, text); } + + private static void CheckEd25519phVector(string sSK, string sPK, string sM, string sCTX, string sSig, string text) + { + byte[] sk = Hex.Decode(sSK); + byte[] pk = Hex.Decode(sPK); + + byte[] pkGen = new byte[Ed25519.PublicKeySize]; + Ed25519.GeneratePublicKey(sk, 0, pkGen, 0); + Assert.IsTrue(Arrays.AreEqual(pk, pkGen), text); + + byte[] m = Hex.Decode(sM); + byte[] ctx = Hex.Decode(sCTX); + byte[] sig = Hex.Decode(sSig); + + byte[] badsig = Arrays.Clone(sig); + badsig[Ed25519.SignatureSize - 1] ^= 0x80; + + byte[] sigGen = new byte[Ed25519.SignatureSize]; + + { + IDigest prehash = Ed25519.CreatePrehash(); + prehash.BlockUpdate(m, 0, m.Length); + + byte[] ph = new byte[Ed25519.PrehashSize]; + prehash.DoFinal(ph, 0); + + Ed25519.SignPrehash(sk, 0, ctx, ph, 0, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + + Ed25519.SignPrehash(sk, 0, pk, 0, ctx, ph, 0, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + + bool shouldVerify = Ed25519.VerifyPrehash(sig, 0, pk, 0, ctx, ph, 0); + Assert.IsTrue(shouldVerify, text); + + bool shouldNotVerify = Ed25519.VerifyPrehash(badsig, 0, pk, 0, ctx, ph, 0); + Assert.IsFalse(shouldNotVerify, text); + } + + { + IDigest ph = Ed25519.CreatePrehash(); + ph.BlockUpdate(m, 0, m.Length); + + Ed25519.SignPrehash(sk, 0, ctx, ph, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + } + + { + IDigest ph = Ed25519.CreatePrehash(); + ph.BlockUpdate(m, 0, m.Length); + + Ed25519.SignPrehash(sk, 0, pk, 0, ctx, ph, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + } + + { + IDigest ph = Ed25519.CreatePrehash(); + ph.BlockUpdate(m, 0, m.Length); + + bool shouldVerify = Ed25519.VerifyPrehash(sig, 0, pk, 0, ctx, ph); + Assert.IsTrue(shouldVerify, text); + } + + { + IDigest ph = Ed25519.CreatePrehash(); + ph.BlockUpdate(m, 0, m.Length); + + bool shouldNotVerify = Ed25519.VerifyPrehash(badsig, 0, pk, 0, ctx, ph); + Assert.IsFalse(shouldNotVerify, text); + } + } } } diff --git a/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs b/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs index 98c487c09..826f76345 100644 --- a/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs +++ b/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs @@ -2,6 +2,7 @@ using NUnit.Framework; +using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Encoders; @@ -42,16 +43,57 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests Ed448.Sign(sk, 0, ctx, m, 0, mLen, sig1, 0); Ed448.Sign(sk, 0, pk, 0, ctx, m, 0, mLen, sig2, 0); - Assert.IsTrue(Arrays.AreEqual(sig1, sig2), "Consistent signatures #" + i); + Assert.IsTrue(Arrays.AreEqual(sig1, sig2), "Ed448 consistent signatures #" + i); bool shouldVerify = Ed448.Verify(sig1, 0, pk, 0, ctx, m, 0, mLen); - Assert.IsTrue(shouldVerify, "Consistent sign/verify #" + i); + Assert.IsTrue(shouldVerify, "Ed448 consistent sign/verify #" + i); sig1[Ed448.PublicKeySize - 1] ^= 0x80; bool shouldNotVerify = Ed448.Verify(sig1, 0, pk, 0, ctx, m, 0, mLen); - Assert.IsFalse(shouldNotVerify, "Consistent verification failure #" + i); + Assert.IsFalse(shouldNotVerify, "Ed448 consistent verification failure #" + i); + } + } + + [Test] + public void TestEd448phConsistency() + { + byte[] sk = new byte[Ed448.SecretKeySize]; + byte[] pk = new byte[Ed448.PublicKeySize]; + byte[] ctx = new byte[Random.Next() & 7]; + byte[] m = new byte[255]; + byte[] ph = new byte[Ed448.PrehashSize]; + byte[] sig1 = new byte[Ed448.SignatureSize]; + byte[] sig2 = new byte[Ed448.SignatureSize]; + + Random.NextBytes(ctx); + Random.NextBytes(m); + + for (int i = 0; i < 10; ++i) + { + Random.NextBytes(sk); + Ed448.GeneratePublicKey(sk, 0, pk, 0); + + int mLen = Random.Next() & 255; + + IXof prehash = Ed448.CreatePrehash(); + prehash.BlockUpdate(m, 0, mLen); + prehash.DoFinal(ph, 0, ph.Length); + + Ed448.SignPrehash(sk, 0, ctx, ph, 0, sig1, 0); + Ed448.SignPrehash(sk, 0, pk, 0, ctx, ph, 0, sig2, 0); + + Assert.IsTrue(Arrays.AreEqual(sig1, sig2), "Ed448ph consistent signatures #" + i); + + bool shouldVerify = Ed448.VerifyPrehash(sig1, 0, pk, 0, ctx, ph, 0); + + Assert.IsTrue(shouldVerify, "Ed448ph consistent sign/verify #" + i); + + sig1[Ed448.PublicKeySize - 1] ^= 0x80; + bool shouldNotVerify = Ed448.VerifyPrehash(sig1, 0, pk, 0, ctx, ph, 0); + + Assert.IsFalse(shouldNotVerify, "Ed448ph consistent verification failure #" + i); } } @@ -370,11 +412,61 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests "Ed448 Vector #1023"); } + [Test] + public void TestEd448phVector1() + { + CheckEd448phVector( + ("833fe62409237b9d62ec77587520911e" + + "9a759cec1d19755b7da901b96dca3d42" + + "ef7822e0d5104127dc05d6dbefde69e3" + + "ab2cec7c867c6e2c49"), + ("259b71c19f83ef77a7abd26524cbdb31" + + "61b590a48f7d17de3ee0ba9c52beb743" + + "c09428a131d6b1b57303d90d8132c276" + + "d5ed3d5d01c0f53880"), + "616263", + "", + ("822f6901f7480f3d5f562c592994d969" + + "3602875614483256505600bbc281ae38" + + "1f54d6bce2ea911574932f52a4e6cadd" + + "78769375ec3ffd1b801a0d9b3f4030cd" + + "433964b6457ea39476511214f97469b5" + + "7dd32dbc560a9a94d00bff07620464a3" + + "ad203df7dc7ce360c3cd3696d9d9fab9" + + "0f00"), + "Ed448ph Vector #1"); + } + + [Test] + public void TestEd448phVector2() + { + CheckEd448phVector( + ("833fe62409237b9d62ec77587520911e" + + "9a759cec1d19755b7da901b96dca3d42" + + "ef7822e0d5104127dc05d6dbefde69e3" + + "ab2cec7c867c6e2c49"), + ("259b71c19f83ef77a7abd26524cbdb31" + + "61b590a48f7d17de3ee0ba9c52beb743" + + "c09428a131d6b1b57303d90d8132c276" + + "d5ed3d5d01c0f53880"), + "616263", + "666f6f", + ("c32299d46ec8ff02b54540982814dce9" + + "a05812f81962b649d528095916a2aa48" + + "1065b1580423ef927ecf0af5888f90da" + + "0f6a9a85ad5dc3f280d91224ba9911a3" + + "653d00e484e2ce232521481c8658df30" + + "4bb7745a73514cdb9bf3e15784ab7128" + + "4f8d0704a608c54a6b62d97beb511d13" + + "2100"), + "Ed448ph Vector #2"); + } + private static void CheckEd448Vector(string sSK, string sPK, string sM, string sCTX, string sSig, string text) { byte[] sk = Hex.Decode(sSK); - byte[] pk = Hex.Decode(sPK); + byte[] pkGen = new byte[Ed448.PublicKeySize]; Ed448.GeneratePublicKey(sk, 0, pkGen, 0); Assert.IsTrue(Arrays.AreEqual(pk, pkGen), text); @@ -383,6 +475,10 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests byte[] ctx = Hex.Decode(sCTX); byte[] sig = Hex.Decode(sSig); byte[] sigGen = new byte[Ed448.SignatureSize]; + + byte[] badsig = Arrays.Clone(sig); + badsig[Ed448.SignatureSize - 1] ^= 0x80; + Ed448.Sign(sk, 0, ctx, m, 0, m.Length, sigGen, 0); Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); @@ -392,9 +488,79 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests bool shouldVerify = Ed448.Verify(sig, 0, pk, 0, ctx, m, 0, m.Length); Assert.IsTrue(shouldVerify, text); - sig[Ed448.SignatureSize - 1] ^= 0x80; - bool shouldNotVerify = Ed448.Verify(sig, 0, pk, 0, ctx, m, 0, m.Length); + bool shouldNotVerify = Ed448.Verify(badsig, 0, pk, 0, ctx, m, 0, m.Length); Assert.IsFalse(shouldNotVerify, text); } + + private static void CheckEd448phVector(string sSK, string sPK, string sM, string sCTX, string sSig, string text) + { + byte[] sk = Hex.Decode(sSK); + byte[] pk = Hex.Decode(sPK); + + byte[] pkGen = new byte[Ed448.PublicKeySize]; + Ed448.GeneratePublicKey(sk, 0, pkGen, 0); + Assert.IsTrue(Arrays.AreEqual(pk, pkGen), text); + + byte[] m = Hex.Decode(sM); + byte[] ctx = Hex.Decode(sCTX); + byte[] sig = Hex.Decode(sSig); + + byte[] badsig = Arrays.Clone(sig); + badsig[Ed448.SignatureSize - 1] ^= 0x80; + + byte[] sigGen = new byte[Ed448.SignatureSize]; + + { + IXof prehash = Ed448.CreatePrehash(); + prehash.BlockUpdate(m, 0, m.Length); + + byte[] ph = new byte[Ed448.PrehashSize]; + prehash.DoFinal(ph, 0, ph.Length); + + Ed448.SignPrehash(sk, 0, ctx, ph, 0, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + + Ed448.SignPrehash(sk, 0, pk, 0, ctx, ph, 0, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + + bool shouldVerify = Ed448.VerifyPrehash(sig, 0, pk, 0, ctx, ph, 0); + Assert.IsTrue(shouldVerify, text); + + bool shouldNotVerify = Ed448.VerifyPrehash(badsig, 0, pk, 0, ctx, ph, 0); + Assert.IsFalse(shouldNotVerify, text); + } + + { + IXof ph = Ed448.CreatePrehash(); + ph.BlockUpdate(m, 0, m.Length); + + Ed448.SignPrehash(sk, 0, ctx, ph, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + } + + { + IXof ph = Ed448.CreatePrehash(); + ph.BlockUpdate(m, 0, m.Length); + + Ed448.SignPrehash(sk, 0, pk, 0, ctx, ph, sigGen, 0); + Assert.IsTrue(Arrays.AreEqual(sig, sigGen), text); + } + + { + IXof ph = Ed448.CreatePrehash(); + ph.BlockUpdate(m, 0, m.Length); + + bool shouldVerify = Ed448.VerifyPrehash(sig, 0, pk, 0, ctx, ph); + Assert.IsTrue(shouldVerify, text); + } + + { + IXof ph = Ed448.CreatePrehash(); + ph.BlockUpdate(m, 0, m.Length); + + bool shouldNotVerify = Ed448.VerifyPrehash(badsig, 0, pk, 0, ctx, ph); + Assert.IsFalse(shouldNotVerify, text); + } + } } } |