算法系列2——RSA

1. RSA介绍

RSA公钥加密算法是1977年由Ron Rivest、Adi
Shamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价。即RSA的重大缺陷是无法从理论上把握它的保密性能如何,而且密码学界多数人士倾向于因子分解不是NPC问题。

RSA的缺点主要有:A)产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。B)分组长度太大,为保证安全性,n 至少也要600BITS以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。目前,SET(Secure Electronic Transaction)协议中要求CA采用2048BITS长的密钥,其他实体使用1024比特的密钥。C)RSA密钥长度随着保密级别提高,增加很快。下表列出了对同一安全级别所对应的密钥长度。


   
  
保密级别     
   


     
  
对称密钥长度(bit)     
   


     
  
  
RSA密钥长度(bit)      
    


        
  
ECC密钥长度(bit)     
  
  


   
      
保密年限   
  


80


80


1024


160


2010


112


112


2048


224


2030


128


128


3072


256


2040


192


192


7680


384


2080


256


256


15360


512


2120

该可逆算法是经批准用于加密和生成数字签名的算法。公钥指数的值只允许是3和216+1。该算法产生的密文及数字签名的长度与模长相等。


描述


最大长度


认证中心公钥模


248字节


发卡行公钥模


248字节


IC卡公钥模


248字节

认证中心公钥模的长度NCA,发卡行公钥模的长度NI,IC卡公钥模的长度NIC,必须满足NIC≤NI≤NCA和NPE≤NI≤NCA。

注: IC卡中一个记录的长度最长不超过254字节(包括Tag和Length),因而实际IC卡公钥和发卡行公钥长度应小于最大长度248字节。命令数据长度最长为255字节,响应数据最长为256字节,动态签名数据作为IC卡响应数据,也限制了IC卡公钥的最大长度。

如卡片支持DDA和CDA,包含IC卡证书的记录模板的长度,即IC卡公钥证书长度加上证书(’9F46’)和记录模板(’70’)的Tag和Length不超过254字节,则IC卡公钥长度不超过247字节,因而发卡行公钥长度最大长度也不超过247字节。

根据发卡行应用数据长度不同,IC卡公钥最大长度在205到240之间。如果Generate AC命令响应包含其他可选数据,IC卡公钥最大长度还应减去这些数据的长度(包括Tag和Length)。如果卡片应用支持INTERNALAUTHENTICATION格式二,IC卡公钥最大长度还应减去7字节。

在选择公钥模长时,应该考虑到比较密钥的生命周期同预期的因数分解进程。

发卡行公钥指数和IC卡公钥指数的值由发卡行决定。认证中心,发卡行和IC卡公钥指数必须等于3或216+1。

标识本数字签名算法的公钥算法标识必须编码为十六进制‘01’。

2.RSA算法源码

<<RSA.h>>

// LargeInt.h
// 大整数类的声明,包含了质数检查,随机数生成,以及RSA密钥生成及加密解密函数。

//////////////////////////////////////////////////////////////////////////////

//RSA加密里所说的1024 位加密、2048位加密,是不是只要
//CLargeInt::CreateRandom(e,1024);
//这句代码里的参数设置成1024、2048就行了?
//
////不是的,2048bit,是指P*Q的积是2048bit,也就是说,当你P和Q都设置为1024的时候,加密强度是2048bit,事实上P和Q的位数可以不等,并且过分接近的P和Q将导致破解难度极大降低。
//
//
//_data 和 _len 这两个变量到底起什么作用?
//_data 占了4092个字节的大小,_len=64时,只输出了512个字节。
////_data和_len其实是模拟了一个动态数组,用来容纳长度不定的大整数。_data 占据的大小是预先设置好的,这个数值在LargeInt.h中有定义:
//enum LIMIT{ LENGTH = 0x3FF,SMALLPRIMES = 5000};
//LENGTH 可以根据需要修改。
//_len是以4字节为单位的目前已经占用的数组的长度,_len = 64就是当前大整数的长度是64*4 = 256字节
//输出的字节是以16进制表示的字符串,每个字节需要两个符号来表示,所以长度是256*2 = 512字节。

//必须保证T_DWORD是4字节。
typedef unsigned long T_DWORD;

class CLargeInt
{
public:
	//说明:
	//基本的操作函数之所以没有设置成运算符的重载,主要是因为,
	//大数运算的过程中,经常需要额外的参数,例如错位相加减的offset值。
	//以及某些额外的结果
	//例如,除法运算的商和余数。
	//为了代码尽量通用,都写成了静态成员函数。
	//运算符的重载可以通过对这些静态成员函数进一步封装来实现。

	//复制
	static void Copy(const CLargeInt& source,CLargeInt& target);

	//比较
	static bool LargerEqual(const CLargeInt& source,const CLargeInt& target,T_DWORD offset = 0);
	static bool Equal(const CLargeInt& source,const CLargeInt& target);

	//和T_DWORD类型交互的底层操作函数
	static void Mul(const CLargeInt& faciend,T_DWORD multiplier,CLargeInt& product);
	static void Div(const CLargeInt& dividend,T_DWORD divisor,CLargeInt& quotient,T_DWORD& residual);

	//移位:
	//右移一位,用来取代 /2 操作。
	static void RCR(CLargeInt& n);
	//左移一位,用来取代 *2 操作。
	static void RCL(CLargeInt& n);

	//CLargeInt类型底层操作函数,
	static void Add(const CLargeInt& augend, const CLargeInt& addend, CLargeInt& sum,T_DWORD offset = 0);
	static void Sub(const CLargeInt& minuend,const CLargeInt& subtrahend, CLargeInt& difference,T_DWORD offset = 0);
	static void Mul(const CLargeInt& faciend, const CLargeInt& multiplier, CLargeInt& product);
	static void Div(const CLargeInt& dividend, const CLargeInt& divisor, CLargeInt& quotient,CLargeInt& residual);
	static void ExpMod(const CLargeInt& source, const CLargeInt& exponent, const CLargeInt& modulo,CLargeInt& result);

	//高阶的测试
	static bool RabinMillerTest(const CLargeInt& source, const CLargeInt& base);
	static bool Coprime(const CLargeInt &source, const CLargeInt &target);

	//RSA算法相关函数:
	static bool IsPrime(const CLargeInt &n);
	static void CreatePrime(CLargeInt &n);
	static bool RSACreate( const CLargeInt &p,const CLargeInt & q,const CLargeInt &e,CLargeInt &d,CLargeInt &n);
	static void RSAEncode( const CLargeInt &n,const CLargeInt &d,const CLargeInt &m,CLargeInt &c);
	static void RSADecode( const CLargeInt &n,const CLargeInt &e,const CLargeInt &c,CLargeInt &m);
	static string RSADecode(const char* N, const char* E, const char* I);
	//建立随机数。
	static void CreateRandom(CLargeInt &n,T_DWORD bitcount);
public:
	CLargeInt(T_DWORD value = 0);
	CLargeInt(const char* str);
	CLargeInt(const CLargeInt& other);

	~CLargeInt();

private:
	enum LIMIT{ LENGTH = 0x3FF, SMALLPRIMES = 5000};
	T_DWORD _len;
	mutable T_DWORD _data[LENGTH]; //之所以用 mutable 是因为需要在计算中获取指针,并且有时还需要在不改变数值的情况下修改某些数组元素。

	//辅助用的小质数表和相关的函数。
	static std::vector<T_DWORD> _smallPrimes;
	static void InitSmallPrimes(T_DWORD count = SMALLPRIMES);
	static bool SmallPrimeTest(const CLargeInt& n);
	string GetHexStr();
};

// LARGEINT_HEADER

<<RSA.CPP>>

std::vector<T_DWORD> CLargeInt::_smallPrimes;
void CLargeInt::InitSmallPrimes(T_DWORD	count)
{
	if (!_smallPrimes.size()) //尚未初始化
	{
		_smallPrimes.reserve(count);
		_smallPrimes.push_back(3);
		_smallPrimes.push_back(5);
		_smallPrimes.push_back(7);
		_smallPrimes.push_back(11);
		_smallPrimes.push_back(13);
		T_DWORD	i = 0;
		for( i = 17; _smallPrimes.size() < count; i+= 2)
		{
			bool bePrime = true;
			for( T_DWORD j = 0; j <	_smallPrimes.size(); j++ )
			{
				if( ( _smallPrimes[j] *	_smallPrimes[j]	) > i )	//已经不可能了。
					break;
				if( (i % _smallPrimes[j]) == 0)	//可以整除
					bePrime	= false;
			}
			if( bePrime ) //是素数
			{
				_smallPrimes.push_back(i);
			}
		}
	}
}

bool CLargeInt::SmallPrimeTest(const CLargeInt&	n)
{
	if (n._data[0] == 2 && n._len == 1)
	{
		return true; //2是质数。
	}

	if (n._len == 1	&& n._data[0] <= _smallPrimes.back()) //整数比表中的数据小。
	{
		if (std::binary_search(_smallPrimes.begin(),_smallPrimes.end(),n._data[0])) //找到,n存在于质数表中。
		{
			return true; //通过测试,数n是质数。
		}

		return false; //没有通过,n是合数。
	}
	else
	{
		CLargeInt temp;
		T_DWORD	r;
		for( T_DWORD i = 0; i <	_smallPrimes.size(); i++)
		{
			Div(n,_smallPrimes[i],temp,r); //依次检查是否能整除。
			if( r == 0) return false; //能整除,说明 n 有小于它的质因子。n 是合数。
		}

		return true; //	n 没有表中已有的质因子,n有可能是质数。
	}
}

bool CLargeInt::IsPrime(const CLargeInt	&n)
{
	InitSmallPrimes();
	if (n._data[0]&1) //奇数
	{
		if (n._len == 1	&& n._data[0] <= _smallPrimes.back())
		{
			return SmallPrimeTest(n);  //是小质数表中的一个质数。
		}
		else
		{
			if( SmallPrimeTest(n) )	//通过小质数测试
			{
				for( int i = 0;	i < 5; i++)
				{
					CLargeInt a(_smallPrimes[ _smallPrimes.size() -	i]);
					if( !RabinMillerTest(n,a) ) return false;
				}

				return true; //99.9%的可能是质数。
			}
			else
			{
				return false;
			}
		}
	}

	return false;
}

void CLargeInt::CreatePrime(CLargeInt &n)
{
	n._data[0] |= 0x01;
	while (!IsPrime(n))
	{
		Add(n, 2, n); //步进2,寻找最接近的下一个质数。这个算法并不是寻找质数最好的算法,但是它可以保证寻找到相邻的质数。
	}
}

CLargeInt::CLargeInt(T_DWORD value) : _len(1)
{
	_data[0] = value;
}

CLargeInt::CLargeInt(const CLargeInt& other)
{
	Copy(other,*this);
}

CLargeInt::CLargeInt(const char	* str):	_len(1)
{
	_data[0] = 0;

	//if(str && strlen(str) >	2 && ( strncmp(str,"0x",2) == 0	|| strncmp(str,"0X",2) == 0 ) )
	if (str)
	{
		CLargeInt temp;
		char ch;
		T_DWORD	n = 0;
		const char * p = str;
		while (*p)
		{
			ch	= *p;
			if ((ch >= '0') && (ch <= '9'))
			{
				n = ch - '0';
			}
			else if ((ch >= 'a') && (ch <= 'f'))
			{
				n = ch - 'a' + 10;       //a->f分别代表10->15   a的AscII为97,所以这里应该减去87
			}
			else if ((ch >= 'A') && (ch <= 'F'))
			{
				n = ch - 'A' + 10;       //同上
			}
			p++;
			Mul(*this, 16, temp);
			Add(temp, n, *this);
		}
	}
	//else
	//{//这里应该用来处理除了0x开头的16进制字符串的情况。
	//	__asm int 3;
	//}
}

CLargeInt::~CLargeInt()
{

}

void CLargeInt::Copy(const CLargeInt& source, CLargeInt& target)
{
	if (&source != &target) //避免自身拷贝。
	{
		target._len = source._len;

		//相信库函数能提供最高效的实现。
		memcpy(target._data, source._data, source._len * 4);
	}
}

bool CLargeInt::Equal(const CLargeInt& source, const CLargeInt& target)
{
	if (source._len	== target._len)
	{
		//相信库函数能提供最高效的实现。
		return !(memcmp(source._data, target._data,source._len * 4));
	}
	else
	{
		return false;
	}
}

bool CLargeInt::LargerEqual(const CLargeInt& source,const CLargeInt& target,T_DWORD offset )
{
	if( source._len	> (target._len + offset) ) return true;
	else if( source._len < (target._len + offset) )	return false;
	else
	{
		int end	= offset;
		for( int i = source._len - 1; i	>= end ; i--)
		{
			T_DWORD	ii = i - offset;
			if( source._data[i] > target._data[ii] ) return	true; //大于
			else if( source._data[i] < target._data[ii] )	return false;
		}
		return true; //相等。
	}

}

void CLargeInt::Add(const CLargeInt &augend, const CLargeInt &addend, CLargeInt	&sum,T_DWORD offset)
{
	T_DWORD	len,len1,len2; //len绝对不能<1,否则会出错。
	T_DWORD	*p1 = 0;
	T_DWORD	*p2 = 0;
	T_DWORD	*p3 = 0;

	if( augend._len	>= (addend._len+offset)	)
	{
		len = augend._len - offset;
		len1 = addend._len;
		len2 =	len - len1;
		p1 = augend._data+offset;
		p2 = addend._data;
		p3 = sum._data+offset;
	}
	else
	{
		len = addend._len;
		if( augend._len	<= offset )
		{
			augend._data[offset] = 0;
			len1 = 1;
			len2 = addend._len - len1;
		}
		else
		{
			len1 = augend._len - offset;
			len2 = addend._len - len1;
		}
		p1 = addend._data;
		p2 = augend._data + offset;
		p3 = sum._data + offset;
	}

	__asm
	{
		pushad;
		//载入计算地址
		mov esi,p1;
		mov ebx,p2;
		mov edi,p3;

		mov eax,len1;
		sal eax,2;

		//计算末地址
		add esi,eax;
		add ebx,eax;
		add edi,eax;

		mov ecx,eax;
		add ecx,4*7;
		and ecx,0xFFFFFFE0; //ecx - ecx%32,这里的ecx就变成了偏移址,同时也是累加器。
		neg ecx; //取负,用作累加。

		sar eax,2; //回复到原来的长度

		neg eax; //取负
		and eax,dword ptr 7;
		jz labeladd0; //如果低位是0,说明长度至少有8(因为长度为0是非法的)

		mov edx,dword ptr 0xC;
		mul edx; //eax变为相对偏移址。

		lea edx,labeladd1; //载入起始地址
		sub edx,dword ptr 0xC;
		add eax,edx; //计算出跳转地址

		clc; //清除标志位。
		jmp eax; //跳转
labeladdloop:
		popf;
labeladd0:
		mov eax,[esi+ecx+0*4];
		adc eax,[ebx+ecx+0*4];
		mov [edi+ecx+0*4],eax;
labeladd1:
		mov eax,[esi+ecx+1*4];
		adc eax,[ebx+ecx+1*4];
		mov [edi+ecx+1*4],eax;
		//labeladd2:
		mov eax,[esi+ecx+2*4];
		adc eax,[ebx+ecx+2*4];
		mov [edi+ecx+2*4],eax;
		//labeladd3:
		mov eax,[esi+ecx+3*4];
		adc eax,[ebx+ecx+3*4];
		mov [edi+ecx+3*4],eax;
		//labeladd4:
		mov eax,[esi+ecx+4*4];
		adc eax,[ebx+ecx+4*4];
		mov [edi+ecx+4*4],eax;
		//labeladd5:
		mov eax,[esi+ecx+5*4];
		adc eax,[ebx+ecx+5*4];
		mov [edi+ecx+5*4],eax;
		//labeladd6:
		mov eax,[esi+ecx+6*4];
		adc eax,[ebx+ecx+6*4];
		mov [edi+ecx+6*4],eax;
		//labeladd7:
		mov eax,[esi+ecx+7*4];
		adc eax,[ebx+ecx+7*4];
		mov [edi+ecx+7*4],eax;
		//labeladd8:
		pushf;
		add ecx,32;
		jnz labeladdloop;

		//运行到这里了,说明两数重合部分已经处理完了。开始处理两数相差的部分。

		mov ecx,len2; //载入长度

		xor ebx,ebx; //因为ebx指向的缓冲区废弃不用了,所以使用已经空闲的ebx寄存器。
		cmp ebx,ecx; //判断ecx是否等于ebx(0)
		jz labelcarry; //如果相等,说明已经处理完了,跳转到处理最后一次进位的地方。

labelfix:
		popf; //弹出上次的标志位。

		mov eax,[esi+ebx*4];
		adc eax,0;
		mov [edi+ebx*4],eax;

		//如果这里没有进位,剩下的部分可以直接拷贝。拷贝的长度就是ecx-1
		jnc labelcopy;

		pushf; //保存标志位。

		inc ebx; //步进
		dec ecx;
		jnz labelfix; //循环。

labelcarry:
		popf; //弹出标志位
		jnc labelend; //没有进位就直接结束
		//没有跳转说明有进位:
		mov dword ptr [edi+ebx*4],dword	ptr 0x00000001;	//直接置1
		lea eax,len;
		inc [eax]; //总长度+1
		inc ecx; //补一次。
labelcopy:
		dec ecx;
		sal ecx,2;
		cmp edi,esi; //比较源地址和目标地址,如果相同就跳过。
		jz labelend;

		sal ebx,2;
		add ebx,4;

		add edi,ebx;
		add esi,ebx;

		rep movs dword ptr [edi],dword ptr [esi];

labelend:
		popad;
	}
	sum._len = len + offset;
}

void CLargeInt::Sub(const CLargeInt& minuend,const CLargeInt& subtrahend,CLargeInt& difference,T_DWORD offset)
{
	T_DWORD	len,len1,len2; //len绝对不能<1,否则会出错。
	T_DWORD	*p1 = 0;
	T_DWORD	*p2 = 0;
	T_DWORD	*p3 = 0;

	if( minuend._len >= (subtrahend._len+offset) )
	{
		len = minuend._len- offset;
		len1 = subtrahend._len;
		len2 =	len - len1;
		p1 = minuend._data + offset;
		p2 = subtrahend._data;
		p3 = difference._data +	offset;
	}
	else
	{
		__asm int 3; //出错。
	}

	__asm
	{
		pushad;
		//载入计算地址
		mov esi,p1;
		mov ebx,p2;
		mov edi,p3;

		mov eax,len1;
		sal eax,2;

		//计算末地址
		add esi,eax;
		add ebx,eax;
		add edi,eax;

		mov ecx,eax;
		add ecx,4*7;
		and ecx,0xFFFFFFE0; //ecx - ecx%32,这里的ecx就变成了偏移址,同时也是累加器。
		neg ecx; //取负,用作累加。

		sar eax,2; //回复到原来的长度

		neg eax; //取负
		and eax,dword ptr 7;
		jz labeladd0; //如果低位是0,说明长度至少有8(因为长度为0是非法的)

		mov edx,dword ptr 0xC;
		mul edx; //eax变为相对偏移址。

		lea edx,labeladd1; //载入起始地址
		sub edx,dword ptr 0xC;
		add eax,edx; //计算出跳转地址

		clc; //清除标志位。
		jmp eax; //跳转
labeladdloop:
		popf;
labeladd0:
		mov eax,[esi+ecx+0*4];
		sbb eax,[ebx+ecx+0*4];
		mov [edi+ecx+0*4],eax;
labeladd1:
		mov eax,[esi+ecx+1*4];
		sbb eax,[ebx+ecx+1*4];
		mov [edi+ecx+1*4],eax;
		//labeladd2:
		mov eax,[esi+ecx+2*4];
		sbb eax,[ebx+ecx+2*4];
		mov [edi+ecx+2*4],eax;
		//labeladd3:
		mov eax,[esi+ecx+3*4];
		sbb eax,[ebx+ecx+3*4];
		mov [edi+ecx+3*4],eax;
		//labeladd4:
		mov eax,[esi+ecx+4*4];
		sbb eax,[ebx+ecx+4*4];
		mov [edi+ecx+4*4],eax;
		//labeladd5:
		mov eax,[esi+ecx+5*4];
		sbb eax,[ebx+ecx+5*4];
		mov [edi+ecx+5*4],eax;
		//labeladd6:
		mov eax,[esi+ecx+6*4];
		sbb eax,[ebx+ecx+6*4];
		mov [edi+ecx+6*4],eax;
		//labeladd7:
		mov eax,[esi+ecx+7*4];
		sbb eax,[ebx+ecx+7*4];
		mov [edi+ecx+7*4],eax;
		//labeladd8:
		pushf;
		add ecx,32;
		jnz labeladdloop;

		//运行到这里了,说明两数重合部分已经处理完了。开始处理两数相差的部分。

		mov ecx,len2; //载入长度,
		//只处理p1的buf

		xor ebx,ebx; //因为ebx指向的缓冲区废弃不用了,所以使用已经空闲的ebx寄存器。
		cmp ebx,ecx; //判断ecx是否等于ebx
		jz labelcarry; //如果相等,说明已经处理完了,跳转到处理最后一次进位的地方。

labelfix:
		popf; //弹出上次的标志位。

		mov eax,[esi+ebx*4];
		sbb eax,0;
		mov [edi+ebx*4],eax;

		//如果这里没有进位,剩下的部分可以直接拷贝。拷贝的长度就是ecx-1
		jnc labelcopy;

		pushf; //保存标志位。

		inc ebx; //步进
		dec ecx;
		jnz labelfix; //循环。

labelcarry:
		popf; //弹出标志位
		jnc labelend; //没有进位就直接结束
		//没有跳转说明有进位:
		int 3; //说明减数不够,结果为负
		mov dword ptr [edi+ebx*4],dword	ptr 0x00000001;	//直接置1
		lea eax,len;
		dec [eax]; //总长度-1
		inc ecx; //补一次。
labelcopy:
		dec ecx;
		sal ecx,2;
		cmp edi,esi; //比较源地址和目标地址,如果相同就跳过。
		jz labelend;

		sal ebx,2;
		add ebx,4;

		add edi,ebx;
		add esi,ebx;

		rep movs dword ptr [edi],dword ptr [esi];

labelend:
		popad;
	}
	difference._len	= len+offset;
	for( T_DWORD i = difference._len-1; i >	0; i--)
	{
		if( difference._data[i]	== 0 ) //末尾是0
		{
			difference._len--;
		}
		else break;
	}
}

void CLargeInt::Mul(const CLargeInt& faciend,T_DWORD multiplier,CLargeInt& product)
{
	T_DWORD	len; //len绝对不能<1,否则会出错。
	T_DWORD	*p1 = 0;
	T_DWORD	*p2 = 0;
	T_DWORD	*p3 = 0;

	len = faciend._len;
	p1 = faciend._data;
	p2 = 0;
	p3 = product._data;

	memset(p3,0,(len+1)*4);
	__asm
	{
		pushad;
		//载入计算地址
		mov esi,p1;
		mov edi,p3;
		mov ebx,multiplier

			mov eax,len;
		sal eax,2;

		//计算末地址
		add esi,eax;
		add edi,eax;

		mov ecx,eax;
		add ecx,4*7;
		and ecx,0xFFFFFFE0; //ecx - ecx%32,这里的ecx就变成了偏移址,同时也是累加器。
		neg ecx; //取负,用作累加。

		sar eax,2; //回复到原来的长度

		neg eax; //取负
		and eax,dword ptr 7;
		jz labeladd0; //如果低位是0,说明长度至少有8(因为长度为0是非法的)

		mov edx,dword ptr 0xe; //0xe是跳转地址的系数。
		mul edx; //eax变为相对偏移址。

		lea edx,labeladd1; //载入起始地址
		sub edx,dword ptr 0xe;
		add eax,edx; //计算出跳转地址

		clc; //清除标志位。
		jmp eax; //跳转
labeladdloop:
labeladd0:
		mov eax,[esi+ecx+0*4];
		mul ebx;
		add [edi+ecx+0*4],eax;
		adc [edi+ecx+1*4],edx;
labeladd1:
		mov eax,[esi+ecx+1*4];
		mul ebx;
		add [edi+ecx+1*4],eax;
		adc [edi+ecx+2*4],edx;
		//labeladd2:
		mov eax,[esi+ecx+2*4];
		mul ebx;
		add [edi+ecx+2*4],eax;
		adc [edi+ecx+3*4],edx;
		//labeladd3:
		mov eax,[esi+ecx+3*4];
		mul ebx;
		add [edi+ecx+3*4],eax;
		adc [edi+ecx+4*4],edx;
		//labeladd4:
		mov eax,[esi+ecx+4*4];
		mul ebx;
		add [edi+ecx+4*4],eax;
		adc [edi+ecx+5*4],edx;
		//labeladd5:
		mov eax,[esi+ecx+5*4];
		mul ebx;
		add [edi+ecx+5*4],eax;
		adc [edi+ecx+6*4],edx;
		//labeladd6:
		mov eax,[esi+ecx+6*4];
		mul ebx;
		add [edi+ecx+6*4],eax;
		adc [edi+ecx+7*4],edx;
		//labeladd7:
		mov eax,[esi+ecx+7*4];
		mul ebx;
		add [edi+ecx+7*4],eax;
		adc [edi+ecx+8*4],edx;
		//labeladd8:
		add ecx,32;
		jnz labeladdloop;

		//labelend:
		popad;
	}
	product._len = len+1;

	for( T_DWORD i = product._len-1; i > 0;	i--)
	{
		if( product._data[i] ==	0 ) //末尾是0
		{
			product._len--;
		}
		else break;
	}

}

void CLargeInt::RCR(CLargeInt& n)
{
	T_DWORD	len; //len绝对不能<1,否则会出错。
	T_DWORD	*p1 = 0;
	len = n._len;
	p1 = n._data;

	__asm
	{
		pushad;		

		//载入计算地址
		mov esi,p1;

		mov eax,len;
		mov ecx,eax;

		add ecx,dword ptr 15;
		and ecx,dword ptr 0xFFFFFFF0;

		mov eax,ecx;
		sal ecx,dword ptr 2;

		sub eax,len; //求初始偏移。

		mov ebx,dword ptr 4; //偏移倍率
		mul ebx;		

		lea ebx,label0;
		add eax,ebx;
		clc;
		jmp eax;
labelloop:
		popf;
label0:
		rcr dword ptr [esi + ecx - 1*4],1;
		//label1:
		rcr dword ptr [esi + ecx - 2*4],1;
		//label2:
		rcr dword ptr [esi + ecx - 3*4],1;
		//label3:
		rcr dword ptr [esi + ecx - 4*4],1;
		//label4:
		rcr dword ptr [esi + ecx - 5*4],1;
		//label5:
		rcr dword ptr [esi + ecx - 6*4],1;
		//label6:
		rcr dword ptr [esi + ecx - 7*4],1;
		//label7:
		rcr dword ptr [esi + ecx - 8*4],1;
		//label8:
		rcr dword ptr [esi + ecx - 9*4],1;
		//label9:
		rcr dword ptr [esi + ecx - 10*4],1;
		//label10:
		rcr dword ptr [esi + ecx - 11*4],1;
		//label11:
		rcr dword ptr [esi + ecx - 12*4],1;
		//label12:
		rcr dword ptr [esi + ecx - 13*4],1;
		//label13:
		rcr dword ptr [esi + ecx - 14*4],1;
		//label14:
		rcr dword ptr [esi + ecx - 15*4],1;
		//label15:
		rcr dword ptr [esi + ecx - 16*4],1;
		//label16:
		pushf;
		sub ecx,dword ptr 64;
		jnz labelloop;
		popf;
		popad;
	}
	for( T_DWORD i = n._len-1; i > 0; i--)
	{
		if( n._data[i] == 0 ) //末尾是0
		{
			n._len--;
		}
		else break;
	}
}

void CLargeInt::RCL(CLargeInt& n)
{
	T_DWORD	len = n._len; //len绝对不能<1,否则会出错。
	T_DWORD	*p1 = 0;

	n._data[len] = 0;
	n._len++;

	len++;
	p1 = n._data;

	__asm
	{
		pushad;		

		//载入计算地址
		mov esi,p1;

		mov eax,len;
		mov ecx,eax;

		sal eax,dword ptr 2;
		add esi,eax;

		add ecx,dword ptr 15;
		and ecx,dword ptr 0xFFFFFFF0;

		mov eax,ecx;
		sal ecx,dword ptr 2;

		neg ecx;

		sub eax,len; //求初始偏移。
		jz label0;

		mov ebx,dword ptr 4; //偏移倍率
		mul ebx;		

		lea ebx,label1;
		sub ebx,4;
		add eax,ebx;
		clc;
		jmp eax;
labelloop:
		popf;
label0:
		rcl dword ptr [esi + ecx + 0*4],1;
label1:
		rcl dword ptr [esi + ecx + 1*4],1;
		//label2:
		rcl dword ptr [esi + ecx + 2*4],1;
		//label3:
		rcl dword ptr [esi + ecx + 3*4],1;
		//label4:
		rcl dword ptr [esi + ecx + 4*4],1;
		//label5:
		rcl dword ptr [esi + ecx + 5*4],1;
		//label6:
		rcl dword ptr [esi + ecx + 6*4],1;
		//label7:
		rcl dword ptr [esi + ecx + 7*4],1;
		//label8:
		rcl dword ptr [esi + ecx + 8*4],1;
		//label9:
		rcl dword ptr [esi + ecx + 9*4],1;
		//label10:
		rcl dword ptr [esi + ecx + 10*4],1;
		//label11:
		rcl dword ptr [esi + ecx + 11*4],1;
		//label12:
		rcl dword ptr [esi + ecx + 12*4],1;
		//label13:
		rcl dword ptr [esi + ecx + 13*4],1;
		//label14:
		rcl dword ptr [esi + ecx + 14*4],1;
		//label15:
		rcl dword ptr [esi + ecx + 15*4],1;
		//label16:
		pushf;
		add ecx,dword ptr 64;
		jnz labelloop;
		popf;
		popad;
	}
	for( T_DWORD i = n._len-1; i > 0; i--)
	{
		if( n._data[i] == 0 ) //末尾是0
		{
			n._len--;
		}
		else break;
	}
}

void CLargeInt::Mul(const CLargeInt& faciend, const CLargeInt& multiplier, CLargeInt& product)
{
	CLargeInt temp;
	product._len = (faciend._len + multiplier._len);
	memset(product._data, 0, product._len * 4);

	for (T_DWORD i = 0; i <	multiplier._len; i++)
	{
		Mul(faciend,multiplier._data[i],temp);
		Add(product,temp,product,i);
	}
	for (T_DWORD i = product._len - 1; i > 0;	i--)
	{
		if( product._data[i] ==	0 ) //末尾是0
		{
			product._len--;
		}
		else
		{
			break;
		}
	}
}

void CLargeInt::Div(const CLargeInt& dividend,T_DWORD divisor,CLargeInt& quotient,T_DWORD& residual)
{
	T_DWORD	len; //len绝对不能<1,否则会出错。
	T_DWORD	*p1 = 0;
	T_DWORD	*p2 = 0;

	T_DWORD	*pr = &residual;

	len = dividend._len;
	quotient._len =	dividend._len;
	p1 = dividend._data;
	p2 = quotient._data;

	__asm
	{
		pushad;		

		//载入计算地址
		mov esi,p1;
		mov edi,p2;

		mov eax,len;
		mov ecx,eax;

		add ecx,dword ptr 7;
		and ecx,dword ptr 0xFFFFFFF8;

		mov eax,ecx;
		sal ecx,dword ptr 2;

		sub eax,len; //求初始偏移。

		mov ebx,dword ptr 0x0A;	//偏移倍率
		mul ebx;		

		lea edx,label0;
		add eax,edx;

		xor edx,edx;

		mov ebx,divisor;

		clc;
		jmp eax;
labelloop:

label0:
		mov eax,[esi + ecx - 1*4];
		div ebx;
		mov [edi + ecx - 1*4],eax;
		//label1:
		mov eax,[esi + ecx - 2*4];
		div ebx;
		mov [edi + ecx - 2*4],eax;
		//label2:
		mov eax,[esi + ecx - 3*4];
		div ebx;
		mov [edi + ecx - 3*4],eax;
		//label3:
		mov eax,[esi + ecx - 4*4];
		div ebx;
		mov [edi + ecx - 4*4],eax;
		//label4:
		mov eax,[esi + ecx - 5*4];
		div ebx;
		mov [edi + ecx - 5*4],eax;
		//label5:
		mov eax,[esi + ecx - 6*4];
		div ebx;
		mov [edi + ecx - 6*4],eax;
		//label6:
		mov eax,[esi + ecx - 7*4];
		div ebx;
		mov [edi + ecx - 7*4],eax;
		//label7:
		mov eax,[esi + ecx - 8*4];
		div ebx;
		mov [edi + ecx - 8*4],eax;
		//label8:
		sub ecx,dword ptr 32;
		jnz labelloop;

		//运行到这里说明已经计算完毕,最后保存余数。
		mov ecx,pr;
		mov [ecx],edx;
		popad;
	}

	for (T_DWORD i = quotient._len-1; i > 0; i--)
	{
		if (quotient._data[i] == 0) //末尾是0
		{
			quotient._len--;
		}
		else
		{
			break;
		}
	}
}

void CLargeInt::Div(const CLargeInt& dividend,const CLargeInt& divisor,CLargeInt& quotient,CLargeInt& residual)
{
	if( dividend._len < divisor._len )
	{
		quotient._len =	1;
		quotient._data[0] = 0;
		Copy(dividend,residual);
	}
	else
	{
		if( divisor._len == 1)
		{
			Div(dividend,divisor._data[0],quotient,residual._data[0]);
			residual._len =	1;
		}
		else
		{
			CLargeInt d,r;

			//满位算法
			T_DWORD	head = divisor._data[divisor._len-1];
			__asm
			{
				pushad;
				mov eax,head;
				bsr ecx,eax;
				mov edx,dword ptr 31;
				sub edx,ecx;
				mov ecx,edx;
				mov eax,dword ptr 0x01;
				sal eax,cl;
				mov head,eax;
				popad;
			}

			Mul(dividend,head,d);
			Mul(divisor,head,r);

			quotient._len =	d._len - r._len	+ 1;
			quotient._data[quotient._len - 1] = 0;

			T_DWORD	newhead	= r._data[r._len - 1];
			//以上处理的目的是使得被除数最高位的1移动到DWORD的最高位。
			//处理之后可以极大减少商的上下限之间的差距。

			T_DWORD	highpart = 0;
			T_DWORD	lowpart	 = 0;
			T_DWORD	max = 0,min = 0;
			T_DWORD	offset = 0;
			CLargeInt temp;
			for( T_DWORD i = d._len-1; i >=	r._len-1; i-- )
			{
				offset = i - (r._len - 1);
				lowpart	= d._data[i];

				__asm
				{//这段汇编代码的作用是求商的上下限。min & max
					pushad;
					mov edx,highpart;
					mov eax,lowpart;
					mov ecx,newhead;
					div ecx;
					mov max,eax;

					inc ecx;
					jz _mov;
					mov edx,highpart;
					mov eax,lowpart;
					div ecx;
					mov edx,eax;
_mov:
					mov min,edx;
					popad;
				}

				if (max == 0)
				{
					highpart = d._data[i];
					quotient._data[offset] = 0;
				}
				else
				{
					Mul(r,max,temp);
					if ( max	!= min )
					{
						while ( !LargerEqual(d,temp,offset) )
						{//这里使用的其实是试商法,
							//由于max和min的差距已经很小,所以这里不再折半试商。
							max--;
							Sub(temp,r,temp);
						}
					}	

					quotient._data[offset] = max; //保存商。
					Sub(d,temp,d,offset); //求本阶的余数。
					highpart = d._data[i]; //载入余数。
				}
			}

			//清除高位的0。
			for(T_DWORD i = quotient._len-1; i > 0; i--)
			{
				if( quotient._data[i] == 0 ) //末尾是0
				{
					quotient._len--;
				}
				else break;
			}
			//除法完成,计算余数:
			Div(d,head,residual,newhead);

			if ( newhead != 0 )
			{
				//余数不为0,说明出错。
				__asm int 3;
			}
		}

	}
}

void CLargeInt::ExpMod(const CLargeInt&	source,const CLargeInt&	exponent,const CLargeInt& modulo,CLargeInt& result)
{
	CLargeInt n,e,r(1),temp,temp1;
	Copy(source,n);
	Copy(exponent,e);

	while( e._len >	1 || e._data[e._len - 1] > 1 )
	{
		if( e._data[0] &1 )
		{
			Mul(r,n,temp);
			Div(temp,modulo,temp1,r);
		}
		RCR(e);
		Mul(n,n,temp);
		Div(temp,modulo,temp1,n);
	}
	Mul(r,n,temp);
	Div(temp,modulo,temp1,result);
}

bool CLargeInt::RabinMillerTest(const CLargeInt& source,const CLargeInt& base)
{
	CLargeInt m,temp(1);

	Sub(source,temp,m);

	T_DWORD	count =	0;
	while(!(m._data[0] & 0x01) )
	{
		count++;
		RCR(m);
	}
	/*
	这里注释掉的是旧的算法,可以用后面的等效算法取代。
	改变的算法使得计算ExpMod的次数由 count 减少到 1
	虽然理论上计算次数大大减少了,但是实际效果似乎只是减少了50%左右的运算量。

	for( T_DWORD i = 0; i< count;	i++)
	{
	CLargeInt mod;
	ExpMod(base,m,source,mod);
	if( mod._data[0] == 1	&& mod._len == 1 )
	{
	return true;
	}
	else
	{
	Sub(source,mod,temp);
	if(  temp._data[0] ==	1 && temp._len == 1)
	{
	return true;
	}
	}
	RCL(m);
	}
	*/

	CLargeInt mod;
	ExpMod(base,m,source,mod);
	if( mod._data[0] == 1 && mod._len == 1 )
	{
		return true;
	}
	else
	{
		Sub(source,mod,temp);
		if(  temp._data[0] == 1	&& temp._len ==	1)
		{
			return true;
		}
	}
	for( T_DWORD i = 1; i< count; i++)
	{
		CLargeInt next,t;
		Mul(mod,mod,next);
		Div(next,source,t,mod);
		if( mod._data[0] == 1 && mod._len == 1 )
		{
			return true;
		}
		else
		{
			Sub(source,mod,temp);
			if(  temp._data[0] == 1	&& temp._len ==	1)
			{
				return true;
			}
		}
	}

	return false;
}

bool CLargeInt::RSACreate( const CLargeInt &p,const CLargeInt &	q,const	CLargeInt &e,CLargeInt &d,CLargeInt &n)
{//由已知的P,Q,E计算N,D,完成RSA密钥生成。
	Mul(p,q,n);
	CLargeInt a(e),b(n);
	Sub(b,p,b);
	Sub(b,q,b);
	Add(b,1,b);

	if( !Coprime(b,e) ) return false;
	//求D的算法,通过辗转相除,最终求得需要的D值。
	CLargeInt k1,c1;
	Div(b,a,k1,c1);
	if( c1._len == 1 && c1._data[0]	== 0 ) return false;
	if( c1._len == 1 && c1._data[0]	== 1 )
	{
		CLargeInt temp;
		Sub(e,1,temp);
		Mul(temp,k1,d);
		Add(d,1,d);
		return true;
	}

	CLargeInt k2,c2,ka2;
	Div(a,c1,k2,c2);
	if( c2._len == 1 && c2._data[0]	== 0 ) return false;
	Mul(k1,k2,ka2);
	Add(ka2,1,ka2);
	if( c2._len == 1 && c2._data[0]	== 1 ) { Copy(ka2,d); return true; }

	CLargeInt k3,c3,ka3;
	Div(c1,c2,k3,c3);
	if( c3._len == 1 && c3._data[0]	== 0 ) return false;
	Mul(k3,ka2,ka3);
	Add(ka3,k1,ka3);
	if( c3._len == 1 && c3._data[0]	== 1 )
	{
		Copy(ka3,d);

		CLargeInt temp,temp1,temp2;
		Mul(d,e,temp);
		Div(temp,b,temp1,temp2);
		Add(temp2,1,temp2);
		if( Equal(temp2,b) )
		{
			Mul(d,d,temp1);
			Div(temp1,b,temp2,d);
			Mul(d,e,temp1);
			Div(temp1,b,temp2,d);
		}
		return true;
	}

	CLargeInt kn_2(k2),cn_2(c2),ka_2(ka2);
	CLargeInt kn_1(k3),cn_1(c3),ka_1(ka3);

	CLargeInt kn,cn,kan;
	do{
		Div(cn_2,cn_1,kn,cn);
		Mul(kn,ka_1,kan);
		Add(kan,ka_2,kan);

		if( cn._len == 1 && cn._data[0]	== 0 ) return false;
		if( cn._len == 1 && cn._data[0]	== 1 )
		{
			Copy(kan,d);

			CLargeInt temp,temp1,temp2;
			Mul(d,e,temp);
			Div(temp,b,temp1,temp2);
			Add(temp2,1,temp2);
			if( Equal(temp2,b) )
			{
				Mul(d,d,temp1);
				Div(temp1,b,temp2,d);
				Mul(d,e,temp1);
				Div(temp1,b,temp2,d);
			}
			return true;
		}
		Copy(kn_1,kn_2);
		Copy(cn_1,cn_2);
		Copy(ka_1,ka_2);

		Copy(kn,kn_1);
		Copy(cn,cn_1);
		Copy(kan,ka_1);
	} while (true);
}

void CLargeInt::RSAEncode( const CLargeInt &n,const CLargeInt &d,const CLargeInt &m,CLargeInt &c)
{
	ExpMod(m,d,n,c);
}

void CLargeInt::RSADecode( const CLargeInt &n,const CLargeInt &e,const CLargeInt &c,CLargeInt &m)
{
	ExpMod(c,e,n,m);
}

string CLargeInt::RSADecode(const char* N, const char* E, const char* I)
{
	CLargeInt o;
	CLargeInt n(N);
	CLargeInt i(I);
	CLargeInt e(E);
	RSADecode(n, e, i, o);
	return o.GetHexStr();
}

string CLargeInt::GetHexStr()
{
	char buffer[128];
	memset(buffer, 0x00, sizeof(buffer));
	string strHex;

	for (int i = _len - 1 ; i >= 0; i--)
	{
		char str[] = "%08X";
		str[2] = '0' + sizeof(T_DWORD) * 2;
		if ( i != (int)(_len - 1) )
		{
			sprintf(buffer, str, _data[i]);
		}
		else
		{
			sprintf(buffer, str, _data[i]);
		}

		strHex += buffer;
	}
	return strHex;
}

typedef	unsigned __int64 ULONGLONG;
inline ULONGLONG GetCycleCount()
{
	__asm RDTSC
}

//#include <windows.h>
void CLargeInt::CreateRandom(CLargeInt &n, T_DWORD bitcount)
{
	n._len = (bitcount + 31) / 32;
	for (T_DWORD i = 0; i <	n._len;	i++)
	{
		T_DWORD	byte[4];

		for (int b = 0;	b < 4; b++)
		{
			for (int j = 0;	j < 4;	j++)
			{
				//Sleep(0);
				j = j + 1 - 1;
			}
			byte[b]	= GetCycleCount() & 0xFF;
		}

		n._data[i] = (byte[0] << 24)
			| (byte[1] << 16)
			| (byte[2] << 8)
			| (byte[3] << 0);
	}
	n._data[0] |= 1;
	n._data[n._len - 1] |= 0x80000000;
	if ((bitcount &	31))
	{
		n._data[n._len - 1] >>=	32 - (bitcount & 31);
	}
}

bool CLargeInt::Coprime(const CLargeInt	&source,const CLargeInt	&target)
{
	CLargeInt m(source),n(target),temp;
	while(true)
	{
		Div(m,n,temp,m);
		if( m._len == 1	&& m._data[0] == 1 ) return true;
		else if( m._len	== 1 &&	m._data[0] == 0	) return false;

		Div(n,m,temp,n);
		if( n._len == 1	&& n._data[0] == 1 ) return true;
		else if( n._len	== 1 &&	n._data[0] == 0	) return false;
	}

}

3.RSA工具

算法系列2——RSA,布布扣,bubuko.com

时间: 2024-10-16 14:08:03

算法系列2——RSA的相关文章

算法系列3——SHA

SHA是一种数据加密算法,该算法经过加密专家多年来的发展和改进已日益完善,现在已成为公认的最安全的散列算法之一,并被广泛使用.该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短.位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程.散列函数值可以说时对明文的一种"指纹"或是"摘要"所以对散列值的数字签名就可以视为对此明文的数字签名. 单向散列函数一般

9.Java 加解密技术系列之 RSA

Java 加解密技术系列之 RSA 序 概念 工作流程 RSA 代码实现 加解密结果 结束语 序 距 离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版.上线,又是新项目太紧,具体的就不多说了,想听我吐槽的小伙伴, 可以私信给我(*^__^*) .上一篇文章,已经把对称加密的算法讲完了.从今天开始,要说说非对称加密了.因为,非对称加密真的是太重要了,我们的日常生活中,都离不开非对称加密. 概念 在说 RSA 之前,首先聊聊什么是非对称加密.在讲对称加密的时候,就曾

算法系列之二十三:离散傅立叶变换之音频播放与频谱显示

算法系列之二十三:离散傅立叶变换之音频播放与频谱显示 算法系列之二十三离散傅立叶变换之音频播放与频谱显示 导语 什么是频谱 1 频谱的原理 2 频谱的选择 3 频谱的计算 显示动态频谱 1 实现方法 2 杂项说明 结果展示 导语 频谱和均衡器,几乎是媒体播放程序的必备物件,没有这两个功能的媒体播放程序会被认为不够专业,现在主流的播放器都具备这两个功能,foobar 2000的十八段均衡器就曾经让很多人着迷.在上一篇对离散傅立叶变换介绍的基础上,本篇就进一步介绍一下频谱是怎么回事儿,下一篇继续介绍

[算法系列之二十]字典树(Trie)

一 概述 又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计. 二 优点 利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高. 三 性质 (1)根节点不包含字符,除根节点外每一个节点都只包含一个字符: (2)从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串: (3)每个节点的所有子节点包含的字符都不相同. 单词列表为"apps&

【白话经典算法系列之十七】 数组中只出现一次的数 其他三次

本文地址:http://blog.csdn.net/morewindows/article/details/12684497转载请标明出处,谢谢. 欢迎关注微博:http://weibo.com/MoreWindows 首先看看题目要求: 数组A中,除了某一个数字x之外,其他数字都出现了三次,而x出现了一次.请给出最快的方法找到x. 这个题目非常有意思,在本人博客中有<位操作基础篇之位操作全面总结>这篇文章介绍了使用位操作的异或来解决——数组中其他数字出现二次,而x出现一次,找出x.有<

三白话经典算法系列 Shell排序实现

山是包插入的精髓排序排序.这种方法,也被称为窄增量排序,因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序. 由于直接插入排序在元素基本有序的情况下(接近最好情况),效率是非常高的,因此希尔排序在时间效率上比前两种方法有较大提高. 以n=10的一个数组49, 38, 65, 97

【转】两种非对称算法原理:RSA和DH

转自:http://blog.chinaunix.net/uid-7550780-id-2611984.html 两种非对称算法原理:RSA和DH 虽然对称算法的效率高,但是密钥的传输需要另外的信道.非对称算法RSA和DH可以解决密钥的传输问题(当然,它们的作用不限于此).这两个算法的名字都是来自于算法作者的缩写,希望有朝一日能够出现用中国人命名的加密算法.非对称算法的根本原理就是单向函数,f(a)=b,但是用b很难得到a. RSA算法 RSA算法是基于大数难于分解的原理.不但可以用于认证,也可

白话经典算法系列之四 直接选择排序及交换二个数据的正确实现

分类: 白话经典算法系列 2011-08-09 11:15 16682人阅读 评论(29) 收藏 举报 算法面试c 直接选择排序和直接插入排序类似,都将数据分为有序区和无序区,所不同的是直接播放排序是将无序区的第一个元素直接插入到有序区以形成一个更大的有序区,而直接选择排序是从无序区选一个最小的元素直接放到有序区的最后. 设数组为a[0…n-1]. 1.      初始时,数组全为无序区为a[0..n-1].令i=0 2.      在无序区a[i…n-1]中选取一个最小的元素,将其与a[i]交

算法系列笔记5(扩展数据结构-动态顺序统计和区间树)

在编程中,我们往往使用已有的数据结构无法解决问题,这是不必要急着创建新的数据结构,而是在已有数据结构的基础上添加新的字段.本节在上一次笔记红黑树这一基础数据结构上进行扩展,得出两个重要的应用-动态顺序统计和区间树. 动态顺序统计 在算法系列笔记2中我们在线性时间内完成了静态表的顺序统计,而这里我们在红黑树上进行扩展,在O(lgn)时间内完成该操作,主要包括返回第i 排名的元素os_select(i)和给定一个元素x,返回其排名(os_rank(x)). 思想:添加新项:在红黑树的结点上记录下该结