diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2021-02-10 16:53:47 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2021-02-10 16:53:47 +0700 |
commit | 332484150c8bcc94dad95b5948d20835d948e831 (patch) | |
tree | 08c6c76ebdc3855524afc71c082558763b89b614 | |
parent | Refactor nonce generator init (diff) | |
download | BouncyCastle.NET-ed25519-332484150c8bcc94dad95b5948d20835d948e831.tar.xz |
EdDSA public key validation
- per NIST SP 800-186
-rw-r--r-- | crypto/src/math/ec/rfc7748/X25519Field.cs | 34 | ||||
-rw-r--r-- | crypto/src/math/ec/rfc7748/X448Field.cs | 34 | ||||
-rw-r--r-- | crypto/src/math/ec/rfc8032/Ed25519.cs | 81 | ||||
-rw-r--r-- | crypto/src/math/ec/rfc8032/Ed448.cs | 74 | ||||
-rw-r--r-- | crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs | 92 | ||||
-rw-r--r-- | crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs | 92 |
6 files changed, 399 insertions, 8 deletions
diff --git a/crypto/src/math/ec/rfc7748/X25519Field.cs b/crypto/src/math/ec/rfc7748/X25519Field.cs index ffede563b..d0b835226 100644 --- a/crypto/src/math/ec/rfc7748/X25519Field.cs +++ b/crypto/src/math/ec/rfc7748/X25519Field.cs @@ -48,6 +48,23 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748 } } + public static int AreEqual(int[] x, int[] y) + { + int d = 0; + for (int i = 0; i < Size; ++i) + { + d |= x[i] ^ y[i]; + } + d |= d >> 16; + d &= 0xFFFF; + return (d - 1) >> 31; + } + + public static bool AreEqualVar(int[] x, int[] y) + { + return 0 != AreEqual(x, y); + } + public static void Carry(int[] z) { int z0 = z[0], z1 = z[1], z2 = z[2], z3 = z[3], z4 = z[4]; @@ -258,6 +275,23 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748 Decode(u, 0, z); } + public static int IsOne(int[] x) + { + int d = x[0] ^ 1; + for (int i = 1; i < Size; ++i) + { + d |= x[i]; + } + d |= d >> 16; + d &= 0xFFFF; + return (d - 1) >> 31; + } + + public static bool IsOneVar(int[] x) + { + return 0 != IsOne(x); + } + public static int IsZero(int[] x) { int d = 0; diff --git a/crypto/src/math/ec/rfc7748/X448Field.cs b/crypto/src/math/ec/rfc7748/X448Field.cs index ef4fd4627..6d8c60e78 100644 --- a/crypto/src/math/ec/rfc7748/X448Field.cs +++ b/crypto/src/math/ec/rfc7748/X448Field.cs @@ -46,6 +46,23 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748 // } //} + public static int AreEqual(uint[] x, uint[] y) + { + uint d = 0; + for (int i = 0; i < Size; ++i) + { + d |= x[i] ^ y[i]; + } + d |= d >> 16; + d &= 0xFFFF; + return ((int)d - 1) >> 31; + } + + public static bool AreEqualVar(uint[] x, uint[] y) + { + return 0 != AreEqual(x, y); + } + public static void Carry(uint[] z) { uint z0 = z[0], z1 = z[1], z2 = z[2], z3 = z[3], z4 = z[4], z5 = z[5], z6 = z[6], z7 = z[7]; @@ -285,6 +302,23 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748 Decode(u, 0, z); } + public static int IsOne(uint[] x) + { + uint d = x[0] ^ 1; + for (int i = 1; i < Size; ++i) + { + d |= x[i]; + } + d |= d >> 16; + d &= 0xFFFF; + return ((int)d - 1) >> 31; + } + + public static bool IsOneVar(uint[] x) + { + return 0 != IsOne(x); + } + public static int IsZero(uint[] x) { uint d = 0; diff --git a/crypto/src/math/ec/rfc8032/Ed25519.cs b/crypto/src/math/ec/rfc8032/Ed25519.cs index bdbe47e50..cc351bc45 100644 --- a/crypto/src/math/ec/rfc8032/Ed25519.cs +++ b/crypto/src/math/ec/rfc8032/Ed25519.cs @@ -183,6 +183,13 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 return !Nat256.Gte(n, L); } + private static byte[] Copy(byte[] buf, int off, int len) + { + byte[] result = new byte[len]; + Array.Copy(buf, off, result, 0, len); + return result; + } + private static IDigest CreateDigest() { return new Sha512Digest(); @@ -220,7 +227,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 private static bool DecodePointVar(byte[] p, int pOff, bool negate, PointAffine r) { - byte[] py = Arrays.CopyOfRange(p, pOff, pOff + PointBytes); + byte[] py = Copy(p, pOff, PointBytes); if (!CheckPointVar(py)) return false; @@ -461,8 +468,8 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 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); + byte[] R = Copy(sig, sigOff, PointBytes); + byte[] S = Copy(sig, sigOff + PointBytes, ScalarBytes); if (!CheckPointVar(R)) return false; @@ -498,6 +505,16 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 return 0 != EncodePoint(pR, check, 0) && Arrays.AreEqual(check, R); } + private static bool IsNeutralElementVar(int[] x, int[] y) + { + return F.IsZeroVar(x) && F.IsOneVar(y); + } + + private static bool IsNeutralElementVar(int[] x, int[] y, int[] z) + { + return F.IsZeroVar(x) && F.AreEqualVar(y, z); + } + private static void PointAdd(PointExt p, PointAccum r) { int[] a = F.Create(); @@ -1234,6 +1251,36 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 F.Copy(p.z, 0, z, 0); } + private static void ScalarMultOrder(PointAffine p, PointAccum r) + { + uint[] n = new uint[ScalarUints]; + Nat.ShiftDownBit(ScalarUints, L, 0, n); + n[ScalarUints - 1] |= 1U << 28; + + int[] table = PointPrecompute(p, 8); + PointExt q = new PointExt(); + + // Replace first 4 doublings (2^4 * P) with 1 addition (P + 15 * P) + PointCopy(p, r); + PointLookup(table, 7, q); + PointAdd(q, r); + + int w = 62; + for (;;) + { + PointLookup(n, w, table, q); + PointAdd(q, r); + + if (--w < 0) + break; + + for (int i = 0; i < 4; ++i) + { + PointDouble(r); + } + } + } + private static void ScalarMultStrausVar(uint[] nb, uint[] np, PointAffine p, PointAccum r) { Precompute(); @@ -1340,6 +1387,34 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, 0, m.Length, sig, sigOff); } + public static bool ValidatePublicKeyFull(byte[] pk, int pkOff) + { + PointAffine p = new PointAffine(); + if (!DecodePointVar(pk, pkOff, false, p)) + return false; + + F.Normalize(p.x); + F.Normalize(p.y); + + if (IsNeutralElementVar(p.x, p.y)) + return false; + + PointAccum r = new PointAccum(); + ScalarMultOrder(p, r); + + F.Normalize(r.x); + F.Normalize(r.y); + F.Normalize(r.z); + + return IsNeutralElementVar(r.x, r.y, r.z); + } + + public static bool ValidatePublicKeyPartial(byte[] pk, int pkOff) + { + PointAffine p = new PointAffine(); + return DecodePointVar(pk, pkOff, false, p); + } + public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen) { byte[] ctx = null; diff --git a/crypto/src/math/ec/rfc8032/Ed448.cs b/crypto/src/math/ec/rfc8032/Ed448.cs index bbe1bb444..28ee546d1 100644 --- a/crypto/src/math/ec/rfc8032/Ed448.cs +++ b/crypto/src/math/ec/rfc8032/Ed448.cs @@ -173,6 +173,13 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 return !Nat.Gte(ScalarUints, n, L); } + private static byte[] Copy(byte[] buf, int off, int len) + { + byte[] result = new byte[len]; + Array.Copy(buf, off, result, 0, len); + return result; + } + public static IXof CreatePrehash() { return CreateXof(); @@ -217,7 +224,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 private static bool DecodePointVar(byte[] p, int pOff, bool negate, PointExt r) { - byte[] py = Arrays.CopyOfRange(p, pOff, pOff + PointBytes); + byte[] py = Copy(p, pOff, PointBytes); if (!CheckPointVar(py)) return false; @@ -459,8 +466,8 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 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[] R = Copy(sig, sigOff, PointBytes); + byte[] S = Copy(sig, sigOff + PointBytes, ScalarBytes); if (!CheckPointVar(R)) return false; @@ -496,6 +503,16 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 return 0 != EncodePoint(pR, check, 0) && Arrays.AreEqual(check, R); } + private static bool IsNeutralElementVar(uint[] x, uint[] y) + { + return F.IsZeroVar(x) && F.IsOneVar(y); + } + + private static bool IsNeutralElementVar(uint[] x, uint[] y, uint[] z) + { + return F.IsZeroVar(x) && F.AreEqualVar(y, z); + } + private static void PointAdd(PointExt p, PointExt r) { uint[] a = F.Create(); @@ -1255,6 +1272,28 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 F.Copy(p.y, 0, y, 0); } + private static void ScalarMultOrder(PointExt p, PointExt r) + { + uint[] n = new uint[ScalarUints]; + Nat.ShiftDownBit(ScalarUints, L, 1, n); + + uint[] table = PointPrecompute(p, 8); + PointExt q = new PointExt(); + + PointLookup(n, 111, table, r); + + for (int w = 110; w >= 0; --w) + { + for (int i = 0; i < 4; ++i) + { + PointDouble(r); + } + + PointLookup(n, w, table, q); + PointAdd(q, r); + } + } + private static void ScalarMultStrausVar(uint[] nb, uint[] np, PointExt p, PointExt r) { Precompute(); @@ -1345,6 +1384,35 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, 0, m.Length, sig, sigOff); } + public static bool ValidatePublicKeyFull(byte[] pk, int pkOff) + { + PointExt p = new PointExt(); + if (!DecodePointVar(pk, pkOff, false, p)) + return false; + + F.Normalize(p.x); + F.Normalize(p.y); + F.Normalize(p.z); + + if (IsNeutralElementVar(p.x, p.y, p.z)) + return false; + + PointExt r = new PointExt(); + ScalarMultOrder(p, r); + + F.Normalize(r.x); + F.Normalize(r.y); + F.Normalize(r.z); + + return IsNeutralElementVar(r.x, r.y, r.z); + } + + public static bool ValidatePublicKeyPartial(byte[] pk, int pkOff) + { + PointExt p = new PointExt(); + return DecodePointVar(pk, pkOff, false, p); + } + public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen) { byte phflag = 0x00; diff --git a/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs b/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs index 8a61609af..29ff67191 100644 --- a/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs +++ b/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs @@ -13,8 +13,10 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests public class Ed25519Test { private static readonly SecureRandom Random = new SecureRandom(); - - [SetUp] + + private static readonly byte[] Neutral = Hex.DecodeStrict("0100000000000000000000000000000000000000000000000000000000000000"); + + [SetUp] public void SetUp() { Ed25519.Precompute(); @@ -365,6 +367,92 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests "Ed25519ph Vector #1"); } + [Test] + public void TestPublicKeyValidationFull() + { + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Neutral, 0)); + + byte[] sk = new byte[Ed25519.SecretKeySize]; + byte[] pk = new byte[Ed25519.PublicKeySize]; + + for (int i = 0; i < 10; ++i) + { + Random.NextBytes(sk); + Ed25519.GeneratePublicKey(sk, 0, pk, 0); + Assert.IsTrue(Ed25519.ValidatePublicKeyFull(pk, 0)); + } + + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("0100000000000000000000000000000000000000000000000000000000000080"), 0)); + + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), 0)); + + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("D73D6044821BD0DF4068AE1792F0851170F53062150AA70A87E2A58A05A26115"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("F9D557BE0F3C700571CD8AD9CFDE0A2C67F88EE71830073C7756A0599311AD94"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("7A772BBC08D53BF381B150D8411B9AF134BBF24B90A038EFD8DA4A17B32606A1"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("DC6EF81316C08B91209A73FE8E208DD319F56C6A47956A03AF7D6D826A88AC87"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("6EEDF105177868C9AD48DAF2C36EE3B169D892A02A3BF83101B1D50D86BFB19E"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("4BAAB5711F22FF7479E6D9BD2C5BC4DCD3CFC9F36921971496907B1F2B62C6BA"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("D96A46432581A80085F978F7FC0977E228C5A3FD2E64D588BB5F5E5A84E4ABAE"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("10C326AE15FA5BA89EDDAB89C860797385298F4C7750BAEB94A5AAC9A876B538"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("7808F3F6EB858E9BBD2570F20A9F7502175F312FA2DBE4C96EB5C683B384AA60"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("0DE943C51E91AA3ED9FFA82D39A9813D94F59246452F6A7780D067BC61342FE1"), 0)); + + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("10026DBFB4C55628716BB0EF979A10DD5AC7AA970C229B5E68DD993E2C20E7D5"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("68EC52D16C1DB4483AA8679277C34E0DC56EB7D064D302B9749F0D31A901D484"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("6E54C8F00669422D5697E09C0575AE1E699841ACF1690A5DFAA25E3160F3A2EF"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("CA66B62D361F790AA9658161BA0FFDC3CE60624151258C7301926DFE0C67EE64"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("88D912C322AE3D0907B38ED08727FBF06D51C5D1DE622B5BC24DAB30078AE9FF"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("F24683E044CE3F14BCA24F1356AE7767509E17EFA2606438BA275860819E14B8"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("B2865F02E6D19A94CE6147B574095733B3628A2FBE2C84022262D88F7D6C4F7D"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("FA4DA03321816C1C9066BD250982DDD1B4349C43C5E124D2B39F8DDA4E5364F8"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("FCADF40DE51A943F3B7847DBEBA0627B33D020D81DFFABF2B3701BD9B746952A"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyFull(Hex.DecodeStrict("379B071E6F7E2479D5A8588AB708137808D63F689127D4A228E2C1681873C55E"), 0)); + } + + [Test] + public void TestPublicKeyValidationPartial() + { + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Neutral, 0)); + + byte[] sk = new byte[Ed25519.SecretKeySize]; + byte[] pk = new byte[Ed25519.PublicKeySize]; + + for (int i = 0; i < 10; ++i) + { + Random.NextBytes(sk); + Ed25519.GeneratePublicKey(sk, 0, pk, 0); + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(pk, 0)); + } + + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("0100000000000000000000000000000000000000000000000000000000000080"), 0)); + + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), 0)); + + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("D73D6044821BD0DF4068AE1792F0851170F53062150AA70A87E2A58A05A26115"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("F9D557BE0F3C700571CD8AD9CFDE0A2C67F88EE71830073C7756A0599311AD94"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("7A772BBC08D53BF381B150D8411B9AF134BBF24B90A038EFD8DA4A17B32606A1"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("DC6EF81316C08B91209A73FE8E208DD319F56C6A47956A03AF7D6D826A88AC87"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("6EEDF105177868C9AD48DAF2C36EE3B169D892A02A3BF83101B1D50D86BFB19E"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("4BAAB5711F22FF7479E6D9BD2C5BC4DCD3CFC9F36921971496907B1F2B62C6BA"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("D96A46432581A80085F978F7FC0977E228C5A3FD2E64D588BB5F5E5A84E4ABAE"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("10C326AE15FA5BA89EDDAB89C860797385298F4C7750BAEB94A5AAC9A876B538"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("7808F3F6EB858E9BBD2570F20A9F7502175F312FA2DBE4C96EB5C683B384AA60"), 0)); + Assert.IsFalse(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("0DE943C51E91AA3ED9FFA82D39A9813D94F59246452F6A7780D067BC61342FE1"), 0)); + + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("10026DBFB4C55628716BB0EF979A10DD5AC7AA970C229B5E68DD993E2C20E7D5"), 0)); + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("68EC52D16C1DB4483AA8679277C34E0DC56EB7D064D302B9749F0D31A901D484"), 0)); + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("6E54C8F00669422D5697E09C0575AE1E699841ACF1690A5DFAA25E3160F3A2EF"), 0)); + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("CA66B62D361F790AA9658161BA0FFDC3CE60624151258C7301926DFE0C67EE64"), 0)); + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("88D912C322AE3D0907B38ED08727FBF06D51C5D1DE622B5BC24DAB30078AE9FF"), 0)); + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("F24683E044CE3F14BCA24F1356AE7767509E17EFA2606438BA275860819E14B8"), 0)); + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("B2865F02E6D19A94CE6147B574095733B3628A2FBE2C84022262D88F7D6C4F7D"), 0)); + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("FA4DA03321816C1C9066BD250982DDD1B4349C43C5E124D2B39F8DDA4E5364F8"), 0)); + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("FCADF40DE51A943F3B7847DBEBA0627B33D020D81DFFABF2B3701BD9B746952A"), 0)); + Assert.IsTrue(Ed25519.ValidatePublicKeyPartial(Hex.DecodeStrict("379B071E6F7E2479D5A8588AB708137808D63F689127D4A228E2C1681873C55E"), 0)); + } + private static void CheckEd25519Vector(string sSK, string sPK, string sM, string sSig, string text) { byte[] sk = Hex.Decode(sSK); diff --git a/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs b/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs index cc8e82de0..40d28cc97 100644 --- a/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs +++ b/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs @@ -14,6 +14,8 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests { private static readonly SecureRandom Random = new SecureRandom(); + private static readonly byte[] Neutral = Hex.DecodeStrict("010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + [SetUp] public void SetUp() { @@ -462,6 +464,96 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests "Ed448ph Vector #2"); } + [Test] + public void TestPublicKeyValidationFull() + { + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Neutral, 0)); + + byte[] sk = new byte[Ed448.SecretKeySize]; + byte[] pk = new byte[Ed448.PublicKeySize]; + + for (int i = 0; i < 10; ++i) + { + Random.NextBytes(sk); + Ed448.GeneratePublicKey(sk, 0, pk, 0); + Assert.IsTrue(Ed448.ValidatePublicKeyFull(pk, 0)); + } + + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"), 0)); + + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081"), 0)); + + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("C784B7238BDDDB84C44FB80936FB103FCF39C1F74EE83163A57DB4AD3946FDC81BF0504D6EC1DBABABDB750997BCA465D5FCD3A45F8E183D00"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("149578BCA53F7D199B472D6D367D22A35942BBCA2051F833122D4DC12FE758A16D672A54D5F8C390C44C2F8B32F21121DA69E9DE8FF9675780"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("9E9F6E7A8576E8D7C286C493FE76559419012B164589DF764E735CFFDE21BFCAF4D7553F9B37178A2F20C77473E4195E3E1E327F3174C14500"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("1979BDCBE0CEC16602B87257114059029605C720D5AFD2A90EF4B06655B34B561EBA6C1034452C3D8D1DA41C57340B0C9A95297E712CA75C00"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("E2B8507036D478F262A7009734CDD383734002CE32397FEA22BFEDEE0CEBB0064D176FB45A05AF19F8B18B07EE20D6E2320D075E95DAF15200"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("3C2FFFFCF504A0EBD8051B3962546C39410464A9C44DC3E82FA9437F2450F0F93C892F28E2ABDF7EA84B051E5536CCA6B44762D0941C5D0700"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("997FE46037CF6207B27B6D0BB9D7D97A038D5BFCF898D07EE6ED07953F0889CC4745D1E018EB7A894EFE88871004452E99C6A344362DA6E080"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("F67C319B8EDCE2E85D450BE46E1671183EB499CE8ABE56BCF666C13A99C5ECBC89FCE9B3B578E2A5D061D3590506BC27614DB6B0C682971B80"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("A7776DDD0BD52EC4D017478E38700395F9F4C45A3BEFFE4EA9994EA1A9E92D8D1CC56539BF57FF88401BBDC764904BC0E3635AEE1721FD3380"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("9F914CD9920D2B75ADBF34F758DA39BB35D1C81B5C480571A7A8B2CAAD7BA0F32D13AF9C69B0BECE5775B324DC49C063354EA2F6F231A23800"), 0)); + + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("2E0ACAB5953BC2F22C557C75E6B86225BE9CB3E82E78FC886EB57B628229C0C9548CD82630483C03D0E5DC02B2C3B1BD0E5DEE0B8DE4A88000"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("0F89D2E413A36A33031329169EFAAE88D8F84E90E741C3DFBB01C32544D995FF6EB354B6C5C29E62ACC124E806540C46CB0C0ED71931B39D00"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("AB553809FE1B027328EC7DBE71929C1F3A435B74CC0C06BEA831BC5E287EF2ACF4E831EC8E0C964A80BF85B966D32CADAE8E17E12EAFD3AF80"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("3043631378826937A822BDB8878DC33B9174BEC3530B2A8A4048F6B06B378DBC450E34ED623E47B1449E7636DAFB72F584605EF3BE01647F00"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("8A03959C8BD20BA7B1DA92A4C5591BC846F4CD8BE07387B325E179BB12245E17BDDE1AC82E9F7CAB2A79DDDBE68F8BA8DB7F03F91156C24A00"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("46299C8D31BAFEBBCF1719A851123CC4722E5BE9D93D8F98C215D34082AF658C570B4CFD44079993CBC19B0EAD3BFD0DFB2B67EBABB119B780"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("81A58C03708DD60BD68237622EC9934E8DE27FE7997F74A501B06C60C8F9D68856E7D12B88F1507E29EB0C30531B5AA353F154F2551AF5E580"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("DC5028F5AA0B9217B40C7FE00E10503C37B6611BA87CDD70F01536E87AD659711BA1265E679F94EC8D5ED87476CE031D14B2C7E46268F11A80"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("910DDFE36AAB6DCB7D5B72E6F2DF0769AD86665262232C487F722FEA85429DE247D1EBBC5C579A01D04672894E2B0F3FBDF22B43EA191DF700"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyFull(Hex.DecodeStrict("43482D0750D4830AAAF578346288050EAE8ADF96DF66F243E73252114E432B448730517FD8726871508CAD7ECECFDB33120CA5558788B6C800"), 0)); + } + + [Test] + public void TestPublicKeyValidationPartial() + { + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Neutral, 0)); + + byte[] sk = new byte[Ed448.SecretKeySize]; + byte[] pk = new byte[Ed448.PublicKeySize]; + + for (int i = 0; i < 10; ++i) + { + Random.NextBytes(sk); + Ed448.GeneratePublicKey(sk, 0, pk, 0); + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(pk, 0)); + } + + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080"), 0)); + + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081"), 0)); + + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("C784B7238BDDDB84C44FB80936FB103FCF39C1F74EE83163A57DB4AD3946FDC81BF0504D6EC1DBABABDB750997BCA465D5FCD3A45F8E183D00"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("149578BCA53F7D199B472D6D367D22A35942BBCA2051F833122D4DC12FE758A16D672A54D5F8C390C44C2F8B32F21121DA69E9DE8FF9675780"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("9E9F6E7A8576E8D7C286C493FE76559419012B164589DF764E735CFFDE21BFCAF4D7553F9B37178A2F20C77473E4195E3E1E327F3174C14500"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("1979BDCBE0CEC16602B87257114059029605C720D5AFD2A90EF4B06655B34B561EBA6C1034452C3D8D1DA41C57340B0C9A95297E712CA75C00"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("E2B8507036D478F262A7009734CDD383734002CE32397FEA22BFEDEE0CEBB0064D176FB45A05AF19F8B18B07EE20D6E2320D075E95DAF15200"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("3C2FFFFCF504A0EBD8051B3962546C39410464A9C44DC3E82FA9437F2450F0F93C892F28E2ABDF7EA84B051E5536CCA6B44762D0941C5D0700"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("997FE46037CF6207B27B6D0BB9D7D97A038D5BFCF898D07EE6ED07953F0889CC4745D1E018EB7A894EFE88871004452E99C6A344362DA6E080"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("F67C319B8EDCE2E85D450BE46E1671183EB499CE8ABE56BCF666C13A99C5ECBC89FCE9B3B578E2A5D061D3590506BC27614DB6B0C682971B80"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("A7776DDD0BD52EC4D017478E38700395F9F4C45A3BEFFE4EA9994EA1A9E92D8D1CC56539BF57FF88401BBDC764904BC0E3635AEE1721FD3380"), 0)); + Assert.IsFalse(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("9F914CD9920D2B75ADBF34F758DA39BB35D1C81B5C480571A7A8B2CAAD7BA0F32D13AF9C69B0BECE5775B324DC49C063354EA2F6F231A23800"), 0)); + + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("2E0ACAB5953BC2F22C557C75E6B86225BE9CB3E82E78FC886EB57B628229C0C9548CD82630483C03D0E5DC02B2C3B1BD0E5DEE0B8DE4A88000"), 0)); + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("0F89D2E413A36A33031329169EFAAE88D8F84E90E741C3DFBB01C32544D995FF6EB354B6C5C29E62ACC124E806540C46CB0C0ED71931B39D00"), 0)); + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("AB553809FE1B027328EC7DBE71929C1F3A435B74CC0C06BEA831BC5E287EF2ACF4E831EC8E0C964A80BF85B966D32CADAE8E17E12EAFD3AF80"), 0)); + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("3043631378826937A822BDB8878DC33B9174BEC3530B2A8A4048F6B06B378DBC450E34ED623E47B1449E7636DAFB72F584605EF3BE01647F00"), 0)); + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("8A03959C8BD20BA7B1DA92A4C5591BC846F4CD8BE07387B325E179BB12245E17BDDE1AC82E9F7CAB2A79DDDBE68F8BA8DB7F03F91156C24A00"), 0)); + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("46299C8D31BAFEBBCF1719A851123CC4722E5BE9D93D8F98C215D34082AF658C570B4CFD44079993CBC19B0EAD3BFD0DFB2B67EBABB119B780"), 0)); + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("81A58C03708DD60BD68237622EC9934E8DE27FE7997F74A501B06C60C8F9D68856E7D12B88F1507E29EB0C30531B5AA353F154F2551AF5E580"), 0)); + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("DC5028F5AA0B9217B40C7FE00E10503C37B6611BA87CDD70F01536E87AD659711BA1265E679F94EC8D5ED87476CE031D14B2C7E46268F11A80"), 0)); + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("910DDFE36AAB6DCB7D5B72E6F2DF0769AD86665262232C487F722FEA85429DE247D1EBBC5C579A01D04672894E2B0F3FBDF22B43EA191DF700"), 0)); + Assert.IsTrue(Ed448.ValidatePublicKeyPartial(Hex.DecodeStrict("43482D0750D4830AAAF578346288050EAE8ADF96DF66F243E73252114E432B448730517FD8726871508CAD7ECECFDB33120CA5558788B6C800"), 0)); + } + private static void CheckEd448Vector(string sSK, string sPK, string sM, string sCTX, string sSig, string text) { byte[] sk = Hex.Decode(sSK); |