KeeLoq算法深入剖析

KeeLoq算法深入剖析

 

请支持原创,尊重原创,转载请注明出处:http://blog.csdn.net/kangweijian(来自kangweijian的csdn博客)

 

1       KeeLoq算法介绍

1.1  KeeLoq运算规则

KeeLoq算法的核心思想就是用8byte密钥加密4byte明文,从而得到4byte密文或者用8byte密钥解密4byte密文,还原出原4byte明文。KeeLoq算法演算过程需要定义一个数据寄存器,用于存放4byte明文y31~0或者4byte密文y31~0,和一个密钥寄存器,用于存放8byte密钥k63~0。

KeeLoq数据加密过程模型图如图1所示,首先定义一个非线性表,这个非线性表有5bits输入码,1bit输出码。它在数据寄存器中间隔均匀地取5bits: y31、y26、y20、y9、y1,通过NLF(Nonlinear Logic Function)运算产生一个输出码。输出码再与数据寄存器中的y16与y0以及密钥寄存器中的k0进行异或运算后生成1bit加密数据码。每生成1bit加密数据码,密钥寄存器和数据寄存器分别进行移位,密钥寄存器作循环移位,加密数据码作为数据寄存器移位的输入,重复上述步骤528次后,得到4byte的输出密文。

NLF(x4,x3,x2,x1,x0)=x4x3x2^x4x3x1^x4x2x0^x4x1x0^x4x2^x4x0^x3x2^x3x0^x2x1^x1x0^x1^x0

图1  KeeLoq加密模型图

KeeLoq数据解密模型图如图2所示,其过程的运算方法与数据加密过程的运算方法基本一致,只是其中运算数据数据位发生变化。非线性表的5bits输入码改成从数据寄存器中间隔均匀地取固定5bits:y30、y25、y19、y8、y0。产生1bit输出码后输出码再与数据寄存器中的y31与y15以及密钥寄存器中的k15进行异或运算后生成1bit解密数据码。每输出1bit解密数据码后,密钥寄存器和数据寄存器分别进行移位,密钥寄存器作循环移位,解密数据码作为数据寄存器移位的输入,重复上述步骤528次后,还原出4byte的明文。

图2  KeeLoq解密模型图

1.2   KeeLoq实现机制

采用KeeLoq方法实现数据编码和解码,其通信过程需严格按照下述过程进行。首先,要求编码端和解码端都需要有非易失性存储空间以存储8byte密钥(用于编解码,可编程且不被发送不可泄露)、3byte序列号(用于区分不同的编码端)、2byte同步计数值(用于产生编码滚动效果,每完成一次数据传送后,其值自加1后更新)、1byte识别码(序列号的低1byte)和4byte种子码(安全模式下用来生成密钥)。

当用户有按键操作时,KeeLoq编码端将1byte功能键、1byte识别码、2byte同步计数值组合成4byte明文,按照图1的NLF运算规则加密成4byte密文,再加上4byte固定码(3byte序列号、1byte功能键),组合成一组8byte的编码数据发送。由于每次发送过程,同步计数值自加1,使得每次发送的4byte密文都是惟一的、不规则的、且不重复,故称之为滚动码,可以有效的防止密码捕捉和密码拷贝。由于8byte的编码组合达到2^64=1.84*10^19,因而可以有效的防止密码扫描。

解码端接收到8byte密文数据后,首先匹配编码端和解码段的3byte序列号一致后,按照图2的KeeLoq解码运算规则还原出4byte明文。再校验明文中的识别码以及功能键正确后,最后判断同步计数值是否合理增加。确认成功后根据功能键定义,控制相应执行机构动作。

2     KeeLoq算法不足与改进

2.1 KeeLoq算法的安全性与不足

KeeLoq算法的NLF运算规则,使得一个很小的输入变化量,也会造成很大的输出变化量,产生的编码滚动效果。密码分析者就无法通过输入微小的变化来观察分析输出的变化,从而破解出密钥,使得KeeLoq算法具有安全性高特点。

虽然KeeLoq算法发布于20世纪80年代,但直到2007年,Bogdanov才首次对KeeLoq算法进行攻击,他使用猜测-决定和滑动技术来完成攻击,攻击的时间复杂度为252,空间复杂度为16GB。在2008年,Courtois等人提出了4种滑动-代数攻击方法,其主要思想是利用KeeLoq算法连续64圈圈函数形成的置换和圈结构与随机置换圈结构的差异,先攻击密钥的前16bits,再攻击剩余的48bits。折合计算复杂性至少约为O(2^43)次加密。2010年,游建雄等人提出3 种不同采用面向字节的差分故障攻击方法,其中攻击效率最好的方法,恢复1
bit 密钥信息平均只需要0. 707617 个错误,恢复8byte的密钥只需要46个错误。

虽然KeeLoq算法发布后至今已经取得很多有效的攻击,大大降低了计算时间复杂度,但是也增加了计算空间复杂度,并且需要一定数量的已知前提。导致在实际密码破解过程中难度系数高,故其安全性足以保证,在实际应用当中有着广泛应用。

2.2   KeeLoq算法的改进

KeeLoq加密算法是4byte的分组密码,密钥长度较短,仅为8byte。算法发布至今已有相关文献报导取得有效攻击,针对这一现状及上述算法不足之处,为了进一步提高 KeeLoq算法安全性,本文分别对编解码过程及密钥管理进行改进。

2.2.1       编解码过程的改进

首先,编解码过程借鉴了三重数据加密算法(3DES,Triple Data Encryption Algorithm),提出三重KeeLoq算法。即采用三个不同密钥分别对明文、第一次获得密文及第二次获得密文进行KeeLoq加密后,生成最终密文。解密过程则是,先用第三个密钥对最终密文解密得到第二次密文,用第二个密钥对第二次密文解密得到第一次密文,最后用第一个密钥对第一次密文解密得到原始明文。该过程是KeeLoq算法的一种更安全的变形,通过增加KeeLoq的密钥长度来提高针对KeeLoq攻击的时间复杂度和计算复杂度,以进一步提高其安全性。

2.2.2       KeeLoq密钥管理机制的改进

以Microchip的KeeLoq密钥管理机制为例。Microchip定义了一套学习模式来管理密钥。学习模式目的是为了编码端与解码端进行配对。在学习过程中,首先按下学习按键之后,解码端解码密文后,校验功能键和识别码正确后,就将该编码端的同步计数值和序列号存到自身的非易失性存储空间,这样就表示学习成功。学习成功之后,编码端才能与解码端正常通信。

Microchip总共提出了三种学习模式(密钥管理机制)。第一种:简易学习模式。简易学习模式无法修改密钥,一旦密钥泄露,后果无法挽回。

第二种:标准学习模式。标准学习模式在学习过程中可同时按下全部或多个功能按钮,则该模式将原始密钥和编码端的序列号通过某种算法生成新的密钥,解码端接收到密文后,通过原始密钥解密不正确之后,就会尝试用原始密钥+序列号生成新的密钥来解密密文,一旦解密成功,解码端就会在自身的非易失性存储空间内将密钥更改掉。很明显,标准学习模式的安全性就比简易学习模式高了许多,原始密钥和序列号同时泄漏的难度明显比单单仅原始密钥泄漏的难度高了多。

第三种:安全学习模式。安全学习模式比标准学习模式多了一个种子码,学习过程与标准模式差不多,差别仅在于标准模式生成新密钥的方式是:原始密钥+序列号。而安全学习模式是:原始密钥+种子码+序列号通过某种算法生成新的密钥。

三种学习模式,其安全性一层比一层高。简易学习模式的安全性完全依赖于密钥不丢失,标准学习模式的安全性依赖于密钥和序列号不同时丢失,安全学习模式的安全性依赖于密钥、种子码和序列号不同时丢失。当然了生成新密钥的算法也不能丢失。

说到这里,我们再说说密钥管理机制的改进,其实有很多种。比如我们可以有一个手动输入的种子码让其放于固定码中发送出去,这样就如我们QQ或者Google帐号被盗窃后,直接手动修改密码那般惬意。或者如果无法做到手动修改,我们可以做一个随机生成器,随机生成一个种子码,这样完全不必担心种子码在哪个环节会泄漏,因为我们自己都不知道种子码会是多少。密钥管理机制的改进就取决于KeeLoq算法的应用环境中。凡事没有尽善尽美,但是我们可以做出哪怕一点点的进步。

附KeeLoq算法源码

源码一:KeeLoq.c (32位处理器)

#include<iostream>
#include<stdio.h>
using namespace std;
unsigned long long int SERX=0xefcdab2143658709;
unsigned long long int key=0xefcdab2143658709;
unsigned int HOPE;
unsigned int c=0;
int NLF[2][2][2][2][2];
int  getBit(unsigned long long int source,int n) {
	unsigned long long int temp0=((long long int) 1<<n);
	unsigned long long int temp1=source&temp0;
	if ( temp1 != 0) {
		return 1;
	}
	return 0;
}
void RrcHOPE(){
	if(c!=0){
		HOPE=(HOPE>>1)|0x80000000;
	}else{
		HOPE=(HOPE>>1)&0x7fffffff;
	}
}
void RlcHOPE(){
	if(c!=0){
		HOPE=(HOPE<<1)|1;
	}else{
		HOPE=(HOPE<<1)&0xFFFFFFFE;
	}
} 

void CRYPT() {
	//key=SERX;
	for (int i = 0; i < 528; i++) {
		int nlf=NLF[getBit(HOPE, 31)][getBit(HOPE, 26)][getBit(HOPE, 20)][getBit(HOPE, 9)][getBit(HOPE, 1)];
		int y16=getBit(HOPE, 16);
		int y0=getBit(HOPE, 0);
		int k=getBit(key, i%64);
		int result=nlf^y16^y0^k;
		if (result!=0) {
			c=1;
		}else {
			c=0;
		}

		RrcHOPE();
	}
}

void DECRYPT() {
	key=SERX;
	for (int i = 528; i >0; i--) {
		int nlf=NLF[getBit(HOPE, 30)][getBit(HOPE, 25)][getBit(HOPE, 19)][getBit(HOPE, 8)][getBit(HOPE, 0)];
		int y15=getBit(HOPE, 15);
		int y31=getBit(HOPE, 31);
		int k=getBit(key, (i-1)%64);
		int result=nlf^y15^y31^k;
		if (result!=0) {
			c=1;
		}else {
			c=0;
		}
		//printf("step %d : %x  %x %x %x %x %x\n",i,HOPE,nlf,y15,y31,k,result);
		RlcHOPE();
	}
}

int main(){
	NLF[0][0][0][0][0]=0;
	NLF[0][0][0][0][1]=1;
	NLF[0][0][0][1][0]=1;
	NLF[0][0][0][1][1]=1;
	NLF[0][0][1][0][0]=0;
	NLF[0][0][1][0][1]=1;
	NLF[0][0][1][1][0]=0;
	NLF[0][0][1][1][1]=0;

	NLF[0][1][0][0][0]=0;
	NLF[0][1][0][0][1]=0;
	NLF[0][1][0][1][0]=1;
	NLF[0][1][0][1][1]=0;
	NLF[0][1][1][0][0]=1;
	NLF[0][1][1][0][1]=1;
	NLF[0][1][1][1][0]=1;
	NLF[0][1][1][1][1]=0;

	NLF[1][0][0][0][0]=0;
	NLF[1][0][0][0][1]=0;
	NLF[1][0][0][1][0]=1;
	NLF[1][0][0][1][1]=1;
	NLF[1][0][1][0][0]=1;
	NLF[1][0][1][0][1]=0;
	NLF[1][0][1][1][0]=1;
	NLF[1][0][1][1][1]=0;

	NLF[1][1][0][0][0]=0;
	NLF[1][1][0][0][1]=1;
	NLF[1][1][0][1][0]=0;
	NLF[1][1][0][1][1]=1;
	NLF[1][1][1][0][0]=1;
	NLF[1][1][1][0][1]=1;
	NLF[1][1][1][1][0]=0;
	NLF[1][1][1][1][1]=0;

	while(1){
		scanf("%x",&HOPE);
		CRYPT();
		printf("%x\n",HOPE);
		DECRYPT();
		printf("%x\n",HOPE);

	}
	return 0;
}

源码二:KeeLoq.h+KeeLoq.c(8位微机)

unsigned char SERX[]={0XEF,0XCD,0XAB,0X21,0X43,0X65,0X87,0X09};
unsigned char key[]={0X09,0X87,0X65,0X43,0X21,0XAB,0XCD,0XEF};
unsigned char NLF[2][2][2][2][2]; 

unsigned char getBit(unsigned char source[],int n);
unsigned char * RRC(unsigned char source[],char c,char n);
unsigned char * RLC(unsigned char source[],char c,char n);
unsigned char * CRYPT(unsigned char *source);
unsigned char *  DECRYPT(unsigned char *source);
void init();
#include<stdio.h>
#include"KeeLoq.h"

/*****************************
 *
 * @param source
 * @param n
 * @return source的第n个位数
 *
******************************/
unsigned char getBit(unsigned char source[],int n)
{
	unsigned char temp0=(unsigned char)1<<(n%8);
	unsigned char temp1=source[n/8]&temp0;
	if(temp1!=0)
	{
		return 1;
	}
	return 0;
}

/***********************
 *
 * @param source[]
 * @param c 进位标志位
 * @param n 数组长度
 * @return source数组带进位右移
 *
***********************/
unsigned char * RRC(unsigned char source[],char c,char n)
{
	int i=0;
	unsigned char temp;
	for(i=n-1;i>=0;i--)
	{
		temp=source[i];
		if(c!=0){
			source[i]=(source[i]>>1)|0x80;
		}else{
			source[i]=(source[i]>>1)&0x7f;
		}

		if(temp&0x01!=0){
			c=1;
		}else{
			c=0;
		}
	}
	return source;
} 

/*********************************
 *
 * @param source[]
 * @param c 进位标志位
 * @param n 数组长度
 * @return source数组带进位左移
 *
*********************************/
unsigned char * RLC(unsigned char source[],char c,char n)
{
	int i=0;
	unsigned char temp;
	for(i=0;i<n;i++)
	{
		temp=source[i];
		if(c!=0){
			source[i]=(source[i]<<1)|0x01;
		}else{
			source[i]=(source[i]<<1)&0xfe;
		}

		if((temp&0x80)!=0){
			c=1;
		}else{
			c=0;
		}
	}
	return source;
} 

/*************************************
 *
 * @param source
 * @return source明文经过KeeLoq加密后的密文
 *
*************************************/
unsigned char * CRYPT(unsigned char *source)
{
	int i=0;
	unsigned char c=0;
	unsigned char nlf,y16,y0,k,result;
	init();
	for (i = 0; i < 528; i++)
	{
		nlf=NLF[getBit(source, 31)][getBit(source, 26)][getBit(source, 20)][getBit(source, 9)][getBit(source, 1)];
		y16=getBit(source, 16);
		y0=getBit(source, 0);
		k=getBit(key, i%64);
		result=nlf^y16^y0^k;
		if (result!=0) {
			c=1;
		}else {
			c=0;
		}
		source=RRC(source,c,4);
	}
	return source;
}

/*************************************
 *
 * @param source
 * @return source密文经过KeeLoq解密后的明文
 *
*************************************/
unsigned char *  DECRYPT(unsigned char *source)
{
	int i=0;
	unsigned char c=0;
	unsigned char nlf,y15,y31,k,result;
	init();
	for (i = 528; i >0; i--)
	{
		nlf=NLF[getBit(source, 30)][getBit(source, 25)][getBit(source, 19)][getBit(source, 8)][getBit(source, 0)];
		y15=getBit(source, 15);
		y31=getBit(source, 31);
		k=getBit(key, (i-1)%64);
		result=nlf^y15^y31^k;
		if (result!=0) {
			c=1;
		}else {
			c=0;
		}
		source=RLC(source,c,4);
	}
	return source;
}

/*************************************
 *
 *  初始化非线性逻辑函数的值
 *
*************************************/
void init()
{
	NLF[0][0][0][0][0]=0;
	NLF[0][0][0][0][1]=1;
	NLF[0][0][0][1][0]=1;
	NLF[0][0][0][1][1]=1;
	NLF[0][0][1][0][0]=0;
	NLF[0][0][1][0][1]=1;
	NLF[0][0][1][1][0]=0;
	NLF[0][0][1][1][1]=0;

	NLF[0][1][0][0][0]=0;
	NLF[0][1][0][0][1]=0;
	NLF[0][1][0][1][0]=1;
	NLF[0][1][0][1][1]=0;
	NLF[0][1][1][0][0]=1;
	NLF[0][1][1][0][1]=1;
	NLF[0][1][1][1][0]=1;
	NLF[0][1][1][1][1]=0;

	NLF[1][0][0][0][0]=0;
	NLF[1][0][0][0][1]=0;
	NLF[1][0][0][1][0]=1;
	NLF[1][0][0][1][1]=1;
	NLF[1][0][1][0][0]=1;
	NLF[1][0][1][0][1]=0;
	NLF[1][0][1][1][0]=1;
	NLF[1][0][1][1][1]=0;

	NLF[1][1][0][0][0]=0;
	NLF[1][1][0][0][1]=1;
	NLF[1][1][0][1][0]=0;
	NLF[1][1][0][1][1]=1;
	NLF[1][1][1][0][0]=1;
	NLF[1][1][1][0][1]=1;
	NLF[1][1][1][1][0]=0;
	NLF[1][1][1][1][1]=0;
}             

int main()
{
	unsigned char source[4];
	unsigned char *p;
	scanf("%c %c %c %c",&source[3],&source[2],&source[1],&source[0]); 

	p=source;

	printf("%x %x %x %x\n",p[3],p[2],p[1],p[0]);  

	p=CRYPT(p);

	printf("%x %x %x %x\n",p[3],p[2],p[1],p[0]);  

	p=DECRYPT(p);

	printf("%x %x %x %x",p[3],p[2],p[1],p[0]);

	return 0;
}

源码三:KeeLoqCrypt.java

import java.util.Scanner;

public class KeeLoqCrypt {

	/**
	 * @param args
	 */
	private static long SERX=0xefcdab2143658709L;
	private static long key=0Xefcdab2143658709L;
	private static int NLF[][][][][]=new int[2][2][2][2][2];

	/*********
	 * 构造函数
	 */
	KeeLoqCrypt(){
		NLF[0][0][0][0][0]=0;
		NLF[0][0][0][0][1]=1;
		NLF[0][0][0][1][0]=1;
		NLF[0][0][0][1][1]=1;
		NLF[0][0][1][0][0]=0;
		NLF[0][0][1][0][1]=1;
		NLF[0][0][1][1][0]=0;
		NLF[0][0][1][1][1]=0;

		NLF[0][1][0][0][0]=0;
		NLF[0][1][0][0][1]=0;
		NLF[0][1][0][1][0]=1;
		NLF[0][1][0][1][1]=0;
		NLF[0][1][1][0][0]=1;
		NLF[0][1][1][0][1]=1;
		NLF[0][1][1][1][0]=1;
		NLF[0][1][1][1][1]=0;

		NLF[1][0][0][0][0]=0;
		NLF[1][0][0][0][1]=0;
		NLF[1][0][0][1][0]=1;
		NLF[1][0][0][1][1]=1;
		NLF[1][0][1][0][0]=1;
		NLF[1][0][1][0][1]=0;
		NLF[1][0][1][1][0]=1;
		NLF[1][0][1][1][1]=0;

		NLF[1][1][0][0][0]=0;
		NLF[1][1][0][0][1]=1;
		NLF[1][1][0][1][0]=0;
		NLF[1][1][0][1][1]=1;
		NLF[1][1][1][0][0]=1;
		NLF[1][1][1][0][1]=1;
		NLF[1][1][1][1][0]=0;
		NLF[1][1][1][1][1]=0;
	}

	/*****************
	 *
	 * @param source
	 * @param n
	 * @return source的第n个位数
	 */
	private static int  getBit(long source,int n) {
		long temp0=((long) 1<<n);
		long temp1=source&temp0;
		if ( temp1 != 0) {
			return 1;
		}
		return 0;
	}

	/****************
	 *
	 * @param soucre
	 * @param c
	 * @return 带进位右移
	 */
	private static int RRC(int soucre,int c){
		if(c!=0){
			soucre=(soucre>>1)|0x80000000;
		}else{
			soucre=(soucre>>1)&0x7fffffff;
		}
		return soucre;
	} 

	/********************
	 *
	 * @param source
	 * @param c
	 * @return 带进位左移
	 */
	private static int RLC(int source, int c){
		if(c!=0){
			source=(source<<1)|1;
		}else{
			source=(source<<1)&0xFFFFFFFE;
		}
		return source;
	} 

	/********************
	 *
	 * @param source
	 * @param key
	 * @return source经过key密钥进行KeeLoq加密后的数据
	 */
	private static int CRYPT(int source , long key) {
		long mKey=key;
		int c;
		for (int i = 0; i < 528; i++) {
			int nlf=NLF[getBit(source, 31)][getBit(source, 26)][getBit(source, 20)][getBit(source, 9)][getBit(source, 1)];
			int y16=getBit(source, 16);
			int y0=getBit(source, 0);
			int k=getBit(mKey, i%64);
			int result=nlf^y16^y0^k;
			if (result!=0) {
				c=1;
			}else {
				c=0;
			}
			source=RRC(source,c);
		}
		return source;
	}

	/*********************************
	 *
	 * @param source
	 * @param key
	 * @return source经过key密钥进行KeeLoq解密后的数据
	 */
	private static int DECRYPT(int source , long key) {
		long mkey=key;
		int c;
		for (int i = 528; i >0; i--) {
			int nlf=NLF[getBit(source, 30)][getBit(source, 25)][getBit(source, 19)][getBit(source, 8)][getBit(source, 0)];
			int y15=getBit(source, 15);
			int y31=getBit(source, 31);
			int k=getBit(mkey, (i-1)%64);
			int result=nlf^y15^y31^k;
			if (result!=0) {
				c=1;
			}else {
				c=0;
			}
			source=RLC(source,c);
		}
		return source;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		NLF[0][0][0][0][0]=0;
		NLF[0][0][0][0][1]=1;
		NLF[0][0][0][1][0]=1;
		NLF[0][0][0][1][1]=1;
		NLF[0][0][1][0][0]=0;
		NLF[0][0][1][0][1]=1;
		NLF[0][0][1][1][0]=0;
		NLF[0][0][1][1][1]=0;

		NLF[0][1][0][0][0]=0;
		NLF[0][1][0][0][1]=0;
		NLF[0][1][0][1][0]=1;
		NLF[0][1][0][1][1]=0;
		NLF[0][1][1][0][0]=1;
		NLF[0][1][1][0][1]=1;
		NLF[0][1][1][1][0]=1;
		NLF[0][1][1][1][1]=0;

		NLF[1][0][0][0][0]=0;
		NLF[1][0][0][0][1]=0;
		NLF[1][0][0][1][0]=1;
		NLF[1][0][0][1][1]=1;
		NLF[1][0][1][0][0]=1;
		NLF[1][0][1][0][1]=0;
		NLF[1][0][1][1][0]=1;
		NLF[1][0][1][1][1]=0;

		NLF[1][1][0][0][0]=0;
		NLF[1][1][0][0][1]=1;
		NLF[1][1][0][1][0]=0;
		NLF[1][1][0][1][1]=1;
		NLF[1][1][1][0][0]=1;
		NLF[1][1][1][0][1]=1;
		NLF[1][1][1][1][0]=0;
		NLF[1][1][1][1][1]=0; 

		Scanner mScanner=new Scanner(System.in);
		int HOPE=mScanner.nextInt(16);
		System.out.printf("%x\n",CRYPT(HOPE,key));
		System.out.printf("%x\n",DECRYPT(CRYPT(HOPE,key),key));
		System.out.printf("%x\n",getBit(HOPE,1));
	}

}

请支持原创,尊重原创,转载请注明出处:http://blog.csdn.net/kangweijian(来自kangweijian的csdn博客)

by 2015.2.4晚

时间: 2024-10-10 08:14:41

KeeLoq算法深入剖析的相关文章

Mahout机器学习平台之聚类算法详细剖析(含实例分析)

第一部分: 学习Mahout必须要知道的资料查找技能: 学会查官方帮助文档: 解压用于安装文件(mahout-distribution-0.6.tar.gz),找到如下位置,我将该文件解压到win7的G盘mahout文件夹下,路径如下所示: G:\mahout\mahout-distribution-0.6\docs 学会查源代码的注释文档: 方案一:用maven创建一个mahout的开发环境(我用的是win7,eclipse作为集成开发环境,之后在Maven Dependencies中找到相应

stl算法:next_permutation剖析

在标准库算法中,next_permutation应用在数列操作上比较广泛.这个函数可以计算一组数据的全排列.但是怎么用,原理如何,我做了简单的剖析. 首先查看stl中相关信息.函数原型: template<class BidirectionalIterator>   bool next_permutation(      BidirectionalIterator _First,       BidirectionalIterator _Last   );template<class B

数据结构与算法简记--剖析微服务接口鉴权限流背后的数据结构和算法

微服务鉴权限流剖析 微服务 把复杂的大应用,解耦拆分成几个小的应用. 有利于团队组织架构的拆分,毕竟团队越大协作的难度越大: 每个应用都可以独立运维,独立扩容,独立上线,各个应用之间互不影响. 有利就有弊: 大应用拆分成微服务之后,服务之间的调用关系变得更复杂,平台的整体复杂熵升高,出错的概率.debug 问题的难度都高了好几个数量级. 为了解决这些问题,服务治理便成了微服务的一个技术重点. 服务治理 简单点讲,就是管理微服务,保证平台整体正常.平稳地运行. 涉及的内容:鉴权.限流.降级.熔断.

2014总结2015展望

2014总结2015展望 明天就大年三十了,这一年已经走到了尽头,下一年即将到来.回首这一年,时光太匆匆,我的脚步亦匆匆.顺着时光轴,我来慢慢总结我这一年.这一年总的可以分为三个篇章:学习比赛篇.生活泡妞篇.找工作篇. 学习比赛篇: 大学中的知识大部分是自己在实验实践中自学而得,只有很少的一部分知识是在课堂上学得.我的学习大部分在比赛中,2014年这一年我参加过四个大型比赛. 首先开始比较早的是蓝桥杯软件设计大赛,编程类竞赛,整个寒假都一半的时间在准备它.天天编程刷题.一个寒假在家20天左右的时

STL源码剖析——算法之set集合算法

前言 本节介绍set集合的相关算法,分别是并集set_union,差集set_difference,交集set_intersection 和对称差集set_symmetric_difference,这是个函数都提供了两个版本的函数原型:第一个版本是采用默认的排序比较方式operator<:第二个版本是用户通过仿函数comp自行指定排序方式.注意:这四个算法接受的输入区间都是有序的,输出也是有序的.下面对set算法进行剖析,具体注释详见源码,同时给出例子说明该算法的功能.本文源码摘自SGI STL

STL源代码剖析——STL算法之set集合算法

前言 本节介绍set集合的相关算法,各自是并集set_union,差集set_difference,交集set_intersection 和对称差集set_symmetric_difference.这是个函数都提供了两个版本号的函数原型:第一个版本号是採用默认的排序比較方式operator<:第二个版本号是用户通过仿函数comp自行指定排序方式.注意:这四个算法接受的输入区间都是有序的,输出也是有序的. 以下对set算法进行剖析,详细凝视详见源代码,同一时候给出样例说明该算法的功能.本文源代码摘

自然语言处理之维特比算法

刘勇  Email:[email protected] 简介 鉴于维特比算法可解决多步骤中每步多选择模型的最优选择问题,本文简要介绍了维特比算法的基本理论,并从源代码角度对维特比算法进行剖析,并对源码中涉及的要点进行了解读,以便能快速应用该算法解决自然语言处理中的问题. 理论 维特比算法是一个特殊但应用最广的动态规划算法,利用动态规划,可以解决任何一个图中的最短路径问题.而维特比算法是针对一个特殊的图--篱笆网络的有向图(Lattice )的最短路径问题而提出的. 凡是使用隐含马尔可夫模型描述的

第03章 服务器细性能剖析

如何确认服务器达到了最佳性能状态,找出某条语句为什么执行不够快,找到服务器卡顿的问题 1 性能优化 性能测试并不会降低cpu利用率.而应该是测试应用大多数的时间花费在哪里,对这部分进行优化. 优化任务的执行时间,应该测试定位不同的子任务花费的时间,然后通过: 优化花费时间多的子任务 降低子任务的执行频率 2 性能剖析 1.1 通过性能剖析优化 性能剖析是测量和分析任务的时间花费在哪里的主要办法,通常步骤为: 测试任务所花费的时间 对结果进行统计和排序,将重要的任务排到前面 在任务开始时启动计时器

无尽虚拟城市来了!Demo可走可飞,“波函数坍缩”开源算法蹿红

神说,要有光. 于是有了光. 神说,要有一座城. 于是有了一座城. 神说,这座城要无限大. 神啊你别再说了,那是另外的价钱. 不过,有种叫做波函数坍缩 (Wave Collapse Function) 的算法,可以让一座白茫茫的城,在虚拟世界里无限延伸. 你跑得再快,飞得再远,都到不了它的尽头. 因为,这座城可以实时扩张,你往哪里走,它就往哪里生成,不会让你跑出去的. 而它背后的波函数坍缩 (WFC) 算法自诞生以来,每隔一段时日,便会引起人类蜂拥而至的关注. 不管是因为这赏心悦目的应用: 还是