/****************************************************************************
 * include/crypto/bn.h
 *
 * SPDX-License-Identifier: Unlicense
 *
 * This is free and unencumbered software released into the public domain.
 * Anyone is free to copy, modify, publish, use, compile, sell, or
 * distribute this software, either in source code form or as a compiled
 * binary, for any purpose, commercial or non-commercial, and by any
 * means.
 * In jurisdictions that recognize copyright laws, the author or authors
 * of this software dedicate any and all copyright interest in the
 * software to the public domain. We make this dedication for the benefit
 * of the public at large and to the detriment of our heirs and
 * successors. We intend this dedication to be an overt act of
 * relinquishment in perpetuity of all present and future rights to this
 * software under copyright law.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * For more information, please refer to <https://unlicense.org>
 ****************************************************************************/

#ifndef __INCLUDE_CRYPTO_BIGNUM_H
#define __INCLUDE_CRYPTO_BIGNUM_H

/* Big number library - arithmetic on multiple-precision unsigned integers.
 *
 * This library is an implementation of arithmetic on arbitrarily large
 * integers.
 *
 * The difference between this and other implementations, is that the data
 * structure
 * has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes
 * RAM),
 * and all memory is allocated statically: no dynamic allocation for better
 * or worse.
 *
 * Primary goals are correctness, clarity of code and clean, portable
 * implementation.
 * Secondary goal is a memory footprint small enough to make it suitable for
 * use in
 * embedded applications.
 *
 *
 * The current state is correct functionality and adequate performance.
 * There may well be room for performance-optimizations and improvements.
 */

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <stdint.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* This macro defines the word size in bytes of the array that constitutes
 * the big-number data structure.
 */

#define WORD_SIZE             1

/* Size of big-numbers in bytes */

#define BN_ARRAY_SIZE         (512 / WORD_SIZE)

/* Data type of array in structure */

#define DTYPE                 uint8_t

/* Data-type larger than DTYPE, for holding intermediate results of
 * calculations
 */

#define DTYPE_TMP             uint32_t

/* bitmask for getting MSB */

#define DTYPE_MSB             ((DTYPE_TMP)(0x80))

/* sprintf format string */

#define SPRINTF_FORMAT_STR    "%.02x"
#define SSCANF_FORMAT_STR     "%2hhx"

/* Max value of integer type */

#define MAX_VAL               ((DTYPE_TMP)0xFF)

/****************************************************************************
 * Public Types
 ****************************************************************************/

/* Data-holding structure: array of DTYPEs */

struct bn
{
  /* Sign: -1 if the bignum is negative, 1 otherwise. */

  int s;
  DTYPE array[BN_ARRAY_SIZE];
};

/* Tokens returned by bignum_cmp() for value comparison */

enum
{
  SMALLER = -1,
  EQUAL = 0,
  LARGER = 1
};

/****************************************************************************
 * Public Functions Prototype
 ****************************************************************************/

/* Initialization functions: */

void bignum_init(FAR struct bn *n);
void bignum_from_int(FAR struct bn *n, DTYPE_TMP i);
int  bignum_to_int(FAR struct bn *n);
void bignum_from_string(FAR struct bn *n, FAR char *str, int nbytes);
void bignum_to_string(FAR struct bn *n, FAR char *str, int maxsize);

/* Basic arithmetic operations: */

/* c = a + b */

void bignum_add(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* c = |a| + |b| */

void bignum_add_abs(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* c = a - b */

void bignum_sub(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* c = |a| - |b| */

void bignum_sub_abs(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* c = a * b */

void bignum_mul(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* c = a / b */

void bignum_div(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* c = a % b */

void bignum_mod(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* c = a / b, d = a % b */

void bignum_divmod(FAR struct bn *a, FAR struct bn *b,
                   FAR struct bn *c, FAR struct bn *d);

/* Bitwise operations: */

/* c = a & b */

void bignum_and(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* c = a | b */

void bignum_or(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* c = a ^ b */

void bignum_xor(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* b = a << nbits */

void bignum_lshift(FAR struct bn *a, FAR struct bn *b, int nbits);

/* b = a >> nbits */

void bignum_rshift(FAR struct bn *a, FAR struct bn *b, int nbits);

/* Special operators and comparison */

/* Compare: returns LARGER, EQUAL or SMALLER */

int  bignum_cmp(FAR struct bn *a, FAR struct bn *b);

/* Compare |A| and |B| */

int  bignum_cmp_abs(FAR struct bn *a, FAR struct bn *b);

/* For comparison with zero */

int  bignum_is_zero(FAR struct bn *n);

/* Increment: add one to n */

void bignum_inc(FAR struct bn *n);

/* Decrement: subtract one from n */

void bignum_dec(FAR struct bn *n);

/* Calculate a^b -- e.g. 2^10 => 1024 */

void bignum_pow(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);

/* Integer square root -- e.g. isqrt(5) => 2 */

void bignum_isqrt(FAR struct bn *a, FAR struct bn *b);

/* Copy src into dst -- dst := src */

void bignum_assign(FAR struct bn *dst, FAR struct bn *src);

/* CRK_EXP_MOD algorithm */

void pow_mod_faster(FAR struct bn *a, FAR struct bn *b,
                    FAR struct bn *n, FAR struct bn *res);

/* Return the number of less significant zero-bits */

int bignum_lsb(FAR struct bn *a);

/* g = gcd(a, b) */

void bignum_gcd(FAR struct bn *a, FAR struct bn *b, FAR struct bn *g);

/* Modular inverse: c = a^-1 mod n */

int bignum_inv_mod(FAR struct bn *a, FAR struct bn *n, FAR struct bn *c);

#endif /* __INCLUDE_CRYPTO_BIGNUM_H */
