/***********************************************************************
 * Distributed under the MIT software license, see the accompanying    *
 * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
 ***********************************************************************/

#ifndef SECP256K1_MODULE_CHILLDKG_ENCPEDPOP_IMPL_H
#define SECP256K1_MODULE_CHILLDKG_ENCPEDPOP_IMPL_H

#include <string.h>

#include "../../../include/secp256k1.h"

#include "util.h"
#include "vss.h"
#include "simplpedpop.h"
#include "encpedpop.h"
#include "../../ecmult.h"
#include "../../util.h"

/* The buffer size for u32be(index) || enc_context. */
#define SECP256K1_CHILLDKG_ENCPEDPOP_MAX_CONTEXT_LEN (8 + 33 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS)

static void secp256k1_chilldkg_encpedpop_serialize_enc_context(unsigned char *out, uint32_t t, const unsigned char *enckeys33, size_t n) {
    secp256k1_write_be32(out, t);
    memcpy(out + 4, enckeys33, 33 * n);
}

static int secp256k1_chilldkg_encpedpop_encaps_multi(const secp256k1_context *ctx, secp256k1_scalar *pads, const secp256k1_scalar *secnonce, const unsigned char *pubnonce33, const unsigned char *deckey32, const unsigned char *enckeys33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, size_t n) {
    const secp256k1_hash_ctx *hash_ctx;
    unsigned char context_[SECP256K1_CHILLDKG_ENCPEDPOP_MAX_CONTEXT_LEN];
    size_t i;

    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
    VERIFY_CHECK(enc_context_len + 4 <= sizeof(context_));
    hash_ctx = secp256k1_get_hash_context(ctx);

    /* This is effectively the "Hashed ElGamal" multi-recipient KEM described
     * in Section 5 of "Multi-recipient encryption, revisited" by Alexandre
     * Pinto, Bertram Poettering, Jacob C. N. Schuldt (AsiaCCS 2014). */
    for (i = 0; i < n; i++) {
        secp256k1_write_be32(context_, (uint32_t)i);
        memcpy(context_ + 4, enc_context, enc_context_len);
        if (i == participant_id) {
            /* We're encrypting to ourselves, so we use a symmetrically
             * derived pad to save the ECDH computation. */
            secp256k1_chilldkg_encpedpop_self_pad(hash_ctx, &pads[i], deckey32, pubnonce33, context_, 4 + enc_context_len);
        } else {
            secp256k1_ge enckey;
            if (!secp256k1_chilldkg_point_load(&enckey, enckeys33 + 33 * i) || secp256k1_ge_is_infinity(&enckey)) {
                /* Invalid host public key: caller input error (the session
                 * parameters must be validated beforehand). */
                for (i = 0; i < n; i++) {
                    secp256k1_scalar_clear(&pads[i]);
                }
                return 0;
            }
            secp256k1_chilldkg_encpedpop_ecdh(ctx, &pads[i], secnonce, &enckey, pubnonce33, enckeys33 + 33 * i, context_, 4 + enc_context_len, 1);
        }
    }
    return 1;
}

static int secp256k1_chilldkg_encpedpop_encrypt_multi(const secp256k1_context *ctx, secp256k1_scalar *ciphertexts, const secp256k1_scalar *secnonce, const unsigned char *pubnonce33, const unsigned char *deckey32, const unsigned char *enckeys33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, const secp256k1_scalar *plaintexts, size_t n) {
    secp256k1_scalar pads[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
    size_t i;
    int ret;

    VERIFY_CHECK(n <= SECP256K1_CHILLDKG_MAX_PARTICIPANTS);
    ret = secp256k1_chilldkg_encpedpop_encaps_multi(ctx, pads, secnonce, pubnonce33, deckey32, enckeys33, enc_context, enc_context_len, participant_id, n);
    if (ret) {
        /* The encryption is additively homomorphic modulo the group order. */
        for (i = 0; i < n; i++) {
            secp256k1_scalar_add(&ciphertexts[i], &plaintexts[i], &pads[i]);
        }
    }
    for (i = 0; i < n; i++) {
        secp256k1_scalar_clear(&pads[i]);
    }
    return ret;
}

static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_decaps_multi(const secp256k1_context *ctx, secp256k1_scalar *pads, uint32_t *fault_index, const unsigned char *deckey32, const unsigned char *enckey33, const unsigned char *pubnonces33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, size_t n) {
    const secp256k1_hash_ctx *hash_ctx;
    unsigned char context_[SECP256K1_CHILLDKG_ENCPEDPOP_MAX_CONTEXT_LEN];
    secp256k1_scalar deckey;
    size_t i;
    int overflow;

    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
    VERIFY_CHECK(enc_context_len + 4 <= sizeof(context_));
    VERIFY_CHECK(participant_id < n);
    hash_ctx = secp256k1_get_hash_context(ctx);

    /* The receiver index in the context is our own participant id for every
     * sender. */
    secp256k1_write_be32(context_, participant_id);
    memcpy(context_ + 4, enc_context, enc_context_len);

    secp256k1_scalar_set_b32(&deckey, deckey32, &overflow);
    overflow |= secp256k1_scalar_is_zero(&deckey);
    /* deckey32 is the caller's own host secret key; a failure is an input
     * error, not a protocol fault. */
    secp256k1_declassify(ctx, &overflow, sizeof(overflow));
    if (overflow) {
        return SECP256K1_CHILLDKG_INVALID_INPUT;
    }

    for (i = 0; i < n; i++) {
        if (i == participant_id) {
            /* The pad for the share from ourselves is derived symmetrically
             * (the sender side of the pad does the same). */
            secp256k1_chilldkg_encpedpop_self_pad(hash_ctx, &pads[i], deckey32, pubnonces33 + 33 * i, context_, 4 + enc_context_len);
        } else {
            secp256k1_ge pubnonce;
            if (!secp256k1_chilldkg_point_load(&pubnonce, pubnonces33 + 33 * i) || secp256k1_ge_is_infinity(&pubnonce)) {
                /* Since deckey and enckey are well-formed, the error must
                 * have been caused by an invalid public nonce. */
                secp256k1_scalar_clear(&deckey);
                *fault_index = (uint32_t)i;
                return SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR;
            }
            secp256k1_chilldkg_encpedpop_ecdh(ctx, &pads[i], &deckey, &pubnonce, enckey33, pubnonces33 + 33 * i, context_, 4 + enc_context_len, 0);
        }
    }
    secp256k1_scalar_clear(&deckey);
    return SECP256K1_CHILLDKG_OK;
}

static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_decrypt_sum(const secp256k1_context *ctx, secp256k1_scalar *out, uint32_t *fault_index, const unsigned char *deckey32, const unsigned char *enckey33, const unsigned char *pubnonces33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, const secp256k1_scalar *sum_ciphertexts, size_t n) {
    secp256k1_scalar pads[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
    secp256k1_chilldkg_fault fault;
    size_t i;

    VERIFY_CHECK(n <= SECP256K1_CHILLDKG_MAX_PARTICIPANTS);
    fault = secp256k1_chilldkg_encpedpop_decaps_multi(ctx, pads, fault_index, deckey32, enckey33, pubnonces33, enc_context, enc_context_len, participant_id, n);
    if (fault == SECP256K1_CHILLDKG_OK) {
        secp256k1_scalar_set_int(out, 0);
        for (i = 0; i < n; i++) {
            secp256k1_scalar_add(out, out, &pads[i]);
        }
        secp256k1_scalar_negate(out, out);
        secp256k1_scalar_add(out, out, sum_ciphertexts);
    }
    for (i = 0; i < n; i++) {
        secp256k1_scalar_clear(&pads[i]);
    }
    return fault;
}

static int secp256k1_chilldkg_encpedpop_participant_step1(const secp256k1_context *ctx, secp256k1_chilldkg_encpedpop_participant_state *state, unsigned char *pmsg, const unsigned char *seed32, const unsigned char *deckey32, const unsigned char *enckeys33, uint32_t t, uint32_t participant_id, const unsigned char *random32, size_t n) {
    const secp256k1_hash_ctx *hash_ctx;
    unsigned char enc_context[4 + 33 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
    unsigned char simpl_seed[32];
    unsigned char simpl_aux_rand[32];
    unsigned char secnonce32[32];
    unsigned char pubnonce33[33];
    secp256k1_scalar secnonce;
    secp256k1_scalar shares[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
    secp256k1_scalar enc_shares[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
    secp256k1_sha256 sha;
    uint32_t i;
    int overflow;
    int ret = 0;

    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
    ARG_CHECK(state != NULL);
    ARG_CHECK(pmsg != NULL);
    ARG_CHECK(seed32 != NULL);
    ARG_CHECK(deckey32 != NULL);
    ARG_CHECK(enckeys33 != NULL);
    ARG_CHECK(random32 != NULL);
    hash_ctx = secp256k1_get_hash_context(ctx);

    if (t < 1 || n < 1 || t > n || participant_id >= n || n > SECP256K1_CHILLDKG_MAX_PARTICIPANTS) {
        return 0;
    }

    /* Derive an encryption nonce and a seed for SimplPedPop.
     *
     * SimplPedPop will use its seed to derive the secret shares, which we
     * will encrypt using the encryption nonce. That means that all entropy
     * used in the derivation of simpl_seed should also be in the derivation
     * of the pubnonce, to ensure that we never encrypt different secret
     * shares with the same encryption pads. The foolproof way to achieve this
     * is to simply derive the nonce from simpl_seed. */
    secp256k1_chilldkg_encpedpop_serialize_enc_context(enc_context, t, enckeys33, n);
    secp256k1_chilldkg_sha256_tagged_encpedpop_seed(hash_ctx, &sha);
    secp256k1_sha256_write(hash_ctx, &sha, seed32, 32);
    secp256k1_sha256_write(hash_ctx, &sha, random32, 32);
    secp256k1_sha256_write(hash_ctx, &sha, enc_context, 4 + 33 * n);
    secp256k1_sha256_finalize(hash_ctx, &sha, simpl_seed);

    secp256k1_chilldkg_sha256_tagged_simplpedpop_aux(hash_ctx, &sha);
    secp256k1_sha256_write(hash_ctx, &sha, simpl_seed, 32);
    secp256k1_sha256_finalize(hash_ctx, &sha, simpl_aux_rand);

    secp256k1_chilldkg_sha256_tagged_encpedpop_secnonce(hash_ctx, &sha);
    secp256k1_sha256_write(hash_ctx, &sha, simpl_seed, 32);
    secp256k1_sha256_finalize(hash_ctx, &sha, secnonce32);
    secp256k1_sha256_clear(&sha);

    /* pubnonce = pubkey_gen_plain(secnonce); fails only if secnonce is not in
     * range 1..n-1 (negligible probability). */
    secp256k1_scalar_set_b32(&secnonce, secnonce32, &overflow);
    overflow |= secp256k1_scalar_is_zero(&secnonce);
    secp256k1_declassify(ctx, &overflow, sizeof(overflow));
    if (!overflow) {
        secp256k1_gej pubnoncej;
        secp256k1_ge pubnonce_ge;
        secp256k1_ecmult_gen_gej(&ctx->ecmult_gen_ctx, &pubnoncej, &secnonce);
        secp256k1_ge_set_gej(&pubnonce_ge, &pubnoncej);
        /* The pubnonce is public (it is part of the participant message);
         * declassify it so that the variable-time serialization is allowed
         * to branch on it. */
        secp256k1_declassify(ctx, &pubnonce_ge, sizeof(pubnonce_ge));
        secp256k1_chilldkg_point_save(pubnonce33, &pubnonce_ge);
        secp256k1_gej_clear(&pubnoncej);

        if (secp256k1_chilldkg_simplpedpop_participant_step1(ctx, &state->simpl_state, pmsg, shares, simpl_seed, t, (uint32_t)n, participant_id, simpl_aux_rand)) {
            if (secp256k1_chilldkg_encpedpop_encrypt_multi(ctx, enc_shares, &secnonce, pubnonce33, deckey32, enckeys33, enc_context, 4 + 33 * n, participant_id, shares, n)) {
                /* pmsg = ParticipantMsg(simpl_pmsg, pubnonce, enc_shares).to_bytes() */
                memcpy(pmsg + 33 * t + 64, pubnonce33, 33);
                for (i = 0; i < n; i++) {
                    secp256k1_scalar_get_b32(pmsg + 33 * t + 97 + 32 * i, &enc_shares[i]);
                }
                memcpy(state->pubnonce33, pubnonce33, 33);
                memcpy(&state->enckeys33[0][0], enckeys33, 33 * n);
                ret = 1;
            }
        }
    }

    secp256k1_scalar_clear(&secnonce);
    for (i = 0; i < n; i++) {
        secp256k1_scalar_clear(&shares[i]);
        secp256k1_scalar_clear(&enc_shares[i]);
    }
    secp256k1_memclear_explicit(simpl_seed, sizeof(simpl_seed));
    secp256k1_memclear_explicit(simpl_aux_rand, sizeof(simpl_aux_rand));
    secp256k1_memclear_explicit(secnonce32, sizeof(secnonce32));
    return ret;
}

static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_participant_step2(const secp256k1_context *ctx, secp256k1_chilldkg_simplpedpop_dkg_output *dkg_output, unsigned char *eq_input, uint32_t *fault_index, secp256k1_chilldkg_encpedpop_participant_inv_data *inv_data, const secp256k1_chilldkg_encpedpop_participant_state *state, const unsigned char *deckey32, const unsigned char *cmsg, size_t cmsg_len, const secp256k1_scalar *enc_secshare) {
    const uint32_t t = state->simpl_state.t;
    const uint32_t n = state->simpl_state.n;
    const uint32_t participant_id = state->simpl_state.participant_id;
    const size_t simpl_cmsg_len = 97 * (size_t)n + 33 * (size_t)(t - 1);
    const unsigned char *pubnonces;
    unsigned char enc_context[4 + 33 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
    secp256k1_scalar pads[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
    secp256k1_scalar padsum;
    secp256k1_scalar secshare;
    secp256k1_chilldkg_fault fault;
    uint32_t i;

    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
    ARG_CHECK(dkg_output != NULL);
    ARG_CHECK(eq_input != NULL);
    ARG_CHECK(state != NULL);
    ARG_CHECK(deckey32 != NULL);
    ARG_CHECK(cmsg != NULL);
    ARG_CHECK(enc_secshare != NULL);

    /* CoordinatorMsg.from_bytes; the simpl_cmsg prefix is parsed (again) by
     * the SimplPedPop participant_step2 below. */
    if (cmsg_len != simpl_cmsg_len + 33 * (size_t)n) {
        return SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
    }
    pubnonces = cmsg + simpl_cmsg_len;

    /* The coordinator must echo our own pubnonce. */
    if (secp256k1_memcmp_var(pubnonces + 33 * participant_id, state->pubnonce33, 33) != 0) {
        return SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
    }

    /* secshare = enc_secshare - sum of the pads (decrypt_sum). */
    secp256k1_chilldkg_encpedpop_serialize_enc_context(enc_context, t, &state->enckeys33[0][0], n);
    fault = secp256k1_chilldkg_encpedpop_decaps_multi(ctx, pads, fault_index, deckey32, state->enckeys33[participant_id], pubnonces, enc_context, 4 + 33 * (size_t)n, participant_id, n);
    if (fault != SECP256K1_CHILLDKG_OK) {
        for (i = 0; i < n; i++) {
            secp256k1_scalar_clear(&pads[i]);
        }
        return fault;
    }
    secp256k1_scalar_set_int(&padsum, 0);
    for (i = 0; i < n; i++) {
        secp256k1_scalar_add(&padsum, &padsum, &pads[i]);
    }
    secp256k1_scalar_negate(&secshare, &padsum);
    secp256k1_scalar_add(&secshare, &secshare, enc_secshare);

    fault = secp256k1_chilldkg_simplpedpop_participant_step2(ctx, dkg_output, eq_input, fault_index, inv_data != NULL ? &inv_data->simpl : NULL, &state->simpl_state, cmsg, simpl_cmsg_len, &secshare);

    /* On an UNKNOWN fault, capture the encrypted secshare and the pads so
     * that the investigation procedure can decrypt the partial secshares
     * (inv_data->simpl was filled by the SimplPedPop participant_step2). */
    if (fault == SECP256K1_CHILLDKG_UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR && inv_data != NULL) {
        inv_data->enc_secshare = *enc_secshare;
        for (i = 0; i < n; i++) {
            inv_data->pads[i] = pads[i];
        }
    }

    secp256k1_scalar_clear(&secshare);
    secp256k1_scalar_clear(&padsum);
    for (i = 0; i < n; i++) {
        secp256k1_scalar_clear(&pads[i]);
    }
    if (fault != SECP256K1_CHILLDKG_OK) {
        return fault;
    }

    /* eq_input += enckeys || pubnonces */
    memcpy(eq_input + 4 + 33 * t, &state->enckeys33[0][0], 33 * (size_t)n);
    memcpy(eq_input + 4 + 33 * t + 33 * (size_t)n, pubnonces, 33 * (size_t)n);
    return SECP256K1_CHILLDKG_OK;
}

static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_coordinator_step(const secp256k1_context *ctx, unsigned char *cmsg, secp256k1_chilldkg_simplpedpop_dkg_output *dkg_output, unsigned char *eq_input, secp256k1_scalar *enc_secshares, uint32_t *fault_index, const unsigned char *const *pmsgs, uint32_t t, const unsigned char *enckeys33, size_t n) {
    const size_t simpl_pmsg_len = 33 * (size_t)t + 64;
    const size_t simpl_cmsg_len = 97 * n + 33 * (size_t)(t - 1);
    secp256k1_ge scratch;
    secp256k1_scalar share;
    secp256k1_chilldkg_fault fault;
    size_t i;
    size_t j;
    int overflow;

    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
    ARG_CHECK(cmsg != NULL);
    ARG_CHECK(dkg_output != NULL);
    ARG_CHECK(eq_input != NULL);
    ARG_CHECK(enc_secshares != NULL);
    ARG_CHECK(pmsgs != NULL);
    ARG_CHECK(enckeys33 != NULL);

    if (t < 1 || n < 1 || t > n || n > SECP256K1_CHILLDKG_MAX_PARTICIPANTS) {
        return SECP256K1_CHILLDKG_INVALID_INPUT;
    }

    /* Parse the participant messages (ParticipantMsg.from_bytes). A malformed
     * message blames its sender. The pubnonces are not parsed (they are plain
     * byte strings in the reference); the participants parse them when
     * decrypting. */
    for (i = 0; i < n; i++) {
        secp256k1_scalar_set_int(&enc_secshares[i], 0);
    }
    for (i = 0; i < n; i++) {
        const unsigned char *pmsg = pmsgs[i];
        /* Validate the SimplPedPop commitment (the actual aggregation happens
         * in the SimplPedPop coordinator step below). */
        for (j = 0; j < t; j++) {
            if (!secp256k1_chilldkg_point_load(&scratch, pmsg + 33 * j)) {
                *fault_index = (uint32_t)i;
                return SECP256K1_CHILLDKG_FAULTY_PARTICIPANT;
            }
        }
        /* Collect the pubnonces in the coordinator message. */
        memcpy(cmsg + simpl_cmsg_len + 33 * i, pmsg + simpl_pmsg_len, 33);
        /* Sum the encrypted shares per recipient (the encryption is
         * additively homomorphic). Wire scalars are parsed checked; an
         * overflow blames the sender. */
        for (j = 0; j < n; j++) {
            secp256k1_scalar_set_b32(&share, pmsg + simpl_pmsg_len + 33 + 32 * j, &overflow);
            if (overflow) {
                secp256k1_scalar_clear(&share);
                *fault_index = (uint32_t)i;
                return SECP256K1_CHILLDKG_FAULTY_PARTICIPANT;
            }
            secp256k1_scalar_add(&enc_secshares[j], &enc_secshares[j], &share);
        }
    }
    secp256k1_scalar_clear(&share);

    fault = secp256k1_chilldkg_simplpedpop_coordinator_step(ctx, cmsg, dkg_output, eq_input, fault_index, pmsgs, t, (uint32_t)n);
    if (fault != SECP256K1_CHILLDKG_OK) {
        return fault;
    }

    /* eq_input += enckeys || pubnonces */
    memcpy(eq_input + 4 + 33 * t, enckeys33, 33 * n);
    memcpy(eq_input + 4 + 33 * t + 33 * n, cmsg + simpl_cmsg_len, 33 * n);
    return SECP256K1_CHILLDKG_OK;
}

static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_participant_investigate(const secp256k1_context *ctx, uint32_t *fault_index, const secp256k1_chilldkg_encpedpop_participant_inv_data *inv_data, const unsigned char *cinv, size_t cinv_len) {
    const uint32_t n = inv_data->simpl.n;
    secp256k1_ge partial_pubshares[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
    secp256k1_scalar enc_partial_secshares[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
    secp256k1_scalar partial_secshares[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
    secp256k1_chilldkg_fault fault;
    uint32_t i;
    int overflow;

    VERIFY_CHECK(ctx != NULL);
    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
    ARG_CHECK(fault_index != NULL);
    ARG_CHECK(inv_data != NULL);
    ARG_CHECK(cinv != NULL);
    /* inv_data was written by participant_step2. */
    VERIFY_CHECK(n >= 1 && n <= SECP256K1_CHILLDKG_MAX_PARTICIPANTS);

    /* CoordinatorInvestigationMsg.from_bytes: enc_partial_secshares (32*n) ||
     * partial_pubshares (33*n). Parse errors blame the coordinator
     * (MsgParseError -> FaultyCoordinatorError in the reference). */
    if (cinv_len != 65 * (size_t)n) {
        return SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
    }
    for (i = 0; i < n; i++) {
        secp256k1_scalar_set_b32(&enc_partial_secshares[i], cinv + 32 * i, &overflow);
        if (overflow) {
            fault = SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
            goto cleanup;
        }
    }
    for (i = 0; i < n; i++) {
        if (!secp256k1_chilldkg_point_load(&partial_pubshares[i], cinv + 32 * n + 33 * i)) {
            fault = SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
            goto cleanup;
        }
    }

    /* Decrypt the partial secshares addressed to us. */
    for (i = 0; i < n; i++) {
        secp256k1_scalar pad_neg;
        secp256k1_scalar_negate(&pad_neg, &inv_data->pads[i]);
        secp256k1_scalar_add(&partial_secshares[i], &enc_partial_secshares[i], &pad_neg);
        secp256k1_scalar_clear(&pad_neg);
    }

    fault = secp256k1_chilldkg_simplpedpop_participant_investigate(ctx, fault_index, &inv_data->simpl, partial_pubshares, partial_secshares);

cleanup:
    for (i = 0; i < n; i++) {
        secp256k1_scalar_clear(&enc_partial_secshares[i]);
        secp256k1_scalar_clear(&partial_secshares[i]);
    }
    return fault;
}

#endif
