【加解密與C】非對稱加解密(三)ECC橢圓曲線

ECC橢圓曲線的基本概念

橢圓曲線密碼學(Elliptic Curve Cryptography,ECC)是一種基于橢圓曲線數學的公鑰密碼體制。與傳統的RSA相比,ECC在相同安全級別下使用更短的密鑰,計算效率更高,適用于資源受限的環境。

橢圓曲線的數學定義通常表示為: [ y^2 = x^3 + ax + b ] 其中 (a) 和 (b) 是滿足 (4a^3 + 27b^2 \neq 0) 的常數,以避免曲線出現奇異點。

ECC的核心運算

橢圓曲線的核心運算包括點加法(Point Addition)和標量乘法(Scalar Multiplication)。點加法用于定義曲線上兩個點的加法運算,標量乘法則是通過重復點加法實現。

點加法的幾何意義:

  • 若 (P) 和 (Q) 是曲線上兩個不同的點,連接 (P) 和 (Q) 的直線與曲線交于第三點 (R),則 (P + Q = -R)(對稱點)。
  • 若 (P = Q),則通過 (P) 的切線與曲線交于 (R),此時 (2P = -R)。

標量乘法用于密鑰生成和加密/解密過程: [ k \cdot P = \underbrace{P + P + \cdots + P}_{k \text{次}} ]

ECC的安全性

ECC的安全性基于橢圓曲線離散對數問題(ECDLP):給定曲線上的點 (P) 和 (Q = k \cdot P),求解 (k) 是計算困難的。目前沒有已知的多項式時間算法可以解決ECDLP。

與RSA相比,ECC的優勢在于:

  • 更短的密鑰長度(例如256位ECC密鑰相當于3072位RSA密鑰的安全性)。
  • 更快的計算速度和更低的資源消耗。

ECC的應用場景

ECC廣泛應用于以下領域:

  • 數字簽名(如ECDSA)。
  • 密鑰交換(如ECDH)。
  • 物聯網(IoT)設備的安全通信。
  • 區塊鏈技術(如比特幣和以太坊使用ECC生成地址)。

ECC的注意事項

使用ECC時需注意以下問題:

  • 選擇標準化的橢圓曲線(如NIST推薦的曲線或SECP256k1)。
  • 避免使用自定義曲線,可能存在安全隱患。
  • 確保隨機數生成器的質量,避免密鑰泄露。

ECC因其高效性和安全性,已成為現代密碼學的重要組成部分。

ECC.h

#ifndef _ECC_H_
#define _ECC_H_
#include <stdint.h>// 定義256位大整數結構
typedef struct {uint32_t d[8]; // 小端序存儲: d[0]是最低32位
} uint256_t;// 橢圓曲線點結構
typedef struct {uint256_t x;uint256_t y;int infinity; // 是否為無窮遠點
} Point;// 密鑰生成
void ecc_keygen(uint256_t* private_key, Point* public_key);// ECDSA簽名
void ecdsa_sign(const uint256_t* private_key, const uint256_t* hash, uint256_t* r, uint256_t* s);// ECDSA驗簽
int ecdsa_verify(const Point* public_key, const uint256_t* hash, const uint256_t* r, const uint256_t* s);// ECC加密
void ecc_encrypt(const Point* public_key, const uint8_t* plain, size_t len, Point* c1, uint8_t* c2);// ECC解密
void ecc_decrypt(const uint256_t* private_key, const Point* c1, const uint8_t* c2, size_t len, uint8_t* plain);
#endif

ECC.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ECC.h"// secp256k1曲線參數
static const uint256_t P = {{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFC2F}};
static const uint256_t A = {{0}};
static const uint256_t B = {{7, 0, 0, 0, 0, 0, 0, 0}};
static const Point G = {{{0x79BE667E, 0xF9DCBBAC, 0x55A06295, 0xCE870B07, 0x029BFCDB, 0x2DCE28D9, 0x59F2815B, 0x16F81798}},{{0x483ADA77, 0x26A3C465, 0x5DA4FBFC, 0x0E1108A8, 0xFD17B448, 0xA6855419, 0x9C47D08F, 0xFB10D4B8}},0
};
static const uint256_t N = {{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xBAAEDCE6, 0xAF48A03B, 0xBFD25E8C, 0xD0364141}};// 比較兩個大整數是否相等
static int uint256_equal(const uint256_t* a, const uint256_t* b) {for (int i = 0; i < 8; i++) {if (a->d[i] != b->d[i]) return 0;}return 1;
}// 判斷大整數是否為0
static int uint256_is_zero(const uint256_t* a) {for (int i = 0; i < 8; i++) {if (a->d[i] != 0) return 0;}return 1;
}// 大整數復制
static void uint256_copy(uint256_t* dest, const uint256_t* src) {memcpy(dest, src, sizeof(uint256_t));
}// 模加: result = (a + b) mod P
static void uint256_add(const uint256_t* a, const uint256_t* b, uint256_t* result) {uint64_t carry = 0;for (int i = 0; i < 8; i++) {uint64_t sum = (uint64_t)a->d[i] + b->d[i] + carry;result->d[i] = (uint32_t)sum;carry = sum >> 32;}// 如果結果大于P,則減去Pif (carry || !uint256_equal(result, &P) && (result->d[7] > P.d[7] || (result->d[7] == P.d[7] && result->d[6] > P.d[6]) || (result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] > P.d[5]) ||(result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] == P.d[5] && result->d[4] > P.d[4]) ||(result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] == P.d[5] && result->d[4] == P.d[4] && result->d[3] > P.d[3]) ||(result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] == P.d[5] && result->d[4] == P.d[4] && result->d[3] == P.d[3] && result->d[2] > P.d[2]) ||(result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] == P.d[5] && result->d[4] == P.d[4] && result->d[3] == P.d[3] && result->d[2] == P.d[2] && result->d[1] > P.d[1]) ||(result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] == P.d[5] && result->d[4] == P.d[4] && result->d[3] == P.d[3] && result->d[2] == P.d[2] && result->d[1] == P.d[1] && result->d[0] >= P.d[0]))) {uint256_t temp = *result;uint64_t borrow = 0;for (int i = 0; i < 8; i++) {uint64_t diff = (uint64_t)temp.d[i] - P.d[i] - borrow;result->d[i] = (uint32_t)diff;borrow = (diff >> 32) ? 1 : 0;}}
}// 模減: result = (a - b) mod P
static void uint256_sub(const uint256_t* a, const uint256_t* b, uint256_t* result) {uint64_t borrow = 0;for (int i = 0; i < 8; i++) {uint64_t diff = (uint64_t)a->d[i] - b->d[i] - borrow;result->d[i] = (uint32_t)diff;borrow = (diff >> 63) ? 1 : 0;}// 如果結果為負,則加上Pif (borrow) {uint256_t temp = *result;uint64_t carry = 0;for (int i = 0; i < 8; i++) {uint64_t sum = (uint64_t)temp.d[i] + P.d[i] + carry;result->d[i] = (uint32_t)sum;carry = sum >> 32;}}
}// 模乘: result = (a * b) mod P
static void uint256_mul(const uint256_t* a, const uint256_t* b, uint256_t* result) {uint64_t product[16] = {0};// 計算乘積for (int i = 0; i < 8; i++) {uint64_t carry = 0;for (int j = 0; j < 8; j++) {uint64_t temp = product[i+j] + (uint64_t)a->d[i] * b->d[j] + carry;product[i+j] = temp & 0xFFFFFFFF;carry = temp >> 32;}product[i+8] = carry;}// 模P約簡 (使用secp256k1的特殊形式)for (int i = 15; i >= 8; i--) {uint64_t carry = 0;for (int j = 0; j < 8; j++) {uint64_t temp = (uint64_t)product[i-8+j] + (product[i] * P.d[j]) + carry;product[i-8+j] = temp & 0xFFFFFFFF;carry = temp >> 32;}if (i < 15) {product[i] = carry;}}// 復制結果for (int i = 0; i < 8; i++) {result->d[i] = (uint32_t)product[i];}// 最終模約簡if (uint256_equal(result, &P) || !uint256_equal(result, &P) && (result->d[7] > P.d[7] || (result->d[7] == P.d[7] && result->d[6] > P.d[6]) || (result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] > P.d[5]) ||(result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] == P.d[5] && result->d[4] > P.d[4]) ||(result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] == P.d[5] && result->d[4] == P.d[4] && result->d[3] > P.d[3]) ||(result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] == P.d[5] && result->d[4] == P.d[4] && result->d[3] == P.d[3] && result->d[2] > P.d[2]) ||(result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] == P.d[5] && result->d[4] == P.d[4] && result->d[3] == P.d[3] && result->d[2] == P.d[2] && result->d[1] > P.d[1]) ||(result->d[7] == P.d[7] && result->d[6] == P.d[6] && result->d[5] == P.d[5] && result->d[4] == P.d[4] && result->d[3] == P.d[3] && result->d[2] == P.d[2] && result->d[1] == P.d[1] && result->d[0] >= P.d[0]))) {uint256_t temp = *result;uint64_t borrow = 0;for (int i = 0; i < 8; i++) {uint64_t diff = (uint64_t)temp.d[i] - P.d[i] - borrow;result->d[i] = (uint32_t)diff;borrow = (diff >> 63) ? 1 : 0;}}
}// 模逆元: result = a^{-1} mod P (使用擴展歐幾里得算法)
static void uint256_inv(const uint256_t* a, uint256_t* result) {uint256_t u = *a;uint256_t v = P;uint256_t x1 = {{1,0,0,0,0,0,0,0}};uint256_t x2 = {{0,0,0,0,0,0,0,0}};uint256_t one = { {1,0,0,0,0,0,0,0} };while (!uint256_equal(&u, &one) && !uint256_equal(&v, &one)) {while ((u.d[0] & 1) == 0) { // u為偶數// u = u / 2for (int i = 7; i >= 0; i--) {if (i > 0 && (u.d[i] & 1)) {u.d[i-1] |= 0x80000000;}u.d[i] >>= 1;}// x1 = x1 / 2if (x1.d[0] & 1) {uint256_add(&x1, &P, &x1);}for (int i = 7; i >= 0; i--) {if (i > 0 && (x1.d[i] & 1)) {x1.d[i-1] |= 0x80000000;}x1.d[i] >>= 1;}}while ((v.d[0] & 1) == 0) { // v為偶數// v = v / 2for (int i = 7; i >= 0; i--) {if (i > 0 && (v.d[i] & 1)) {v.d[i-1] |= 0x80000000;}v.d[i] >>= 1;}// x2 = x2 / 2if (x2.d[0] & 1) {uint256_add(&x2, &P, &x2);}for (int i = 7; i >= 0; i--) {if (i > 0 && (x2.d[i] & 1)) {x2.d[i-1] |= 0x80000000;}x2.d[i] >>= 1;}}if (u.d[7] < v.d[7] || (u.d[7] == v.d[7] && u.d[6] < v.d[6]) || (u.d[7] == v.d[7] && u.d[6] == v.d[6] && u.d[5] < v.d[5]) ||(u.d[7] == v.d[7] && u.d[6] == v.d[6] && u.d[5] == v.d[5] && u.d[4] < v.d[4]) ||(u.d[7] == v.d[7] && u.d[6] == v.d[6] && u.d[5] == v.d[5] && u.d[4] == v.d[4] && u.d[3] < v.d[3]) ||(u.d[7] == v.d[7] && u.d[6] == v.d[6] && u.d[5] == v.d[5] && u.d[4] == v.d[4] && u.d[3] == v.d[3] && u.d[2] < v.d[2]) ||(u.d[7] == v.d[7] && u.d[6] == v.d[6] && u.d[5] == v.d[5] && u.d[4] == v.d[4] && u.d[3] == v.d[3] && u.d[2] == v.d[2] && u.d[1] < v.d[1]) ||(u.d[7] == v.d[7] && u.d[6] == v.d[6] && u.d[5] == v.d[5] && u.d[4] == v.d[4] && u.d[3] == v.d[3] && u.d[2] == v.d[2] && u.d[1] == v.d[1] && u.d[0] < v.d[0])) {uint256_sub(&v, &u, &v);uint256_sub(&x2, &x1, &x2);} else {uint256_sub(&u, &v, &u);uint256_sub(&x1, &x2, &x1);}}if (uint256_equal(&u, &one)) {uint256_copy(result, &x1);} else {uint256_copy(result, &x2);}if (result->d[7] & 0x80000000) {uint256_add(result, &P, result);}
}// 橢圓曲線點運算
static int point_is_zero(const Point* p) {return p->infinity;
}static void point_set_zero(Point* p) {p->infinity = 1;
}// 點加倍: result = 2 * P
static void point_double(const Point* p, Point* result) {if (point_is_zero(p)) {point_set_zero(result);return;}// λ = (3x2 + a) / (2y)uint256_t lambda, numerator, denominator, temp;// 計算分子: 3x2 + auint256_mul(&p->x, &p->x, &temp);uint256_t three = {{3,0,0,0,0,0,0,0}};uint256_mul(&temp, &three, &numerator);uint256_add(&numerator, &A, &numerator);// 計算分母: 2yuint256_t two = {{2,0,0,0,0,0,0,0}};uint256_mul(&p->y, &two, &denominator);// 計算λ = 分子 / 分母uint256_inv(&denominator, &temp);uint256_mul(&numerator, &temp, &lambda);// 計算新點坐標// xr = λ2 - 2xuint256_mul(&lambda, &lambda, &temp);uint256_mul(&p->x, &two, &denominator);uint256_sub(&temp, &denominator, &result->x);// yr = λ(x - xr) - yuint256_sub(&p->x, &result->x, &temp);uint256_mul(&lambda, &temp, &temp);uint256_sub(&temp, &p->y, &result->y);result->infinity = 0;
}// 點加法: result = P + Q
static void point_add(const Point* p, const Point* q, Point* result) {if (point_is_zero(p)) {*result = *q;return;}if (point_is_zero(q)) {*result = *p;return;}// 處理相同點的情況if (uint256_equal(&p->x, &q->x)) {if (uint256_equal(&p->y, &q->y)) {point_double(p, result);return;} else {point_set_zero(result);return;}}// λ = (yq - yp) / (xq - xp)uint256_t lambda, numerator, denominator, temp;uint256_sub(&q->y, &p->y, &numerator);uint256_sub(&q->x, &p->x, &denominator);uint256_inv(&denominator, &temp);uint256_mul(&numerator, &temp, &lambda);// xr = λ2 - xp - xquint256_mul(&lambda, &lambda, &temp);uint256_sub(&temp, &p->x, &temp);uint256_sub(&temp, &q->x, &result->x);// yr = λ(xp - xr) - ypuint256_sub(&p->x, &result->x, &temp);uint256_mul(&lambda, &temp, &temp);uint256_sub(&temp, &p->y, &result->y);result->infinity = 0;
}// 標量乘法: result = k * P
static void point_mul(const uint256_t* k, const Point* p, Point* result) {Point r;point_set_zero(&r);Point temp_point = *p;for (int i = 0; i < 256; i++) {int word_index = i / 32;int bit_index = i % 32;if ((k->d[word_index] >> bit_index) & 1) {if (point_is_zero(&r)) {r = temp_point;} else {point_add(&r, &temp_point, &r);}}Point new_point;point_double(&temp_point, &new_point);temp_point = new_point;}*result = r;
}// 密鑰生成
void ecc_keygen(uint256_t* private_key, Point* public_key) {// 生成隨機私鑰 (1 < d < N-1)do {for (int i = 0; i < 8; i++) {private_key->d[i] = rand() ^ (rand() << 16);}} while (uint256_equal(private_key, &N) || uint256_is_zero(private_key) || private_key->d[7] >= N.d[7] || (private_key->d[7] == N.d[7] && private_key->d[6] >= N.d[6]) ||(private_key->d[7] == N.d[7] && private_key->d[6] == N.d[6] && private_key->d[5] >= N.d[5]) ||(private_key->d[7] == N.d[7] && private_key->d[6] == N.d[6] && private_key->d[5] == N.d[5] && private_key->d[4] >= N.d[4]) ||(private_key->d[7] == N.d[7] && private_key->d[6] == N.d[6] && private_key->d[5] == N.d[5] && private_key->d[4] == N.d[4] && private_key->d[3] >= N.d[3]) ||(private_key->d[7] == N.d[7] && private_key->d[6] == N.d[6] && private_key->d[5] == N.d[5] && private_key->d[4] == N.d[4] && private_key->d[3] == N.d[3] && private_key->d[2] >= N.d[2]) ||(private_key->d[7] == N.d[7] && private_key->d[6] == N.d[6] && private_key->d[5] == N.d[5] && private_key->d[4] == N.d[4] && private_key->d[3] == N.d[3] && private_key->d[2] == N.d[2] && private_key->d[1] >= N.d[1]) ||(private_key->d[7] == N.d[7] && private_key->d[6] == N.d[6] && private_key->d[5] == N.d[5] && private_key->d[4] == N.d[4] && private_key->d[3] == N.d[3] && private_key->d[2] == N.d[2] && private_key->d[1] == N.d[1] && private_key->d[0] >= N.d[0]));// 公鑰 = 私鑰 * Gpoint_mul(private_key, &G, public_key);
}// ECDSA簽名
void ecdsa_sign(const uint256_t* private_key, const uint256_t* hash, uint256_t* r, uint256_t* s) {uint256_t k = { 0 };Point kG;do {// 生成隨機kfor (int i = 0; i < 8; i++) {k.d[i] = rand() ^ (rand() << 16);}// 計算 r = (kG).x mod Npoint_mul(&k, &G, &kG);uint256_copy(r, &kG.x);while (!uint256_equal(r, &N) && (r->d[7] > N.d[7] || (r->d[7] == N.d[7] && r->d[6] > N.d[6]) || (r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] > N.d[5]) ||(r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] == N.d[5] && r->d[4] > N.d[4]) ||(r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] == N.d[5] && r->d[4] == N.d[4] && r->d[3] > N.d[3]) ||(r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] == N.d[5] && r->d[4] == N.d[4] && r->d[3] == N.d[3] && r->d[2] > N.d[2]) ||(r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] == N.d[5] && r->d[4] == N.d[4] && r->d[3] == N.d[3] && r->d[2] == N.d[2] && r->d[1] > N.d[1]) ||(r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] == N.d[5] && r->d[4] == N.d[4] && r->d[3] == N.d[3] && r->d[2] == N.d[2] && r->d[1] == N.d[1] && r->d[0] >= N.d[0]))) {uint256_sub(r, &N, r);}} while (uint256_is_zero(r));// 計算 s = (hash + r*d) * k^{-1} mod Nuint256_t tmp1, kinv;uint256_mul(r, private_key, &tmp1);   // r * duint256_add(&tmp1, hash, &tmp1);       // hash + r*duint256_inv(&k, &kinv);               // k^{-1}uint256_mul(&tmp1, &kinv, s);          // s = (hash + r*d) * k^{-1}while (!uint256_equal(s, &N) && (s->d[7] > N.d[7] || (s->d[7] == N.d[7] && s->d[6] > N.d[6]) || (s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] > N.d[5]) ||(s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] == N.d[5] && s->d[4] > N.d[4]) ||(s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] == N.d[5] && s->d[4] == N.d[4] && s->d[3] > N.d[3]) ||(s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] == N.d[5] && s->d[4] == N.d[4] && s->d[3] == N.d[3] && s->d[2] > N.d[2]) ||(s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] == N.d[5] && s->d[4] == N.d[4] && s->d[3] == N.d[3] && s->d[2] == N.d[2] && s->d[1] > N.d[1]) ||(s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] == N.d[5] && s->d[4] == N.d[4] && s->d[3] == N.d[3] && s->d[2] == N.d[2] && s->d[1] == N.d[1] && s->d[0] >= N.d[0]))) {uint256_sub(s, &N, s);}
}// ECDSA驗簽
int ecdsa_verify(const Point* public_key, const uint256_t* hash, const uint256_t* r, const uint256_t* s) {if (uint256_is_zero(r) || uint256_is_zero(s) || !uint256_equal(r, &N) && (r->d[7] > N.d[7] || (r->d[7] == N.d[7] && r->d[6] > N.d[6]) || (r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] > N.d[5]) ||(r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] == N.d[5] && r->d[4] > N.d[4]) ||(r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] == N.d[5] && r->d[4] == N.d[4] && r->d[3] > N.d[3]) ||(r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] == N.d[5] && r->d[4] == N.d[4] && r->d[3] == N.d[3] && r->d[2] > N.d[2]) ||(r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] == N.d[5] && r->d[4] == N.d[4] && r->d[3] == N.d[3] && r->d[2] == N.d[2] && r->d[1] > N.d[1]) ||(r->d[7] == N.d[7] && r->d[6] == N.d[6] && r->d[5] == N.d[5] && r->d[4] == N.d[4] && r->d[3] == N.d[3] && r->d[2] == N.d[2] && r->d[1] == N.d[1] && r->d[0] >= N.d[0])) ||!uint256_equal(s, &N) && (s->d[7] > N.d[7] || (s->d[7] == N.d[7] && s->d[6] > N.d[6]) || (s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] > N.d[5]) ||(s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] == N.d[5] && s->d[4] > N.d[4]) ||(s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] == N.d[5] && s->d[4] == N.d[4] && s->d[3] > N.d[3]) ||(s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] == N.d[5] && s->d[4] == N.d[4] && s->d[3] == N.d[3] && s->d[2] > N.d[2]) ||(s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] == N.d[5] && s->d[4] == N.d[4] && s->d[3] == N.d[3] && s->d[2] == N.d[2] && s->d[1] > N.d[1]) ||(s->d[7] == N.d[7] && s->d[6] == N.d[6] && s->d[5] == N.d[5] && s->d[4] == N.d[4] && s->d[3] == N.d[3] && s->d[2] == N.d[2] && s->d[1] == N.d[1] && s->d[0] >= N.d[0]))) {return 0;}uint256_t w;uint256_inv(s, &w);  // w = s^{-1} mod Nuint256_t u1, u2;uint256_mul(hash, &w, &u1);  // u1 = hash * w mod Nuint256_mul(r, &w, &u2);     // u2 = r * w mod NPoint p1, p2;point_mul(&u1, &G, &p1);     // u1 * Gpoint_mul(&u2, public_key, &p2); // u2 * QPoint res;point_add(&p1, &p2, &res);   // 計算點 (x, y)if (point_is_zero(&res)) {return 0;}// 驗證 r == x mod Nuint256_t x = res.x;while (!uint256_equal(&x, &N) && (x.d[7] > N.d[7] || (x.d[7] == N.d[7] && x.d[6] > N.d[6]) || (x.d[7] == N.d[7] && x.d[6] == N.d[6] && x.d[5] > N.d[5]) ||(x.d[7] == N.d[7] && x.d[6] == N.d[6] && x.d[5] == N.d[5] && x.d[4] > N.d[4]) ||(x.d[7] == N.d[7] && x.d[6] == N.d[6] && x.d[5] == N.d[5] && x.d[4] == N.d[4] && x.d[3] > N.d[3]) ||(x.d[7] == N.d[7] && x.d[6] == N.d[6] && x.d[5] == N.d[5] && x.d[4] == N.d[4] && x.d[3] == N.d[3] && x.d[2] > N.d[2]) ||(x.d[7] == N.d[7] && x.d[6] == N.d[6] && x.d[5] == N.d[5] && x.d[4] == N.d[4] && x.d[3] == N.d[3] && x.d[2] == N.d[2] && x.d[1] > N.d[1]) ||(x.d[7] == N.d[7] && x.d[6] == N.d[6] && x.d[5] == N.d[5] && x.d[4] == N.d[4] && x.d[3] == N.d[3] && x.d[2] == N.d[2] && x.d[1] == N.d[1] && x.d[0] >= N.d[0]))) {uint256_sub(&x, &N, &x);}return uint256_equal(&x, r);
}// ECC加密
void ecc_encrypt(const Point* public_key, const uint8_t* plain, size_t len, Point* c1, uint8_t* c2) {uint256_t k = { 0 };Point kQ;// 生成臨時密鑰kdo {for (int i = 0; i < 8; i++) {k.d[i] = rand() ^ (rand() << 16);}} while (uint256_is_zero(&k));// c1 = k * Gpoint_mul(&k, &G, c1);// 共享密鑰 S = k * Qpoint_mul(&k, public_key, &kQ);// 使用S.x的低32位作為XOR密鑰uint32_t key = kQ.x.d[0];for (size_t i = 0; i < len; i++) {c2[i] = plain[i] ^ (key & 0xFF);key = (key >> 8) | (key << 24); // 循環移位}
}// ECC解密
void ecc_decrypt(const uint256_t* private_key, const Point* c1, const uint8_t* c2, size_t len, uint8_t* plain) {// 計算共享密鑰 S = d * c1Point S;point_mul(private_key, c1, &S);// 使用S.x的低32位作為XOR密鑰uint32_t key = S.x.d[0];for (size_t i = 0; i < len; i++) {plain[i] = c2[i] ^ (key & 0xFF);key = (key >> 8) | (key << 24); // 循環移位}
}

※說明:代碼僅從原理上實現了ecc的加解密、簽名、驗簽,并未充分驗證其正確性和完整性,且性能較差,僅供自學習時參考。若應用于生產環境,請使用openssl等三方庫。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88185.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88185.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88185.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

力扣網編程150題:加油站(貪心解法)

一. 簡介 前面一篇文章使用暴力解法來解決力扣網150 題目&#xff1a;加油站。文章如下&#xff1a; 力扣網編程150題&#xff1a;加油站&#xff08;暴力解法&#xff09;-CSDN博客 暴力解法就是遍歷了所有元素作為起始點的可能&#xff0c;算法時間復雜度為 O(n*n)&#x…

windwos 設置redis長久密碼不生效

1、設置長久密碼redis.windows.conf 文件修改對應的設置密碼2、啟動時設置對應的加載配置文件

物聯網(IoT)領域存在多種協議

物聯網&#xff08;IoT&#xff09;領域存在多種協議&#xff0c;主要是因為不同的應用場景對通信的需求差異很大&#xff0c;包括實時性、帶寬、功耗、設備兼容性、安全性等。以下從協議多樣性的原因和你提到的具體協議&#xff08;如 dc3-driver-* 模塊&#xff09;展開說明&…

二、encoders

文章目錄一、batch_encoder (用于 BFV)1. 概述2. 數學原理3. 使用方法4. 代碼示例二、ckks_encoder (用于 CKKS)在 1. bfv_basics.cpp 中&#xff0c;我們展示了如何使用BFV方案執行非常簡單的計算。計算是在 plain_modulus 參數的模下執行的&#xff0c;并且 只使用了 BFV 明文…

數據一致性解決方案總結

數據一致性解決方案總結 我們在系統中&#xff0c;主要進行了數據冗余&#xff0c;那么就會帶來數據一致性的問題。常見的數據一致性問題有&#xff1a;數據庫主從同步延遲導致的讀數據不一致&#xff1b;數據庫主主之間數據的不一致&#xff1b;緩存和數據庫之間的數據不一致。…

17.Spring Boot的Bean詳解(新手版)

文章目錄1. 什么是Bean&#xff1f;從零開始理解1.1 Bean的定義1.2 為什么需要Bean&#xff1f;1.3 Bean vs 普通對象的區別2. Spring容器&#xff1a;Bean的家2.1 什么是Spring容器&#xff1f;2.2 容器的工作流程3. Bean的聲明方式詳解3.1 使用Component及其專門化注解3.1.1 …

cherryStudio electron因為環境問題無法安裝解決方法或打包失敗解決方法

$env:ELECTRON_MIRROR"https://npmmirror.com/mirrors/electron/"; $env:ELECTRON_CUSTOM_DIR"{{ version }}"; yarn install1. 上面是關于electron安裝失敗的解決方法. 也可以通過到git上下面包,解壓后,放到對應的目錄下面,并把里面的build文件夾刪除, b…

微服務架構中數據一致性保證機制深度解析

在微服務架構中&#xff0c;數據一致性是分布式系統設計的核心挑戰。由于服務拆分后數據自治&#xff08;每個服務獨立數據庫&#xff09;&#xff0c;跨服務操作的一致性保障需突破傳統單體事務的局限。本文從一致性模型、核心解決方案、技術實現及面試高頻問題四個維度&#…

【Gin】HTTP 請求調試器

文章目錄 項目概述代碼功能詳解1. 導入必要的包2. 主函數和路由設置3. 請求信息捕獲4. 請求參數和頭信息5. 請求體處理5.1 JSON 數據處理5.2 表單數據處理5.3 Multipart 表單數據處理5.4 其他類型數據處理6. 構造響應對象7. 返回 JSON 響應功能特點使用場景完整代碼項目概述 這…

物聯網(IoT)領域的協議

物聯網&#xff08;IoT&#xff09;領域的通信協議種類繁多&#xff0c;不同協議適用于不同的應用場景&#xff08;如低功耗設備、工業自動化、家庭智能設備等&#xff09;。以下是主要物聯網協議的分類及詳細解釋&#xff1a;一、物聯網協議分類物聯網協議通常分為兩大類&…

專題一_雙指針_四數之和

一&#xff1a;題目解析 題目鏈接&#xff1a;18. 四數之和 - 力扣&#xff08;LeetCode&#xff09; 注&#xff1a;本題是在上題的基礎上講解的&#xff1a;專題一_雙指針_三數之和-CSDN博客 解析&#xff1a;和三數之區別在于找四元組和為targe的數字 而不是0 二&#xff1a…

Spring Boot多數據源配置詳解

Spring Boot多數據源配置詳解 在實際企業開發中&#xff0c;隨著業務復雜度提升&#xff0c;單一數據源已無法滿足所有場景需求。比如&#xff1a;讀寫分離、分庫分表、數據遷移、微服務整合等&#xff0c;這時就需要用到多數據源配置。本文將從原理、配置、常見問題和最佳實踐…

項目進度嚴重依賴關鍵人,如何分散風險

項目進度嚴重依賴關鍵人的風險&#xff0c;可以通過建立知識共享機制、強化團隊協作模式、實施交叉培訓和培養后備人才、優化流程標準化等措施有效分散。其中&#xff0c;實施交叉培訓和培養后備人才尤為重要&#xff0c;通過培養多個成員具備相似的關鍵技能&#xff0c;能夠迅…

【RK3568+PG2L50H開發板實驗例程】FPGA部分 | 以太網傳輸實驗例程

本原創文章由深圳市小眼睛科技有限公司創作&#xff0c;版權歸本公司所有&#xff0c;如需轉載&#xff0c;需授權并注明出處&#xff08;www.meyesemi.com)1.實驗簡介實驗目的&#xff1a;完成 DDR3 的讀寫測試。實驗環境&#xff1a;Window11 PDS2022.2-SP6.4芯片型號&#x…

《每日AI-人工智能-編程日報》--2025年7月9日

介紹:AI 方面1. Manus 通用智能體初成型&#xff0c;開啟 AIAgent 新時代?中泰證券發布研報稱&#xff0c;首款通用型 AI 智能體 Manus 已問世&#xff0c;能夠將復雜任務拆解為可執行的步驟鏈&#xff0c;并在虛擬環境中靈活調用工具&#xff0c;標志著 AI 從 “Reasoner” 走…

MyBatis之數據操作增刪改查基礎全解

目錄 1. ?MyBatis添加數據 1.1. 持久層接口添加方法 1.2. 映射文件添加標簽 1.3. 編寫測試方法 2. ??MyBatis修改數據 2.1. 代碼的優化 2.2. 持久層接口添加方法 2.3. 映射文件添加標簽 2.4. 編寫測試方法 3. &#x1f5d1;?MyBatis刪除數據與根據Id查詢 3.1. 刪…

kbmMemTable Pro 7.82 Delphi 11 源代碼

kbmMemTable Pro 7.82 Delphi 11 源代碼KbmMemTable 是一個用于在 Win 32/64、Mac OS、Android 和 iOS 32/64 應用程序中存儲臨時數據的組件&#xff0c;這些應用程序可以使用 RAD Studio、Delphi、C Builder 或 FPC 等編程語言創建&#xff0c;同時您還可以高速訪問存儲在數據…

LeetCode Hot 100 除自身以外數組的乘積

給你一個整數數組 nums&#xff0c;返回 數組 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘積 。題目數據 保證 數組 nums之中任意元素的全部前綴元素和后綴的乘積都在 32 位 整數范圍內。請 不要使用除法&#xff0c;且在 O(n) 時間復雜度內…

VC Code--常用的配置

原文網址&#xff1a;VC Code--常用的配置-CSDN博客 簡介 本文介紹VC Cod常用的配置。 1.字體大小 整體字體大小 左下角齒輪> Settings> Windows> Window: Zoom Level> 改為&#xff1a;2 編輯器字體大小&#xff08;如果調整了整體字體大小&#xff0c;此處…

大模型驅動的智能體:從GPT-4到o1的能力躍升

大模型驅動的智能體&#xff1a;從GPT-4到o1的能力躍升 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 總有一行代碼&#xff0c;能點亮萬千星辰。 &#x1f50d; 在技術的宇宙中&#xff0c;我愿做永不停歇的探索者。 ? 用代碼丈量世界&#xf…