gcd&exgcd O(∩_∩)O哈!

欧几里德算法

  欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。其计算原理依赖于下面的定理:
  定理:gcd(a,b) = gcd(b,a mod b)
  证明:a可以表示成a = kb + r,则r = a mod b
  假设d是a,b的一个公约数,则有
  d|a, d|b,而r = a - kb,因此d|r
  因此d是(b,a mod b)的公约数
  假设d 是(b,a mod b)的公约数,则
  d | b , d |r ,但是a = kb +r
  因此d也是(a,b)的公约数
  因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证
  欧几里德算法就是根据这个原理来做的,其算法用C++语言描述为:
  int Gcd(int a, int b)
  {
  if(b == 0)
  return a;
  return Gcd(b, a % b);
  }
  当然你也可以写成迭代形式:
  int Gcd(int a, int b)
  {
  while(b != 0)
  {
  int r = b;
  b = a % b;
  a = r;
  }
  return a;
  }
  本质上都是用的上面那个原理。

扩展欧几里德算法

  扩展欧几里德算法是用来在已知a, b求解一组p,q使得p * a+q * b = Gcd(a, b) (解一定存在,根据数论中的相关定理)。

 算法描述为:

  int exGcd(int a, int b, int &x, int &y)
  {
  if(b == 0)
  {
  x = 1;
  y = 0;
  return a;
  }
  int r = exGcd(b, a % b, x, y);
  int t = x;
  x = y;
  y = t - a / b * y;
  return r;
  }
  把这个实现和Gcd的递归实现相比,发现多了下面的x,y赋值过程,这就是扩展欧几里德算法的精髓。
  可以这样思考:
  对于a’ = b, b’ = a % b 而言,我们求得 x, y使得 a’x + b’y = Gcd(a’, b’)
  由于b’ = a % b = a - a / b * b (注:这里的/是程序设计语言中的除法)
  那么可以得到:
  a’x + b’y = Gcd(a’, b’) ===>
  bx + (a - a / b * b)y = Gcd(a’, b’) = Gcd(a, b) ===>
  ay +b(x - a / b*y) = Gcd(a, b)
  因此对于a和b而言,他们的相对应的p,q分别是 y和(x-a/b*y)。

解释的非常好。附3行的gcd和3行的exgcd:

inline int gcd(int a,int b){

int t;

while(t=a%b) a=b,b=t;

return b;}

inline int exgcd(int a,int b,int &x,int &y){

if(!b) return x=1,y=0,a;

int r=exgcd(b,a%b,x,y),t=x;

return x=y,y=t-a/b*y,r;}

标题中提及的“BOE-B2-154-240-JD9851-Gamma2.2_190903.rar”标识了一款由京东方公司生产的液晶显示单元,属于B2产品线,物理规格为154毫米乘以240毫米,适配于JD9851型号设备,并采用Gamma2.2标准进行色彩校正,文档生成日期为2019年9月3日。该压缩文件内包含的代码资源主要涉及液晶模块的底层控制程序,采用C/C++语言编写,用于管理显示屏的基础运行功能。 液晶模块驱动作为嵌入式系统的核心软件组成部分,承担着直接操控显示硬件的任务,其关键作用在于通过寄存器读写机制来调整屏幕的各项视觉参数,包括亮度、对比度及色彩表现,同时负责屏幕的启动与关闭流程。在C/C++环境下开发此类驱动需掌握若干关键技术要素: 首先,硬件寄存器的访问依赖于输入输出操作,常借助内存映射技术实现,例如在Linux平台使用`mmap()`函数将寄存器地址映射至用户内存空间,进而通过指针进行直接操控。 其次,驱动需处理可能产生的中断信号,如帧缓冲区更新完成事件,因此需注册相应的中断服务例程以实时响应硬件事件。 第三,为确保多线程或进程环境下共享资源(如寄存器)的安全访问,必须引入互斥锁、信号量等同步机制来避免数据竞争。 第四,在基于设备树的嵌入式Linux系统中,驱动需依据设备树节点中定义的硬件配置信息完成初始化与参数设置。 第五,帧缓冲区的管理至关重要,驱动需维护该内存区域,保证图像数据准确写入并及时刷新至显示面板。 第六,为优化能耗,驱动应集成电源管理功能,通过寄存器控制实现屏幕的休眠与唤醒状态切换。 第七,针对不同显示设备支持的色彩格式差异,驱动可能需执行色彩空间转换运算以适配目标设备的色彩输出要求。 第八,驱动开发需熟悉液晶显示控制器与主处理器间的通信接口协议,如SPI、I2C或LVDS等串行或并行传输标准。 最后,完成代码编写后需进行系统化验证,包括基础显示功能测试、性能评估及异常处理能力检验,确保驱动稳定可靠。 该源代码集合为深入理解液晶显示控制原理及底层驱动开发实践提供了重要参考,通过剖析代码结构可掌握硬件驱动设计的具体方法与技术细节。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
<think> 这段代码是RSA密钥生成过程中生成素数p的部分,并确保该素数满足与公钥指数e互质的条件。以下是对代码的逐行解释: ### 代码解释: ```c /* make p */ if (err == MP_OKAY) { // 如果之前的操作没有错误,则进入生成素数p的流程 do { // 生成一个随机的素数p,长度为size/16字节(即size/2比特) // rng是随机数生成器,key->heap用于内存分配 err = rand_prime(p, size/16, rng, key->heap); /* size in bytes/2 */ // 如果生成素数成功(err == MP_OKAY),则计算p-1 if (err == MP_OKAY) err = mp_sub_d(p, 1, tmp1); /* tmp1 = p-1 */ // 如果上一步成功,计算gcd(p-1, e),结果存入tmp2 if (err == MP_OKAY) err = mp_gcd(tmp1, tmp3, tmp2); /* tmp2 = gcd(p-1, e) */ } while (err == MP_OKAY && mp_cmp_d(tmp2, 1) != 0); // 当满足以下条件时循环继续: // 1. 前面的操作都成功(err == MP_OKAY) // 2. gcd(p-1, e) != 1(即tmp2不等于1) } ``` ### 详细说明: 1. **`rand_prime` 函数**: - 作用:生成一个指定长度的随机素数,并将其存储在变量 `p` 中。 - 参数 `size/16`:因为 `size` 是密钥的总比特长度,RSA需要两个长度大致相等的素数。所以每个素数的长度大约是总长度的一半。这里 `size/16` 将比特长度转换为字节长度(因为1字节=8比特,所以除以16得到的是半字节数?注意:实际上,`size`是比特数,`size/16`得到的是字节数的一半,即 `size/2` 比特。例如,对于2048位的RSA密钥,每个素数应该是1024位,即128字节,所以 `size/16` 为2048/16=128字节)。 2. **`mp_sub_d(p, 1, tmp1)`**: - 作用:计算 `p-1` 并将结果存储在 `tmp1` 中。这是一个大数减法操作。 3. **`mp_gcd(tmp1, tmp3, tmp2)`**: - 作用:计算 `tmp1`(即 `p-1`)和 `tmp3`(存储的是公钥指数 `e`)的最大公约数(GCD),结果存储在 `tmp2` 中。 - 为什么需要这个GCD?在RSA中,要求公钥指数 `e` 与欧拉函数 `φ(n)=(p-1)(q-1)` 互质。由于 `φ(n)` 是两个素数减1的乘积,所以必须保证 `e` 与 `p-1` 互质,同时与 `q-1` 互质。这里通过检查 `gcd(p-1, e)==1` 来确保 `e` 和 `p-1` 互质。 4. **循环条件**: - 如果 `gcd(p-1, e) != 1`(即 `mp_cmp_d(tmp2, 1) != 0`),则当前生成的素数 `p` 不满足条件,需要重新生成一个新的素数并再次检查。 - 循环会一直持续,直到找到一个满足条件的素数 `p`(即 `gcd(p-1, e)==1`)或者出现错误(`err != MP_OKAY`)。 ### 目的: 这段代码的目的是生成一个满足以下条件的素数 `p`: - 是一个随机素数(通过 `rand_prime` 生成)。 - 满足 `gcd(p-1, e) == 1`,即 `e` 和 `p-1` 互质。 ### 优化点: 在之前的问题中,我们讨论过优化方法:当 `e` 是较小的素数(如65537)时,可以用模运算代替GCD运算。优化后的代码如下: ```c do { err = rand_prime(p, size/16, rng, key->heap); if (err != MP_OKAY) break; // 优化:使用模运算代替GCD mp_digit r; err = mp_mod_d(p, (mp_digit)e, &r); // 计算 p mod e if (err != MP_OKAY) break; if (r == 1) { // 如果 p mod e == 1,则 e 整除 p-1(因为 p-1 mod e = (p mod e) - 1 = 0) // 不满足条件,继续循环 continue; } else { // 满足条件,退出循环 break; } } while (1); ``` 这种优化基于以下数学原理: 当 `e` 是素数时,`gcd(p-1, e) == 1` 当且仅当 `e` 不整除 `p-1`,即 `(p-1) mod e != 0`。 由于 `(p-1) mod e = (p mod e - 1) mod e`,所以当 `p mod e != 1` 时,条件满足。 ### 注意事项: - 优化方法仅当 `e` 是素数时有效(通常RSA中 `e` 取65537,是素数)。 - 如果 `e` 不是素数,则必须使用原始的GCD方法。 --- §§相关问题§§: 1. 在RSA密钥生成中,为什么要求 `e` 与 `(p-1)(q-1)` 互质? 2. `rand_prime` 函数通常如何实现?它使用了哪些素数测试方法? 3. 除了互质条件,生成素数 `p` 和 `q` 还有哪些安全要求? 4. 如果 `e` 是一个合数(例如在某些自定义场景中),应如何修改上述代码? </think>这段代码是 RSA 密钥生成过程中**生成并验证素数 `p`** 的关键部分,其主要作用是确保生成的素数 `p` 满足 RSA 算法的数学要求。以下是对代码的逐行详细解释: ### 代码功能详解 ```c /* make p */ // 开始生成素数 p 的流程 if (err == MP_OKAY) { // 检查之前操作是否成功(无错误) do { // 使用循环确保生成符合条件的素数 // 步骤1: 生成随机素数 err = rand_prime(p, size/16, rng, key->heap); /* size in bytes/2 */ // rand_prime: 生成指定位数的随机素数 // - p: 存储生成的素数 // - size/16: 素数位数(比特数除以16转换为字节长度) // - rng: 随机数生成器 // - key->heap: 内存分配上下文 if (err == MP_OKAY) // 如果素数生成成功 // 步骤2: 计算 p-1 err = mp_sub_d(p, 1, tmp1); /* tmp1 = p-1 */ // mp_sub_d: 大数减法(p - 1 = tmp1) // 为后续数学验证做准备 if (err == MP_OKAY) // 如果上一步成功 // 步骤3: 计算 gcd(p-1, e) err = mp_gcd(tmp1, tmp3, tmp2); /* tmp2 = gcd(p-1, e) */ // mp_gcd: 计算最大公约数(GCD) // - tmp1 = p-1 // - tmp3 = e(公钥指数,通常为65537) // - tmp2 = gcd(p-1, e) } while (err == MP_OKAY && mp_cmp_d(tmp2, 1) != 0); /* e divdes p-1 */ // 循环条件: // 1. 所有操作成功 (err == MP_OKAY) // 2. gcd(p-1, e) ≠ 1 (mp_cmp_d(tmp2, 1) != 0) } ``` ### 关键数学原理 1. **为什么需要计算 `gcd(p-1, e)`?** - RSA 要求公钥指数 `e` 与欧拉函数 `φ(n) = (p-1)(q-1)` 互质 - 由于 `φ(n)` 是 `(p-1)` 和 `(q-1)` 的乘积,必须确保: ```math \gcd(p-1, e) = 1 \quad \text{且} \quad \gcd(q-1, e) = 1 ``` - 如果 `gcd(p-1, e) > 1`,会导致 `d = e⁻¹ mod φ(n)` 不存在 2. **循环的作用** - 如果 `gcd(p-1, e) ≠ 1`,当前生成的素数 `p` 无效 - 循环会重新生成新的素数 `p`,直到找到满足条件的素数 - 示例:当 `e=65537` 时,大约 1/65537 的概率需要重新生成 ### 算法流程图解 ```mermaid flowchart TD A[开始生成p] --> B[rand_prime生成随机素数p] B --> C[计算tmp1 = p-1] C --> D[计算tmp2 = gcd(p-1, e)] D --> E{检查gcd == 1?} E -->|是| F[接受p, 结束] E -->|否| B[重新生成p] ``` ### 时间复杂度分析 1. **`rand_prime`**:最耗时操作(Miller-Rabin测试),复杂度 O(k·log³p) - k: 安全性参数(测试轮数) - p: 素数大小(通常 1024-4096 位) 2. **`mp_sub_d`**:线性时间 O(log p) 3. **`mp_gcd`**:欧几里得算法,O(log²p) ### 安全意义 1. **防止密钥无效**:确保私钥 `d` 存在 2. **避免弱密钥**:防止 `e` 与 `φ(n)` 有公因子导致的安全漏洞 3. **满足标准要求**:符合 PKCS#1 和 FIPS 186-4 标准 ### 实际运行示例 假设: - `e = 65537` - 第一次生成 `p = 65539` ``` p-1 = 65538 gcd(65538, 65537) = 1 # 有效素数 ``` - 第二次生成 `p = 131074` ``` p-1 = 131073 gcd(131073, 65537) = 65537 > 1 # 无效,需重新生成 ``` 这段代码确保 RSA 密钥的数学基础牢固,是密钥生成过程中最关键的安全检查之一。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值