/***********************************************************************
 * Copyright (c) Pieter Wuille, Peter Dettman                          *
 * Distributed under the MIT software license, see the accompanying    *
 * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
 ***********************************************************************/

#ifndef SECP256K1_ECMULT_GEN_H
#define SECP256K1_ECMULT_GEN_H

#include "hash.h"
#include "scalar.h"
#include "group.h"


/* Configuration parameters for the signed-digit multi-comb algorithm:
 *
 * - COMB_BLOCKS is the number of blocks the input is split into. Each
 *   has a corresponding table.
 * - COMB_TEETH is the number of bits simultaneously covered by one table.
 * - COMB_RANGE is the number of bits in supported scalars. For production
 *   purposes, only 256 is reasonable, but smaller numbers are supported for
 *   exhaustive test mode.
 *
 * The comb's spacing (COMB_SPACING), or the distance between the teeth,
 * is defined as ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)). Each block covers
 * COMB_SPACING * COMB_TEETH consecutive bits in the input.
 *
 * The size of the precomputed table is COMB_BLOCKS * (1 << (COMB_TEETH - 1))
 * secp256k1_ge_storages.
 *
 * The number of point additions equals COMB_BLOCKS * COMB_SPACING. Each point
 * addition involves a cmov from (1 << (COMB_TEETH - 1)) table entries and a
 * conditional negation.
 *
 * The number of point doublings is COMB_SPACING - 1. */

#if defined(EXHAUSTIVE_TEST_ORDER)
/* We need to control these values for exhaustive tests because
 * the table cannot have infinities in them (secp256k1_ge_storage
 * doesn't support infinities) */
#  undef COMB_BLOCKS
#  undef COMB_TEETH
#  if EXHAUSTIVE_TEST_ORDER == 7
#    define COMB_RANGE 3
#    define COMB_BLOCKS 1
#    define COMB_TEETH 2
#  elif EXHAUSTIVE_TEST_ORDER == 13
#    define COMB_RANGE 4
#    define COMB_BLOCKS 1
#    define COMB_TEETH 2
#  elif EXHAUSTIVE_TEST_ORDER == 199
#    define COMB_RANGE 8
#    define COMB_BLOCKS 2
#    define COMB_TEETH 3
#  else
#    error "Unknown exhaustive test order"
#  endif
#  if (COMB_RANGE >= 32) || ((EXHAUSTIVE_TEST_ORDER >> (COMB_RANGE - 1)) != 1)
#    error "COMB_RANGE != ceil(log2(EXHAUSTIVE_TEST_ORDER+1))"
#  endif
#else /* !defined(EXHAUSTIVE_TEST_ORDER) */
#  define COMB_RANGE 256
#endif /* defined(EXHAUSTIVE_TEST_ORDER) */

/* Use (11, 6) as default configuration, which results in a 22 kB table. */
#ifndef COMB_BLOCKS
#  define COMB_BLOCKS 11
#  ifdef DEBUG_CONFIG
#    pragma message DEBUG_CONFIG_MSG("COMB_BLOCKS undefined, assuming default value")
#  endif
#endif
#ifndef COMB_TEETH
#  define COMB_TEETH 6
#  ifdef DEBUG_CONFIG
#    pragma message DEBUG_CONFIG_MSG("COMB_TEETH undefined, assuming default value")
#  endif
#endif
/* Use ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)) as COMB_SPACING. */
#define COMB_SPACING CEIL_DIV(COMB_RANGE, COMB_BLOCKS * COMB_TEETH)

/* Range checks on the parameters. */

/* The remaining COMB_* parameters are derived values, don't modify these. */
/* - The number of bits covered by all the blocks; must be at least COMB_RANGE. */
#define COMB_BITS (COMB_BLOCKS * COMB_TEETH * COMB_SPACING)
/* - The number of entries per table. */
#define COMB_POINTS (1 << (COMB_TEETH - 1))

/* Sanity checks. */
#if !(1 <= COMB_BLOCKS && COMB_BLOCKS <= 256)
#  error "COMB_BLOCKS must be in the range [1, 256]"
#endif
#if !(1 <= COMB_TEETH && COMB_TEETH <= 8)
#  error "COMB_TEETH must be in the range [1, 8]"
#endif
#if COMB_BITS < COMB_RANGE
#  error "COMB_BLOCKS * COMB_TEETH * COMB_SPACING is too low"
#endif

/* These last 2 checks are not strictly required, but prevent gratuitously inefficient
 * configurations. Note that they compare with 256 rather than COMB_RANGE, so they do
 * permit somewhat excessive values for the exhaustive test case, where testing with
 * suboptimal parameters may be desirable. */
#if (COMB_BLOCKS - 1) * COMB_TEETH * COMB_SPACING >= 256
#  error "COMB_BLOCKS can be reduced"
#endif
#if COMB_BLOCKS * (COMB_TEETH - 1) * COMB_SPACING >= 256
#  error "COMB_TEETH can be reduced"
#endif

#ifdef DEBUG_CONFIG
#  pragma message DEBUG_CONFIG_DEF(COMB_RANGE)
#  pragma message DEBUG_CONFIG_DEF(COMB_BLOCKS)
#  pragma message DEBUG_CONFIG_DEF(COMB_TEETH)
#  pragma message DEBUG_CONFIG_DEF(COMB_SPACING)
#endif

typedef struct {
    /* Whether the context has been built. */
    int built;

    /* Values chosen such that
     *
     *   n*G == comb(n + scalar_offset, G/2) + ge_offset.
     *
     * This expression lets us use scalar blinding and optimize the comb precomputation. See
     * ecmult_gen_impl.h for more details. */
    secp256k1_scalar scalar_offset;
    secp256k1_ge ge_offset;

    /* Factor used for projective blinding. This value is used to rescale the Z
     * coordinate of the first table lookup. */
    secp256k1_fe proj_blind;
} secp256k1_ecmult_gen_context;

static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_hash_ctx *hash_ctx);
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);

/** Multiply with the generator: R = a*G */
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a);

static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32);

#endif /* SECP256K1_ECMULT_GEN_H */
