Skip to main content

Commitment Schemes

承诺方案(Commitment Schemes)是密码学中的一种基本原语,用于在不泄露实际内容的情况下,使一方对某个值进行“承诺”,并在稍后时间“揭示”该值。承诺方案在许多密码学协议中起着重要作用,例如零知识证明、多方计算和安全投票等。

承诺方案的基本性质

一个有效的承诺方案通常需要满足以下两个基本性质:

  1. 隐藏性(Hiding)

    • 在承诺阶段,承诺者提供的承诺值不应泄露实际值的任何信息。换句话说,接收者在承诺阶段无法从承诺值中推断出实际值。
  2. 绑定性(Binding)

    • 在揭示阶段,承诺者不能更改其承诺的值。也就是说,一旦承诺者生成了一个承诺值,他们就无法找到另一个不同的值来匹配相同的承诺值。

承诺方案的两个阶段

一个典型的承诺方案包括两个阶段:承诺阶段和揭示阶段。

  1. 承诺阶段(Commitment Phase)

    • 承诺者选择一个秘密值 mm 和一个随机数 rr
    • 计算承诺值 C=Commit(m,r)C = \text{Commit}(m, r),并将 CC 发送给接收者。
  2. 揭示阶段(Reveal Phase)

    • 承诺者揭示秘密值 mm 和随机数 rr
    • 接收者验证 CC 是否等于 Commit(m,r)\text{Commit}(m, r)。如果相等,则验证通过。

具体例子

基于哈希函数的承诺方案

一种简单的承诺方案可以使用哈希函数来实现。假设 HH 是一个安全的哈希函数:

  1. 承诺阶段

    • 承诺者选择一个秘密值 mm 和一个随机数 rr
    • 计算承诺值 C=H(mr)C = H(m \| r),其中 \| 表示串联操作。
    • CC 发送给接收者。
  2. 揭示阶段

    • 承诺者揭示 mmrr
    • 接收者计算 H(mr)H(m \| r) 并检查是否等于 CC

这种方案满足隐藏性,因为哈希函数的输出应该在输入未知的情况下是不可预测的。它也满足绑定性,因为找到两个不同的 mmrr 使得 H(mr)H(m \| r) 相同是计算上不可行的(假设哈希函数是碰撞抗性的)。

基于离散对数的承诺方案

另一种常见的承诺方案基于离散对数问题:

  1. 承诺阶段

    • 承诺者选择一个秘密值 mm 和一个随机数 rr
    • 计算承诺值 C=gmhrC = g^m h^r,其中 gghh 是公认的生成元。
    • CC 发送给接收者。
  2. 揭示阶段

    • 承诺者揭示 mmrr
    • 接收者计算 gmhrg^m h^r 并检查是否等于 CC

这种方案在离散对数问题难解的假设下是安全的,满足隐藏性和绑定性。

应用

承诺方案在许多密码学协议中有广泛应用,包括但不限于:

  • 零知识证明在零知识证明中,承诺方案用于隐藏证明者的某些信息,同时允许验证者在稍后阶段验证这些信息
  • 多方计算在多方计算协议中,参与者使用承诺方案来隐藏其输入,直到所有参与者都提交了承诺值,从而防止提前泄露信息
  • 安全投票:在电子投票系统中,选民可以使用承诺方案提交其投票,确保投票的隐私性和不可篡改性。

总结

承诺方案是密码学中的一个重要工具,提供了一种在不泄露实际内容的情况下进行信息承诺的方法。它们在许多高级密码学协议中起着关键作用,确保协议的安全性和隐私性。

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)。
  • 如果承诺无效,则返回 falsenil

这个承诺方案的主要用途是确保某个秘密值在某个时间点被固定,并且在之后的时间点可以验证该值是否被篡改。