/// <summary> /// </summary> /// <param name="transaction"></param> /// <returns></returns> public async Task <VerifyResult> VerifyOutputCommitments(Transaction transaction) { Guard.Argument(transaction, nameof(transaction)).NotNull(); var offSets = transaction.Vin.Select(v => v.Key).SelectMany(k => k.Offsets.Split(33)).ToArray(); var list = offSets.Where((value, index) => index % 2 == 0).ToArray(); foreach (var commit in list) { var blocks = await _unitOfWork.HashChainRepository.WhereAsync(x => new ValueTask <bool>(x.Txs.Any(v => v.Vout.Any(c => c.C.Xor(commit))))); if (!blocks.Any()) { return(VerifyResult.UnableToVerify); } var outputs = blocks.SelectMany(block => block.Txs).SelectMany(x => x.Vout); if (outputs.Where(output => output.T == CoinType.Coinbase && output.T == CoinType.Fee) .Select(output => VerifyLockTime(new LockTime(Utils.UnixTimeToDateTime(output.L)), output.S)) .Any(verified => verified != VerifyResult.UnableToVerify)) { return(VerifyResult.UnableToVerify); } } return(VerifyResult.Succeed); }
/// <summary> /// </summary> /// <param name="transaction"></param> /// <returns></returns> public VerifyResult VerifyBulletProof(Transaction transaction) { Guard.Argument(transaction, nameof(transaction)).NotNull(); Guard.Argument(transaction.Vout, nameof(transaction)).NotNull(); try { if (transaction.Validate().Any()) { return(VerifyResult.UnableToVerify); } using var secp256K1 = new Secp256k1(); using var bulletProof = new BulletProof(); if (transaction.Bp.Select((t, i) => bulletProof.Verify(transaction.Vout[i + 2].C, t.Proof, null)) .Any(verified => !verified)) { return(VerifyResult.UnableToVerify); } } catch (Exception ex) { _logger.Here().Error(ex, "Unable to verify the bullet proof"); return(VerifyResult.UnableToVerify); } return(VerifyResult.Succeed); }
/// <summary> /// /// </summary> /// <param name="transaction"></param> /// <returns></returns> public async Task <VerifyResult> VerifyTransaction(Transaction transaction) { Guard.Argument(transaction, nameof(transaction)).NotNull(); if (transaction.Validate().Any()) { return(VerifyResult.UnableToVerify); } var verifySum = VerifyCommitSum(transaction); if (verifySum == VerifyResult.UnableToVerify) { return(verifySum); } var verifyBulletProof = VerifyBulletProof(transaction); if (verifyBulletProof == VerifyResult.UnableToVerify) { return(verifyBulletProof); } var transactionTypeArray = transaction.Vout.Select(x => x.T.ToString()).ToArray(); if (transactionTypeArray.Contains(CoinType.Fee.ToString()) && transactionTypeArray.Contains(CoinType.Coin.ToString())) { var verifyVOutCommits = await VerifyOutputCommitments(transaction); if (verifyVOutCommits == VerifyResult.UnableToVerify) { return(verifyVOutCommits); } } var verifyKImage = await VerifyKeyImage(transaction); if (verifyKImage == VerifyResult.UnableToVerify) { return(verifyKImage); } using var mlsag = new MLSAG(); for (var i = 0; i < transaction.Vin.Length; i++) { var m = Makemlsag(transaction.Rct[i].M, transaction.Vout, transaction.Vin[i].Key.Offsets, transaction.Mix, 2); var verifymlsag = mlsag.Verify(transaction.Rct[i].I, transaction.Mix, 2, m, transaction.Vin[i].Key.Image, transaction.Rct[i].P, transaction.Rct[i].S); if (verifymlsag) { continue; } _logger.Here() .Fatal("Unable to verify the Multilayered Linkable Spontaneous Anonymous Group transaction"); return(VerifyResult.UnableToVerify); } return(VerifyResult.Succeed); }
/// <summary> /// </summary> /// <param name="transaction"></param> /// <returns></returns> public async Task <VerifyResult> VerifyKeyImage(Transaction transaction) { Guard.Argument(transaction, nameof(transaction)).NotNull(); if (transaction.Validate().Any()) { return(VerifyResult.UnableToVerify); } foreach (var vin in transaction.Vin) { var blocks = await _unitOfWork.HashChainRepository.WhereAsync(x => new ValueTask <bool>(x.Txs.Any(t => t.Vin.First().Key.Image.Xor(vin.Key.Image)))); if (blocks.Count > 1) { return(VerifyResult.UnableToVerify); } } return(VerifyResult.Succeed); }
/// <summary> /// </summary> /// <param name="transaction"></param> /// <returns></returns> public VerifyResult VerifyCommitSum(Transaction transaction) { Guard.Argument(transaction, nameof(transaction)).NotNull(); try { if (transaction.Validate().Any()) { return(VerifyResult.UnableToVerify); } using var pedersen = new Pedersen(); for (var i = 0; i < transaction.Vout.Length / 3; i++) { var fee = transaction.Vout[i].C; var payment = transaction.Vout[i + 1].C; var change = transaction.Vout[i + 2].C; var commitSumBalance = pedersen.CommitSum(new List <byte[]> { fee, payment, change }, new List <byte[]>()); if (!pedersen.VerifyCommitSum(new List <byte[]> { commitSumBalance }, new List <byte[]> { fee, payment, change })) { return(VerifyResult.UnableToVerify); } } } catch (Exception ex) { _logger.Here().Error(ex, "Unable to verify the committed sum"); return(VerifyResult.UnableToVerify); } return(VerifyResult.Succeed); }
/// <summary> /// </summary> /// <param name="transaction"></param> /// <returns></returns> public VerifyResult VerifyTransactionFee(Transaction transaction) { Guard.Argument(transaction, nameof(transaction)).NotNull(); var output = transaction.Vout.First(); if (output.T != CoinType.Fee) { return(VerifyResult.UnableToVerify); } var feeRate = Fee(FeeNByte); if (output.A != feeRate) { return(VerifyResult.UnableToVerify); } using var pedersen = new Pedersen(); var commitSum = pedersen.CommitSum(new List <byte[]> { output.C }, new List <byte[]> { output.C }); return(commitSum == null ? VerifyResult.Succeed : VerifyResult.UnableToVerify); }