I tried to implement the JavaScript code to recover y coordinate from a compressed P-256 X point at https://stackoverflow.com/a/30431547/1332416.
To my eyes it looks like the following code is equivalent in .NET/C#, but this does not seem to work as the result is not correct. So it stands to conclude there is something wrong with the code, but I seem to be unable to spot the problem. Can someone else perhaps see it?
/*
Curves and their primes
NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1
NIST P-384 (secp384r1) 2^384 - 2^128 - 2^96 + 2^32 - 1
NIST P-521 (secp521r1) 2^521 - 1
const two = new bigInt(2),
// 115792089210356248762697446949407573530086143415290314195533631308867097853951
prime = two.pow(256).sub( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).sub(1),
b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
// Pre-computed value, or literal
pIdent = prime.add(1).divide(4); // 28948022302589062190674361737351893382521535853822578548883407827216774463488
*/
var key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var keyParams = key.ExportParameters(includePrivateParameters: false);
var prime = BigInteger.Parse("115792089210356248762697446949407573530086143415290314195533631308867097853951");
var b = BigInteger.Parse("41058363725152142129326129780047268409114441015993725554835256314039467401291");
var pIdent = BigInteger.Parse("28948022302589062190674361737351893382521535853822578548883407827216774463488");
// Other combinations of isUnsighed and isBigEndian do not seem to work.
var xBig = new BigInteger(keyParams.Q.X, isUnsigned: false, isBigEndian: false);
var y = BigInteger.ModPow(BigInteger.Pow(xBig, 3) - (xBig * 3) + b, pIdent, prime);
// Either yarr0 or yarr1 should match with yParams. This is not the case here now. Calculation going wrong?
var yParams = keyParams.Q.Y;
var yarr0 = y.ToByteArray();
var yarr1 = (prime - y).ToByteArray();
(Code to add and check 0x02
, 0x03
or 0x04
or is omitted on purpose as .NET by default does not do that and it's not need for this minimal case. This also lacks other checks to see if points are on the curve etc.)