作业要求:
构造256字节的表格X2,使得X2[i] ={02}*i,i是GF(2^8)中的元素。将此表运用于GF(2^8)的乘法,与之前作业的乘法对比,看谁的速度快?
直奔主题吧。
先看看主函数:
int main()
{   //  -- 构造乘法表X2 --createX2();//  -- 进入乘法运算程序 --int abin[8], bbin[8], c[8];LARGE_INTEGER start_t, stop_t, freq; // start_t表示计时开始时间,stop_t表示计时结束时间,freq为计时器的时钟频率double exe_time;QueryPerformanceFrequency(&freq);// fprintf(stdout, "The frequency of your pc is %d.\n", freq.QuadPart);char choose='y';while(choose=='y'||choose=='Y'){//  -- 清空之前的计算结果 --for(int i=0; i<8; i++){c[i]=0; // 清空结果}state=0; // 清空当前查表次数//  -- 输入乘数a和b --if(input(abin, 'a')==0) // 如果输入a没有出错{if(input(bbin, 'b')==0) // 如果输入b没有出错{//  -- 程序开始执行,开始计时 --QueryPerformanceCounter(&start_t);// -- 将输入的二进制数组转换为十进制数组并保存到temp中 --int temp[2];temp[0]=binToDec(abin, 0);temp[1]=binToDec(abin, 1);//  -- 执行乘法运算 --for(i=7; i>=0; i--){if(bbin[i]==1){xor(c, leftshift(abin, 7-i, temp)); // 求和}            }//  -- 输出运算结果 --cout<<"运算结果为:";for(i=0; i<8; i++){cout<<c[i];}//  -- 程序结束执行,结束计时 --QueryPerformanceCounter(&stop_t);exe_time = 1e3*(stop_t.QuadPart-start_t.QuadPart)/freq.QuadPart;cout<<endl;fprintf(stdout, "计算用时:%fms.\n", exe_time);}}//  -- 是否继续执行程序 --cout<<endl<<"是否继续?y/n:";choose=cin.get();if(cin.get()==10){// 跳过输入y/n后的回车键,防止影响下面的输入}}return 0;
}
程序流程:构造乘法表X2 —— 初始化工作 —— 输入数a和数b —— 用查表法计算乘法结果 —— 输出运算结果和运算所用时间 —— 是否循环执行程序。
下面分段来看。
1.构造乘法表X2
为了便于使用该表,将其声明为全局静态变量:
static int *xtable[16][16]; // 乘法表X2

构造表的函数:

/* 建造乘法表X2 */
void createX2()
{int temp=0, arr[2], bin[8];int j, k;// 初始化xtable前半部分:00-7Ffor(j=0; j<8; j++){for(k=0; k<16; k++){intToArr(temp*2, arr);temp++;xtable[j][k]=new int[2];xtable[j][k][0]=arr[0];xtable[j][k][1]=arr[1];}}// 初始化xtable后半部分:80-FFfor(j=8; j<16; j++){for(k=0; k<16; k++){intToArr(temp, arr);decToBin(arr, bin);leftshift1(bin);arr[0]=binToDec(bin, 0);arr[1]=binToDec(bin, 1);xtable[j][k]=new int[2];xtable[j][k][0]=arr[0];xtable[j][k][1]=arr[1];temp++;}}
}

由于00-7F的运算结果为00-FE,没有溢出,所以可以作为表的前半部分初始化。80-FF全部溢出,需要先左移1位再异或1BH,所以作为表的后半部分初始化。

注意由于xtable二维数组中的元素均为指针类型,如果对于每一次赋值都使用xtable[j][k]=arr;那么xtable中所有指针都指向同一块内存块arr,由于arr[2]最后的结果为14 5,所以所有xtable中的元素都指向{14, 5}数组,因此必须首先new一个xtable[j][k]指针,其长度为2,然后分别对其中的两个元素赋值。
在后半部分初始化中,例如255,先要用intToArr函数将其转化为两位的16进制数组(每一位都是十进制数),即{15,15}:
/* 将整数转换为数组,例如78=4 14* 参数temp为要转换的整数* 参数a[]为转换结果*/
void intToArr(int temp, int a[])
{a[1]=temp%16;a[0]=(temp-a[1])/16;
}

然后用decToBin函数将两位16进制数组转换为二进制数组,即11111111:

/* 将2位十进制数组转换为8位二进制数组 * 参数d[]为要转换的十进制数组* 参数bin[]为转换后的二进制数组*/
void decToBin(int d[], int bin[])
{int h0=d[0];int h1=d[1];int i=3;while(i>=0){bin[i--]=h0%2;h0/=2;}i=7;while(i>=4){bin[i--]=h1%2;h1/=2;}
}

先将转换后的数组bin左移1位,再作溢出处理,即使用leftshift1函数:

/* 乘2,左移1位,如果溢出则异或1BH */
void leftshift1(int a[])
{int temp=a[0];for(int i=0; i<7; i++){a[i]=a[i+1];}a[7]=0;if(temp==1) // 溢出处理{int mod[8]={0, 0, 0, 1, 1, 0, 1, 1};xor(a, mod);}
}

将转换的二进制数组转换为两位16进制数组:

/* 将4位二进制数组转换为十进制数 * 参数b[]为要进行转换的数组* 参数bit用于判断高低位,0为高位,1为低位* 返回结果为转换后的十进制数*/
int binToDec(int b[], int bit)
{int n=8, i=0, sum=0;if(bit==0) // 高四位二进制转换十进制i=0;else if(bit==1) // 低四位二进制转换十进制i=4;else return -1;// 4位二进制转换十进制,例如1011=11while(n>=1){sum+=(n*b[i]);i++;n/=2;}return sum;
}

注意,为什么每一位都是十进制数呢(例如F对应15),原因是查表时行号和列号是直接用十进制查的,这样便于迭代查表。虽然转换麻烦了点,但是在做乘法查表时不用再转换。

如果表格为两位16进制字符数组,那么结果为:
static char *sbox[16][16]={ {"00", "02", "04", "06", "08", "0A", "0C", "0E", "10", "12", "14", "16", "18", "1A", "1C", "1E"}, // 0{"20", "22", "24", "26", "28", "2A", "2C", "2E", "30", "32", "34", "36", "38", "3A", "3C", "3E"}, // 1{"40", "42", "44", "46", "48", "4A", "4C", "4E", "50", "52", "54", "56", "58", "5A", "5C", "5E"}, // 2{"60", "62", "64", "66", "68", "6A", "6C", "6E", "70", "72", "74", "76", "78", "7A", "7C", "7E"}, // 3{"80", "82", "84", "86", "88", "8A", "8C", "8E", "90", "92", "94", "96", "98", "9A", "9C", "9E"}, // 4{"A0", "A2", "A4", "A6", "A8", "AA", "AC", "AE", "B0", "B2", "B4", "B6", "B8", "BA", "BC", "BE"}, // 5{"C0", "C2", "C4", "C6", "C8", "CA", "CC", "CE", "D0", "D2", "D4", "D6", "D8", "DA", "DC", "DE"}, // 6{"E0", "E2", "E4", "E6", "E8", "EA", "EC", "EE", "F0", "F2", "F4", "F6", "F8", "FA", "FC", "FE"}, // 7{"1B", "19", "1F", "1D", "13", "11", "17", "15", "0B", "09", "0F", "0D", "03", "01", "07", "05"}, // 8{"3B", "39", "3F", "3D", "33", "31", "37", "35", "2B", "29", "2F", "2D", "23", "21", "27", "25"}, // 9{"5B", "59", "5F", "5D", "53", "51", "57", "55", "4B", "49", "4F", "4D", "43", "41", "47", "45"}, // A{"7B", "79", "7F", "7D", "73", "71", "77", "75", "6B", "69", "6F", "6D", "63", "61", "67", "65"}, // B{"9B", "99", "9F", "9D", "93", "91", "97", "95", "8B", "89", "8F", "8D", "83", "81", "87", "85"}, // C{"BB", "B9", "BF", "BD", "B3", "B1", "B7", "B5", "AB", "A9", "AF", "AD", "A3", "A1", "A7", "A5"}, // D{"DB", "D9", "DF", "DD", "D3", "D1", "D7", "D5", "CB", "C9", "CF", "CD", "C3", "C1", "C7", "C5"}, // E{"FB", "F9", "FF", "FD", "F3", "F1", "F7", "F5", "EB", "E9", "EF", "ED", "E3", "E1", "E7", "E5"}  // F//  0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
};
2.用查表法计算乘法结果
这里沿用了移位乘法的程序框架,只是计算的方法不同而已:
               //  -- 执行乘法运算 --for(i=7; i>=0; i--){if(bbin[i]==1){xor(c, leftshift(abin, 7-i, temp)); // 求和}            }

leftshift函数为:

/* 计算a[]乘上2的len次幂的结果* 参数bin[]为要进行移位的数组* 参数len为查表的次数* 参数temp[]用于保存乘法运算结果* 返回结果为乘2的运算结果*/
int *leftshift(int bin[], int len, int temp[])
{if(len==0){state=0;return bin;}int row, column;for(state; state<len; state++){row=temp[0];column=temp[1];temp[0]=xtable[row][column][0];temp[1]=xtable[row][column][1];}decToBin(temp, bin); // 将16进制的temp转换为二进制数组binreturn bin;
}
state为全局静态变量:
static int state=0; // 用于记录左移的位数,也就是已经查表的次数
其中一次查表就相当于一次左移(包括溢出处理)运算。
这里优化程序的思想和在GF(2^8)下可做任意两个数乘法的程序(一)中的乘法思想是一样的,为了避免每次都要从头开始查表,每次运算结果都用temp保存起来,用于下一次运算的查表。
例如:求a * 00000110,从右边开始,由于b[6]=1,所以先查表一次计算得到a * 2,并用temp保存a * 2的结果,在求a * 4的时候,可以直接用temp(也就是a * 2的结果)查表一次得到结果,如果没有用到temp的话,那么* 4必须要查表2次。最后将a * 2和 a * 4异或即可。
如果a中1的个数越多,那么优化后的程序效率更高(单纯就乘法该过程看),例如如果是a * 11111111,那么不优化的情况下要查表(每次查表对应一次乘2)1+2+3+4+5+6+7=28次。如果按以上的方法优化了,只需要查表7次就可以了。
至于输入数a和数b ,异或加运算等函数和在GF(2^8)下可做任意两个数乘法的程序(一)给出的一样,不再赘述。
运行一下,比较两者的运行效率:
乘法表运算时间结果:
直接乘法运算时间结果:
首先有一点要强调的是,由于CPU每个时刻工作的速度和时钟频率等都处于动态变化当中,所以以上数据不能算绝对准确,加上程序员不同的算法也会导致程序运行的时间出现差异,因此以上数据仅仅用于对比,而且也不能算得上绝对准确。
比较之下,乘法表运算多了一些转换的工作(包括leftshift函数,因为其中的异或运算必须要使用二进制数组,而且输出结果形式也是二进制形式),也就是在乘法表的条件差于移位乘法的情况下其效率仍然高于后者,所以也得出了老师想向我们传递的信息:GF(2^8)中的乘法运算查表运算的效率高于直接运算。
当初AES的设计者就是用该方法来对乘法进行加速(另外乘法可能会受到时间分析攻击),另外表所使用的空间开销并不大,用查表计算乘法结果的方法优于直接使用乘法。
最后,小结一个问题:
对于调用函数,如果传入参数的是数组指针并且在函数中修改了参数的值,那么数组的值将相应变化。如果传入参数的是基本类型并且在函数中修改了参数的值,基本类型变量的值却不会相应发生变化。例如:

#include <iostream>
using namespace std;void setTemp(int temp)
{temp=1;
}void setArr(int a[])
{a[0]=1;a[1]=1;
}void setBool(bool b)
{b=false;
}int main()
{int temp=0;bool b=true;int arr[2]={0,0};setTemp(temp);setArr(arr);cout<<"temp="<<temp<<endl;cout<<"b="<<b<<endl;cout<<"arr[0]="<<arr[0]<<endl;cout<<"arr[1]="<<arr[1]<<endl;
}

运行结果:

道理很简单,因为在传入指针到参数后,若参数值被修改,那么指针所指向的内存块的值也相应被修改。而基本类型变量的参数传入则是另外复制一份传值。

使用乘法表计算GF(2^8)中的乘法相关推荐

  1. 一个按钮显示九九乘法表html,在JSP页面显示九九乘法表

    pageEncoding="UTF-8"%> Insert title here { for (int j = 1; j <=i; j++) { int s=j*i; ...

  2. python输出九九乘法表儿歌_python学习:输出九九乘法表

    输出九九乘法表 代码: num1 = 1 while num1 <= 9: num2 = 1 while num2 <= num1: print(str(num2)+"*&quo ...

  3. R7-2 sdut-九九乘法表分数 30作者 周雪芹单位 山东理工大学九九乘法表是数学学习的基础,今天我们就来看看乘法表的相关问题。《九九乘法歌诀》,又常称为“小九九”,如下图所示。你的任务是

    R7-2 sdut-九九乘法表 分数 30 全屏浏览题目 切换布局 作者 周雪芹 单位 山东理工大学 九九乘法表是数学学习的基础,今天我们就来看看乘法表的相关问题.<九九乘法歌诀>,又常称 ...

  4. php编写九九乘法表隔行换色,JavaScript实现99乘法表及隔行变色实例代码

    项目需求:实现在页面中输出99乘法表.(要求:以每三行为一组,实现隔行变色(颜色为白,红,黄(也可自己定义)),鼠标滑过每一行,行背景颜色变为蓝色,鼠标离开又恢复原来的颜色),隔行变色的效果需要用if ...

  5. python for循环九九乘法表_python3:使用for循环打印九九乘法表

    for i in range(1, 10):for j in range(1, i + 1):print(j, '*', i, '=', i * j, end=" ") #end= ...

  6. 九九乘法表居中c语言,JavaScript实现九九乘法表的简单实例

    每个学过编程的人都写过"HelloWorld" 但99乘法表,我想也应该成为每个编程初学者的必编程序 这是JavaScript的实现方法,非常适合初学者!!! 以下是代码及注释 J ...

  7. php九九乘法表隔行换色,JavaScript实现99乘法表及隔行变色实例代码_javascript技巧...

    项目需求:实现在页面中输出99乘法表.(要求:以每三行为一组,实现隔行变色(颜色为白,红,黄(也可自己定义)),鼠标滑过每一行,行背景颜色变为蓝色,鼠标离开又恢复原来的颜色),隔行变色的效果需要用if ...

  8. php函数 99乘法表,使用php自定义函数实现99乘法表代码

    在php自定义函数创建定义是非常的简单的我们只要利用function空格后面跟函数名就可以了,中间函数是可以有参数与相关的内容了,具体如下吧. 使用自定义函数方式来实现99乘法表,函数是一种可以在任何 ...

  9. python右对齐输出乘法表_Python实现不同格式打印九九乘法表

    前言:最近在学习Python,学习资源有慕课网上的视频教程.菜鸟教程以及Python官方文档tutorial.虽然了解了Python的基本语法,但是还没有真正意义上输出自己写的代码.代码小白,之前仅学 ...

  10. php while做乘法表,php 循环的使用 (php 99乘法表)

    1.while循环 PHP 中最简单的循环 //指定的条件为真,while 循环执行代码块 (输出1~9) $i = 1; $max = 10; while($i echo $i; echo ' '; ...

最新文章

  1. 在Ubuntu 16.04.6 LTS上升级Go到最新版1.12.5实录
  2. android如何获取listview中的任意行数据
  3. python爬虫面试问题_Python爬虫面试总结
  4. 程序员的SOHO:接单到完成的全过程
  5. 看似简单的dual,其实深藏玄机
  6. Java 18 发布:甲骨文公司已开始将Java纳入其软件许可审计
  7. VOIP Codec 三剑客之 ISAC/ILBC -- ISAC (5) LPC Parameter Encode 模块
  8. 阿里云短信API使用
  9. 谷歌gmail注册入口_如何删除您的Gmail帐户而不删除您的Google帐户
  10. 服装尺寸 html,服装尺寸表
  11. 2019电大计算机专业英语1答案,2019年最新国家开放大学电大《管理英语4》网络核心课形考网考作业附全答案...
  12. beats android 蓝牙连接电脑,beatsx怎么连接电脑_Beats X耳机连接win10电脑的详细操作步骤...
  13. [WTL/ATL]_[Gdiplus]_[绘制虚线并设置破折号空格的宽度]
  14. Sublime Text:选择变量的所有实例并编辑变量名称
  15. C语言中函数的重点知识总结
  16. 新型病毒DoubleAgent曝光:攻击计算机前先入侵防病毒软件
  17. [经验分享] 覃超线上直播课-模拟面试
  18. JAVA 实现字符串(String)的模糊查找
  19. 定向天线ADS-B地面接收机 Pentagon
  20. python assert使用

热门文章

  1. 饭前跑步还是饭后跑步 - 饭后多久跑步
  2. 业务流程优化的三点思考
  3. Spring Data Jpa 复合主键
  4. python中reduce是什么意思_python中的reduce是什么
  5. 微信小程序 上传头像截图功能
  6. Winxp U盘无法复制磁盘写保护解决办法。
  7. 自除数的判断——C语言实现
  8. 在合并单元格中数组公式无效_Excel|普通公式无法有效解决问题时使用数组公式...
  9. Your actions speak louder
  10. 作为一名程序员未来的出路究竟在哪里?