OpenSSL密码库算法笔记——第5.4.11章 椭圆曲线的多倍点运算——未知点

本小节来讨论kP的计算方法,这里的P为椭圆曲线上的点,k为一个整数。这个运算就是多倍点运算,它是椭圆曲线密码算法的核心。设曲线的阶为#E(Fp)=nh,其中n为素数,是点P在椭圆曲线上的阶,h为相伴因子,是一个很小的数,k∈[1, n-1]。

        多倍点计算主要是通过对k的不同表示来实现的。有对k进行二进制展开的平方和算法(平方和算法的思想参见§4.1.1);有对k进行NAF展开的二进制NAF算法;有结合NAF和窗口算法的wNAF算法(窗口算法的思想参见§4.1.2)。下面将重点介绍高效的wNAF算法。

        wNAF算法中的NAF是一种表示形式,而w表示的是窗口算法的宽度。

具体说来,NAF是系数k的一种“不相邻表示形式”【non-adjacent form】,简称NAF,它将k表示成带符号的比特形式k=∑ki2i,这里的ki ∈{0, ±1}。任一正整数k都有唯一一个NAF表示形式,记为NAF(k)。NAF展开式要求任意连续的两个比特中最多只能有一个比特非零,即不可能出现连续的两个比特都非零的情况。NAF表示的长度最多比二进制表示的长度多1,且其非零比特数将减少。如果将非零比特数和全部比特数的比值称为密度,则NAF展开的密度为1/3,比二进制展开的密度1/2小。

例如39的二进制展开形式为(1, 0, 0, 1, 1, 1),如用NAF展开则得到NAF(39)=(1, 0, 1, 0, 0, -1)。

既然窗口算法的思想可以用在二进制展开中(见§4.1.2),那为什么不能将窗口算法的思想用在NAF展开形式中呢?由此,就有了wNAF展开形式。它将k表示成带符号的“比特”形式k=∑ki2i,这里的ki为奇数且| ki | < 2w-1,w是窗口大小。同样地,任一正整数k都有唯一一个wNAF表示形式,记为NAFw(k),且NAF2(k)=NAF(k)。wNAF展开要求任意连续的w个比特中最多只能有一个比特非零。与NAF表示一样,wNAF展开的长度最多比二进制的长度多1。wNAF展开的密度为1/(w+1),相比之下,NAF展开的密度为1/3,二进制展开的密度为1/2。计算wNAF展开形式的算法如下:

        Step2.1中的k mods 2w是指k模2w的(可负)最小剩余u,即

 …………(5.13)

        下面来看看wNAF算法怎样用于多被点的计算之中。设系数k的wNAF展开已经计算出来。

首先,预计算出一些点:Pi ←iP,i=1, 3, 5, …, 2w-1-1;然后,再类似于窗口算法那样计算kP。具体算法如下。

        在预计算Step1中需要花费1D+2w-2A,这里的D表示二倍点运算,A表示点的普通加法;在Step3中需要花费mD+m/(w+1)A。

实现代码中做多倍点计算时采用的就是这个wNAF算法。

───────────────────────────────────────

int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[])

功能:    多个点的多倍点运算

输入:    groupscalarnum【点points []的个数】,points[]scalars[]

输出:    r scalar×group->generator(scalars[0]×points[0]scalars[1]×points[1]+……)

返回:    1【正常】 or 0【出错】

出处:    ec_lib.c

调用:        int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[])

备注:    调用的ec_wNAF_mul采用的是wNAF算法,但不同的点采用的宽度可能不同。

───────────────────────────────────────

        特别地,当points []的个数num退化为1的时候,即

      ……(5.14)

就可以使用简化形式:

───────────────────────────────────────

int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,const EC_POINT *point, const BIGNUM *p_scalar)

功能:    两个点的多倍点运算

输入:    groupg_scalarpointp_scalar

输出:    r g_scalar×group->generatorp_scalar×point

返回:    1【正常】 or 0【出错】

出处:    ec_lib.c

调用:        int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[])

───────────────────────────────────────

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单的示例代码实现SM2椭圆曲线公钥加密算法: ``` #include <iostream> #include <string> #include <cstring> #include <cmath> #include <vector> using namespace std; // SM2椭圆曲线参数 const int N = 256; // 字节数 const int n = 32; // 字节数组长度 const int w = 8; // 字节位数 const int p = 0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff; // 素数 const int a = 0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc; // 系数a const int b = 0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92d; // 系数b const int gx = 0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be171; // 基Gx const int gy = 0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0; // 基Gy const int n0 = 1 << w; // 字节的最高位 // 将整数转换为字节数组 vector<unsigned char> int2byte(int x) { vector<unsigned char> res(n); for (int i = 0; i < n; i++) { res[i] = x % n0; x >>= w; } return res; } // 将字节数组转换为整数 int byte2int(vector<unsigned char> bytes) { int res = 0; for (int i = n - 1; i >= 0; i--) { res <<= w; res += bytes[i]; } return res; } // 模运算 int mod(int a, int b) { return (a % b + b) % b; } // 逆元运算 int inv(int a, int b) { int b0 = b, t, q; int x0 = 0, x1 = 1; if (b == 1) return 1; while (a > 1) { q = a / b; t = b, b = a % b, a = t; t = x0, x0 = x1 - q * x0, x1 = t; } if (x1 < 0) x1 += b0; return x1; } // 运算 vector<int> add(vector<int> P, vector<int> Q) { vector<int> R(3); int lambda; if (P[0] == Q[0] && P[1] == Q[1]) { lambda = mod(3 * P[0] * P[0] + a, p) * inv(2 * P[1], p) % p; } else { lambda = (Q[1] - P[1]) * inv(Q[0] - P[0], p) % p; } R[0] = mod(lambda * lambda - P[0] - Q[0], p); R[1] = mod(lambda * (P[0] - R[0]) - P[1], p); R[2] = 1; return R; } // 运算 vector<int> mul(int k, vector<int> P) { vector<int> R = P; k--; while (k > 0) { if (k % 2 == 1) { R = add(R, P); } P = add(P, P); k /= 2; } return R; } // 生成公钥 vector<vector<int>> genPublicKey(int d) { vector<vector<int>> publicKey; vector<int> P(3); P[0] = gx; P[1] = gy; P[2] = 1; publicKey.push_back(mul(d, P)); return publicKey; } // SM2加密 vector<unsigned char> sm2Encrypt(string plaintext, vector<vector<int>> publicKey) { // 将明文转换为字节数组 vector<unsigned char> M(n); memcpy(&M[0], plaintext.c_str(), plaintext.length()); // 生成随机数k int k = rand() % (p - 1) + 1; // 计算C1 = [k]G vector<int> G(3); G[0] = gx; G[1] = gy; G[2] = 1; vector<int> C1 = mul(k, G); // 计算S = [h]PB和C2 = M^T ^ kP vector<int> P = publicKey[0]; vector<int> S = mul(h, P); vector<unsigned char> C2(n); for (int i = 0; i < n; i++) { C2[i] = M[i] ^ ((k * P[0] + S[0]) >> (w * i) & (n0 - 1)); } // 拼接密文 vector<unsigned char> ciphertext; ciphertext.insert(ciphertext.end(), int2byte(C1[0]).begin(), int2byte(C1[0]).end()); ciphertext.insert(ciphertext.end(), int2byte(C1[1]).begin(), int2byte(C1[1]).end()); ciphertext.insert(ciphertext.end(), C2.begin(), C2.end()); return ciphertext; } int main() { // 生成公钥 int d = 1234567890; // 私钥 vector<vector<int>> publicKey = genPublicKey(d); // 加密 string plaintext = "Hello, world!"; vector<unsigned char> ciphertext = sm2Encrypt(plaintext, publicKey); // 输出密文 cout << "Ciphertext: "; for (unsigned char c : ciphertext) { printf("%02x", c); } cout << endl; return 0; } ``` 需要注意的是,以上代码仅为演示用途,实际使用时需要进行更加严格的错误处理和安全措施。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值