///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004 Intel Corporation 
// All rights reserved. 
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met: 
//
// * Redistributions of source code must retain the above copyright notice, 
// this list of conditions and the following disclaimer. 
// * Redistributions in binary form must reproduce the above copyright notice, 
// this list of conditions and the following disclaimer in the documentation 
// and/or other materials provided with the distribution. 
// * Neither name of Intel Corporation nor the names of its contributors 
// may be used to endorse or promote products derived from this software 
// without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <ipp.h>
#include <ippcp.h>

#include "bignum.h"

BigNum::BigNum(int length)
{
	int bufSize;
	length_ = length;

	ippsBigNumBufferSize(length_, &bufSize);

	pNum_ = (IppsBigNum*)ippsMalloc_8u(bufSize);

	ippsBigNumInit(length_, pNum_);
}

BigNum::~BigNum()
{
	if (pNum_) ippsFree(pNum_);
}

void BigNum::Set(int sign, const unsigned int* pData)
{
	ippsSet_BN((IppsBigNumSGN)(sign>0), length_,
		pData, pNum_);
}

void BigNum::Get(int* sign, unsigned int* pData) const
{
	int dummy;
	IppsBigNumSGN sgn;
	ippsGet_BN(&sgn, &dummy, pData, pNum_);
	if ((int)sgn) *sign = 1;
	else *sign = -1;
}

void BigNum::Zero()
{
	Ipp32u* pZero = ippsMalloc_32u(length_);
	ippsZero_16s((Ipp16s*)pZero, length_*2);
	ippsSet_BN((IppsBigNumSGN)0, length_, pZero, pNum_);
}
/*
void BigNum::Randomize(int len)
{
	// Seed RNG with low 32 bits of CPU clock.
	int i;
	Ipp32u *pSeed = ippsMalloc_32u(length_*2);
	for (i=0; i<(length_*2-1); i++)
		*(Ipp64u*)(pSeed+i) = ippCoreGetCpuClocks();

	int rngSize;
	ippsPRNGBufferSize(length_*32, &rngSize);
	IppsPRNG* pRNG = (IppsPRNG*)ippsMalloc_8u(rngSize);
	ippsPRNGInit(length_*32, pRNG);

	// Give entropy to the PRNG
	ippsPRNGSetSeed(pSeed, pRNG);
	BigNum b(length_*2);
	b.Set(1, pSeed);
	ippsPRNGAdd(b.pNum_, length_*64, pRNG);

	int bitLength;
	Ipp32u* pRand = ippsMalloc_32u(length_);
	ippsPRNGGetRand(&bitLength, pRand, pRNG);

	// Pad with zeros if passed a length
	if (len != -1)
		ippsSet_32s(0, (Ipp32s*)pRand+len, length_ - len);

	// Fill *this with generated random number
	Set(1, pRand);

	ippsFree(pRand);
}
*/
void BigNum::Randomize(int len)
{
	// Seed RNG with low 32 bits of CPU clock.
	int i;
	Ipp32u seed  = ippCoreGetCpuClocks() % (((Ipp64s)1<<32)-1);
//printf("Seed: %x\n", seed);
	srand(seed);

	Ipp32u* pRand = ippsMalloc_32u(length_);
    for (i = 0; i < length_; i++)
        pRand[i] = (Ipp32u)rand() + (((Ipp32u)rand())<<16);

	// Pad with zeros if passed a length
	if (len != -1)
		ippsSet_32s(0, (Ipp32s*)pRand+len, length_ - len);

	// Fill *this with generated random number
	Set(1, pRand);

	ippsFree(pRand);
}

void BigNum::Print() const
{
	Ipp32u* pData = ippsMalloc_32u(length_);
	int dummy;
	Get(&dummy, pData);

	for (int i=0; i<length_; i++)
		printf("%x ",pData[i]);
	printf("\n");

	ippsFree(pData);
}
