diff --git a/crypto/src/math/ec/rfc8032/Scalar25519.cs b/crypto/src/math/ec/rfc8032/Scalar25519.cs
index 67eee6155..4fb2fd2da 100644
--- a/crypto/src/math/ec/rfc8032/Scalar25519.cs
+++ b/crypto/src/math/ec/rfc8032/Scalar25519.cs
@@ -606,6 +606,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
Span<uint> Nu = stackalloc uint[16]; LSq.CopyTo(Nu);
Span<uint> Nv = stackalloc uint[16]; Nat256.Square(k, Nv); ++Nv[0];
Span<uint> p = stackalloc uint[16]; Nat256.Mul(L, k, p);
+ Span<uint> t = stackalloc uint[16];
Span<uint> u0 = stackalloc uint[4]; u0.CopyFrom(L);
Span<uint> u1 = stackalloc uint[4];
Span<uint> v0 = stackalloc uint[4]; v0.CopyFrom(k);
@@ -622,12 +623,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
if ((int)p[last] < 0)
{
- ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtilities.AddShifted_UV(last: 3, s, u0, u1, v0, v1);
}
else
{
- ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtilities.SubShifted_UV(last: 3, s, u0, u1, v0, v1);
}
@@ -658,6 +659,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
uint[] Nu = new uint[16]; Array.Copy(LSq, Nu, 16);
uint[] Nv = new uint[16]; Nat256.Square(k, Nv); ++Nv[0];
uint[] p = new uint[16]; Nat256.Mul(L, k, p);
+ uint[] t = new uint[16];
uint[] u0 = new uint[4]; Array.Copy(L, u0, 4);
uint[] u1 = new uint[4];
uint[] v0 = new uint[4]; Array.Copy(k, v0, 4);
@@ -674,12 +676,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
if ((int)p[last] < 0)
{
- ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtilities.AddShifted_UV(last: 3, s, u0, u1, v0, v1);
}
else
{
- ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtilities.SubShifted_UV(last: 3, s, u0, u1, v0, v1);
}
diff --git a/crypto/src/math/ec/rfc8032/Scalar448.cs b/crypto/src/math/ec/rfc8032/Scalar448.cs
index 124b91250..d53f0b669 100644
--- a/crypto/src/math/ec/rfc8032/Scalar448.cs
+++ b/crypto/src/math/ec/rfc8032/Scalar448.cs
@@ -1125,6 +1125,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
Span<uint> Nu = stackalloc uint[28]; LSq.CopyTo(Nu);
Span<uint> Nv = stackalloc uint[28]; Nat448.Square(k, Nv); ++Nv[0];
Span<uint> p = stackalloc uint[28]; Nat448.Mul(L, k, p);
+ Span<uint> t = stackalloc uint[28];
Span<uint> u0 = stackalloc uint[8]; u0.CopyFrom(L);
Span<uint> u1 = stackalloc uint[8];
Span<uint> v0 = stackalloc uint[8]; v0.CopyFrom(k);
@@ -1141,12 +1142,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
if ((int)p[last] < 0)
{
- ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtilities.AddShifted_UV(last: 7, s, u0, u1, v0, v1);
}
else
{
- ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtilities.SubShifted_UV(last: 7, s, u0, u1, v0, v1);
}
@@ -1180,6 +1181,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
uint[] Nu = new uint[28]; Array.Copy(LSq, Nu, 28);
uint[] Nv = new uint[28]; Nat448.Square(k, Nv); ++Nv[0];
uint[] p = new uint[28]; Nat448.Mul(L, k, p);
+ uint[] t = new uint[28];
uint[] u0 = new uint[8]; Array.Copy(L, u0, 8);
uint[] u1 = new uint[8];
uint[] v0 = new uint[8]; Array.Copy(k, v0, 8);
@@ -1196,12 +1198,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
if ((int)p[last] < 0)
{
- ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtilities.AddShifted_UV(last: 7, s, u0, u1, v0, v1);
}
else
{
- ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtilities.SubShifted_UV(last: 7, s, u0, u1, v0, v1);
}
diff --git a/crypto/src/math/ec/rfc8032/ScalarUtilities.cs b/crypto/src/math/ec/rfc8032/ScalarUtilities.cs
index c70a4f2e8..fca4a0232 100644
--- a/crypto/src/math/ec/rfc8032/ScalarUtilities.cs
+++ b/crypto/src/math/ec/rfc8032/ScalarUtilities.cs
@@ -12,62 +12,120 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void AddShifted_NP(int last, int s, Span<uint> Nu, ReadOnlySpan<uint> Nv, Span<uint> _p)
+ internal static void AddShifted_NP(int last, int s, Span<uint> Nu, ReadOnlySpan<uint> Nv, Span<uint> p, Span<uint> t)
#else
- internal static void AddShifted_NP(int last, int s, uint[] Nu, uint[] Nv, uint[] _p)
+ internal static void AddShifted_NP(int last, int s, uint[] Nu, uint[] Nv, uint[] p, uint[] t)
#endif
{
- int sWords = s >> 5, sBits = s & 31;
-
- ulong cc__p = 0UL;
+ ulong cc_p = 0UL;
ulong cc_Nu = 0UL;
- if (sBits == 0)
+ if (s == 0)
{
- for (int i = sWords; i <= last; ++i)
+ for (int i = 0; i <= last; ++i)
{
+ uint p_i = p[i];
+
cc_Nu += Nu[i];
- cc_Nu += _p[i - sWords];
+ cc_Nu += p_i;
- cc__p += _p[i];
- cc__p += Nv[i - sWords];
- _p[i] = (uint)cc__p; cc__p >>= 32;
+ cc_p += p_i;
+ cc_p += Nv[i];
+ p_i = (uint)cc_p; cc_p >>= 32;
+ p[i] = p_i;
- cc_Nu += _p[i - sWords];
+ cc_Nu += p_i;
Nu[i] = (uint)cc_Nu; cc_Nu >>= 32;
}
}
- else
+ else if (s < 32)
{
uint prev_p = 0U;
uint prev_q = 0U;
uint prev_v = 0U;
- for (int i = sWords; i <= last; ++i)
+ for (int i = 0; i <= last; ++i)
{
- uint next_p = _p[i - sWords];
- uint p_s = (next_p << sBits) | (prev_p >> -sBits);
- prev_p = next_p;
+ uint p_i = p[i];
+ uint p_s = (p_i << s) | (prev_p >> -s);
+ prev_p = p_i;
cc_Nu += Nu[i];
cc_Nu += p_s;
- uint next_v = Nv[i - sWords];
- uint v_s = (next_v << sBits) | (prev_v >> -sBits);
+ uint next_v = Nv[i];
+ uint v_s = (next_v << s) | (prev_v >> -s);
prev_v = next_v;
- cc__p += _p[i];
- cc__p += v_s;
- _p[i] = (uint)cc__p; cc__p >>= 32;
+ cc_p += p_i;
+ cc_p += v_s;
+ p_i = (uint)cc_p; cc_p >>= 32;
+ p[i] = p_i;
- uint next_q = _p[i - sWords];
- uint q_s = (next_q << sBits) | (prev_q >> -sBits);
- prev_q = next_q;
+ uint q_s = (p_i << s) | (prev_q >> -s);
+ prev_q = p_i;
cc_Nu += q_s;
Nu[i] = (uint)cc_Nu; cc_Nu >>= 32;
}
}
+ else
+ {
+ // Keep the original value of p in t
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ t[..(last + 1)].CopyFrom(p);
+#else
+ Array.Copy(p, 0, t, 0, last + 1);
+#endif
+
+ int sWords = s >> 5, sBits = s & 31;
+ if (sBits == 0)
+ {
+ for (int i = sWords; i <= last; ++i)
+ {
+ cc_Nu += Nu[i];
+ cc_Nu += t[i - sWords];
+
+ cc_p += p[i];
+ cc_p += Nv[i - sWords];
+ p[i] = (uint)cc_p; cc_p >>= 32;
+
+ cc_Nu += p[i - sWords];
+ Nu[i] = (uint)cc_Nu; cc_Nu >>= 32;
+ }
+ }
+ else
+ {
+ uint prev_t = 0U;
+ uint prev_q = 0U;
+ uint prev_v = 0U;
+
+ for (int i = sWords; i <= last; ++i)
+ {
+ uint next_t = t[i - sWords];
+ uint t_s = (next_t << sBits) | (prev_t >> -sBits);
+ prev_t = next_t;
+
+ cc_Nu += Nu[i];
+ cc_Nu += t_s;
+
+ uint next_v = Nv[i - sWords];
+ uint v_s = (next_v << sBits) | (prev_v >> -sBits);
+ prev_v = next_v;
+
+ cc_p += p[i];
+ cc_p += v_s;
+ p[i] = (uint)cc_p; cc_p >>= 32;
+
+ uint next_q = p[i - sWords];
+ uint q_s = (next_q << sBits) | (prev_q >> -sBits);
+ prev_q = next_q;
+
+ cc_Nu += q_s;
+ Nu[i] = (uint)cc_Nu; cc_Nu >>= 32;
+ }
+ }
+ }
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
@@ -171,62 +229,120 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void SubShifted_NP(int last, int s, Span<uint> Nu, ReadOnlySpan<uint> Nv, Span<uint> _p)
+ internal static void SubShifted_NP(int last, int s, Span<uint> Nu, ReadOnlySpan<uint> Nv, Span<uint> p, Span<uint> t)
#else
- internal static void SubShifted_NP(int last, int s, uint[] Nu, uint[] Nv, uint[] _p)
+ internal static void SubShifted_NP(int last, int s, uint[] Nu, uint[] Nv, uint[] p, uint[] t)
#endif
{
- int sWords = s >> 5, sBits = s & 31;
-
- long cc__p = 0L;
+ long cc_p = 0L;
long cc_Nu = 0L;
- if (sBits == 0)
+ if (s == 0)
{
- for (int i = sWords; i <= last; ++i)
+ for (int i = 0; i <= last; ++i)
{
+ uint p_i = p[i];
+
cc_Nu += Nu[i];
- cc_Nu -= _p[i - sWords];
+ cc_Nu -= p_i;
- cc__p += _p[i];
- cc__p -= Nv[i - sWords];
- _p[i] = (uint)cc__p; cc__p >>= 32;
+ cc_p += p_i;
+ cc_p -= Nv[i];
+ p_i = (uint)cc_p; cc_p >>= 32;
+ p[i] = p_i;
- cc_Nu -= _p[i - sWords];
+ cc_Nu -= p_i;
Nu[i] = (uint)cc_Nu; cc_Nu >>= 32;
}
}
- else
+ else if (s < 32)
{
uint prev_p = 0U;
uint prev_q = 0U;
uint prev_v = 0U;
- for (int i = sWords; i <= last; ++i)
+ for (int i = 0; i <= last; ++i)
{
- uint next_p = _p[i - sWords];
- uint p_s = (next_p << sBits) | (prev_p >> -sBits);
- prev_p = next_p;
+ uint p_i = p[i];
+ uint p_s = (p_i << s) | (prev_p >> -s);
+ prev_p = p_i;
cc_Nu += Nu[i];
cc_Nu -= p_s;
- uint next_v = Nv[i - sWords];
- uint v_s = (next_v << sBits) | (prev_v >> -sBits);
+ uint next_v = Nv[i];
+ uint v_s = (next_v << s) | (prev_v >> -s);
prev_v = next_v;
- cc__p += _p[i];
- cc__p -= v_s;
- _p[i] = (uint)cc__p; cc__p >>= 32;
+ cc_p += p_i;
+ cc_p -= v_s;
+ p_i = (uint)cc_p; cc_p >>= 32;
+ p[i] = p_i;
- uint next_q = _p[i - sWords];
- uint q_s = (next_q << sBits) | (prev_q >> -sBits);
- prev_q = next_q;
+ uint q_s = (p_i << s) | (prev_q >> -s);
+ prev_q = p_i;
cc_Nu -= q_s;
Nu[i] = (uint)cc_Nu; cc_Nu >>= 32;
}
}
+ else
+ {
+ // Keep the original value of p in t
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ t[..(last + 1)].CopyFrom(p);
+#else
+ Array.Copy(p, 0, t, 0, last + 1);
+#endif
+
+ int sWords = s >> 5, sBits = s & 31;
+ if (sBits == 0)
+ {
+ for (int i = sWords; i <= last; ++i)
+ {
+ cc_Nu += Nu[i];
+ cc_Nu -= t[i - sWords];
+
+ cc_p += p[i];
+ cc_p -= Nv[i - sWords];
+ p[i] = (uint)cc_p; cc_p >>= 32;
+
+ cc_Nu -= p[i - sWords];
+ Nu[i] = (uint)cc_Nu; cc_Nu >>= 32;
+ }
+ }
+ else
+ {
+ uint prev_t = 0U;
+ uint prev_q = 0U;
+ uint prev_v = 0U;
+
+ for (int i = sWords; i <= last; ++i)
+ {
+ uint next_t = t[i - sWords];
+ uint t_s = (next_t << sBits) | (prev_t >> -sBits);
+ prev_t = next_t;
+
+ cc_Nu += Nu[i];
+ cc_Nu -= t_s;
+
+ uint next_v = Nv[i - sWords];
+ uint v_s = (next_v << sBits) | (prev_v >> -sBits);
+ prev_v = next_v;
+
+ cc_p += p[i];
+ cc_p -= v_s;
+ p[i] = (uint)cc_p; cc_p >>= 32;
+
+ uint next_q = p[i - sWords];
+ uint q_s = (next_q << sBits) | (prev_q >> -sBits);
+ prev_q = next_q;
+
+ cc_Nu -= q_s;
+ Nu[i] = (uint)cc_Nu; cc_Nu >>= 32;
+ }
+ }
+ }
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
diff --git a/crypto/test/src/crypto/test/Ed25519Test.cs b/crypto/test/src/crypto/test/Ed25519Test.cs
index b604916de..88b06c32e 100644
--- a/crypto/test/src/crypto/test/Ed25519Test.cs
+++ b/crypto/test/src/crypto/test/Ed25519Test.cs
@@ -25,6 +25,21 @@ namespace Org.BouncyCastle.Crypto.Tests
}
[Test]
+ public void TestRegression_GitHub_bc_java_1599()
+ {
+ Ed25519PublicKeyParameters publicKey = new Ed25519PublicKeyParameters(
+ Hex.DecodeStrict("386e7cf7b9e8353933b07f1db8d84d3720bb667cbd811b312b4e338672338a6d"));
+ byte[] content = Hex.DecodeStrict("414141624c6743596c6f414141514943486e6a4a71326a75705455472d5a36694d716871313467414854486f64757677694844664f594a3230775f77426c6e35444a3953614e616353496835336b626e716e723965ef34c5");
+ byte[] sig = Hex.DecodeStrict("74dc43223fc21b9157e686a1446621a4640464b8ee4877ea7e3963cb5da8b21b9089241defdd7f36448ec4c76174af131994321da7e28483b3c2a7906947fa0f");
+
+ ISigner signer = new Ed25519Signer();
+ signer.Init(false, publicKey);
+ signer.BlockUpdate(content, 0, content.Length);
+ bool verified = signer.VerifySignature(sig);
+ Assert.True(verified);
+ }
+
+ [Test]
public void TestFunction()
{
string resultText = Perform().ToString();
|