/// <summary> /// Point addition /// </summary> /// <param name="p1">point</param> /// <param name="p2">point</param> /// <returns>result</returns> private Ed25519Point PointAdd(Ed25519Point p1, Ed25519Point p2) { // based on draft-irtf-cfrg-eddsa-08 "Edwards-curve Digital Signature Algorithm (EdDSA)" var A = (this._p + p1.Y - p1.X) * (this._p + p2.Y - p2.X) % this._p; var B = (p1.Y + p1.X) * (p2.Y + p2.X) % this._p; var C = (p1.T << 1) * p2.T * this._d % this._p; var D = (p1.Z << 1) * p2.Z % this._p; var E = this._p + B - A; var F = this._p + D - C; var G = D + C; var H = B + A; var X3 = E * F % this._p; var Y3 = G * H % this._p; var Z3 = F * G % this._p; var T3 = E * H % this._p; return(new Ed25519Point(X3, Y3, Z3, T3)); }
/// <summary> /// Encodes a point to the octet string. /// </summary> /// <param name="q">a point</param> /// <param name="data">octet string returned</param> /// <returns>true if encoding succeeded, otherwise false.</returns> private bool EncodePoint(Ed25519Point q, out byte[] data) { // based on draft-irtf-cfrg-eddsa-08 "Edwards-curve Digital Signature Algorithm (EdDSA)" const int DATALEN = 32; var zinv = q.Z.ModInverse(this._p); var x = q.X * zinv % this._p; var y = q.Y * zinv % this._p; byte[] yBytes = y.GetBytes(); byte[] w = new byte[DATALEN]; Buffer.BlockCopy(yBytes, 0, w, w.Length - yBytes.Length, yBytes.Length); Array.Reverse(w); // to little endian if (x % 2u != 0) { w[DATALEN - 1] |= 0x80; // set MSB } data = w; return(true); }
/// <summary> /// Point multiplication /// </summary> /// <param name="k">scalar value</param> /// <param name="p">point</param> /// <returns>result</returns> private Ed25519Point PointMul(BigInteger k, Ed25519Point p) { Ed25519Point mp = p; Ed25519Point q = new Ed25519Point(0, 1, 1, 0); // Neutral element int kBitCount = k.BitCount(); byte[] kBytes = k.GetBytes(); int kOffset = kBytes.Length - 1; for (int i = 0; i < kBitCount; ++i) { if (i > 0) { mp = PointAdd(mp, mp); } if ((kBytes[kOffset - i / 8] & (byte)(1 << (i % 8))) != 0) { q = PointAdd(q, mp); } } return(q); }
/// <summary> /// Point multiplication /// </summary> /// <param name="k">scalar value</param> /// <param name="p">point</param> /// <returns>result</returns> private Ed25519Point PointMul(BigInteger k, Ed25519Point p) { Ed25519Point mp = p; Ed25519Point q = new Ed25519Point(0, 1, 1, 0); // Neutral element int kBitCount = k.BitCount(); byte[] kBytes = k.GetBytes(); int kOffset = kBytes.Length - 1; for (int i = 0; i < kBitCount; ++i) { if (i > 0) { mp = PointAdd(mp, mp); } if ((kBytes[kOffset - i / 8] & (byte)(1 << (i % 8))) != 0) { q = PointAdd(q, mp); } } return q; }
/// <summary> /// Point addition /// </summary> /// <param name="p1">point</param> /// <param name="p2">point</param> /// <returns>result</returns> private Ed25519Point PointAdd(Ed25519Point p1, Ed25519Point p2) { // based on draft-irtf-cfrg-eddsa-08 "Edwards-curve Digital Signature Algorithm (EdDSA)" var A = (this._p + p1.Y - p1.X) * (this._p + p2.Y - p2.X) % this._p; var B = (p1.Y + p1.X) * (p2.Y + p2.X) % this._p; var C = (p1.T << 1) * p2.T * this._d % this._p; var D = (p1.Z << 1) * p2.Z % this._p; var E = this._p + B - A; var F = this._p + D - C; var G = D + C; var H = B + A; var X3 = E * F % this._p; var Y3 = G * H % this._p; var Z3 = F * G % this._p; var T3 = E * H % this._p; return new Ed25519Point(X3, Y3, Z3, T3); }
/// <summary> /// Encodes a point to the octet string. /// </summary> /// <param name="q">a point</param> /// <param name="data">octet string returned</param> /// <returns>true if encoding succeeded, otherwise false.</returns> private bool EncodePoint(Ed25519Point q, out byte[] data) { // based on draft-irtf-cfrg-eddsa-08 "Edwards-curve Digital Signature Algorithm (EdDSA)" const int DATALEN = 32; var zinv = q.Z.ModInverse(this._p); var x = q.X * zinv % this._p; var y = q.Y * zinv % this._p; byte[] yBytes = y.GetBytes(); byte[] w = new byte[DATALEN]; Buffer.BlockCopy(yBytes, 0, w, w.Length - yBytes.Length, yBytes.Length); Array.Reverse(w); // to little endian if (x % 2u != 0) { w[DATALEN - 1] |= 0x80; // set MSB } data = w; return true; }
/// <summary> /// Decode the octet string to a point. /// </summary> /// <param name="data">point data</param> /// <param name="point"></param> /// <returns>true if decoding succeeded, otherwise false.</returns> private bool DecodePoint(byte[] data, out Ed25519Point point) { // based on draft-irtf-cfrg-eddsa-08 "Edwards-curve Digital Signature Algorithm (EdDSA)" const int DATALEN = 32; if (data.Length != DATALEN) { point = null; return false; } // note that the byte order of the data is little endian byte[] w = (byte[])data.Clone(); int sign = w[DATALEN - 1] >> 7; // MSB represents the sign of x w[DATALEN - 1] &= 0x7f; Array.Reverse(w); // to big endian var y = new BigInteger(w); if (y >= _p) { point = null; return false; } // recover x var y2 = y * y; var x2 = (((this._p + y2 - 1) % this._p) * (this._d * y2 + 1).ModInverse(this._p)) % this._p; BigInteger x; if (x2 == 0) { if (sign != 0) { point = null; return false; } else { x = 0; } } else { x = x2.ModPow((this._p + 3) >> 3, this._p); if ((x * x) % this._p != x2) { // square root of -1 x = x * (new BigInteger(2)).ModPow((this._p - 1) >> 2, this._p) % this._p; if ((x * x) % this._p != x2) { point = null; return false; } } if ((x % 2u) != (uint)sign) { x = _p - x; } } point = new Ed25519Point(x, y, 1, (x * y) % this._p); return true; }
/// <summary> /// Decode the octet string to a point. /// </summary> /// <param name="data">point data</param> /// <param name="point"></param> /// <returns>true if decoding succeeded, otherwise false.</returns> private bool DecodePoint(byte[] data, out Ed25519Point point) { // based on draft-irtf-cfrg-eddsa-08 "Edwards-curve Digital Signature Algorithm (EdDSA)" const int DATALEN = 32; if (data.Length != DATALEN) { point = null; return(false); } // note that the byte order of the data is little endian byte[] w = (byte[])data.Clone(); int sign = w[DATALEN - 1] >> 7; // MSB represents the sign of x w[DATALEN - 1] &= 0x7f; Array.Reverse(w); // to big endian var y = new BigInteger(w); if (y >= _p) { point = null; return(false); } // recover x var y2 = y * y; var x2 = (((this._p + y2 - 1) % this._p) * (this._d * y2 + 1).ModInverse(this._p)) % this._p; BigInteger x; if (x2 == 0) { if (sign != 0) { point = null; return(false); } else { x = 0; } } else { x = x2.ModPow((this._p + 3) >> 3, this._p); if ((x * x) % this._p != x2) { // square root of -1 x = x * (new BigInteger(2)).ModPow((this._p - 1) >> 2, this._p) % this._p; if ((x * x) % this._p != x2) { point = null; return(false); } } if ((x % 2u) != (uint)sign) { x = _p - x; } } point = new Ed25519Point(x, y, 1, (x * y) % this._p); return(true); }