为何持续触发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
相关产品推荐
相关产品推荐

