Top Page�^ AES�� top�^

intel SSE2����(SIMD)�ɂ��AES�Í������@��������������

�����v���O����

aes_c.zip�@�c�@Visual C++�݂̂ŏ��������B
�|���Z��SubByte()�𓯎��ɍs���B

���Ȃ݂ɁAVisual C++.net 2008 Express Edition�ł́A�b�����SSE2���߂̍œK���͓��ǂ��Ȃ������ł��B
�b�o�t�̖��߃f�R�[�h�̌��������l�������߂̕��בւ��ʂ͂��Ă���܂����A��������������A�N�Z�X�������đ������������Ă��܂��B
�֐����I��閈�ɁA���Z���ʂ�xmm���W�X�^���烁�����Ɋi�[���ČĂяo�����ɓn���āA �Ăяo�����ł��̃���������ǂݍ����xmm���W�X�^�ɑ������Ƃ��A����Ȗ��ʂȎ������\����Ă��܂��B
�Ƃɂ����A�������A�N�Z�X�������œK���ɂȂ��Ă��܂����B
�ȉ��A�A�Z���u������ŏ��������̂́A���̂悤�Ȗ��ʂ�r�����A�����Ă��܂��B

aes_asm.zip�@�c�@�A�Z���u������ŏ����āA��荂���������݂����B
�S�́i�Í��E�����j�ɋ��ʂ��Ď{�����œK���͈ȉ��̒ʂ�ł��B

  • ���Z�͋ɗ̓��W�X�^�[�ōς܂����Ń������A�N�Z�X�����炵�A�L���b�V���~�X�ɂ��y�i���e�B�[�̃��X�N��ጸ�����i��Z�̃e�[�u���Q�Ƃ������j�B
  • ����������ɗ͌��炵�A����\���~�X�ɂ��y�i���e�B�[�̃��X�N��ጸ�����B

���̑��A�Í����ɂ����ẮA�K���A��GF(28)�̏�Z��SubByte()�𓯎��ɍs���e�[�u���ɒu�������܂����B ���̂��߁A�K���A��GF(28)�̏�Z���[�`���̌Ăяo���͖����Ȃ�܂������A�e�[�u���Q�Ɓi�‚܂胁�����ǂݍ��݁j�͑����Ă��܂��B
�����̃A���S���Y�����œK��������@�͎v�������т܂���ł����B InvSubByte()��InvAddRound()�̏��Ԃ͓���ւ���Ȃ��̂ŁB

SSE���߂ŁA�X�ɍ����������@�����邩������܂���B���������C�t������������܂�����A�����Ē�����Ɗ������ł��B

��������

�ȉ��A�W[MByte]�̈Í��E�����ɗv�����N���b�N���̑�܂��Ȍv�����ʂł��B
�b����ŏ��������́A�A�Z���u������ŏ��������́A�����SSE2�ɂ��x�N�g�������Ȃ���Ă��܂��B
���AVisual C++.net�̃v���W�F�N�g���ł́A�R���p�C���I�v�V���������s���x�ōœK������悤�ɐݒ肵�Ă���܂��B

Intel(R) Celeron(R) M CPU 430 @ 1.73GHz
(Windows XP (32bit) / Memory 760MByte)
�v���O���� �� ����
�b���� �� 1,848 Mclk
�i�� 1,643 Mclk �c ���j
�� 2,943 Mclk
�A�Z���u�������� 1,282 Mclk �c �� �� 1,774 Mclk
���K���A��GF(28)�̏�Z��SubByte()�u�����A�����ɍs���e�[�u���u���ɒu�������B

�Z�������ł́A�Í��E�������ɃA�Z���u������ɂ����ʂ��o�Ă���B
�Í��́A�K���A��GF(28)�̏�Z���[�`���̌Ăяo����r���������ɂ����ʂ��傫���B
�����ł̓K���A��GF(28)�̏�Z���[�`�����Ăяo���Ă��邪�A����ȏ�ɃA�Z���u������ɂ�鍂�����������Ă���B

Intel(R) Core(TM)2 Quad CPU Q9450 @ 2.66GHz
(Windows 7 (32bit) / Memory 4GByte)
�v���O���� �� ����
�b���� �� 973 Mclk �� 1,532 Mclk
�A�Z���u�������� 986 Mclk �c �� �� 1,048 Mclk
���K���A��GF(28)�̏�Z��SubByte()�u�����A�����ɍs���e�[�u���u���ɒu�������B

Core2 Quad�ł́A�Í��͋t�Ɏ኱�x���Ȃ��Ă���B
�A�Z���u������ɂ�鍂�����ɁA�e�[�u���Q�Ɓi�������ǂݍ��݁j�̒x�����������������Ă���Ǝv����B
�����́A�b����ŏ��������̂Ƃقړ����A���S���Y���ł��邪�A�A�Z���u������ɂ�鍂�����������Ă���B
Core2 Quad�̗l�ɓ��쑬�x�������b�o�t�ɂ����ẮA�������ǂݍ��݂��s���e�[�u���Q�Ƃ����A �K���A��GF(28)�̏�Z���v�Z���Ă��܂������A�X�ɍ������������߂邩������Ȃ��B

�����̎����ł̌v�����ʂ́A�t�@�C���A�N�Z�X�̎��ԁA�Í��������̎��Ԃ��܂݂܂���B

�b����Ńv���O�����R�[�h�̐���

���X�P�W���[���̐���

���X�P�W���[���̐����ɂ‚��ẮASSE2���߂�p�����x�N�g�����͎v�������΂Ȃ������B
�Ȃ̂ŁA���X�P�W���[���̐������@�́A�ʓr"�A"fips-197"���Q�Ƃ��Ă��炢�����B
������������A�ǂ����@������̂�������Ȃ��B
�Ƃ肠�����A�b++�ɂ��\�[�X���ȉ��ɏ����Ă����B


//==============================================================
//		fips-197	5.2	Key Expansion
//--------------------------------------------------------------
//	������
//		char			cNK	= 4(0100)	: 128bit AES
//						= 6(0110)	: 192bit AES
//						= 8(1000)	: 256bit AES
//		const unsigned char	Key[]			: Cipher Key
//	���Ԓl
//		����
//==============================================================
void	AES::KeyExpansion(char cNk, const unsigned char *key)
{
	//The round constant word array.
	static	const	unsigned	int	Rcon[10]={
		0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36};

	unsigned	int	i;
				int	iR;
				int	iRm;
				int	temp;

	Nk	= cNk & 0xFE;
	Nr	= Nk + 6;

	//�����������R�s�[
	i	= 0;
	do{
		_mm_storel_epi64((__m128i*)&w[i], _mm_loadl_epi64((__m128i*)&key[i*4]));
		i++;
		i++;
	} while (i < Nk);

	i		= Nk;
	temp	= w[i-1];
	do{
		iR	= i/Nk;
		iRm	= i%Nk;		//����Z���߂��Q�“f���ܑ͖̖̂����B

		if(iRm==0){
			temp = SubWord(RotWord(temp)) ^ Rcon[(iR)-1];
		} else if((Nk > 6) && ( (i%Nk) == 4)){
			temp = SubWord(temp);
		}
		temp	^= w[i-Nk];
		w[i]	 = temp;

		i++;

	} while (i < Nb * (Nr+1));
}

RotWord()

�R�����g�A�E�g�ɂ������Ă��邪�A4Byte�P�ʂ̉�]�̓A�Z���u�������ror���߂��g���ƌ������ǂ��A
�œK���ɂ����ror ���߂ɂȂ�悤�ɁA�\�[�X�������Ƒ����Ȃ�B


//==============================================================
//		fips-197	5.2	RotWord()
//--------------------------------------------------------------
//	������
//			unsigned int data	4Byte�̐��l
//	���Ԓl
//			unsigned int		ror data,8 �̌���
//==============================================================
unsigned	int	AES::RotWord(unsigned int data)
{
	return( (data>>8) | (data<<24) );		//�‚܂�	ror data,8
}

SubWord()

Sbox���̃e�[�u���u���́A�ǂ����悤���Ȃ��Ǝv���B
�������Ȃ���A4Byte�A���C�����g����Ă��Ȃ��������ǂݍ��݂ɂ̓y�i���e�B�[������̂ŁA
�w�ϊ����悤�Ƃ���f�[�^4Byte�͓����Ƀ���������ǂݍ��ށx�R�[�h�ɍœK�������l�ɁA�\�[�X�������B
"static const unsigned char Sbox[256]"�� "static const unsigned int Sbox[256]"�ɏ��������ƁA�܂������Ȃ邩������Ȃ��B
���ACPU����1���L���b�V���ɗ��߂����Ă������߂ɁA�e�[�u���̃T�C�Y�͏����������ǂ���������Ȃ��B

���̊֐��́A�Í����̍ۂɂ��Ă΂��B


//==============================================================
//		fips-197	5.2	Sbox()	(4Byte������)
//--------------------------------------------------------------
//	������
//			unsigned int	data	4Byte�̐��l
//	���Ԓl
//			unsigned int		SBox�K�p��
//==============================================================
unsigned	int	AES::SubWord(unsigned int data)
{
//	fips-197	Figure 7
static	const	unsigned	char	Sbox[256]={
	0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
	0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
	0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
	0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
	0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
	0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
	0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
	0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
	0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
	0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
	0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
	0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
	0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
	0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
	0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
	0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
	};

	//�e�[�u���ϊ��Ɋւ���SIMD���߂͖����H
	unsigned	char	a0	= Sbox[(data    ) & 0xFF];
	unsigned	char	a1	= Sbox[(data>>8 ) & 0xFF];
	unsigned	char	a2	= Sbox[(data>>16) & 0xFF];
	unsigned	char	a3	= Sbox[(data>>24)];

	return(a0 | a1<<8 | a2<<16 | a3<<24);
}

InvSubWord()

���SubWord()�֐��̋t�ϊ���������́B
���̊֐��́A�����̍ۂɌĂ΂����̂ł��邪�A�����ɏ����Ă����B


//==============================================================
//		fips-197	5.2	InvSbox()	(4Byte������)
//--------------------------------------------------------------
//	������
//			unsigned int	data	4Byte�̐��l
//	���Ԓl
//			unsigned int		InvSBox�K�p��
//==============================================================
unsigned	int	AES::InvSubWord(unsigned int data)
{
//	fips-197	Figure 14
static	const	unsigned	char	InvSbox[256]={
	0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
	0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
	0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
	0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
	0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
	0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
	0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
	0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
	0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
	0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
	0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
	0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
	0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
	0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
	0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
	0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
	};

	//�e�[�u���ϊ��Ɋւ���SIMD���߂͖����H
	unsigned	char	a0	= InvSbox[(data    ) & 0xFF];
	unsigned	char	a1	= InvSbox[(data>>8 ) & 0xFF];
	unsigned	char	a2	= InvSbox[(data>>16) & 0xFF];
	unsigned	char	a3	= InvSbox[(data>>24)];

	return(a0 | a1<<8 | a2<<16 | a3<<24);
}

��

16Byte�P�ʂňÍ�������֐��B
���̂悤�ȈÍ����w�u���b�N�Í��x�ƌĂсA�u���b�N�P�ʂňÍ��^���������B
���̊֐�����сA��������ׂ̊֐����ĂԑO�ɂ́A���X�P�W���[���𐶐����Ȃ���΂Ȃ�Ȃ��B

�Í����́A�ȉ��̏����ŁA�e�֐����J��Ԃ��Ă΂�A���������B

Round Function
0
���񃉃E���h
AddRoundKey()
1 �` (Nr-1) SubBytes()
ShiftRows()
MixColumns()
AddRoundKey()
Nr
�ŏI���E���h
SubBytes()
ShiftRows()
AddRoundKey()

���E���h���́A���ʌ����ɂ���ĈقȂ�B

���ʌ������E���h���iNr�j
128 bit 10
192 bit 12
256 bit 14

//==============================================================
//		fips-197	5.1	Cipher
//--------------------------------------------------------------
//	������
//			__m128i	data	Plain-text 
//	���Ԓl
//			__m128i		Cipher-text
//==============================================================
__m128i	AES::Cipher(__m128i data)
{
	//��Round [0]
	int	i=0;

	data = AddRoundKey(data, i);
	i++;

	//��Round (1) �` (Nr-1)
	do{
		data = AddRoundKey(MixColumns(ShiftRows(SubBytes(data))),i);
		i++;
	} while(i < Nr);

	//��Round (Nr)
	data = AddRoundKey(ShiftRows(SubBytes(data)),i);

	return(data);
}

SubBytes()

���X�P�W���[���̐����ł��q�ׂ��悤�ɁASBox�̃e�[�u���ϊ��ɂ‚��ẮASIMD��������@��S���v���‚��Ȃ��B
�Ƃ肠�����A4Byte���ɕϊ����s���B


//==============================================================
//		fips-197	5.1.1	SubBytes
//--------------------------------------------------------------
//	������
//			__m128i	data	Input
//	���Ԓl
//			__m128i		Output
//==============================================================
__m128i	AES::SubBytes(__m128i data)
{
	//�e�[�u���ϊ��́ASIMD���ł��Ȃ��H
	data.m128i_u32[0] = SubWord(data.m128i_u32[0]);
	data.m128i_u32[1] = SubWord(data.m128i_u32[1]);
	data.m128i_u32[2] = SubWord(data.m128i_u32[2]);
	data.m128i_u32[3] = SubWord(data.m128i_u32[3]);

	return(data);
}

ShiftRows()

������肽�����Ƃ����ƁA

����
D[ 0]D[ 4]D[ 8]D[12]
D[ 1]D[ 5]D[ 9]D[13]
D[ 2]D[ 6]D[10]D[14]
D[ 3]D[ 7]D[11]D[15]

�Ƃ������͂ɑ΂���

�o��
D[ 0]D[ 4]D[ 8]D[12]
D[ 5]D[ 9]D[13]D[ 1]
D[10]D[14]D[ 2]D[ 6]
D[15]D[ 3]D[ 7]D[11]

�ɕ��בւ��ďo�͂���֐���ShiftRows()�B ���̔z��������@�Ƃ��ẮA�܂��Aa0�`a3�����B
����a0�`a3�́A_mm_shuffle_epi32()�ɂ���āA���͂��ꂽ�z���32bit�P�ʂœ���ւ������́B

a0 �� ����

a0
D[ 0]D[ 4]D[ 8]D[12]
D[ 1]D[ 5]D[ 9]D[13]
D[ 2]D[ 6]D[10]D[14]
D[ 3]D[ 7]D[11]D[15]

pshufd a1, ����, 00111001b

a1
D[ 4]D[ 8]D[12]D[ 0]
D[ 5]D[ 9]D[13]D[ 1]
D[ 6]D[10]D[14]D[ 2]
D[ 7]D[11]D[15]D[ 3]

pshufd a2, ����, 01001110b

a2
D[ 8]D[12]D[ 0]D[ 4]
D[ 9]D[13]D[ 1]D[ 5]
D[10]D[14]D[ 2]D[ 6]
D[11]D[15]D[ 3]D[ 7]

pshufd a3, ����, 10010011b

a3
D[12]D[ 0]D[ 4]D[ 8]
D[13]D[ 1]D[ 5]D[ 9]
D[14]D[ 2]D[ 6]D[10]
D[15]D[ 3]D[ 7]D[11]

���ɁA�s�v�Ȑ��l���}�X�N���āA"0"�ɂ���B

a0
D[ 0]D[ 4]D[ 8]D[12]
0 00 0
0 00 0
0 00 0

a1
0 00 0
D[ 5]D[ 9]D[13]D[ 1]
0 00 0
0 00 0

a2
0 00 0
0 00 0
D[10]D[14]D[ 2]D[ 6]
0 00 0

a3
0 00 0
0 00 0
0 00 0
D[15]D[ 3]D[ 7]D[11]

����a0�`a3���A�_���a���Z(OR)����ƁA�����Ɋ��҂̔z�񂪏o���オ��B
�o�� �� a0 | a1 | a2 | a3

�o��
D[ 0]D[ 4]D[ 8]D[12]
D[ 5]D[ 9]D[13]D[ 1]
D[10]D[14]D[ 2]D[ 6]
D[15]D[ 3]D[ 7]D[11]

//==============================================================
//		fips-197	5.1.2	ShiftRows
//--------------------------------------------------------------
//	������
//			__m128i	data	Input
//	���Ԓl
//			__m128i		Output
//==============================================================
__m128i	AES::ShiftRows(__m128i data)
{
__declspec(align(16))	static	const	unsigned	int	mask0[4] = {0x000000FF,0x000000FF,0x000000FF,0x000000FF};
__declspec(align(16))	static	const	unsigned	int	mask1[4] = {0x0000FF00,0x0000FF00,0x0000FF00,0x0000FF00};
__declspec(align(16))	static	const	unsigned	int	mask2[4] = {0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000};
__declspec(align(16))	static	const	unsigned	int	mask3[4] = {0xFF000000,0xFF000000,0xFF000000,0xFF000000};

	const	__m128i	_mm_mask0 = _mm_load_si128((__m128i*)&mask0);
	const	__m128i	_mm_mask1 = _mm_load_si128((__m128i*)&mask1);
	const	__m128i	_mm_mask2 = _mm_load_si128((__m128i*)&mask2);
	const	__m128i	_mm_mask3 = _mm_load_si128((__m128i*)&mask3);

	__m128i	a0	=	_mm_and_si128(_mm_mask0, data);					//�c�����̉�]
	__m128i	a1	=	_mm_and_si128(_mm_mask1, _mm_shuffle_epi32(data, 0x39));	//0011 1001 b
	__m128i	a2	=	_mm_and_si128(_mm_mask2, _mm_shuffle_epi32(data, 0x4E));	//0100 1110 b
	__m128i	a3	=	_mm_and_si128(_mm_mask3, _mm_shuffle_epi32(data, 0x93));	//1001 0011 b

	return(_mm_or_si128(_mm_or_si128(a0,a1),_mm_or_si128(a2,a3)));
}

MixColumns()

4Byte�P�ʂŁA�K���A��GF(28)�ɂ�����s��̉��Z���s���B
�i�K���A�́i�L���́j�ɂ‚��ẮA���w�̐�发���Q�Ƃ̎��B�j

  • �����Z�@�c�@�r���I�_���a�iXOR�j
  • �|���Z�@�c�@�ȉ��Amul()�֐����Q�ƁB
���͂��ꂽ�z���I[0]�`I[3]�A�o�͂��ׂ��z���O[0]�`O[3]�Ɖ��肷��ƁA

�@| O[0] |�@ �@�@| �Q�@�R�@�P�@�P || I[0] |
�@| O[1] |�@���@| �P�@�Q�@�R�@�P || I[1] |
�@| O[2] |�@ �@�@| �P�@�P�@�Q�@�R || I[2] |
�@| O[3] |�@ �@�@| �R�@�P�@�P�@�Q || I[3] |

�‚܂�A

�@O[0] �� 2I[0] �{ 3I[1] �{�@I[2] �{�@I[3]
�@O[1] ���@I[0] �{ 2I[1] �{ 3I[2] �{�@I[3]
�@O[2] ���@I[0] �{�@I[1] �{ 2I[2] �{ 3I[3]
�@O[3] �� 3I[0] �{�@I[1] �{�@I[2] �{ 2I[3]

���̌v�Z���A�s���B
SIMD������ɓ������ẮA�ȉ��̃v���Z�X�Ƃ����B

���͂ɑ΂��āA�Q�{���ꂽ�z��ia0�j�ƁA�P�{���ꂽ�z����Q�ia1,a2�j�A�R�{���ꂽ�z��ia3�j��p�ӂ���B

a0 �� �Q �~ ����

a0
2D[ 0]2D[ 4]2D[ 8]2D[12]
2D[ 1]2D[ 5]2D[ 9]2D[13]
2D[ 2]2D[ 6]2D[10]2D[14]
2D[ 3]2D[ 7]2D[11]2D[15]

a1 �� �P �~ ����

a0
D[ 0]D[ 4]D[ 8]D[12]
D[ 1]D[ 5]D[ 9]D[13]
D[ 2]D[ 6]D[10]D[14]
D[ 3]D[ 7]D[11]D[15]

a2 �� �P �~ ����

a0
D[ 0]D[ 4]D[ 8]D[12]
D[ 1]D[ 5]D[ 9]D[13]
D[ 2]D[ 6]D[10]D[14]
D[ 3]D[ 7]D[11]D[15]

a3 �� �R �~ ����

a0
3D[ 0]3D[ 4]3D[ 8]3D[12]
3D[ 1]3D[ 5]3D[ 9]3D[13]
3D[ 2]3D[ 6]3D[10]3D[14]
3D[ 3]3D[ 7]3D[11]3D[15]

���ɂ�邱�Ƃ́A32bit�P�ʂŁAa0�`a3����]�B

rol a0,0�@�@�i�‚܂��]���Ȃ��B�j

a0
2D[ 0]2D[ 4]2D[ 8]2D[12]
2D[ 1]2D[ 5]2D[ 9]2D[13]
2D[ 2]2D[ 6]2D[10]2D[14]
2D[ 3]2D[ 7]2D[11]2D[15]

rol a1,8�@�@�i��8bit��]�j

a0
D[ 3]D[ 7]D[11]D[15]
D[ 0]D[ 4]D[ 8]D[12]
D[ 1]D[ 5]D[ 9]D[13]
D[ 2]D[ 6]D[10]D[14]

rol a2,16�@�@�i��16bit��]�j

a0
D[ 2]D[ 6]D[10]D[14]
D[ 3]D[ 7]D[11]D[15]
D[ 0]D[ 4]D[ 8]D[12]
D[ 1]D[ 5]D[ 9]D[13]

rol a3,24�@�@�i��24bit��]�j

a0
3D[ 1]3D[ 5]3D[ 9]3D[13]
3D[ 2]3D[ 6]3D[10]3D[14]
3D[ 3]3D[ 7]3D[11]3D[15]
3D[ 0]3D[ 4]3D[ 8]3D[12]

��]��A����a0�`a3�����Z����΁A���Ғl�̔z�񂪓�����킯�ł��B
�����ł̉��Z�́A�K���A��GF(28)�ɂ����鉉�Z�ł���̂ŁA
���Ғl �� a0 ^ a1 ^ a2 ^ a3


//==============================================================
//		fips-197	5.1.3	MixColumns
//--------------------------------------------------------------
//	������
//			__m128i	data	Input
//	���Ԓl
//			__m128i		Output
//==============================================================
__m128i	AES::MixColumns(__m128i data)
{
	__m128i		a0 = mul(data, 2);
	__m128i		a1 = data;		//	= mul(data, 1);
	__m128i		a2 = data;		//	= mul(data, 1);
	__m128i		a3 = mul(data, 3);
										//	����SSE���߂�ror����������
										//	�����������Ɓi32bit�E��]�j
	a1	= _mm_or_si128(_mm_srli_epi32(a1,24),_mm_slli_epi32(a1, 8));	//	prord	a1, 24
	a2	= _mm_or_si128(_mm_srli_epi32(a2,16),_mm_slli_epi32(a2,16));	//	prord	a2, 16
	a3	= _mm_or_si128(_mm_srli_epi32(a3, 8),_mm_slli_epi32(a3,24));	//	prord	a3, 8

	return(_mm_xor_si128(_mm_xor_si128(a0,a1),_mm_xor_si128(a2,a3)));
}

�ȉ��́A�K���A��GF(28)�ɂ������Z���s���֐��B
�L�����[�i���オ��j����������ׁA�z��v�f�����ɕ����āA8bit���̔z���16bit���ɂ��A���Z���Ă���B
�K���A��GF(28)�ɂ����āA�wx8 + x4 + x3 + x2 + 1 �� 0�x�ł���ׁA���オ�莞�́A���̒l�i0x011B�j�����Z�iXOR�j����B


//==============================================================
//		fips-197	4.2	Multiplication
//--------------------------------------------------------------
//	������
//			__m128i	data	Input
//			unsigned char n	
//	���Ԓl
//			__m128i		Result (data[0..15] �~ n)
//==============================================================
__m128i	AES::mul(__m128i data, unsigned char n)
{
__declspec(align(16))	static	const	unsigned	__int16	_FF00[8] = {0xFF00,0xFF00,0xFF00,0xFF00, 0xFF00,0xFF00,0xFF00,0xFF00};
__declspec(align(16))	static	const	unsigned	__int16	_00FF[8] = {0x00FF,0x00FF,0x00FF,0x00FF, 0x00FF,0x00FF,0x00FF,0x00FF};
__declspec(align(16))	static	const	unsigned	__int16	_011B[8] = {0x011B,0x011B,0x011B,0x011B, 0x011B,0x011B,0x011B,0x011B};

	const	__m128i	_mm_FF00 = _mm_load_si128((__m128i*)&_FF00);
	const	__m128i	_mm_00FF = _mm_load_si128((__m128i*)&_00FF);
	const	__m128i	_mm_011B = _mm_load_si128((__m128i*)&_011B);

	__m128i	data1	=	_mm_srli_epi16(	_mm_and_si128(data, _mm_FF00), 8);
	__m128i	data2	=			_mm_and_si128(data, _mm_00FF);

	__m128i	result1	=	_mm_setzero_si128();
	__m128i	result2	=	_mm_setzero_si128();

	unsigned	char	i = 0x08;

	do{
		result1	= _mm_slli_epi16(result1, 1);
		result2	= _mm_slli_epi16(result2, 1);

		result1	= _mm_xor_si128(result1, _mm_and_si128(_mm_cmpgt_epi16(result1, _mm_00FF), _mm_011B));
		result2	= _mm_xor_si128(result2, _mm_and_si128(_mm_cmpgt_epi16(result2, _mm_00FF), _mm_011B));

		if(i & n){
			result1 = _mm_xor_si128(result1, data1);
			result2 = _mm_xor_si128(result2, data2);
		}
		i >>= 1;
	} while (i>0);

	return(_mm_or_si128(_mm_slli_epi16(result1, 8), result2));
}

AddRoundKey()

���E���h���ɉ��������X�P�W���[���ƁA�r���I�_���a(XOR)���邾���B


//==============================================================
//		fips-197	5.1.4	AddRoundKey
//--------------------------------------------------------------
//	������
//			__m128i	data	Input
//			int	i	Round
//	���Ԓl
//			__m128i		Output
//==============================================================
__m128i	AES::AddRoundKey(__m128i data, int i)
{
	return(_mm_xor_si128(data, _mm_load_si128((__m128i*)&w[i*4])));
}

����

�Í����̋t�̏��ԂƂȂ�B

Round Function
Nr
���񃉃E���h
InvAddRoundKey()
(Nr-1) �` 1 InvShiftRows()
InvSubBytes()
InvAddRoundKey()
InvMixColumns()
0
�ŏI���E���h
InvShiftRows()
InvSubBytes()
InvAddRoundKey()

//==============================================================
//		fips-197	5.3	InvCipher
//--------------------------------------------------------------
//	������
//			__m128i	data	Cipher-text
//	���Ԓl
//			__m128i		Plain-text
//==============================================================
__m128i	AES::InvCipher(__m128i data)
{
	//��Round (Nr)
	int	i=Nr;

	data = InvAddRoundKey(data, i);
	i--;

	//��Round (Nr-1) �` (1)
	do{
		data = InvMixColumns(InvAddRoundKey(InvSubBytes(InvShiftRows(data)),i));
		i--;
	} while(i > 0);

	//��Round (0)
	data = InvAddRoundKey(InvSubBytes(InvShiftRows(data)), i);

	return(data);
}

InvShiftRows()

������肽�����Ƃ����ƁAShiftRows()�̋t�̉�]�B

����
D[ 0]D[ 4]D[ 8]D[12]
D[ 1]D[ 5]D[ 9]D[13]
D[ 2]D[ 6]D[10]D[14]
D[ 3]D[ 7]D[11]D[15]

�Ƃ������͂ɑ΂���

�o��
D[ 0]D[ 4]D[ 8]D[12]
D[13]D[ 1]D[ 5]D[ 9]
D[10]D[14]D[ 2]D[ 6]
D[ 7]D[11]D[15]D[ 3]

�ɕ��בւ��ďo�͂���֐���InvShiftRows()�B
ShiftRows()�ƁA���l�̕��@�ʼn�]�ł���B


//==============================================================
//		fips-197	5.3.1	InvShiftRows
//--------------------------------------------------------------
//	������
//			__m128i	data	Input
//	���Ԓl
//			__m128i		Output
//==============================================================
__m128i	AES::InvShiftRows(__m128i data)
{
__declspec(align(16))	static	const	unsigned	int	mask0[4] = {0x000000FF,0x000000FF,0x000000FF,0x000000FF};
__declspec(align(16))	static	const	unsigned	int	mask1[4] = {0x0000FF00,0x0000FF00,0x0000FF00,0x0000FF00};
__declspec(align(16))	static	const	unsigned	int	mask2[4] = {0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000};
__declspec(align(16))	static	const	unsigned	int	mask3[4] = {0xFF000000,0xFF000000,0xFF000000,0xFF000000};

	const	__m128i	_mm_mask0 = _mm_load_si128((__m128i*)&mask0);
	const	__m128i	_mm_mask1 = _mm_load_si128((__m128i*)&mask1);
	const	__m128i	_mm_mask2 = _mm_load_si128((__m128i*)&mask2);
	const	__m128i	_mm_mask3 = _mm_load_si128((__m128i*)&mask3);

	__m128i		a0	=	_mm_and_si128(_mm_mask0, data);					//�c�����̉�]
	__m128i		a1	=	_mm_and_si128(_mm_mask3, _mm_shuffle_epi32(data, 0x39));	//0011 1001 b
	__m128i		a2	=	_mm_and_si128(_mm_mask2, _mm_shuffle_epi32(data, 0x4E));	//0100 1110 b
	__m128i		a3	=	_mm_and_si128(_mm_mask1, _mm_shuffle_epi32(data, 0x93));	//1001 0011 b

	return(_mm_or_si128(_mm_or_si128(a0,a1),_mm_or_si128(a2,a3)));
}

InvSubBytes()

SubBytes()�֐��̋t�ϊ����s���B


//==============================================================
//		fips-197	5.3.2	InvSubBytes
//--------------------------------------------------------------
//	������
//			__m128i	data	Input
//	���Ԓl
//			__m128i		Output
//==============================================================
__m128i	AES::InvSubBytes(__m128i data)
{
	//�e�[�u���ϊ��́ASIMD���ł��Ȃ��H
	data.m128i_u32[0] = InvSubWord(data.m128i_u32[0]);
	data.m128i_u32[1] = InvSubWord(data.m128i_u32[1]);
	data.m128i_u32[2] = InvSubWord(data.m128i_u32[2]);
	data.m128i_u32[3] = InvSubWord(data.m128i_u32[3]);

	return(data);
}

InvMixColumns()

MixColumns()�ōs�����s�񉉎Z�ɂĎg�p�����s��̋t�s���p���ĉ��Z����B
���͂��ꂽ�z���I[0]�`I[3]�A�o�͂��ׂ��z���O[0]�`O[3]�Ɖ��肷��ƁA

�@| O[0] |�@ �@�@| 14�@09�@13�@11 || I[0] |
�@| O[1] |�@���@| 11�@14�@09�@13 || I[1] |
�@| O[2] |�@ �@�@| 13�@11�@14�@09 || I[2] |
�@| O[3] |�@ �@�@| 09�@13�@11�@14 || I[3] |

�‚܂�A

�@O[0] ��14I[0] �{ 9I[1] �{13I[2] �{11I[3]
�@O[1] ��11I[0] �{14I[1] �{ 9I[2] �{13I[3]
�@O[2] ��13I[0] �{11I[1] �{14I[2] �{ 9I[3]
�@O[3] �� 9I[0] �{13I[1] �{11I[2] �{14I[3]

���̌v�Z���A�s���B
���͂ɑ΂��āA14�{���ꂽ�z��ia0�j�A9�{���ꂽ�z��ia1�j�A13�{���ꂽ�z��ia2�j�ƁA11�{���ꂽ�z��ia3�j��p�ӂ��A MixColumns()�֐����l�Ɍv�Z�ł���B


//==============================================================
//		fips-197	5.3.3	InvMixColumns
//--------------------------------------------------------------
//	������
//			__m128i	data	Input
//	���Ԓl
//			__m128i		Output
//==============================================================
__m128i	AES::InvMixColumns(__m128i data)
{
	__m128i		a0 = mul(data, 0x0E);
	__m128i		a1 = mul(data, 0x09);
	__m128i		a2 = mul(data, 0x0D);
	__m128i		a3 = mul(data, 0x0B);
										//	����SSE���߂�ror����������
										//	�����������Ɓi32bit�E��]�j
	a1	= _mm_or_si128(_mm_srli_epi32(a1,24),_mm_slli_epi32(a1, 8));	//	prord	a1, 24
	a2	= _mm_or_si128(_mm_srli_epi32(a2,16),_mm_slli_epi32(a2,16));	//	prord	a2, 16
	a3	= _mm_or_si128(_mm_srli_epi32(a3, 8),_mm_slli_epi32(a3,24));	//	prord	a3, 8

	return(_mm_xor_si128(_mm_xor_si128(a0,a1),_mm_xor_si128(a2,a3)));
}

InvAddRoundKey()

���E���h���ɉ��������X�P�W���[���ƁA�r���I�_���a(XOR)���邾���B


//==============================================================
//		fips-197	5.3.4	InvAddRoundKey
//--------------------------------------------------------------
//	������
//			__m128i	data	Input
//			int	i	Round
//	���Ԓl
//			__m128i		Output
//==============================================================
__m128i	AES::InvAddRoundKey(__m128i data, int i)
{
	return(_mm_xor_si128(data, _mm_load_si128((__m128i*)&w[i*4])));
}