如何用单个P256密钥对实现ECDSA与ECDH?Rust/Go适配咨询
解决方案
一、继续使用P256曲线(适配Rust WASM + Go互操作)
你偏好纯Rust库且需要适配WASM,无需局限于dalek系列,RustCrypto的p256 crate是纯Rust实现,支持P256曲线的ECDSA签名/密钥生成,且完全兼容Go的crypto/ecdsa。
Rust端实现(纯Rust,支持WASM)
- 添加依赖到
Cargo.toml:
[dependencies] p256 = { version = "0.13", features = ["ecdsa", "sha256", "wasm-bindgen"] } sha2 = "0.10"
- 生成密钥对并导出Go可解析的公钥:
use p256::ecdsa::{SigningKey, VerifyingKey}; use p256::pkcs8::EncodePublicKey; use rand_core::OsRng; // 生成P256密钥对 let signing_key = SigningKey::random(&mut OsRng); let verifying_key = VerifyingKey::from(&signing_key); // 导出公钥为ASN.1 DER格式(Go crypto/ecdsa可直接解析) let pub_key_der = verifying_key.to_public_key_der().unwrap(); let pub_key_bytes = pub_key_der.as_bytes(); // 将pub_key_bytes发送到Go服务
Go端解析Rust发来的公钥
package main import ( "crypto/ecdsa" "crypto/elliptic" "crypto/x509" "fmt" ) func main() { // pubKeyBytes 为从Rust接收的DER格式公钥字节 var pubKey ecdsa.PublicKey derBytes := pubKeyBytes // 替换为实际接收的字节 if err := x509.ParsePKIXPublicKey(derBytes, &pubKey); err != nil { panic(err) } if pubKey.Curve != elliptic.P256() { panic("invalid curve") } // 已完成公钥解析,可用于签名验证等操作 fmt.Println("Parsed P256 public key:", pubKey) }
二、切换到ed25519/X25519的方案(签名+密钥交换)
ed25519是签名算法,X25519是对应的ECDH密钥交换算法,不存在同一个密钥对同时支持ed25519签名和ECDH的标准方案,但可以从同一个原始ed25519私钥派生X25519私钥,实现“一套原始密钥,两用”的效果:
Rust端实现
用ed25519-dalek做签名,x25519-dalek做密钥交换:
use ed25519_dalek::{SigningKey, VerifyingKey}; use x25519_dalek::{StaticSecret, PublicKey}; use rand_core::OsRng; // 生成ed25519密钥对 let ed_signing_key = SigningKey::generate(&mut OsRng); let ed_verifying_key = VerifyingKey::from(&ed_signing_key); // 从ed25519私钥派生X25519私钥 let x25519_secret = StaticSecret::from(ed_signing_key.to_bytes()); let x25519_public = PublicKey::from(&x25519_secret); // 可发送ed25519公钥(签名验证用)或由Go端自行从ed25519公钥派生X25519公钥
Go端实现
Go标准库支持从ed25519密钥派生X25519密钥:
package main import ( "crypto/ed25519" "crypto/x25519" "fmt" ) func main() { // 接收Rust发来的ed25519公钥字节 edPubKey := ed25519.PublicKey(recvEdPubBytes) // 替换为实际接收的字节 // 从ed25519公钥派生X25519公钥 x25519PubKey, err := x25519.Ed25519PublicKeyToX25519(edPubKey) if err != nil { panic(err) } // 本地ed25519私钥派生X25519私钥 edPrivKey := ed25519.PrivateKey(localEdPrivBytes) // 替换为本地私钥 x25519PrivKey, err := x25519.Ed25519PrivateKeyToX25519(edPrivKey) if err != nil { panic(err) } // 用x25519PrivKey与对方x25519PubKey完成ECDH密钥交换 }
内容的提问来源于stack exchange,提问作者mama
相关产品推荐
相关产品推荐

