Commitment Schemes
承诺方案(Commitment Schemes)是密码学中的一种基本原语,用于在不泄露实际内容的情况下,使一方对某个值进行“承诺”,并在稍后时间“揭示”该值。承诺方案在许多密码学协议中起着重要作用,例如零知识证明、多方计算和安全投票等。
承诺方案的基本性质
一个有效的承诺方案通常需要满足以下两个基本性质:
-
隐藏性(Hiding):
- 在承诺阶段,承诺者提供的承诺值不应泄露实际值的任何信息。换句话说,接收者在承诺阶段无法从承诺值中推断出实际值。
-
绑定性(Binding):
- 在揭示阶段,承诺者不能更改其承诺的值。也就是说,一旦承诺者生成了一个承诺值,他们就无法找到另一个不同的值来匹配相同的承诺值。
承诺方案的两个阶段
一个典型的承诺方案包括两个阶段:承诺阶段和揭示阶段。
-
承诺阶段(Commitment Phase):
- 承诺者选择一个秘密值 和一个随机数 。
- 计算承诺值 ,并将 发送给接收者。
-
揭示阶段(Reveal Phase):
- 承诺者揭示秘密值 和随机数 。
- 接收者验证 是否等于 。如果相等,则验证通过。
具体例子
基于哈希函数的承诺方案
一种简单的承诺方案可以使用哈希函数来实现。假设 是一个安全的哈希函数:
-
承诺阶段:
- 承诺者选择一个秘密值 和一个随机数 。
- 计算承诺值 ,其中 表示串联操作。
- 将 发送给接收者。
-
揭示阶段:
- 承诺者揭示 和 。
- 接收者计算 并检查是否等于 。
这种方案满足隐藏性,因为哈希函数的输出应该在输入未知的情况下是不可预测的。它也满足绑定性,因为找到两个不同的 和 使得 相同是计算上不可行的(假设哈希函数是碰撞抗性的)。
基于离散对数的承诺方案
另一种常见的承诺方案基于离散对数问题:
-
承诺阶段:
- 承诺者选择一个秘密值 和一个随机数 。
- 计算承诺值 ,其中 和 是公认的生成元。
- 将 发送给接收者。
-
揭示阶 段:
- 承诺者揭示 和 。
- 接收者计算 并检查是否等于 。
这种方案在离散对数问题难解的假设下是安全的,满足隐藏性和绑定性。
应用
承诺方案在许多密码学协议中有广泛应用,包括但不限于:
- 零知识证明:在零知识证明中,承诺方案用于隐藏证明者的某些信息,同时允许验证者在稍后阶段验证这些信息。
- 多方计算:在多方计算协议中,参与者使用承诺方案来隐藏其输入,直到所有参与者都提交了承诺值,从而防止提前泄露信息。
- 安全投票:在电子投票系统中,选民可以使用承诺方案提交其投票,确保投票的隐私性和不可篡改性。
总结
承诺方案是密码学中的一个重要工具,提供了一种在不泄露实际内容的情况下进行信息承诺的方法。它们在许多高级密码学协议中起着关键作用,确保协议的安全性和隐私性。
code
package commitment
import (
"crypto/rand"
"math/big"
"github.com/okx/threshold-lib/crypto"
)
type (
Commitment = *big.Int
Witness = []*big.Int
HashCommitment struct {
C Commitment
Msg Witness
}
)
// NewCommitment commit []*big.int use sha512
func NewCommitment(secrets ...*big.Int) *HashCommitment {
var rBytes [32]byte
_, err := rand.Read(rBytes[:])
if err != nil {
return nil
}
r := new(big.Int).SetBytes(rBytes[:])
parts := make([]*big.Int, len(secrets)+1)
parts[0] = r
for i := 1; i < len(parts); i++ {
parts[i] = secrets[i-1]
}
hash := crypto.SHA512Int(parts...)
cmt := &HashCommitment{}
cmt.C = hash
cmt.Msg = parts
return cmt
}
// Verify verify the commitment
func (cmt *HashCommitment) Verify() bool {
C, D := cmt.C, cmt.Msg
if C == nil || D == nil {
return false
}
hash := crypto.SHA512Int(D...)
return hash.Cmp(C) == 0
}
// Open open the commitment
func (cmt *HashCommitment) Open() (bool, Witness) {
if cmt.Verify() {
return true, cmt.Msg[1:]
} else {
return false, nil
}
}
这个 Go 代码定义了一个简单的承诺方案(commitment scheme),使用 SHA-512 作为哈希函数来实现。承诺方案在密码学中用于确保某个值在某个时间点被固定,并且在之后的时间点可以验证该值是否被篡改。
以下是代码的详细解释:
类型定义
type (
Commitment = *big.Int
Witness = []*big.Int
HashCommitment struct {
C Commitment
Msg Witness
}
)
Commitment是一个指向big.Int的指针,表示承诺值。Witness是一个*big.Int的切片,表示见证值。HashCommitment结构体包含两个字段:C是承诺值。Msg是见证值。
NewCommitment 函数
func NewCommitment(secrets ...*big.Int) *HashCommitment {
var rBytes [32]byte
_, err := rand.Read(rBytes[:])
if err != nil {
return nil
}
r := new(big.Int).SetBytes(rBytes[:])
parts := make([]*big.Int, len(secrets)+1)
parts[0] = r
for i := 1; i < len(parts); i++ {
parts[i] = secrets[i-1]
}
hash := crypto.SHA512Int(parts...)
cmt := &HashCommitment{}
cmt.C = hash
cmt.Msg = parts
return cmt
}
NewCommitment函数接受一个或多个*big.Int类型的秘密值作为参数。- 它首先生成一个 32 字节的随机数
r,并将其转换为*big.Int类型。 - 然后创建一个
parts切片,其长度比秘密值多一个元素,并将r放在第一个位置,秘密值依次放在后面的位置。 - 使用
crypto.SHA512Int函数计算parts的哈希值作为承诺值C。 - 最后,创建一个
HashCommitment结构体,将计算得到的承诺值C和见证值parts赋值给它,并返回该结构体。
Verify 函数
func (cmt *HashCommitment) Verify() bool {
C, D := cmt.C, cmt.Msg
if C == nil || D == nil {
return false
}
hash := crypto.SHA512Int(D...)
return hash.Cmp(C) == 0
}
Verify函数用于验证承诺是否有效。- 它首先检查承诺值
C和见证值D是否为nil,如果是则返回false。 - 然后重新计算见证值
D的哈希值,并将其与承诺值C进行比较,如果相等则返回true,否则返回false。
Open 函数
func (cmt *HashCommitment) Open() (bool, Witness) {
if cmt.Verify() {
return true, cmt.Msg[1:]
} else {
return false, nil
}
}
Open函数用于打开承诺,返回见证值。- 它首先调用
Verify函数验证承诺是否有效。 - 如果承诺有效,则返回
true和见证值(去掉第一个随机数r)。 - 如果承诺无效,则返回
false和nil。
这个承诺方案的主要用途是确保某个秘密值在某个时间点被固定,并且在之后的时间点可以验证该值是否被篡改。