/********************************************************************************/
/*										*/
/*	Functions that are used for the two-phase, ECC, key-exchange protocols	*/
/*			     Written by Ken Goldman				*/
/*		       IBM Thomas J. Watson Research Center			*/
/*										*/
/*  Licenses and Notices							*/
/*										*/
/*  1. Copyright Licenses:							*/
/*										*/
/*  - Trusted Computing Group (TCG) grants to the user of the source code in	*/
/*    this specification (the "Source Code") a worldwide, irrevocable, 		*/
/*    nonexclusive, royalty free, copyright license to reproduce, create 	*/
/*    derivative works, distribute, display and perform the Source Code and	*/
/*    derivative works thereof, and to grant others the rights granted herein.	*/
/*										*/
/*  - The TCG grants to the user of the other parts of the specification 	*/
/*    (other than the Source Code) the rights to reproduce, distribute, 	*/
/*    display, and perform the specification solely for the purpose of 		*/
/*    developing products based on such documents.				*/
/*										*/
/*  2. Source Code Distribution Conditions:					*/
/*										*/
/*  - Redistributions of Source Code must retain the above copyright licenses, 	*/
/*    this list of conditions and the following disclaimers.			*/
/*										*/
/*  - Redistributions in binary form must reproduce the above copyright 	*/
/*    licenses, this list of conditions	and the following disclaimers in the 	*/
/*    documentation and/or other materials provided with the distribution.	*/
/*										*/
/*  3. Disclaimers:								*/
/*										*/
/*  - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF	*/
/*  LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH	*/
/*  RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES)	*/
/*  THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE.		*/
/*  Contact TCG Administration (admin@trustedcomputinggroup.org) for 		*/
/*  information on specification licensing rights available through TCG 	*/
/*  membership agreements.							*/
/*										*/
/*  - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED 	*/
/*    WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR 	*/
/*    FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR 		*/
/*    NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY 		*/
/*    OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.		*/
/*										*/
/*  - Without limitation, TCG and its members and licensors disclaim all 	*/
/*    liability, including liability for infringement of any proprietary 	*/
/*    rights, relating to use of information in this specification and to the	*/
/*    implementation of this specification, and TCG disclaims all liability for	*/
/*    cost of procurement of substitute goods or services, lost profits, loss 	*/
/*    of use, loss of data or any incidental, consequential, direct, indirect, 	*/
/*    or special damages, whether under contract, tort, warranty or otherwise, 	*/
/*    arising in any way out of use or reliance upon this specification or any 	*/
/*    information herein.							*/
/*										*/
/*  (c) Copyright IBM Corp. and others, 2016 - 2023				*/
/*										*/
/********************************************************************************/

//** Introduction
// This file contains the functions that are used for the two-phase, ECC,
// key-exchange protocols

#include "Tpm.h"
#include "TpmMath_Util_fp.h"
#include "TpmEcc_Util_fp.h"

#if CC_ZGen_2Phase == YES

//** Functions

#  if ALG_ECMQV

//*** avf1()
// This function does the associated value computation required by MQV key
// exchange.
// Process:
// 1. Convert 'xQ' to an integer 'xqi' using the convention specified in Appendix C.3.
// 2. Calculate
//        xqm = xqi mod 2^ceil(f/2) (where f = ceil(log2(n)).
// 3. Calculate the associate value function
//        avf(Q) = xqm + 2ceil(f / 2)
// Always returns TRUE(1).
static BOOL avf1(Crypt_Int* bnX,  // IN/OUT: the reduced value
		 Crypt_Int* bnN   // IN: the order of the curve
		 )
{
    // compute f = 2^(ceil(ceil(log2(n)) / 2))
    int f = (ExtMath_SizeInBits(bnN) + 1) / 2;
    // x' = 2^f + (x mod 2^f)
    ExtMath_MaskBits(bnX, f);  // This is mod 2*2^f but it doesn't matter because
    // the next operation will SET the extra bit anyway
    if(!ExtMath_SetBit(bnX, f))
	{
	    FAIL(FATAL_ERROR_CRYPTO);
	}
    return TRUE;
}

//*** C_2_2_MQV()
// This function performs the key exchange defined in SP800-56A
// 6.1.1.4 Full MQV, C(2, 2, ECC MQV).
//
// CAUTION: Implementation of this function may require use of essential claims in
// patents not owned by TCG members.
//
// Points 'QsB' and 'QeB' are required to be on the curve of 'inQsA'. The function
// will fail, possibly catastrophically, if this is not the case.
//  Return Type: TPM_RC
//      TPM_RC_NO_RESULT        the value for dsA does not give a valid point on the
//                              curve
static TPM_RC C_2_2_MQV(TPMS_ECC_POINT* outZ,   // OUT: the computed point
			TPM_ECC_CURVE curveId,  // IN: the curve for the computations
			TPM2B_ECC_PARAMETER* dsA,  // IN: static private TPM key
			TPM2B_ECC_PARAMETER* deA,  // IN: ephemeral private TPM key
			TPMS_ECC_POINT*      QsB,  // IN: static public party B key
			TPMS_ECC_POINT*      QeB   // IN: ephemeral public party B key
			)
{
    CRYPT_CURVE_INITIALIZED(E, curveId);
    CRYPT_POINT_VAR(pQeA);
    CRYPT_POINT_INITIALIZED(pQeB, QeB);
    CRYPT_POINT_INITIALIZED(pQsB, QsB);
    CRYPT_ECC_NUM(bnTa);
    CRYPT_ECC_INITIALIZED(bnDeA, deA);
    CRYPT_ECC_INITIALIZED(bnDsA, dsA);
    CRYPT_ECC_NUM(bnN);
    CRYPT_ECC_NUM(bnXeB);
    TPM_RC retVal;
    //
    // Parameter checks
    if(E == NULL)
	ERROR_EXIT(TPM_RC_VALUE);
    pAssert(
	    outZ != NULL && pQeB != NULL && pQsB != NULL && deA != NULL && dsA != NULL);
    // Process:
    //  1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n.
    //  2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B).
    //  3. If P = O, output an error indicator.
    //  4. Z=xP, where xP is the x-coordinate of P.

    // Compute the public ephemeral key pQeA = [de,A]G
    if((retVal =
	TpmEcc_PointMult(pQeA, ExtEcc_CurveGetG(curveId), bnDeA, NULL, NULL, E))
       != TPM_RC_SUCCESS)
	goto Exit;

    //  1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n.
    //  tA := (ds,A + de,A  avf(Xe,A)) mod n    (3)
    //  Compute 'tA' = ('deA' +  'dsA'  avf('XeA')) mod n
    // Ta = avf(XeA);
    ExtMath_Copy(bnTa, ExtEcc_PointX(pQeA));
    avf1(bnTa, bnN);
    // do Ta = ds,A * Ta mod n = dsA * avf(XeA) mod n
    ExtMath_ModMult(bnTa, bnDsA, bnTa, bnN);
    // now Ta = deA + Ta mod n =  deA + dsA * avf(XeA) mod n
    ExtMath_Add(bnTa, bnTa, bnDeA);
    ExtMath_Mod(bnTa, bnN);

    //  2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B).
    // Put this in because almost every case of h is == 1 so skip the call when
    // not necessary.
    if(!ExtMath_IsEqualWord(ExtEcc_CurveGetCofactor(curveId), 1))
	// Cofactor is not 1 so compute Ta := Ta * h mod n
	ExtMath_ModMult(bnTa,
			bnTa,
			ExtEcc_CurveGetCofactor(curveId),
			ExtEcc_CurveGetOrder(curveId));

    // Now that 'tA' is (h * 'tA' mod n)
    // 'outZ' = (tA)(Qe,B + avf(Qe,B)Qs,B).

    // first, compute XeB = avf(XeB)
    avf1(bnXeB, bnN);

    // QsB := [XeB]QsB
    TpmEcc_PointMult(pQsB, pQsB, bnXeB, NULL, NULL, E);
    ExtEcc_PointAdd(pQeB, pQeB, pQsB, E);

    // QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity
    // If the result is not the point at infinity, return QeB
    TpmEcc_PointMult(pQeB, pQeB, bnTa, NULL, NULL, E);
    if(ExtEcc_IsInfinityPoint(pQeB))
	ERROR_EXIT(TPM_RC_NO_RESULT);
    // Convert Crypt_Int* E to TPM2B E
    TpmEcc_PointTo2B(outZ, pQeB, E);

 Exit:
    CRYPT_CURVE_FREE(E);
    return retVal;
}

#  endif  // ALG_ECMQV

//*** C_2_2_ECDH()
// This function performs the two phase key exchange defined in SP800-56A,
// 6.1.1.2 Full Unified Model, C(2, 2, ECC CDH).
//
static TPM_RC C_2_2_ECDH(TPMS_ECC_POINT* outZs,  // OUT: Zs
			 TPMS_ECC_POINT* outZe,  // OUT: Ze
			 TPM_ECC_CURVE curveId,  // IN: the curve for the computations
			 TPM2B_ECC_PARAMETER* dsA,  // IN: static private TPM key
			 TPM2B_ECC_PARAMETER* deA,  // IN: ephemeral private TPM key
			 TPMS_ECC_POINT*      QsB,  // IN: static public party B key
			 TPMS_ECC_POINT*      QeB  // IN: ephemeral public party B key
			 )
{
    CRYPT_CURVE_INITIALIZED(E, curveId);
    CRYPT_ECC_INITIALIZED(bnAs, dsA);
    CRYPT_ECC_INITIALIZED(bnAe, deA);
    CRYPT_POINT_INITIALIZED(ecBs, QsB);
    CRYPT_POINT_INITIALIZED(ecBe, QeB);
    CRYPT_POINT_VAR(ecZ);
    TPM_RC retVal;
    //
    // Parameter checks
    if(E == NULL)
	ERROR_EXIT(TPM_RC_CURVE);
    pAssert(
	    outZs != NULL && dsA != NULL && deA != NULL && QsB != NULL && QeB != NULL);

    // Do the point multiply for the Zs value ([dsA]QsB)
    retVal = TpmEcc_PointMult(ecZ, ecBs, bnAs, NULL, NULL, E);
    if(retVal == TPM_RC_SUCCESS)
	{
	    // Convert the Zs value.
	    TpmEcc_PointTo2B(outZs, ecZ, E);
	    // Do the point multiply for the Ze value ([deA]QeB)
	    retVal = TpmEcc_PointMult(ecZ, ecBe, bnAe, NULL, NULL, E);
	    if(retVal == TPM_RC_SUCCESS)
		TpmEcc_PointTo2B(outZe, ecZ, E);
	}
 Exit:
    CRYPT_CURVE_FREE(E);
    return retVal;
}

//*** CryptEcc2PhaseKeyExchange()
// This function is the dispatch routine for the EC key exchange functions that use
// two ephemeral and two static keys.
//  Return Type: TPM_RC
//      TPM_RC_SCHEME             scheme is not defined
LIB_EXPORT TPM_RC CryptEcc2PhaseKeyExchange(
					    TPMS_ECC_POINT*      outZ1,    // OUT: a computed point
					    TPMS_ECC_POINT*      outZ2,    // OUT: and optional second point
					    TPM_ECC_CURVE        curveId,  // IN: the curve for the computations
					    TPM_ALG_ID           scheme,   // IN: the key exchange scheme
					    TPM2B_ECC_PARAMETER* dsA,      // IN: static private TPM key
					    TPM2B_ECC_PARAMETER* deA,      // IN: ephemeral private TPM key
					    TPMS_ECC_POINT*      QsB,      // IN: static public party B key
					    TPMS_ECC_POINT*      QeB       // IN: ephemeral public party B key
					    )
{
    pAssert(
	    outZ1 != NULL && dsA != NULL && deA != NULL && QsB != NULL && QeB != NULL);

    // Initialize the output points so that they are empty until one of the
    // functions decides otherwise
    outZ1->x.b.size = 0;
    outZ1->y.b.size = 0;
    if(outZ2 != NULL)
	{
	    outZ2->x.b.size = 0;
	    outZ2->y.b.size = 0;
	}
    switch(scheme)
	{
	  case TPM_ALG_ECDH:
	    return C_2_2_ECDH(outZ1, outZ2, curveId, dsA, deA, QsB, QeB);
	    break;
#  if ALG_ECMQV
	  case TPM_ALG_ECMQV:
	    return C_2_2_MQV(outZ1, curveId, dsA, deA, QsB, QeB);
	    break;
#  endif
#  if ALG_SM2
	  case TPM_ALG_SM2:
	    return SM2KeyExchange(outZ1, curveId, dsA, deA, QsB, QeB);
	    break;
#  endif
	  default:
	    return TPM_RC_SCHEME;
	}
}

#  if ALG_SM2

//*** ComputeWForSM2()
// Compute the value for w used by SM2
static UINT32 ComputeWForSM2(TPM_ECC_CURVE curveId)
{
    //  w := ceil(ceil(log2(n)) / 2) - 1
    return (ExtMath_MostSigBitNum(ExtEcc_CurveGetOrder(curveId)) / 2 - 1);
}

//*** avfSm2()
// This function does the associated value computation required by SM2 key
// exchange. This is different from the avf() in the international standards
// because it returns a value that is half the size of the value returned by the
// standard avf(). For example, if 'n' is 15, 'Ws' ('w' in the standard) is 2 but
// the 'W' here is 1. This means that an input value of 14 (1110b) would return a
// value of 110b with the standard but 10b with the scheme in SM2.
static Crypt_Int* avfSm2(Crypt_Int* bn,  // IN/OUT: the reduced value
			 UINT32     w    // IN: the value of w
			 )
{
    // a)   set w := ceil(ceil(log2(n)) / 2) - 1
    // b)   set x' := 2^w + ( x & (2^w - 1))
    // This is just like the avf for MQV where x' = 2^w + (x mod 2^w)

    ExtMath_MaskBits(bn, w);  // as with avf1, this is too big by a factor of 2 but
    // it doesn't matter because we SET the extra bit
    // anyway
    if(!ExtMath_SetBit(bn, w))
	{
	    FAIL(FATAL_ERROR_CRYPTO);
	}
    return bn;
}

//*** SM2KeyExchange()
// This function performs the key exchange defined in SM2.
// The first step is to compute
//  'tA' = ('dsA' + 'deA'  avf(Xe,A)) mod 'n'
// Then, compute the 'Z' value from
// 'outZ' = ('h'  'tA' mod 'n') ('QsA' + [avf('QeB.x')]('QeB')).
// The function will compute the ephemeral public key from the ephemeral
// private key.
// All points are required to be on the curve of 'inQsA'. The function will fail
// catastrophically if this is not the case
//  Return Type: TPM_RC
//      TPM_RC_NO_RESULT        the value for dsA does not give a valid point on the
//                              curve
LIB_EXPORT TPM_RC SM2KeyExchange(
				 TPMS_ECC_POINT*      outZ,     // OUT: the computed point
				 TPM_ECC_CURVE        curveId,  // IN: the curve for the computations
				 TPM2B_ECC_PARAMETER* dsAIn,    // IN: static private TPM key
				 TPM2B_ECC_PARAMETER* deAIn,    // IN: ephemeral private TPM key
				 TPMS_ECC_POINT*      QsBIn,    // IN: static public party B key
				 TPMS_ECC_POINT*      QeBIn     // IN: ephemeral public party B key
				 )
{
    CRYPT_CURVE_INITIALIZED(E, curveId);
    CRYPT_ECC_INITIALIZED(dsA, dsAIn);
    CRYPT_ECC_INITIALIZED(deA, deAIn);
    CRYPT_POINT_INITIALIZED(QsB, QsBIn);
    CRYPT_POINT_INITIALIZED(QeB, QeBIn);
    CRYPT_INT_WORD_INITIALIZED(One, 1);
    CRYPT_POINT_VAR(QeA);
    CRYPT_ECC_NUM(XeB);
    CRYPT_POINT_VAR(Z);
    CRYPT_ECC_NUM(Ta);
    CRYPT_ECC_NUM(QeA_X);
    UINT32 w;
    TPM_RC retVal = TPM_RC_NO_RESULT;
    //
    // Parameter checks
    if(E == NULL)
	ERROR_EXIT(TPM_RC_CURVE);
    pAssert(outZ != NULL && dsA != NULL && deA != NULL && QsB != NULL && QeB != NULL);

    // Compute the value for w
    w = ComputeWForSM2(curveId);

    // Compute the public ephemeral key pQeA = [de,A]G
    if(!ExtEcc_PointMultiply(QeA, ExtEcc_CurveGetG(curveId), deA, E))
	goto Exit;

    //  tA := (ds,A + de,A  avf(Xe,A)) mod n    (3)
    //  Compute 'tA' = ('dsA' +  'deA'  avf('XeA')) mod n
    // Ta = avf(XeA);
    // do Ta = de,A * Ta = deA * avf(XeA)
    ExtMath_Copy(QeA_X, ExtEcc_PointX(QeA));  // create mutable copy
    ExtMath_Multiply(Ta, deA, avfSm2(QeA_X, w));
    // now Ta = dsA + Ta =  dsA + deA * avf(XeA)
    ExtMath_Add(Ta, dsA, Ta);
    ExtMath_Mod(Ta, ExtEcc_CurveGetOrder(curveId));

    //  outZ = [h  tA mod n] (Qs,B + [avf(Xe,B)](Qe,B)) (4)
    // Put this in because almost every case of h is == 1 so skip the call when
    // not necessary.
    if(!ExtMath_IsEqualWord(ExtEcc_CurveGetCofactor(curveId), 1))
	// Cofactor is not 1 so compute Ta := Ta * h mod n
	ExtMath_ModMult(
			Ta, Ta, ExtEcc_CurveGetCofactor(curveId), ExtEcc_CurveGetOrder(curveId));
    // Now that 'tA' is (h * 'tA' mod n)
    // 'outZ' = ['tA'](QsB + [avf(QeB.x)](QeB)).
    ExtMath_Copy(XeB, ExtEcc_PointX(QeB));
    if(!ExtEcc_PointMultiplyAndAdd(Z, QsB, One, QeB, avfSm2(XeB, w), E))
	goto Exit;
    // QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity
    if(!ExtEcc_PointMultiply(Z, Z, Ta, E))
	goto Exit;
    // Convert Crypt_Int* E to TPM2B E
    TpmEcc_PointTo2B(outZ, Z, E);
    retVal = TPM_RC_SUCCESS;
 Exit:
    CRYPT_CURVE_FREE(E);
    return retVal;
}
#  endif

#endif  // CC_ZGen_2Phase
