< Summary

Information
Class: ArturRios.Jwt.P256
Assembly: ArturRios.Jwt
File(s): /home/runner/work/dotnet-jwt/dotnet-jwt/src/P256.cs
Line coverage
100%
Covered lines: 19
Uncovered lines: 0
Coverable lines: 19
Total lines: 75
Line coverage: 100%
Branch coverage
81%
Covered branches: 18
Total branches: 22
Branch coverage: 81.8%
Method coverage
100%
Covered methods: 4
Fully covered methods: 4
Total methods: 4
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
get_Curve()100%11100%
IsNamed(...)66.66%1212100%
IsOnCurve(...)100%1010100%

File(s)

/home/runner/work/dotnet-jwt/dotnet-jwt/src/P256.cs

#LineLine coverage
 1using System.Globalization;
 2using System.Numerics;
 3using System.Security.Cryptography;
 4
 5namespace ArturRios.Jwt;
 6
 7/// <summary>
 8/// The NIST P-256 curve (secp256r1, prime256v1): its identifiers, and the check that a point lies on it.
 9/// </summary>
 10/// <remarks>
 11/// The check is explicit rather than left to the platform's import. A public key off the curve is the
 12/// precondition of invalid-curve attacks, and whether an import rejects one differs between platforms
 13/// and versions; the curve equation does not.
 14/// </remarks>
 15internal static class P256
 16{
 17    /// <summary>The curve's object identifier.</summary>
 18    public const string Oid = "1.2.840.10045.3.1.7";
 19
 20    /// <summary>The curve's name in a JWK's <c>crv</c> member.</summary>
 21    public const string JwkCurveName = "P-256";
 22
 23    /// <summary>The length of each coordinate, and of the private scalar, in bytes.</summary>
 24    public const int CoordinateBytes = 32;
 25
 26    /// <summary>The field prime p = 2^256 − 2^224 + 2^192 + 2^96 − 1.</summary>
 127    private static readonly BigInteger s_p = BigInteger.Parse(
 128        "0ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", NumberStyles.HexNumber);
 29
 30    /// <summary>The curve coefficient b of y² = x³ − 3x + b.</summary>
 131    private static readonly BigInteger s_b = BigInteger.Parse(
 132        "05ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", NumberStyles.HexNumber);
 33
 34    /// <summary>The curve, as the platform names it.</summary>
 9335    public static ECCurve Curve => ECCurve.NamedCurves.nistP256;
 36
 37    /// <summary>
 38    /// Whether <paramref name="curve"/> is P-256. Platforms report it by OID or by one of its friendly
 39    /// names, so any of them counts.
 40    /// </summary>
 41    public static bool IsNamed(ECCurve curve) =>
 4542        curve.IsNamed &&
 4543        (curve.Oid.Value == Oid ||
 4544         curve.Oid.FriendlyName is "nistP256" or "ECDSA_P256" or "prime256v1" or "secp256r1");
 45
 46    /// <summary>
 47    /// Whether (<paramref name="x"/>, <paramref name="y"/>), big-endian and 32 bytes each, satisfies
 48    /// y² = x³ − 3x + b over P-256's field, with both coordinates below the field prime.
 49    /// </summary>
 50    public static bool IsOnCurve(ReadOnlySpan<byte> x, ReadOnlySpan<byte> y)
 51    {
 10452        if (x.Length != CoordinateBytes || y.Length != CoordinateBytes)
 53        {
 554            return false;
 55        }
 56
 9957        var px = new BigInteger(x, isUnsigned: true, isBigEndian: true);
 9958        var py = new BigInteger(y, isUnsigned: true, isBigEndian: true);
 59
 9960        if (px >= s_p || py >= s_p)
 61        {
 162            return false;
 63        }
 64
 9865        var left = BigInteger.ModPow(py, 2, s_p);
 9866        var right = (BigInteger.ModPow(px, 3, s_p) - 3 * px + s_b) % s_p;
 67
 9868        if (right.Sign < 0)
 69        {
 7270            right += s_p;
 71        }
 72
 9873        return left == right;
 74    }
 75}