ECC算法与ECDSA签名、SM2签名、SM2加密、ElGamal加密的C/C++实现

一、原理

ECDSA

SM2

ElGamal

二、C/C++实现

头文件

POperation.h

#ifndef POPERATION_H
#define POPERATION_H

// 定义点的结构
typedef struct {
    long long x;
    long long y;
} Point;

// 定义椭圆曲线的结构
typedef struct {
    long long a, b; // 曲线参数 y^2 = x^3 + ax + b
    long long p;    // 有限域的素数
} EllipticCurve;

// 模逆运算的函数声明
long long mod_inverse(long long a, long long m);

// 点加运算的函数声明
Point point_add(Point P, Point Q, EllipticCurve ec);

// 点乘运算的函数声明
Point point_multiply(long long scalar, Point P, EllipticCurve ec);

#endif // POPERATION_H

ECDSA.h

#ifndef ECDSA_H
#define ECDSA_H

#include "POperation.h" // 包含 EllipticCurve 和 Point 结构的定义

// ECDSA签名函数声明
void ecdsa_sign(char* message, long long d, EllipticCurve ec, Point G, long long n, long long* r, long long* s);

// ECDSA验证函数声明
int ecdsa_verify(char* message, Point Q, EllipticCurve ec, Point G, long long n, long long r, long long s);

// 简单哈希函数声明
long long simple_hash(char* message);

#endif // ECDSA_H

ElGamal.h

#ifndef ELGAMAL_H
#define ELGAMAL_H

#include <gmpxx.h>
#include <vector>
#include <iostream>

// 检测原根
bool is_primitive_root(const mpz_class& g, const mpz_class& p);

// 生成大质数和其原根
void generate_prime_and_primitive_root(mpz_class& p, mpz_class& g);

// 生成公钥和私钥
void generate_keys(mpz_class& p, mpz_class& g, mpz_class& y, mpz_class& x);

// 加密
void encrypt(const mpz_class& p, const mpz_class& g, const mpz_class& y, const mpz_class& m, mpz_class& c1, mpz_class& c2);

// 解密
void decrypt(const mpz_class& p, const mpz_class& x, const mpz_class& c1, const mpz_class& c2, mpz_class& m);

#endif  // ELGAMAL_H

SM2.h

#pragma once
#ifndef SM2_H
#define SM2_H

#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <iostream>
#include <cstring>

// 错误处理函数
void handleOpenSSLErrors();

// 生成SM2密钥对
EVP_PKEY* generateSM2KeyPair();

// SM2签名
bool sm2Sign(EVP_PKEY* pkey, const unsigned char* data, size_t dataLen, unsigned char** sig, size_t* sigLen);

#endif // SM2_H

源文件

POperation.cpp

#include <stdio.h>
#include <stdlib.h>
#include "POperation.h"

//typedef struct {
//    long long x;
//    long long y;
//} Point;
//
//typedef struct {
//    long long a, b; // 曲线参数 y^2 = x^3 + ax + b
//    long long p;    // 有限域的素数
//} EllipticCurve;

// 模逆运算
long long mod_inverse(long long a, long long m) {
    long long m0 = m, t, q;
    long long x0 = 0, x1 = 1;

    if (m == 1) {
        return 0;
    }

    while (a > 1) {
        q = a / m;
        t = m;
        m = a % m, a = t;
        t = x0;
        x0 = x1 - q * x0;
        x1 = t;
    }

    if (x1 < 0) {
        x1 += m0;
    }

    return x1;
}

// 点加运算
Point point_add(Point P, Point Q, EllipticCurve ec) {
    Point R;

    if (P.x == Q.x && P.y == Q.y) { // 点倍运算
        if (P.y == 0) {
            R.x = 0;
            R.y = 0;
            return R;
        }

        long long s = (3 * P.x * P.x + ec.a) * mod_inverse(2 * P.y, ec.p) % ec.p;
        R.x = (s * s - 2 * P.x) % ec.p;
        R.y = (s * (P.x - R.x) - P.y) % ec.p;
    }
    else { // 一般点加运算
        if (P.x == Q.x) {
            R.x = 0;
            R.y = 0;
            return R;
        }

        long long s = (Q.y - P.y) * mod_inverse(Q.x - P.x, ec.p) % ec.p;
        R.x = (s * s - P.x - Q.x) % ec.p;
        R.y = (s * (P.x - R.x) - P.y) % ec.p;
    }

    R.x = (R.x + ec.p) % ec.p;
    R.y = (R.y + ec.p) % ec.p;
    return R;
}

// 点乘运算
Point point_multiply(long long scalar, Point P, EllipticCurve ec) {
    Point result = { 0, 0 }; // 无穷远点
    Point temp = P;

    while (scalar != 0) {
        if (scalar % 2 != 0) {
            if (result.x == 0 && result.y == 0) {
                result = temp;
            }
            else {
                result = point_add(result, temp, ec);
            }
        }

        temp = point_add(temp, temp, ec);
        scalar /= 2;
    }

    return result;
}

ECDSA.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "POperation.h"  // 假设之前定义的椭圆曲线结构和函数在这个头文件中
#include "ECDSA.h"

// 简单的哈希函数(仅用于示例)
long long simple_hash(char* message) {
    long long hash = 0;
    while (*message) {
        hash = (hash * 31 + *message) % LONG_MAX;
        message++;
    }
    return hash;
}

void ecdsa_sign(char* message, long long d, EllipticCurve ec, Point G, long long n, long long* r, long long* s) {
    long long z = simple_hash(message); // 获取消息的哈希值

    long long k, x1, y1;
    do {
        k = rand() % (n - 1) + 1;      // 随机数 k
        Point kG = point_multiply(k, G, ec); // 计算 k * G
        x1 = kG.x; y1 = kG.y;

        *r = x1 % n;
    } while (*r == 0);

    long long k_inv = mod_inverse(k, n);
    *s = (k_inv * (z + *r * d)) % n;

    if (*s == 0) {
        ecdsa_sign(message, d, ec, G, n, r, s); // 如果 s 为 0,则重新签名
    }
}


int ecdsa_verify(char* message, Point Q, EllipticCurve ec, Point G, long long n, long long r, long long s) {
    if (r <= 0 || r >= n || s <= 0 || s >= n) {
        return 0; // 验证 r 和 s 是否在合法范围内
    }

    long long z = simple_hash(message); // 获取消息的哈希值

    long long w = mod_inverse(s, n);
    long long u1 = (z * w) % n;
    long long u2 = (r * w) % n;

    Point u1G = point_multiply(u1, G, ec);
    Point u2Q = point_multiply(u2, Q, ec);
    Point P = point_add(u1G, u2Q, ec);

    if (P.x == LONG_MAX && P.y == LONG_MAX) {
        return 0; // 如果 P 是无穷远点
    }

    return (P.x % n == r); // 验证 r 是否等于 P.x mod n
}





ElGamal.cpp

#include <gmpxx.h>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <iostream>
#include "ElGamal.h"

using namespace std;

// 检测原根
bool is_primitive_root(const mpz_class& g, const mpz_class& p) {
    vector<mpz_class> factors;
    mpz_class phi = p - 1;
    mpz_class n = phi;

    // 计算p - 1的所有质因数
    for (mpz_class i = 2; i * i <= n; ++i) {
        if (n % i == 0) {
            factors.push_back(i);
            while (n % i == 0)
                n /= i;
        }
    }
    if (n > 1)
        factors.push_back(n);

    for (mpz_class factor : factors) {
        mpz_class res;
        mpz_powm(res.get_mpz_t(), g.get_mpz_t(), mpz_class(phi / factor).get_mpz_t(), p.get_mpz_t());
        if (res == 1)
            return false;
    }
    return true;
}



// 生成大质数和其原根
void generate_prime_and_primitive_root(mpz_class& p, mpz_class& g) {
    // 生成大质数
    gmp_randclass rr(gmp_randinit_default);
    rr.seed(time(NULL));
    p = rr.get_z_bits(512);
    mpz_nextprime(p.get_mpz_t(), p.get_mpz_t());

    // 寻找原根
    g = 2;
    while (!is_primitive_root(g, p))
        g += 1;
}

// 生成公钥和私钥
void generate_keys(mpz_class& p, mpz_class& g, mpz_class& y, mpz_class& x) {
    // 随机生成大质数p和其原根g
    // 由于寻找原根的效率问题,这里简化为固定的质数和原根
    p = 23;  // 实际应用中应该是大质数
    g = 5;   // 实际应用中应该是p的原根

    // 随机选择私钥x
    x = rand() % (p - 2) + 1;

    // 计算公钥y
    mpz_powm(y.get_mpz_t(), g.get_mpz_t(), x.get_mpz_t(), p.get_mpz_t());
}

// 加密
void encrypt(const mpz_class& p, const mpz_class& g, const mpz_class& y, const mpz_class& m, mpz_class& c1, mpz_class& c2) {
    mpz_class k = rand() % (p - 1) + 1;  // 随机选择k
    mpz_class s;

    // 计算c1
    mpz_powm(c1.get_mpz_t(), g.get_mpz_t(), k.get_mpz_t(), p.get_mpz_t());
    // 计算s (共享密钥)
    mpz_powm(s.get_mpz_t(), y.get_mpz_t(), k.get_mpz_t(), p.get_mpz_t());
    // 计算c2
    c2 = (m * s) % p;
}

// 解密
void decrypt(const mpz_class& p, const mpz_class& x, const mpz_class& c1, const mpz_class& c2, mpz_class& m) {
    mpz_class s, s_inv;

    // 计算s (共享密钥)
    mpz_powm(s.get_mpz_t(), c1.get_mpz_t(), x.get_mpz_t(), p.get_mpz_t());
    // 计算s的逆
    mpz_invert(s_inv.get_mpz_t(), s.get_mpz_t(), p.get_mpz_t());
    // 解密消息
    m = (c2 * s_inv) % p;
}

SM2.cpp

#include "openssl/evp.h"
#include "openssl/ec.h"
#include "openssl/pem.h"

#include <iostream>
#include <cstring>
#include "SM2.h"


// 错误处理
void handleOpenSSLErrors() {
    ERR_print_errors_fp(stderr);
    abort
    ();
}

// 生成SM2密钥对
EVP_PKEY* generateSM2KeyPair() {
    EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
    EVP_PKEY* pkey = nullptr;
    if (EVP_PKEY_keygen_init(pctx) <= 0) {
        handleOpenSSLErrors();
    }

    if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_sm2) <= 0) {
        handleOpenSSLErrors();
    }

    if (EVP_PKEY_keygen(pctx, &pkey) <= 0) {
        handleOpenSSLErrors();
    }

    EVP_PKEY_CTX_free(pctx);
    return pkey;
}

// SM2签名
bool sm2Sign(EVP_PKEY* pkey, const unsigned char* data, size_t dataLen, unsigned char** sig, size_t* sigLen) {
    EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
    EVP_PKEY_CTX* pctx = nullptr;
    bool result = false;
    if (EVP_DigestSignInit(mdctx, &pctx, EVP_sm3(), nullptr, pkey) <= 0) {
        handleOpenSSLErrors();
    }

    if (EVP_DigestSign(mdctx, nullptr, sigLen, data, dataLen) <= 0) {
        handleOpenSSLErrors();
    }

    *sig = (unsigned char*)OPENSSL_malloc(*sigLen);
    if (EVP_DigestSign(mdctx, *sig, sigLen, data, dataLen) <= 0) {
        handleOpenSSLErrors();
    }
    else {
        result = true;
    }

    EVP_MD_CTX_free(mdctx);
    return result;
}

ECCtest.cpp

 main.c
//#include "ecc.h"
//#include <stdio.h>
//
//int main() {
//    EllipticCurve ec = {/* 初始化曲线参数 */ };
//    Point p = {/* 初始化点 */ };
//
//    // 测试点乘
//    Point result = point_multiply(2, p, ec);
//    printf("Result of Point Multiply: (%lld, %lld)\n", result.x, result.y);
//
//    // 测试ECDSA签名和验证
//
//    return 0;
//}

#include<cstdio>
#include <gmp.h>
#include <time.h>
//#include "openssl/ec.h"
//#include "openssl/evp.h"

#include "POperation.h"
#include "SM2.h"
#include "ECDSA.h"
#include "ElGamal.h"

#define P "23"
#define G "5"


int main() {
     示例:定义椭圆曲线参数和点
    //EllipticCurve ec = { 1, 6, 11 }; // 曲线 y² = x³ + x + 6 (mod 11)
    //Point P = { 2, 4 }; // 初始点
     执行点乘运算
    //Point Q = point_multiply(3, P, ec);
    //printf("3P = (%lld, %lld)\n", Q.x, Q.y);

     执行点加运算
    //Point R = point_add(P, Q, ec);
    //printf("P + 3P = (%lld, %lld)\n", R.x, R.y);



    //auto key = EC_KEY_new_by_curve_name(NID_secp256k1);
    //EC_KEY_generate_key(key);

    //unsigned char* pub_key = nullptr;

    //auto size = i2o_ECPublicKey(key, &pub_key);
    //for (int i = 0; i < size; ++i) {
    //    std::printf("%02x", pub_key[i]);
    //}

    // EC_KEY_free(key);









    ECDSA sign and verify
    // // 定义椭圆曲线参数(简化版secp256k1)
    //EllipticCurve ec = { 0, 7, 17 };  // y^2 = x^3 + 7 (mod 17)
    //Point G = { 1, 1 };              // 基点G
    //long long n = 19;              // 基点的阶

     定义私钥(随机选取,但必须小于n)
    //long long d = 13; // 私钥

     计算公钥
    //Point Q = point_multiply(d, G, ec);

     要签名的消息
    //char message[] = "Hello, ECDSA!";

     签名
    //long long r, s;
    //ecdsa_sign(message, d, ec, G, n, &r, &s);
    //printf("Signature:\n");
    //printf("r: %lld\n", r);
    //printf("s: %lld\n", s);

     验证
    //int valid = ecdsa_verify(message, Q, ec, G, n, r, s);
    //if (valid) {
    //    printf("Signature is valid.\n");
    //}
    //else {
    //    printf("Signature is invalid.\n");
    //}



    SM2加密和签名
    //OpenSSL_add_all_algorithms();
    //ERR_load_crypto_strings();
     生成密钥对
    //EVP_PKEY* pkey = generateSM2KeyPair();

     要签名的数据
    //const char* data = "Hello, SM2!";
    //unsigned char* sig = nullptr;
    //size_t sigLen = 0;

     签名
    //if (sm2Sign(pkey, (const unsigned char*)data, strlen(data), &sig, &sigLen)) {
    //    std::cout << "Signature successful!" << std::endl;
    //}
    //else {
    //    std::cout << "Signature failed!" << std::endl;
    //}

     清理
    //OPENSSL_free(sig);
    //EVP_PKEY_free(pkey);
    //EVP_cleanup();
    //ERR_free_strings();




    //ElGamal测试
    mpz_t p, g, x, y, m, c1, c2, decrypted_m;
    mpz_inits(p, g, x, y, m, c1, c2, decrypted_m, NULL);

    // 设置p和g
    mpz_set_str(p, P, 10);
    mpz_set_str(g, G, 10);

    // 生成密钥
    generate_keys(p, g, x, y);
    gmp_printf("Public Key (y): %Zd\n", y);
    gmp_printf("Private Key (x): %Zd\n", x);

    // 设置消息m
    mpz_set_ui(m, 13); // 设置一个示例消息

    // 加密消息
    encrypt(p, g, y, m, c1, c2);
    gmp_printf("Encrypted Message (c1, c2): (%Zd, %Zd)\n", c1, c2);

    // 解密消息
    decrypt(p, x, c1, c2, decrypted_m);
    gmp_printf("Decrypted Message: %Zd\n", decrypted_m);

    mpz_clears(p, g, x, y, m, c1, c2, decrypted_m, NULL);


    return 0;
}


三、运行结果

POperation测试

SM2测试

ECDSA测试

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是巴巴布莱特呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值