bc-csharp
bc-csharp copied to clipboard
EC Public Key Calculate Y Coordinate from X
I am currently in need of verifying a block of data signed with a private EC key (P-256) and only have access to the X coordinate of the Public Key.
I have found that the Y coordinate of the Public Key can be calculated by using the following formula:
y^2 = b + x ( a + x^2)
Which is mostly achievable, however there is no BigInteger Square Root function that I can find.
Could you please point me towards a Square Root function or possibly where I may be going wrong / something I have missed?
An EC private key doesn't have an X coordinate, rather it is just a single scalar (it's the public key that is a point with X,Y coordinates). You could construct a private key object as follows:
Org.BouncyCastle.Math.BigInteger d = ...; // this would be the value you've been given
Org.BouncyCastle.Crypto.Parameters.ECDomainParameters dp = Org.BouncyCastle.Asn1.X9.ECNamedCurveTable.GetByName("P-256");
var privateKey = new Org.BouncyCastle.Crypto.Parameters.ECPrivateKeyParameters(d, dp);
and that could then be e.g. used with an ISigner of some kind to verify a signature. You'd need to provide more details about the signature to know exactly how.
Apologies, i wasn't clear in my original message.
I have the X coordinate of the Public Key, but no Y coordinate. I want to calculate the Y coordinate of the Public Key so that I can verify the block signed by the private key.
Below is my code:
ECDomainParameters domainParameters = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H, ecParams.GetSeed());
var G = ecParams.G;
ECCurve curve = ecParams.Curve;
var x = new BigInteger(1, publicKeyXCoord);
////calculate the y coordinate from the X
var a = curve.A.ToBigInteger();
var b = curve.B.ToBigInteger();
var y2 = b.Add(x.Multiply(a.Add(x.Square())));
var y = y2; // Need to get the square root of y2
ECPoint q = curve.CreatePoint(x, y);
var pubKeyParam = new ECPublicKeyParameters(q, domainParameters);
var verifier = SignerUtilities.GetSigner("SHA-256withECDSA");
verifier.Init(false, pubKeyParam);
verifier.BlockUpdate(dataToVerify, 0, dataToVerify.Length);
var result = verifier.VerifySignature(signature);
Are you sure you have "the X coordinate" and not a compressed public key? The X coordinate by itself would be a 32 byte value (and by itself it would not tell you which of two possible public keys it corresponds to - i.e. which square root), while a compressed public key would be 33 bytes beginning with a 0x02 or 0x03 byte.
If it's the 33 byte compressed key, then you just use curve.DecodePoint
and it will handle the details.
I am certain I have the X coordinate, it is of 32 bytes exactly and has been extracted from the public key.
In this case I have the full public key for reference, but for other cases I will not have the public key available (except the X coordinate)
Well the X coordinate alone is ambiguous, since there are two possible public keys with any given X coordinate. Either there is some unstated assumption about which key is meant, or something else is missing in your description.
ECCurve.DecodePoint
is the way to do what you are trying to do, but to do that you need to either be given the 33-byte compressed key, or I guess there could be a rule that says you always prepend 0x02 (or 0x03) to the X coordinate to create the compressed key.
Note that calculating the square root yourself doesn't escape the issue since there are two roots to choose from.