From 9d24081e7690f4ec1ff898e3998e385d3486b226 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sun, 2 Oct 2022 01:12:28 +0700 Subject: Span-based variant of ECCurve.DecodePoint --- crypto/src/math/ec/ECCurve.cs | 163 +++++++++++++++++++++++++++++++----------- 1 file changed, 120 insertions(+), 43 deletions(-) diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs index 38e05991e..905ddb247 100644 --- a/crypto/src/math/ec/ECCurve.cs +++ b/crypto/src/math/ec/ECCurve.cs @@ -436,67 +436,143 @@ namespace Org.BouncyCastle.Math.EC */ public virtual ECPoint DecodePoint(byte[] encoded) { - ECPoint p = null; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return DecodePoint(encoded.AsSpan()); +#else + ECPoint p; int expectedLength = (FieldSize + 7) / 8; byte type = encoded[0]; switch (type) { - case 0x00: // infinity - { - if (encoded.Length != 1) - throw new ArgumentException("Incorrect length for infinity encoding", "encoded"); + case 0x00: // infinity + { + if (encoded.Length != 1) + throw new ArgumentException("Incorrect length for infinity encoding", "encoded"); - p = Infinity; - break; - } + p = Infinity; + break; + } - case 0x02: // compressed - case 0x03: // compressed - { - if (encoded.Length != (expectedLength + 1)) - throw new ArgumentException("Incorrect length for compressed encoding", "encoded"); + case 0x02: // compressed + case 0x03: // compressed + { + if (encoded.Length != (expectedLength + 1)) + throw new ArgumentException("Incorrect length for compressed encoding", "encoded"); - int yTilde = type & 1; - BigInteger X = new BigInteger(1, encoded, 1, expectedLength); + int yTilde = type & 1; + BigInteger X = new BigInteger(1, encoded, 1, expectedLength); - p = DecompressPoint(yTilde, X); - if (!p.ImplIsValid(true, true)) - throw new ArgumentException("Invalid point"); + p = DecompressPoint(yTilde, X); + if (!p.ImplIsValid(true, true)) + throw new ArgumentException("Invalid point"); - break; - } + break; + } - case 0x04: // uncompressed - { - if (encoded.Length != (2 * expectedLength + 1)) - throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded"); + case 0x04: // uncompressed + { + if (encoded.Length != (2 * expectedLength + 1)) + throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded"); - BigInteger X = new BigInteger(1, encoded, 1, expectedLength); - BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength); + BigInteger X = new BigInteger(1, encoded, 1, expectedLength); + BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength); - p = ValidatePoint(X, Y); - break; - } + p = ValidatePoint(X, Y); + break; + } - case 0x06: // hybrid - case 0x07: // hybrid - { - if (encoded.Length != (2 * expectedLength + 1)) - throw new ArgumentException("Incorrect length for hybrid encoding", "encoded"); + case 0x06: // hybrid + case 0x07: // hybrid + { + if (encoded.Length != (2 * expectedLength + 1)) + throw new ArgumentException("Incorrect length for hybrid encoding", "encoded"); - BigInteger X = new BigInteger(1, encoded, 1, expectedLength); - BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength); + BigInteger X = new BigInteger(1, encoded, 1, expectedLength); + BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength); - if (Y.TestBit(0) != (type == 0x07)) - throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded"); + if (Y.TestBit(0) != (type == 0x07)) + throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded"); - p = ValidatePoint(X, Y); - break; - } + p = ValidatePoint(X, Y); + break; + } - default: - throw new FormatException("Invalid point encoding " + type); + default: + throw new FormatException("Invalid point encoding " + type); + } + + if (type != 0x00 && p.IsInfinity) + throw new ArgumentException("Invalid infinity encoding", "encoded"); + + return p; +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual ECPoint DecodePoint(ReadOnlySpan encodedX) + { + ECPoint p; + int expectedLength = (FieldSize + 7) / 8; + + byte type = encodedX[0]; + switch (type) + { + case 0x00: // infinity + { + if (encodedX.Length != 1) + throw new ArgumentException("Incorrect length for infinity encoding", "encoded"); + + p = Infinity; + break; + } + + case 0x02: // compressed + case 0x03: // compressed + { + if (encodedX.Length != (expectedLength + 1)) + throw new ArgumentException("Incorrect length for compressed encoding", "encoded"); + + int yTilde = type & 1; + BigInteger X = new BigInteger(1, encodedX[1..]); + + p = DecompressPoint(yTilde, X); + if (!p.ImplIsValid(true, true)) + throw new ArgumentException("Invalid point"); + + break; + } + + case 0x04: // uncompressed + { + if (encodedX.Length != (2 * expectedLength + 1)) + throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded"); + + BigInteger X = new BigInteger(1, encodedX[1..(1 + expectedLength)]); + BigInteger Y = new BigInteger(1, encodedX[(1 + expectedLength)..]); + + p = ValidatePoint(X, Y); + break; + } + + case 0x06: // hybrid + case 0x07: // hybrid + { + if (encodedX.Length != (2 * expectedLength + 1)) + throw new ArgumentException("Incorrect length for hybrid encoding", "encoded"); + + BigInteger X = new BigInteger(1, encodedX[1..(1 + expectedLength)]); + BigInteger Y = new BigInteger(1, encodedX[(1 + expectedLength)..]); + + if (Y.TestBit(0) != (type == 0x07)) + throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded"); + + p = ValidatePoint(X, Y); + break; + } + + default: + throw new FormatException("Invalid point encoding " + type); } if (type != 0x00 && p.IsInfinity) @@ -504,6 +580,7 @@ namespace Org.BouncyCastle.Math.EC return p; } +#endif private class DefaultLookupTable : AbstractECLookupTable -- cgit 1.4.1