/*************************************************************************
 * To the extent possible under law, the author(s) have dedicated all    *
 * copyright and related and neighboring rights to the software in this  *
 * file to the public domain worldwide. This software is distributed     *
 * without any warranty. For the CC0 Public Domain Dedication, see       *
 * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
 *************************************************************************/

/** A 3-of-7 group signing beside an ordinary MuSig2 cosigner.
 *
 *  The group behaves as one MuSig2 participant, and the finished signature is
 *  an ordinary BIP-340 signature that records nothing about the group.
 *
 *  Three roles appear below and they run different code, which is the thing
 *  worth keeping straight while reading:
 *
 *    participant  holds a share, produces a nonce and a signature share, and
 *                 never sees the whole key. There are seven of them.
 *    coordinator  moves messages around and combines them. Untrusted: every
 *                 check here assumes it is hostile.
 *    cosigner     an ordinary MuSig2 signer that knows nothing about any of
 *                 this and calls the plain musig API.
 *
 *  The participants are wiped between the two rounds and rebuilt from storage,
 *  because no secret nonce survives that gap; see reboot_participants for what
 *  does survive it, which is not nothing. One call is made that is expected to
 *  fail, in refusals_are_refused.
 *
 *  See also include/secp256k1_iceberg.h and doc/iceberg.md.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <secp256k1.h>
#include <secp256k1_extrakeys.h>
#include <secp256k1_schnorrsig.h>
#include <secp256k1_musig.h>
#include <secp256k1_iceberg.h>
/* The trusted dealer lives in its own header, and is not part of the installed
 * API. See the note at the top of it. */
#include <secp256k1_iceberg_dealer.h>

#include "examples_util.h"

#define N 7              /* participants in the group */
#define T 3              /* how many of them can sign */
#define MU (2 * T - 1)   /* how many must take part in round one */

/* One participant's memory: one secret, and one note to itself.
 *
 * The share is the secret and never changes. `answered` is the highest session
 * label this participant has signed under. The library does not know about it and
 * could not, since it holds nothing between calls, but answering twice under one
 * label gives away the key share, so somebody has to remember, and the somebody
 * is the caller. */
struct participant {
    secp256k1_iceberg_share share;
    unsigned char answered[32];
};

/* The same participant's disk. A reboot loses the struct above, not this one,
 * and both fields have to come back. See reboot_participants. */
struct storage {
    unsigned char share_bytes[SECP256K1_ICEBERG_SHARE_MAX_LEN];
    size_t share_len;
    unsigned char answered_bytes[32];
};

/* The threshold side. Set up once, then unchanged for the life of the group. */
struct group {
    struct participant member[N];
    struct storage disk[N];
    secp256k1_iceberg_pubshare pubshare[N];
    secp256k1_pubkey pubkey;
};

/* The other side: an ordinary MuSig2 signer, which knows nothing about any of
 * the above. Everything it holds is its own, including the secret nonce that
 * the group deliberately does not have an equivalent of. */
struct cosigner {
    secp256k1_keypair keypair;
    secp256k1_pubkey pubkey;
    secp256k1_musig_secnonce secnonce;
};

/* What the two of them add up to. Computed once, at key aggregation, and the
 * only thing a verifier ever sees. */
struct shared_key {
    secp256k1_musig_keyagg_cache keyagg_cache;
    secp256k1_xonly_pubkey output;
};

/* One attempt at one signature. Everything here is public. */
struct signing_session {
    unsigned char sid[32];
    secp256k1_iceberg_pubnonce contribution[MU];
    const secp256k1_iceberg_pubnonce *contribution_ptr[MU];
    secp256k1_musig_pubnonce group_nonce;      /* the group's, after interpolating */
    secp256k1_musig_pubnonce cosigner_nonce;   /* the cosigner's, as published */
    secp256k1_musig_aggnonce cosigner_aggnonce;  /* the cosigners' alone */
    secp256k1_musig_session musig_session;
};

static void heading(const char *text) {
    printf("\n%s\n", text);
}

static void step(const char *text) {
    printf("  %-55s", text);
    fflush(stdout);
}

/* Deal the shares and publish the group's key.
 *
 * This is a trusted dealer: for the length of one call, this machine holds
 * enough to reconstruct the group's private key. Acceptable for testing, and
 * where one party is trusted already. A distributed key generation produces
 * the same shares without that moment ever existing, and this module does not
 * provide one. */
static int deal_shares(const secp256k1_context *ctx, struct group *group) {
    secp256k1_iceberg_share *share_ptr[N];
    const secp256k1_iceberg_pubshare *pubshare_ptr[N];
    unsigned char seed[32];
    unsigned int k;
    int ok;

    step("Dealing shares (secp256k1_iceberg_shares_gen)");
    if (!fill_random(seed, sizeof(seed))) {
        return 0;
    }
    for (k = 0; k < N; k++) {
        share_ptr[k] = &group->member[k].share;
    }
    ok = secp256k1_iceberg_shares_gen(ctx, share_ptr, N, T, seed);
    secure_erase(seed, sizeof(seed));
    if (!ok) {
        return 0;
    }
    printf("ok\n");

    /* A share is one seed per (t-1)-subset that leaves this participant out,
     * so it is large and grows quickly with the group. Each participant keeps
     * its own and nothing else. */
    step("Storing them (secp256k1_iceberg_share_serialize)");
    for (k = 0; k < N; k++) {
        group->disk[k].share_len = sizeof(group->disk[k].share_bytes);
        if (!secp256k1_iceberg_share_serialize(ctx, group->disk[k].share_bytes,
                                               &group->disk[k].share_len, &group->member[k].share)) {
            return 0;
        }
        /* Nothing answered yet, so the lowest possible label. Do this once, at
         * dealing; doing it again later throws the protection away. */
        memset(group->member[k].answered, 0, sizeof(group->member[k].answered));
        memcpy(group->disk[k].answered_bytes, group->member[k].answered, 32);
    }
    printf("ok, %lu bytes each\n", (unsigned long)group->disk[0].share_len);

    step("Group public key (secp256k1_iceberg_pubkey_agg)");
    for (k = 0; k < N; k++) {
        if (!secp256k1_iceberg_pubshare_gen(ctx, &group->pubshare[k], &group->member[k].share, NULL)) {
            return 0;
        }
        pubshare_ptr[k] = &group->pubshare[k];
    }
    /* 2t-1 public shares are more than the key needs, since t of them already
     * determine it, and the surplus is the point: they have to agree, so a
     * participant that published a wrong one is caught now rather than at
     * signing time. */
    if (!secp256k1_iceberg_pubkey_agg(ctx, &group->pubkey, pubshare_ptr, MU, N, T)) {
        return 0;
    }
    printf("ok\n");
    return 1;
}

/* Aggregate the group's key with the cosigner's, and tweak the result.
 *
 * Nothing below this point knows that one of the two keys is a group. The
 * tweak belongs to this outer session: musig_nonce_process sets its term aside
 * and musig_partial_sig_agg adds it once, at the top. No Iceberg call is even
 * told the tweak happened, which is what stops it being counted twice. */
static int aggregate_keys(const secp256k1_context *ctx, struct group *group, struct cosigner *cosigner, struct shared_key *shared) {
    const secp256k1_pubkey *pubkeys[2];
    secp256k1_pubkey output_pk;
    unsigned char taptweak[32];
    unsigned char seckey[32];
    int ok;

    step("Cosigner keypair (secp256k1_keypair_create)");
    ok = fill_random(seckey, sizeof(seckey))
         && secp256k1_keypair_create(ctx, &cosigner->keypair, seckey)
         && secp256k1_keypair_pub(ctx, &cosigner->pubkey, &cosigner->keypair);
    /* The keypair holds everything needed from here on, so the raw key does not
     * outlive this call; secp256k1_keypair_sec brings it back when required. */
    secure_erase(seckey, sizeof(seckey));
    if (!ok) {
        return 0;
    }
    printf("ok\n");

    step("Aggregating (secp256k1_musig_pubkey_agg)");
    pubkeys[0] = &group->pubkey;
    pubkeys[1] = &cosigner->pubkey;
    if (!secp256k1_musig_pubkey_agg(ctx, NULL, &shared->keyagg_cache, pubkeys, 2)) {
        return 0;
    }
    printf("ok\n");

    /* The cache records the hash of the key list, not the list, so nothing ties
     * it to the group's key later. Run this once, here, rather than trusting a
     * cache round two cannot check. */
    step("Checking the cache (secp256k1_iceberg_keyagg_check)");
    if (!secp256k1_iceberg_keyagg_check(ctx, &shared->keyagg_cache, pubkeys, 2,
                                        &group->pubkey)) {
        return 0;
    }
    printf("ok\n");

    step("Tweaking (secp256k1_musig_pubkey_xonly_tweak_add)");
    if (!fill_random(taptweak, sizeof(taptweak))
        || !secp256k1_musig_pubkey_xonly_tweak_add(ctx, &output_pk, &shared->keyagg_cache, taptweak)
        || !secp256k1_xonly_pubkey_from_pubkey(ctx, &shared->output, NULL, &output_pk)) {
        return 0;
    }
    printf("ok\n");
    return 1;
}

/* Round one, the group's half. Note the arguments: a share and a label. No
 * message, no cosigner, nothing from anybody else. */
static int group_round_one(const secp256k1_context *ctx, struct group *group,
                           struct signing_session *session) {
    unsigned int k;

    /* The label is the most delicate value in the scheme, and it is the
     * caller's to choose. Every participant's secret nonces are a function of
     * (its seeds, this label), and the seeds never change, so whoever picks the
     * label picks everyone's secrets.
     *
     * Here it is a fixed byte string, which is fine for an example and wrong
     * for anything else. In Lightning it is the commitment number: unique,
     * strictly increasing over the channel's life, and known before the
     * transaction is assembled, which is what lets this round run at all,
     * since the message does not exist yet. */
    step("Choosing the session label");
    memset(session->sid, 0x2c, sizeof(session->sid));
    printf("ok, ");
    print_hex(session->sid, 4);

    step("Participant nonces (secp256k1_iceberg_nonce_gen)");
    for (k = 0; k < MU; k++) {
        if (!secp256k1_iceberg_nonce_gen(ctx, &session->contribution[k], &group->member[k].share, NULL, session->sid)) {
            return 0;
        }
        session->contribution_ptr[k] = &session->contribution[k];
    }
    printf("ok, %d of the %d participants\n", MU, N);

    /* Verification, not addition. The contributions are points on a degree
     * t-1 polynomial in the exponent; this checks that they lie on one and
     * then interpolates. It is most of what the group costs, and it is what
     * stops a single participant biasing the group's nonce.
     *
     * NULL is the group's internal aggregate, which nothing takes back. */
    step("Combining them (secp256k1_iceberg_nonce_agg)");
    if (!secp256k1_iceberg_nonce_agg(ctx, &session->group_nonce, NULL,
                                     session->contribution_ptr, MU, N, T, &group->pubkey)) {
        return 0;
    }
    printf("ok\n");
    return 1;
}

/* Round one, the cosigner's half. Ordinary MuSig2, and it does not know a group
 * exists. Runs before, after or alongside the function above. */
static int cosigner_round_one(const secp256k1_context *ctx, struct cosigner *cosigner, struct shared_key *shared,
                              struct signing_session *session, const unsigned char *msg32) {
    const secp256k1_musig_pubnonce *just_the_cosigner[1];
    unsigned char secrand[32];
    unsigned char seckey[32];
    int ok;

    step("Cosigner nonce (secp256k1_musig_nonce_gen)");
    ok = fill_random(secrand, sizeof(secrand))
         && secp256k1_keypair_sec(ctx, seckey, &cosigner->keypair)
         && secp256k1_musig_nonce_gen(ctx, &cosigner->secnonce, &session->cosigner_nonce,
                                      secrand, seckey, &cosigner->pubkey,
                                      msg32, &shared->keyagg_cache, NULL);
    secure_erase(secrand, sizeof(secrand));
    secure_erase(seckey, sizeof(seckey));
    if (!ok) {
        return 0;
    }

    /* Round two needs the cosigners' aggregate on its own, separately from the
     * one that includes the group. With one cosigner it is an aggregate of one,
     * which is not a special case anywhere. */
    just_the_cosigner[0] = &session->cosigner_nonce;
    if (!secp256k1_musig_nonce_agg(ctx, &session->cosigner_aggnonce, just_the_cosigner, 1)) {
        return 0;
    }
    printf("ok\n");
    return 1;
}

/* Both halves have published. Combine them into the session everybody signs
 * against, which is where the message finally enters. */
static int open_session(const secp256k1_context *ctx, struct shared_key *shared,
                        struct signing_session *session, const unsigned char *msg32) {
    const secp256k1_musig_pubnonce *both[2];
    secp256k1_musig_aggnonce full_aggnonce;

    step("Session (secp256k1_musig_nonce_process)");
    both[0] = &session->group_nonce;
    both[1] = &session->cosigner_nonce;
    if (!secp256k1_musig_nonce_agg(ctx, &full_aggnonce, both, 2)
        || !secp256k1_musig_nonce_process(ctx, &session->musig_session, &full_aggnonce,
                                          msg32, &shared->keyagg_cache, NULL)) {
        return 0;
    }
    printf("ok\n");
    return 1;
}

/* Forget the secret nonces, then rebuild from disk.
 *
 * A FROST signer has to keep a secret nonce alive across this line, and losing
 * it, restoring an old backup over it, or running two copies of the signer are
 * each catastrophic. An Iceberg participant keeps no secret nonce at all: its
 * nonces are a function of its share and the label, both of which it is given
 * again.
 *
 * That property is narrower than "keeps no state".
 * A participant still has to remember which labels it has already answered
 * under, because two answers under one label are two equations in its three
 * secrets and three are enough to recover its key share. That bookkeeping is
 * not secret, and it is not optional; it is simply not this library's, since
 * only the group as a whole can decide which message a label belongs to.
 *
 * So wipe the secrets and prove that much. Skip the parse below and the next
 * call is handed a wiped share, whose magic fails an ARG_CHECK, so it aborts
 * through the illegal callback rather than returning 0. */
static int reboot_participants(const secp256k1_context *ctx, struct group *group) {
    unsigned int k;

    step("Wiping every participant's secret material");
    for (k = 0; k < N; k++) {
        secure_erase(&group->member[k], sizeof(group->member[k]));
    }
    printf("ok\n");

    step("Rebuilding (secp256k1_iceberg_share_parse)");
    for (k = 0; k < N; k++) {
        if (!secp256k1_iceberg_share_parse(ctx, &group->member[k].share,
                                           group->disk[k].share_bytes,
                                           group->disk[k].share_len)) {
            return 0;
        }
        memcpy(group->member[k].answered, group->disk[k].answered_bytes, 32);
    }
    printf("ok\n");

    /* Note what came back besides the share: `answered`. That record is not
     * secret, which is why it sits on the same disk in the clear, and it is
     * not optional, which is why it is restored here rather than left at zero.
     * A participant that forgets it will answer twice. */
    return 1;
}

/* One label, one answer: the half of the rule a participant can enforce alone.
 *
 * The library cannot do this for you. It holds nothing between calls, so "have I
 * answered under this label before?" is a question only the caller's storage can
 * answer. Here that storage is one 32-byte field per participant and the rule is
 * that a label must be strictly greater than the last one signed under, which is
 * free when the label is a counter. It refuses a repeat outright rather than
 * asking whether the repeat was harmless: a label is one signing attempt, so an
 * honest retry arrives under a new label and never needs the exception.
 *
 * The record reaches disk here, before the caller has a share to publish. A
 * crash between signing and storing is the same as never having stored, and the
 * next boot answers the label again.
 *
 * The other half of the rule, that no two participants answer one label on
 * different messages, cannot be checked here or anywhere else inside a
 * participant, because it is a fact about what other people were shown. See
 * doc/iceberg.md. */
static int may_sign_under(struct participant *member, struct storage *disk, const unsigned char *sid32) {
    if (memcmp(sid32, member->answered, 32) <= 0) {
        return 0;
    }
    memcpy(member->answered, sid32, 32);
    memcpy(disk->answered_bytes, member->answered, 32);
    return 1;
}

/* The group's half of round two, signed by participants first, first+1 and
 * first+2.
 *
 * Taking `first` is not generality for its own sake. The point of the scheme is
 * that any t of them will do, so main runs this twice with different people and
 * compares the two signatures.
 *
 * Any t of the seven, and not only the five who were in round one. The last
 * section of main proves that by having a participant who sat round one out
 * sign anyway. What each signer does need is the whole round-one set to check
 * against, which is a different count from the number of signers. */
static int group_signs(const secp256k1_context *ctx, struct group *group,
                       struct shared_key *shared, struct signing_session *session,
                       unsigned int first, const unsigned char *msg32,
                       secp256k1_musig_partial_sig *group_partial_sig) {
    secp256k1_iceberg_partial_sig sig_share[T];
    const secp256k1_iceberg_partial_sig *sig_share_ptr[T];
    unsigned int k;

    /* Note what this takes: the group's own round-one contributions, not an
     * aggregate of them, and not the cosigners', which arrive separately and
     * already aggregated. Do not read that as an optimization waiting to happen.
     * The nesting coefficient is a hash of the group's aggregate nonce, so a
     * coordinator free to invent that aggregate has a coefficient it can vary at
     * will, and three invented aggregates under one label give three equations in
     * the same three unknowns, and the third is the key. So the aggregate is
     * derived here from the contributions instead. */
    step("Signature shares (secp256k1_iceberg_partial_sign)");
    for (k = 0; k < T; k++) {
        if (!may_sign_under(&group->member[first + k], &group->disk[first + k], session->sid)) {
            printf("refused: participant %d has already answered under this label\n",
                   first + k + 1);
            return 0;
        }
        /* The signer derives the aggregate from the contributions, then checks
         * the polynomial they determine against the contribution it derives for
         * itself, which ties the set to this label. It need not have been one of
         * the contributors. */
        if (!secp256k1_iceberg_partial_sign(ctx, &sig_share[k], &group->member[first + k].share, NULL,
                                            session->sid, session->contribution_ptr, MU,
                                            &group->pubkey, &shared->keyagg_cache,
                                            msg32, &session->cosigner_aggnonce)) {
            return 0;
        }
        sig_share_ptr[k] = &sig_share[k];
    }
    printf("ok, from participants %d, %d and %d\n", first + 1, first + 2, first + 3);

    /* Optional, and the coordinator's to decide on. Skipping it costs nothing
     * until a share is bad, at which point the final signature simply fails
     * BIP-340 and says nothing about which of the three caused it. Checking
     * costs about what producing a share costs, per share.
     *
     * That is with exactly t shares, which is what this collects. Hand
     * secp256k1_iceberg_partial_sig_agg one more than it needs and it refuses a
     * set that disagrees with itself, cheaply and without naming anybody, for
     * the same reason pubkey_agg can above: past the threshold there is a spare
     * point to check against.
     *
     * It answers "is this share bad", not "who is lying". A share that fails
     * here may have been written by somebody other than the member it names,
     * and the same 0 comes back if this machine has the wrong message. */
    step("Checking them (secp256k1_iceberg_partial_sig_verify)");
    for (k = 0; k < T; k++) {
        if (!secp256k1_iceberg_partial_sig_verify(ctx, &sig_share[k], &group->pubshare[first + k],
                                                  session->contribution_ptr, MU, N, T,
                                                  &group->pubkey, &shared->keyagg_cache, msg32,
                                                  &session->cosigner_aggnonce)) {
            printf("share from participant %d does not check out\n", first + k + 1);
            return 0;
        }
    }
    printf("ok, all %d\n", T);

    step("Combining (secp256k1_iceberg_partial_sig_agg)");
    if (!secp256k1_iceberg_partial_sig_agg(ctx, group_partial_sig, sig_share_ptr, T, N, T)) {
        return 0;
    }
    printf("ok\n");
    return 1;
}

/* The cosigner's half, which happens exactly once.
 *
 * secp256k1_musig_partial_sign consumes the secret nonce, zeroing it on
 * the way out, precisely so that signing twice with it is not something a
 * caller can do by accident. Which quorum the group fielded is not the
 * cosigner's business and does not change its answer. */
static int cosigner_signs(const secp256k1_context *ctx, struct cosigner *cosigner,
                          struct shared_key *shared, struct signing_session *session,
                          secp256k1_musig_partial_sig *cosigner_partial_sig) {
    step("Cosigner's share (secp256k1_musig_partial_sign)");
    if (!secp256k1_musig_partial_sign(ctx, cosigner_partial_sig, &cosigner->secnonce,
                                      &cosigner->keypair, &shared->keyagg_cache,
                                      &session->musig_session)) {
        return 0;
    }
    printf("ok\n");
    return 1;
}

/* One group share plus one cosigner share makes an ordinary MuSig2 signature. */
static int combine(const secp256k1_context *ctx, struct signing_session *session,
                   const secp256k1_musig_partial_sig *group_partial_sig,
                   const secp256k1_musig_partial_sig *cosigner_partial_sig,
                   unsigned char *sig64) {
    const secp256k1_musig_partial_sig *both[2];

    step("Final signature (secp256k1_musig_partial_sig_agg)");
    both[0] = group_partial_sig;
    both[1] = cosigner_partial_sig;
    if (!secp256k1_musig_partial_sig_agg(ctx, sig64, &session->musig_session, both, 2)) {
        return 0;
    }
    printf("ok\n");
    return 1;
}

/* One call that must be refused and one that must not, with the reason beside
 * each.
 *
 * The refusal below is a load-bearing security check that looks like a bug from
 * outside; the call after it is the case that looks refusable and must not
 * be. */
static int refusals_are_refused(const secp256k1_context *ctx, struct group *group,
                                struct shared_key *shared, struct signing_session *session,
                                const unsigned char *msg32) {
    secp256k1_iceberg_partial_sig sig_share;

    step("Signing over contributions from another session");
    {
        /* The contributions below are a real sharing, internally consistent
         * and passing the degree check, but they were produced under a
         * different label. Accepting them would give whoever supplied them a
         * coefficient in the signing equation that this participant cannot
         * check, which is worth a signature share to an adversary and nothing
         * to anybody else.
         *
         * The signer catches it by interpolating the contributions and
         * evaluating the result at its own index: the polynomial does not pass
         * through the contribution it derives locally for the label it is
         * signing under. */
        secp256k1_iceberg_pubnonce elsewhere[MU];
        const secp256k1_iceberg_pubnonce *elsewhere_ptrs[MU];
        unsigned char other_sid[32];
        unsigned int k;

        memcpy(other_sid, session->sid, sizeof(other_sid));
        other_sid[0] ^= 1;
        for (k = 0; k < MU; k++) {
            if (!secp256k1_iceberg_nonce_gen(ctx, &elsewhere[k], &group->member[k].share,
                                             NULL, other_sid)) {
                return 0;
            }
            elsewhere_ptrs[k] = &elsewhere[k];
        }
        /* The set is a perfectly good sharing. What it is not is a sharing of
         * *this* label, and only the signer can tell, because only the signer
         * holds the share that says what its own contribution should have
         * been. */
        if (secp256k1_iceberg_partial_sign(ctx, &sig_share, &group->member[0].share, NULL,
                                           session->sid, elsewhere_ptrs, MU, &group->pubkey,
                                           &shared->keyagg_cache, msg32,
                                           &session->cosigner_aggnonce)) {
            printf("FAILED: it signed, and it should not have\n");
            return 0;
        }
    }
    printf("refused, correctly\n");

    /* The other half of that check is a thing it must NOT cost. */
    step("Signing by a member who sat round one out");
    {
        /* Participants 6 and 7 were not among the 2t-1 who produced nonces.
         * They can still sign, because a contribution is a function of the
         * share and the label, so an absent member can derive what its
         * contribution would have been and check the polynomial against it
         * without ever having been one of the contributors.
         *
         * This is the property that lets a quorum change between the rounds,
         * which is most of why the scheme works this way: keys sit in
         * cold storage and members are routinely absent rather than hostile. */
        if (!secp256k1_iceberg_partial_sign(ctx, &sig_share, &group->member[N - 1].share, NULL,
                                            session->sid, session->contribution_ptr, MU,
                                            &group->pubkey, &shared->keyagg_cache, msg32,
                                            &session->cosigner_aggnonce)) {
            printf("FAILED: it refused, and it should not have\n");
            return 0;
        }
    }
    printf("signed, correctly\n");
    return 1;
}

static void print_caveats(void) {
    heading("WHAT THIS EXAMPLE IS NOT");
    printf("  A trusted dealer deals the shares. Real deployments want a\n");
    printf("  distributed key generation, which this module does not provide.\n");
    printf("\n");
    printf("  Everything is passed as structs in one process. The wire formats\n");
    printf("  exist: 34 bytes for a public share, 67 for a nonce contribution,\n");
    printf("  33 for a signature share. Nothing here uses them, so the\n");
    printf("  network is the part you still have to write.\n");
    printf("\n");
    printf("  Structs in one process also satisfy constraint 2 for free. Over a\n");
    printf("  network the channel must be authenticated and a contribution taken\n");
    printf("  only from the member its index names; without that, an adversary\n");
    printf("  supplying t of the 2t-1 picks the group's nonce and every check\n");
    printf("  here still passes.\n");
    printf("\n");
    printf("  Verifying a share tells you whether it satisfies the equation,\n");
    printf("  not who is at fault: partial signatures are forgeable, so a share\n");
    printf("  that fails may have been written by somebody else.\n");
    printf("\n");
    printf("  may_sign_under above is half the rule, and the easy half: it\n");
    printf("  stops one participant answering twice. Nothing anywhere stops two\n");
    printf("  participants answering one label on different messages. Two answers\n");
    printf("  under one label are two equations in a participant's three\n");
    printf("  secrets; three recover its key share.\n");
    printf("\n");
    printf("  The label is an argument, rather than something derived from the\n");
    printf("  message, because round one has to run before the message exists.\n");
    printf("  In Lightning the nonce is fixed a round-trip before the\n");
    printf("  transaction is assembled, and the commitment number is what\n");
    printf("  Lightning supplies instead.\n");
    printf("\n");
    printf("  So half of that discipline is yours, never answering twice under\n");
    printf("  one label, and half is the group's: agree which message a label\n");
    printf("  belongs to before anyone answers. The unforgeability proof, which\n");
    printf("  is not yet peer-reviewed, assumes both. See doc/iceberg.md.\n");
}

int main(void) {
    secp256k1_context *ctx;
    struct group group;
    struct cosigner cosigner;
    struct shared_key shared;
    struct signing_session session;
    unsigned char msg[32] = "this_could_be_the_hash_of_a_msg";
    secp256k1_musig_partial_sig group_partial_sig, cosigner_partial_sig;
    unsigned char sig[64], sig_from_the_others[64];
    unsigned int k;
    int ok;

    ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);

    printf("Iceberg: a %d-of-%d group signing as one MuSig2 participant.\n\n", T, N);
    printf("  round one needs %d of the %d participants; round two needs %d\n", MU, N, MU);
    printf("  online again, not necessarily the same ones, and combines %d\n", T);
    printf("  signature shares. See doc/iceberg.md for why those differ.\n");

    heading("Setup: once, by a dealer who is then not needed again");
    ok = deal_shares(ctx, &group);

    if (ok) {
        heading("Key aggregation: the group is now just a public key");
        ok = aggregate_keys(ctx, &group, &cosigner, &shared);
    }
    if (ok) {
        /* The two halves are written in this order because something has to
         * go first on the page. Swap the two calls and the example still
         * passes, since neither needs anything the other produces, which is why
         * two Iceberg groups can sign with each other. */
        heading("Round one: needs 2t-1 participants, in no particular order");
        ok = group_round_one(ctx, &group, &session)
             && cosigner_round_one(ctx, &cosigner, &shared, &session, msg)
             && open_session(ctx, &shared, &session, msg);
    }
    if (ok) {
        heading("The gap: every participant forgets its secret nonces");
        ok = reboot_participants(ctx, &group);
    }
    if (ok) {
        heading("Round two: t shares, from any members, not just round one's");
        ok = group_signs(ctx, &group, &shared, &session, 0, msg, &group_partial_sig)
             && cosigner_signs(ctx, &cosigner, &shared, &session, &cosigner_partial_sig)
             && combine(ctx, &session, &group_partial_sig, &cosigner_partial_sig, sig);
    }
    if (ok) {
        step("Verifying (secp256k1_schnorrsig_verify)");
        ok = secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &shared.output);
        if (ok) {
            printf("ok\n    ");
            print_hex(sig, sizeof(sig));
            printf("    An ordinary BIP-340 signature. Nothing in it records a group.\n");
        }
    }
    if (ok) {
        heading("The same signature, from different people");
        /* Participants 4, 5 and 6 this time, with no overlap with 1, 2 and 3, and
         * 6 was not in round one either. Both of those matter. Disjoint,
         * because nobody may answer twice under one label. The library holds
         * nothing between calls and cannot detect that, so may_sign_under above
         * is what refuses it. And 6 absent from round one, because a member that
         * was away can still work out what its contribution would have been.
         *
         * Only the group signs again. The cosigner's share is reused, since it
         * has one secret nonce and spending it twice would be nonce reuse. */
        ok = group_signs(ctx, &group, &shared, &session, T, msg, &group_partial_sig)
             && combine(ctx, &session, &group_partial_sig, &cosigner_partial_sig, sig_from_the_others);
    }
    if (ok) {
        step("Comparing the two signatures");
        ok = memcmp(sig, sig_from_the_others, sizeof(sig)) == 0;
        printf(ok ? "byte-identical\n" : "the two quorums disagreed\n");
    }
    if (ok) {
        heading("What the module checks, and what it leaves to you");
        ok = refusals_are_refused(ctx, &group, &shared, &session, msg);
    }
    if (!ok) {
        printf("FAILED\n");
    }
    print_caveats();

    /* Clear the secrets: a bug elsewhere that leaks memory, or an OS that swaps
     * it to disk, should not find them lying around. The group's shares are the
     * long-term secret here, and the cosigner's keypair and secret nonce are
     * the rest. */
    for (k = 0; k < N; k++) {
        secure_erase(&group.member[k], sizeof(group.member[k]));
        secure_erase(&group.disk[k], sizeof(group.disk[k]));
    }
    secure_erase(&cosigner, sizeof(cosigner));
    secp256k1_context_destroy(ctx);
    return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
