有限域GF(2^8)内乘法代码实现以及原理

2023-11-05

       在密码学中经常用到有限域的乘法,一般在AES中用到的是GF(2^8)有限域内乘法。什么是有限域呢?有限域通俗的讲就是函数的运算结果全都包含在一个域中,不同于实数域,有限域有一个最大值,所有超过这个最大值的数都会经过一定的方法使他回到这个域中,在密码学中应用很广泛,2^8意味着这个域的最大值是256.

       以下代码是GF(2^8)有限域内乘法的C代码实现:

unsigned char XTIME(unsigned char x) {
	return ((x << 1) ^ ((x & 0x80) ? 0x1b : 0x00));
}
unsigned char multiply(unsigned char a, unsigned char b) {
	unsigned char temp[8] = { a };
	unsigned char tempmultiply = 0x00;
	int i = 0;
	for (i = 1; i < 8; i++) {
		temp[i] = XTIME(temp[i - 1]);
	}
	tempmultiply = (b & 0x01) * a;
	for (i = 1; i <= 7; i++) {
		tempmultiply ^= (((b >> i) & 0x01) * temp[i]);
	}
	return tempmultiply;
}

以下讲一下乘法的原理:

          在二进制中,所有的数都能用0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80异或得到,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80的二进制表示如下:


       后一个分别是前一个的2倍。假设任意一个数a,他的二进制表示为10101101,可以由以下组合组成:


       而任何一个数x和a相乘都可以表示为


所以只要计算出

一切乘法的结果都可以得到。

         XTIME函数的含义是求一个数x与0x02的乘积,一般求一个数的2倍,都是作移一位,在有限域内,要计算有限域的乘法,必须先确定一个GF上的8次不可约多项式,Rijndael密码中,这个多项式确定为x^8+x^4+x^3+x+1,如果最高位是1的话,左移一位的同时要异或0x1B,是因为最高位是1的话,再继续左移会超出域的最大值,这个时候需要取除以同余式,也就是异或0x1B。

for (i = 1; i < 8; i++) {
	temp[i] = XTIME(temp[i - 1]);
}
经过这个循环可以得到一串包含8个字符的数组,分别是0x01*x,0x02*x,0x04*x,0x08*x,0x10*x,0x20*x,0x40*x,,0x80*x,放在temp这个数组内。接下来通过这个循环

for (i = 1; i <= 7; i++) {
	tempmultiply ^= (((b >> i) & 0x01) * temp[i]);
}

另一个乘数b右移一位和0x01与运算,分别和这8个字符相乘,再把相乘的结果异或。就得到了a和b相乘的结果。

接下来举个例子:

求0x3a*0x24?

        首先0x3a=00111010,分别求



0x24=00100100,所以0x3a*0x24=0x3a*00100100=0x04*0x3a^0x20*0x3a=0xe8^0x01=0xe9.

是正确结果。


如果要提高算法的计算效率,还可以这么做。

如果一个乘数的二进制可以表示为


一个乘数表示为


那么a的倍数关系可表示为:


那么他的乘积可以表示为


其中


所以乘法可以表示为


所以还有一种计算方法,那就是按照上面这个矩阵乘法。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void print_bit(bool *hexbit, int len) {
	int i = 0;
	for (i = 0; i < len; i++) {
		printf("%x ", hexbit[i]);
	}
}

void print_matrix(bool matrix[8][8]) {
	int i = 0;
	for (i = 0; i < 8; i++) {
		print_bit(matrix[i], 8);
		printf("\n");

	}
}

void convertto_bit(unsigned char cipher, bool *hexbit, int len) {

	len = 8;
	int i = 0;
	for (i = 0; i < 8; i++) {
		if (cipher & 0x80) {
			hexbit[i] = true;
		}
		cipher = cipher << 1;
	}
}
void convertto_matrix(bool hexbit[8], bool matrix[8][8]) {

	matrix[0][0] = hexbit[0];
	matrix[0][1] = hexbit[1];
	matrix[0][2] = hexbit[2];
	matrix[0][3] = hexbit[3];
	matrix[0][4] = hexbit[0] ^ hexbit[4];
	matrix[0][5] = hexbit[0] ^ hexbit[1] ^ hexbit[5];
	matrix[0][6] = hexbit[1] ^ hexbit[2] ^ hexbit[6];
	matrix[0][7] = hexbit[0] ^ hexbit[2] ^ hexbit[3] ^ hexbit[7];

	matrix[1][0] = hexbit[1];
	matrix[1][1] = hexbit[2];
	matrix[1][2] = hexbit[3];
	matrix[1][3] = matrix[0][4];
	matrix[1][4] = matrix[0][5];
	matrix[1][5] = matrix[0][6];
	matrix[1][6] = hexbit[0] ^ hexbit[2] ^ hexbit[3] ^ hexbit[7];
	matrix[1][7] = hexbit[1] ^ hexbit[3] ^ hexbit[4];

	matrix[2][0] = hexbit[2];
	matrix[2][1] = hexbit[3];
	matrix[2][2] = matrix[1][3];
	matrix[2][3] = matrix[1][4];
	matrix[2][4] = matrix[1][5];
	matrix[2][5] = matrix[1][6];
	matrix[2][6] = matrix[1][7];
	matrix[2][7] = hexbit[2] ^ hexbit[4] ^ hexbit[5];

	matrix[3][0] = hexbit[3];
	matrix[3][1] = matrix[2][2];
	matrix[3][2] = matrix[2][3];
	matrix[3][3] = matrix[2][4];
	matrix[3][4] = matrix[2][5];
	matrix[3][5] = matrix[2][6];
	matrix[3][6] = matrix[2][7];
	matrix[3][7] = hexbit[0] ^ hexbit[3] ^ hexbit[5] ^ hexbit[6];

	matrix[4][0] = hexbit[4];
	matrix[4][1] = hexbit[0] ^ hexbit[5];
	matrix[4][2] = hexbit[1] ^ hexbit[6];
	matrix[4][3] = hexbit[0] ^ hexbit[2] ^ hexbit[7];
	matrix[4][4] = hexbit[0] ^ hexbit[1] ^ hexbit[3];
	matrix[4][5] = hexbit[0] ^ hexbit[1] ^ hexbit[2] ^ hexbit[4];
	matrix[4][6] = hexbit[0] ^ hexbit[1] ^ hexbit[2] ^ hexbit[3] ^ hexbit[5];
	matrix[4][7] = hexbit[0] ^ hexbit[1] ^ hexbit[2] ^ hexbit[3] ^ hexbit[4]
			^ hexbit[6];

	matrix[5][0] = hexbit[5];
	matrix[5][1] = hexbit[6];
	matrix[5][2] = hexbit[0] ^ hexbit[7];
	matrix[5][3] = hexbit[0] ^ hexbit[1];
	matrix[5][4] = hexbit[1] ^ hexbit[2];
	matrix[5][5] = hexbit[2] ^ hexbit[3];
	matrix[5][6] = hexbit[0] ^ hexbit[3] ^ hexbit[4];
	matrix[5][7] = hexbit[1] ^ hexbit[4] ^ hexbit[5];

	matrix[6][0] = hexbit[6];
	matrix[6][1] = matrix[5][2];
	matrix[6][2] = matrix[5][3];
	matrix[6][3] = matrix[5][4];
	matrix[6][4] = matrix[5][5];
	matrix[6][5] = matrix[5][6];
	matrix[6][6] = matrix[5][7];
	matrix[6][7] = hexbit[0] ^ hexbit[2] ^ hexbit[5] ^ hexbit[6];

	matrix[7][0] = hexbit[7];
	matrix[7][1] = hexbit[0];
	matrix[7][2] = hexbit[1];
	matrix[7][3] = hexbit[2];
	matrix[7][4] = hexbit[3];
	matrix[7][5] = matrix[2][2];
	matrix[7][6] = matrix[2][3];
	matrix[7][7] = matrix[2][4];

	return;
}

unsigned char XTIME(unsigned char x) {
	return ((x << 1) ^ ((x & 0x80) ? 0x1b : 0x00));
}
unsigned char multiply(unsigned char a, unsigned char b) {
	unsigned char temp[8] = { a };
	unsigned char tempmultiply = 0x00;
	int i = 0;
	for (i = 1; i < 8; i++) {
		temp[i] = XTIME(temp[i - 1]);
	}
	tempmultiply = (b & 0x01) * a;
	for (i = 1; i <= 7; i++) {
		tempmultiply ^= (((b >> i) & 0x01) * temp[i]);
	}
	return tempmultiply;
}

unsigned char multiply_bit(unsigned char plaintext, unsigned char key) {
	int ret_len = 0;
	bool plaintext_hexbit[8] = { false, false, false, false, false, false,
			false, false };
	bool key_hexbit[8] = { false, false, false, false, false, false, false,
			false };
	bool cipher_hexbit[8] = { false, false, false, false, false, false, false,
			false };
	//把plaintext转换成二进制
	convertto_bit(plaintext, plaintext_hexbit, ret_len);
	bool matrix[8][8] = { };
	convertto_matrix(plaintext_hexbit, matrix);

	//把key转换成二进制
	convertto_bit(key, key_hexbit, ret_len);

	//print_matrix(matrix);
	//printf("\n");

	//print_bit(key_hexbit, sizeof(key_hexbit));
	//printf("\n");
	int i = 0;
	int j = 0;

	for (i = 0; i < 8; i++) {
		cipher_hexbit[i] = false;
		for(j = 0;j < 8;j++) {
			if(key_hexbit[j]){
				cipher_hexbit[i] ^=matrix[i][7-j];
			}
		}
	}

	//print_bit(cipher_hexbit, sizeof(cipher_hexbit));

	unsigned char outcome = 0;
	for (i = 0; i < 8; i++) {
		if (cipher_hexbit[i]) {
			outcome ^= 0x01 << (7 - i);
		}
	}
	return outcome;
}

int main(int argc, char * argv[]) {

	unsigned char plaintext = 0x49;
	unsigned char key = 0x24;

	printf("%#x", multiply_bit(plaintext, key));
	printf("\n");
//	unsigned char plaintext1 = 0x01;
//	unsigned char key1 = 0x21;
	printf("%#x", multiply(plaintext, key));

	return 0;
}



输出结果是
0xdc
0xdc
结果一样,是正确的

经过测试,后一种方法比第一种方法效率慢很多,原因是其中代码计算矩阵和矩阵乘法比第一种方法复杂。但是第二种提供另外一种思路。




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有限域GF(2^8)内乘法代码实现以及原理 的相关文章

  • Web UI 中的 .Result 出现死锁

    我正在阅读以下主题http blog stephencleary com 2012 07 dont block on async code html http blog stephencleary com 2012 07 dont bloc
  • 如何向 UWP 项目添加 .NET dll 引用?

    我有几个适用于 NETv4 x 的 NET dll 项目 我将版本更改为 4 6 1 并重新构建 没有出现问题 当我尝试从 UWP 项目向它们添加引用时 出现错误 项目的目标是 NETCore 而文件引用的目标是 NET框架 这不是受支持的
  • 如何从当前 .NET 表单/应用程序发送密钥 F12

    我非常确定以下按钮激活的表单代码应该在我的 C 应用程序中引发 Control F12 SendKeys F12 但它似乎并没有继续进入 Windows shell 并激活另一个正在侦听它的程序 我的键盘可以用 看起来发送键在某处被拦截 并
  • LINQ to XML - 如何正确使用 XDocument

    现在我首先要说的是 这确实是一项任务 然而 在我遇到 Linq to XML 语法之前 我几乎已经完成了它 我有 2 个课程 曲目和 CD 现在作为作业的一部分 我创建了一张 CD 然后向其中添加了一些曲目 在搜索了大量完美解释了如何从 x
  • .NET 可移植类库中的 .ToShortDateString 发生了什么

    我想知道为什么没有 ToShortDateString在 NET 可移植类库中 我有 2 个项目 Silverlight 和常规 NET 类库 使用相同的代码 并且代码涉及调用 ToShortDateString on a DateTime
  • 我应该在单元测试中使用 AutoMapper 吗?

    我正在为 ASP NET MVC 控制器方法编写单元测试 这些控制器依赖于IMapper 我创建的用于抽象 AutoMapper 的接口 使用 Castle Windsor 通过构造函数注入传入 动作方法使用IMapper从领域对象映射到
  • __FUNCTION__ 宏的 C# 版本

    有人对 C FUNCTION 宏的 C 版本有好的解决方案吗 编译器似乎不喜欢它 尝试使用这个代替 System Reflection MethodBase GetCurrentMethod Name C 没有 LINE or FUNCTI
  • 组合 Datepicker 和 Timepicker 值 Win 8.1

    我试图同时使用 Datepicker Timepicker 来返回可以存储在数据库中的 DateTime 例如 我想要安排会议的开始日期和结束日期 如果适用 我将如何将这些值组合成 SQL 数据库可以处理的正确格式 任何反馈都会很棒 我让这
  • 推送 Lua 表

    我已经创建了一个Lua表C 但我不知道如何将该表推入堆栈顶部 以便我可以将其传递给 Lua 函数 有谁知道如何做到这一点 这是我当前的代码 lua createtable state libraries size 0 int table i
  • 为什么以下代码不允许我使用 fgets 获取用户输入但可以使用 scanf?

    这是一个更大程序的简短摘录 但该程序的其余部分无关紧要 因为我认为我能够隔离该问题 我怀疑这与我使用 fgets 的方式有关 我读过 最好使用 fgets 而不是 scanf 但我似乎无法让它在这里正常工作 当我使用以下代码时 程序不会给我
  • 抽象类和接口之间的区别[重复]

    这个问题在这里已经有答案了 可能的重复 接口与基类 https stackoverflow com questions 56867 interface vs base class 我不明白抽象类和接口之间的区别 我什么时候需要使用哪种字体
  • 使用 AutoMapper 进行 LINQ GroupBy 聚合

    试图让查询工作 但老实说不确定如何 或者是否可能 进行它 因为我尝试过的一切都不起作用 共查询6个表 Person PersonVote PersonCategory Category City FirstAdminDivision Per
  • 为什么我不能在扩展 List 的类中调用 OrderBy?

    我有一堂课 Deck 其中包含一个名为的方法Shuffle 我正在致力于重构Deck延长List
  • 宏观评价[重复]

    这个问题在这里已经有答案了 可能的重复 未定义的行为和序列点 https stackoverflow com questions 4176328 undefined behavior and sequence points 我无法理解以下宏
  • 有没有办法让 VS2010 在我的方法中扩展或收缩 try 块?

    我的代码有很多 try catch finally 块 与我在 VS2010 中的方法不同 除了添加区域之外 我无法在开发时扩展或收缩这些区域来隐藏内容 try vm R vm Qu vm T vm D vm Fil vm Type vm
  • 从 C# 中的 .NET SecureString 读取单个字符?

    WPF 的PasswordBox 返回一个SecureString 它对窥探者隐藏密码 问题是你最终必须获得密码的值 而我在网上找到的建议都涉及将值复制到字符串中 这会让你回到窥探者的问题 IntPtr bstr Marshal Secur
  • C++0x 中的新 unicode 字符

    我正在构建一个 API 它允许我获取各种编码的字符串 包括 utf8 utf16 utf32 和 wchar t 根据操作系统 可能是 utf32 或 utf16 新的 C 标准引入了新类型char16 t and char32 t没有这么
  • Windows 上 libcurl 的静态库[重复]

    这个问题在这里已经有答案了 如何将此库 libcurl 静态链接到 exe 我努力了 disable share enable static 没有帮助 我使用的是MingW32 有没有一种简单的方法来静态链接这个库 这样我的应用程序就不再有
  • 当我读取 500MB FileStream 时出现 OutOfMemoryException

    我使用 Filestream 读取大文件 gt 500 MB 但出现 OutOfMemoryException 任何有关它的解决方案 我的代码是 using var fs3 new FileStream filePath2 FileMode
  • 最后从同一类中的其他构造函数调用构造函数

    我在这里读到可以调用另一个构造函数从同一类中的另一个构造函数调用构造函数 https stackoverflow com questions 829870 calling constructor from other constructor

随机推荐

  • 【Linux】常见基本指令

    目录 1 ls指令 1 1 ls 1 2 ls l或 ll 1 3 ls a 1 4 ls d 1 5 ls i 1 6 ls n 1 7 ls F 1 8 ls R 2 pwd指令 3 cd指令 4 touch指令 5 mkdir 指令
  • onnxruntime 运行过程报错“onnxruntime::Model::Model Unknown model file format version“

    背景 这几天在玩一下yolov6 使用的是paddle框架训练的yolov6 然后使用paddl 转成onnx 再用onnxruntime来去预测模型 由于是在linux服务器上转出来 的onnx模型 并在本地的windows电脑上去使用
  • 希尔(Shell)排序 C++

    希尔排序是一个很有意思的排序算法 就是在选择不同的增量序列时算法的效率会有显著的不同 更有意思的是它和Dijkstra算法都有相似之后 就是刚发明的时候并不知道有那么厉害 特别是Dijkstra 自己都不知道自己发明的这个算法有没有用 希尔
  • 运算放大器分类及运算放大器参数说明

    运算放大器 我们在大部分情况下只了解运放简单的电路模型 而在很多场景中 并不是任何放大器都可以被直接拿过来应用 而是需要更加深入的了解运放的性能 那什么是性能呢 就是运放本身的参数 只有选择符合要求的运放 我们才能放大我们想要的信号 滤除我
  • 生命在于折腾——Obsidian笔记软件折腾记录(一)

    一 开端 我使用过很多笔记软件 OneNote 语雀 Notability GoodNotes 印象笔记 有道云笔记 不得不说 我一直想拥有一款满足以下条件的笔记软件 买断制 符合以下所有条件我考虑订阅 ipad可手写 icloud可同步
  • Cocos2dx——戏如人生(1)

    建立工程 cocos new game3 1 com cn wang l cpp d project 本人用的是cocos2dx 3 6 运行工程 Hello world helloworldscene h ifndef HELLOWORL
  • 使用DVWA进行XSS漏洞实战

    使用DVWA进行XSS漏洞实战 本文记录使用DVWA进行XSS漏洞实战的过程 跨站脚本 Cross Site Scripting XSS 是一种经常出现在 WEB 应用程序中的计算机安全漏洞 是由于 WEB 应用程序对用户的输入过滤不足而产
  • 区块链与分布式数据库的区别

    1 来源 分布式数据库 应对互联网条件下大规模数据的增删改查需求 解决传统数据库面临的通信开销大 性能差 容量可扩展性差和可靠性低的问题 通信开销大 假设只有一个数据库 并且放在北京 那么纽约的用户就需要等待网络从纽约到北京的往返通信延迟
  • 使用python写一个爬取百度前10条热搜

    import requests from bs4 import BeautifulSoup def get baidu hot url https top baidu com board tab realtime headers User
  • 宝塔面板如何部署静态网站?一分钟教会你最简单的方法

    宝塔面板如何部署静态网站 如果你有做好的静态网站源码 想要直接上传到宝塔面板 有的朋友可能不知道放在哪里 这里教大家一个最简单的方法 首先 一键部署好你的网站 这里用WordPress一键部署来举例 填写好你的网站信息 保存好数据库名和密码
  • 神经网络的过拟合是什么,神经网络过拟合的表现

    神经网络过拟合的现象是什么 发生原因 过拟合现象一般都是因为学习的过于精确 就好比让机器学习人脸 取了100个人的脸训练 但是由于你学习的过精确 导致除了这个样本100人外其他的人脸神经网络都认为不是人脸 实际我们只需要学习人脸的基本特征而
  • lstm时间序列预测+GRU(python)

    lstm时间序列预测 GRU python 1 数据分布 2 完整代码 3 实验结果 4 相关代码 4 1 GRU的修改 4 2 BiLSTM的修改 可以参考新发布的文章 1 BP神经网络预测 python 2 mlp多层感知机预测 pyt
  • 1、muduo网络库 ---- Linux平台下muduo编译安装

    muduo库的介绍 一个基于reactor反应堆模型的多线程C 网络库 作者是陈硕大神 muduo库是基于 boost 库开发的 所以需要在 Linux 平台上首先安装 boost 库 1 boost 库安装 1 编译源码安装 第一种方法是
  • Linux Nginx 配置 Thinkphp 两种方式

    第一种常见 前端vue后端Thinkphp接口以 api开头 这种Thinkphp不用启动 但是需要启动 php pfm 遇到的问题是我多个Thinkphp 项目在不同的目录 配置也是对应目录 但是不同域名访问接口 时都指向了第一个Thin
  • MQ--3 Message queuing)>>>>kafka

    MQ 1 Message queuing gt gt gt gt RabbitMQ MQ 2 Message queuing gt gt gt gt ZooKeeper 三 Kafka http kafka apache org 官网链接
  • windows的磁盘操作之二——初始化磁盘

    转载自 windows的磁盘操作之二 初始化磁盘 bunny技术坊的技术博客 51CTO博客 原文如下 上一节中我们介绍了一些基本概念和主要的API 本节开始我们将列举并分析一些实例 本文中的所有代码我都在vs2008下测试过 读者只需要替
  • Flutter使用C++

    总体 flutter通过dart语言和C 交互 dart的ffi包完成交互 ffi封装了c 的基本数据类型 包括结构体 和一些基本方法 我们可以直接在dart中访问c 的内存数据等 相对于jni更加直接 基本步骤 官方步骤 https do
  • 数据挖掘七种常用的方法汇总

    数据挖掘 Data Mining 就是从大量的 不完全的 有噪声的 模糊的 随机的实际应用数据中 提取隐含在其中的 人们事先不知道的 但又是潜在有用的信息和知识的过程 这个定义包括几层含义 数据源必须是真实的 大量的 含噪声的 发现的是用户
  • 将本地jar 批量发布到 Nexus 私服

    前言 在日常开发过程中 我们有遇到将项目依赖通过 mvn deploy 发布到自己的公司的私服 以便其他人 环境统一下载入口 但是也有一些特殊情况 比如只能拿到第三方 或甲方 的依赖jar 并拿不到源码 所以只能将jar 通过 mvn de
  • 有限域GF(2^8)内乘法代码实现以及原理

    在密码学中经常用到有限域的乘法 一般在AES中用到的是GF 2 8 有限域内乘法 什么是有限域呢 有限域通俗的讲就是函数的运算结果全都包含在一个域中 不同于实数域 有限域有一个最大值 所有超过这个最大值的数都会经过一定的方法使他回到这个域中