private byte[] ConvertEdPublicKeyToMontgomery(byte[] edPublicKey) { int[] x = X25519Field.Create(); int[] oneMinusY = X25519Field.Create(); int[] aY = new int[X25519Field.Size]; X25519Field.Decode(edPublicKey, 0, aY); X25519Field.One(oneMinusY); X25519Field.Sub(oneMinusY, aY, oneMinusY); X25519Field.One(x); X25519Field.Add(x, aY, x); X25519Field.Inv(oneMinusY, oneMinusY); X25519Field.Mul(x, oneMinusY, x); byte[] xpublicKey = new byte[X25519PublicKeyParameters.KeySize]; X25519Field.Encode(x, xpublicKey, 0); // UPDATE: the reality of the situation is that it's OK to check if it works, because the vast, vast majority work right off the bat, and it takes very little time to generate // I have no idea, but it has always worked....: I am very unhappy with it (tested 1m times, didn't fail). But since I don't trust it, I check it too (when it is possible) if (xpublicKey[X25519PublicKeyParameters.KeySize - 1] >= 128) { // Take off 128 xpublicKey[X25519PublicKeyParameters.KeySize - 1] -= 128; // We need to add 19 as well... xpublicKey[0] = (byte)((xpublicKey[0] + 19) % 256); if (xpublicKey[0] < 19) { int index = 0; while (true) { index++; if (xpublicKey[index] != 255) { xpublicKey[index] += 1; break; } xpublicKey[index] = 0; } } } return(xpublicKey); }
private static bool DecodePointVar(byte[] p, int pOff, bool negate, PointExt r) { byte[] py = Arrays.CopyOfRange(p, pOff, pOff + PointBytes); if (!CheckPointVar(py)) { return(false); } int x_0 = (py[PointBytes - 1] & 0x80) >> 7; py[PointBytes - 1] &= 0x7F; X25519Field.Decode(py, 0, r.y); int[] u = X25519Field.Create(); int[] v = X25519Field.Create(); X25519Field.Sqr(r.y, u); X25519Field.Mul(C_d, u, v); X25519Field.SubOne(u); X25519Field.AddOne(v); if (!X25519Field.SqrtRatioVar(u, v, r.x)) { return(false); } X25519Field.Normalize(r.x); if (x_0 == 1 && X25519Field.IsZeroVar(r.x)) { return(false); } if (negate ^ (x_0 != (r.x[0] & 1))) { X25519Field.Negate(r.x, r.x); } PointExtendXY(r); return(true); }