/*******************************************************************************
* Copyright 2002-2018 Intel Corporation
* All Rights Reserved.
*
* If this  software was obtained  under the  Intel Simplified  Software License,
* the following terms apply:
*
* The source code,  information  and material  ("Material") contained  herein is
* owned by Intel Corporation or its  suppliers or licensors,  and  title to such
* Material remains with Intel  Corporation or its  suppliers or  licensors.  The
* Material  contains  proprietary  information  of  Intel or  its suppliers  and
* licensors.  The Material is protected by  worldwide copyright  laws and treaty
* provisions.  No part  of  the  Material   may  be  used,  copied,  reproduced,
* modified, published,  uploaded, posted, transmitted,  distributed or disclosed
* in any way without Intel's prior express written permission.  No license under
* any patent,  copyright or other  intellectual property rights  in the Material
* is granted to  or  conferred  upon  you,  either   expressly,  by implication,
* inducement,  estoppel  or  otherwise.  Any  license   under such  intellectual
* property rights must be express and approved by Intel in writing.
*
* Unless otherwise agreed by Intel in writing,  you may not remove or alter this
* notice or  any  other  notice   embedded  in  Materials  by  Intel  or Intel's
* suppliers or licensors in any way.
*
*
* If this  software  was obtained  under the  Apache License,  Version  2.0 (the
* "License"), the following terms apply:
*
* 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.
*******************************************************************************/

/* 
//               Intel(R) Integrated Performance Primitives
//                   Cryptographic Primitives (ippcp)
// 
// 
*/

#if !defined(_CP_MONTGOMETRY_H)
#define _CP_MONTGOMETRY_H

#include "pcpbn.h"
#include "gsmodstuff.h"

//tbcd: temporary excluded: #include <assert.h>

#define MONT_DEFAULT_POOL_LENGTH (6)

/*
// Montgomery spec structure
*/
struct _cpMontgomery
{
   IppCtxId       idCtx;      /* Montgomery spec identifier             */
   cpSize         maxLen;     /* Maximum length of modulus being stored */
   gsModEngine*   pEngine;    /* Modular arith engine structure         */
};

/* accessory macros */
#define MNT_ID(eng)       ((eng)->idCtx)
#define MNT_ROOM(eng)     ((eng)->maxLen)
#define MNT_ENGINE(eng)   ((eng)->pEngine)

#define MNT_VALID_ID(eng) (MNT_ID((eng))==idCtxMontgomery)

/* default methos */
#define EXPONENT_METHOD    (ippBinaryMethod)

/* alignment */
#define MONT_ALIGNMENT  ((int)(sizeof(void*)))


/*
// Pacp/unpack Montgomery context
*/
#define cpPackMontCtx OWNAPI(cpPackMontCtx)
void    cpPackMontCtx(const IppsMontState* pCtx, Ipp8u* pBuffer);
#define cpUnpackMontCtx OWNAPI(cpUnpackMontCtx)
void    cpUnpackMontCtx(const Ipp8u* pBuffer, IppsMontState* pCtx);


/*
// Montgomery reduction, multiplication and squaring
*/
__INLINE void cpMontRed_BNU(BNU_CHUNK_T* pR,
                            BNU_CHUNK_T* pProduct,
                            gsModEngine* pModEngine)
{
   MOD_METHOD( pModEngine )->red(pR, pProduct, pModEngine);
}

__INLINE void cpMontMul_BNU(BNU_CHUNK_T* pR,
                     const BNU_CHUNK_T* pA,
                     const BNU_CHUNK_T* pB,
                           gsModEngine* pModEngine)
{
   MOD_METHOD( pModEngine )->mul(pR, pA, pB, pModEngine);
}

__INLINE cpSize cpMontMul_BNU_EX(BNU_CHUNK_T* pR,
                           const BNU_CHUNK_T* pA, cpSize nsA,
                           const BNU_CHUNK_T* pB, cpSize nsB,
                                 gsModEngine* pModEngine)
{
   const int usedPoolLen = 1;
   cpSize nsM = MOD_LEN( pModEngine );
   BNU_CHUNK_T* pDataR  = pR;
   BNU_CHUNK_T* pDataA  = gsModPoolAlloc(pModEngine, usedPoolLen);
   //tbcd: temporary excluded: assert(NULL!=pDataA);

   ZEXPAND_COPY_BNU(pDataA, nsM, pA, nsA);
   ZEXPAND_COPY_BNU(pDataR, nsM, pB, nsB);

   MOD_METHOD( pModEngine )->mul(pDataR, pDataA, pDataR, pModEngine);

   gsModPoolFree(pModEngine, usedPoolLen);
   return nsM;
}

__INLINE void cpMontSqr_BNU(BNU_CHUNK_T* pR,
                      const BNU_CHUNK_T* pA,
                            gsModEngine* pModEngine)
{
   MOD_METHOD( pModEngine )->sqr(pR, pA, pModEngine);
}

__INLINE void cpMontSqr_BNU_EX(BNU_CHUNK_T* pR,
                         const BNU_CHUNK_T* pA, cpSize nsA,
                               gsModEngine* pModEngine)
{
   cpSize nsM = MOD_LEN( pModEngine );
   ZEXPAND_COPY_BNU(pR, nsM, pA, nsA);

   MOD_METHOD( pModEngine )->sqr(pR, pR, pModEngine);
}

/*
// Montgomery encoding/decoding
*/
__INLINE cpSize cpMontEnc_BNU(BNU_CHUNK_T* pR,
                        const BNU_CHUNK_T* pXreg,
                              gsModEngine* pModEngine)
{
   cpSize nsM = MOD_LEN(pModEngine);

   MOD_METHOD( pModEngine )->encode(pR, pXreg, pModEngine);

   FIX_BNU(pR, nsM);
   return nsM;
}

__INLINE cpSize cpMontEnc_BNU_EX(BNU_CHUNK_T* pR,
                           const BNU_CHUNK_T* pXreg, cpSize nsX,
                                 gsModEngine* pModEngine)
{
   cpSize nsM = MOD_LEN(pModEngine);

   ZEXPAND_COPY_BNU(pR, nsM, pXreg, nsX);

   MOD_METHOD( pModEngine )->encode(pR, pR, pModEngine);

   FIX_BNU(pR, nsM);

   return nsM;
}

__INLINE cpSize cpMontDec_BNU(BNU_CHUNK_T* pR,
                        const BNU_CHUNK_T* pXmont, cpSize nsX,
                              gsModEngine* pModEngine)
{
   cpSize nsM = MOD_LEN( pModEngine );

   ZEXPAND_COPY_BNU(pR, nsM, pXmont, nsX);

   MOD_METHOD( pModEngine )->decode(pR, pR, pModEngine);

   FIX_BNU(pR, nsM);
   return nsM;
}

__INLINE void cpMontMul_BN(IppsBigNumState* pRbn,
                     const IppsBigNumState* pXbn,
                     const IppsBigNumState* pYbn,
                           gsModEngine*     pModEngine)
{
   cpSize nsM = cpMontMul_BNU_EX(BN_NUMBER(pRbn),
                                 BN_NUMBER(pXbn), BN_SIZE(pXbn),
                                 BN_NUMBER(pYbn), BN_SIZE(pYbn),
                                 pModEngine);

   FIX_BNU(BN_NUMBER(pRbn), nsM);
   BN_SIZE(pRbn) = nsM;
   BN_SIGN(pRbn) = ippBigNumPOS;
}

__INLINE void cpMontEnc_BN(IppsBigNumState* pRbn,
                     const IppsBigNumState* pXbn,
                           gsModEngine*     pModEngine)
{
   cpSize nsM = cpMontEnc_BNU_EX(BN_NUMBER(pRbn),
                                 BN_NUMBER(pXbn), BN_SIZE(pXbn),
                                 pModEngine);

   BN_SIZE(pRbn) = nsM;
   BN_SIGN(pRbn) = ippBigNumPOS;
}

__INLINE void cpMontDec_BN(IppsBigNumState* pRbn,
                     const IppsBigNumState* pXbn,
                           gsModEngine*     pModEngine)
{
   cpSize nsM = MOD_LEN(pModEngine);
   cpMontDec_BNU(BN_NUMBER(pRbn), BN_NUMBER(pXbn), BN_SIZE(pXbn), pModEngine);

   BN_SIZE(pRbn) = nsM;
   BN_SIGN(pRbn) = ippBigNumPOS;
}

/*
// Montgomery exponentiation (binary) "fast" and "safe" versions
*/
#define cpMontExpBin_BNU_sscm OWNAPI(cpMontExpBin_BNU_sscm)
cpSize  cpMontExpBin_BNU_sscm(BNU_CHUNK_T* pY,
                       const BNU_CHUNK_T* pX, cpSize nsX,
                       const BNU_CHUNK_T* pE, cpSize nsE,
                             gsModEngine* pModEngine);

#define cpMontExpBin_BNU OWNAPI(cpMontExpBin_BNU)
cpSize  cpMontExpBin_BNU(BNU_CHUNK_T* pY,
                   const BNU_CHUNK_T* pX, cpSize nsX,
                   const BNU_CHUNK_T* pE, cpSize nsE,
                         gsModEngine* pModEngine);

__INLINE void cpMontExpBin_BN_sscm(IppsBigNumState* pYbn,
                             const IppsBigNumState* pXbn,
                             const IppsBigNumState* pEbn,
                                   gsModEngine*     pMont)
{
   BNU_CHUNK_T* pX = BN_NUMBER(pXbn);
   cpSize nsX = BN_SIZE(pXbn);
   BNU_CHUNK_T* pE = BN_NUMBER(pEbn);
   cpSize nsE = BN_SIZE(pEbn);
   BNU_CHUNK_T* pY = BN_NUMBER(pYbn);
   cpSize nsY = cpMontExpBin_BNU_sscm(pY, pX,nsX, pE,nsE, pMont);
   FIX_BNU(pY, nsY);
   BN_SIZE(pYbn) = nsY;
   BN_SIGN(pYbn) = ippBigNumPOS;
}

__INLINE void cpMontExpBin_BN(IppsBigNumState* pYbn,
                        const IppsBigNumState* pXbn,
                        const IppsBigNumState* pEbn,
                              gsModEngine* pModEngine)
{
   BNU_CHUNK_T* pX = BN_NUMBER(pXbn);
   cpSize nsX = BN_SIZE(pXbn);
   BNU_CHUNK_T* pE = BN_NUMBER(pEbn);
   cpSize nsE = BN_SIZE(pEbn);
   BNU_CHUNK_T* pY = BN_NUMBER(pYbn);
   cpSize nsY = cpMontExpBin_BNU(pY, pX,nsX, pE,nsE, pModEngine);
   FIX_BNU(pY, nsY);
   BN_SIZE(pYbn) = nsY;
   BN_SIGN(pYbn) = ippBigNumPOS;
}


/*
// Montgomery exponentiation (fixed window)
*/
#define cpMontExp_WinSize OWNAPI(cpMontExp_WinSize)
cpSize  cpMontExp_WinSize(int bitsize);

#if defined(_USE_WINDOW_EXP_)
#define cpMontExpWin_BN_sscm OWNAPI(cpMontExpWin_BN_sscm)
void    cpMontExpWin_BN_sscm(IppsBigNumState* pY,
                      const IppsBigNumState* pX, const IppsBigNumState* pE,
                            gsModEngine*     pMont,
                            BNU_CHUNK_T* pPrecompResource);

#define cpMontExpWin_BN OWNAPI(cpMontExpWin_BN)
void    cpMontExpWin_BN(IppsBigNumState* pY,
                  const IppsBigNumState* pX, const IppsBigNumState* pE,
                        gsModEngine*     pMont,
                        BNU_CHUNK_T* pPrecompResource);
#endif

/*
// Montgomery multi-exponentiation
*/
/* precompute table for multi-exponentiation */
#define cpMontMultiExpInitArray OWNAPI(cpMontMultiExpInitArray)
void    cpMontMultiExpInitArray(BNU_CHUNK_T* pPrecomTbl,
                         const BNU_CHUNK_T** ppX, cpSize xItemBitSize, cpSize numItems,
                               gsModEngine* pMont);

/* multi-exponentiation */
#define cpFastMontMultiExp OWNAPI(cpFastMontMultiExp)
void    cpFastMontMultiExp(BNU_CHUNK_T* pY,
                     const BNU_CHUNK_T* pPrecomTbl,
                     const Ipp8u** ppE, cpSize eItemBitSize, cpSize numItems,
                           gsModEngine* pMont);
/*
// Montgomery inversion
*/
#define      cpMontInv_BNU OWNAPI(cpMontInv_BNU)
BNU_CHUNK_T* cpMontInv_BNU(BNU_CHUNK_T* pR, const BNU_CHUNK_T* pA, IppsMontState* pMont);
#define      cpRegInv_BNU OWNAPI(cpRegInv_BNU)
BNU_CHUNK_T* cpRegInv_BNU(BNU_CHUNK_T* pR, const BNU_CHUNK_T* pA, IppsMontState* pMont);


/*
// Montgomery internal GetSize/Init functions
*/
#define   cpMontGetSize OWNAPI(cpMontGetSize)
IppStatus cpMontGetSize(cpSize maxLen32, int poolLength, cpSize* pCtxSize);

#define   cpMontInit OWNAPI(cpMontInit)
IppStatus cpMontInit(int maxLen32, int poolLength, IppsMontState* pMont);

#define   cpMontSet OWNAPI(cpMontSet)
IppStatus cpMontSet(const Ipp32u* pModulus, cpSize len32, IppsMontState* pMont);

#endif /* _CP_MONTGOMETRY_H */