Exemplo n.º 1
0
        public void CanSerialize()
        {
            var    key     = new BlindingRsaKey();
            string jsonKey = key.ToJson();
            var    key2    = BlindingRsaKey.CreateFromJson(jsonKey);

            Assert.Equal(key, key2);
            Assert.Equal(key.PubKey, key2.PubKey);

            var jsonPubKey = key.PubKey.ToJson();
            var pubKey2    = BlindingRsaPubKey.CreateFromJson(jsonPubKey);

            Assert.Equal(key.PubKey, pubKey2);

            // generate blinding factor with pubkey
            // blind message
            byte[] message = Encoding.UTF8.GetBytes("áéóúősing me please~!@#$%^&*())_+");
            var(BlindingFactor, BlindedData) = pubKey2.Blind(message);

            // sign the blinded message
            var signature = key.SignBlindedData(BlindedData);

            // unblind the signature
            var unblindedSignature = key2.PubKey.UnblindSignature(signature, BlindingFactor);

            // verify the original data is signed
            Assert.True(key2.PubKey.Verify(unblindedSignature, message));
        }
Exemplo n.º 2
0
        public void CanEncodeDecodeBlinding()
        {
            var key = new BlindingRsaKey();

            byte[] message     = Encoding.UTF8.GetBytes("áéóúősing me please~!@#$%^&*())_+");
            byte[] blindedData = key.PubKey.Blind(message).BlindedData;
            string encoded     = ByteHelpers.ToHex(blindedData);

            byte[] decoded = ByteHelpers.FromHex(encoded);
            Assert.Equal(blindedData, decoded);
        }
Exemplo n.º 3
0
        public async static Task InitializeAsync()
        {
            _dataDir          = null;
            CoinJoinStorePath = Path.Combine(DataDir, "CoinJoins.json");

            await InitializeConfigAsync();

            string rsaPath = Path.Combine(DataDir, "RsaKey.json");

            if (File.Exists(rsaPath))
            {
                string rsaKeyJson = await File.ReadAllTextAsync(rsaPath, Encoding.UTF8);

                RsaKey = BlindingRsaKey.CreateFromJson(rsaKeyJson);
            }
            else
            {
                RsaKey = new BlindingRsaKey();
                await File.WriteAllTextAsync(rsaPath, RsaKey.ToJson(), Encoding.UTF8);

                Console.WriteLine($"Created RSA key at: {rsaPath}");
            }

            RpcClient = new RPCClient(
                credentials: new RPCCredentialString
            {
                UserPassword = new NetworkCredential(Config.BitcoinRpcUser, Config.BitcoinRpcPassword)
            },
                network: Config.Network);
            await AssertRpcNodeFullyInitializedAsync();

            if (File.Exists(CoinJoinStorePath))
            {
                CoinJoinStore = await CoinJoinStore.CreateFromFileAsync(CoinJoinStorePath);
            }
            else
            {
                CoinJoinStore = new CoinJoinStore();
            }

            await InitializeUtxoRefereeAsync();

            StateMachine          = new TumblerStateMachine();
            StateMachineJobCancel = new CancellationTokenSource();
            StateMachineJob       = StateMachine.StartAsync(StateMachineJobCancel.Token);
        }
Exemplo n.º 4
0
        public void CanBlindSign()
        {
            // generate rsa keypair
            var key = new BlindingRsaKey();

            // generate blinding factor with pubkey
            // blind message
            byte[] message = Encoding.UTF8.GetBytes("áéóúősing me please~!@#$%^&*())_+");
            var(BlindingFactor, BlindedData) = key.PubKey.Blind(message);

            // sign the blinded message
            var signature = key.SignBlindedData(BlindedData);

            // unblind the signature
            var unblindedSignature = key.PubKey.UnblindSignature(signature, BlindingFactor);

            // verify the original data is signed
            Assert.True(key.PubKey.Verify(unblindedSignature, message));
        }
Exemplo n.º 5
0
        public CcjCoordinator(Network network, string folderPath, RPCClient rpc, CcjRoundConfig roundConfig)
        {
            Network     = Guard.NotNull(nameof(network), network);
            FolderPath  = Guard.NotNullOrEmptyOrWhitespace(nameof(folderPath), folderPath, trim: true);
            RpcClient   = Guard.NotNull(nameof(rpc), rpc);
            RoundConfig = Guard.NotNull(nameof(roundConfig), roundConfig);

            Rounds         = new List <CcjRound>();
            RoundsListLock = new AsyncLock();

            CoinJoins            = new List <uint256>();
            UnconfirmedCoinJoins = new List <uint256>();
            CoinJoinsLock        = new AsyncLock();

            Directory.CreateDirectory(FolderPath);

            UtxoReferee = new UtxoReferee(Network, FolderPath, RpcClient);

            // Initialize RsaKey
            string rsaKeyPath = Path.Combine(FolderPath, "RsaKey.json");

            if (File.Exists(rsaKeyPath))
            {
                string rsaKeyJson = File.ReadAllText(rsaKeyPath, encoding: Encoding.UTF8);
                RsaKey = BlindingRsaKey.CreateFromJson(rsaKeyJson);
            }
            else
            {
                RsaKey = new BlindingRsaKey();
                File.WriteAllText(rsaKeyPath, RsaKey.ToJson(), encoding: Encoding.UTF8);
                Logger.LogInfo <CcjCoordinator>($"Created RSA key at: {rsaKeyPath}");
            }

            if (File.Exists(CoinJoinsFilePath))
            {
                try
                {
                    var      toRemove = new List <string>();
                    string[] allLines = File.ReadAllLines(CoinJoinsFilePath);
                    foreach (string line in allLines)
                    {
                        uint256     txHash = new uint256(line);
                        RPCResponse getRawTransactionResponse = RpcClient.SendCommand(RPCOperations.getrawtransaction, txHash.ToString(), true);
                        if (string.IsNullOrWhiteSpace(getRawTransactionResponse?.ResultString))
                        {
                            toRemove.Add(line);
                        }
                        else
                        {
                            CoinJoins.Add(txHash);
                            if (getRawTransactionResponse.Result.Value <int>("confirmations") <= 0)
                            {
                                UnconfirmedCoinJoins.Add(txHash);
                            }
                        }
                    }

                    if (toRemove.Count != 0)                     // a little performance boost, it'll be empty almost always
                    {
                        var newAllLines = allLines.Where(x => !toRemove.Contains(x));
                        File.WriteAllLines(CoinJoinsFilePath, newAllLines);
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogWarning <CcjCoordinator>($"CoinJoins file got corrupted. Deleting {CoinJoinsFilePath}. {ex.GetType()}: {ex.Message}");
                    File.Delete(CoinJoinsFilePath);
                }
            }
        }
Exemplo n.º 6
0
        public CcjCoordinator(Network network, string folderPath, RPCClient rpc, CcjRoundConfig roundConfig)
        {
            Network     = Guard.NotNull(nameof(network), network);
            FolderPath  = Guard.NotNullOrEmptyOrWhitespace(nameof(folderPath), folderPath, trim: true);
            RpcClient   = Guard.NotNull(nameof(rpc), rpc);
            RoundConfig = Guard.NotNull(nameof(roundConfig), roundConfig);

            Rounds         = new List <CcjRound>();
            RoundsListLock = new AsyncLock();

            CoinJoins            = new List <uint256>();
            UnconfirmedCoinJoins = new List <uint256>();
            CoinJoinsLock        = new AsyncLock();

            Directory.CreateDirectory(FolderPath);

            UtxoReferee = new UtxoReferee(Network, FolderPath, RpcClient, RoundConfig);

            // Initialize RsaKey
            string rsaKeyPath = Path.Combine(FolderPath, "RsaKey.json");

            if (File.Exists(rsaKeyPath))
            {
                string rsaKeyJson = File.ReadAllText(rsaKeyPath, encoding: Encoding.UTF8);
                RsaKey = BlindingRsaKey.CreateFromJson(rsaKeyJson);
            }
            else
            {
                RsaKey = new BlindingRsaKey();
                File.WriteAllText(rsaKeyPath, RsaKey.ToJson(), encoding: Encoding.UTF8);
                Logger.LogInfo <CcjCoordinator>($"Created RSA key at: {rsaKeyPath}");
            }

            if (File.Exists(CoinJoinsFilePath))
            {
                try
                {
                    var      toRemove = new List <string>();
                    string[] allLines = File.ReadAllLines(CoinJoinsFilePath);
                    foreach (string line in allLines)
                    {
                        try
                        {
                            uint256     txHash = new uint256(line);
                            RPCResponse getRawTransactionResponse = RpcClient.SendCommand(RPCOperations.getrawtransaction, txHash.ToString(), true);
                            CoinJoins.Add(txHash);
                            if (getRawTransactionResponse.Result.Value <int>("confirmations") <= 0)
                            {
                                UnconfirmedCoinJoins.Add(txHash);
                            }
                        }
                        catch (Exception ex)
                        {
                            toRemove.Add(line);

                            var logEntry = ex is RPCException rpce && rpce.RPCCode == RPCErrorCode.RPC_INVALID_ADDRESS_OR_KEY
                                                                ? $"CoinJoins file contains invalid transaction ID {line}"
                                                                : $"CoinJoins file got corrupted. Deleting offending line \"{line.Substring(0, 20)}\".";

                            Logger.LogWarning <CcjCoordinator>($"{logEntry}. {ex.GetType()}: {ex.Message}");
                        }
                    }

                    if (toRemove.Count != 0)                     // a little performance boost, it'll be empty almost always
                    {
                        var newAllLines = allLines.Where(x => !toRemove.Contains(x));
                        File.WriteAllLines(CoinJoinsFilePath, newAllLines);
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogWarning <CcjCoordinator>($"CoinJoins file got corrupted. Deleting {CoinJoinsFilePath}. {ex.GetType()}: {ex.Message}");
                    File.Delete(CoinJoinsFilePath);
                }
            }

            try
            {
                string roundCountFilePath = Path.Combine(folderPath, "RoundCount.txt");
                if (File.Exists(roundCountFilePath))
                {
                    string roundCount = File.ReadAllText(roundCountFilePath);
                    CcjRound.RoundCount = long.Parse(roundCount);
                }
                else
                {
                    // First time initializes (so the first constructor will increment it and we'll start from 1.)
                    CcjRound.RoundCount = 0;
                }
            }
            catch (Exception ex)
            {
                CcjRound.RoundCount = 0;
                Logger.LogInfo <CcjCoordinator>($"{nameof(CcjRound.RoundCount)} file was corrupt. Resetting to 0.");
                Logger.LogDebug <CcjCoordinator>(ex);
            }
        }