Example #1
0
        public EdSignatureResult Sign(EdDomainParameters domainParameters, EdKeyPair keyPair, BitString message, BitString context, bool preHash = false)
        {
            Sha = domainParameters.Hash;

            // If preHash version, then the message becomes the hash of the message
            if (preHash)
            {
                message = Sha.HashMessage(message, 512).Digest;
            }

            // 1. Hash the private key
            var hashResult = HashPrivate(domainParameters, keyPair.PrivateD);

            // 2. Compute r
            // Determine dom. Empty if ed25519. Different for preHash function
            BitString dom;
            if (preHash)
            {
                dom = domainParameters.CurveE.CurveName == Curve.Ed448 ? Dom4(1, context) : Dom2(1, context);
            }
            else
            {
                dom = domainParameters.CurveE.CurveName == Curve.Ed448 ? Dom4(0, context) : new BitString("");
            }

            // Hash (dom4 || Prefix || message)
            var rBits = Sha.HashMessage(BitString.ConcatenateBits(dom, BitString.ConcatenateBits(hashResult.HDigest2, message)), 912).Digest;

            // Convert rBits to little endian and mod order n
            var r = BitString.ReverseByteOrder(rBits).ToPositiveBigInteger() % domainParameters.CurveE.OrderN;

            // 3. Compute [r]G. R is the encoding of [r]G
            var rG = domainParameters.CurveE.Multiply(domainParameters.CurveE.BasePointG, r);

            // Encode the point rG into a b-bit bitstring
            var R = domainParameters.CurveE.Encode(rG);

            // 4. Define S
            // Hash (dom4 || R || Q || M). Need to use dom4 if ed448
            var hashData = BitString.ConcatenateBits(keyPair.PublicQ, message);
            hashData = BitString.ConcatenateBits(dom, BitString.ConcatenateBits(R, hashData));
            var hash = Sha.HashMessage(hashData, 912).Digest;

            // Convert hash to int from little endian and mod order n
            var hashInt = BitString.ReverseByteOrder(hash).ToPositiveBigInteger() % domainParameters.CurveE.OrderN;

            // Determine s as done in key generation
            var s = NumberTheory.Pow2(domainParameters.CurveE.VariableN) + hashResult.Buffer.ToPositiveBigInteger();

            // Calculate S as an BigInteger
            var Sint = (r + (hashInt * s)).PosMod(domainParameters.CurveE.OrderN);

            // Encode S in little endian
            var S = BitString.ReverseByteOrder(new BitString(Sint, domainParameters.CurveE.VariableB));

            // 5. Form the signature by concatenating R and S
            return new EdSignatureResult(new EdSignature(R, S));
        }
        public static (EdPoint R, BigInteger s) DecodeSig(EdDomainParameters domainParameters, EdSignature sig)
        {
            var rBits = sig.Sig.MSBSubstring(0, domainParameters.CurveE.VariableB);
            var sBits = sig.Sig.Substring(0, domainParameters.CurveE.VariableB);

            var R = domainParameters.CurveE.Decode(rBits);
            var s = BitString.ReverseByteOrder(sBits).ToPositiveBigInteger();

            return(R, s);
        }
Example #3
0
        public static BitString Encode(EdPoint point, int b)
        {
            var encoding = new BitString(point.Y, b);

            var xBit = new BitString(point.X, b).GetLeastSignificantBits(1);

            var bytes = new byte[b / 8];

            bytes[0] = 1 << 7;
            if (xBit.Equals(BitString.One()))
            {
                encoding = encoding.OR(new BitString(bytes));
            }
            else
            {
                encoding = encoding.AND(new BitString(bytes).NOT());
            }

            return(BitString.ReverseByteOrder(encoding));      // switch to little endian
        }
Example #4
0
        /// <summary>
        /// Hashs private key and formats both the prefix (used in signing) and A (used in generating the public key)
        /// </summary>
        /// <param name="domainParameters"></param>
        /// <param name="d"></param>
        /// <returns></returns>
        private (BitString Buffer, BitString HDigest2) HashPrivate(EdDomainParameters domainParameters, BitString d)
        {
            // 912 is the output length for Ed448 when using SHAKE. It will not affect SHA512 output length for Ed25519.
            var h = Sha.HashMessage(d, 912).Digest;

            // Split the hash result in half
            var hDigest2 = h.Substring(0, domainParameters.CurveE.VariableB);
            var buffer = BitString.ReverseByteOrder(h.MSBSubstring(0, domainParameters.CurveE.VariableB));

            // Prune the buffer
            for (int i = 0; i < domainParameters.CurveE.VariableC; i++)
            {
                buffer.Bits.Set(i, false);
            }
            for (int i = domainParameters.CurveE.VariableN; i < buffer.Bits.Length; i++)
            {
                buffer.Bits.Set(i, false);
            }

            return (buffer, hDigest2);
        }
Example #5
0
        public static EdPoint Decode(BitString encoded, BigInteger p, BigInteger a, BigInteger d, int b)
        {
            var encodedBits = BitString.ReverseByteOrder(encoded);       // switch to big endian
            var x           = encodedBits.GetMostSignificantBits(1).ToPositiveBigInteger();
            var YBits       = BitString.ConcatenateBits(BitString.Zero(), encodedBits.GetLeastSignificantBits(b - 1));
            var Y           = YBits.ToPositiveBigInteger();

            BigInteger X;
            var        u = ((Y * Y) - 1) % p;
            var        v = ((d * Y * Y) - a) % p;

            if (p % 4 == 3)
            {
                var w        = (u * u * u * v * BigInteger.ModPow(BigInteger.ModPow(u, 5, p) * BigInteger.ModPow(v, 3, p) % p, (p - 3) / 4, p)) % p;
                var vwSquare = (v * ((w * w) % p)) % p;
                if (vwSquare == u)
                {
                    X = w;
                }
                else
                {
                    throw new Exception("Square root does not exist");
                }
            }
            else if (p % 8 == 5)
            {
                var w        = (u * v * v * v * BigInteger.ModPow(u * BigInteger.ModPow(v, 7, p), (p - 5) / 8, p)) % p;
                var vwSquare = (v * ((w * w) % p)) % p;
                if (vwSquare == u)
                {
                    X = w;
                }
                else if (vwSquare == (p - u).PosMod(p))
                {
                    X = (w * BigInteger.ModPow(2, (p - 1) / 4, p)) % p;
                }
                else
                {
                    throw new Exception("Square root does not exist");
                }
            }
            else
            {
                // need to use Tonelli-Shanks algorithm in SP800-186 Appendix E
                throw new NotImplementedException("Need to implement Tonelli-Shanks");
            }

            if (X == 0 && x == 1)
            {
                throw new Exception("Point Decode failed");
            }

            if (X % 2 == x)
            {
                return(new EdPoint(X, Y));
            }
            else
            {
                return(new EdPoint(p - X, Y));
            }
        }
Example #6
0
        public EdVerificationResult Verify(EdDomainParameters domainParameters, EdKeyPair keyPair, BitString message, EdSignature signature, BitString context, bool preHash = false)
        {
            Sha = domainParameters.Hash;

            // If preHash version, then the message becomes the hash of the message
            if (preHash)
            {
                message = Sha.HashMessage(message, 512).Digest;
            }

            // 1. Decode R, s, and Q
            EdPoint R;
            BigInteger s;
            EdPoint Q;
            try
            {
                var sigDecoded = SignatureDecoderHelper.DecodeSig(domainParameters, signature);
                R = sigDecoded.R;
                s = sigDecoded.s;
                Q = domainParameters.CurveE.Decode(keyPair.PublicQ);
            }
            catch (Exception e)
            {
                return new EdVerificationResult(e.Message);
            }

            // 2. Concatenate R || Q || M
            var hashData = BitString.ConcatenateBits(domainParameters.CurveE.Encode(R), BitString.ConcatenateBits(keyPair.PublicQ, message));

            // 3. Compute t
            // Determine dom. Empty if ed25519. Different for preHash function
            BitString dom;
            if (preHash)
            {
                dom = domainParameters.CurveE.CurveName == Curve.Ed448 ? Dom4(1, context) : Dom2(1, context);
            }
            else
            {
                dom = domainParameters.CurveE.CurveName == Curve.Ed448 ? Dom4(0, context) : new BitString("");
            }

            // Compute Hash(dom4 || HashData)
            var hash = Sha.HashMessage(BitString.ConcatenateBits(dom, hashData), 912).Digest;

            // Interpret hash as a little endian integer
            var t = BitString.ReverseByteOrder(hash).ToPositiveBigInteger();

            // 4. Check the verification equation [2^c * s]G = [2^c]R + [2^c * t]Q
            // 2^c
            var powC = NumberTheory.Pow2(domainParameters.CurveE.VariableC);

            // [2^c * s]G
            var lhs = domainParameters.CurveE.Multiply(domainParameters.CurveE.BasePointG, (powC * s).PosMod(domainParameters.CurveE.OrderN));

            // [2^c]R
            var rhs1 = domainParameters.CurveE.Multiply(R, powC);

            // [2^c * t]Q
            var rhs2 = domainParameters.CurveE.Multiply(Q, (powC * t).PosMod(domainParameters.CurveE.OrderN));

            // [2^c]R + [2^c * t]Q
            var rhs = domainParameters.CurveE.Add(rhs1, rhs2);

            if (lhs.Equals(rhs))
            {
                return new EdVerificationResult();
            }

            return new EdVerificationResult("The verification equation is not satisfied. Signature not valid");
        }