/*
	Licensed to the Apache Software Foundation (ASF) under one
	or more contributor license agreements.  See the NOTICE file
	distributed with this work for additional information
	regarding copyright ownership.  The ASF licenses this file
	to you under the Apache License, Version 2.0 (the
	"License"); you may not use this file except in compliance
	with the License.  You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing,
	software distributed under the License is distributed on an
	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
	KIND, either express or implied.  See the License for the
	specific language governing permissions and limitations
	under the License.
*/

/* AMCL header file */
/* Designed for AES-128/192/256 security, 254-521 bit elliptic curves and BN curves for pairings */
/* Each "limb" of a big number occupies at most (n-3) bits of an n-bit computer word. The most significant word must have at least 4 extra unused bits */

/**
 * @file amcl.h
 * @author Mike Scott and Kealan McCusker
 * @date 19th May 2015
 * @brief Main Header File
 *
 * Allows some user configuration
 * defines structures
 * declares functions
 *
 */

/* NOTE: There is only one user configurable section in this header - see below */

#ifndef AMCL_H
#define AMCL_H

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "arch.h"

#ifdef CMAKE
#define AMCL_VERSION_MAJOR @AMCL_VERSION_MAJOR@ /**< Major version of the library */
#define AMCL_VERSION_MINOR @AMCL_VERSION_MINOR@ /**< Minor version of the library */
#define AMCL_VERSION_PATCH @AMCL_VERSION_PATCH@ /**< Patch version of the library */
#define OS "@OS@"                               /**< Operative system */
#cmakedefine USE_PATENTS   /**< Use Patents */
#cmakedefine USE_ANONYMOUS /**< Use Anonymous Configuration in MPin */
#endif

/* Curve types */

#define WEIERSTRASS 0 /**< Short Weierstrass form curve  */
#define EDWARDS 1     /**< Edwards or Twisted Edwards curve  */
#define MONTGOMERY 2  /**< Montgomery form curve  */

/* Elliptic curves are defined over prime fields */
/* Here are some popular EC prime fields for which we have prepared standard curves. Feel free to specify your own. */

#define NIST256 0    /**< For the NIST 256-bit standard curve - WEIERSTRASS only */
#define C25519 1     /**< Bernstein's Modulus 2^255-19 - EDWARDS or MONTGOMERY only */
#define BRAINPOOL 2  /**< For Brainpool 256-bit curve - WEIERSTRASS only */
#define ANSSI 3      /**< For French 256-bit standard curve - WEIERSTRASS only */
#define MF254 4      /**< For NUMS curves from Bos et al - 254-bit Montgomery friendly modulus - WEIERSTRASS or EDWARDS or MONTGOMERY */
#define MS255 5      /**< For NUMS curve - 255-bit pseudo-mersenne modulus - WEIERSTRASS or EDWARDS or MONTGOMERY */
#define MF256 6      /**< For NUMS curve - 256-bit Montgomery friendly modulus - WEIERSTRASS or EDWARDS or MONTGOMERY */
#define MS256 7      /**< For NUMS curve - 256-bit pseudo-merseene modulus - WEIERSTRASS or EDWARDS or MONTGOMERY */
#define HIFIVE 8     /**< My 336-bit pseudo-mersenne modulus - EDWARDS only */
#define GOLDILOCKS 9 /**< Goldilocks generalized-mersenne modulus - EDWARDS only */
#define NIST384 10   /**< For the NIST 384-bit standard curve - WEIERSTRASS only */
#define C41417 11    /**< Bernstein et al Curve41417 2^414-17 - EDWARDS only */
#define NIST521 12   /**< For the NIST 521-bit standard curve - WEIERSTRASS only */

/* BN Curves */
#define BN_CURVES 100 /**< Barreto-Naehrig curves */
#define BN454 100     /**< New AES-128 security BN curve - Modulus built from -0x10000010000000000000100000001  - WEIERSTRASS only */
#define BN646 101     /**< AES-192 security BN curve -  Modulus built from t=-0x10000000000000000000004000000000000001001 - WEIERSTRASS only */

/* A few 254-bit alternative BN curves */
#define BN254 102 /**< Standard Nogami BN curve - fastest. Modulus built from  t=-0x4080000000000001 - WEIERSTRASS only */

/* GT_STRONG curves */
#define BN254_CX 103 /**< Our CertiVox BN curve. Modulus built from t=-0x4000000003C012B1 - WEIERSTRASS only */
#define BN254_T 104  /**< GT_Strong BN curve. Modulus built from t=-0x4000806000004081 - WEIERSTRASS only */
#define BN254_T2 105 /**< G2 and GT-Strong BN curve.  Modulus built from t=-0x4000020100608205 - WEIERSTRASS only */

/* BLS-12 Curves */
#define BLS_CURVES 200 /**< Barreto-Lynn-Scott curves */
#define BLS455 200     /**< New AES-128 security BLS curve - Modulus built from -0x10002000002000010007  - WEIERSTRASS only */
#define BLS383 201     /**< New AES-128 security BLS curve - Modulus built from -0x1101000000040110  - WEIERSTRASS only */






/*** START OF USER CONFIGURABLE SECTION - set architecture and choose modulus and curve  ***/

#ifdef CMAKE
#define CHOICE @AMCL_CHOICE@ /**< Current choice of Field */
#else
#define CHOICE BN254_CX	     /**< Current choice of Field */
#endif

/* For some moduli only one parameterisation of curve may supported. For others there is a choice of WEIERSTRASS, EDWARDS or MONTGOMERY curves. See above. */
#ifdef CMAKE
#define CURVETYPE @AMCL_CURVETYPE@ /**< Note that not all curve types are supported - see above */
#else
#define CURVETYPE WEIERSTRASS	   /**< Note that not all curve types are supported - see above */
#endif


/* Actual curve parameters associated with these choices can be found in rom.c */

/* These next options only apply for pairings */
#ifdef USE_PATENTS
#define USE_GLV	  /**< Note this method is patented (GLV), so maybe you want to comment this out */
#define USE_GS_G2 /**< Well we didn't patent it :) But may be covered by GLV patent :( */
#endif
#define USE_GS_GT /**< Not patented, so probably safe to always use this */

/* Finite field support - for RSA, DH etc. */
#ifdef CMAKE
#define FFLEN @AMCL_FFLEN@ /**< 2^n multiplier of BIGBITS to specify supported Finite Field size, e.g 2048=256*2^3 where BIGBITS=256 */
#else
#define FFLEN 8 /**< 2^n multiplier of BIGBITS to specify supported Finite Field size, e.g 2048=256*2^3 where BIGBITS=256 */
#endif



/* For debugging Only.*/
#ifdef CMAKE
#cmakedefine DEBUG_REDUCE /**< Print debug message for field reduction */
#cmakedefine DEBUG_NORM   /**< Detect digit overflow */
#cmakedefine GET_STATS    /**< Debug statistics - use with debugger */
#else
//#define DEBUG_REDUCE
//#define DEBUG_NORM
//#define GET_STATS
#endif


// #define UNWOUND

/*** END OF USER CONFIGURABLE SECTION ***/








#define NLEN (1+((MBITS-1)/BASEBITS)) /**< Number of words in BIG. */
#define MODBYTES (1+(MBITS-1)/8)      /**< Number of bytes in Modulus */
#define BIGBITS (MODBYTES*8)	      /**< Number of bits representable in a BIG */
#define FF_BITS (BIGBITS*FFLEN)	      /**< Finite Field Size in bits - must be BIGBITS.2^n */

/* modulus types */

#define NOT_SPECIAL 0	       /**< Modulus of no exploitable form */
#define PSEUDO_MERSENNE 1      /**< Pseudo-mersenne modulus of form $2^n-c$  */
#define MONTGOMERY_FRIENDLY 3  /**< Montgomery Friendly modulus of form $2^a(2^b-c)-1$  */
#define GENERALISED_MERSENNE 2 /**< Generalised-mersenne modulus of form $2^n-2^m-1$, GOLDILOCKS only */

/* Built-in curves defined here */
/* MIRACL check.cpp utility used to determine optimal choice for BASEBITS */

/* Define AES_S if the desired AES-equivalent security is significantly less than the group order */


#if CHOICE==NIST256
#define MBITS 256	             /**< Number of bits in Modulus */
#define MOD8 7	                     /**< Modulus mod 8  */
#define MODTYPE  NOT_SPECIAL         /**< Modulus type */
#if CURVETYPE!=WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#define BASEBITS 13                  /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 32
#define BASEBITS 29                  /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56                  /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

#if CHOICE==C25519
#define MBITS 255	             /**< Number of bits in Modulus */
#define MOD8 5		             /**< Modulus mod 8  */
#define MODTYPE PSEUDO_MERSENNE      /**< Modulus type */
#if CURVETYPE==WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#if CURVETYPE==MONTGOMERY
#error Not supported
#else
#define BASEBITS 13		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#if CHUNK == 32
#define BASEBITS 29		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

#if CHOICE==BRAINPOOL
#define MBITS 256                    /**< Number of bits in Modulus */
#define MOD8 7                       /**< Modulus mod 8  */
#define MODTYPE  NOT_SPECIAL         /**< Modulus type */
#if CURVETYPE!=WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#define BASEBITS 13                  /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 32
#define BASEBITS 29                  /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56                  /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

#if CHOICE==ANSSI
#define MBITS 256	             /**< Number of bits in Modulus */
#define MOD8 3		             /**< Modulus mod 8  */
#define MODTYPE  NOT_SPECIAL         /**< Modulus type */
#if CURVETYPE!=WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#define BASEBITS 13                  /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 32
#define BASEBITS 29                  /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56                  /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

/**< NUMS curve from Bos et al. paper */

#if CHOICE==MF254
#define MBITS 254                    /**< Number of bits in Modulus */
#define MOD8 7                       /**< Modulus mod 8  */
#define MODTYPE MONTGOMERY_FRIENDLY  /**< Modulus type */
#if CHUNK==16
#error Not Supported
#endif
#if CHUNK == 32
#define BASEBITS 29                  /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56                  /**< Numbers represented to base 2*BASEBITS */
#endif
#endif

#if CHOICE==MF256
#define MBITS 256                    /**< Number of bits in Modulus */
#define MOD8 7                       /**< Modulus mod 8  */
#define MODTYPE MONTGOMERY_FRIENDLY  /**< Modulus type */
#if CHUNK==16
#error Not Supported
#endif
#if CHUNK == 32
#define BASEBITS 29                  /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56                  /**< Numbers represented to base 2*BASEBITS */
#endif
#endif

#if CHOICE==MS255
#define MBITS 255	             /**< Number of bits in Modulus */
#define MOD8 3		             /**< Modulus mod 8  */
#define MODTYPE PSEUDO_MERSENNE      /**< Modulus type */
#if CHUNK==16
#define BASEBITS 13                  /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 32
#define BASEBITS 29                  /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56                  /**< Numbers represented to base 2*BASEBITS */
#endif
#endif

#if CHOICE==MS256
#define MBITS 256	             /**< Number of bits in Modulus */
#define MOD8 3		             /**< Modulus mod 8  */
#define MODTYPE PSEUDO_MERSENNE      /**< Modulus type */
#if CHUNK==16
#define BASEBITS 13	             /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 32
#define BASEBITS 29		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif

#if CHOICE==HIFIVE
#define MBITS 336	             /**< Number of bits in Modulus */
#define MOD8 5		             /**< Modulus mod 8  */
#define MODTYPE PSEUDO_MERSENNE      /**< Modulus type */
#define AES_S 128                    /**< Desired AES equivalent strength */
#if CURVETYPE!=EDWARDS
#error Not supported
#else
#if CHUNK==16
#error Not Supported
#endif
#if CHUNK == 32
#define BASEBITS 29		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 60		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

#if CHOICE==GOLDILOCKS
#define MBITS 448	             /**< Number of bits in Modulus */
#define MOD8 7		             /**< Modulus mod 8  */
#define MODTYPE GENERALISED_MERSENNE /**< Modulus type */
#if CURVETYPE!=EDWARDS
#error Not supported
#else
#if CHUNK==16
#error Not Supported
#endif
#if CHUNK == 32
#define BASEBITS 29		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 60		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

#if CHOICE==NIST384
#define MBITS 384	             /**< Number of bits in Modulus */
#define MOD8 7		             /**< Modulus mod 8  */
#define MODTYPE  NOT_SPECIAL         /**< Modulus type */
#if CURVETYPE!=WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#error Not supported
#endif
#if CHUNK == 32
#define BASEBITS 28		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

#if CHOICE==C41417
#define MBITS 414	             /**< Number of bits in Modulus */
#define MOD8 7		             /**< Modulus mod 8  */
#define MODTYPE  PSEUDO_MERSENNE     /**< Modulus type */
#if CURVETYPE!=EDWARDS
#error Not supported
#else
#if CHUNK==16
#error Not supported
#endif
#if CHUNK == 32
#define BASEBITS 29		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 60		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

#if CHOICE==NIST521
#define MBITS 521	             /**< Number of bits in Modulus */
#define MOD8 7		             /**< Modulus mod 8  */
#define MODTYPE  PSEUDO_MERSENNE     /**< Modulus type */
#if CURVETYPE!=WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#error Not supported
#endif
#if CHUNK == 32
#define BASEBITS 28		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 60		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

/* New BN curve to be used for AES-128 security as response to new DL developments - see Kim & Barbulescu ePrint Archive: Report 2015/1027 */

#if CHOICE==BN454
#define MBITS 454	             /**< Number of bits in Modulus */
#define MOD8 3		             /**< Modulus mod 8  */
#define MODTYPE  NOT_SPECIAL         /**< Modulus type */
#define AES_S 128                    /**< Desired AES equivalent strength */
#if CURVETYPE!=WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#error Not supported
#endif
#if CHUNK == 32
#define BASEBITS 29		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 60		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

/* New BLS curve to be used for AES-128 security as response to new DL developments - see Kim & Barbulescu ePrint Archive: Report 2015/1027 */

#if CHOICE==BLS455
#define MBITS 455	             /**< Number of bits in Modulus */
#define MOD8 3		             /**< Modulus mod 8  */
#define MODTYPE  NOT_SPECIAL         /**< Modulus type */
#define AES_S 128                    /**< Desired AES equivalent strength */
#if CURVETYPE!=WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#error Not supported
#endif
#if CHUNK == 32
#define BASEBITS 29		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 60		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif


#if CHOICE==BLS383
#define MBITS 383	             /**< Number of bits in Modulus */
#define MOD8 3		             /**< Modulus mod 8  */
#define MODTYPE  NOT_SPECIAL         /**< Modulus type */
#if CURVETYPE!=WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#error Not supported
#endif
#if CHUNK == 32
#define BASEBITS 28		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

#if CHOICE==BN646
#define MBITS 646	             /**< Number of bits in Modulus */
#define MOD8 3		             /**< Modulus mod 8  */
#define MODTYPE  NOT_SPECIAL         /**< Modulus type */
#define AES_S 192                    /**< Desired AES equivalent strength */
#if CURVETYPE!=WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#error Not supported
#endif
#if CHUNK == 32
#define BASEBITS 29		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 60		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif

#if CHOICE<BLS_CURVES

#if CHOICE>=BN254                    /* Its a BN curve */
#define MBITS 254	             /**< Number of bits in Modulus */
#define MOD8 3		             /**< Modulus mod 8  */
#define MODTYPE  NOT_SPECIAL         /**< Modulus type */
#if CURVETYPE!=WEIERSTRASS
#error Not supported
#else
#if CHUNK==16
#define BASEBITS 13		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 32
#define BASEBITS 29		     /**< Numbers represented to base 2*BASEBITS */
#endif
#if CHUNK == 64
#define BASEBITS 56		     /**< Numbers represented to base 2*BASEBITS */
#endif
#endif
#endif


#if CHOICE>BN254
#define GT_STRONG /**< Using a GT-Strong 254-bit BN curve */
#endif
#endif


/* Don't mess with anything below this line */

#ifdef GET_STATS
extern int tsqr,rsqr,tmul,rmul;
extern int tadd,radd,tneg,rneg;
extern int tdadd,rdadd,tdneg,rdneg;
#endif

#define DCHUNK 2*CHUNK	/**< Number of bits in double-length type */
#define DNLEN 2*NLEN	/**< double length required for products of BIGs */
#define HFLEN (FFLEN/2) /**< Useful for half-size RSA private key operations */

#define CHUNK_BITS 8*sizeof(chunk) /**< Number of bits in a chunk */

#ifdef DEBUG_NORM  /* Add an extra location to track chunk extension */
typedef chunk BIG[NLEN+1];   /**< Define type BIG as array of chunks */
typedef chunk DBIG[DNLEN+1]; /**< Define type DBIG as array of chunks */
#else
typedef chunk BIG[NLEN];     /**< Define type BIG as array of chunks */
typedef chunk DBIG[DNLEN];   /**< Define type DBIG as array of chunks */
#endif

#define HBITS (BASEBITS/2)      /**< Number of bits in number base divided by 2 */
#define HBITS1 ((BASEBITS+1)/2) /**< Number of bits in number base plus 1 divided by 2 */
#define HDIFF (HBITS1-HBITS)    /**< Will be either 0 or 1, depending if number of bits in number base is even or odd */

#define BMASK (((chunk)1<<BASEBITS)-1) /**< Mask = 2^BASEBITS-1 */
#define HMASK (((chunk)1<<HBITS)-1)    /**< Mask = 2^HBITS-1 */
#define HMASK1 (((chunk)1<<HBITS1)-1)  /**< Mask = 2^HBITS1-1 */

#define MODBITS MBITS                             /**< Number of bits in Modulus for selected curve */
#define TBITS (MBITS%BASEBITS)                    /**< Number of active bits in top word */
#define TMASK (((chunk)1<<TBITS)-1)               /**< Mask for active bits in top word */
#define NEXCESS (1<<(CHUNK-BASEBITS-1))           /**< 2^(CHUNK-BASEBITS-1) - digit cannot be multiplied by more than this before normalisation */
#define FEXCESS ((chunk)1<<(BASEBITS*NLEN-MBITS)) /**< 2^(BASEBITS*NLEN-MODBITS) - normalised BIG can be multiplied by more than this before reduction */
#define OMASK (-((chunk)(1)<<TBITS))              /**<  for masking out overflow bits */

/* catch field excesses */
#define EXCESS(a) ((a[NLEN-1]&OMASK)>>(TBITS)) /**< Field Excess */


#define P_MBITS (MODBYTES*8) /**< TODO */
#define P_TBITS (P_MBITS%BASEBITS) /**< TODO */
#define P_EXCESS(a) ((a[NLEN-1])>>(P_TBITS)) /**< TODO */
#define P_FEXCESS ((chunk)1<<(BASEBITS*NLEN-P_MBITS)) /**< TODO */



/* Field Params - see rom.c */
extern const BIG Modulus;  /**< Actual Modulus set in rom.c */
extern const chunk MConst; /**< Montgomery only - 1/p mod 2^BASEBITS */

/* Curve Params - see rom.c */
extern const int CURVE_A;     /**< Elliptic curve A parameter */
extern const BIG CURVE_B;     /**< Elliptic curve B parameter */
extern const BIG CURVE_Order; /**< Elliptic curve group order */
extern const BIG CURVE_Cof;   /**< Elliptic curve cofactor */

/* Generator point on G1 */
extern const BIG CURVE_Gx; /**< x-coordinate of generator point in group G1  */
extern const BIG CURVE_Gy; /**< y-coordinate of generator point in group G1  */

/* For Pairings only */

/* Generator point on G2 */
extern const BIG CURVE_Pxa; /**< real part of x-coordinate of generator point in group G2 */
extern const BIG CURVE_Pxb; /**< imaginary part of x-coordinate of generator point in group G2 */
extern const BIG CURVE_Pya; /**< real part of y-coordinate of generator point in group G2 */
extern const BIG CURVE_Pyb; /**< imaginary part of y-coordinate of generator point in group G2 */

extern const BIG CURVE_Bnx; /**< BN curve x parameter */

extern const BIG CURVE_Cru; /**< BN curve Cube Root of Unity */

extern const BIG CURVE_Fra; /**< real part of BN curve Frobenius Constant */
extern const BIG CURVE_Frb; /**< imaginary part of BN curve Frobenius Constant */


extern const BIG CURVE_W[2];	 /**< BN curve constant for GLV decomposition */
extern const BIG CURVE_SB[2][2]; /**< BN curve constant for GLV decomposition */
extern const BIG CURVE_WB[4];	 /**< BN curve constant for GS decomposition */
extern const BIG CURVE_BB[4][4]; /**< BN curve constant for GS decomposition */

/* Structures */

/**
	@brief ECP structure - Elliptic Curve Point over base field
*/

typedef struct
{
#if CURVETYPE!=EDWARDS
    int inf; /**< Infinity Flag - not needed for Edwards representation */
#endif
    BIG x; /**< x-coordinate of point */
#if CURVETYPE!=MONTGOMERY
    BIG y; /**< y-coordinate of point. Not needed for Montgomery representation */
#endif
    BIG z;/**< z-coordinate of point */
} ECP;

/**
	@brief FP2 Structure - quadratic extension field
*/

typedef struct
{
    BIG a; /**< real part of FP2 */
    BIG b; /**< imaginary part of FP2 */
} FP2;

/**
	@brief FP4 Structure - towered over two FP2
*/

typedef struct
{
    FP2 a; /**< real part of FP4 */
    FP2 b; /**< imaginary part of FP4 */
} FP4;

/**
	@brief FP12 Structure - towered over three FP4
*/

typedef struct
{
    FP4 a; /**< first part of FP12 */
    FP4 b; /**< second part of FP12 */
    FP4 c; /**< third part of FP12 */
} FP12;

/**
	@brief ECP2 Structure - Elliptic Curve Point over quadratic extension field
*/

typedef struct
{
    int inf; /**< Infinity Flag */
    FP2 x;   /**< x-coordinate of point */
    FP2 y;   /**< y-coordinate of point */
    FP2 z;   /**< z-coordinate of point */
} ECP2;

/**
 * @brief SHA256 hash function instance */
typedef struct
{
    unsign32 length[2]; /**< 64-bit input length */
    unsign32 h[8];      /**< Internal state */
    unsign32 w[80];	/**< Internal state */
    int hlen;		/**< Hash length in bytes */
} hash256;

/**
 * @brief SHA384-512 hash function instance */
typedef struct
{
    unsign64 length[2]; /**< 64-bit input length */
    unsign64 h[8];      /**< Internal state */
    unsign64 w[80];	/**< Internal state */
    int hlen;           /**< Hash length in bytes */
} hash512;

/**
 * @brief SHA384 hash function instance */
typedef hash512 hash384;

#define SHA256 32 /**< SHA-256 hashing */
#define SHA384 48 /**< SHA-384 hashing */
#define SHA512 64 /**< SHA-512 hashing */

/* Symmetric Encryption AES structure */

#define ECB   0  /**< Electronic Code Book */
#define CBC   1  /**< Cipher Block Chaining */
#define CFB1  2  /**< Cipher Feedback - 1 byte */
#define CFB2  3  /**< Cipher Feedback - 2 bytes */
#define CFB4  5  /**< Cipher Feedback - 4 bytes */
#define OFB1  14 /**< Output Feedback - 1 byte */
#define OFB2  15 /**< Output Feedback - 2 bytes */
#define OFB4  17 /**< Output Feedback - 4 bytes */
#define OFB8  21 /**< Output Feedback - 8 bytes */
#define OFB16 29 /**< Output Feedback - 16 bytes */
#define CTR1  30 /**< Counter Mode - 1 byte */
#define CTR2  31 /**< Counter Mode - 2 bytes */
#define CTR4  33 /**< Counter Mode - 4 bytes */
#define CTR8  37 /**< Counter Mode - 8 bytes */
#define CTR16 45 /**< Counter Mode - 16 bytes */

#define uchar unsigned char  /**<  Unsigned char */

/**
	@brief AES instance
*/


typedef struct
{
    int Nk;            /**< AES Key Length */
    int Nr;            /**< AES Number of rounds */
    int mode;          /**< AES mode of operation */
    unsign32 fkey[60]; /**< subkeys for encrypton */
    unsign32 rkey[60]; /**< subkeys for decrypton */
    char f[16];        /**< buffer for chaining vector */
} amcl_aes;

/* AES-GCM suppport.  */

#define GCM_ACCEPTING_HEADER 0   /**< GCM status */
#define GCM_ACCEPTING_CIPHER 1   /**< GCM status */
#define GCM_NOT_ACCEPTING_MORE 2 /**< GCM status */
#define GCM_FINISHED 3           /**< GCM status */
#define GCM_ENCRYPTING 0         /**< GCM mode */
#define GCM_DECRYPTING 1         /**< GCM mode */


/**
	@brief GCM mode instance, using AES internally
*/

typedef struct
{
    unsign32 table[128][4]; /**< 2k byte table */
    uchar stateX[16];	    /**< GCM Internal State */
    uchar Y_0[16];	    /**< GCM Internal State */
    unsign32 lenA[2];	    /**< GCM 64-bit length of header */
    unsign32 lenC[2];	    /**< GCM 64-bit length of ciphertext */
    int status;		    /**< GCM Status */
    amcl_aes a;		    /**< Internal Instance of AMCL_AES cipher */
} gcm;

/* Marsaglia & Zaman Random number generator constants */

#define NK   21 /**< PRNG constant */
#define NJ   6  /**< PRNG constant */
#define NV   8  /**< PRNG constant */


/**
	@brief Cryptographically secure pseudo-random number generator instance
*/

typedef struct
{
    unsign32 ira[NK]; /**< random number array   */
    int      rndptr;  /**< pointer into array */
    unsign32 borrow;  /**<  borrow as a result of subtraction */
    int pool_ptr;     /**< pointer into random pool */
    char pool[32];    /**< random pool */
} csprng;


/**
	@brief Portable representation of a big positive number
*/

typedef struct
{
    int len;   /**< length in bytes  */
    int max;   /**< max length allowed - enforce truncation  */
    char *val; /**< byte array  */
} octet;

/**
	@brief Integer Factorisation Public Key
*/

typedef struct
{
    sign32 e;     /**< RSA exponent (typically 65537) */
    BIG n[FFLEN]; /**< An array of BIGs to store public key */
} rsa_public_key;

/**
	@brief Integer Factorisation Private Key
*/

typedef struct
{
    BIG p[FFLEN/2];  /**< secret prime p  */
    BIG q[FFLEN/2];  /**< secret prime q  */
    BIG dp[FFLEN/2]; /**< decrypting exponent mod (p-1)  */
    BIG dq[FFLEN/2]; /**< decrypting exponent mod (q-1)  */
    BIG c[FFLEN/2];  /**< 1/p mod q */
} rsa_private_key;

/*

Note that a normalised BIG consists of digits mod 2^BASEBITS
However BIG digits may be "extended" up to 2^(WORDLENGTH-1).

BIGs in extended form may need to be normalised before certain
operations.

A BIG may be "reduced" to be less that the Modulus, or it
may be "unreduced" and allowed to grow greater than the
Modulus.

Normalisation is quite fast. Reduction involves conditional branches,
which can be regarded as significant "speed bumps". We try to
delay reductions as much as possible. Reductions may also involve
side channel leakage, so delaying and batching them
hopefully disguises internal operations.

*/

/* BIG number prototypes */

/**	@brief Calculates a*b+c+*d
 *
	Calculate partial product of a.b, add in carry c, and add total to d
	@param a multiplier
	@param b multiplicand
	@param c carry
	@param d pointer to accumulated bottom half of result
	@return top half of result
 */
extern chunk muladd(chunk a,chunk b,chunk c,chunk *d);
/**	@brief Tests for BIG equal to zero
 *
	@param x a BIG number
	@return 1 if zero, else returns 0
 */
extern int BIG_iszilch(BIG x);
/**	@brief Tests for DBIG equal to zero
 *
	@param x a DBIG number
	@return 1 if zero, else returns 0
 */
extern int BIG_diszilch(DBIG x);
/**	@brief Outputs a BIG number to the console
 *
	@param x a BIG number
 */
extern void BIG_output(BIG x);
/**	@brief Outputs a BIG number to the console in raw form (for debugging)
 *
	@param x a BIG number
 */
extern void BIG_rawoutput(BIG x);
/**	@brief Conditional constant time swap of two BIG numbers
 *
	Conditionally swaps parameters in constant time (without branching)
	@param x a BIG number
	@param y another BIG number
	@param s swap takes place if not equal to 0
 */
extern void BIG_cswap(BIG x,BIG y,int s);
/**	@brief Conditional copy of BIG number
 *
	Conditionally copies second parameter to the first (without branching)
	@param x a BIG number
	@param y another BIG number
	@param s copy takes place if not equal to 0
 */
extern void BIG_cmove(BIG x,BIG y,int s);
/**	@brief Conditional copy of DBIG number
 *
	Conditionally copies second parameter to the first (without branching)
	@param x a DBIG number
	@param y another DBIG number
	@param s copy takes place if not equal to 0
 */
extern void BIG_dcmove(BIG x,BIG y,int s);
/**	@brief Convert from BIG number to byte array
 *
	@param a byte array
	@param x BIG number
 */
extern void BIG_toBytes(char *a,BIG x);
/**	@brief Convert to BIG number from byte array
 *
	@param x BIG number
	@param a byte array
 */
extern void BIG_fromBytes(BIG x,char *a);
/**	@brief Convert to BIG number from byte array of given length
 *
	@param x BIG number
	@param a byte array
	@param s byte array length
 */
extern void BIG_fromBytesLen(BIG x,char *a,int s);
/**@brief Convert to DBIG number from byte array of given length
 *
   @param x DBIG number
   @param a byte array
   @param s byte array length
 */
extern void BIG_dfromBytesLen(DBIG x,char *a,int s);
/**	@brief Outputs a DBIG number to the console
 *
	@param x a DBIG number
 */
extern void BIG_doutput(DBIG x);
/**	@brief Copy BIG from Read-Only Memory to a BIG
 *
	@param x BIG number
	@param y BIG number in ROM
 */
extern void BIG_rcopy(BIG x,const BIG y);
/**	@brief Copy BIG to another BIG
 *
	@param x BIG number
	@param y BIG number to be copied
 */
extern void BIG_copy(BIG x,BIG y);
/**	@brief Copy DBIG to another DBIG
 *
	@param x DBIG number
	@param y DBIG number to be copied
 */
extern void BIG_dcopy(DBIG x,DBIG y);
/**	@brief Copy BIG to upper half of DBIG
 *
	@param x DBIG number
	@param y BIG number to be copied
 */
extern void BIG_dsucopy(DBIG x,BIG y);
/**	@brief Copy BIG to lower half of DBIG
 *
	@param x DBIG number
	@param y BIG number to be copied
 */
extern void BIG_dscopy(DBIG x,BIG y);
/**	@brief Copy lower half of DBIG to a BIG
 *
	@param x BIG number
	@param y DBIG number to be copied
 */
extern void BIG_sdcopy(BIG x,DBIG y);
/**	@brief Copy upper half of DBIG to a BIG
 *
	@param x BIG number
	@param y DBIG number to be copied
 */
extern void BIG_sducopy(BIG x,DBIG y);
/**	@brief Set BIG to zero
 *
	@param x BIG number to be set to zero
 */
extern void BIG_zero(BIG x);
/**	@brief Set DBIG to zero
 *
	@param x DBIG number to be set to zero
 */
extern void BIG_dzero(DBIG x);
/**	@brief Set BIG to one (unity)
 *
	@param x BIG number to be set to one.
 */
extern void BIG_one(BIG x);
/**	@brief Set BIG to inverse mod 2^256
 *
	@param x BIG number to be inverted
 */
extern void BIG_invmod2m(BIG x);
/**	@brief Set BIG to sum of two BIGs - output not normalised
 *
	@param x BIG number, sum of other two
	@param y BIG number
	@param z BIG number
 */
extern void BIG_add(BIG x,BIG y,BIG z);
/**	@brief Increment BIG by a small integer - output not normalised
 *
	@param x BIG number to be incremented
	@param i integer
 */
extern void BIG_inc(BIG x,int i);
/**	@brief Set BIG to difference of two BIGs
 *
	@param x BIG number, difference of other two - output not normalised
	@param y BIG number
	@param z BIG number
 */
extern void BIG_sub(BIG x,BIG y,BIG z);
/**	@brief Decrement BIG by a small integer - output not normalised
 *
	@param x BIG number to be decremented
	@param i integer
 */
extern void BIG_dec(BIG x,int i);
/**	@brief Set DBIG to difference of two DBIGs
 *
	@param x DBIG number, difference of other two - output not normalised
	@param y DBIG number
	@param z DBIG number
 */
extern void BIG_dsub(DBIG x,DBIG y,DBIG z);
/**	@brief Multiply BIG by a small integer - output not normalised
 *
	@param x BIG number, product of other two
	@param y BIG number
	@param i small integer
 */
extern void BIG_imul(BIG x,BIG y,int i);
/**	@brief Multiply BIG by not-so-small small integer - output normalised
 *
	@param x BIG number, product of other two
	@param y BIG number
	@param i small integer
	@return Overflowing bits
 */
extern chunk BIG_pmul(BIG x,BIG y,int i);
/**	@brief Divide BIG by 3 - output normalised
 *
	@param x BIG number
	@return Remainder
 */
extern int BIG_div3(BIG x);
/**	@brief Multiply BIG by even bigger small integer resulting in a DBIG - output normalised
 *
	@param x DBIG number, product of other two
	@param y BIG number
	@param i small integer
 */
extern void BIG_pxmul(DBIG x,BIG y,int i);
/**	@brief Multiply BIG by another BIG resulting in DBIG - inputs normalised and output normalised
 *
	@param x DBIG number, product of other two
	@param y BIG number
	@param z BIG number
 */
extern void BIG_mul(DBIG x,BIG y,BIG z);
/**	@brief Multiply BIG by another BIG resulting in another BIG - inputs normalised and output normalised
 *
	Note that the product must fit into a BIG, and x must be distinct from y and z
	@param x BIG number, product of other two
	@param y BIG number
	@param z BIG number
 */
extern void BIG_smul(BIG x,BIG y,BIG z);
/**	@brief Square BIG resulting in a DBIG - input normalised and output normalised
 *
	@param x DBIG number, square of a BIG
	@param y BIG number to be squared
 */
extern void BIG_sqr(DBIG x,BIG y);
/**	@brief Shifts a BIG left by any number of bits - input must be normalised, output normalised
 *
	@param x BIG number to be shifted
	@param s Number of bits to shift
 */
extern void BIG_shl(BIG x,int s);
/**	@brief Fast shifts a BIG left by a small number of bits - input must be normalised, output will be normalised
 *
	The number of bits to be shifted must be less than BASEBITS
	@param x BIG number to be shifted
	@param s Number of bits to shift
	@return Overflow bits
 */
extern int BIG_fshl(BIG x,int s);
/**	@brief Shifts a DBIG left by any number of bits - input must be normalised, output normalised
 *
	@param x DBIG number to be shifted
	@param s Number of bits to shift
 */
extern void BIG_dshl(DBIG x,int s);
/**	@brief Shifts a BIG right by any number of bits - input must be normalised, output normalised
 *
	@param x BIG number to be shifted
	@param s Number of bits to shift
 */
extern void BIG_shr(BIG x,int s);
/**	@brief Fast shifts a BIG right by a small number of bits - input must be normalised, output will be normalised
 *
	The number of bits to be shifted must be less than BASEBITS
	@param x BIG number to be shifted
	@param s Number of bits to shift
	@return Shifted out bits
 */
extern int BIG_fshr(BIG x,int s);
/**	@brief Shifts a DBIG right by any number of bits - input must be normalised, output normalised
 *
	@param x DBIG number to be shifted
	@param s Number of bits to shift
 */
extern void BIG_dshr(DBIG x,int s);
/**	@brief Splits a DBIG into two BIGs - input must be normalised, outputs normalised
 *
	Internal function. The value of s must be approximately in the middle of the DBIG.
	Typically used to extract z mod 2^MODBITS and z/2^MODBITS
	@param x BIG number, top half of z
	@param y BIG number, bottom half of z
	@param z DBIG number to be split in two.
	@param s Bit position at which to split
	@return carry-out from top half
 */
extern chunk BIG_split(BIG x,BIG y,DBIG z,int s);
/**	@brief Normalizes a BIG number - output normalised
 *
	All digits of the input BIG are reduced mod 2^BASEBITS
	@param x BIG number to be normalised
 */
extern chunk BIG_norm(BIG x);
/**	@brief Normalizes a DBIG number - output normalised
 *
	All digits of the input DBIG are reduced mod 2^BASEBITS
	@param x DBIG number to be normalised
 */
extern void BIG_dnorm(DBIG x);
/**	@brief Compares two BIG numbers. Inputs must be normalised externally
 *
	@param x first BIG number to be compared
	@param y second BIG number to be compared
	@return -1 is x<y, 0 if x=y, 1 if x>y
 */
extern int BIG_comp(BIG x,BIG y);
/**	@brief Compares two DBIG numbers. Inputs must be normalised externally
 *
	@param x first DBIG number to be compared
	@param y second DBIG number to be compared
	@return -1 is x<y, 0 if x=y, 1 if x>y
 */
extern int BIG_dcomp(DBIG x,DBIG y);
/**	@brief Calculate number of bits in a BIG - output normalised
 *
	@param x BIG number
	@return Number of bits in x
 */
extern int BIG_nbits(BIG x);
/**	@brief Calculate number of bits in a DBIG - output normalised
 *
	@param x DBIG number
	@return Number of bits in x
 */
extern int BIG_dnbits(DBIG x);
/**	@brief Reduce x mod n - input and output normalised
 *
	Slow but rarely used
	@param x BIG number to be reduced mod n
	@param n The modulus
 */
extern void BIG_mod(BIG x,BIG n);
/**	@brief Divide x by n - output normalised
 *
	Slow but rarely used
	@param x BIG number to be divided by n
	@param n The Divisor
 */
extern void BIG_sdiv(BIG x,BIG n);
/**	@brief  x=y mod n - output normalised
 *
	Slow but rarely used. y is destroyed.
	@param x BIG number, on exit = y mod n
	@param y DBIG number
	@param n Modulus
 */
extern void BIG_dmod(BIG x,DBIG y,BIG n);
/**	@brief  x=y/n - output normalised
 *
	Slow but rarely used. y is destroyed.
	@param x BIG number, on exit = y/n
	@param y DBIG number
	@param n Modulus
 */
extern void BIG_ddiv(BIG x,DBIG y,BIG n);
/**	@brief  return parity of BIG, that is the least significant bit
 *
	@param x BIG number
	@return 0 or 1
 */
extern int BIG_parity(BIG x);
/**	@brief  return i-th of BIG
 *
	@param x BIG number
	@param i the bit of x to be returned
	@return 0 or 1
 */
extern int BIG_bit(BIG x,int i);
/**	@brief  return least significant bits of a BIG
 *
	@param x BIG number
	@param n number of bits to return. Assumed to be less than BASEBITS.
	@return least significant n bits as an integer
 */
extern int BIG_lastbits(BIG x,int n);
/**	@brief  Create a random BIG from a random number generator
 *
	Assumes that the random number generator has been suitably initialised
	@param x BIG number, on exit a random number
	@param r A pointer to a Cryptographically Secure Random Number Generator
 */
extern void BIG_random(BIG x,csprng *r);
/**	@brief  Create an unbiased random BIG from a random number generator, reduced with respect to a modulus
 *
	Assumes that the random number generator has been suitably initialised
	@param x BIG number, on exit a random number
	@param n The modulus
	@param r A pointer to a Cryptographically Secure Random Number Generator
 */
extern void BIG_randomnum(BIG x,BIG n,csprng *r);
/**	brief  return NAF (Non-Adjacent-Form) value as +/- 1, 3 or 5, inputs must be normalised
 *
	Given x and 3*x extracts NAF value from given bit position, and returns number of bits processed, and number of trailing zeros detected if any
	param x BIG number
	param x3 BIG number, three times x
	param i bit position
	param nbs pointer to integer returning number of bits processed
	param nzs pointer to integer returning number of trailing 0s
	return + or - 1, 3 or 5
*/
//extern int BIG_nafbits(BIG x,BIG x3,int i,int *nbs,int *nzs);

/**	@brief  Calculate x=y*z mod n
 *
	Slow method for modular multiplication
	@param x BIG number, on exit = y*z mod n
	@param y BIG number
	@param z BIG number
	@param n The BIG Modulus
 */
extern void BIG_modmul(BIG x,BIG y,BIG z,BIG n);
/**	@brief  Calculate x=y/z mod n
 *
	Slow method for modular division
	@param x BIG number, on exit = y/z mod n
	@param y BIG number
	@param z BIG number
	@param n The BIG Modulus
 */
extern void BIG_moddiv(BIG x,BIG y,BIG z,BIG n);
/**	@brief  Calculate x=y^2 mod n
 *
	Slow method for modular squaring
	@param x BIG number, on exit = y^2 mod n
	@param y BIG number
	@param n The BIG Modulus
 */
extern void BIG_modsqr(BIG x,BIG y,BIG n);
/**	@brief  Calculate x=-y mod n
 *
	Modular negation
	@param x BIG number, on exit = -y mod n
	@param y BIG number
	@param n The BIG Modulus
 */
extern void BIG_modneg(BIG x,BIG y,BIG n);
/**	@brief  Calculate jacobi Symbol (x/y)
 *
	@param x BIG number
	@param y BIG number
	@return Jacobi symbol, -1,0 or 1
 */
extern int BIG_jacobi(BIG x,BIG y);
/**	@brief  Calculate x=1/y mod n
 *
	Modular Inversion - This is slow. Uses binary method.
	@param x BIG number, on exit = 1/y mod n
	@param y BIG number
	@param n The BIG Modulus
 */
extern void BIG_invmodp(BIG x,BIG y,BIG n);
/** @brief Calculate x=x mod 2^m
 *
	Truncation
	@param x BIG number, on reduced mod 2^m
	@param m new truncated size
*/
extern void BIG_mod2m(BIG x,int m);



/* FP prototypes */

/**	@brief Tests for BIG equal to zero mod Modulus
 *
	@param x BIG number to be tested
	@return 1 if zero, else returns 0
 */
extern int FP_iszilch(BIG x);
/**	@brief Converts from BIG integer to n-residue form mod Modulus
 *
	@param x BIG number to be converted
 */
extern void FP_nres(BIG x);
/**	@brief Converts from n-residue form back to BIG integer form
 *
	@param x BIG number to be converted
 */
extern void FP_redc(BIG x);
/**	@brief Sets BIG to representation of unity in n-residue form
 *
	@param x BIG number to be set equal to unity.
 */
extern void FP_one(BIG x);
/**	@brief Reduces DBIG to BIG exploiting special form of the modulus
 *
	This function comes in different flavours depending on the form of Modulus that is currently in use.
	@param r BIG number, on exit = d mod Modulus
	@param d DBIG number to be reduced
 */
extern void FP_mod(BIG r,DBIG d);
/**	@brief Fast Modular multiplication of two BIGs in n-residue form, mod Modulus
 *
	Uses appropriate fast modular reduction method
	@param x BIG number, on exit the modular product = y*z mod Modulus
	@param y BIG number, the multiplicand
	@param z BIG number, the multiplier
 */
extern void FP_mul(BIG x,BIG y,BIG z);
/**	@brief Fast Modular multiplication of a BIG in n-residue form, by a small integer, mod Modulus
 *
	@param x BIG number, on exit the modular product = y*i mod Modulus
	@param y BIG number, the multiplicand
	@param i a small number, the multiplier
 */
extern void FP_imul(BIG x,BIG y,int i);
/**	@brief Fast Modular squaring of a BIG in n-residue form, mod Modulus
 *
	Uses appropriate fast modular reduction method
	@param x BIG number, on exit the modular product = y^2 mod Modulus
	@param y BIG number, the number to be squared

 */
extern void FP_sqr(BIG x,BIG y);
/**	@brief Modular addition of two BIGs in n-residue form, mod Modulus
 *
	@param x BIG number, on exit the modular sum = y+z mod Modulus
	@param y BIG number
	@param z BIG number
 */
extern void FP_add(BIG x,BIG y,BIG z);
/**	@brief Modular subtraction of two BIGs in n-residue form, mod Modulus
 *
	@param x BIG number, on exit the modular difference = y-z mod Modulus
	@param y BIG number
	@param z BIG number
 */
extern void FP_sub(BIG x,BIG y,BIG z);
/**	@brief Modular division by 2 of a BIG in n-residue form, mod Modulus
 *
	@param x BIG number, on exit =y/2 mod Modulus
	@param y BIG number
 */
extern void FP_div2(BIG x,BIG y);
/**	@brief Fast Modular exponentiation of a BIG in n-residue form, to the power of a BIG, mod Modulus
 *
	@param x BIG number, on exit  = y^z mod Modulus
	@param y BIG number
	@param z Big number exponent
 */
extern void FP_pow(BIG x,BIG y,BIG z);
/**	@brief Fast Modular square root of a BIG in n-residue form, mod Modulus
 *
	@param x BIG number, on exit  = sqrt(y) mod Modulus
	@param y BIG number, the number whose square root is calculated

 */
extern void FP_sqrt(BIG x,BIG y);
/**	@brief Modular negation of a BIG in n-residue form, mod Modulus
 *
	@param x BIG number, on exit = -y mod Modulus
	@param y BIG number
 */
extern void FP_neg(BIG x,BIG y);
/**	@brief Outputs a BIG number that is in n-residue form to the console
 *
	Converts from n-residue form before output
	@param x a BIG number
 */
extern void FP_output(BIG x);
/**	@brief Outputs a BIG number that is in n-residue form to the console, in raw form
 *
	Converts from n-residue form before output
	@param x a BIG number
 */
extern void FP_rawoutput(BIG x);
/**	@brief Reduces possibly unreduced BIG mod Modulus
 *
	@param x BIG number, on exit reduced mod Modulus
 */
extern void FP_reduce(BIG x);
/**	@brief Tests for BIG a quadratic residue mod Modulus
 *
	@param x BIG number to be tested
	@return 1 if quadratic residue, else returns 0 if quadratic non-residue
 */
extern int FP_qr(BIG x);
/**	@brief Modular inverse of a BIG in n-residue form, mod Modulus
 *
	@param x BIG number, on exit = 1/y mod Modulus
	@param y BIG number
 */
extern void FP_inv(BIG x,BIG y);


/* FP2 prototypes */

/**	@brief Tests for FP2 equal to zero
 *
	@param x FP2 number to be tested
	@return 1 if zero, else returns 0
 */
extern int FP2_iszilch(FP2 *x);
/**	@brief Conditional copy of FP2 number
 *
	Conditionally copies second parameter to the first (without branching)
	@param x FP2 instance, set to y if s!=0
	@param y another FP2 instance
	@param s copy only takes place if not equal to 0
 */
extern void FP2_cmove(FP2 *x,FP2 *y,int s);
/**	@brief Tests for FP2 equal to one
 *
	@param x FP2 instance to be tested
	@return 1 if x=1, else returns 0
 */
extern int FP2_isunity(FP2 *x);
/**	@brief Tests for equality of two FP2s
 *
	@param x FP2 instance to be compared
	@param y FP2 instance to be compared
	@return 1 if x=y, else returns 0
 */
extern int FP2_equals(FP2 *x,FP2 *y);
/**	@brief Initialise FP2 from two BIGs in n-residue form
 *
	@param x FP2 instance to be initialised
	@param a BIG to form real part of FP2
	@param b BIG to form imaginary part of FP2
 */
extern void FP2_from_FPs(FP2 *x,BIG a,BIG b);
/**	@brief Initialise FP2 from two BIG integers
 *
	@param x FP2 instance to be initialised
	@param a BIG to form real part of FP2
	@param b BIG to form imaginary part of FP2
 */
extern void FP2_from_BIGs(FP2 *x,BIG a,BIG b);
/**	@brief Initialise FP2 from single BIG in n-residue form
 *
	Imaginary part is set to zero
	@param x FP2 instance to be initialised
	@param a BIG to form real part of FP2
 */
extern void FP2_from_FP(FP2 *x,BIG a);
/**	@brief Initialise FP2 from single BIG
 *
	Imaginary part is set to zero
	@param x FP2 instance to be initialised
	@param a BIG to form real part of FP2
 */
extern void FP2_from_BIG(FP2 *x,BIG a);
/**	@brief Copy FP2 to another FP2
 *
	@param x FP2 instance, on exit = y
	@param y FP2 instance to be copied
 */
extern void FP2_copy(FP2 *x,FP2 *y);
/**	@brief Set FP2 to zero
 *
	@param x FP2 instance to be set to zero
 */
extern void FP2_zero(FP2 *x);
/**	@brief Set FP2 to unity
 *
	@param x FP2 instance to be set to one
 */
extern void FP2_one(FP2 *x);
/**	@brief Negation of FP2
 *
	@param x FP2 instance, on exit = -y
	@param y FP2 instance
 */
extern void FP2_neg(FP2 *x,FP2 *y);
/**	@brief Conjugation of FP2
 *
	If y=(a,b) on exit x=(a,-b)
	@param x FP2 instance, on exit = conj(y)
	@param y FP2 instance
 */
extern void FP2_conj(FP2 *x,FP2 *y);
/**	@brief addition of two FP2s
 *
	@param x FP2 instance, on exit = y+z
	@param y FP2 instance
	@param z FP2 instance
 */
extern void FP2_add(FP2 *x,FP2 *y,FP2 *z);
/**	@brief subtraction of two FP2s
 *
	@param x FP2 instance, on exit = y-z
	@param y FP2 instance
	@param z FP2 instance
 */
extern void FP2_sub(FP2 *x,FP2 *y,FP2 *z);
/**	@brief Multiplication of an FP2 by an n-residue
 *
	@param x FP2 instance, on exit = y*b
	@param y FP2 instance
	@param b BIG n-residue
 */
extern void FP2_pmul(FP2 *x,FP2 *y,BIG b);
/**	@brief Multiplication of an FP2 by a small integer
 *
	@param x FP2 instance, on exit = y*i
	@param y FP2 instance
	@param i an integer
 */
extern void FP2_imul(FP2 *x,FP2 *y,int i);
/**	@brief Squaring an FP2
 *
	@param x FP2 instance, on exit = y^2
	@param y FP2 instance
 */
extern void FP2_sqr(FP2 *x,FP2 *y);
/**	@brief Multiplication of two FP2s
 *
	@param x FP2 instance, on exit = y*z
	@param y FP2 instance
	@param z FP2 instance
 */
extern void FP2_mul(FP2 *x,FP2 *y,FP2 *z);
/**	@brief Formats and outputs an FP2 to the console
 *
	@param x FP2 instance
 */
extern void FP2_output(FP2 *x);
/**	@brief Formats and outputs an FP2 to the console in raw form (for debugging)
 *
	@param x FP2 instance
 */
extern void FP2_rawoutput(FP2 *x);
/**	@brief Inverting an FP2
 *
	@param x FP2 instance, on exit = 1/y
	@param y FP2 instance
 */
extern void FP2_inv(FP2 *x,FP2 *y);
/**	@brief Divide an FP2 by 2
 *
	@param x FP2 instance, on exit = y/2
	@param y FP2 instance
 */
extern void FP2_div2(FP2 *x,FP2 *y);
/**	@brief Multiply an FP2 by (1+sqrt(-1))
 *
	Note that (1+sqrt(-1)) is irreducible for FP4
	@param x FP2 instance, on exit = x*(1+sqrt(-1))
 */
extern void FP2_mul_ip(FP2 *x);
/**	@brief Divide an FP2 by (1+sqrt(-1))
 *
	Note that (1+sqrt(-1)) is irreducible for FP4
	@param x FP2 instance, on exit = x/(1+sqrt(-1))
 */
extern void FP2_div_ip(FP2 *x);
/**	@brief Normalises the components of an FP2
 *
	@param x FP2 instance to be normalised
 */
extern void FP2_norm(FP2 *x);
/**	@brief Reduces all components of possibly unreduced FP2 mod Modulus
 *
	@param x FP2 instance, on exit reduced mod Modulus
 */
extern void FP2_reduce(FP2 *x);
/**	@brief Raises an FP2 to the power of a BIG
 *
	@param x FP2 instance, on exit = y^b
	@param y FP2 instance
	@param b BIG number
 */
extern void FP2_pow(FP2 *x,FP2 *y,BIG b);
/**	@brief Square root of an FP2
 *
	@param x FP2 instance, on exit = sqrt(y)
	@param y FP2 instance
 */
extern int FP2_sqrt(FP2 *x,FP2 *y);



/* ECP E(Fp) prototypes */
/**	@brief Tests for ECP point equal to infinity
 *
	@param P ECP point to be tested
	@return 1 if infinity, else returns 0
 */
extern int ECP_isinf(ECP *P);
/**	@brief Tests for equality of two ECPs
 *
	@param P ECP instance to be compared
	@param Q ECP instance to be compared
	@return 1 if P=Q, else returns 0
 */
extern int ECP_equals(ECP *P,ECP *Q);
/**	@brief Copy ECP point to another ECP point
 *
	@param P ECP instance, on exit = Q
	@param Q ECP instance to be copied
 */
extern void ECP_copy(ECP *P,ECP *Q);
/**	@brief Negation of an ECP point
 *
	@param P ECP instance, on exit = -P
 */
extern void ECP_neg(ECP *P);
/**	@brief Set ECP to point-at-infinity
 *
	@param P ECP instance to be set to infinity
 */
extern void ECP_inf(ECP *P);
/**	@brief Calculate Right Hand Side of curve equation y^2=f(x)
 *
	Function f(x) depends on form of elliptic curve, Weierstrass, Edwards or Montgomery.
	Used internally.
	@param r BIG n-residue value of f(x)
	@param x BIG n-residue x
 */
extern void ECP_rhs(BIG r,BIG x);
/**	@brief Set ECP to point(x,y) given just x and sign of y
 *
	Point P set to infinity if no such point on the curve. If x is on the curve then y is calculated from the curve equation.
	The correct y value (plus or minus) is selected given its sign s.
	@param P ECP instance to be set (x,[y])
	@param x BIG x coordinate of point
	@param s an integer representing the "sign" of y, in fact its least significant bit.
 */
extern int ECP_setx(ECP *P,BIG x,int s);

#if CURVETYPE==MONTGOMERY
/**	@brief Set ECP to point(x,[y]) given x
 *
	Point P set to infinity if no such point on the curve. Note that y coordinate is not needed.
	@param P ECP instance to be set (x,[y])
	@param x BIG x coordinate of point
	@return 1 if point exists, else 0
 */
extern int ECP_set(ECP *P,BIG x);
/**	@brief Extract x coordinate of an ECP point P
 *
	@param x BIG on exit = x coordinate of point
	@param P ECP instance (x,[y])
	@return -1 if P is point-at-infinity, else 0
 */
extern int ECP_get(BIG x,ECP *P);
/**	@brief Adds ECP instance Q to ECP instance P, given difference D=P-Q
 *
	Differential addition of points on a Montgomery curve
	@param P ECP instance, on exit =P+Q
	@param Q ECP instance to be added to P
	@param D Difference between P and Q
 */
extern void ECP_add(ECP *P,ECP *Q,ECP *D);
#else
/**	@brief Set ECP to point(x,y) given x and y
 *
	Point P set to infinity if no such point on the curve.
	@param P ECP instance to be set (x,y)
	@param x BIG x coordinate of point
	@param y BIG y coordinate of point
	@return 1 if point exists, else 0
 */
extern int ECP_set(ECP *P,BIG x,BIG y);
/**	@brief Extract x and y coordinates of an ECP point P
 *
	If x=y, returns only x
	@param x BIG on exit = x coordinate of point
	@param y BIG on exit = y coordinate of point (unless x=y)
	@param P ECP instance (x,y)
	@return sign of y, or -1 if P is point-at-infinity
 */
extern int ECP_get(BIG x,BIG y,ECP *P);
/**	@brief Adds ECP instance Q to ECP instance P
 *
	@param P ECP instance, on exit =P+Q
	@param Q ECP instance to be added to P
 */
extern void ECP_add(ECP *P,ECP *Q);
/**	@brief Subtracts ECP instance Q from ECP instance P
 *
	@param P ECP instance, on exit =P-Q
	@param Q ECP instance to be subtracted from P
 */
extern void ECP_sub(ECP *P,ECP *Q);
#endif
/**	@brief Converts an ECP point from Projective (x,y,z) coordinates to affine (x,y) coordinates
 *
	@param P ECP instance to be converted to affine form
 */
extern void ECP_affine(ECP *P);
/**	@brief Formats and outputs an ECP point to the console, in projective coordinates
 *
	@param P ECP instance to be printed
 */
extern void ECP_outputxyz(ECP *P);
/**	@brief Formats and outputs an ECP point to the console, converted to affine coordinates
 *
	@param P ECP instance to be printed
 */
extern void ECP_output(ECP * P);
/**	@brief Formats and outputs an ECP point to an octet string
 *
	The octet string is created in the standard form 04|x|y, except for Montgomery curve in which case it is 06|x
	Here x (and y) are the x and y coordinates in big-endian base 256 form.
	@param S output octet string
	@param P ECP instance to be converted to an octet string
 */
extern void ECP_toOctet(octet *S,ECP *P);
/**	@brief Creates an ECP point from an octet string
 *
	The octet string is in the standard form 0x04|x|y, except for Montgomery curve in which case it is 0x06|x
	Here x (and y) are the x and y coordinates in left justified big-endian base 256 form.
	@param P ECP instance to be created from the octet string
	@param S input octet string
	return 1 if octet string corresponds to a point on the curve, else 0
 */
extern int ECP_fromOctet(ECP *P,octet *S);
/**	@brief Doubles an ECP instance P
 *
	@param P ECP instance, on exit =2*P
 */
extern void ECP_dbl(ECP *P);
/**	@brief Multiplies an ECP instance P by a small integer, side-channel resistant
 *
	@param P ECP instance, on exit =i*P
	@param i small integer multiplier
	@param b maximum number of bits in multiplier
 */
extern void ECP_pinmul(ECP *P,int i,int b);
/**	@brief Multiplies an ECP instance P by a BIG, side-channel resistant
 *
	Uses Montgomery ladder for Montgomery curves, otherwise fixed sized windows.
	@param P ECP instance, on exit =b*P
	@param b BIG number multiplier

 */
extern void ECP_mul(ECP *P,BIG b);
/**	@brief Calculates double multiplication P=e*P+f*Q, side-channel resistant
 *
	@param P ECP instance, on exit =e*P+f*Q
	@param Q ECP instance
	@param e BIG number multiplier
	@param f BIG number multiplier
 */
extern void ECP_mul2(ECP *P,ECP *Q,BIG e,BIG f);



/* ECP2 E(Fp2) prototypes */
/**	@brief Tests for ECP2 point equal to infinity
 *
	@param P ECP2 point to be tested
	@return 1 if infinity, else returns 0
 */
extern int ECP2_isinf(ECP2 *P);
/**	@brief Copy ECP2 point to another ECP2 point
 *
	@param P ECP2 instance, on exit = Q
	@param Q ECP2 instance to be copied
 */
extern void ECP2_copy(ECP2 *P,ECP2 *Q);
/**	@brief Set ECP2 to point-at-infinity
 *
	@param P ECP2 instance to be set to infinity
 */
extern void ECP2_inf(ECP2 *P);
/**	@brief Tests for equality of two ECP2s
 *
	@param P ECP2 instance to be compared
	@param Q ECP2 instance to be compared
	@return 1 if P=Q, else returns 0
 */
extern int ECP2_equals(ECP2 *P,ECP2 *Q);
/**	@brief Converts an ECP2 point from Projective (x,y,z) coordinates to affine (x,y) coordinates
 *
	@param P ECP2 instance to be converted to affine form
 */
extern void ECP2_affine(ECP2 *P);
/**	@brief Extract x and y coordinates of an ECP2 point P
 *
	If x=y, returns only x
	@param x FP2 on exit = x coordinate of point
	@param y FP2 on exit = y coordinate of point (unless x=y)
	@param P ECP2 instance (x,y)
	@return -1 if P is point-at-infinity, else 0
 */
extern int ECP2_get(FP2 *x,FP2 *y,ECP2 *P);
/**	@brief Formats and outputs an ECP2 point to the console, converted to affine coordinates
 *
	@param P ECP2 instance to be printed
 */
extern void ECP2_output(ECP2 *P);
/**	@brief Formats and outputs an ECP2 point to the console, in projective coordinates
 *
	@param P ECP2 instance to be printed
 */
extern void ECP2_outputxyz(ECP2 *P);
/**	@brief Formats and outputs an ECP2 point to an octet string
 *
	The octet string is created in the form x|y.
	Convert the real and imaginary parts of the x and y coordinates to big-endian base 256 form.
	@param S output octet string
	@param P ECP2 instance to be converted to an octet string
 */
extern void ECP2_toOctet(octet *S,ECP2 *P);
/**	@brief Creates an ECP2 point from an octet string
 *
	The octet string is in the form x|y
	The real and imaginary parts of the x and y coordinates are in big-endian base 256 form.
	@param P ECP2 instance to be created from the octet string
	@param S input octet string
	return 1 if octet string corresponds to a point on the curve, else 0
 */
extern int ECP2_fromOctet(ECP2 *P,octet *S);
/**	@brief Calculate Right Hand Side of curve equation y^2=f(x)
 *
	Function f(x)=x^3+Ax+B
	Used internally.
	@param r FP2 value of f(x)
	@param x FP2 instance
 */
extern void ECP2_rhs(FP2 *r,FP2 *x);
/**	@brief Set ECP2 to point(x,y) given x and y
 *
	Point P set to infinity if no such point on the curve.
	@param P ECP2 instance to be set (x,y)
	@param x FP2 x coordinate of point
	@param y FP2 y coordinate of point
	@return 1 if point exists, else 0
 */
extern int ECP2_set(ECP2 *P,FP2 *x,FP2 *y);
/**	@brief Set ECP to point(x,[y]) given x
 *
	Point P set to infinity if no such point on the curve. Otherwise y coordinate is calculated from x.
	@param P ECP instance to be set (x,[y])
	@param x BIG x coordinate of point
	@return 1 if point exists, else 0
 */
extern int ECP2_setx(ECP2 *P,FP2 *x);
/**	@brief Negation of an ECP2 point
 *
	@param P ECP2 instance, on exit = -P
 */
extern void ECP2_neg(ECP2 *P);
/**	@brief Doubles an ECP2 instance P
 *
	@param P ECP2 instance, on exit =2*P
 */
extern int ECP2_dbl(ECP2 *P);
/**	@brief Adds ECP2 instance Q to ECP2 instance P
 *
	@param P ECP2 instance, on exit =P+Q
	@param Q ECP2 instance to be added to P
 */
extern int ECP2_add(ECP2 *P,ECP2 *Q);
/**	@brief Subtracts ECP instance Q from ECP2 instance P
 *
	@param P ECP2 instance, on exit =P-Q
	@param Q ECP2 instance to be subtracted from P
 */
extern void ECP2_sub(ECP2 *P,ECP2 *Q);
/**	@brief Multiplies an ECP2 instance P by a BIG, side-channel resistant
 *
	Uses fixed sized windows.
	@param P ECP2 instance, on exit =b*P
	@param b BIG number multiplier

 */
extern void ECP2_mul(ECP2 *P,BIG b);
/**	@brief Multiplies an ECP2 instance P by the internal modulus p, using precalculated Frobenius constant f
 *
	Fast point multiplication using Frobenius
	@param P ECP2 instance, on exit = p*P
	@param f FP2 precalculated Frobenius constant

 */
extern void ECP2_frob(ECP2 *P,FP2 *f);
/**	@brief Calculates P=b[0]*Q[0]+b[1]*Q[1]+b[2]*Q[2]+b[3]*Q[3]
 *
	@param P ECP2 instance, on exit = b[0]*Q[0]+b[1]*Q[1]+b[2]*Q[2]+b[3]*Q[3]
	@param Q ECP2 array of 4 points
	@param b BIG array of 4 multipliers
 */
extern void ECP2_mul4(ECP2 *P,ECP2 *Q,BIG *b);



/* FP4 prototypes */
/**	@brief Tests for FP4 equal to zero
 *
	@param x FP4 number to be tested
	@return 1 if zero, else returns 0
 */
extern int FP4_iszilch(FP4 *x);
/**	@brief Tests for FP4 equal to unity
 *
	@param x FP4 number to be tested
	@return 1 if unity, else returns 0
 */
extern int FP4_isunity(FP4 *x);
/**	@brief Tests for equality of two FP4s
 *
	@param x FP4 instance to be compared
	@param y FP4 instance to be compared
	@return 1 if x=y, else returns 0
 */
extern int FP4_equals(FP4 *x,FP4 *y);
/**	@brief Tests for FP4 having only a real part and no imaginary part
 *
	@param x FP4 number to be tested
	@return 1 if real, else returns 0
 */
extern int FP4_isreal(FP4 *x);
/**	@brief Initialise FP4 from two FP2s
 *
	@param x FP4 instance to be initialised
	@param a FP2 to form real part of FP4
	@param b FP2 to form imaginary part of FP4
 */
extern void FP4_from_FP2s(FP4 *x,FP2 *a,FP2 *b);
/**	@brief Initialise FP4 from single FP2
 *
	Imaginary part is set to zero
	@param x FP4 instance to be initialised
	@param a FP2 to form real part of FP4
 */
extern void FP4_from_FP2(FP4 *x,FP2 *a);
/**	@brief Copy FP4 to another FP4
 *
	@param x FP4 instance, on exit = y
	@param y FP4 instance to be copied
 */
extern void FP4_copy(FP4 *x,FP4 *y);
/**	@brief Set FP4 to zero
 *
	@param x FP4 instance to be set to zero
 */
extern void FP4_zero(FP4 *x);
/**	@brief Set FP4 to unity
 *
	@param x FP4 instance to be set to one
 */
extern void FP4_one(FP4 *x);
/**	@brief Negation of FP4
 *
	@param x FP4 instance, on exit = -y
	@param y FP4 instance
 */
extern void FP4_neg(FP4 *x,FP4 *y);
/**	@brief Conjugation of FP4
 *
	If y=(a,b) on exit x=(a,-b)
	@param x FP4 instance, on exit = conj(y)
	@param y FP4 instance
 */
extern void FP4_conj(FP4 *x,FP4 *y);
/**	@brief Negative conjugation of FP4
 *
	If y=(a,b) on exit x=(-a,b)
	@param x FP4 instance, on exit = -conj(y)
	@param y FP4 instance
 */
extern void FP4_nconj(FP4 *x,FP4 *y);
/**	@brief addition of two FP4s
 *
	@param x FP4 instance, on exit = y+z
	@param y FP4 instance
	@param z FP4 instance
 */
extern void FP4_add(FP4 *x,FP4 *y,FP4 *z);
/**	@brief subtraction of two FP4s
 *
	@param x FP4 instance, on exit = y-z
	@param y FP4 instance
	@param z FP4 instance
 */
extern void FP4_sub(FP4 *x,FP4 *y,FP4 *z);
/**	@brief Multiplication of an FP4 by an FP2
 *
	@param x FP4 instance, on exit = y*a
	@param y FP4 instance
	@param a FP2 multiplier
 */
extern void FP4_pmul(FP4 *x,FP4 *y,FP2 *a);
/**	@brief Multiplication of an FP4 by a small integer
 *
	@param x FP4 instance, on exit = y*i
	@param y FP4 instance
	@param i an integer
 */
extern void FP4_imul(FP4 *x,FP4 *y,int i);
/**	@brief Squaring an FP4
 *
	@param x FP4 instance, on exit = y^2
	@param y FP4 instance
 */
extern void FP4_sqr(FP4 *x,FP4 *y);
/**	@brief Multiplication of two FP4s
 *
	@param x FP4 instance, on exit = y*z
	@param y FP4 instance
	@param z FP4 instance
 */
extern void FP4_mul(FP4 *x,FP4 *y,FP4 *z);
/**	@brief Inverting an FP4
 *
	@param x FP4 instance, on exit = 1/y
	@param y FP4 instance
 */
extern void FP4_inv(FP4 *x,FP4 *y);
/**	@brief Formats and outputs an FP4 to the console
 *
	@param x FP4 instance to be printed
 */
extern void FP4_output(FP4 *x);
/**	@brief Formats and outputs an FP4 to the console in raw form (for debugging)
 *
	@param x FP4 instance to be printed
 */
extern void FP4_rawoutput(FP4 *x);
/**	@brief multiplies an FP4 instance by irreducible polynomial sqrt(1+sqrt(-1))
 *
	@param x FP4 instance, on exit = sqrt(1+sqrt(-1)*x
 */
extern void FP4_times_i(FP4 *x);
/**	@brief Normalises the components of an FP4
 *
	@param x FP4 instance to be normalised
 */
extern void FP4_norm(FP4 *x);
/**	@brief Reduces all components of possibly unreduced FP4 mod Modulus
 *
	@param x FP4 instance, on exit reduced mod Modulus
 */
extern void FP4_reduce(FP4 *x);
/**	@brief Raises an FP4 to the power of a BIG
 *
	@param x FP4 instance, on exit = y^b
	@param y FP4 instance
	@param b BIG number
 */
extern void FP4_pow(FP4 *x,FP4 *y,BIG b);
/**	@brief Raises an FP4 to the power of the internal modulus p, using the Frobenius constant
 *
	@param x FP4 instance, on exit = x^p
	@param f FP2 precalculated Frobenius constant
 */
extern void FP4_frob(FP4 *x,FP2 *f);
/**	@brief Calculates the XTR addition function r=w*x-conj(x)*y+z
 *
	@param r FP4 instance, on exit = w*x-conj(x)*y+z
	@param w FP4 instance
	@param x FP4 instance
	@param y FP4 instance
	@param z FP4 instance
 */
extern void FP4_xtr_A(FP4 *r,FP4 *w,FP4 *x,FP4 *y,FP4 *z);
/**	@brief Calculates the XTR doubling function r=x^2-2*conj(x)
 *
	@param r FP4 instance, on exit = x^2-2*conj(x)
	@param x FP4 instance
 */
extern void FP4_xtr_D(FP4 *r,FP4 *x);
/**	@brief Calculates FP4 trace of an FP12 raised to the power of a BIG number
 *
	XTR single exponentiation
	@param r FP4 instance, on exit = trace(w^b)
	@param x FP4 instance, trace of an FP12 w
	@param b BIG number
 */
extern void FP4_xtr_pow(FP4 *r,FP4 *x,BIG b);
/**	@brief Calculates FP4 trace of c^a.d^b, where c and d are derived from FP4 traces of FP12s
 *
	XTR double exponentiation
	Assumes c=tr(x^m), d=tr(x^n), e=tr(x^(m-n)), f=tr(x^(m-2n))
	@param r FP4 instance, on exit = trace(c^a.d^b)
	@param c FP4 instance, trace of an FP12
	@param d FP4 instance, trace of an FP12
	@param e FP4 instance, trace of an FP12
	@param f FP4 instance, trace of an FP12
	@param a BIG number
	@param b BIG number
 */
extern void FP4_xtr_pow2(FP4 *r,FP4 *c,FP4 *d,FP4 *e,FP4 *f,BIG a,BIG b);



/* FP12 prototypes */
/**	@brief Tests for FP12 equal to zero
 *
	@param x FP12 number to be tested
	@return 1 if zero, else returns 0
 */
extern int FP12_iszilch(FP12 *x);
/**	@brief Tests for FP12 equal to unity
 *
	@param x FP12 number to be tested
	@return 1 if unity, else returns 0
 */
extern int FP12_isunity(FP12 *x);
/**	@brief Copy FP12 to another FP12
 *
	@param x FP12 instance, on exit = y
	@param y FP12 instance to be copied
 */
extern void FP12_copy(FP12 *x,FP12 *y);
/**	@brief Set FP12 to unity
 *
	@param x FP12 instance to be set to one
 */
extern void FP12_one(FP12 *x);
/**	@brief Tests for equality of two FP12s
 *
	@param x FP12 instance to be compared
	@param y FP12 instance to be compared
	@return 1 if x=y, else returns 0
 */
extern int FP12_equals(FP12 *x,FP12 *y);
/**	@brief Conjugation of FP12
 *
	If y=(a,b,c) (where a,b,c are its three FP4 components) on exit x=(conj(a),-conj(b),conj(c))
	@param x FP12 instance, on exit = conj(y)
	@param y FP12 instance
 */
extern void FP12_conj(FP12 *x,FP12 *y);
/**	@brief Initialise FP12 from single FP4
 *
	Sets first FP4 component of an FP12, other components set to zero
	@param x FP12 instance to be initialised
	@param a FP4 to form first part of FP4
 */
extern void FP12_from_FP4(FP12 *x,FP4 *a);
/**	@brief Initialise FP12 from three FP4s
 *
	@param x FP12 instance to be initialised
	@param a FP4 to form first part of FP12
	@param b FP4 to form second part of FP12
	@param c FP4 to form third part of FP12
 */
extern void FP12_from_FP4s(FP12 *x,FP4 *a,FP4* b,FP4 *c);
/**	@brief Fast Squaring of an FP12 in "unitary" form
 *
	@param x FP12 instance, on exit = y^2
	@param y FP4 instance, must be unitary
 */
extern void FP12_usqr(FP12 *x,FP12 *y);
/**	@brief Squaring an FP12
 *
	@param x FP12 instance, on exit = y^2
	@param y FP12 instance
 */
extern void FP12_sqr(FP12 *x,FP12 *y);
/**	@brief Fast multiplication of an FP12 by an FP12 that arises from an ATE pairing line function
 *
	Here the multiplier has a special form that can be exploited
	@param x FP12 instance, on exit = x*y
	@param y FP12 instance, of special form
 */
extern void FP12_smul(FP12 *x,FP12 *y);
/**	@brief Multiplication of two FP12s
 *
	@param x FP12 instance, on exit = x*y
	@param y FP12 instance, the multiplier
 */
extern void FP12_mul(FP12 *x,FP12 *y);
/**	@brief Inverting an FP12
 *
	@param x FP12 instance, on exit = 1/y
	@param y FP12 instance
 */
extern void FP12_inv(FP12 *x,FP12 *y);
/**	@brief Raises an FP12 to the power of a BIG
 *
	@param r FP12 instance, on exit = y^b
	@param x FP12 instance
	@param b BIG number
 */
extern void FP12_pow(FP12 *r,FP12 *x,BIG b);
/**	@brief Raises an FP12 instance x to a small integer power, side-channel resistant
 *
	@param x ECP instance, on exit = x^i
	@param i small integer exponent
	@param b maximum number of bits in exponent
 */
extern void FP12_pinpow(FP12 *x,int i,int b);
/**	@brief Calculate x[0]^b[0].x[1]^b[1].x[2]^b[2].x[3]^b[3], side-channel resistant
 *
	@param r ECP instance, on exit = x[0]^b[0].x[1]^b[1].x[2]^b[2].x[3]^b[3]
	@param x FP12 array with 4 FP12s
	@param b BIG array of 4 exponents
 */
extern void FP12_pow4(FP12 *r,FP12 *x,BIG *b);
/**	@brief Raises an FP12 to the power of the internal modulus p, using the Frobenius
 *
	@param x FP12 instance, on exit = x^p
	@param f FP2 precalculated Frobenius constant
 */
extern void FP12_frob(FP12 *x,FP2 *f);
/**	@brief Reduces all components of possibly unreduced FP12 mod Modulus
 *
	@param x FP12 instance, on exit reduced mod Modulus
 */
extern void FP12_reduce(FP12 *x);
/**	@brief Normalises the components of an FP12
 *
	@param x FP12 instance to be normalised
 */
extern void FP12_norm(FP12 *x);
/**	@brief Formats and outputs an FP12 to the console
 *
	@param x FP12 instance to be printed
 */
extern void FP12_output(FP12 *x);
/**	@brief Formats and outputs an FP12 instance to an octet string
 *
	Serializes the components of an FP12 to big-endian base 256 form.
	@param S output octet string
	@param x FP12 instance to be converted to an octet string
 */
extern void FP12_toOctet(octet *S,FP12 *x);
/**	@brief Creates an FP12 instance from an octet string
 *
	De-serializes the components of an FP12 to create an FP12 from big-endian base 256 components.
	@param x FP12 instance to be created from an octet string
	@param S input octet string

 */
extern void FP12_fromOctet(FP12 *x,octet *S);
/**	@brief Calculate the trace of an FP12
 *
	@param t FP4 trace of x, on exit = tr(x)
	@param x FP12 instance

 */
extern void FP12_trace(FP4 *t,FP12 *x);



/* Pairing function prototypes */
/**	@brief Calculate Miller loop for Optimal ATE pairing e(P,Q)
 *
	@param r FP12 result of the pairing calculation e(P,Q)
	@param P ECP2 instance, an element of G2
	@param Q ECP instance, an element of G1

 */
extern void PAIR_ate(FP12 *r,ECP2 *P,ECP *Q);
/**	@brief Calculate Miller loop for Optimal ATE double-pairing e(P,Q).e(R,S)
 *
	Faster than calculating two separate pairings
	@param r FP12 result of the pairing calculation e(P,Q).e(R,S), an element of GT
	@param P ECP2 instance, an element of G2
	@param Q ECP instance, an element of G1
	@param R ECP2 instance, an element of G2
	@param S ECP instance, an element of G1
 */
extern void PAIR_double_ate(FP12 *r,ECP2 *P,ECP *Q,ECP2 *R,ECP *S);
/**	@brief Final exponentiation of pairing, converts output of Miller loop to element in GT
 *
	Here p is the internal modulus, and r is the group order
	@param x FP12, on exit = x^((p^12-1)/r)
 */
extern void PAIR_fexp(FP12 *x);
/**	@brief Fast point multiplication of a member of the group G1 by a BIG number
 *
	May exploit endomorphism for speed.
	@param Q ECP member of G1.
	@param b BIG multiplier

 */
extern void PAIR_G1mul(ECP *Q,BIG b);
/**	@brief Fast point multiplication of a member of the group G2 by a BIG number
 *
	May exploit endomorphism for speed.
	@param P ECP2 member of G1.
	@param b BIG multiplier

 */
extern void PAIR_G2mul(ECP2 *P,BIG b);
/**	@brief Fast raising of a member of GT to a BIG power
 *
	May exploit endomorphism for speed.
	@param x FP12 member of GT.
	@param b BIG exponent

 */
extern void PAIR_GTpow(FP12 *x,BIG b);
/**	@brief Tests FP12 for membership of GT
 *
	@param x FP12 instance
	@return 1 if x is in GT, else return 0

 */
extern int PAIR_GTmember(FP12 *x);



/* Finite Field Prototypes */
/**	@brief Copy one FF element of given length to another
 *
	@param x FF instance to be copied to, on exit = y
	@param y FF instance to be copied from
	@param n size of FF in BIGs

 */
extern void FF_copy(BIG *x,BIG *y,int n);
/**	@brief Initialize an FF element of given length from a 32-bit integer m
 *
	@param x FF instance to be copied to, on exit = m
	@param m integer
	@param n size of FF in BIGs
 */
extern void FF_init(BIG *x,sign32 m,int n);
/**	@brief Set FF element of given size to zero
 *
	@param x FF instance to be set to zero
	@param n size of FF in BIGs
 */
extern void FF_zero(BIG *x,int n);
/**	@brief Tests for FF element equal to zero
 *
	@param x FF number to be tested
	@param n size of FF in BIGs
	@return 1 if zero, else returns 0
 */
extern int FF_iszilch(BIG *x,int n);
/**	@brief  return parity of an FF, that is the least significant bit
 *
	@param x FF number
	@return 0 or 1
 */
extern int FF_parity(BIG *x);
/**	@brief  return least significant m bits of an FF
 *
	@param x FF number
	@param m number of bits to return. Assumed to be less than BASEBITS.
	@return least significant n bits as an integer
 */
extern int FF_lastbits(BIG *x,int m);
/**	@brief Set FF element of given size to unity
 *
	@param x FF instance to be set to unity
	@param n size of FF in BIGs
 */
extern void FF_one(BIG *x,int n);
/**	@brief Compares two FF numbers. Inputs must be normalised externally
 *
	@param x first FF number to be compared
	@param y second FF number to be compared
	@param n size of FF in BIGs
	@return -1 is x<y, 0 if x=y, 1 if x>y
 */
extern int FF_comp(BIG *x,BIG *y,int n);
/**	@brief addition of two FFs
 *
	@param x FF instance, on exit = y+z
	@param y FF instance
	@param z FF instance
	@param n size of FF in BIGs
 */
extern void FF_add(BIG *x,BIG *y,BIG *z,int n);
/**	@brief subtraction of two FFs
 *
	@param x FF instance, on exit = y-z
	@param y FF instance
	@param z FF instance
	@param n size of FF in BIGs
 */
extern void FF_sub(BIG *x,BIG *y,BIG *z,int n);
/**	@brief increment an FF by an integer,and normalise
 *
	@param x FF instance, on exit = x+m
	@param m an integer to be added to x
	@param n size of FF in BIGs
 */
extern void FF_inc(BIG *x,int m,int n);
/**	@brief Decrement an FF by an integer,and normalise
 *
	@param x FF instance, on exit = x-m
	@param m an integer to be subtracted from x
	@param n size of FF in BIGs
 */
extern void FF_dec(BIG *x,int m,int n);
/**	@brief Normalises the components of an FF
 *
	@param x FF instance to be normalised
	@param n size of FF in BIGs
 */
extern void FF_norm(BIG *x,int n);
/**	@brief Shift left an FF by 1 bit
 *
	@param x FF instance to be shifted left
	@param n size of FF in BIGs
 */
extern void FF_shl(BIG *x,int n);
/**	@brief Shift right an FF by 1 bit
 *
	@param x FF instance to be shifted right
	@param n size of FF in BIGs
 */
extern void FF_shr(BIG *x,int n);
/**	@brief Formats and outputs an FF to the console
 *
	@param x FF instance to be printed
	@param n size of FF in BIGs
 */
extern void FF_output(BIG *x,int n);
/**	@brief Formats and outputs an FF to the console, in raw form
 *
 	@param x FF instance to be printed
 	@param n size of FF in BIGs
 */
extern void FF_rawoutput(BIG *x,int n);
/**	@brief Formats and outputs an FF instance to an octet string
 *
	Converts an FF to big-endian base 256 form.
	@param S output octet string
	@param x FF instance to be converted to an octet string
	@param n size of FF in BIGs
 */
extern void FF_toOctet(octet *S,BIG *x,int n);
/**	@brief Populates an FF instance from an octet string
 *
	Creates FF from big-endian base 256 form.
	@param x FF instance to be created from an octet string
	@param S input octet string
	@param n size of FF in BIGs
 */
extern void FF_fromOctet(BIG *x,octet *S,int n);
/**	@brief Multiplication of two FFs
 *
	Uses Karatsuba method internally
	@param x FF instance, on exit = y*z
	@param y FF instance
	@param z FF instance
	@param n size of FF in BIGs
 */
extern void FF_mul(BIG *x,BIG *y,BIG *z,int n);
/**	@brief Reduce FF mod a modulus
 *
	This is slow
	@param x FF instance to be reduced mod m - on exit = x mod m
	@param m FF modulus
	@param n size of FF in BIGs
 */
extern void FF_mod(BIG *x,BIG *m,int n);
/**	@brief Square an FF
 *
	Uses Karatsuba method internally
	@param x FF instance, on exit = y^2
	@param y FF instance to be squared
	@param n size of FF in BIGs
 */
extern void FF_sqr(BIG *x,BIG *y,int n);
/**	@brief Reduces a double-length FF with respect to a given modulus
 *
	This is slow
	@param x FF instance, on exit = y mod z
	@param y FF instance, of double length 2*n
	@param z FF modulus
	@param n size of FF in BIGs
 */
extern void FF_dmod(BIG *x,BIG *y,BIG *z,int n);
/**	@brief Invert an FF mod a prime modulus
 *
	@param x FF instance, on exit = 1/y mod z
	@param y FF instance
	@param z FF prime modulus
	@param n size of FF in BIGs
 */
extern void FF_invmodp(BIG *x,BIG *y,BIG *z,int n);
/**	@brief Create an FF from a random number generator
 *
	@param x FF instance, on exit x is a random number of length n BIGs with most significant bit a 1
	@param R an instance of a Cryptographically Secure Random Number Generator
	@param n size of FF in BIGs
 */
extern void FF_random(BIG *x,csprng *R,int n);
/**	@brief Create a random FF less than a given modulus from a random number generator
 *
	@param x FF instance, on exit x is a random number < y
	@param y FF instance, the modulus
	@param R an instance of a Cryptographically Secure Random Number Generator
	@param n size of FF in BIGs
 */
extern void FF_randomnum(BIG *x,BIG *y,csprng *R,int n);
/**	@brief Calculate r=x^e mod m, side channel resistant
 *
	@param r FF instance, on exit = x^e mod p
	@param x FF instance
	@param e FF exponent
	@param m FF modulus
	@param n size of FF in BIGs
 */
extern void FF_skpow(BIG *r,BIG *x,BIG * e,BIG *m,int n);
/**	@brief Calculate r=x^e mod m, side channel resistant
 *
	For short BIG exponent
	@param r FF instance, on exit = x^e mod p
	@param x FF instance
	@param e BIG exponent
	@param m FF modulus
	@param n size of FF in BIGs
 */
extern void FF_skspow(BIG *r,BIG *x,BIG e,BIG *m,int n);
/**	@brief Calculate r=x^e mod m
 *
	For very short integer exponent
	@param r FF instance, on exit = x^e mod p
	@param x FF instance
	@param e integer exponent
	@param m FF modulus
	@param n size of FF in BIGs
 */
extern void FF_power(BIG *r,BIG *x,int e,BIG *m,int n);
/**	@brief Calculate r=x^e mod m
 *
	@param r FF instance, on exit = x^e mod p
	@param x FF instance
	@param e FF exponent
	@param m FF modulus
	@param n size of FF in BIGs
 */
extern void FF_pow(BIG *r,BIG *x,BIG *e,BIG *m,int n);
/**	@brief Test if an FF has factor in common with integer s
 *
	@param x FF instance to be tested
	@param s the supplied integer
	@param n size of FF in BIGs
	@return 1 if gcd(x,s)!=1, else return 0
 */
extern int FF_cfactor(BIG *x,sign32 s,int n);
/**	@brief Test if an FF is prime
 *
	Uses Miller-Rabin Method
	@param x FF instance to be tested
	@param R an instance of a Cryptographically Secure Random Number Generator
	@param n size of FF in BIGs
	@return 1 if x is (almost certainly) prime, else return 0
 */
extern int FF_prime(BIG *x,csprng *R,int n);
/**	@brief Calculate r=x^e.y^f mod m
 *
	@param r FF instance, on exit = x^e.y^f mod p
	@param x FF instance
	@param e BIG exponent
	@param y FF instance
	@param f BIG exponent
	@param m FF modulus
	@param n size of FF in BIGs
 */
extern void FF_pow2(BIG *r,BIG *x,BIG e,BIG *y,BIG f,BIG *m,int n);


/* Octet string handlers */
/**	@brief Formats and outputs an octet to the console in hex
 *
	@param O Octet to be output
 */
extern void OCT_output(octet *O);
/**	@brief Formats and outputs an octet to the console as a character string
 *
	@param O Octet to be output
 */
extern void OCT_output_string(octet *O);
/**	@brief Wipe clean an octet
 *
	@param O Octet to be cleaned
 */
extern void OCT_clear(octet *O);
/**	@brief Compare two octets
 *
	@param O first Octet to be compared
	@param P second Octet to be compared
	@return 1 if equal, else 0
 */
extern int  OCT_comp(octet *O,octet *P);
/**	@brief Compare first n bytes of two octets
 *
	@param O first Octet to be compared
	@param P second Octet to be compared
	@param n number of bytes to compare
	@return 1 if equal, else 0
 */
extern int  OCT_ncomp(octet *O,octet *P,int n);
/**	@brief Join from a C string to end of an octet
 *
	Truncates if there is no room
	@param O Octet to be written to
	@param s zero terminated string to be joined to octet
 */
extern void OCT_jstring(octet *O,char *s);
/**	@brief Join bytes to end of an octet
 *
	Truncates if there is no room
	@param O Octet to be written to
	@param s bytes to be joined to end of octet
	@param n number of bytes to join
 */
extern void OCT_jbytes(octet *O,char *s,int n);
/**	@brief Join single byte to end of an octet, repeated n times
 *
	Truncates if there is no room
	@param O Octet to be written to
	@param b byte to be joined to end of octet
	@param n number of times b is to be joined
 */
extern void OCT_jbyte(octet *O,int b,int n);
/**	@brief Join one octet to the end of another
 *
	Truncates if there is no room
	@param O Octet to be written to
	@param P Octet to be joined to the end of O
 */
extern void OCT_joctet(octet *O,octet *P);
/**	@brief XOR common bytes of a pair of Octets
 *
	@param O Octet - on exit = O xor P
	@param P Octet to be xored into O
 */
extern void OCT_xor(octet *O,octet *P);
/**	@brief reset Octet to zero length
 *
	@param O Octet to be emptied
 */
extern void OCT_empty(octet *O);
/**	@brief Pad out an Octet to the given length
 *
	Padding is done by inserting leading zeros, so abcd becomes 00abcd
	@param O Octet to be padded
	@param n new length of Octet
 */
extern int OCT_pad(octet *O,int n);
/**	@brief Convert an Octet to printable base64 number
 *
	@param b zero terminated byte array to take base64 conversion
	@param O Octet to be converted
 */
extern void OCT_tobase64(char *b,octet *O);
/**	@brief Populate an Octet from base64 number
 *
 	@param O Octet to be populated
	@param b zero terminated base64 string

 */
extern void OCT_frombase64(octet *O,char *b);
/**	@brief Copy one Octet into another
 *
 	@param O Octet to be copied to
	@param P Octet to be copied from

 */
extern void OCT_copy(octet *O,octet *P);
/**	@brief XOR every byte of an octet with input m
 *
 	@param O Octet
	@param m byte to be XORed with every byte of O

 */
extern void OCT_xorbyte(octet *O,int m);
/**	@brief Chops Octet into two, leaving first n bytes in O, moving the rest to P
 *
 	@param O Octet to be chopped
	@param P new Octet to be created
	@param n number of bytes to chop off O

 */
extern void OCT_chop(octet *O,octet *P,int n);
/**	@brief Join n bytes of integer m to end of Octet O (big endian)
 *
	Typically n is 4 for a 32-bit integer
 	@param O Octet to be appended to
	@param m integer to be appended to O
	@param n number of bytes in m

 */
extern void OCT_jint(octet *O,int m,int n);
/**	@brief Create an Octet from bytes taken from a random number generator
 *
	Truncates if there is no room
 	@param O Octet to be populated
	@param R an instance of a Cryptographically Secure Random Number Generator
	@param n number of bytes to extracted from R

 */
extern void OCT_rand(octet *O,csprng *R,int n);
/**	@brief Shifts Octet left by n bytes
 *
	Leftmost bytes disappear
 	@param O Octet to be shifted
	@param n number of bytes to shift

 */
extern void OCT_shl(octet *O,int n);
/**	@brief Convert a hex number to an Octet
 *
	@param dst Octet
	@param src Hex string to be converted
 */
extern void OCT_fromHex(octet *dst,char *src);
/**	@brief Convert an Octet to printable hex number
 *
	@param dst hex value
	@param src Octet to be converted
 */
extern void OCT_toHex(octet *src,char *dst);
/**	@brief Convert an Octet to string
 *
	@param dst string value
	@param src Octet to be converted
 */
extern void OCT_toStr(octet *src,char *dst);



/* Hash function */
/**	@brief Initialise an instance of SHA256
 *
	@param H an instance SHA256
 */
extern void HASH256_init(hash256 *H);
/**	@brief Add a byte to the hash
 *
	@param H an instance SHA256
	@param b byte to be included in hash
 */
extern void HASH256_process(hash256 *H,int b);
/**	@brief Generate 32-byte hash
 *
	@param H an instance SHA256
	@param h is the output 32-byte hash
 */
extern void HASH256_hash(hash256 *H,char *h);


/**	@brief Initialise an instance of SHA384
 *
	@param H an instance SHA384
 */
extern void HASH384_init(hash384 *H);
/**	@brief Add a byte to the hash
 *
	@param H an instance SHA384
	@param b byte to be included in hash
 */
extern void HASH384_process(hash384 *H,int b);
/**	@brief Generate 48-byte hash
 *
	@param H an instance SHA384
	@param h is the output 48-byte hash
 */
extern void HASH384_hash(hash384 *H,char *h);


/**	@brief Initialise an instance of SHA512
 *
	@param H an instance SHA512
 */
extern void HASH512_init(hash512 *H);
/**	@brief Add a byte to the hash
 *
	@param H an instance SHA512
	@param b byte to be included in hash
 */
extern void HASH512_process(hash512 *H,int b);
/**	@brief Generate 64-byte hash
 *
	@param H an instance SHA512
	@param h is the output 64-byte hash
 */
extern void HASH512_hash(hash512 *H,char *h);


/* AES functions */
/**	@brief Reset AES mode or IV
 *
	@param A an instance of the AMCL_AES
	@param m is the new active mode of operation (ECB, CBC, OFB, CFB etc)
	@param iv the new Initialisation Vector
 */
extern void AES_reset(amcl_aes *A,int m,char *iv);
/**	@brief Extract chaining vector from AMCL_AES instance
 *
	@param A an instance of the AMCL_AES
	@param f the extracted chaining vector
 */
extern void AES_getreg(amcl_aes *A,char * f);
/**	@brief Initialise an instance of AMCL_AES and its mode of operation
 *
	@param A an instance AMCL_AES
	@param m is the active mode of operation (ECB, CBC, OFB, CFB etc)
	@param n is the key length in bytes, 16, 24 or 32
	@param k the AES key as an array of 16 bytes
	@param iv the Initialisation Vector
	@return 0 for invalid n
 */
extern int AES_init(amcl_aes *A,int m,int n,char *k,char *iv);
/**	@brief Encrypt a single 16 byte block in ECB mode
 *
	@param A an instance of the AMCL_AES
	@param b is an array of 16 plaintext bytes, on exit becomes ciphertext
 */
extern void AES_ecb_encrypt(amcl_aes *A,uchar * b);
/**	@brief Decrypt a single 16 byte block in ECB mode
 *
	@param A an instance of the AMCL_AES
	@param b is an array of 16 cipherext bytes, on exit becomes plaintext
 */
extern void AES_ecb_decrypt(amcl_aes *A,uchar * b);
/**	@brief Encrypt a single 16 byte block in active mode
 *
	@param A an instance of the AMCL_AES
	@param b is an array of 16 plaintext bytes, on exit becomes ciphertext
	@return 0, or overflow bytes from CFB mode
 */
extern unsign32 AES_encrypt(amcl_aes *A,char *b );
/**	@brief Decrypt a single 16 byte block in active mode
 *
	@param A an instance of the AMCL_AES
	@param b is an array of 16 ciphertext bytes, on exit becomes plaintext
	@return 0, or overflow bytes from CFB mode
 */
extern unsign32 AES_decrypt(amcl_aes *A,char *b);
/**	@brief Clean up after application of AES
 *
	@param A an instance of the AMCL_AES
 */
extern void AES_end(amcl_aes *A);


/* AES-GCM functions */
/**	@brief Initialise an instance of AES-GCM mode
 *
	@param G an instance AES-GCM
	@param nk is the key length in bytes, 16, 24 or 32
	@param k the AES key as an array of 16 bytes
	@param n the number of bytes in the Initialisation Vector (IV)
	@param iv the IV
 */
extern void GCM_init(gcm *G,int nk,char *k,int n,char *iv);
/**	@brief Add header (material to be authenticated but not encrypted)
 *
	Note that this function can be called any number of times with n a multiple of 16, and then one last time with any value for n
	@param G an instance AES-GCM
	@param b is the header material to be added
	@param n the number of bytes in the header
 */
extern int GCM_add_header(gcm *G,char *b,int n);
/**	@brief Add plaintext and extract ciphertext
 *
	Note that this function can be called any number of times with n a multiple of 16, and then one last time with any value for n
	@param G an instance AES-GCM
	@param c is the ciphertext generated
	@param p is the plaintext material to be added
	@param n the number of bytes in the plaintext
 */
extern int GCM_add_plain(gcm *G,char *c,char *p,int n);
/**	@brief Add ciphertext and extract plaintext
 *
	Note that this function can be called any number of times with n a multiple of 16, and then one last time with any value for n
	@param G an instance AES-GCM
	@param p is the plaintext generated
	@param c is the ciphertext material to be added
	@param n the number of bytes in the ciphertext
 */
extern int GCM_add_cipher(gcm *G,char *p,char *c,int n);
/**	@brief Finish off and extract authentication tag (HMAC)
 *
	@param G is an active instance AES-GCM
	@param t is the output 16 byte authentication tag
 */
extern void GCM_finish(gcm *G,char *t);



/* random numbers */
/**	@brief Seed a random number generator from an array of bytes
 *
	The provided seed should be truly random
	@param R an instance of a Cryptographically Secure Random Number Generator
	@param n the number of seed bytes provided
	@param b an array of seed bytes

 */
extern void RAND_seed(csprng *R,int n,char *b);
/**	@brief Delete all internal state of a random number generator
 *
	@param R an instance of a Cryptographically Secure Random Number Generator
 */
extern void RAND_clean(csprng *R);
/**	@brief Return a random byte from a random number generator
 *
	@param R an instance of a Cryptographically Secure Random Number Generator
	@return a random byte
 */
extern int RAND_byte(csprng *R);

/**
 * @brief Convert to DBIG number from byte array of given length
 *
 * Convert to DBIG number from byte array of given length.
 *
 * @param x DBIG number
 * @param a byte array
 * @param s byte array length
 */
extern void BIG_dfromBytesLen(DBIG x,char *a,int s);

#endif
