Commit 0227cb44 authored by Anders Jensen Løvig's avatar Anders Jensen Løvig
Browse files

Fix Schnorr and remove Schnorr disjunction

parent 4f1f5dca
Pipeline #21850 passed with stages
in 1 minute and 38 seconds
......@@ -12,6 +12,7 @@ import (
// Params represent parameters required by Schnorr's protocol
type Params struct {
Zq *zn.Zn
Zp *zn.Zn
G *big.Int
H *big.Int
......@@ -21,6 +22,7 @@ type Params struct {
func NewParams(params *common.Params) *Params {
return &Params{
Zp: params.Zp,
Zq: params.Zq,
G: params.G,
H: params.H,
}
......@@ -28,95 +30,114 @@ func NewParams(params *common.Params) *Params {
// Proof struct as the tuple of numbers required for the proof
type Proof struct {
token *big.Int // a
commit *big.Int // a
challenge *big.Int // e
response *big.Int // z
commit *big.Int // y
}
// Prove the knowledge of 'w'
// Prove the knowledge of 'w' in statement x
// the challenge is generated from the hash of y
func (s *Params) Prove(w *big.Int) *Proof {
e := Hash(s.Zp.Exp(s.G, w))
return s.ProveWithChallenge(w, e)
}
func (s *Params) Prove(w, y *big.Int) *Proof {
r := s.Zq.GetRandomElement()
a := s.Zp.Exp(s.G, r)
// ProveWithChallenge 'w' by supplying the challenge 'e'
func (s *Params) ProveWithChallenge(w, e *big.Int) *Proof {
return s.ProveWithChallengeFn(w, func(_ *Proof) *big.Int { return e })
}
e := Hash(a, s.G, y)
// ProveWithChallengeFn proves 'w' by using a function 'fn' to
// generate the challenge
func (s *Params) ProveWithChallengeFn(w *big.Int, fn func(*Proof) *big.Int) *Proof {
proof := new(Proof)
proof.commit = s.Zp.Exp(s.G, w) // y = g^w
r := s.Zp.GetRandomElement()
proof.token = s.Zp.Exp(s.G, r) // a = g^r
proof.challenge = fn(proof)
proof.response = s.Zp.Add(r, s.Zp.Mul(proof.challenge, w)) // z = r + ew
return proof
}
z := s.Zq.Add(r, s.Zq.Mul(e, w))
// Verify the proof by doing the comparison g^z = a*y^e
func (s *Params) Verify(proof *Proof) bool {
left := s.Zp.Exp(s.G, proof.response)
right := s.Zp.Mul(s.Zp.Exp(proof.commit, proof.challenge), proof.token)
return left.Cmp(right) != 0
return &Proof{a, e, z}
}
// ForgeProof creates a forged proof.
func (s *Params) ForgeProof(Q *big.Int) *Proof {
proof := new(Proof)
proof.commit = Q
proof.challenge = s.Zp.GetRandomElement()
proof.response = s.Zp.GetRandomElement()
func (s *Params) Verify(y *big.Int, proof *Proof) bool {
e := Hash(proof.commit, s.G, y)
t1 := s.Zp.Neg(proof.challenge)
t2 := s.Zp.Exp(s.H, proof.response)
t3 := s.Zp.Exp(Q, t1)
if e.Cmp(proof.challenge) != 0 {
log.Printf("%d != %d\n", e, proof.challenge)
return false
}
proof.token = s.Zp.Mul(t2, t3)
return proof
}
rhs := s.Zp.Exp(s.G, proof.response)
lhs := s.Zp.Mul(proof.commit, s.Zp.Exp(y, e))
// ProveDisjunction creates double proof for which one of them is false
// providing the parameters 'w' for the real one and 'Q' for the fake.
func (s *Params) ProveDisjunction(w, Q *big.Int) (*Proof, *Proof) {
p0 := s.ForgeProof(Q)
fn := func(p *Proof) *big.Int {
t := Hash(s.G, s.H, p0.token, p.token, p0.commit, p.commit)
t = s.Zp.Mod(t)
return s.Zp.Sub(t, p0.challenge)
}
p1 := s.ProveWithChallengeFn(w, fn)
return p0, p1
return rhs.Cmp(lhs) == 0
}
// VerifyDisjunction verifies that the double proof p0 and p1 hold.
func (s *Params) VerifyDisjunction(p0, p1 *Proof) bool {
t := Hash(s.G, s.H, p0.token, p1.token, p0.commit, p1.commit)
t = s.Zp.Mod(t)
e := s.Zp.Add(p0.challenge, p1.challenge)
if e.Cmp(t) != 0 {
return false
}
if !s.Verify(p0) {
log.Println("failed first proof")
return false
}
if !s.Verify(p1) {
log.Println("failed second proof")
return false
}
return true
}
// // ProveWithChallenge 'w' by supplying the challenge 'e'
// func (s *Params) ProveWithChallenge(w, e *big.Int) *Proof {
// return s.ProveWithChallengeFn(w, func(_ *Proof) *big.Int { return e })
// }
// // ProveWithChallengeFn proves 'w' by using a function 'fn' to
// // generate the challenge
// func (s *Params) ProveWithChallengeFn(w *big.Int, fn func(*Proof) *big.Int) *Proof {
// proof := new(Proof)
// proof.commit = s.Zp.Exp(s.G, w) // y = g^w
// r := s.Zp.GetRandomElement()
// proof.token = s.Zp.Exp(s.G, r) // a = g^r
// proof.challenge = fn(proof)
// proof.response = s.Zp.Add(r, s.Zp.Mul(proof.challenge, w)) // z = r + ew
// return proof
// }
// // Verify the proof by doing the comparison g^z = a*y^e
// func (s *Params) Verify(proof *Proof) bool {
// left := s.Zp.Exp(s.G, proof.response)
// right := s.Zp.Mul(s.Zp.Exp(proof.commit, proof.challenge), proof.token)
// return left.Cmp(right) != 0
// }
// // ForgeProof creates a forged proof.
// func (s *Params) ForgeProof(Q *big.Int) *Proof {
// proof := new(Proof)
// proof.commit = Q
// proof.challenge = s.Zp.GetRandomElement()
// proof.response = s.Zp.GetRandomElement()
// t1 := s.Zp.Neg(proof.challenge)
// t2 := s.Zp.Exp(s.H, proof.response)
// t3 := s.Zp.Exp(Q, t1)
// proof.token = s.Zp.Mul(t2, t3)
// return proof
// }
// // ProveDisjunction creates double proof for which one of them is false
// // providing the parameters 'w' for the real one and 'Q' for the fake.
// func (s *Params) ProveDisjunction(w, Q *big.Int) (*Proof, *Proof) {
// p0 := s.ForgeProof(Q)
// fn := func(p *Proof) *big.Int {
// t := Hash(s.G, s.H, p0.token, p.token, p0.commit, p.commit)
// t = s.Zp.Mod(t)
// return s.Zp.Sub(t, p0.challenge)
// }
// p1 := s.ProveWithChallengeFn(w, fn)
// return p0, p1
// }
// // VerifyDisjunction verifies that the double proof p0 and p1 hold.
// func (s *Params) VerifyDisjunction(p0, p1 *Proof) bool {
// t := Hash(s.G, s.H, p0.token, p1.token, p0.commit, p1.commit)
// t = s.Zp.Mod(t)
// e := s.Zp.Add(p0.challenge, p1.challenge)
// if e.Cmp(t) != 0 {
// return false
// }
// if !s.Verify(p0) {
// log.Println("failed first proof")
// return false
// }
// if !s.Verify(p1) {
// log.Println("failed second proof")
// return false
// }
// return true
// }
// Hash the given big ints into a new big int using sha512
func Hash(ls ...*big.Int) *big.Int {
hash := sha512.New()
for _, e := range ls {
hash.Write(e.Bytes())
_, _ = hash.Write(e.Bytes())
}
sum := hash.Sum([]byte{})
return new(big.Int).SetBytes(sum)
......
......@@ -6,23 +6,34 @@ import (
"testing"
)
func TestDisjunction(t *testing.T) {
params := NewParams(common.DefaultParams())
// func TestDisjunction(t *testing.T) {
// params := NewParams(common.DefaultParams())
w := big.NewInt(23)
Q := big.NewInt(4444)
p0, p1 := params.ProveDisjunction(w, Q)
succes := params.VerifyDisjunction(p0, p1)
if !succes {
t.Fail()
}
}
// w := big.NewInt(23)
// Q := big.NewInt(4444)
// p0, p1 := params.ProveDisjunction(w, Q)
// succes := params.VerifyDisjunction(p0, p1)
// if !succes {
// t.Fail()
// }
// t.Fail()
// }
func TestSchnorr(t *testing.T) {
params := NewParams(common.DefaultParams())
w := big.NewInt(23)
proof := params.Prove(w)
if !params.Verify(proof) {
y := params.Zp.Exp(params.G, w)
proof := params.Prove(w, y)
if !params.Verify(y, proof) {
t.Errorf("proof failed with witness %s", w.String())
}
// y = params.Zp.Exp(params.G, big.NewInt(123))
// proof = params.Prove(y, w)
// if params.Verify(y, proof) {
// t.Errorf("proof incorrectly verified with witness %s", w.String())
// }
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment