You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

椭圆曲线密码学C语言实现解密异常求助:疑点减法错误

解决ECC解密失败的问题

我仔细看了你的代码,确实有几个关键细节出了问题,导致解密无法得到预期结果。下面逐一分析并给出修复方案:

1. 原点判断逻辑错误

你把(0,0)作为无穷远点的替代,但在add()函数里的判断条件写错了:

// 错误:只要x或y为0就误判为原点
if (A[0]==0 || A[1]==0) return B;
if (B[0]==0 || B[1]==0) return A;

正确的逻辑是只有当x和y同时为0时,才是原点,否则只是曲线上的普通点。修改为:

if (A[0] == 0 && A[1] == 0) return B;
if (B[0] == 0 && B[1] == 0) return A;

2. 标量乘法修改了输入点(严重BUG)

你的sclr_mult()函数在执行过程中直接修改了传入的P数组,这会破坏原有的基点/公钥点数据,导致后续所有依赖这些点的计算全部出错。比如第一次调用sclr_mult(random, Pbase)后,Pbase已经变成了翻倍多次后的点,而非最初的基点。

修复方法是在函数内部创建输入点的临时副本,用副本进行翻倍操作:

int * sclr_mult(int k,int P[2])//using LSB first algorithm
{
 int *temp,i;
 int *Q = calloc(2,sizeof(int));
 Q[0]=0;
 Q[1]=0;
 // 创建P的临时副本,避免修改原输入点
 int P_copy[2] = {P[0], P[1]};
 for(i=31;i>=0;i--)
 {
 if((k>>i)&1) break;
 }
 for(int j=0;j<=i;j++)
 {
 if((k>>j)&1)
 {
 temp=add(Q,P_copy);
 Q[0]=*temp;
 Q[1]=*(temp+1);
 }
 temp=add(P_copy,P_copy);
 P_copy[0]=*temp;
 P_copy[1]=*(temp+1);
 }
 return Q;
}

3. 模运算处理不严谨

计算斜率和点坐标时,需要确保所有运算结果都在模p的范围内,尤其是负数的情况。比如B[1]-A[1]可能为负,应该先调整为正再计算逆元;所有乘法、减法后的结果都要取模并修正符号:

修改add()函数中的关键计算部分:

// 点加法(A≠B)的斜率计算
x = ((B[1] - A[1] + p) % p) * inverse( (B[0] - A[0] + p) % p );
x %= p; // 确保斜率在模p范围内

// 点加倍(A=B)的斜率计算
x = ((3 * (A[0] * A[0] % p) + a) % p) * inverse( (2 * A[1]) % p );
x %= p;

同时,坐标计算后的取模要更严谨:

// 点加法的x坐标
C[0] = (x*x - A[0] - B[0]) % p;
// 点加倍的x坐标
C[0] = (x*x - 2*A[0]) % p;

// 统一修正负数坐标
if (C[0] < 0) C[0] += p;
if (C[1] < 0) C[1] += p;

4. 额外的内存泄漏问题

你的代码中使用calloc分配内存,但没有释放,虽然是概念验证,但养成好习惯很重要。比如在main函数中,每次调用sclr_multadd后返回的指针,使用完可以用free(temp)释放。

修复后的预期结果

应用这些修改后,运行代码应该能正确解密出原始消息点:

  • 基点选points[5](即(3,10)
  • 公钥计算为11*(3,10),结果为(24, 7)
  • 解密时会正确抵消掉加密时添加的kPb项,最终还原出原始消息点(3,10)

其他建议

  • 计算椭圆曲线的阶数,验证标量乘法的结果是否在合理范围内,避免使用无效的标量值。
  • 把无穷远点的定义封装成常量(比如#define INF_X 0 #define INF_Y 0),避免硬编码判断条件,提高代码可读性。
  • 所有算术运算都先取模,防止整数溢出(即使现在用小p值,对后续优化也有帮助)。

内容的提问来源于stack exchange,提问作者Shubham Annigeri

火山引擎 最新活动