密码学 | 多重签名:基于 Schnorr 的 MuSig 方案

⚠️原文:Schnorr Applications: MuSig

⚠️写在前面:本文属搬运博客,自己留存学习。



1 什么是多签名?

多签名 是指:一组签名密钥 ( X 1 , X 2 , . . . , X n ) (X_1, X_2, ..., X_n) (X1,X2,...,Xn) 共同生成一条消息的签名。

任何正常签名方案 —— 如 Schnorr 或 ECDSA —— 的多签名方案,最简单的方法是将每个签名者对给定消息的单个签名连接起来: s = ( s 1 , s 2 , . . . , s n ) s=(s_1, s_2, ..., s_n) s=(s1,s2,...,sn)

个人理解:默认的 Schnorr 或 ECDSA 是单签名方案,但它们也可以有多签名版本。最简单的方式,就是将各个单签名连接起来,构成一个多签名。

这个方案已在比特币中通过操作 OP_CHECKMULTISIG —— 简称 OP_CMS —— 得到支持。实际上,OP_CMS 支持更多的操作,你可以创建一个由 m-of-n 参与者控制的地址,其中 m ≤ n,但我们今天只考虑 n-of-n 的情况。

什么是 m-of-n 参与者?答:意思是,至少需要 n 个参与者中的 m 个人同意,才能生成一个有效的签名。当 m=1 时,它等同于传统的单签名方案,即只需要一个人同意即可生成签名。

虽然 OP_CMS 是一个正确的多签名方案,但它有一些严重的缺点。在这种方案中,n-of-n 多签名将是常规签名的 n 倍 大小,因为它需要在链上放置 n 个签名和公钥对。同样,这比验证单个签名需要更长的时间。最后,它没有隐私功能,因为所有参与者都是公开的,即所有 n 个密钥都必须用于验证。

为什么需要在链上放置 n 个签名和公钥对?答:因为在验证签名的时候,我们需要使用相应的签名和公钥。由于在 OP_CMS 方案中,一个多签名是由 n 个签名拼接来的,因此我们在验证时需要这 n 个签名和它们各自对应的公钥。

MuSig 旨在解决这些问题,它是一个 Schnorr 多签名方案。无论签字方的数量多少,它都能产生一个与普通 Schnorr 签名无法区分的签名。因此,MuSig 签名的验证与普通 Schnorr 签名完全相同。此外,它支持 密钥聚合,因此单个签名密钥可以保持私密。

与 OP_CMS 相比,MuSig 降低了存储负担、减少了验证时间、保护了密钥隐私😇

具体来说,假设有 n 个签名者 X 1 , X 2 , . . . , X n X_1, X_2, ..., X_n X1,X2,...,Xn 和一条消息 m m m,他们希望共同签署这条消息。通过使用 MuSig,他们可以生成一个单一的 Schnorr 签名 ( R , s ) (R, s) (R,s)

这将使用 聚合密钥 X = a g g ( X 1 , X 2 , . . . , X n ) X = agg(X_1, X_2, ..., X_n) X=agg(X1,X2,...,Xn) m m m 进行有效签名,这样在任何公共空间 —— 如区块链 —— 中,这 n 个签名者们可以假装自己只是一位拥有密钥 X X X 的签名者。简而言之,我们可以使得多签名输出和标准输出没有区别。



2 朴素 Schnorr 多签名

针对签名者 i i i,我们对其所使用的变量进行说明:

  • 私钥: x i x_i xi
  • 公钥: X i = x i ∗ G X_i=x_i*G Xi=xiG
  • 一次性私钥: k i k_i ki
  • 部分签名: R i = k i ∗ G R_i=k_i*G Ri=kiG
  • 部分签名: s i = k i + H ( X , R , m ) ∗ x i s_i=k_i+H(X, R, m)*x_i si=ki+H(X,R,m)xi

为什么叫作一次性私钥?答:签名者 i i i 每次签名都会重新生成一个随机值 k i k_i ki,对 k i k_i ki 是用完即弃,与 x i x_i xi 这种长期性私钥应该区分开来。

假设有 n n n 个签名者。

朴素 Schnorr 多签名让每个签名者分享自己的公钥 X i X_i Xi,计算并定义聚合密钥为:

X = X 1 + X 2 + . . . + X n X = X_1 + X_2 + ... + X_n X=X1+X2+...+Xn

让每个签名者生成并分享自己的部分签名 R i R_i Ri,计算并定义部分聚合签名为:

R = R 1 + R 2 + . . . + R n R = R_1 + R_2 + ... + R_n R=R1+R2+...+Rn

为什么 R i R_i Ri 被称为 部分签名 R R R 被称为 部分聚合签名?答:因为一个完整的签名是 ( R , s ) (R, s) (R,s),所以单独的 R R R s s s 只能算作部分签名或者部分聚合签名。

获得部分聚合签名 R R R 后,每个签名者可以自行计算他们的部分签名 s i s_i si

s i = k i + H ( X , R , m ) ∗ x i s_i = k_i + H(X, R, m)*x_i si=ki+H(X,R,m)xi

为了让 s i s_i si 们可以相加,朴素 Schnorr 多签名Schnorr 签名 中的 H ( X , R i , m ) H(X, R_i, m) H(X,Ri,m) 改为了 H ( X , R , m ) H(X, R, m) H(X,R,m)

然后再分享自己的部分签名 s i s_i si,计算并定义部分聚合签名为:

s = s 1 + s 2 + . . . + s n = ( k 1 + . . . + k n ) + H ( X , R , m ) ∗ ( x 1 + . . . + x n ) = k + H ( X , R , m ) ∗ x \begin{alignat}{2} s &= s_1 + s_2 + ... + s_n \\ &= (k_1 + ... + k_n) + H(X, R, m)*(x_1 + ... + x_n) \\ &= k + H(X, R, m)*x \end{alignat} s=s1+s2+...+sn=(k1+...+kn)+H(X,R,m)(x1+...+xn)=k+H(X,R,m)x

最终的朴素 Schnorr 多签名为 ( R , s ) (R,s) (R,s),涉及以下变量:

  • 聚合私钥: x x x
  • 聚合公钥: X X X
  • 聚合一次性私钥: k k k
  • 聚合部分签名: R R R
  • 聚合部分签名: s s s

验证者的验证等式为:

s ∗ G = ? R + H ( R , M ) ∗ X s*G\overset{?}{=} R+H(R,M)*X sG=?R+H(R,M)X

可以看出,上述方案不仅是一个 多签名方案,还是一个 聚合签名方案,因为它允许将多个签名合并为一个签名,隐藏掉了原始的单个签名的信息。遗憾的是,该方案容易受到所谓的 恶意密钥攻击 或称 流氓密钥攻击

英文是 Rogue Key Attack



3 恶意密钥攻击

假设我的公钥是 X 1 X_1 X1

我可以撒谎,将一个 X 1 ′ = X 1 − X 2 − . . . − X n X_1'=X_1 - X_2 - ... - X_n X1=X1X2...Xn 值传给其他签名者,并声称这就是我的公钥。这将导致聚合公钥 X X X 变为 X = X 1 ′ + X 2 + . . . + X n = X 1 X = X_1' + X_2 + ... + X_n = X_1 X=X1+X2+...+Xn=X1。又因为我是公钥 X 1 X_1 X1 的所有者,所以我知道 X 1 X_1 X1 对应的私钥。由此一来,我可以单方面将资金发送到任何我想要的地方,而无需任何合作。

首先,因为公钥都是公开的,所以我可以获取到所有其他签名者的公钥。接着,我令虚假公钥的值为 X 1 − X 2 − . . . − X n X_1 - X_2 - ... - X_n X1X2...Xn,以此使聚合公钥 X X X 退化为我的公钥 X 1 X_1 X1 。最后,我便可以为所欲为😈

如果你要求我证明:我对声称属于我的公钥拥有私钥,这将阻止我的恶意密钥攻击,但我还可以对随机数值 R i R_i Ri 执行相同的攻击,以控制聚合一次性私钥 k k k

原文中的 nonce 值是什么意思?答:nonce 是 number once 的缩写,在密码学中 nonce 是一个只被使用一次的任意或非重复的随机数值。

然后,我会在接收完所有其他签名者的部分签名 s i s_i si 之后,计算出聚合签名 s = k + H ( X , R , m ) ∗ x s = k + H(X, R, m)*x s=k+H(X,R,m)x,这将允许我计算出 x x x,再次让我能够不合作地将所有资金发送到任何地方。

刚才已经获取到了 k k k 值, s s s H ( X , R , m ) H(X, R, m) H(X,R,m) 又是已知的,因此可以倒推出 x x x 的值。



4 改进方案

为了修复上述方案,我们需要确保聚合随机数值 R R R 和聚合公钥 X X X 能够抵御恶意密钥攻击。

具体来说,我们要求每个签名者广播自己的随机数 R i R_i Ri 的哈希值 t i = H ( R i ) t_i = H(R_i) ti=H(Ri) —— 而非 R i R_i Ri 本身 —— 并且只有在看到所有其他签名者的 t i t_i ti 之后才揭示自己的随机数 R i R_i Ri

这里说的其实就是一个哈希承诺的过程,请自行补课密码学承诺😇

这种方案能够缓解对随机数 R i R_i Ri 的攻击,但对聚合签名公钥 X X X 来说却不切实际。因为公钥通常是公开的并且可以被重复使用。

上述方案相当于是把 R i R_i Ri 藏起来,但 X i X_i Xi 作为公钥是需要被公开的,因此不切实际。

因此,我们可以尝试改变我们的聚合公钥 X X X,使其通过所有签名公钥 X i X_i Xi 的哈希值来计算。

具体来说,令 L L L 为所有公钥的集合 ( X 1 , X 2 , . . . , X n ) (X_1, X_2, ..., X_n) (X1,X2,...,Xn) 的某种编码,然后让:

a i = H ( L ∣ ∣ X i ) a_i = H(L||X_i) ai=H(L∣∣Xi) X = a 1 ∗ X 1 + a 2 ∗ X 2 + . . . + a n ∗ X n X = a_1*X_1 + a_2*X_2 + ... + a_n*X_n X=a1X1+a2X2+...+anXn

其中 H H H 表示哈希函数。

终于看到论文中使用的方法了,喜极而泣😈

这样就很难从 ( X 1 , X 2 , . . . , X n ) (X_1, X_2, ..., X_n) (X1,X2,...,Xn) 中计算出一个 X 1 ′ X_1' X1 使得 X = X 1 X = X_1 X=X1 了。

然而,这样的修改会使聚合私钥 x = x 1 + . . . + x n x=x_1 + ... + x_n x=x1+...+xn 的值不再是聚合公钥 X X X 对应的私钥的值。幸运的是,有一个简单的调整可以修复这个问题:

s i = k i + H ( X , R , m ) ∗ a i ∗ x i s_i = k_i + H(X, R, m)*a_i*x_i si=ki+H(X,R,m)aixi

个人理解:聚合私钥 x x x 本质上就是聚合公钥 X X X 的私钥,需要满足 x ∗ G = X x*G=X xG=X 这一关系。这里 X i X_i Xi 乘以 a i a_i ai 这一权重后导致 X X X 发生了改变,那么 x i x_i xi 也需要乘以相应的权重,以保证 x x x 仍然是 X X X 的私钥。

这样我们就恢复了我们的聚合签名:

s = s 1 + s 2 + . . . + s n = ( k 1 + . . . + k n ) + H ( X , R , m ) ∗ ( a 1 ∗ x 1 + . . . + a n ∗ x n ) = k + H ( X , R , m ) ∗ x \begin{alignat}{2} s &= s_1 + s_2 + ... + s_n \\ &= (k_1 + ... + k_n) + H(X, R, m)*(a_1*x_1 + ... + a_n*x_n) \\ &= k + H(X, R, m)*x \end{alignat} s=s1+s2+...+sn=(k1+...+kn)+H(X,R,m)(a1x1+...+anxn)=k+H(X,R,m)x

回顾一下,MuSig 签名过程包括三个阶段:

  1. 所有签名者发送承诺 t i t_i ti
  2. 所有签名者揭示随机数 R i R_i Ri,并且所有签名者验证 t i = H ( R i ) t_i = H(R_i) ti=H(Ri)
  3. 所有签名者计算并发送他们的部分签名 s i s_i si

最后,任何所有签名者都可以计算并使用普通 Schnorr 签名 ( R , s ) (R, s) (R,s)

什么是承诺?答:承诺全称密码学承诺,是一个密码学概念,主要用于防止发送者撒谎。



5 未来展望

这是本文中证明安全的 MuSig 提案,但许多人对需要 3 个往返通信的要求不满意,并且已经有很多工作致力于消除一个交互性的回合,以制作一个只有 2 个回合的 MuSig 版本。参见 Jonas Nick 的这篇博客文章,了解为什么将 3 个回合协议缩短为 2 个回合协议的各种捷径是不安全的。



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/1025.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开放式耳机哪个牌子好?热门开放式耳机合集,买前必看!

随着人们对运动健康的重视,越来越多的运动爱好者开始关注如何在运动中享受音乐。开放式蓝牙耳机凭借其独特的设计,成为了户外运动的理想选择。它不仅让你在运动时能够清晰听到周围环境的声音,保持警觉,还能让你在需要时与他人轻松…

Compose Canvas

文章目录 Compose Canvas概述Canvas属性drawPoints 绘制点drawPoints属性使用 drawLine 绘制线drawLine属性使用 drawRect 绘制矩形drawRect属性使用 drawRoundRect 绘制圆角矩形drawRoundRect属性使用 drawCircle 绘制圆drawCircle属性使用 drawOval 绘制椭圆drawOval属性使用…

《王者荣耀》Hello Kitty 小兵皮肤完整设置指南

王者荣耀与三丽鸥的联动活动上线了 Hello Kitty 小兵皮肤,让我们的峡谷小兵们也能穿上漂亮的衣服啦!这款皮肤极具卡哇伊风格,引起了许多玩家的关注。许多小伙伴都想知道如何使用这款 Hello Kitty 小兵皮肤,今天小编将为大家整理出…

5.前后端分离

目录 一、前后端分离上传文件 1.在yml中设置port和localhost 2.如何使用postman测试上传文件的接口 二、如何导出excel文件 ​编辑1.在pom.xml中导包 2.在实体类中给每个字段添加注解,导出表格时,列名将会改为对应的中文 3.controller中方法的具体…

英语新概念2-回译法-lesson10

托尼斯蒂尔进来的时候我正在吃饭,托尼很多年前在一家律师事务所工作,但是他现在在银行工作。他有一份不错的薪资,但是他总是问他的朋友们借钱并且从不归还。托尼看到我然后走过来和我坐在同一张桌子。他从来没有问我借过钱。当他在吃饭的时候…

java程序将内容写到存储文件中

import javax.servlet.*; import javax.servlet.http.*; import java.io.*;public class ShortcutKeysServlet extends HttpServlet {Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 设置…

【OpenGL高级】罗德里格斯公式:绕任意轴旋转

相关主题: OpenGL 矩阵、四元数到矩阵、角度到轴、观察到轴 目录 一、说明二、罗德里格斯公式的推导2.1 空间点旋转问题2.2 对旋转问题的分析 三、罗德里格斯旋转公式矩阵表示:四、最小C代码五、结论 一、说明 解决三维坐标下的刚体旋转问题&#xff0…

Centos7.9下 建立systemd服务自启 包含脚本sh运行springboot

一.建立脚本 1.建立test.sh文件 /home/server/rescue/test.sh #!/bin/bash export JAVA_HOME/usr/lib/jvm/java export JRE_HOME/usr/lib/jvm/jre export CLASS_PATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib export PATH$PATH:$JAVA_HOME/bin:$JRE_…

【Linux】服务器时区 [ CST | UTC | GMT | RTC ]

目录 1. 硬件时间(Real_TIME Clock [RTC time]) 1.1 硬件时间简介 1.2 如何使用硬件时间 2. 系统时间(UTC时间)(Universal time) 2.1 系统时间简介 2.2 UTC时间 3. 本地时间(Local time&…

深入理解大语言模型微调技术

一、概念解析 1、什么是微调(Fine-tuning)? 大模型微调,也称为Fine-tuning,是指在已经预训练好的大型语言模型基础上(一般称为“基座模型”),使用特定的数据集进行进一步的训练&am…

DeepWalk论文精读

介绍 图神经网络的开山之作 DeepWalk:一种用于学习网络中顶点的潜在表示的新方法,使用随机行走中获得的局部信息,通过将序列视为句子,节点视为单词 通过随机游走可以采样出一个序列,序列好比一句话,节点…

记录一个hive中因没启yarn导致的spark引擎跑insert语句的报错

【背景说明】 刚在hive中配置了Spark引擎,在进行Hive on Spark测试时报错, 报错截图如下: [atguiguhadoop102 conf]$ hive which: no hbase in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/module/jdk1.8.0_212/bin:/opt/mod…

【项目案例】基于强化学习Q-Learning训练“汉诺塔Tower of Hanoi”游戏策略

文章目录 1. 引言2. 基本要素定义3. 训练过程3.1 初始化动作价值函数3.2 采集完整状态序列3.3 更新动作估计价值4. 策略检验1. 引言 汉诺塔游戏(Tower of Hanoi)是根据一个传说形成的数学问题,小规模汉诺塔问题也常常作为强化学习的入门案例。它的规则是,在游戏台上,有若…

【LAMMPS学习】八、基础知识(3.5)计算弹性常数

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语,以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

【云计算】云数据中心网络(三):NAT 网关

《云网络》系列,共包含以下文章: 云网络是未来的网络基础设施云网络产品体系概述云数据中心网络(一):VPC云数据中心网络(二):弹性公网 IP云数据中心网络(三)…

【C语言】每日一题,快速提升(8)!

🔥博客主页🔥:【 坊钰_CSDN博客 】 欢迎各位点赞👍评论✍收藏⭐ 题目:金字塔图案 输入: 4输出: * * * * * * * * * * 代码: //对于有行有列的图形采用双循环,i控制行…

C# 面向对象编程(二)——继承

总目录 C# 语法总目录 C# 面向对象编程 二——继承 简介正文继承** 向上向下转型 **as 运算符is 运算符 1. 虚函数和抽象函数 及抽象类2. 隐藏父类成员3.密封函数** base关键字 **4. 构造器继承** 重载与重写 ** 简介 主要记录的是继承的相关注意事项 正文 继承 继承只能继承…

线性投影的意义

线性投影是机器学习和数学中的一个概念,它指的是通过线性变换将数据从一个空间映射到另一个空间的过程。在机器学习中,线性投影通常用于数据降维、特征提取或数据可视化。 数据降维:在处理高维数据时,线性投影可以用来减少数据的维…

[管理者与领导者-177] :人际网络-4-坐车的礼仪

目录 一、坐私车的基本礼仪 二、跟领导乘车,你坐对了吗?要注意什么? 2.1 乘车座次礼仪规则: 2.2 双排5座汽车礼仪的应用 2.2.1 司机驾车 2.2.2 领导驾车 2.3 三排7座商务车 一、坐私车的基本礼仪 坐私人车辆时&#xff0c…

sklearn 笔记: preprocessing.OrdinalEncoder

sklearn.preprocessing.OrdinalEncoder 是一个用于将分类特征编码为整数数组的预处理转换器编码方式:将分类特征(如字符串或整数表示的离散特征)转换成序数整数形式。这样每个特征都被编码为一个整数序列,范围从 0 到该特征的类别…