crypto/elliptic 不能直接加密,仅支持密钥协商和签名;它提供点乘、密钥生成等底层数学操作,加密需结合 crypto/ecdsa、curve25519 或 aes 自行实现 ecies。

crypto/elliptic 不能直接加密,它只做密钥协商和签名
很多人搜 crypto/elliptic 是想“用椭圆曲线加密数据”,结果发现没有 Encrypt 或 Decrypt 方法——这不是你用错了,是设计如此。crypto/elliptic 只提供底层数学能力:点乘、公私钥生成、签名验证。真正加密得靠上层封装,比如 crypto/ecdsa 做签名,golang.org/x/crypto/curve25519 做密钥交换,或者结合 crypto/aes 自行实现 ECIES。
常见错误现象:undefined: elliptic.Encrypt;或误把 elliptic.P256() 当成可直接加密的“算法对象”。
-
elliptic.Curve接口只定义Params、IsOnCurve、ScalarMult等数学操作,不涉及密码学协议 - 标准库中真正用于签名的是
crypto/ecdsa,它内部调用elliptic,但你该用ecdsa.Sign而不是自己手算点乘 - P-256、P-384 这些曲线在
elliptic中只是参数集合,安全性依赖实现是否恒定时间——Go 标准库的elliptic.P256()是,但旧版(
选曲线别只看名字:P-256 ≠ curve25519,API 和用途完全不同
Go 里两套主流椭圆曲线支持:标准库 crypto/elliptic(含 P-224/P-256/P-384/P-521)和 golang.org/x/crypto/curve25519(Ed25519 兼容)。它们连函数签名都不兼容。
使用场景差异明显:P-256 多用于 TLS 证书、X.509 签名;curve25519 更适合密钥交换(如 Noise 协议)、高性能签名(Ed25519),且抗侧信道能力更强。
立即学习“go语言免费学习笔记(深入)”;
-
elliptic.P256().ScalarBaseMult返回*big.Int坐标,需手动序列化为 ASN.1 或 SEC1 格式 -
curve25519.X25519直接输入 32 字节私钥和 32 字节公钥,输出 32 字节共享密钥,无坐标转换开销 - P-256 私钥是 32 字节随机数,但必须落在曲线阶范围内(
elliptic.P256().Params().N),而 curve25519 私钥需 clamping(掩码低字节),直接用 rand.Read 会出错
从 crypto/elliptic 到可用签名:绕不开 crypto/ecdsa
想用椭圆曲线签名?别硬啃 elliptic 的点运算。Go 标准库已通过 crypto/ecdsa 封装好完整流程:密钥生成 → 签名 → 验证。它底层调用 elliptic,但屏蔽了所有坐标运算细节。
典型错误:试图用 elliptic.P256().ScalarMult 手算公钥,再拼凑 DER 编码签名——既易出错,又可能引入非恒定时间分支。
- 生成密钥对直接用
ecdsa.GenerateKey(elliptic.P256(), rand.Reader),别自己 newelliptic.PrivateKey - 签名时传入哈希值(如
sha256.Sum256的[32]byte),不是原始数据;ecdsa.Sign返回的r, s *big.Int需用asn1.Marshal转 DER,或用ecdsa.SignASN1一步到位 - 验证失败常见原因是:公钥未校验是否在曲线上(
elliptic.IsOnCurve)、哈希长度与曲线不匹配(P-256 要 32 字节哈希)、DER 签名格式损坏
性能敏感场景下,避免反复调用 elliptic.P256()
elliptic.P256() 每次调用都返回新实例,但它的参数(Params)是只读常量。高频场景(如每秒数千次签名)下,反复调用它虽无功能问题,但会产生无谓的接口分配和指针解引用。
更关键的是:如果你在循环里写 elliptic.P256().ScalarMult(...),Go 的逃逸分析可能把整个曲线参数逃逸到堆上——实测在 Go 1.21 中,这种写法比缓存 curve := elliptic.P256() 慢约 8%(基准测试用 go test -bench)。
- 把
elliptic.P256()结果赋给包级变量或局部常量,比如var p256 = elliptic.P256() - 不要在 hot path 里用
elliptic.P384()做密钥交换——P-384 的点乘比 P-256 慢近 3 倍,且标准库未对其做汇编优化 - 注意
elliptic.Curve不满足sync.Pool使用条件(无 Reset 方法),别试图池化它
真正难的不是调用哪个函数,而是分清「数学曲线」、「密码协议」和「工程封装」三层边界。比如看到 ecdsa.Verify 失败,第一反应不该是重写点乘,而是检查哈希是否截断、公钥是否被篡改、或签名是否用了错误的曲线参数——这些细节藏在 X.509 解析或 JWT 库里,跟 elliptic 本身关系不大。










