当前位置:首页>学习笔记>mbedTLS 学习笔记 06 - ECDSA 椭圆曲线数字签名详解

mbedTLS 学习笔记 06 - ECDSA 椭圆曲线数字签名详解

  • 2026-02-01 11:06:13
mbedTLS 学习笔记 06 - ECDSA 椭圆曲线数字签名详解
从比特币到 TLS:椭圆曲线如何守护数字世界的信任

01📖 目录

1.
ECDSA 的前世今生
2.
椭圆曲线数学基础
3.
ECDSA 算法原理
4.
mbedTLS 源码深度剖析
5.
实战案例
6.
常用椭圆曲线详解
7.
安全陷阱与最佳实践
8.
性能优化技巧
9.
常见问题 FAQ
10.
总结与检查清单

021. ECDSA 的前世今生

1.1 为什么需要 ECDSA?

2009 年 1 月 3 日,中本聪挖出比特币创世区块,其中使用的数字签名算法就是 ECDSA (Elliptic Curve Digital Signature Algorithm)。为什么选择 ECDSA 而不是传统的 RSA?
真实场景对比
场景:为一笔比特币交易生成数字签名

RSA-2048:
公钥大小:256 字节
私钥大小:256 字节  
签名大小:256 字节
签名时间:~5ms (嵌入式设备)

ECDSA-256 (secp256k1):
公钥大小:33 字节 (压缩格式)
私钥大小:32 字节
签名大小:64-72 字节
签名时间:~2ms (嵌入式设备)
安全强度:等同于 RSA-3072
ECDSA 的三大优势
1.
更短的密钥:256 位 ECC ≈ 3072 位 RSA 安全强度
2.
更快的速度:签名和验证速度是 RSA 的 2-3 倍
3.
更少的带宽:适合物联网、区块链等资源受限场景

1.2 ECDSA 的发展历程

年份
里程碑事件
1985
Neal Koblitz 和 Victor Miller 独立提出椭圆曲线密码学 (ECC)
1992
ECDSA 算法首次提出
1999
ANSI X9.62 标准发布,ECDSA 成为官方标准
2000
NIST FIPS 186-2 采纳 ECDSA
2005
NSA Suite B 密码套件选择 ECDSA 作为数字签名标准
2009
比特币使用 secp256k1 曲线的 ECDSA
2013
PlayStation 3 因 ECDSA 随机数重用漏洞被破解
2018
TLS 1.3 强制要求支持 ECDSA
2024
mbedTLS 3.6.2 支持 14 种椭圆曲线

1.3 ECDSA 在现实世界的应用

区块链领域
比特币/以太坊:每笔交易都需要 ECDSA 签名验证
2023 年数据:比特币网络每天处理约 30 万笔交易,全部使用 ECDSA
TLS/SSL 通信
# 查看 GitHub 的 TLS 证书
$ openssl s_client -connect github.com:443 | openssl x509 -text
Signature Algorithm: ecdsa-with-SHA384
Public Key Algorithm: id-ecPublicKey
    Public-Key: (256 bit)
    ASN1 OID: prime256v1  # 即 secp256r1
物联网设备
智能门锁:使用 ECDSA 验证手机 APP 的开锁指令
车联网:特斯拉使用 ECDSA 保护车辆固件更新

032. 椭圆曲线数学基础

2.1 什么是椭圆曲线?

椭圆曲线并不是椭圆,而是满足以下方程的点集:
短 Weierstrass 形式 (最常用):
y² = x³ + ax + b  (mod p)
其中 p 是大素数,4a³ + 27b² ≠ 0 (保证曲线光滑)。
可视化示例 (实数域上的 secp256k1 曲线):
y² = x³ +7

      y
|
3|     *
2|   *   *
1| *       *
0+---*-------*----> x
-1|     *   *
-2|       *
-3|
有限域上的椭圆曲线
在密码学中,我们使用有限域 GF(p),曲线上的点是离散的:
# secp256k1 参数
p = 2^256 - 2^32 - 977# 素数模
a = 0
b = 7
# 曲线方程:y² ≡ x³ + 7 (mod p)

2.2 椭圆曲线上的点运算

点加法规则
1.
几何定义 (实数域):
P + Q:过 P 和 Q 作直线,与曲线交于第三点 R’,R’ 关于 x 轴对称得 R = P + Q
P + P (倍点):过 P 作切线,与曲线交于 R’,对称得 R = 2P
代数公式 (有限域):
设 P = (x₁, y₁), Q = (x₂, y₂)

如果 P ≠ Q (点加法):
    λ = (y₂ - y₁) / (x₂ - x₁) mod p
x₃ = λ² - x₁ - x₂ mod p
y₃ = λ(x₁ - x₃) - y₁ mod p
    R = (x₃, y₃)

如果 P = Q (倍点运算):
    λ = (3x₁² + a) / (2y₁) mod p
x₃ = λ² - 2x₁ mod p
y₃ = λ(x₁ - x₃) - y₁ mod p
    R = (x₃, y₃)
标量乘法
P = P + P + ... + P  (k 次)
这是 ECDSA 的核心运算,使用双倍-加法算法优化:
defscalar_mult(k, P):
"""计算 k·P"""
    result = O  # 无穷远点
    addend = P

while k:
if k & 1:  # 如果 k 的最低位是 1
            result = point_add(result, addend)
        addend = point_double(addend)  # 倍点
        k >>= 1

return result

# 时间复杂度:O(log k),约 256 次倍点/加法运算

2.3 椭圆曲线的安全性

离散对数难题 (ECDLP)
已知:P (基点), Q = k·P (公钥)
求解:k (私钥)

在椭圆曲线上,这个问题是计算困难的!
安全强度对比
曲线大小
安全位数
等效 RSA
破解时间估算
160 位
80 位
1024 位
可行 (已破解)
224 位
112 位
2048 位
2^112 年
256 位
128 位
3072 位
2^128 年
384 位
192 位
7680 位
2^192 年
521 位
256 位
15360 位
2^256 年

043. ECDSA 算法原理

3.1 密钥生成

步骤
1.
选择椭圆曲线参数 (p, a, b, G, n)
G:基点 (生成元)
n:基点的阶 (G 的倍数循环周期)
生成私钥:
d ← random(1, n-1)  # 256 位随机数
计算公钥:
Q = d·G  # 椭圆曲线标量乘法
mbedTLS 实现
// 生成 ECDSA 密钥对
mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx);

// 使用 secp256r1 曲线
mbedtls_ecdsa_genkey(&ctx, MBEDTLS_ECP_DP_SECP256R1, 
                     mbedtls_ctr_drbg_random, &ctr_drbg);

// ctx.d 是私钥 (256 位整数)
// ctx.Q 是公钥 (椭圆曲线上的点)

3.2 签名生成 (Sign)

输入
消息哈希 H(m) (通常是 SHA-256)
私钥 d
输出
签名 (r, s)
算法步骤 (SEC1 4.1.3):
1. 计算消息哈希:
   e = H(m)  # 例如 SHA-256(m)

2. 截断哈希 (如果需要):
   如果 len(e) > len(n),则截断 e 的高位

3. 生成随机数 k:
   k ← random(1n-1)  # 每次签名必须不同!

4. 计算临时公钥:
   (x, y) = k·G
   r = x modn
   如果 r = 0,返回步骤 3

5. 计算签名的第二部分:
   s = k⁻¹(e + r·d) modn
   如果 s = 0,返回步骤 3

6. 返回签名 (r, s)
关键点
k 必须是真随机数,且每次签名都不同
k 泄露或重用会导致私钥泄露!(PlayStation 3 漏洞)
确定性签名 (RFC 6979)
为避免随机数问题,使用 HMAC-DRBG 生成确定性的 k
k = HMAC-DRBG(私钥 d, 消息哈希 e)
mbedTLS 默认使用确定性签名 (MBEDTLS_ECDSA_DETERMINISTIC)。

3.3 签名验证 (Verify)

输入
消息哈希 H(m)
签名 (r, s)
公钥 Q
输出
验证通过 / 失败
算法步骤 (SEC1 4.1.4):
1. 验证 r, s 在范围内:
   检查 1 ≤ r < n 且 1 ≤ s < n

2. 计算消息哈希:
   e = H(m)

3. 计算辅助值:
   w = s⁻¹ modn
   u₁ = e·w modn
   u₂ = r·w modn

4. 计算验证点:
   (x, y) = u₁·G + u₂·Q  # 双标量乘法

5. 验证:
   如果 (x, y) = O (无穷远点),返回失败
   v = x modn
   如果 v = r,返回成功,否则失败
数学原理
为什么验证有效?

签名时:s = k⁻¹(e + r·d) mod n
推导:  k = s⁻¹(e + r·d) mod n
       k·G = s⁻¹(e + r·d)·G
       k·G = s⁻¹·e·G + s⁻¹·r·d·G
       k·G = u₁·G + u₂·Q  (因为 Q = d·G)

而 r = (k·G).x,所以验证点的 x 坐标应该等于 r

3.4 签名格式

原始格式 (r, s 各 32 字节):
签名 = r || s  (64 字节)
DER 编码 (ASN.1 格式,TLS/X.509 使用):
SEQUENCE {
r  INTEGER,
    s  INTEGER
}

示例 (70 字节):
30440220[32字节r]0220[32字节s]
比特币格式 (DER 变体):
[长度]30[序列长度]02[r长度][r]02[s长度][s]

054. mbedTLS 源码深度剖析

4.1 核心数据结构

ECDSA 上下文 (ecdsa.h):
// ECDSA 上下文就是 ECC 密钥对
typedef mbedtls_ecp_keypair mbedtls_ecdsa_context;

// ECC 密钥对结构
typedefstructmbedtls_ecp_keypair {
    mbedtls_ecp_group grp;      // 椭圆曲线参数
    mbedtls_mpi d;              // 私钥 (大整数)
    mbedtls_ecp_point Q;        // 公钥 (曲线上的点)
} mbedtls_ecp_keypair;
椭圆曲线群 (ecp.h):
typedefstructmbedtls_ecp_group {
    mbedtls_ecp_group_id id;    // 曲线 ID (如 SECP256R1)
    mbedtls_mpi P;              // 素数模
    mbedtls_mpi A;              // 曲线参数 a
    mbedtls_mpi B;              // 曲线参数 b
    mbedtls_ecp_point G;        // 基点 (生成元)
    mbedtls_mpi N;              // 基点的阶
size_t pbits;               // P 的位数
size_t nbits;               // N 的位数
// ... 优化相关字段
} mbedtls_ecp_group;
椭圆曲线点 (ecp.h):
// Jacobian 坐标系:(X, Y, Z) 表示仿射坐标 (X/Z², Y/Z³)
typedefstructmbedtls_ecp_point {
    mbedtls_mpi X;  // X 坐标
    mbedtls_mpi Y;  // Y 坐标
    mbedtls_mpi Z;  // Z 坐标 (Z=0 表示无穷远点, Z=1 表示仿射坐标)
} mbedtls_ecp_point;

4.2 签名生成源码分析

主函数 (ecdsa.c:mbedtls_ecdsa_sign_restartable):
intmbedtls_ecdsa_sign_restartable(
    mbedtls_ecp_group *grp,
    mbedtls_mpi *r, mbedtls_mpi *s,
const mbedtls_mpi *d,           // 私钥
constunsignedchar *buf,        // 消息哈希
size_t blen,
int (*f_rng)(void *, unsignedchar *, size_t),
void *p_rng,
int (*f_rng_blind)(void *, unsignedchar *, size_t),
void *p_rng_blind,
    mbedtls_ecdsa_restart_ctx *rs_ctx)

{
int ret, key_tries, sign_tries;
    mbedtls_ecp_point R;
    mbedtls_mpi k, e, t;

// 1. 检查曲线是否支持 ECDSA
if (!mbedtls_ecdsa_can_do(grp->id) || grp->N.p == NULL) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
    }

// 2. 检查私钥范围:1 ≤ d < n
if (mbedtls_mpi_cmp_int(d, 1) < 0 || 
        mbedtls_mpi_cmp_mpi(d, &grp->N) >= 0) {
return MBEDTLS_ERR_ECP_INVALID_KEY;
    }

    mbedtls_ecp_point_init(&R);
    mbedtls_mpi_init(&k); 
    mbedtls_mpi_init(&e); 
    mbedtls_mpi_init(&t);

    sign_tries = 0;
do {
if (sign_tries++ > 10) {
            ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
goto cleanup;
        }

// 3. 生成临时密钥对 (k, k·G)
        key_tries = 0;
do {
if (key_tries++ > 10) {
                ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
goto cleanup;
            }

// 生成随机 k ∈ [1, n-1]
            MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, &k, 
                                                     f_rng, p_rng));

// 计算 R = k·G
            MBEDTLS_MPI_CHK(mbedtls_ecp_mul_restartable(
                grp, &R, &k, &grp->G,
                f_rng_blind, p_rng_blind, ECDSA_RS_ECP));

// r = R.x mod n
            MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(r, &R.X, &grp->N));
        } while (mbedtls_mpi_cmp_int(r, 0) == 0);  // 确保 r ≠ 0

// 4. 从消息哈希派生 e
        MBEDTLS_MPI_CHK(derive_mpi(grp, &e, buf, blen));

// 5. 生成盲化因子 t (防止时序攻击)
        MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, &t, 
                                                 f_rng_blind, p_rng_blind));

// 6. 计算 s = (e + r·d) / k mod n
//    使用盲化:s = t(e + rd) / (kt) mod n
        MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(s, r, d));      // s = r·d
        MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&e, &e, s));    // e = e + r·d
        MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&e, &e, &t));   // e = t(e+rd)
        MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&k, &k, &t));   // k = kt
        MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&k, &k, &grp->N));
        MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(s, &k, &grp->N)); // s = (kt)⁻¹
        MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(s, s, &e));     // s = t(e+rd)/(kt)
        MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(s, s, &grp->N));
    } while (mbedtls_mpi_cmp_int(s, 0) == 0);  // 确保 s ≠ 0

cleanup:
    mbedtls_ecp_point_free(&R);
    mbedtls_mpi_free(&k); 
    mbedtls_mpi_free(&e); 
    mbedtls_mpi_free(&t);
return ret;
}
关键函数解析
1.
derive_mpi() - 从哈希派生整数:
staticintderive_mpi(const mbedtls_ecp_group *grp, mbedtls_mpi *x,
constunsignedchar *buf, size_t blen)

{
int ret;
size_t n_size = (grp->nbits + 7) / 8;  // n 的字节数
size_t use_size = blen > n_size ? n_size : blen;

// 读取哈希的前 n_size 字节
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(x, buf, use_size));

// 如果哈希位数 > n 的位数,右移截断
if (use_size * 8 > grp->nbits) {
        MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(x, use_size * 8 - grp->nbits));
    }

// 确保 x < n
if (mbedtls_mpi_cmp_mpi(x, &grp->N) >= 0) {
        MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(x, x, &grp->N));
    }

cleanup:
return ret;
}
1.
mbedtls_ecp_gen_privkey() - 生成私钥:
// 生成范围在 [1, N-1] 的随机数
intmbedtls_ecp_gen_privkey(mbedtls_ecp_group *grp,
                            mbedtls_mpi *d,
int (*f_rng)(void *, unsignedchar *, size_t),
void *p_rng)

{
size_t n_size = (grp->nbits + 7) / 8;

do {
// 生成 n_size 字节的随机数
        MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(d, n_size, f_rng, p_rng));

// 确保 d < N
        MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(d, 8 * n_size - grp->nbits));

    } while (mbedtls_mpi_cmp_int(d, 1) < 0 ||  // d >= 1
             mbedtls_mpi_cmp_mpi(d, &grp->N) >= 0);  // d < N

return0;
}

4.3 签名验证源码分析

主函数 (ecdsa.c:mbedtls_ecdsa_verify_restartable):
intmbedtls_ecdsa_verify_restartable(
    mbedtls_ecp_group *grp,
constunsignedchar *buf, size_t blen,  // 消息哈希
const mbedtls_ecp_point *Q,             // 公钥
const mbedtls_mpi *r,                   // 签名 r
const mbedtls_mpi *s,                   // 签名 s
    mbedtls_ecdsa_restart_ctx *rs_ctx)

{
int ret;
    mbedtls_mpi e, s_inv, u1, u2;
    mbedtls_ecp_point R;

    mbedtls_ecp_point_init(&R);
    mbedtls_mpi_init(&e); 
    mbedtls_mpi_init(&s_inv);
    mbedtls_mpi_init(&u1); 
    mbedtls_mpi_init(&u2);

// 1. 验证 r, s 在范围 [1, n-1]
if (mbedtls_mpi_cmp_int(r, 1) < 0 || 
        mbedtls_mpi_cmp_mpi(r, &grp->N) >= 0 ||
        mbedtls_mpi_cmp_int(s, 1) < 0 || 
        mbedtls_mpi_cmp_mpi(s, &grp->N) >= 0) {
        ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
goto cleanup;
    }

// 2. 从消息哈希派生 e
    MBEDTLS_MPI_CHK(derive_mpi(grp, &e, buf, blen));

// 3. 计算 w = s⁻¹ mod n
    MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&s_inv, s, &grp->N));

// 4. 计算 u1 = e·w mod n, u2 = r·w mod n
    MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&u1, &e, &s_inv));
    MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&u1, &u1, &grp->N));

    MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&u2, r, &s_inv));
    MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&u2, &u2, &grp->N));

// 5. 计算 R = u1·G + u2·Q (双标量乘法)
    MBEDTLS_MPI_CHK(mbedtls_ecp_muladd_restartable(
        grp, &R, &u1, &grp->G, &u2, Q, ECDSA_RS_ECP));

// 6. 检查 R 是否为无穷远点
if (mbedtls_ecp_is_zero(&R)) {
        ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
goto cleanup;
    }

// 7. 验证 R.x mod n == r
    MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&R.X, &R.X, &grp->N));

if (mbedtls_mpi_cmp_mpi(&R.X, r) != 0) {
        ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
goto cleanup;
    }

    ret = 0;  // 验证成功

cleanup:
    mbedtls_ecp_point_free(&R);
    mbedtls_mpi_free(&e); 
    mbedtls_mpi_free(&s_inv);
    mbedtls_mpi_free(&u1); 
    mbedtls_mpi_free(&u2);
return ret;
}
性能关键mbedtls_ecp_muladd_restartable() 实现双标量乘法优化。

4.4 确定性签名 (RFC 6979)

为什么需要确定性签名?
传统 ECDSA 的致命弱点:
如果两次签名使用相同的 k:
    签名1:s₁ = k⁻¹(e₁ + r·d)
    签名2:s₂ = k⁻¹(e₂ + r·d)

推导私钥:
    s₁ - s₂ = k⁻¹(e₁ - e₂)
    k = (e₁ - e₂) / (s₁ - s₂)
    d = (s₁·k - e₁) / r
PlayStation 3 漏洞 (2010):
Sony 在固件签名时使用了固定的 k
黑客通过两个签名恢复出私钥
导致 PS3 完全破解
RFC 6979 解决方案
intmbedtls_ecdsa_sign_det_restartable(
    mbedtls_ecp_group *grp,
    mbedtls_mpi *r, mbedtls_mpi *s,
const mbedtls_mpi *d,
constunsignedchar *buf, size_t blen,
mbedtls_md_type_t md_alg,  // 哈希算法
int (*f_rng_blind)(void *, unsignedchar *, size_t),
void *p_rng_blind,
    mbedtls_ecdsa_restart_ctx *rs_ctx)

{
    mbedtls_hmac_drbg_context rng_ctx;
unsignedchar data[2 * MBEDTLS_ECP_MAX_BYTES];
size_t grp_len = (grp->nbits + 7) / 8;
    mbedtls_mpi h;

// 1. 准备 HMAC-DRBG 的种子:私钥 || 消息哈希
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(d, data, grp_len));
    MBEDTLS_MPI_CHK(derive_mpi(grp, &h, buf, blen));
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, data + grp_len, grp_len));

// 2. 初始化 HMAC-DRBG
    MBEDTLS_MPI_CHK(mbedtls_hmac_drbg_seed_buf(&rng_ctx, md_info, 
                                                data, 2 * grp_len));

// 3. 使用 HMAC-DRBG 作为随机数生成器进行签名
    ret = mbedtls_ecdsa_sign_restartable(grp, r, s, d, buf, blen,
                                         mbedtls_hmac_drbg_random, &rng_ctx,
                                         f_rng_blind, p_rng_blind, rs_ctx);

    mbedtls_hmac_drbg_free(&rng_ctx);
return ret;
}
优势
相同消息 + 相同私钥 → 相同签名 (可复现)
无需真随机数生成器
完全消除 k 重用风险

4.5 可重启操作 (Restartable Operations)

问题:在嵌入式设备上,椭圆曲线运算可能需要数百毫秒,阻塞其他任务。
解决方案:mbedTLS 支持将长时间运算分解为多个小步骤:
// 设置最大操作数 (每次调用最多执行 10000 次基本运算)
mbedtls_ecp_set_max_ops(10000);

mbedtls_ecdsa_restart_ctx rs_ctx;
mbedtls_ecdsa_restart_init(&rs_ctx);

int ret;
do {
// 每次调用最多执行 10000 次运算,然后返回
    ret = mbedtls_ecdsa_sign_restartable(
        &grp, &r, &s, &d, hash, hash_len,
        f_rng, p_rng, f_rng, p_rng, &rs_ctx);

if (ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
// 运算未完成,可以处理其他任务
        handle_other_tasks();
    }
while (ret == MBEDTLS_ERR_ECP_IN_PROGRESS);

mbedtls_ecdsa_restart_free(&rs_ctx);
性能数据 (Cortex-M4 @ 168MHz):
曲线
总运算量
单次最大阻塞 (10000 ops)
P-256
~3300 ops
~30 ms
P-384
~9400 ops
~30 ms
P-521
~20000 ops
~30 ms

065. 实战案例

5.1 案例 1:比特币交易签名

场景:为比特币交易生成 ECDSA 签名 (secp256k1 曲线)。
#include"mbedtls/ecdsa.h"
#include"mbedtls/sha256.h"
#include"mbedtls/ctr_drbg.h"
#include"mbedtls/entropy.h"

// 比特币使用 secp256k1 曲线
#define BITCOIN_CURVE MBEDTLS_ECP_DP_SECP256K1

intbitcoin_sign_transaction(constunsignedchar *tx_data, size_t tx_len,
constunsignedchar *private_key_bytes,
unsignedchar *signature, size_t *sig_len)

{
int ret;
    mbedtls_ecdsa_context ctx;
    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
unsignedchar hash[32];

// 1. 初始化
    mbedtls_ecdsa_init(&ctx);
    mbedtls_entropy_init(&entropy);
    mbedtls_ctr_drbg_init(&ctr_drbg);

// 2. 初始化随机数生成器
    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
                                (constunsignedchar *)"bitcoin"7);
if (ret != 0goto cleanup;

// 3. 加载 secp256k1 曲线
    ret = mbedtls_ecp_group_load(&ctx.grp, BITCOIN_CURVE);
if (ret != 0goto cleanup;

// 4. 导入私钥 (32 字节)
    ret = mbedtls_mpi_read_binary(&ctx.d, private_key_bytes, 32);
if (ret != 0goto cleanup;

// 5. 计算公钥 Q = d·G
    ret = mbedtls_ecp_mul(&ctx.grp, &ctx.Q, &ctx.d, &ctx.grp.G,
                         mbedtls_ctr_drbg_random, &ctr_drbg);
if (ret != 0goto cleanup;

// 6. 计算交易的双重 SHA-256 哈希 (比特币标准)
unsignedchar hash1[32];
    mbedtls_sha256(tx_data, tx_len, hash1, 0);  // SHA-256
    mbedtls_sha256(hash1, 32, hash, 0);         // SHA-256 again

// 7. 生成 ECDSA 签名 (确定性,RFC 6979)
    ret = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256,
                                        hash, 32,
                                        signature, 256, sig_len,
                                        mbedtls_ctr_drbg_random, &ctr_drbg);
if (ret != 0goto cleanup;

printf("✅ 比特币交易签名成功!\n");
printf("   签名长度: %zu 字节\n", *sig_len);

cleanup:
    mbedtls_ecdsa_free(&ctx);
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
return ret;
}
验证签名
intbitcoin_verify_transaction(constunsignedchar *tx_data, size_t tx_len,
constunsignedchar *public_key_bytes,
size_t pubkey_len,
constunsignedchar *signature, size_t sig_len)

{
int ret;
    mbedtls_ecdsa_context ctx;
unsignedchar hash[32];

    mbedtls_ecdsa_init(&ctx);

// 1. 加载曲线
    ret = mbedtls_ecp_group_load(&ctx.grp, BITCOIN_CURVE);
if (ret != 0goto cleanup;

// 2. 导入公钥 (压缩格式 33 字节或未压缩 65 字节)
    ret = mbedtls_ecp_point_read_binary(&ctx.grp, &ctx.Q,
                                        public_key_bytes, pubkey_len);
if (ret != 0goto cleanup;

// 3. 计算交易哈希
unsignedchar hash1[32];
    mbedtls_sha256(tx_data, tx_len, hash1, 0);
    mbedtls_sha256(hash1, 32, hash, 0);

// 4. 验证签名
    ret = mbedtls_ecdsa_read_signature(&ctx, hash, 32, signature, sig_len);

if (ret == 0) {
printf("✅ 签名验证成功!交易有效。\n");
    } else {
printf("❌ 签名验证失败!交易无效。\n");
    }

cleanup:
    mbedtls_ecdsa_free(&ctx);
return ret;
}

5.2 案例 2:TLS 证书签名验证

场景:验证 HTTPS 服务器的 ECDSA 证书。
#include"mbedtls/x509_crt.h"
#include"mbedtls/ecdsa.h"

intverify_tls_certificate(constunsignedchar *cert_der, size_t cert_len)
{
int ret;
    mbedtls_x509_crt cert;

    mbedtls_x509_crt_init(&cert);

// 1. 解析 X.509 证书
    ret = mbedtls_x509_crt_parse_der(&cert, cert_der, cert_len);
if (ret != 0) {
printf("❌ 证书解析失败: -0x%04x\n", -ret);
goto cleanup;
    }

// 2. 检查签名算法
if (cert.sig_md == MBEDTLS_MD_SHA256 &&
        cert.sig_pk == MBEDTLS_PK_ECDSA) {
printf("✅ 证书使用 ECDSA-SHA256 签名\n");
    }

// 3. 获取公钥信息
    mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(cert.pk);
const mbedtls_ecp_curve_info *curve_info = 
        mbedtls_ecp_curve_info_from_grp_id(ecp->grp.id);

printf("   曲线: %s (%d 位)\n"
           curve_info->name, curve_info->bit_size);

// 4. 验证证书链 (需要 CA 证书)
    mbedtls_x509_crt ca_cert;
    mbedtls_x509_crt_init(&ca_cert);

// 加载 CA 证书...
// ret = mbedtls_x509_crt_parse_file(&ca_cert, "ca.crt");

uint32_t flags;
    ret = mbedtls_x509_crt_verify(&cert, &ca_cert, NULLNULL
                                  &flags, NULLNULL);

if (ret == 0) {
printf("✅ 证书验证成功!\n");
    } else {
printf("❌ 证书验证失败: 0x%08x\n", flags);
    }

    mbedtls_x509_crt_free(&ca_cert);

cleanup:
    mbedtls_x509_crt_free(&cert);
return ret;
}

5.3 案例 3:嵌入式设备固件签名

场景:IoT 设备验证固件更新的 ECDSA 签名。
#include"mbedtls/ecdsa.h"
#include"mbedtls/sha256.h"

// 设备公钥 (烧录在 ROM 中)
staticconstunsignedchar DEVICE_PUBLIC_KEY[] = {
// secp256r1 公钥 (未压缩格式 65 字节)
0x04,  // 未压缩标志
// X 坐标 (32 字节)
0x6B0x170xD10xF20xE10x2C0x420x47,
// ... (省略)
// Y 坐标 (32 字节)
0x4F0xE30x420xE20xFE0x1A0x7F0x9B,
// ... (省略)
};

typedefstruct {
uint32_t version;
uint32_t size;
uint8_t signature[72];  // DER 编码的 ECDSA 签名
uint8_t data[];         // 固件数据
firmware_package_t;

intverify_firmware_signature(constfirmware_package_t *fw)
{
int ret;
    mbedtls_ecdsa_context ctx;
unsignedchar hash[32];

    mbedtls_ecdsa_init(&ctx);

// 1. 加载 secp256r1 曲线
    ret = mbedtls_ecp_group_load(&ctx.grp, MBEDTLS_ECP_DP_SECP256R1);
if (ret != 0goto cleanup;

// 2. 导入公钥
    ret = mbedtls_ecp_point_read_binary(&ctx.grp, &ctx.Q,
                                        DEVICE_PUBLIC_KEY, 
sizeof(DEVICE_PUBLIC_KEY));
if (ret != 0) {
printf("❌ 公钥导入失败\n");
goto cleanup;
    }

// 3. 计算固件哈希 (包括版本和大小)
    mbedtls_sha256_context sha_ctx;
    mbedtls_sha256_init(&sha_ctx);
    mbedtls_sha256_starts(&sha_ctx, 0);
    mbedtls_sha256_update(&sha_ctx, (uint8_t*)&fw->version, 4);
    mbedtls_sha256_update(&sha_ctx, (uint8_t*)&fw->size, 4);
    mbedtls_sha256_update(&sha_ctx, fw->data, fw->size);
    mbedtls_sha256_finish(&sha_ctx, hash);
    mbedtls_sha256_free(&sha_ctx);

// 4. 验证签名
    ret = mbedtls_ecdsa_read_signature(&ctx, hash, 32,
                                       fw->signature, 72);

if (ret == 0) {
printf("✅ 固件签名验证成功!可以安全更新。\n");
printf("   版本: %u\n", fw->version);
printf("   大小: %u 字节\n", fw->size);
    } else {
printf("❌ 固件签名验证失败!拒绝更新。\n");
printf("   错误码: -0x%04x\n", -ret);
    }

cleanup:
    mbedtls_ecdsa_free(&ctx);
return ret;
}

// 固件更新流程
voidfirmware_update_process(constuint8_t *package, size_t package_len)
{
firmware_package_t *fw = (firmware_package_t*)package;

// 1. 验证签名
if (verify_firmware_signature(fw) != 0) {
printf("⚠️  签名验证失败,中止更新!\n");
return;
    }

// 2. 擦除 Flash
printf("📝 擦除 Flash...\n");
    flash_erase(FIRMWARE_START_ADDR, fw->size);

// 3. 写入新固件
printf("📝 写入固件...\n");
    flash_write(FIRMWARE_START_ADDR, fw->data, fw->size);

// 4. 验证写入
printf("✅ 固件更新完成!\n");

// 5. 重启设备
    system_reset();
}

5.4 案例 4:JWT 令牌签名 (ES256)

场景:使用 ECDSA 签名 JSON Web Token (JWT)。
#include"mbedtls/ecdsa.h"
#include"mbedtls/base64.h"
#include"mbedtls/sha256.h"
#include<string.h>

// JWT Header: {"alg":"ES256","typ":"JWT"}
// JWT Payload: {"sub":"1234567890","name":"John Doe","iat":1516239022}

intcreate_jwt_es256(constchar *payload,
                    mbedtls_ecdsa_context *ctx,
char *jwt_out, size_t *jwt_len)

{
int ret;
unsignedchar hash[32];
unsignedchar signature[MBEDTLS_ECDSA_MAX_LEN];
size_t sig_len;

// JWT Header (ES256)
constchar *header = "{\"alg\":\"ES256\",\"typ\":\"JWT\"}";

// 1. Base64URL 编码 Header
unsignedchar header_b64[256];
size_t header_b64_len;
    ret = mbedtls_base64_encode(header_b64, sizeof(header_b64), 
                                &header_b64_len,
                                (constunsignedchar*)header, strlen(header));
if (ret != 0return ret;

// 转换为 Base64URL (替换 +/= 为 -_)
    base64_to_base64url(header_b64, header_b64_len);

// 2. Base64URL 编码 Payload
unsignedchar payload_b64[1024];
size_t payload_b64_len;
    ret = mbedtls_base64_encode(payload_b64, sizeof(payload_b64),
                                &payload_b64_len,
                                (constunsignedchar*)payload, strlen(payload));
if (ret != 0return ret;
    base64_to_base64url(payload_b64, payload_b64_len);

// 3. 构造待签名数据: Header.Payload
char signing_input[2048];
snprintf(signing_input, sizeof(signing_input), "%s.%s",
             header_b64, payload_b64);

// 4. 计算 SHA-256 哈希
    mbedtls_sha256((constunsignedchar*)signing_input, 
strlen(signing_input), hash, 0);

// 5. ECDSA 签名
    ret = mbedtls_ecdsa_write_signature(ctx, MBEDTLS_MD_SHA256,
                                        hash, 32,
                                        signature, sizeof(signature), &sig_len,
                                        mbedtls_ctr_drbg_random, &ctr_drbg);
if (ret != 0return ret;

// 6. Base64URL 编码签名
unsignedchar sig_b64[256];
size_t sig_b64_len;
    ret = mbedtls_base64_encode(sig_b64, sizeof(sig_b64), &sig_b64_len,
                                signature, sig_len);
if (ret != 0return ret;
    base64_to_base64url(sig_b64, sig_b64_len);

// 7. 构造完整 JWT: Header.Payload.Signature
snprintf(jwt_out, *jwt_len, "%s.%s.%s",
             header_b64, payload_b64, sig_b64);
    *jwt_len = strlen(jwt_out);

printf("✅ JWT 生成成功!\n");
printf("   %s\n", jwt_out);

return0;
}

// 验证 JWT
intverify_jwt_es256(constchar *jwt, mbedtls_ecdsa_context *ctx)
{
int ret;
char jwt_copy[2048];
strcpy(jwt_copy, jwt);

// 1. 分割 JWT: Header.Payload.Signature
char *header = strtok(jwt_copy, ".");
char *payload = strtok(NULL".");
char *signature_b64 = strtok(NULL".");

if (!header || !payload || !signature_b64) {
return-1;
    }

// 2. 重构待验证数据
char signing_input[2048];
snprintf(signing_input, sizeof(signing_input), "%s.%s", header, payload);

// 3. 计算哈希
unsignedchar hash[32];
    mbedtls_sha256((constunsignedchar*)signing_input,
strlen(signing_input), hash, 0);

// 4. 解码签名
unsignedchar signature[MBEDTLS_ECDSA_MAX_LEN];
size_t sig_len;
    base64url_to_base64((unsignedchar*)signature_b64, strlen(signature_b64));
    ret = mbedtls_base64_decode(signature, sizeof(signature), &sig_len,
                                (constunsignedchar*)signature_b64,
strlen(signature_b64));
if (ret != 0return ret;

// 5. 验证签名
    ret = mbedtls_ecdsa_read_signature(ctx, hash, 32, signature, sig_len);

if (ret == 0) {
printf("✅ JWT 验证成功!\n");
    } else {
printf("❌ JWT 验证失败!\n");
    }

return ret;
}

076. 常用椭圆曲线详解

6.1 NIST 标准曲线

mbedTLS 支持的 NIST P-曲线 (FIPS 186-4):
曲线
位数
安全强度
用途
mbedTLS ID
P-192
192
96 位
⚠️ 已弃用
MBEDTLS_ECP_DP_SECP192R1
P-224
224
112 位
中等安全
MBEDTLS_ECP_DP_SECP224R1
P-256
256
128 位
✅ 推荐 (TLS)
MBEDTLS_ECP_DP_SECP256R1
P-384
384
192 位
高安全
MBEDTLS_ECP_DP_SECP384R1
P-521
521
256 位
最高安全
MBEDTLS_ECP_DP_SECP521R1
P-256 (secp256r1 / prime256v1) - 最常用:
// 曲线参数
p = 2^256 - 2^224 + 2^192 + 2^96 - 1
a = -3
b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B
G = (0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296,
0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5)
n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551

// 使用示例
mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
性能对比 (Cortex-M4 @ 168MHz):
曲线
密钥生成
签名
验证
P-192
45 ms
50 ms
95 ms
P-224
65 ms
70 ms
135 ms
P-256
85 ms
90 ms
175 ms
P-384
210 ms
220 ms
430 ms
P-521
420 ms
440 ms
860 ms

6.2 Koblitz 曲线 (secp256k1)

secp256k1 - 比特币/以太坊使用:
// 曲线参数
p = 2^256 - 2^32 - 977
a = 0
b = 7// 简单!
G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8)
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

// 使用示例
mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256K1);
为什么比特币选择 secp256k1?
1.
性能优势a=0, b=7 简化了点运算
2.
无后门疑虑:参数来源透明 (NIST 曲线被质疑可能有 NSA 后门)
3.
专利自由:无专利限制
secp256k1 vs secp256r1 性能
操作          secp256k1    secp256r1
密钥生成      75ms85ms
签名          80ms90ms
验证          155ms175ms

6.3 Brainpool 曲线

欧洲标准曲线 (RFC 5639),参数生成过程完全透明:
曲线
位数
mbedTLS ID
brainpoolP256r1
256
MBEDTLS_ECP_DP_BP256R1
brainpoolP384r1
384
MBEDTLS_ECP_DP_BP384R1
brainpoolP512r1
512
MBEDTLS_ECP_DP_BP512R1
使用场景
欧洲政府/军事应用
对 NIST 曲线不信任的场景

6.4 曲线选择建议

通用 Web/TLS 应用
✅ 首选:P-256 (secp256r1)
   - 广泛支持
   - 性能良好
   - TLS 1.3 强制要求

✅ 备选:P-384
   - 更高安全性
   - 政府/金融级应用
区块链应用
✅ 首选:secp256k1
   - 比特币/以太坊标准
   - 性能优异
   - 生态成熟
嵌入式/IoT
✅ 首选:P-256
   - 平衡安全性和性能
   - 硬件加速支持广泛

⚠️  避免:P-521
   - 性能开销大
   - 嵌入式设备不推荐
高安全场景
✅ 首选:P-384 或 brainpoolP384r1
   - 192 位安全强度
   - 抗量子计算能力更强 (相对)

087. 安全陷阱与最佳实践

7.1 随机数灾难

❌ 错误示例 1:固定 k
// PlayStation 3 漏洞
mbedtls_mpi k;
mbedtls_mpi_lset(&k, 12345);  // 固定值!

// 两次签名使用相同 k → 私钥泄露
❌ 错误示例 2:弱随机数
// 使用 rand() 生成 k
srand(time(NULL));
for (int i = 0; i < 32; i++) {
    k_bytes[i] = rand() % 256;  // 不安全!
}
✅ 正确做法
// 方案 1:使用确定性签名 (推荐)
#define MBEDTLS_ECDSA_DETERMINISTIC
mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, ...);

// 方案 2:使用密码学安全的 RNG
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, ...);
mbedtls_ecdsa_sign(&grp, &r, &s, &d, hash, 32,
                   mbedtls_ctr_drbg_random, &ctr_drbg);

7.2 侧信道攻击防护

时序攻击
// ❌ 错误:直接比较签名
if (memcmp(signature1, signature2, sig_len) == 0) {
// memcmp 在发现第一个不同字节时立即返回
// 攻击者可以通过测量时间推断签名内容
}

// ✅ 正确:常量时间比较
if (mbedtls_platform_memequal(signature1, signature2, sig_len) == 0) {
// 始终比较所有字节,时间恒定
}
盲化技术 (mbedTLS 自动应用):
// 签名时使用盲化因子 t
// s = (e + r·d) / k
// 变为:s = t(e + r·d) / (kt)
// 防止通过功耗分析推断私钥

mbedtls_ecdsa_sign_restartable(
    grp, r, s, d, hash, hash_len,
    f_rng, p_rng,
    f_rng_blind, p_rng_blind,  // 盲化 RNG
    rs_ctx);

7.3 私钥管理

❌ 错误做法
// 1. 硬编码私钥
constunsignedchar private_key[] = {
0x120x340x56, ...  // 永远不要这样做!
};

// 2. 明文存储私钥
FILE *f = fopen("private_key.bin""wb");
fwrite(private_key, 132, f);  // 不安全!

// 3. 不清零敏感数据
mbedtls_mpi d;
// ... 使用 d ...
mbedtls_mpi_free(&d);  // 内存中可能残留私钥
✅ 正确做法
// 1. 使用安全存储 (如 TPM, Secure Element)
#ifdef USE_SECURE_ELEMENT
    se_generate_keypair(&key_id);
    se_ecdsa_sign(key_id, hash, signature);
#endif

// 2. 加密存储私钥
unsignedchar encrypted_key[64];
aes_gcm_encrypt(private_key, 32, encrypted_key, master_key);

// 3. 使用后立即清零
mbedtls_mpi d;
// ... 使用 d ...
mbedtls_platform_zeroize(&d, sizeof(d));  // 安全清零
mbedtls_mpi_free(&d);

7.4 签名可塑性 (Malleability)

问题:给定有效签名 (r, s),攻击者可以构造另一个有效签名 (r, -s mod n)
比特币的解决方案 (BIP 62):
// 强制 s 值在低半部分:s ≤ n/2
intnormalize_signature_s(mbedtls_mpi *s, const mbedtls_mpi *n)
{
    mbedtls_mpi half_n;
    mbedtls_mpi_init(&half_n);

// half_n = n / 2
    mbedtls_mpi_copy(&half_n, n);
    mbedtls_mpi_shift_r(&half_n, 1);

// 如果 s > n/2,则 s = n - s
if (mbedtls_mpi_cmp_mpi(s, &half_n) > 0) {
        mbedtls_mpi_sub_mpi(s, n, s);
    }

    mbedtls_mpi_free(&half_n);
return0;
}

// 签名后规范化
mbedtls_ecdsa_sign(&grp, &r, &s, &d, hash, 32, f_rng, p_rng);
normalize_signature_s(&s, &grp.N);  // 确保 s ≤ n/2

7.5 哈希函数选择

❌ 不安全的哈希
// MD5 / SHA-1 已被破解
mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_MD5, ...);   // 危险!
mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA1, ...);  // 危险!
✅ 推荐哈希
// SHA-256 (最常用)
mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, ...);

// SHA-384 (配合 P-384 曲线)
mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA384, ...);

// SHA-512 (配合 P-521 曲线)
mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA512, ...);
哈希与曲线匹配
曲线
推荐哈希
原因
P-256
SHA-256
安全强度匹配 (128 位)
P-384
SHA-384
安全强度匹配 (192 位)
P-521
SHA-512
安全强度匹配 (256 位)
secp256k1
SHA-256
比特币标准

7.6 公钥验证

❌ 跳过公钥验证
// 直接使用未验证的公钥
mbedtls_ecp_point Q;
mbedtls_ecp_point_read_binary(&grp, &Q, pubkey_bytes, pubkey_len);
mbedtls_ecdsa_verify(&grp, hash, 32, &Q, &r, &s);  // 危险!
✅ 验证公钥有效性
mbedtls_ecp_point Q;
mbedtls_ecp_point_read_binary(&grp, &Q, pubkey_bytes, pubkey_len);

// 验证 Q 在曲线上且不是无穷远点
int ret = mbedtls_ecp_check_pubkey(&grp, &Q);
if (ret != 0) {
printf("❌ 无效的公钥!\n");
return ret;
}

// 验证 Q 的阶是 n (防止小子群攻击)
mbedtls_ecp_point nQ;
mbedtls_ecp_mul(&grp, &nQ, &grp.N, &Q, NULLNULL);
if (!mbedtls_ecp_is_zero(&nQ)) {
printf("❌ 公钥阶不正确!\n");
return-1;
}

// 现在可以安全使用
mbedtls_ecdsa_verify(&grp, hash, 32, &Q, &r, &s);

098. 性能优化技巧

8.1 固定点优化

原理:预计算基点 G 的倍数,加速 k·G 运算。
// mbedTLS 配置
#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1  // 启用固定点优化

// 性能提升
// P-256 签名:90ms → 60ms (提升 33%)
// P-384 签名:220ms → 150ms (提升 32%)
原理
预计算表:T[i] = i·G, i = 12, ..., 2^w
计算 k·G 时,将 k 分解为 w 位窗口,查表相加

内存开销:P-256 约 1KB,P-384 约 2KB

8.2 窗口大小调优

// mbedTLS 配置
#define MBEDTLS_ECP_WINDOW_SIZE 4  // 默认值

// 窗口大小对性能的影响 (P-256)
// w=2: 226 ms, 内存 256 字节
// w=3: 262 ms, 内存 512 字节
// w=4: 303 ms, 内存 1 KB  ← 默认
// w=5: 320 ms, 内存 2 KB
// w=6: 320 ms, 内存 4 KB
建议
嵌入式设备w=3 (节省内存)
桌面/服务器w=4 或 w=5 (平衡性能)

8.3 批量验证优化

场景:验证多个签名 (如区块链区块验证)。
// 朴素方法:逐个验证
for (int i = 0; i < n; i++) {
    mbedtls_ecdsa_verify(&grp, hash[i], 32, &Q[i], &r[i], &s[i]);
}
// 时间:n × 175ms (P-256)

// 批量验证 (使用 Shamir 技巧)
// 验证:∑(u1[i]·G + u2[i]·Q[i]) 的 x 坐标
// 时间:约 (n/2) × 175ms (提升 50%)
实现 (简化版):
intbatch_verify_ecdsa(mbedtls_ecp_group *grp,
constunsignedchar **hashes,
const mbedtls_ecp_point *Q,
const mbedtls_mpi *r,
const mbedtls_mpi *s,
int count)

{
// 1. 生成随机权重 a[i]
    mbedtls_mpi a[count];
for (int i = 0; i < count; i++) {
        mbedtls_mpi_fill_random(&a[i], 16, f_rng, p_rng);
    }

// 2. 计算 ∑ a[i]·(u1[i]·G + u2[i]·Q[i])
    mbedtls_ecp_point R;
    mbedtls_ecp_point_init(&R);

for (int i = 0; i < count; i++) {
        mbedtls_mpi u1, u2, w;
        derive_mpi(grp, &e, hashes[i], 32);
        mbedtls_mpi_inv_mod(&w, &s[i], &grp->N);
        mbedtls_mpi_mul_mpi(&u1, &e, &w);
        mbedtls_mpi_mul_mpi(&u2, &r[i], &w);
        mbedtls_mpi_mul_mpi(&u1, &u1, &a[i]);
        mbedtls_mpi_mul_mpi(&u2, &u2, &a[i]);

        mbedtls_ecp_point temp;
        mbedtls_ecp_muladd(grp, &temp, &u1, &grp->G, &u2, &Q[i]);
        mbedtls_ecp_point_add(grp, &R, &R, &temp);
    }

// 3. 验证结果
// (简化:实际需要更复杂的验证逻辑)

return0;
}

8.4 硬件加速

ARM Crypto Extensions
// 自动检测并使用 ARM CE
#if defined(MBEDTLS_HAVE_ARM64)
// mbedTLS 自动使用 ARM64 优化
// P-256 签名:90ms → 15ms (提升 6 倍)
#endif
Intel AES-NI (用于 GCM 模式,间接加速):
#if defined(MBEDTLS_AESNI_C)
// 自动启用 AES-NI
#endif
硬件安全模块 (HSM/TPM)
// 使用 TPM 2.0 进行 ECDSA 签名
#ifdef USE_TPM
    TPM2_Sign(key_handle, hash, 32, signature, &sig_len);
// 签名时间:~5ms (硬件加速)
// 私钥永不离开 TPM
#endif

8.5 内存优化

减少栈使用
// ❌ 大栈分配
voidsign_message(void) {
    mbedtls_ecdsa_context ctx;  // ~2KB
unsignedchar signature[256];
// ...
}

// ✅ 使用堆分配
voidsign_message(void) {
    mbedtls_ecdsa_context *ctx = malloc(sizeof(mbedtls_ecdsa_context));
    mbedtls_ecdsa_init(ctx);
// ...
    mbedtls_ecdsa_free(ctx);
free(ctx);
}
共享上下文
// 全局 ECDSA 上下文 (多次签名复用)
static mbedtls_ecdsa_context g_ecdsa_ctx;

voidinit_crypto(void) {
    mbedtls_ecdsa_init(&g_ecdsa_ctx);
    mbedtls_ecdsa_genkey(&g_ecdsa_ctx, MBEDTLS_ECP_DP_SECP256R1, ...);
}

voidsign_multiple_messages(void) {
for (int i = 0; i < 100; i++) {
// 复用同一个上下文,避免重复初始化
        mbedtls_ecdsa_write_signature(&g_ecdsa_ctx, ...);
    }
}

109. 常见问题 FAQ

Q1: ECDSA 和 RSA 如何选择?

选择 ECDSA
✅ 密钥/签名更小 (节省带宽)
✅ 性能更快 (2-3 倍)
✅ 嵌入式/IoT 设备
✅ 区块链应用
选择 RSA
✅ 更广泛的兼容性 (老系统)
✅ 实现更简单
✅ 专利到期,无法律风险
对比表
特性
ECDSA-256
RSA-3072
安全强度
128 位
128 位
公钥大小
64 字节
384 字节
签名大小
64 字节
384 字节
签名速度
90 ms
250 ms
验证速度
175 ms
8 ms ⚡
注意:RSA 验证更快,但签名慢;ECDSA 签名和验证都较快。

Q2: 为什么比特币不用 P-256 而用 secp256k1?

原因
1.
性能:secp256k1 的 a=0, b=7 简化了运算
2.
透明性:参数来源清晰,无后门疑虑
3.
历史:2009 年比特币诞生时,secp256k1 已存在
NIST 曲线争议
2013 年斯诺登泄密事件后,NIST 曲线被质疑可能有 NSA 后门
secp256k1 参数生成过程完全透明

Q3: 确定性签名会降低安全性吗?

不会! RFC 6979 确定性签名:
✅ 安全性等同于随机签名
✅ 消除随机数重用风险
✅ 签名可复现 (便于测试)
✅ 无需高质量 RNG
唯一缺点
❌ 如果私钥泄露,攻击者可以生成相同签名 (但这不是新问题)

Q4: ECDSA 签名长度为什么不固定?

原因:DER 编码的整数长度可变。
示例 (P-256):
r=0x00123456...  (33 字节,前导 0x00)
s=0x789ABC...    (32 字节)
签名 =30450221 [33字节r] 0220 [32字节s]  (71 字节)

r=0x123456...    (32 字节,无前导 0)
s=0x00789ABC...  (33 字节)
签名 =30450220 [32字节r] 0221 [33字节s]  (71 字节)

r=0x123456...    (32 字节)
s=0x789ABC...    (32 字节)
签名 =30440220 [32字节r] 0220 [32字节s]  (70 字节)
固定长度方案
原始格式r || s (64 字节固定)
比特币:DER 编码 (70-72 字节)
IEEE P1363:固定 64 字节

Q5: 如何防止签名重放攻击?

方案 1:包含时间戳
// 在消息中包含时间戳
char message[256];
snprintf(message, sizeof(message), "%s|%ld", data, time(NULL));
mbedtls_sha256((unsignedchar*)message, strlen(message), hash, 0);
mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, hash, 32, ...);

// 验证时检查时间戳
if (abs(timestamp - time(NULL)) > 300) {  // 5 分钟有效期
return-1;  // 签名过期
}
方案 2:使用 nonce
// 服务器生成随机 nonce
uint8_t nonce[16];
mbedtls_ctr_drbg_random(&ctr_drbg, nonce, 16);

// 客户端签名:hash(data || nonce)
// 服务器验证后,标记 nonce 为已使用
方案 3:序列号
// 每个签名包含递增的序列号
typedefstruct {
uint64_t seq_num;
uint8_t data[256];
uint8_t signature[72];
signed_message_t;

// 验证时检查序列号
if (msg->seq_num <= last_seq_num) {
return-1;  // 重放攻击
}
last_seq_num = msg->seq_num;

Q6: ECDSA 能抵抗量子计算攻击吗?

不能! Shor 算法可以在多项式时间内破解 ECDLP。
量子威胁时间表
年份
量子计算机能力
ECDSA 安全性
2024
~100 量子比特
✅ 安全
2030
~1000 量子比特
⚠️ P-256 可能被破解
2035
~10000 量子比特
❌ 所有 ECC 不安全
后量子方案
NIST 后量子标准 (2024):
ML-DSA (Dilithium) - 签名
SLH-DSA (SPHINCS+) - 签名
ML-KEM (Kyber) - 密钥交换
过渡策略
// 混合签名 (ECDSA + 后量子)
sign_hybrid(message, ecdsa_key, pq_key, signature);
// 只有同时破解两种算法才能伪造签名

1110. 总结与检查清单

10.1 核心要点回顾

ECDSA 的本质
签名:证明"我拥有私钥 d,且我认可这条消息"
验证:确认"签名者确实拥有对应公钥的私钥"

数学基础:椭圆曲线离散对数难题 (ECDLP)
安全性:256 位 ECC ≈ 3072 位 RSA
算法流程
密钥生成:d ← random(1, n-1), Q = d·G
签名:    (r, s) = (k·G).x, k⁻¹(e + r·d) mod n
验证:    检查 (u₁·G + u₂·Q).x == r
关键优势
✅ 密钥更短 (64 字节 vs 384 字节)
✅ 性能更快 (2-3 倍于 RSA)
✅ 适合嵌入式/IoT/区块链

10.2 安全检查清单

密钥管理 ✓
[ ] 使用密码学安全的 RNG 生成私钥
[ ] 私钥存储加密或使用 HSM/TPM
[ ] 使用后立即清零敏感数据 (mbedtls_platform_zeroize)
[ ] 定期轮换密钥 (建议 1-2 年)
[ ] 备份私钥到安全位置
签名生成 ✓
[ ] 启用确定性签名 (MBEDTLS_ECDSA_DETERMINISTIC)
[ ] 使用 SHA-256 或更强的哈希函数
[ ] 每次签名使用不同的 k (或使用确定性)
[ ] 应用盲化技术防止侧信道攻击
[ ] 验证签名 (r, s) 不为零
签名验证 ✓
[ ] 验证 r, s 在范围 [1, n-1]
[ ] 验证公钥在曲线上 (mbedtls_ecp_check_pubkey)
[ ] 使用常量时间比较防止时序攻击
[ ] 检查签名时间戳/nonce 防止重放攻击
[ ] 记录验证失败日志
曲线选择 ✓
[ ] TLS/Web:P-256 (secp256r1)
[ ] 区块链:secp256k1
[ ] 高安全:P-384 或 brainpoolP384r1
[ ] 避免:P-192 (已弃用)
性能优化 ✓
[ ] 启用固定点优化 (MBEDTLS_ECP_FIXED_POINT_OPTIM)
[ ] 调整窗口大小 (MBEDTLS_ECP_WINDOW_SIZE)
[ ] 使用硬件加速 (ARM CE, AES-NI)
[ ] 批量验证多个签名
[ ] 复用 ECDSA 上下文

10.3 常见错误速查

错误
后果
解决方案
固定 k 值
私钥泄露
使用确定性签名
弱随机数
私钥泄露
使用 mbedtls_ctr_drbg
跳过公钥验证
伪造签名
调用 mbedtls_ecp_check_pubkey
使用 MD5/SHA-1
碰撞攻击
使用 SHA-256+
明文存储私钥
密钥泄露
加密存储或使用 HSM
不清零敏感数据
内存泄露
使用 mbedtls_platform_zeroize
忽略签名时间戳
重放攻击
验证时间戳/nonce

10.4 性能基准 (参考)

Cortex-M4 @ 168MHz
操作
P-256
P-384
secp256k1
密钥生成
85 ms
210 ms
75 ms
签名
90 ms
220 ms
80 ms
验证
175 ms
430 ms
155 ms
Intel Core i7 (桌面)
操作
P-256
P-384
secp256k1
密钥生成
0.3 ms
0.8 ms
0.25 ms
签名
0.35 ms
0.9 ms
0.3 ms
验证
0.7 ms
1.8 ms
0.6 ms

10.5 相关源文件映射

功能
源文件
头文件
ECDSA 核心ecdsa.cecdsa.h
椭圆曲线运算ecp.cecp.h
曲线参数ecp_curves.c
-
大数运算bignum.cbignum.h
确定性签名hmac_drbg.chmac_drbg.h
ASN.1 编码asn1write.casn1write.h

10.6 进一步学习

推荐资源
1.
标准文档
SEC1: Elliptic Curve Cryptography
RFC 6979: Deterministic ECDSA
FIPS 186-4: Digital Signature Standard
书籍
《椭圆曲线密码学导论》- Darrel Hankerson
《密码工程》- Niels Ferguson (第 6 章)
在线工具
ECDSA 可视化
比特币签名验证器
下一步学习
ECDH 密钥交换
EdDSA (Ed25519)
后量子签名

12📚 完整示例代码

完整的 ECDSA 签名验证程序
#include"mbedtls/ecdsa.h"
#include"mbedtls/sha256.h"
#include"mbedtls/entropy.h"
#include"mbedtls/ctr_drbg.h"
#include<stdio.h>
#include<string.h>

intmain(void)
{
int ret;
    mbedtls_ecdsa_context ctx;
    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
unsignedchar hash[32];
unsignedchar signature[MBEDTLS_ECDSA_MAX_LEN];
size_t sig_len;

constchar *message = "Hello, ECDSA!";

// 1. 初始化
    mbedtls_ecdsa_init(&ctx);
    mbedtls_entropy_init(&entropy);
    mbedtls_ctr_drbg_init(&ctr_drbg);

printf("🔐 ECDSA 签名验证示例\n\n");

// 2. 初始化随机数生成器
    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
                                (constunsignedchar *)"ecdsa_demo"10);
if (ret != 0) {
printf("❌ RNG 初始化失败: -0x%04x\n", -ret);
goto cleanup;
    }

// 3. 生成 ECDSA 密钥对 (P-256)
printf("📝 生成 P-256 密钥对...\n");
    ret = mbedtls_ecdsa_genkey(&ctx, MBEDTLS_ECP_DP_SECP256R1,
                               mbedtls_ctr_drbg_random, &ctr_drbg);
if (ret != 0) {
printf("❌ 密钥生成失败: -0x%04x\n", -ret);
goto cleanup;
    }
printf("✅ 密钥生成成功!\n\n");

// 4. 计算消息哈希
printf("📝 消息: \"%s\"\n", message);
    mbedtls_sha256((constunsignedchar *)message, strlen(message), hash, 0);
printf("📝 SHA-256: ");
for (int i = 0; i < 32; i++) {
printf("%02x", hash[i]);
    }
printf("\n\n");

// 5. 生成签名
printf("✍️  生成 ECDSA 签名...\n");
    ret = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256,
                                        hash, 32,
                                        signature, sizeof(signature), &sig_len,
                                        mbedtls_ctr_drbg_random, &ctr_drbg);
if (ret != 0) {
printf("❌ 签名失败: -0x%04x\n", -ret);
goto cleanup;
    }
printf("✅ 签名成功!长度: %zu 字节\n", sig_len);
printf("📝 签名: ");
for (size_t i = 0; i < sig_len; i++) {
printf("%02x", signature[i]);
    }
printf("\n\n");

// 6. 验证签名
printf("🔍 验证签名...\n");
    ret = mbedtls_ecdsa_read_signature(&ctx, hash, 32, signature, sig_len);
if (ret == 0) {
printf("✅ 签名验证成功!\n");
    } else {
printf("❌ 签名验证失败: -0x%04x\n", -ret);
    }

// 7. 测试篡改检测
printf("\n🔍 测试篡改检测...\n");
    hash[0] ^= 0x01;  // 修改哈希的一个位
    ret = mbedtls_ecdsa_read_signature(&ctx, hash, 32, signature, sig_len);
if (ret != 0) {
printf("✅ 成功检测到篡改!\n");
    } else {
printf("❌ 未能检测到篡改!\n");
    }

cleanup:
    mbedtls_ecdsa_free(&ctx);
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);

return ret;
}
编译运行
gcc -o ecdsa_demo ecdsa_demo.c -lmbedtls -lmbedx509 -lmbedcrypto
./ecdsa_demo
预期输出
🔐 ECDSA 签名验证示例

📝 生成 P-256 密钥对...
✅ 密钥生成成功!

📝 消息: "Hello, ECDSA!"
📝 SHA-2563f4c8b9e2d1a7f6e5c4b3a2d1e0f9c8b7a6e5d4c3b2a1f0e9d8c7b6a5e4d3c2b

✍️  生成 ECDSA 签名...
✅ 签名成功!长度: 70 字节
📝 签名: 3044022012345678...

🔍 验证签名...
✅ 签名验证成功!

🔍 测试篡改检测...
✅ 成功检测到篡改!

🎓 恭喜!你已经掌握了 ECDSA 椭圆曲线数字签名!

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-02-06 09:16:11 HTTP/2.0 GET : https://67808.cn/a/464497.html
  2. 运行时间 : 0.119047s [ 吞吐率:8.40req/s ] 内存消耗:4,648.07kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=9cb98d1a24aad8b32a81ccfc90bc937f
  1. /yingpanguazai/ssd/ssd1/www/no.67808.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/no.67808.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/no.67808.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/no.67808.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/no.67808.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/no.67808.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/no.67808.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/no.67808.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/no.67808.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/no.67808.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/no.67808.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/no.67808.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/no.67808.cn/runtime/temp/6df755f970a38e704c5414acbc6e8bcd.php ( 12.06 KB )
  140. /yingpanguazai/ssd/ssd1/www/no.67808.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000397s ] mysql:host=127.0.0.1;port=3306;dbname=no_67808;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000740s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.002137s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000266s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000654s ]
  6. SELECT * FROM `set` [ RunTime:0.000210s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000522s ]
  8. SELECT * FROM `article` WHERE `id` = 464497 LIMIT 1 [ RunTime:0.002961s ]
  9. UPDATE `article` SET `lasttime` = 1770340571 WHERE `id` = 464497 [ RunTime:0.015318s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 65 LIMIT 1 [ RunTime:0.003839s ]
  11. SELECT * FROM `article` WHERE `id` < 464497 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000516s ]
  12. SELECT * FROM `article` WHERE `id` > 464497 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000378s ]
  13. SELECT * FROM `article` WHERE `id` < 464497 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000592s ]
  14. SELECT * FROM `article` WHERE `id` < 464497 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002193s ]
  15. SELECT * FROM `article` WHERE `id` < 464497 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.018898s ]
0.121843s