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; }
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); }
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; } }
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); }
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); }
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)); } }
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); }
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; } }
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); }