<commit_before>// Copyright (c) 2017-2019 The Particl Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.

#include <anon.h>

#include <assert.h>
#include <secp256k1.h>
#include <secp256k1_rangeproof.h>
#include <secp256k1_mlsag.h>

#include <blind.h>
#include <rctindex.h>
#include <txdb.h>
#include <util/system.h>
#include <validation.h>
#include <validationinterface.h>
#include <consensus/validation.h>
#include <chainparams.h>
#include <txmempool.h>


bool VerifyMLSAG(const CTransaction &tx, CValidationState &state)
{
    int rv;
    std::set<int64_t> setHaveI; // Anon prev-outputs can only be used once per transaction.
    std::set<CCmpPubKey> setHaveKI;
    bool fSplitCommitments = tx.vin.size() > 1;

    size_t nStandard = 0, nCt = 0, nRingCT = 0;
    CAmount nPlainValueOut = tx.GetPlainValueOut(nStandard, nCt, nRingCT);
    CAmount nTxFee = 0;
    if (!tx.GetCTFee(nTxFee)) {
        return state.DoS(100, error("%s: bad-fee-output", __func__), REJECT_INVALID, "bad-fee-output");
    }

    nPlainValueOut += nTxFee;

    // Get commitment for unblinded amount
    uint8_t zeroBlind[32];
    memset(zeroBlind, 0, 32);
    secp256k1_pedersen_commitment plainCommitment;
    if (nPlainValueOut > 0) {
        if (!secp256k1_pedersen_commit(secp256k1_ctx_blind,
            &plainCommitment, zeroBlind, (uint64_t) nPlainValueOut, &secp256k1_generator_const_h, &secp256k1_generator_const_g)) {
            return state.DoS(100, false, REJECT_INVALID, "bad-plain-commitment");
        }
    }

    std::vector<const uint8_t*> vpInputSplitCommits;
    if (fSplitCommitments) {
        vpInputSplitCommits.reserve(tx.vin.size());
    }

    for (const auto &txin : tx.vin) {
        if (!txin.IsAnonInput()) {
            return state.DoS(100, false, REJECT_MALFORMED, "bad-anon-input");
        }

        uint32_t nInputs, nRingSize;
        txin.GetAnonInfo(nInputs, nRingSize);

        if (nInputs < 1 || nInputs > MAX_ANON_INPUTS) { // TODO: Select max inputs size
            return state.DoS(100, false, REJECT_INVALID, "bad-anon-num-inputs");
        }

        if (nRingSize < MIN_RINGSIZE || nRingSize > MAX_RINGSIZE) {
            return state.DoS(100, false, REJECT_INVALID, "bad-anon-ringsize");
        }

        uint256 txhash = tx.GetHash();

        size_t nCols = nRingSize;
        size_t nRows = nInputs + 1;

        if (txin.scriptData.stack.size() != 1) {
            return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-dstack-size");
        }
        if (txin.scriptWitness.stack.size() != 2) {
            return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-wstack-size");
        }

        const std::vector<uint8_t> &vKeyImages = txin.scriptData.stack[0];
        const std::vector<uint8_t> &vMI = txin.scriptWitness.stack[0];
        const std::vector<uint8_t> &vDL = txin.scriptWitness.stack[1];

        if (vKeyImages.size() != nInputs * 33) {
            return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-keyimages-size");
        }

        if (vDL.size() != (1 + (nInputs+1) * nRingSize) * 32 + (fSplitCommitments ? 33 : 0)) {
            return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-sig-size");
        }

        std::vector<uint8_t> vM(nCols * nRows * 33);

        std::vector<secp256k1_pedersen_commitment> vCommitments;
        vCommitments.reserve(nCols * nInputs);
        std::vector<const uint8_t*> vpOutCommits;
        std::vector<const uint8_t*> vpInCommits(nCols * nInputs);

        if (fSplitCommitments) {
            vpOutCommits.push_back(&vDL[(1 + (nInputs+1) * nRingSize) * 32]);
            vpInputSplitCommits.push_back(&vDL[(1 + (nInputs+1) * nRingSize) * 32]);
        } else {
            vpOutCommits.push_back(plainCommitment.data);

            secp256k1_pedersen_commitment *pc;
            for (const auto &txout : tx.vpout) {
                if ((pc = txout->GetPCommitment())) {
                    vpOutCommits.push_back(pc->data);
                }
            }
        }

        size_t ofs = 0, nB = 0;
        for (size_t k = 0; k < nInputs; ++k)
        for (size_t i = 0; i < nCols; ++i) {
            int64_t nIndex;

            if (0 != GetVarInt(vMI, ofs, (uint64_t&)nIndex, nB)) {
                return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-extract-i");
            }
            ofs += nB;

            if (!setHaveI.insert(nIndex).second) {
                return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-dup-i");
            }

            CAnonOutput ao;
            if (!pblocktree->ReadRCTOutput(nIndex, ao)) {
                LogPrint(BCLog::RINGCT, "bad-anonin-unknown-i %ld\n", nIndex);
                return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-unknown-i");
            }
            memcpy(&vM[(i+k*nCols)*33], ao.pubkey.begin(), 33);
            vCommitments.push_back(ao.commitment);
            vpInCommits[i+k*nCols] = vCommitments.back().data;
        }

        uint256 txhashKI;
        for (size_t k = 0; k < nInputs; ++k) {
            const CCmpPubKey &ki = *((CCmpPubKey*)&vKeyImages[k*33]);

            if (!setHaveKI.insert(ki).second) {
                if (LogAcceptCategory(BCLog::RINGCT)) {
                    LogPrintf("%s: Duplicate keyimage detected in txn %s.\n", __func__,<commit_msg>Log more info by default.<commit_after>// Copyright (c) 2017-2019 The Particl Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.

#include <anon.h>

#include <assert.h>
#include <secp256k1.h>
#include <secp256k1_rangeproof.h>
#include <secp256k1_mlsag.h>

#include <blind.h>
#include <rctindex.h>
#include <txdb.h>
#include <util/system.h>
#include <validation.h>
#include <validationinterface.h>
#include <consensus/validation.h>
#include <chainparams.h>
#include <txmempool.h>


bool VerifyMLSAG(const CTransaction &tx, CValidationState &state)
{
    int rv;
    std::set<int64_t> setHaveI; // Anon prev-outputs can only be used once per transaction.
    std::set<CCmpPubKey> setHaveKI;
    bool fSplitCommitments = tx.vin.size() > 1;

    size_t nStandard = 0, nCt = 0, nRingCT = 0;
    CAmount nPlainValueOut = tx.GetPlainValueOut(nStandard, nCt, nRingCT);
    CAmount nTxFee = 0;
    if (!tx.GetCTFee(nTxFee)) {
        return state.DoS(100, error("%s: bad-fee-output", __func__), REJECT_INVALID, "bad-fee-output");
    }

    nPlainValueOut += nTxFee;

    // Get commitment for unblinded amount
    uint8_t zeroBlind[32];
    memset(zeroBlind, 0, 32);
    secp256k1_pedersen_commitment plainCommitment;
    if (nPlainValueOut > 0) {
        if (!secp256k1_pedersen_commit(secp256k1_ctx_blind,
            &plainCommitment, zeroBlind, (uint64_t) nPlainValueOut, &secp256k1_generator_const_h, &secp256k1_generator_const_g)) {
            return state.DoS(100, false, REJECT_INVALID, "bad-plain-commitment");
        }
    }

    std::vector<const uint8_t*> vpInputSplitCommits;
    if (fSplitCommitments) {
        vpInputSplitCommits.reserve(tx.vin.size());
    }

    for (const auto &txin : tx.vin) {
        if (!txin.IsAnonInput()) {
            return state.DoS(100, false, REJECT_MALFORMED, "bad-anon-input");
        }

        uint32_t nInputs, nRingSize;
        txin.GetAnonInfo(nInputs, nRingSize);

        if (nInputs < 1 || nInputs > MAX_ANON_INPUTS) { // TODO: Select max inputs size
            return state.DoS(100, false, REJECT_INVALID, "bad-anon-num-inputs");
        }

        if (nRingSize < MIN_RINGSIZE || nRingSize > MAX_RINGSIZE) {
            return state.DoS(100, false, REJECT_INVALID, "bad-anon-ringsize");
        }

        uint256 txhash = tx.GetHash();

        size_t nCols = nRingSize;
        size_t nRows = nInputs + 1;

        if (txin.scriptData.stack.size() != 1) {
            return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-dstack-size");
        }
        if (txin.scriptWitness.stack.size() != 2) {
            return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-wstack-size");
        }

        const std::vector<uint8_t> &vKeyImages = txin.scriptData.stack[0];
        const std::vector<uint8_t> &vMI = txin.scriptWitness.stack[0];
        const std::vector<uint8_t> &vDL = txin.scriptWitness.stack[1];

        if (vKeyImages.size() != nInputs * 33) {
            return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-keyimages-size");
        }

        if (vDL.size() != (1 + (nInputs+1) * nRingSize) * 32 + (fSplitCommitments ? 33 : 0)) {
            return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-sig-size");
        }

        std::vector<uint8_t> vM(nCols * nRows * 33);

        std::vector<secp256k1_pedersen_commitment> vCommitments;
        vCommitments.reserve(nCols * nInputs);
        std::vector<const uint8_t*> vpOutCommits;
        std::vector<const uint8_t*> vpInCommits(nCols * nInputs);

        if (fSplitCommitments) {
            vpOutCommits.push_back(&vDL[(1 + (nInputs+1) * nRingSize) * 32]);
            vpInputSplitCommits.push_back(&vDL[(1 + (nInputs+1) * nRingSize) * 32]);
        } else {
            vpOutCommits.push_back(plainCommitment.data);

            secp256k1_pedersen_commitment *pc;
            for (const auto &txout : tx.vpout) {
                if ((pc = txout->GetPCommitment())) {
                    vpOutCommits.push_back(pc->data);
                }
            }
        }

        size_t ofs = 0, nB = 0;
        for (size_t k = 0; k < nInputs; ++k)
        for (size_t i = 0; i < nCols; ++i) {
            int64_t nIndex;

            if (0 != GetVarInt(vMI, ofs, (uint64_t&)nIndex, nB)) {
                return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-extract-i");
            }
            ofs += nB;

            if (!setHaveI.insert(nIndex).second) {
                LogPrintf("%s: Duplicate output: %ld\n", __func__, nIndex);
                return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-dup-i");
            }

            CAnonOutput ao;
            if (!pblocktree->ReadRCTOutput(nIndex, ao)) {
                LogPrintf("%s: ReadRCTOutput failed: %ld\n", __func__, nIndex);
                return state.DoS(100, false, REJECT_MALFORMED, "bad-anonin-unknown-i");
            }
            memcpy(&vM[(i+k*nCols)*33], ao.pubkey.begin(), 33);
            vCommitments.push_back(ao.commitment);
            vpInCommits[i+k*nCols] = vCommitments.back().data;
        }

        uint256 txhashKI;
        for (size_t k = 0; k < nInputs; ++k) {
            const CCmpPubKey &ki = *((CCmpPubKey*)&vKeyImages[k*33]);

            if (!setHaveKI.insert(ki).second) {
                if (LogAcceptCategory(BCLog::RINGCT)) {
                    LogPrintf("%s: Duplicate keyimage detected in txn %s.\n", __func__,
{'fraction_non_alphanumeric': 0.13483249196879302, 'fraction_numerical': 0.02918770078017439, 'mean_word_length': 2.5193798449612403, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2676206', 'n_tokens_mistral': 4151, 'n_tokens_neox': 3896, 'n_words': 733}