Beispiel #1
0
        private async Task CollectPiecesWithSecretSharingAsync(SecretSharingInformation secretSharingInformation,
                                                               Hash newInValue, string selfPubkey)
        {
            var encryptedPieces = new Dictionary <string, byte[]>();
            var decryptedPieces = new Dictionary <string, byte[]>();

            var minersCount  = secretSharingInformation.PreviousRound.RealTimeMinersInformation.Count;
            var minimumCount = minersCount.Mul(2).Div(3);
            var secretShares =
                SecretSharingHelper.EncodeSecret(newInValue.ToByteArray(), minimumCount, minersCount);

            foreach (var pair in secretSharingInformation.PreviousRound.RealTimeMinersInformation
                     .OrderBy(m => m.Value.Order).ToDictionary(m => m.Key, m => m.Value.Order))
            {
                var pubkey = pair.Key;
                var order  = pair.Value;

                var plainMessage      = secretShares[order - 1];
                var receiverPublicKey = ByteArrayHelper.HexStringToByteArray(pubkey);
                var encryptedPiece    = await _accountService.EncryptMessageAsync(receiverPublicKey, plainMessage);

                encryptedPieces[pubkey] = encryptedPiece;
                if (secretSharingInformation.PreviousRound.RealTimeMinersInformation.ContainsKey(selfPubkey) &&
                    secretSharingInformation.PreviousRound.RealTimeMinersInformation[selfPubkey].EncryptedPieces
                    .ContainsKey(pubkey))
                {
                    secretSharingInformation.PreviousRound.RealTimeMinersInformation[selfPubkey]
                    .EncryptedPieces[pubkey]
                        = ByteString.CopyFrom(encryptedPiece);
                }
                else
                {
                    continue;
                }

                if (!secretSharingInformation.PreviousRound.RealTimeMinersInformation.ContainsKey(pubkey))
                {
                    continue;
                }

                var encryptedShares =
                    secretSharingInformation.PreviousRound.RealTimeMinersInformation[pubkey].EncryptedPieces;
                if (!encryptedShares.Any())
                {
                    continue;
                }
                var interestingMessage = encryptedShares[selfPubkey];
                var senderPublicKey    = ByteArrayHelper.HexStringToByteArray(pubkey);

                var decryptedPiece =
                    await _accountService.DecryptMessageAsync(senderPublicKey, interestingMessage.ToByteArray());

                decryptedPieces[pubkey] = decryptedPiece;
                secretSharingInformation.PreviousRound.RealTimeMinersInformation[pubkey].DecryptedPieces[selfPubkey]
                    = ByteString.CopyFrom(decryptedPiece);
            }

            _encryptedPieces[secretSharingInformation.CurrentRoundId] = encryptedPieces;
            _decryptedPieces[secretSharingInformation.CurrentRoundId] = decryptedPieces;
        }
Beispiel #2
0
        public void HashSharingTest(int threshold, int totalParts)
        {
            var hash   = Hash.Generate().ToHex();
            var parts  = SecretSharingHelper.EncodeSecret(hash, threshold, totalParts);
            var result = SecretSharingHelper.DecodeSecret(parts.Take(threshold).ToList(),
                                                          Enumerable.Range(1, threshold).ToList(), threshold);

            Assert.Equal(hash, result);
        }
Beispiel #3
0
        private void RevealSharedInValues(Round currentRound, string publicKey)
        {
            if (!currentRound.RealTimeMinersInformation.ContainsKey(publicKey))
            {
                return;
            }

            if (!TryToGetPreviousRoundInformation(out var previousRound))
            {
                return;
            }

            var minersCount  = currentRound.RealTimeMinersInformation.Count;
            var minimumCount = minersCount.Mul(2).Div(3);

            minimumCount = minimumCount == 0 ? 1 : minimumCount;

            foreach (var pair in previousRound.RealTimeMinersInformation.OrderBy(m => m.Value.Order))
            {
                // Skip himself.
                if (pair.Key == publicKey)
                {
                    continue;
                }

                var publicKeyOfAnotherMiner     = pair.Key;
                var anotherMinerInPreviousRound = pair.Value;

                if (anotherMinerInPreviousRound.EncryptedInValues.Count < minimumCount)
                {
                    continue;
                }
                if (anotherMinerInPreviousRound.DecryptedPreviousInValues.Count < minersCount)
                {
                    continue;
                }

                // Reveal another miner's in value for target round:

                var orders = anotherMinerInPreviousRound.DecryptedPreviousInValues.Select((t, i) =>
                                                                                          previousRound.RealTimeMinersInformation.Values
                                                                                          .First(m => m.Pubkey ==
                                                                                                 anotherMinerInPreviousRound.DecryptedPreviousInValues.Keys.ToList()[i]).Order)
                             .ToList();

                var sharedParts = anotherMinerInPreviousRound.DecryptedPreviousInValues.Values.ToList()
                                  .Select(s => s.ToByteArray()).ToList();

                var revealedInValue =
                    Hash.FromRawBytes(SecretSharingHelper.DecodeSecret(sharedParts, orders, minimumCount));

                Context.LogDebug(() =>
                                 $"Revealed in value of {publicKeyOfAnotherMiner} of round {previousRound.RoundNumber}: {revealedInValue}");

                currentRound.RealTimeMinersInformation[publicKeyOfAnotherMiner].PreviousInValue = revealedInValue;
            }
        }
Beispiel #4
0
        public void HashSharingTest(int threshold, int totalParts)
        {
            var hash      = Hash.FromString("hash");
            var hashBytes = hash.ToByteArray();
            var parts     = SecretSharingHelper.EncodeSecret(hashBytes, threshold, totalParts);
            var result    = SecretSharingHelper.DecodeSecret(parts.Take(threshold).ToList(),
                                                             Enumerable.Range(1, threshold).ToList(), threshold);

            Assert.Equal(hashBytes, result);
        }
Beispiel #5
0
        public void SharingTest(string str, int threshold, int totalParts)
        {
            var parts = SecretSharingHelper.EncodeSecret(str, threshold, totalParts);

            Assert.Equal(totalParts, parts.Count);

            var result = SecretSharingHelper.DecodeSecret(parts.Take(threshold).ToList(),
                                                          Enumerable.Range(1, threshold).ToList(), threshold);

            Assert.Equal(str, result);
        }
Beispiel #6
0
        private void RevealPreviousInValues(SecretSharingInformation secretSharingInformation, string selfPubkey)
        {
            var round        = secretSharingInformation.PreviousRound;
            var minersCount  = round.RealTimeMinersInformation.Count;
            var minimumCount = minersCount.Mul(2).Div(3);

            minimumCount = minimumCount == 0 ? 1 : minimumCount;

            var revealedInValues = new Dictionary <string, Hash>();

            foreach (var pair in round.RealTimeMinersInformation.OrderBy(m => m.Value.Order))
            {
                // Skip himself.
                if (pair.Key == selfPubkey)
                {
                    continue;
                }

                var pubkey       = pair.Key;
                var minerInRound = pair.Value;

                if (minerInRound.EncryptedPieces.Count < minimumCount)
                {
                    continue;
                }
                if (minerInRound.DecryptedPieces.Count < minersCount)
                {
                    continue;
                }

                // Reveal another miner's in value for target round:

                var orders = minerInRound.DecryptedPieces.Select((t, i) =>
                                                                 round.RealTimeMinersInformation.Values
                                                                 .First(m => m.Pubkey ==
                                                                        minerInRound.DecryptedPieces.Keys.ToList()[i]).Order)
                             .ToList();

                var sharedParts = minerInRound.DecryptedPieces.Values.ToList()
                                  .Select(s => s.ToByteArray()).ToList();

                var revealedInValue =
                    Hash.FromRawBytes(SecretSharingHelper.DecodeSecret(sharedParts, orders, minimumCount));

                Logger.LogDebug($"Revealed in value of {pubkey} of round {round.RoundNumber}: {revealedInValue}");

                revealedInValues[pubkey] = revealedInValue;
            }

            _revealedInValues[secretSharingInformation.CurrentRoundId] = revealedInValues;
        }
        private void ShareInValueOfCurrentRound(Round currentRound, Round previousRound, Hash inValue, string publicKey)
        {
            if (!currentRound.RealTimeMinersInformation.ContainsKey(publicKey)) return;

            var minersCount = currentRound.RealTimeMinersInformation.Count;
            var minimumCount = minersCount.Mul(2).Div(3);
            minimumCount = minimumCount == 0 ? 1 : minimumCount;

            var secretShares = SecretSharingHelper.EncodeSecret(inValue.ToByteArray(), minimumCount, minersCount);
            foreach (var pair in currentRound.RealTimeMinersInformation.OrderBy(m => m.Value.Order)
                .ToDictionary(m => m.Key, m => m.Value.Order))
            {
                // Skip himself.
                if (pair.Key == publicKey) continue;

                var publicKeyOfAnotherMiner = pair.Key;
                var orderOfAnotherMiner = pair.Value;

                // Share in value of current round:

                // Encrypt every secret share with other miner's public key, then fill EncryptedInValues field.
                var plainMessage = secretShares[orderOfAnotherMiner - 1];
                var receiverPublicKey = ByteArrayHelper.HexStringToByteArray(publicKeyOfAnotherMiner);
                var encryptedInValue = Context.EncryptMessage(receiverPublicKey, plainMessage);
                currentRound.RealTimeMinersInformation[publicKey].EncryptedInValues
                    .Add(publicKeyOfAnotherMiner, ByteString.CopyFrom(encryptedInValue));

                // Decrypt shares published during previous round:

                // First round of every term don't have previous in values.
                if (IsFirstRoundOfCurrentTerm(out _)) continue;

                // Become a miner from this round.
                if (!previousRound.RealTimeMinersInformation.ContainsKey(publicKeyOfAnotherMiner)) continue;

                // No need to decrypt shares of miners who already revealed their previous in values.
                if (currentRound.RealTimeMinersInformation[publicKeyOfAnotherMiner].PreviousInValue != null) continue;

                var encryptedShares =
                    previousRound.RealTimeMinersInformation[publicKeyOfAnotherMiner].EncryptedInValues;
                if (!encryptedShares.Any()) continue;
                var interestingMessage = encryptedShares[publicKey];
                var senderPublicKey = ByteArrayHelper.HexStringToByteArray(publicKeyOfAnotherMiner);
                // Decrypt another miner's secret share then add a result to this miner's DecryptedInValues field.
                var decryptedInValue = Context.DecryptMessage(senderPublicKey, interestingMessage.ToByteArray());
                currentRound.RealTimeMinersInformation[publicKeyOfAnotherMiner].DecryptedPreviousInValues
                    .Add(publicKey, ByteString.CopyFrom(decryptedInValue));
            }
        }
Beispiel #8
0
        public void OffChain_DecryptMessage_Test()
        {
            var message = Hash.FromString("message").ToByteArray();
            var secrets =
                SecretSharingHelper.EncodeSecret(message, MinimumCount, EconomicContractsTestConstants.InitialCoreDataCenterCount);
            var encryptedValues = new Dictionary <string, byte[]>();
            var decryptedValues = new Dictionary <string, byte[]>();
            var ownerKeyPair    = InitialCoreDataCenterKeyPairs[0];
            var othersKeyPairs  = InitialCoreDataCenterKeyPairs.Skip(1).ToList();
            var decryptResult   = new byte[0];

            var initial = 0;

            foreach (var keyPair in othersKeyPairs)
            {
                var encryptedMessage = CryptoHelper.EncryptMessage(ownerKeyPair.PrivateKey, keyPair.PublicKey,
                                                                   secrets[initial++]);
                encryptedValues.Add(keyPair.PublicKey.ToHex(), encryptedMessage);
            }

            // Check encrypted values.
            encryptedValues.Count.ShouldBe(EconomicContractsTestConstants.InitialCoreDataCenterCount - 1);

            // Others try to recover.
            foreach (var keyPair in othersKeyPairs)
            {
                var cipherMessage  = encryptedValues[keyPair.PublicKey.ToHex()];
                var decryptMessage =
                    CryptoHelper.DecryptMessage(ownerKeyPair.PublicKey, keyPair.PrivateKey, cipherMessage);
                decryptedValues.Add(keyPair.PublicKey.ToHex(), decryptMessage);

                if (decryptedValues.Count >= MinimumCount)
                {
                    decryptResult = SecretSharingHelper.DecodeSecret(
                        decryptedValues.Values.ToList(),
                        Enumerable.Range(1, MinimumCount).ToList(), MinimumCount);
                    break;
                }
            }

            decryptResult.ShouldBe(message);
        }
        public void OffChainDecryptMessageTest()
        {
            var message         = Hash.Generate().ToHex();
            var secrets         = SecretSharingHelper.EncodeSecret(message, MinimumCount, MinersCount);
            var encryptedValues = new Dictionary <string, byte[]>();
            var decryptedValues = new Dictionary <string, byte[]>();
            var ownerKeyPair    = InitialMinersKeyPairs[0];
            var othersKeyPairs  = InitialMinersKeyPairs.Skip(1).ToList();
            var decryptResult   = "";

            var initial = 0;

            foreach (var keyPair in othersKeyPairs)
            {
                var encryptedMessage = CryptoHelpers.EncryptMessage(ownerKeyPair.PrivateKey, keyPair.PublicKey,
                                                                    Encoding.UTF8.GetBytes(secrets[initial++]));
                encryptedValues.Add(keyPair.PublicKey.ToHex(), encryptedMessage);
            }

            // Check encrypted values.
            encryptedValues.Count.ShouldBe(MinersCount - 1);

            // Others try to recover.
            foreach (var keyPair in othersKeyPairs)
            {
                var cipherMessage  = encryptedValues[keyPair.PublicKey.ToHex()];
                var decryptMessage =
                    CryptoHelpers.DecryptMessage(ownerKeyPair.PublicKey, keyPair.PrivateKey, cipherMessage);
                decryptedValues.Add(keyPair.PublicKey.ToHex(), decryptMessage);

                if (decryptedValues.Count >= MinimumCount)
                {
                    decryptResult = SecretSharingHelper.DecodeSecret(
                        decryptedValues.Values.Select(v => Encoding.UTF8.GetString(v)).ToList(),
                        Enumerable.Range(1, MinimumCount).ToList(), MinimumCount);
                    break;
                }
            }

            decryptResult.ShouldBe(message);
        }
 private void TestSecretSharing()
 {
     SecretSharingHelper.DecodeSecret(new List <byte[]>(), new List <int>(), 2);
 }
Beispiel #11
0
        private void ShareAndRecoverInValue(Round round, Round previousRound, Hash inValue, string publicKey)
        {
            var minersCount  = round.RealTimeMinersInformation.Count;
            var minimumCount = (int)(minersCount * 2d / 3);

            minimumCount = minimumCount == 0 ? 1 : minimumCount;

            var secretShares = SecretSharingHelper.EncodeSecret(inValue.ToHex(), minimumCount, minersCount);

            foreach (var pair in round.RealTimeMinersInformation.OrderBy(m => m.Value.Order))
            {
                var currentPublicKey = pair.Key;

                if (currentPublicKey == publicKey)
                {
                    continue;
                }

                // Encrypt every secret share with other miner's public key, then fill own EncryptedInValues field.
                var plainMessage      = Encoding.UTF8.GetBytes(secretShares[pair.Value.Order - 1]);
                var receiverPublicKey = ByteArrayHelpers.FromHexString(currentPublicKey);
                var encryptedInValue  = Context.EncryptMessage(receiverPublicKey, plainMessage);
                round.RealTimeMinersInformation[publicKey].EncryptedInValues
                .Add(currentPublicKey, ByteString.CopyFrom(encryptedInValue));

                if (previousRound.RoundId == 0 || round.TermNumber != previousRound.TermNumber)
                {
                    continue;
                }

                var encryptedInValues = previousRound.RealTimeMinersInformation[currentPublicKey].EncryptedInValues;
                if (encryptedInValues.Any())
                {
                    var interestingMessage = encryptedInValues[publicKey];
                    var senderPublicKey    = ByteArrayHelpers.FromHexString(currentPublicKey);
                    // Decrypt every miner's secret share then add a result to other miner's DecryptedInValues field.
                    var decryptedInValue = Context.DecryptMessage(senderPublicKey, interestingMessage.ToByteArray());
                    round.RealTimeMinersInformation[pair.Key].DecryptedPreviousInValues
                    .Add(publicKey, ByteString.CopyFrom(decryptedInValue));
                }

                if (pair.Value.DecryptedPreviousInValues.Count < minimumCount)
                {
                    continue;
                }

                Context.LogDebug(() => "Now it's enough to recover previous in values.");

                // Try to recover others' previous in value.
                var orders = pair.Value.DecryptedPreviousInValues.Select((t, i) =>
                                                                         previousRound.RealTimeMinersInformation.Values
                                                                         .First(m => m.PublicKey == pair.Value.DecryptedPreviousInValues.Keys.ToList()[i]).Order)
                             .ToList();

                var previousInValue = Hash.LoadHex(SecretSharingHelper.DecodeSecret(
                                                       pair.Value.DecryptedPreviousInValues.Values.ToList()
                                                       .Select(s => Encoding.UTF8.GetString(s.ToByteArray())).ToList(),
                                                       orders, minimumCount));
                if (round.RealTimeMinersInformation[pair.Key].PreviousInValue != null &&
                    round.RealTimeMinersInformation[pair.Key].PreviousInValue != previousInValue)
                {
                    Context.LogDebug(() => "Different previous in value.");
                }
                round.RealTimeMinersInformation[pair.Key].PreviousInValue = previousInValue;
            }
        }
Beispiel #12
0
        public Task AddSharingInformationAsync(LogEvent logEvent)
        {
            try
            {
                var secretSharingInformation = new SecretSharingInformation();
                secretSharingInformation.MergeFrom(logEvent);

                var newInValue = GenerateInValue(secretSharingInformation);
                _inValueCacheService.AddInValue(secretSharingInformation.CurrentRoundId, newInValue);

                //Logger.LogTrace(
                //$"Handling sharing information: {secretSharingInformation}. New in value: {newInValue}");

                if (secretSharingInformation.PreviousRound.RealTimeMinersInformation.Count == 1)
                {
                    return(Task.CompletedTask);
                }

                var encryptedPieces = new Dictionary <string, byte[]>();
                var decryptedPieces = new Dictionary <string, byte[]>();

                var minersCount  = secretSharingInformation.PreviousRound.RealTimeMinersInformation.Count;
                var minimumCount = minersCount.Mul(2).Div(3);
                var secretShares =
                    SecretSharingHelper.EncodeSecret(newInValue.ToByteArray(), minimumCount, minersCount);
                var selfPubkey = AsyncHelper.RunSync(_accountService.GetPublicKeyAsync).ToHex();
                foreach (var pair in secretSharingInformation.PreviousRound.RealTimeMinersInformation
                         .OrderBy(m => m.Value.Order).ToDictionary(m => m.Key, m => m.Value.Order))
                {
                    var pubkey = pair.Key;
                    var order  = pair.Value;

                    var plainMessage      = secretShares[order - 1];
                    var receiverPublicKey = ByteArrayHelper.HexStringToByteArray(pubkey);
                    var encryptedPiece    = AsyncHelper.RunSync(() =>
                                                                _accountService.EncryptMessageAsync(receiverPublicKey, plainMessage));
                    encryptedPieces[pubkey] = encryptedPiece;
                    if (secretSharingInformation.PreviousRound.RealTimeMinersInformation.ContainsKey(selfPubkey) &&
                        secretSharingInformation.PreviousRound.RealTimeMinersInformation[selfPubkey].EncryptedPieces
                        .ContainsKey(pubkey))
                    {
                        secretSharingInformation.PreviousRound.RealTimeMinersInformation[selfPubkey]
                        .EncryptedPieces[pubkey]
                            = ByteString.CopyFrom(encryptedPiece);
                    }
                    else
                    {
                        continue;
                    }

                    if (!secretSharingInformation.PreviousRound.RealTimeMinersInformation.ContainsKey(pubkey))
                    {
                        continue;
                    }

                    var encryptedShares =
                        secretSharingInformation.PreviousRound.RealTimeMinersInformation[pubkey].EncryptedPieces;
                    if (!encryptedShares.Any())
                    {
                        continue;
                    }
                    var interestingMessage = encryptedShares[selfPubkey];
                    var senderPublicKey    = ByteArrayHelper.HexStringToByteArray(pubkey);

                    var decryptedPiece = AsyncHelper.RunSync(() =>
                                                             _accountService.DecryptMessageAsync(senderPublicKey, interestingMessage.ToByteArray()));
                    decryptedPieces[pubkey] = decryptedPiece;
                    secretSharingInformation.PreviousRound.RealTimeMinersInformation[pubkey].DecryptedPieces[selfPubkey]
                        = ByteString.CopyFrom(decryptedPiece);
                }

                _encryptedPieces[secretSharingInformation.CurrentRoundId] = encryptedPieces;
                _decryptedPieces[secretSharingInformation.CurrentRoundId] = decryptedPieces;

                RevealPreviousInValues(secretSharingInformation, selfPubkey);

                Logger.LogTrace($"Final secret sharing information: {secretSharingInformation}");
            }
            catch (Exception e)
            {
                Logger.LogError($"Error in AddSharingInformationAsync.\n{e.Message}\n{e.StackTrace}");
            }

            return(Task.CompletedTask);
        }