Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace tpke keys with ts keys #300

Open
wants to merge 12 commits into
base: dev
Choose a base branch
from
2 changes: 1 addition & 1 deletion src/Lachain.Consensus/CommonSubset/CommonSubset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using Lachain.Consensus.BinaryAgreement;
using Lachain.Consensus.Messages;
using Lachain.Consensus.ReliableBroadcast;
using Lachain.Crypto.TPKE;
using Lachain.Crypto.ThresholdEncryption;

namespace Lachain.Consensus.CommonSubset
{
Expand Down
115 changes: 25 additions & 90 deletions src/Lachain.Consensus/HoneyBadger/HoneyBadger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
using Lachain.Consensus.CommonSubset;
using Lachain.Consensus.Messages;
using Lachain.Crypto;
using Lachain.Crypto.TPKE;
using Lachain.Crypto.ThresholdEncryption;
using Lachain.Crypto.ThresholdSignature;
using Lachain.Proto;
using Lachain.Utility.Utils;

Expand All @@ -16,41 +17,19 @@ public class HoneyBadger : AbstractProtocol
private static readonly ILogger<HoneyBadger> Logger = LoggerFactory.GetLoggerForClass<HoneyBadger>();

private readonly HoneyBadgerId _honeyBadgerId;
private readonly PrivateKey _privateKey;
private readonly EncryptedShare?[] _receivedShares;
private readonly IRawShare?[] _shares;
private readonly ISet<PartiallyDecryptedShare>[] _decryptedShares;
private readonly bool[][] _receivedShareFrom;
private readonly bool[] _taken;
private ResultStatus _requested;
private IRawShare? _rawShare;
private EncryptedShare? _encryptedShare;
private ISet<IRawShare>? _result;
private bool _takenSet;
private bool _skipDecryptedShareValidation;
private IThresholdEncryptor _thresholdEncryptor;

public HoneyBadger(HoneyBadgerId honeyBadgerId, IPublicConsensusKeySet wallet,
PrivateKey privateKey, bool skipDecryptedShareValidation, IConsensusBroadcaster broadcaster)
PrivateKeyShare privateKey, bool skipDecryptedShareValidation, IConsensusBroadcaster broadcaster)
: base(wallet, honeyBadgerId, broadcaster)
{
_honeyBadgerId = honeyBadgerId;
_privateKey = privateKey;
_receivedShares = new EncryptedShare[N];
_decryptedShares = new ISet<PartiallyDecryptedShare>[N];
for (var i = 0; i < N; ++i)
{
_decryptedShares[i] = new HashSet<PartiallyDecryptedShare>();
}

_taken = new bool[N];
_shares = new IRawShare[N];
_requested = ResultStatus.NotRequested;
_skipDecryptedShareValidation = skipDecryptedShareValidation;
_receivedShareFrom = new bool[N][];
for (var iter = 0 ; iter < N ; iter++)
{
_receivedShareFrom[iter] = new bool[N];
}
_thresholdEncryptor = new ThresholdEncryptor(privateKey, wallet.ThresholdSignaturePublicKeySet, skipDecryptedShareValidation);
}

public override void ProcessMessage(MessageEnvelope envelope)
Expand Down Expand Up @@ -120,7 +99,7 @@ private void CheckEncryption()
{
if (_rawShare == null) return;
if (_encryptedShare != null) return;
_encryptedShare = Wallet.TpkePublicKey.Encrypt(_rawShare);
_encryptedShare = _thresholdEncryptor.Encrypt(_rawShare);
Broadcaster.InternalRequest(
new ProtocolRequest<CommonSubsetId, EncryptedShare>(Id, new CommonSubsetId(_honeyBadgerId),
_encryptedShare));
Expand All @@ -141,32 +120,17 @@ private void CheckResult()
private void HandleCommonSubset(ProtocolResult<CommonSubsetId, ISet<EncryptedShare>> result)
{
Logger.LogTrace($"Common subset finished {result.From}");
foreach (var share in result.Result)
var encryptedShares = result.Result.ToList();
var decryptedShares = _thresholdEncryptor.AddEncryptedShares(encryptedShares);
foreach (var dec in decryptedShares)
{
var dec = _privateKey.Decrypt(share);
_taken[share.Id] = true;
_receivedShares[share.Id] = share;
if (_decryptedShares[share.Id].Count > 0) // if we have any partially decrypted shares for this share - verify them
{
if (!_skipDecryptedShareValidation)
{
if (Wallet.GetTpkeVerificationKey(share.Id) is null)
_decryptedShares[share.Id].Clear();
else
_decryptedShares[share.Id] = _decryptedShares[share.Id]
.Where(ps => Wallet.GetTpkeVerificationKey(ps.DecryptorId)!.VerifyShare(share, ps))
.ToHashSet();
}
}

// todo think about async access to protocol method. This may pose threat to protocol internal invariants
CheckDecryptedShares(share.Id);
CheckDecryptedShares(dec.ShareId);
Broadcaster.Broadcast(CreateDecryptedMessage(dec));
}

_takenSet = true;

foreach (var share in result.Result)
foreach (var share in encryptedShares)
{
CheckDecryptedShares(share.Id);
}
Expand All @@ -178,7 +142,7 @@ protected virtual ConsensusMessage CreateDecryptedMessage(PartiallyDecryptedShar
{
var message = new ConsensusMessage
{
Decrypted = Wallet.TpkePublicKey.Encode(share)
Decrypted = share.Encode()
};
return message;
}
Expand All @@ -189,42 +153,20 @@ protected virtual ConsensusMessage CreateDecryptedMessage(PartiallyDecryptedShar
// and the value of 'share.ShareId' needs to be checked. If it is out of range, it can throw exception
private void HandleDecryptedMessage(TPKEPartiallyDecryptedShareMessage msg, int senderId)
{
PartiallyDecryptedShare? share = null;
bool added;
try
{
// DecryptorId is basically the validator id, it tells us who decrypted the message, so it should be same
if (msg.DecryptorId != senderId)
throw new Exception($"Validator {senderId} sends message with decryptor id {msg.DecryptorId}");
// same decrypted id more than once prevents full decrypt
if (_receivedShareFrom[msg.ShareId][msg.DecryptorId])
throw new Exception($"validator {senderId} sent decrypted messsage for share {msg.ShareId} twice");

_receivedShareFrom[msg.ShareId][msg.DecryptorId] = true;
// Converting any random bytes to G1 is not possible
share = Wallet.TpkePublicKey.Decode(msg);
if (!(_receivedShares[share.ShareId] is null))
{
if (!_skipDecryptedShareValidation)
{
if (Wallet.GetTpkeVerificationKey(share.DecryptorId) is null)
throw new Exception("No verification key for this sender");
if (!Wallet.GetTpkeVerificationKey(share.DecryptorId)!.VerifyShare(
_receivedShares[share.ShareId]!, share))
throw new Exception("Invalid share");
}
}

_decryptedShares[share.ShareId].Add(share);
added = _thresholdEncryptor.AddDecryptedShare(msg, senderId);
}
catch (Exception ex)
{
share = null;
added = false;
var pubKey = Broadcaster.GetPublicKeyById(senderId)!.ToHex();
Logger.LogWarning($"Exception occured handling Decrypted message: {msg} from {senderId} ({pubKey}), exception: {ex}");
}

if (!(share is null))
CheckDecryptedShares(share.ShareId);
if (added)
CheckDecryptedShares(msg.ShareId);
}

// There are several potential issues in Wallet.TpkePublicKey.FullDecrypt() that needs to be resolved.
Expand All @@ -236,27 +178,20 @@ private void HandleDecryptedMessage(TPKEPartiallyDecryptedShareMessage msg, int
// corresponding validator id (depends on the relation of decryptor id and validator id)
private void CheckDecryptedShares(int id)
{
if (!_takenSet) return;
if (!_taken[id]) return;
if (_decryptedShares[id].Count < F + 1) return;
if (_shares[id] != null) return;
if (_receivedShares[id] is null) return;
Logger.LogTrace($"Collected {_decryptedShares[id].Count} shares for {id}, can decrypt now");
_shares[id] = Wallet.TpkePublicKey.FullDecrypt(_receivedShares[id]!, _decryptedShares[id].ToList());
CheckAllSharesDecrypted();
var decrypted = _thresholdEncryptor.CheckDecryptedShares(id);
if (decrypted)
CheckAllSharesDecrypted();
}

private void CheckAllSharesDecrypted()
{
if (!_takenSet) return;
if (_result != null) return;

if (_taken.Zip(_shares, (b, share) => b && share is null).Any(x => x)) return;

_result = _taken.Zip(_shares, (b, share) => (b, share))
.Where(x => x.b)
.Select(x => x.share ?? throw new Exception("impossible"))
.ToHashSet();
if (!_thresholdEncryptor.GetResult(out var fullDecryptedShares))
{
return;
}
_result = fullDecryptedShares;

CheckResult();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using Google.Protobuf;
using Lachain.Consensus.Messages;
using Lachain.Crypto;
using Lachain.Crypto.TPKE;
using Lachain.Crypto.ThresholdEncryption;
using Lachain.Logger;
using Lachain.Proto;
using Lachain.Utility.Serialization;
Expand Down
4 changes: 2 additions & 2 deletions src/Lachain.Core/Consensus/EraBroadcaster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ public void Terminate()
case HoneyBadgerId hbId:
var hb = new HoneyBadger(
hbId, _validators!,
_wallet.GetTpkePrivateKeyForBlock((ulong) _era - 1)
?? throw new InvalidOperationException($"No TPKE keys present for era {_era}"),
_wallet.GetThresholdSignatureKeyForBlock((ulong) _era - 1)
?? throw new InvalidOperationException($"No Threshold keys present for era {_era}"),
!HardforkHeights.IsHardfork_12Active((ulong)_era > 2 * StakingContract.CycleDuration ? (ulong)_era - 2 * StakingContract.CycleDuration : 0),
this
);
Expand Down
15 changes: 9 additions & 6 deletions src/Lachain.Crypto/DefaultCrypto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using Lachain.Crypto.ThresholdEncryption;
using Lachain.Crypto.ThresholdSignature;
using Lachain.Logger;
using Lachain.Utility.Benchmark;
Expand Down Expand Up @@ -54,18 +55,20 @@ public static void ResetBenchmark()
Logger.LogTrace($" - ts_sign: {fn(ThresholdSigner.SignBenchmark)}");
Logger.LogTrace($" - ts_verify: {fn(ThresholdSigner.VerifyBenchmark)}");
Logger.LogTrace($" - ts_combine: {fn(ThresholdSigner.CombineBenchmark)}");
Logger.LogTrace($" - tpke_encrypt: {fn(TPKE.PublicKey.EncryptBenchmark)}");
Logger.LogTrace($" - tpke_full_decrypt: {fn(TPKE.PublicKey.FullDecryptBenchmark)}");
Logger.LogTrace($" - tpke_part_decrypt: {fn(TPKE.PrivateKey.DecryptBenchmark)}");
Logger.LogTrace($" - threshold_ecryption_encrypt: {fn(ThresholdEncryptor.EncryptBenchmark)}");
Logger.LogTrace($" - threshold_ecryption_part_decrypt: {fn(ThresholdEncryptor.DecryptBenchmark)}");
Logger.LogTrace($" - threshold_ecryption_verify: {fn(ThresholdEncryptor.VerifyBenchmark)}");
Logger.LogTrace($" - threshold_ecryption_full_decrypt: {fn(ThresholdEncryptor.FullDecryptBenchmark)}");
EcRecover.Reset();
EcSign.Reset();
EcVerify.Reset();
ThresholdSigner.CombineBenchmark.Reset();
ThresholdSigner.SignBenchmark.Reset();
ThresholdSigner.VerifyBenchmark.Reset();
TPKE.PublicKey.EncryptBenchmark.Reset();
TPKE.PublicKey.FullDecryptBenchmark.Reset();
TPKE.PrivateKey.DecryptBenchmark.Reset();
ThresholdEncryptor.EncryptBenchmark.Reset();
ThresholdEncryptor.DecryptBenchmark.Reset();
ThresholdEncryptor.VerifyBenchmark.Reset();
ThresholdEncryptor.FullDecryptBenchmark.Reset();
}

[MethodImpl(MethodImplOptions.Synchronized)]
Expand Down
20 changes: 0 additions & 20 deletions src/Lachain.Crypto/TPKE/PartiallyDecryptedShare.cs

This file was deleted.

17 changes: 6 additions & 11 deletions src/Lachain.Crypto/TPKE/PrivateKey.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
using System;
using Lachain.Utility.Benchmark;
using Lachain.Crypto.ThresholdEncryption;
using Lachain.Utility.Serialization;
using MCL.BLS12_381.Net;

namespace Lachain.Crypto.TPKE
{
public class PrivateKey : IFixedWidth
{
public static readonly TimeBenchmark DecryptBenchmark = new TimeBenchmark();

private readonly Fr _x;
private readonly int _id;

Expand All @@ -20,14 +18,11 @@ public PrivateKey(Fr x, int id)

public PartiallyDecryptedShare Decrypt(EncryptedShare share)
{
return DecryptBenchmark.Benchmark(() =>
{
var h = Utils.HashToG2(share.U, share.V);
if (!GT.Pairing(G1.Generator, share.W).Equals(GT.Pairing(share.U, h)))
throw new Exception("Invalid share!");
var ui = share.U * _x;
return new PartiallyDecryptedShare(ui, _id, share.Id);
});
var h = Utils.HashToG2(share.U, share.V);
if (!GT.Pairing(G1.Generator, share.W).Equals(GT.Pairing(share.U, h)))
throw new Exception("Invalid share!");
var ui = share.U * _x;
return new PartiallyDecryptedShare(ui, _id, share.Id);
}

public static PrivateKey FromBytes(ReadOnlyMemory<byte> bytes)
Expand Down