public void Ok()
        {
            BigInteger seed = new BigInteger(DateTime.Now.Ticks) << DateTime.Now.Second;

            var rnd       = new Random(BitConverter.ToInt32(seed.ToByteArray().Take(4).ToArray()));
            var publicKey = new byte[32];
            var secretKey = new byte[64];
            var payload   = new byte[64];

            rnd.NextBytes(publicKey);
            rnd.NextBytes(secretKey);
            rnd.NextBytes(payload);

            var pk = AddressUtils.GetPublicKeyFromAddr("5GWYBLjRtCQLXQmcyyRa6KaF1ihuqLjvVDE2gswJsEMxd9Qm");

            var kp  = new SR25519Keypair(pk.Bytes, secretKey);
            var sig = SR25519.Sign(payload, (ulong)payload.Length, kp);

            var arrayNotSame = new Func <byte[], bool>((btArr) => {
                return(btArr.GroupBy((i) => i).Count() > 50);
            });

            Assert.True(sig.Length == 64);
            Assert.True(arrayNotSame(sig));
        }
        public void ShouldGenerateKeypair()
        {
            // Arrange.
            var seed           = "fac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e";
            var expectedPublic = "46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a";

            // Act.
            var derived = SR25519.GenerateKeypairFromSeed(seed);

            // Assert.
            Assert.AreEqual(expectedPublic, Utils.ByteArrayToHexString(derived.Public));
        }
        public void ShouldSoftDerivePublicKey()
        {
            // Arrange.
            var publicKey      = "46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a";
            var cc             = "0c666f6f00000000000000000000000000000000000000000000000000000000";
            var expectedPublic = "40b9675df90efa6069ff623b0fdfcf706cd47ca7452a5056c7ad58194d23440a";

            // Act.
            var derived = SR25519.SoftDerivePublicKey(publicKey, cc);

            // Assert.
            Assert.AreEqual(expectedPublic, Utils.ByteArrayToHexString(derived));
        }
        public void ShouldVrfSignAndVerifyMessageBytes()
        {
            // Arrange.
            var message1 = "Hello, world!";
            var message2 = "Hello, Earth!";

            // Act.
            var keys = SR25519.GenerateKeypairFromSeed(
                "f6dbe0604959f8d4f53ef58754f44391c69cfc87f1b97872abef63161e18c885");

            var threshold = Enumerable.Repeat((byte)0xFF, 16).ToArray();

            VrfSignResult signResult;
            var           signVerification = SR25519.VrfSignIfLess(
                Encoding.UTF8.GetBytes(message1),
                keys,
                threshold,
                out signResult
                );

            Assert.IsTrue(signVerification);
            Assert.AreEqual(Sr25519SignatureResult.Ok, signResult.Result);
            Assert.IsTrue(signResult.IsLess);

            VrfVerifyResult verifyResult;
            var             verification1 = SR25519.VrfVerify(
                Encoding.UTF8.GetBytes(message1),
                keys.Public,
                signResult.Output,
                signResult.Proof,
                threshold,
                out verifyResult
                );

            Assert.IsTrue(verification1);
            Assert.AreEqual(Sr25519SignatureResult.Ok, verifyResult.Result);
            Assert.IsTrue(verifyResult.IsLess);

            var verification2 = SR25519.VrfVerify(
                Encoding.UTF8.GetBytes(message2),
                keys.Public,
                signResult.Output,
                signResult.Proof,
                threshold,
                out verifyResult
                );

            Assert.IsFalse(verification2);
            Assert.AreEqual(Sr25519SignatureResult.EquationFalse, verifyResult.Result);
            Assert.IsFalse(verifyResult.IsLess);
        }
        public void ShouldSoftDeriveKeypair()
        {
            // Arrange.
            var keys = SR25519.GenerateKeypairFromSeed(
                "fac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e");
            var cc             = "0c666f6f00000000000000000000000000000000000000000000000000000000";
            var expectedPublic = "40b9675df90efa6069ff623b0fdfcf706cd47ca7452a5056c7ad58194d23440a";

            // Act.
            var derived = SR25519.SoftDeriveKeypair(keys, cc);

            // Assert.
            Assert.AreEqual(expectedPublic, Utils.ByteArrayToHexString(derived.Public));
        }
        public void ShouldHardDeriveKeypair()
        {
            // Arrange.
            var keys = SR25519.GenerateKeypairFromSeed(
                "fac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e");
            var cc             = "14416c6963650000000000000000000000000000000000000000000000000000";
            var expectedPublic = "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";

            // Act.
            var derived = SR25519.HardDeriveKeypair(keys, cc);

            // Assert.
            Assert.AreEqual(expectedPublic, Utils.ByteArrayToHexString(derived.Public));
        }
        public void ShouldSignAndVerifyMessageString()
        {
            // Arrange.
            var message1 = "positive test message";
            var message2 = "negative test message";

            // Act.
            var keys = SR25519.GenerateKeypairFromSeed(
                "f6dbe0604959f8d4f53ef58754f44391c69cfc87f1b97872abef63161e18c885");
            var sig           = SR25519.Sign(message1, keys);
            var verification1 = SR25519.Verify(message1, sig, keys.Public);
            var verification2 = SR25519.Verify(message2, sig, keys.Public);

            // Assert.
            Assert.IsTrue(verification1);
            Assert.IsFalse(verification2);
        }
        public void ShouldSignAndVerifyMessageBytes()
        {
            // Arrange.
            var message1 = "010203040506070809";
            var message2 = "090807060504030201";

            // Act.
            var keys = SR25519.GenerateKeypairFromSeed(
                "f6dbe0604959f8d4f53ef58754f44391c69cfc87f1b97872abef63161e18c885");
            var sig = SR25519.Sign(Utils.HexStringToByteArray(message1), keys);

            var verification1 = SR25519.Verify(Utils.HexStringToByteArray(message1), sig, keys.Public);
            var verification2 = SR25519.Verify(Utils.HexStringToByteArray(message2), sig, keys.Public);

            // Assert.
            Assert.IsTrue(verification1);
            Assert.IsFalse(verification2);
        }
        private string ExtrinsicQueryString(byte[] encodedMethodBytes, string module, string method, Address sender, string privateKey)
        {
            _logger.Info("=== Started Invoking Extrinsic ===");

            // Get account Nonce
            var nonce        = GetAccountNonce(sender);
            var compactNonce = Scale.EncodeCompactInteger(nonce);

            _logger.Info($"sender nonce: {nonce}");

            byte[] mmBuf = new byte[3];
            // Module + Method
            var absoluteIndex = _protocolParams.Metadata.GetModuleIndex(module, false);

            mmBuf[0] = (byte)_protocolParams.Metadata.GetModuleIndex(module, true);
            mmBuf[1] = (byte)_protocolParams.Metadata.GetCallMethodIndex(absoluteIndex, method);

            // Address separator
            mmBuf[2] = Consts.ADDRESS_SEPARATOR;

            Extrinsic ce = new Extrinsic();

            var completeMessage = new byte[encodedMethodBytes.Length + 3];

            mmBuf.CopyTo(completeMessage.AsMemory());
            encodedMethodBytes.CopyTo(completeMessage.AsMemory(3));

            // memcpy(completeMessage + 3, encodedMethodBytes, encodedMethodBytesSize);

            ce.Signature.Version = Consts.SIGNATURE_VERSION;
            var senderPK = _protocolParams.Metadata.GetPublicKeyFromAddr(sender);

            ce.Signature.SignerPublicKey = senderPK.Bytes;
            ce.Signature.Nonce           = nonce;
            ce.Signature.Era             = ExtrinsicEra.IMMORTAL_ERA;

            // Format signature payload
            SignaturePayload sp = new SignaturePayload();

            sp.Nonce = nonce;

            sp.MethodBytesLength = encodedMethodBytes.Length + 3;
            sp.MethodBytes       = completeMessage;
            sp.Era = ExtrinsicEra.IMMORTAL_ERA;
            sp.AuthoringBlockHash = _protocolParams.GenesisBlockHash;

            // Serialize and Sign payload
            var  signaturePayloadBytes = new byte[Consts.MAX_METHOD_BYTES_SZ];
            long payloadLength         = sp.SerializeBinary(ref signaturePayloadBytes);

            var secretKeyVec = Converters.StringToByteArray(privateKey);

            // p/invoke version
            var kp  = new SR25519Keypair(ce.Signature.SignerPublicKey, secretKeyVec);
            var sig = SR25519.Sign(signaturePayloadBytes, (ulong)payloadLength, kp);

            ce.Signature.Sr25519Signature = sig;

            //// adopted version
            //var sr25519 = new Sr25519();
            //var message = signaturePayloadBytes.AsMemory().Slice(0, (int)payloadLength).ToArray();
            //var sig2 = sr25519.Sign(secretKeyVec, te.Signature.SignerPublicKey, message);
            //te.Signature.Sr25519Signature = sig2.ToBytes();

            // Copy signature bytes to transaction
            ce.Signature.Sr25519Signature = sig;
            var length        = Consts.DEFAULT_FIXED_EXSTRINSIC_SIZE + encodedMethodBytes.Length + compactNonce.Length - 1;
            var compactLength = Scale.EncodeCompactInteger(length);

            /////////////////////////////////////////
            // Serialize message signature and write to buffer

            long writtenLength = 0;
            var  buf           = new byte[2048];
            var  buf2          = new List <byte>();

            // Length
            writtenLength += Scale.WriteCompactToBuf(compactLength, ref buf, writtenLength);

            // Signature version
            buf[writtenLength++] = ce.Signature.Version;

            // Address separator
            buf[writtenLength++] = Consts.ADDRESS_SEPARATOR;

            // Signer public key
            ce.Signature.SignerPublicKey.CopyTo(buf.AsMemory((int)writtenLength));

            writtenLength += Consts.SR25519_PUBLIC_SIZE;

            // SR25519 Signature
            ce.Signature.Sr25519Signature.CopyTo(buf.AsMemory((int)writtenLength));
            writtenLength += Consts.SR25519_SIGNATURE_SIZE;

            // Nonce
            writtenLength += Scale.WriteCompactToBuf(compactNonce, ref buf, writtenLength);

            // Extrinsic Era
            buf[writtenLength++] = (byte)ce.Signature.Era;

            // Serialize and send transaction
            var teBytes = new byte[Consts.MAX_METHOD_BYTES_SZ];

            teBytes = buf;
            completeMessage.AsMemory().CopyTo(teBytes.AsMemory((int)writtenLength));

            long teByteLength = writtenLength + encodedMethodBytes.Length + 3;

            return($"0x{Converters.ByteArrayToString(teBytes, (int)teByteLength)}");
        }
        public int SignAndSendTransfer(string sender, string privateKey, string recipient, BigInteger amount, Action <string> callback)
        {
            _logger.Info("=== Starting a Transfer Extrinsic ===");

            // Get account Nonce
            var address = new Address {
                Symbols = sender
            };
            var nonce = GetAccountNonce(address);

            _logger.Info($"sender nonce: {nonce} ");

            // Format transaction
            TransferExtrinsic te = new TransferExtrinsic();

            te.Method.ModuleIndex = _protocolParams.BalanceModuleIndex;
            te.Method.MethodIndex = _protocolParams.TransferMethodIndex;

            var recipientPK = _protocolParams.Metadata.GetPublicKeyFromAddr(new Address(recipient));

            te.Method.ReceiverPublicKey = recipientPK.Bytes;
            te.Method.Amount            = amount;
            te.Signature.Version        = Consts.SIGNATURE_VERSION;
            var senderPK = _protocolParams.Metadata.GetPublicKeyFromAddr(new Address(sender));

            te.Signature.SignerPublicKey = senderPK.Bytes;
            te.Signature.Nonce           = nonce;
            te.Signature.Era             = ExtrinsicEra.IMMORTAL_ERA;

            // Format signature payload
            SignaturePayload sp = new SignaturePayload();

            sp.Nonce = nonce;
            var methodBytes = new byte[Consts.MAX_METHOD_BYTES_SZ];

            sp.MethodBytesLength = (int)te.SerializeMethodBinary(ref methodBytes);
            sp.MethodBytes       = methodBytes;
            sp.Era = ExtrinsicEra.IMMORTAL_ERA;
            sp.AuthoringBlockHash = _protocolParams.GenesisBlockHash;

            // Serialize and Sign payload
            var  signaturePayloadBytes = new byte[Consts.MAX_METHOD_BYTES_SZ];
            long payloadLength         = sp.SerializeBinary(ref signaturePayloadBytes);

            byte[] secretKeyVec = Converters.StringToByteArray(privateKey);

            // p/invoke version
            var kp  = new SR25519Keypair(te.Signature.SignerPublicKey, secretKeyVec);
            var sig = SR25519.Sign(signaturePayloadBytes, (ulong)payloadLength, kp);

            te.Signature.Sr25519Signature = sig;

            //// adopted version
            //var sr25519 = new Sr25519();
            //var message = signaturePayloadBytes.AsMemory().Slice(0, (int)payloadLength).ToArray();
            //var sig2 = sr25519.Sign(secretKeyVec, te.Signature.SignerPublicKey, message);
            //te.Signature.Sr25519Signature = sig2.ToBytes();

            // Serialize and send transaction
            var    teBytes      = new byte[Consts.MAX_METHOD_BYTES_SZ];
            long   teByteLength = te.SerializeBinary(ref teBytes);
            string teStr        = $"0x{Converters.ByteArrayToString(teBytes, (int)teByteLength)}";

            var query = new JObject {
                { "method", "author_submitAndWatchExtrinsic" }, { "params", new JArray {
                                                                      teStr
                                                                  } }
            };

            // Send == Subscribe callback to completion
            return(Subscribe(query, (json) =>
            {
                callback(json.ToString());
            }));
        }