登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go教程

Go crypto/mldsa 怎样在生成 ML-DSA 签名(输入边界)

来源:17golang原创

时间:2026-10-25 05:43:24 112浏览 收藏

Go 的 crypto/mldsa 可以生成 ML-DSA 密钥并对消息签名。入门时建议选择 MLDSA44 参数集,通过 GenerateKey 创建密钥,把原始消息字节传给 Sign,再用对应公钥、同一份消息和相同 Context 调用 Verify。最容易传错的输入不是签名长度,而是把摘要当成消息、把种子当成任意口令,或者让两端的上下文不一致。

官方地址:https://pkg.go.dev/crypto/mldsa

以下以提供 crypto/mldsa 的 Go 1.27 工具链为前提,比较同一个包内的调用方案。示例用于说明接口契约,没有在本文环境执行,也不提供虚构的运行输出或性能数据。

使用场景:先确定双方要签的是同一串字节

以一个发布清单为例:签名端持有清单文件的原始内容,校验端取得公钥、签名和清单。这里的消息是 []byte,不是“看起来一样的文本”。换行、UTF-8 编码、字段顺序或末尾空格发生变化,都可能让待验签字节与签名时不同。

签名接口不会替你确定 JSON 的规范化规则。如果系统签的是文件原始字节,接收端应使用那份原始字节;如果协议规定先序列化,则两端必须采用相同规则。不能先解析为对象,再随意重新排版,最后把验签失败归因于算法。

同样,公钥应来自系统约定的可信分发渠道。把公钥与消息一起从不可信来源拿来,只能检查这两者是否相配,不能据此证明发布者身份。这里的输入边界属于应用协议,单次 Verify 调用无法代替它。

候选方案:随机生成密钥与导入种子各管什么

新建签名身份时,GenerateKey(params) 负责产生随机私钥;恢复已有身份时,NewPrivateKey(params, seed) 使用已有种子。两者解决的是不同任务。后者要求种子恰好为32字节,不能把用户名、密码、十六进制文本或任意长度随机串直接塞进去。

PrivateKey.Bytes() 导出的是私钥种子。种子属于秘密材料;公钥编码则由 PublicKey.Bytes() 取得。工程上应给这两类数据不同的字段名、存储权限和传输用途,避免把都叫 bytes 的结果混用。

图中的密钥入口组包含 GenerateKey、NewPrivateKey 和 seed;密钥对象组包含 PrivateKey、PublicKey 与公钥编码。静态关系分别为生成、种子输入、恢复、对应公钥和公钥导出,不表示实际执行记录。

随机密钥生成和种子导入对应私钥及公钥编码的静态关系
图1:密钥输入结构图,两个入口分别服务于创建和恢复身份,公钥编码与私钥种子不可混用。
任务选择输入重点
首次建立签名身份GenerateKey明确参数集,处理返回错误
从已保存秘密恢复身份NewPrivateKey导入准确的32字节种子及原参数集
向验证端分发验证材料PublicKey.Bytes分发公钥编码,不分发私钥种子

对比维度:消息、上下文和参数集不能混用

参数集决定采用 ML-DSA-44、ML-DSA-65 还是 ML-DSA-87。Go 文档给多数应用的起点是 MLDSA44;具体协议有明确要求时按协议选择。接收公钥编码时,应把参数集也纳入格式约定,而不是凭文件名或字节串的外观猜测。

Options.Context 用于区分签名用途,最多255字节。它不是 context.Context,也不承载取消信号。比如固定使用 release-manifest/v1,可以表达该签名属于发布清单协议。验证端必须使用同样的值;空上下文也应当是双方明确约定,而不是一端忘了设置。

Go 的字符串长度 len(ctx) 按字节计数,因此中文上下文不能按“255个字符”理解。对用户可配置的上下文,应在进入签名接口前检查字节长度,并保留原字符串,不做单端裁剪或大小写转换。

消息契约组含 message 与 Context,签名材料组含 PrivateKey、PublicKey 与 signature,接口组含 Verify。图中连线表示签名依赖消息、上下文和私钥,验签依赖公钥及签名;正文还要求验签端提供相同消息与上下文。

消息上下文和密钥材料共同限定签名验签契约的结构图
图2:签名契约说明图,消息和上下文属于双方共有的约定,私钥与公钥承担不同角色。

推荐选择:用普通签名接口完成最小闭环

第一次接入时先用普通 Sign 建立闭环,减少与业务无关的输入变化。下面的完整示例用一个固定用途标签和一份原创清单消息,逐项处理密钥生成、签名和验签错误。没有输出私钥,也没有依赖固定签名内容。

package main

import (
    "crypto/mldsa"
    "fmt"
    "log"
)

func main() {
    // 普通应用先选择默认推荐参数集,实际协议要求优先。
    sk, err := mldsa.GenerateKey(mldsa.MLDSA44())
    if err != nil {
        log.Fatal("生成密钥失败: ", err)
    }

    // 签名与验签必须保留完全相同的消息字节和用途标签。
    message := []byte("artifact=guide.zip\nrevision=7\n")
    ctx := "release-manifest/v1"
    if len(ctx) > 255 {
        log.Fatal("上下文超过255字节")
    }
    opts := &mldsa.Options{Context: ctx}

    // 此包的 Sign 忽略 Reader 参数;消息直接传入,不先自行做摘要。
    signature, err := sk.Sign(nil, message, opts)
    if err != nil {
        log.Fatal("签名失败: ", err)
    }
    if err := mldsa.Verify(sk.PublicKey(), message, signature, opts); err != nil {
        log.Fatal("验签失败: ", err)
    }
    fmt.Println("当前消息验签通过")
}

在自己的项目中,可以把这段程序保存为 main.go,再使用带有该包的工具链执行。成功时应走到最后的提示;如果失败,应依据当前步骤返回的错误定位,不能只检查签名是否为非空。

需要重新导入公钥时,用 NewPublicKey(params, encoding) 并处理错误。encoding 应取自公钥导出的原始字节;如果存储层使用 Base64,应先正确解码,再交给公钥构造函数。参数集与编码应共同传递并与协议约定核对。

不适用情况:不要把任意摘要当成原始消息

Sign 的 opts 为 nil 或 HashFunc 返回零时,会直接签所给消息。它也支持 crypto.MLDSAMu 表示的专用 μ 消息代表值,但这不是“随便选一个哈希”的通用开关。把 SHA-256 摘要放进普通消息位置,只是在签那串摘要字节;并不自动等于协议定义的预处理模式。

如果现有抽象把所有 crypto.Signer 都视为“先算摘要再签名”,接入时应先审视这个抽象。ML-DSA 的消息输入规则必须由协议与包文档共同确定,不能为了复用旧调用器而伪造一个非零 HashFunc。本文的入门例子只采用直接消息模式,不展开专用 μ 模式的构造。

SignDeterministic 是另一个选择:它提供确定性签名。需要可重复结果且协议允许时再采用;普通接入不应把“同一消息产生完全相同的签名字节”当成成功条件。验签是否成功与签名字节是否每次相同,是两个判断。

最后,签名不负责加密消息,也不负责建立网络会话。需要保密传输、证书信任或发布者授权时,应在系统其他部分建立对应机制。不要将“用了后量子签名”扩大解释成整套系统已经具备某种完整安全保证。

决策表:按输入条件选择调用方式

输入情况采用的方式先明确什么
新密钥与完整消息GenerateKey + Sign参数集、原始字节与用途标签
已有私钥种子NewPrivateKey32字节秘密种子及原参数集
接收公钥和签名NewPublicKey + Verify可信公钥来源、消息与相同上下文
需要确定性签名SignDeterministic协议是否允许,不能以重复字节替代验签
只有普通摘要先明确协议不能默认当成 μ 消息代表值

Context 可以用中文吗?接口使用字符串,但限制按字节计算;双方还必须保持同样的编码和值。固定短协议标签通常比临时自然语言描述更容易保持一致。

种子可以每次重新生成吗?如果需要保持同一签名身份,应恢复同一秘密种子对应的密钥并保留参数约定;每次新建身份会改变接收方所信任的公钥。

为什么能签名却不能验签?先分别排查消息字节、Context、公钥及参数集的对应关系,再看编码与传输是否改变了签名材料。非空签名不能证明接收端使用了同一份输入。

接口依据:Go crypto/mldsa 官方文档;版本背景见 Go 1.27 发布说明。本文比较的是同包内不同输入入口,不以未经测量的速度或签名强度排名替代协议选择。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>