예제 #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);
        }
예제 #3
0
        public void GeneratePublicKeyFromPrivateWithSomeManipulationEnsureNoLongerValidKeyPair()
        {
            var privateKey     = new BitString("4C089A9597865D316B5163A01F85458A0B954CD542B9B2D83E39CB3CBA010441");
            var expectedPublic = new BitString("EBB9897DF6C5E4E42999578ECA0F48B0985FF99032E80244C4679032F1132A24");

            // Gen public key from private
            var subject = new EdDsa(EntropyProviderTypes.Testable);

            subject.AddEntropy(privateKey.ToPositiveBigInteger());

            var factory = new EdwardsCurveFactory();
            var curve   = factory.GetCurve(Curve.Ed25519);

            var domainParams = new EdDomainParameters(curve, new NativeShaFactory());

            var keyPair = subject.GenerateKeyPair(domainParams).KeyPair;

            Assert.AreEqual(expectedPublic, keyPair.PublicQ, "expected public key");
            // Check x/y, record
            var x = new BitString("172B32732D86C9D9D63B11957AAD1364E9D3C1EC258CD13AB012E10648942C4E")
                    .ToPositiveBigInteger();
            var y = new BitString("242A13F1329067C44402E83290F95F98B0480FCA8E579929E4E4C5F67D89B9EB")
                    .ToPositiveBigInteger();

            // encode public key (done by default, and represented in Q
            // decode public key
            var decoded = domainParams.CurveE.Decode(keyPair.PublicQ);

            // check that the decoded x/y match the previous prior to encode/decode
            Assert.AreEqual(x, decoded.X, "x decoded matches");
            Assert.AreEqual(y, decoded.Y, "y decoded matches");

            Assert.IsTrue(subject.ValidateKeyPair(domainParams, keyPair).Success, "original key pair should be valid");

            // Modify the public key value until the point is no longer on the curve
            var modifiedPublicQ = curve.Decode(keyPair.PublicQ);

            var addedX = modifiedPublicQ.X;
            var addedY = modifiedPublicQ.Y;
            var adds   = 0;

            do
            {
                modifiedPublicQ = new EdPoint(modifiedPublicQ.X, modifiedPublicQ.Y + 8);
                addedX          = modifiedPublicQ.X + 41;
                addedY          = modifiedPublicQ.Y + 23;
                keyPair         = new EdKeyPair(curve.Encode(modifiedPublicQ), keyPair.PrivateD.GetDeepCopy());
                adds++;
            } while (subject.ValidateKeyPair(domainParams, keyPair).Success);

            Assert.IsFalse(curve.PointExistsOnCurve(modifiedPublicQ), "check point not on curve prior to encode");
            Assert.IsFalse(subject.ValidateKeyPair(domainParams, keyPair).Success, "keypair should not be valid.");
        }
예제 #4
0
        public void ShouldValidateKeyPairsCorrectlyWithNewMangleLogic(Curve curveEnum, string dHex, string qHex, bool expectedResult)
        {
            var d = LoadValue(dHex);
            var q = LoadValue(qHex);

            var factory = new EdwardsCurveFactory();
            var curve   = factory.GetCurve(curveEnum);

            var domainParams = new EdDomainParameters(curve, new NativeShaFactory());
            var keyPair      = new EdKeyPair(q, d);

            var subject = new EdDsa();

            var result = subject.ValidateKeyPair(domainParams, keyPair);

            Assert.AreEqual(expectedResult, result.Success);
        }
예제 #5
0
        public void ShouldGenerateKeyPairsCorrectly(Curve curveEnum, string dHex, string qHex)
        {
            var d = LoadValue(dHex);
            var q = LoadValue(qHex);

            var factory = new EdwardsCurveFactory();
            var curve   = factory.GetCurve(curveEnum);

            var domainParams = new EdDomainParameters(curve, new NativeShaFactory());

            var subject = new EdDsa(EntropyProviderTypes.Testable);

            subject.AddEntropy(d.ToPositiveBigInteger());

            var result = subject.GenerateKeyPair(domainParams);

            Assert.IsTrue(result.Success);
            Assert.AreEqual(result.KeyPair.PrivateD, d, "d");
            Assert.AreEqual(q, result.KeyPair.PublicQ, "q");
        }
예제 #6
0
        public void ShouldGenerateSignaturesCorrectly(Curve curveEnum, string dHex, string qHex, string msgHex, string sigHex)
        {
            var d           = LoadValue(dHex);
            var q           = LoadValue(qHex);
            var msg         = new BitString(msgHex);
            var expectedSig = LoadValue(sigHex);

            var factory = new EdwardsCurveFactory();
            var curve   = factory.GetCurve(curveEnum);

            var domainParams = new EdDomainParameters(curve, new NativeShaFactory());
            var keyPair      = new EdKeyPair(q, d);

            var subject = new EdDsa(EntropyProviderTypes.Testable);

            var result = subject.Sign(domainParams, keyPair, msg);

            Assert.IsTrue(result.Success);
            Assert.AreEqual(expectedSig, result.Signature.Sig, "sig");
        }
예제 #7
0
        public EdKeyPairValidateResult ValidateKeyPair(EdDomainParameters domainParameters, EdKeyPair keyPair)
        {
            // If D is out of bounds, reject
            if (keyPair.PrivateD.ToPositiveBigInteger() < 1 || keyPair.PrivateD.ToPositiveBigInteger() > NumberTheory.Pow2(domainParameters.CurveE.VariableB) - 1)
            {
                return new EdKeyPairValidateResult("D must be able to be a b-bit string");
            }

            EdPoint Q;
            try
            {
                Q = domainParameters.CurveE.Decode(keyPair.PublicQ);
            }
            catch (Exception e)
            {
                return new EdKeyPairValidateResult(e.Message);
            }

            // If Q == (0, 1), invalid
            if (Q.Equals(new EdPoint(0, 1)))
            {
                return new EdKeyPairValidateResult("Q cannot be neutral element");
            }

            // If Q is not a valid point on the specific curve, invalid
            // could make this more efficient
            if (!domainParameters.CurveE.PointExistsOnCurve(Q))
            {
                return new EdKeyPairValidateResult("Q does not lie on the curve");
            }

            // If n * Q == 0, valid
            // This is fast because the scalar (n) is taken modulo n... so it's 0
            if (domainParameters.CurveE.Multiply(Q, domainParameters.CurveE.OrderN).Equals(new EdPoint(0, 1)))
            {
                return new EdKeyPairValidateResult();
            }

            // Otherwise invalid
            return new EdKeyPairValidateResult("n * Q must equal (0, 1)");
        }
예제 #8
0
        public void ShouldValidateSignaturesCorrectly(Curve curveEnum, string dHex, string qHex, string msgHex, string sigHex, bool expectedResult)
        {
            var d           = LoadValue(dHex);
            var q           = LoadValue(qHex);
            var msg         = new BitString(msgHex);
            var expectedSig = LoadValue(sigHex);

            var factory = new EdwardsCurveFactory();
            var curve   = factory.GetCurve(curveEnum);

            var domainParams = new EdDomainParameters(curve, new NativeShaFactory());

            var keyPair   = new EdKeyPair(q);
            var signature = new EdSignature(expectedSig);

            var subject = new EdDsa();

            var result = subject.Verify(domainParams, keyPair, msg, signature);

            Assert.AreEqual(expectedResult, result.Success);
        }
예제 #9
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);
        }
예제 #10
0
        public EdKeyPairGenerateResult GenerateKeyPair(EdDomainParameters domainParameters)
        {
            Sha = domainParameters.Hash;

            // Generate random number d
            var d = _entropyProvider.GetEntropy(1, NumberTheory.Pow2(domainParameters.CurveE.VariableB) - 1);

            // 1. Hash the private key
            // 2. Prune the buffer
            // Both accomplished by this function
            var h = HashPrivate(domainParameters, new BitString(d, domainParameters.CurveE.VariableB)).Buffer;

            // 3. Determine s
            var s = NumberTheory.Pow2(domainParameters.CurveE.VariableN) + h.ToPositiveBigInteger();

            // 4. Compute Q such that Q = s * G
            var Q = domainParameters.CurveE.Multiply(domainParameters.CurveE.BasePointG, s);

            // Encode Q
            var qEncoded = EdPointEncoder.Encode(Q, domainParameters.CurveE.VariableB);

            // Return key pair (Q, d)
            return new EdKeyPairGenerateResult(new EdKeyPair(qEncoded, new BitString(d, domainParameters.CurveE.VariableB)));
        }
예제 #11
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");
        }
예제 #12
0
 public EdVerificationResult Verify(EdDomainParameters domainParameters, EdKeyPair keyPair, BitString message, EdSignature signature, bool preHash = false)
 {
     return Verify(domainParameters, keyPair, message, signature, null, preHash);
 }
예제 #13
0
 public EdSignatureResult Sign(EdDomainParameters domainParameters, EdKeyPair keyPair, BitString message, bool preHash = false)
 {
     return Sign(domainParameters, keyPair, message, null, preHash);
 }