You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何持续触发InvalidPublicKey错误?secp256k1公钥验证异常

解决libsecp256k1中「InvalidPublicKey」错误(群元素不在曲线上)

在使用Rust的libsecp256k1库验证签名时,反复触发「InvalidPublicKey」错误,调试后发现错误来自Affine::is_valid_var()函数,提示群元素不在secp256k1曲线上,但相同的公钥参数在Golang代码中可正常验证签名。以下是问题代码:

extern crate libsecp256k1;
use libsecp256k1::{Message, PublicKey, PublicKeyFormat, Signature, verify};
extern crate x509_parser;
use x509_parser::pem::parse_x509_pem;
extern crate spki;
use spki::SubjectPublicKeyInfo;

fn main() {
    pub const PUBKEY_TEST: &str = "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQem4RK/YPgiT83UqNnIAx7GAFX3b\n948NbKnilBKoD5t/4LSKDmP/X7qCrEIQ8TafiXB2r3mW9BPlX1mGZ0iYXw==\n-----END PUBLIC KEY-----";
    let (rem, pem) = parse_x509_pem(&PUBKEY_TEST.as_bytes()).unwrap();
    assert!(rem.is_empty());
    assert_eq!(pem.label, String::from("PUBLIC"));
    let pub_key = SubjectPublicKeyInfo::try_from(pem.contents.as_slice()).unwrap();
    assert_eq!(pub_key.subject_public_key.len(), 65);
    assert_eq!(pub_key.subject_public_key[0], 4); // tag pubkey full
    let pubkey = PublicKey::parse_slice(&pub_key.subject_public_key, Some(PublicKeyFormat::Full)).unwrap();
}

可能的原因及解决方案

1. 公钥格式解析的隐式差异

虽然代码指定了PublicKeyFormat::Full,但x509_parser和spki库的ASN.1解析逻辑可能与Golang的x509处理存在差异,导致提取的公钥字节序列存在隐藏格式问题。

解决办法:手动提取公钥坐标构造公钥
跳过SPKI解析的中间步骤,直接从公钥字节中提取X、Y坐标:

// 在main函数中替换原公钥解析部分
let pub_key_bytes = &pub_key.subject_public_key;
let x = &pub_key_bytes[1..33]; // 第1-32字节是X坐标
let y = &pub_key_bytes[33..65]; // 第33-64字节是Y坐标
let pubkey = PublicKey::from_slice(x, y).unwrap();

2. DER编码解析的细节问题

SPKI的DER编码包含额外的ASN.1结构标签,部分解析库可能对这些标签的处理不完全一致,导致最终传递给libsecp256k1的字节序列存在冗余。

解决办法:手动解析DER编码提取公钥
绕开第三方解析库,直接解码PEM并手动解析DER结构:

use base64::decode;

fn main() {
    pub const PUBKEY_TEST: &str = "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQem4RK/YPgiT83UqNnIAx7GAFX3b\n948NbKnilBKoD5t/4LSKDmP/X7qCrEIQ8TafiXB2r3mW9BPlX1mGZ0iYXw==\n-----END PUBLIC KEY-----";
    // 提取并解码PEM内容
    let pem_clean = PUBKEY_TEST
        .replace("-----BEGIN PUBLIC KEY-----\n", "")
        .replace("\n-----END PUBLIC KEY-----", "")
        .replace('\n', "");
    let der_bytes = decode(pem_clean).unwrap();

    // 手动解析DER结构,跳过外层SEQUENCE和BIT STRING标签
    let mut offset = 0;
    // 跳过外层SEQUENCE
    offset += 2 + (der_bytes[1] as usize);
    // 跳过BIT STRING标签和长度
    offset += 2;
    // 跳过BIT STRING填充位(若存在)
    if der_bytes[offset] != 0x00 {
        offset += 1;
    }
    // 提取最终的65字节公钥
    let pubkey_raw = &der_bytes[offset..offset+65];
    let pubkey = PublicKey::parse_slice(pubkey_raw, Some(PublicKeyFormat::Full)).unwrap();
}

3. 库版本兼容性问题

不同版本的libsecp256k1对公钥合法性验证的严格程度不同,尝试升级或降级库版本,匹配Golang使用的secp256k1核心版本。

解决办法:更新依赖版本
修改Cargo.toml中的依赖版本:

[dependencies]
libsecp256k1 = "0.27.0" # 使用最新稳定版
x509-parser = "0.15.0"
spki = "0.7.2"
base64 = "0.21.0"

内容的提问来源于stack exchange,提问作者Jose Moran Urena

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 00:45:38