后量子签名的零知识方法:认识MQOM(MQ on my Mind)
本文介绍了MQOM(MQ on my Mind),一种基于MPC-in-the-Head和多元二次方程组(MQ)的零知识证明后量子签名方案。文章解释了其原理:通过将秘密拆分为多个份额,利用多方计算证明知道满足P(s)=y的s而不泄露。对比了NIST第二轮候选签名方案,给出了MQOM不同参数下的密钥和签名大小,并提供了使用Zig和Liboqs库的完整代码示例。MQOM支持两种sigma变体(3轮和5轮),提供128位、192位、256位安全级别。

后量子签名的零知识方法:认识 MQOM(MQ on my Mind)
那么,为什么我们不能使用零知识证明方法来生成抗量子签名呢?答案是我们可以使用头内MPC(多方计算) 方法。基于此,MQOM(MQ on my Mind) 目前正在接受 NIST 的评估,已进入附加签名第二轮。正在评估的全部方法包括:
- 多元签名(4个):MAYO、QR-UOV、SNOVA 和 UOV(不平衡油醋)。
- 头内MPC(多方计算)签名(5个):MIRA/MiRitH(头内最小秩)、MQOM(MQ on my Mind)、PERK、RYDE 和 SDitH(头内译码)。
- 基于格的签名(1个):HAWK。
- 基于码的签名(2个):CROSS(编码与受限对象签名)和 LESS(线性等价)。
- 基于对称的签名(1个):FAEST。
- 同源签名(1个):SQIsign。
总体来看,头内MPC方法最受欢迎,其中一种有很大机会被批准用于抗量子签名。好消息是,Liboqs 在 2026 年 7 月的版本中已将 MQOM 集成到其库中。以下是一个演示:
使用 Liboqs 和 Zig 的 MQOM(MQ on my Mind)签名
头内MPC(Picnic)
在上一轮中,我们看到了 Picnic,这是一种头内MPC方法。Picnic 使用非交互式零知识证明知识和MPC(多方计算)。通过MPC,我们可以将问题拆分为多个计算元素,这些元素协同工作以产生结果,且没有任何元素能窥见中间阶段的运算过程。总体而言,Picnic 使用了在 [1] 中定义的头内MPC方法。这种方法的一大优势是只使用对称密钥方法(分组密码和哈希函数)。
为了生成她的签名密钥,Peggy(证明者)生成一个随机的对称密钥。这将是她的私钥 (sk)。然后她创建一个公开的明文块,并用她的对称密钥将其加密成一个公开的密文块。这两个元素构成了她的公钥,如图 1 所示。

图 1
在该方法中(如图 2 所示),我们生成一个随机明文块 (p) 和一个随机密钥 (sk)。接下来,计算 C=LowMC(sk,p),然后确定公钥 pk=(C,p)。为了签名,我们定义知道 sk 使得 C=LowMC(sk,p),并将消息 m 和公钥 pk 与签名证明集成。这样,签名本质上就是使用消息作为 nonce 值对 sk 的知识证明。

图 2
MQOM(MQ on my Mind)
对于 Picnic,我们证明自己知道一个 AES 计算的结果,而对于 MQOM,我们使用头内MPC零知识证明来证明知道一个多元二次方程组的解。然后,利用 Fiat–Shamir 启发式将该证明转换为非交互式数字签名。
让我记住以便更快登录
这样,签名者旨在证明他们知道 s 的值而不泄露它:
P( s)= y
这可以通过基于头内MPC构建的零知识证明来完成。总体而言,我们将秘密拆分为多个份额:
s = s 1+ s 2… sn
每个参与方持有一个份额,它们共同可以评估 P( s) 而无需重构 s。
MQOM(MQ on my Mind)方案支持两种 sigma 变体:三轮变体和五轮变体,分别用于实现短签名或快速性能。这提供了三个安全等级:L1(AES-128 安全性)、L3(AES-192 安全性)和 L5(AES-256 安全性)。
方法 公钥大小 私钥大小 签名大小 安全等级
------------------------------------------------------------------------------------------------------
mqom2_cat1_gf16_fast_r3 60 88 3484 1 (128-bit)
mqom2_cat1_gf16_fast_r5 60 88 3280 1 (128-bit)
mqom2_cat1_gf16_short_r3 60 88 3060 1 (128-bit)
mqom2_cat1_gf16_short_r5 60 88 2916 1 (128-bit)
mqom2_cat3_gf16_fast_r3 90 132 8224 3 (192-bit)
mqom2_cat3_gf16_fast_r5 90 132 7738 3 (192-bit)
mqom2_cat3_gf16_short_r3 90 132 6820 3 (192-bit)
mqom2_cat3_gf16_short_r5 90 132 6496 3 (192-bit)
mqom2_cat5_gf16_fast_r3 122 180 14708 5 (256-bit)
mqom2_cat5_gf16_fast_r5 122 180 13772 5 (256-bit)
mqom2_cat5_gf16_short_r3 122 180 12664 5 (256-bit)
mqom2_cat5_gf16_short_r5 122 180 12014 5 (256-bit)
代码位于 此处:
const std = @import("std");
const c = @cImport({
@cInclude("oqs/oqs.h");
});
fn oqsCheck(rc: c_int, what: []const u8) !void {
// OQS_SUCCESS == 0
if (rc == c.OQS_SUCCESS) return;
std.debug.print("{s} failed (rc={d})\n", .{ what, rc });
return error.OqsError;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Zig 0.15.2 stdout writer pattern
var stdout_buffer: [4096]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const stdout = &stdout_writer.interface;
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
const msg: []const u8 = args[1];
// "mqom2_cat1_gf16_fast_r3", 等
const alg_name = args[2];
// 我们需要以 NUL 结尾的 C 字符串用于 OQS_SIG_new
const alg_z = try std.fmt.allocPrint(allocator, "{s}", .{alg_name});
defer allocator.free(alg_z);
const sig_obj = c.OQS_SIG_new(alg_z.ptr);
defer c.OQS_SIG_free(sig_obj);
const pk_len: usize = sig_obj.*.length_public_key;
const sk_len: usize = sig_obj.*.length_secret_key;
const sig_len_max: usize = sig_obj.*.length_signature;
const pk = try allocator.alloc(u8, pk_len);
defer allocator.free(pk);
const sk = try allocator.alloc(u8, sk_len);
defer allocator.free(sk);
// 生成密钥对 (sk - 私钥, pk - 公钥)
try oqsCheck(c.OQS_SIG_keypair(sig_obj, pk.ptr, sk.ptr), "OQS_SIG_keypair");
// 使用私钥 (sk) 对消息签名
var signature = try allocator.alloc(u8, sig_len_max);
defer allocator.free(signature);
var sig_len: usize = 0;
try oqsCheck(
c.OQS_SIG_sign(sig_obj, signature.ptr, &sig_len, msg.ptr, msg.len, sk.ptr),
"OQS_SIG_sign",
);
signature = signature[0..sig_len];
// 使用公钥 (pk) 验证签名
const vrc = c.OQS_SIG_verify(sig_obj, msg.ptr, msg.len, signature.ptr, signature.len, pk.ptr);
const ok = (vrc == c.OQS_SUCCESS);
try stdout.print("Liboqs. Algorithm: {s}\n", .{alg_name});
try stdout.print("Message: {s}\n\n", .{msg});
if (sk_len > 200) {
try stdout.print("Private key (first 200 bytes): {x} Length: {d}\n\n", .{ sk[0..200], sk_len });
} else try stdout.print("Private key: {x} Length: {d}\n\n", .{ sk, sk_len });
if (pk_len > 200) {
try stdout.print("Public key (first 200 bytes): {x} Length: {d}\n\n", .{ pk[0..200], pk_len });
} else try stdout.print("Public key: {x} Length: {d}\n\n", .{ pk, pk_len });
if (sig_len > 200) {
try stdout.print("Signature (first 200 bytes): {x} Length: {d}\n\n", .{ signature[0..200], sig_len });
} else try stdout.print("Signature key: {x} Length: {d}\n\n", .{ signature, sig_len });
try stdout.print("Verify: {s}\n\n", .{if (ok) "OK" else "FAIL"});
try stdout.flush();
}
我们可以使用 Zig 和 liboqs.lib 库进行编译:
zig build-exe zig_oqs_mqom.zig -I C:\home\liboqs\build\include -lc liboqs.lib -target x86_64-windows
对于 mqom2_cat1_gf16_fast_r3,消息为 "Hello" 此处:
Liboqs. Algorithm: mqom2_cat1_gf16_fast_r3
Message: Hello
Private key: e4ea25fb639c59320372f4b0e24cd28d2034a0a6db10d0c8dfd3505160950f98572dabeb68274c3a83d4e2eb8dfc4a2c451db1d01e7d3955721d823e3eec4b0dd2ff8d864141970f3446c3c902201289b164cd54f834cb6a
Length: 88
Public key: e4ea25fb639c59320372f4b0e24cd28d2034a0a6db10d0c8dfd3505160950f98572dabeb68274c3a83d4e2eb8dfc4a2c451db1d01e7d3955721d823e
Length: 60
Signature (first 200 bytes): baf71238e8bbe11068db70f4b07316c9f3c826ff4276ce267ecf99126be68d62f050fb1da6d96b66e1497649fef9ca33ff6501421d2bf21707e2c838d2ab6162a38b95fcd6a1c3575297f2cf9b13d6397548f23582941d43bb48c270ccdb06bd38d45e12c312460310cd88b8dc7bff28492a9cc14a533cfddb91120d09b5cc5620a255e6cc5e89da75e2ed2279a231ffe04ec88a7c555787b4f8159d138a9e0d2d2d0e1981b84cbba6981abea44bcc1e72439e4eb751b5cee55e6dfaad649011ddcee36a3aa11cb0
Length: 3484
Verify: OK
对于 mqom2_cat3_gf16_fast_r3,我们得到更大的密钥尺寸和更大的签名 此处:
Liboqs. Algorithm: mqom2_cat3_gf16_fast_r3
Message: Hello
Private key: dac399c831d5b3119d8da2e0902d7d2f20df59e15e3b3e031055f619c2836bf96e81fdf2b59fd9dae70de2ede26410fc6911c67f9634de4834a103d928312d9567305dac8a87d1f34d476181a9fc8e549d8bd3ba3fd184ab755337b45544ea87984a963c1b3f0e8efef1593d04dbc1a41d49f45460c1b6df233be639876097ba8184066d
Length: 132
Public key: dac399c831d5b3119d8da2e0902d7d2f20df59e15e3b3e031055f619c2836bf96e81fdf2b59fd9dae70de2ede26410fc6911c67f9634de4834a103d928312d9567305dac8a87d1f34d476181a9fc8e549d8bd3ba3fd184ab7553
Length: 90
Signature (first 200 bytes): 0513dbcf07d3854b75d49ec52b02ed96e3577408bb0f3db5166cc490152c9746563d3c3bc88ad6f79555f9b39e2e749a73ce9e6c1e3db982d0998b0f4eb2dcb0521d1dfa0fbdd8b552b3aee42332046af3c447659cc5b1f2ab0ba6cdfcfa06d5844fbdf5124aae0e57e393122f98efbfbe694adb6fe2d3a13daef1b69f73d839b86caf42a86df9a8b087a37d46b81340b0056a9ff45facc06c8fe1e091ba60346333d4ac22c58795281cf318858be757e0c61c992c5d4236d12a230b8351fecc990f045dfced1b69
Length: 8224
Verify: OK
结论
以上就是全部内容。这是一种使用了零知识证明的快速高效的签名方法。
- 原文链接: medium.com/asecuritysite...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~