forked from Zondax/multi-party-sig
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nth.go
95 lines (80 loc) · 1.99 KB
/
nth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// zknth is based on the zkenc package,
// and can be seen as the special case where the ciphertext encrypts the "0" value.
package zknth
import (
"crypto/rand"
"github.com/cronokirby/safenum"
"github.com/sa8/multi-party-sig/pkg/hash"
"github.com/sa8/multi-party-sig/pkg/math/arith"
"github.com/sa8/multi-party-sig/pkg/math/sample"
"github.com/sa8/multi-party-sig/pkg/paillier"
)
type Public struct {
// N
N *paillier.PublicKey
// R = r = ρᴺ (mod N²)
R *safenum.Nat
}
type Private struct {
// Rho = ρ
Rho *safenum.Nat
}
type Commitment struct {
// A = αᴺ (mod N²)
A *safenum.Nat
}
type Proof struct {
Commitment
// Z = αρᴺ (mod N²)
Z *safenum.Nat
}
func (p *Proof) IsValid(public Public) bool {
if !arith.IsValidNatModN(public.N.N(), p.Z) {
return false
}
if !arith.IsValidNatModN(public.N.ModulusSquared().Modulus, p.A) {
return false
}
return true
}
// NewProof generates a proof that r = ρᴺ (mod N²).
func NewProof(hash *hash.Hash, public Public, private Private) *Proof {
N := public.N.N()
// α ← ℤₙˣ
alpha := sample.UnitModN(rand.Reader, N)
// A = αⁿ (mod n²)
A := public.N.ModulusSquared().Exp(alpha, N.Nat())
commitment := Commitment{
A: A,
}
e, _ := challenge(hash, public, commitment)
// Z = αρᵉ (mod N)
Z := public.N.Modulus().ExpI(private.Rho, e)
Z.ModMul(Z, alpha, N)
return &Proof{
Commitment: commitment,
Z: Z,
}
}
func (p *Proof) Verify(hash *hash.Hash, public Public) bool {
if !p.IsValid(public) {
return false
}
e, err := challenge(hash, public, p.Commitment)
if err != nil {
return false
}
NSquared := public.N.ModulusSquared()
lhs := NSquared.Exp(p.Z, public.N.N().Nat())
rhs := NSquared.ExpI(public.R, e)
rhs.ModMul(rhs, p.A, NSquared.Modulus)
if lhs.Eq(rhs) != 1 {
return false
}
return true
}
func challenge(hash *hash.Hash, public Public, commitment Commitment) (e *safenum.Int, err error) {
err = hash.WriteAny(public.N, public.R, commitment.A)
e = sample.IntervalL(hash.Digest())
return
}