Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zk/dl: adds prefixed labels and updates nomenclature. #396

Merged
merged 1 commit into from Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
110 changes: 55 additions & 55 deletions zk/dl/dl.go
@@ -1,86 +1,86 @@
// Reference: https://datatracker.ietf.org/doc/html/rfc8235#page-6
// Prove the knowledge of [k] given [k]G, G and the curve where the points reside
// Package dl provides a Schnorr NIZK discrete-log proof.
//
// This package implements a Schnorr NIZK discrete-log proof obtained from the
// interactive Schnorr identification scheme through a Fiat-Shamir transformation.
//
// Given (k,G,kG) the Prove function returns a Proof struct attesting that
// kG = [k]G, which can be validated using the Verify function.
//
// The userID label is a unique identifier for the prover.
//
// The otherInfo label is defined to allow flexible inclusion of contextual
// information in the Schnorr NIZK proof.
// The otherInfo is also used as a domain separation tag (dst) for the hash
// to scalar function.
//
// Reference: https://datatracker.ietf.org/doc/html/rfc8235
package dl

import (
"encoding/binary"
"io"

"github.com/cloudflare/circl/group"
)

// Input: myGroup, the group we operate in
// Input: R = [kA]DB
// Input: proverLabel, verifierLabel labels of prover and verifier
// Ouptput: (V,r), the prove such that we know kA without revealing kA
func ProveGen(myGroup group.Group, DB, R group.Element, kA group.Scalar, proverLabel, verifierLabel, dst []byte, rnd io.Reader) (group.Element, group.Scalar) {
v := myGroup.RandomNonZeroScalar(rnd)
V := myGroup.NewElement()
V.Mul(DB, v)
type Proof struct {
V group.Element
R group.Scalar
}

// Hash transcript (D_B | V | R | proverLabel | verifierLabel) to get the random coin
DBByte, errByte := DB.MarshalBinary()
func calcChallenge(myGroup group.Group, G, V, A group.Element, userID, otherInfo []byte) group.Scalar {
// Hash transcript (G | V | A | UserID | OtherInfo) to get the random coin.
GByte, errByte := G.MarshalBinary()
if errByte != nil {
panic(errByte)
}
VByte, errByte := V.MarshalBinary()
if errByte != nil {
panic(errByte)
}

RByte, errByte := R.MarshalBinary()
AByte, errByte := A.MarshalBinary()
if errByte != nil {
panic(errByte)
}

hashByte := append(DBByte, VByte...)
hashByte = append(hashByte, RByte...)
hashByte = append(hashByte, proverLabel...)
hashByte = append(hashByte, verifierLabel...)

c := myGroup.HashToScalar(hashByte, dst)
uPrefix := [4]byte{}
binary.BigEndian.PutUint32(uPrefix[:], uint32(len(userID)))
oPrefix := [4]byte{}
binary.BigEndian.PutUint32(oPrefix[:], uint32(len(otherInfo)))

kAc := myGroup.NewScalar()
kAc.Mul(c, kA)
r := v.Copy()
r.Sub(r, kAc)
hashByte := append(append(append(append(append(append(
GByte, VByte...), AByte...),
uPrefix[:]...), userID...),
oPrefix[:]...), otherInfo...)

return V, r
return myGroup.HashToScalar(hashByte, otherInfo)
}

// Input: myGroup, the group we operate in
// Input: R = [kA]DB
// Input: (V,r), the prove such that the prover knows kA
// Input: proverLabel, verifierLabel labels of prover and verifier
// Output: V ?= [r]D_B +[c]R
func Verify(myGroup group.Group, DB, R group.Element, V group.Element, r group.Scalar, proverLabel, verifierLabel, dst []byte) bool {
// Hash the transcript (D_B | V | R | proverLabel | verifierLabel) to get the random coin
DBByte, errByte := DB.MarshalBinary()
if errByte != nil {
panic(errByte)
}
VByte, errByte := V.MarshalBinary()
if errByte != nil {
panic(errByte)
}
// Prove returns a proof attesting that kG = [k]G.
func Prove(myGroup group.Group, G, kG group.Element, k group.Scalar, userID, otherInfo []byte, rnd io.Reader) Proof {
v := myGroup.RandomNonZeroScalar(rnd)
V := myGroup.NewElement()
V.Mul(G, v)

RByte, errByte := R.MarshalBinary()
if errByte != nil {
panic(errByte)
}
hashByte := append(DBByte, VByte...)
hashByte = append(hashByte, RByte...)
hashByte = append(hashByte, proverLabel...)
hashByte = append(hashByte, verifierLabel...)
c := calcChallenge(myGroup, G, V, kG, userID, otherInfo)

r := myGroup.NewScalar()
r.Sub(v, myGroup.NewScalar().Mul(k, c))

return Proof{V, r}
}

c := myGroup.HashToScalar(hashByte, dst)
// Verify checks whether the proof attests that kG = [k]G.
func Verify(myGroup group.Group, G, kG group.Element, p Proof, userID, otherInfo []byte) bool {
c := calcChallenge(myGroup, G, p.V, kG, userID, otherInfo)

rDB := myGroup.NewElement()
rDB.Mul(DB, r)
rG := myGroup.NewElement()
rG.Mul(G, p.R)

cR := myGroup.NewElement()
cR.Mul(R, c)
ckG := myGroup.NewElement()
ckG.Mul(kG, c)

rDB.Add(rDB, cR)
rG.Add(rG, ckG)

return V.IsEqual(rDB)
return p.V.IsEqual(rG)
}
17 changes: 9 additions & 8 deletions zk/dl/dl_test.go
@@ -1,13 +1,14 @@
package dl
package dl_test

import (
"crypto/rand"
"testing"

"github.com/cloudflare/circl/group"
"github.com/cloudflare/circl/zk/dl"
)

const testzkDLCount = 10
const testzkDLCount = 1 << 8

func testzkDL(t *testing.T, myGroup group.Group) {
kA := myGroup.RandomNonZeroScalar(rand.Reader)
Expand All @@ -18,11 +19,11 @@ func testzkDL(t *testing.T, myGroup group.Group) {

dst := "zeroknowledge"
rnd := rand.Reader
V, r := ProveGen(myGroup, DB, R, kA, []byte("Prover"), []byte("Verifier"), []byte(dst), rnd)
proof := dl.Prove(myGroup, DB, R, kA, []byte("Prover"), []byte(dst), rnd)

verify := Verify(myGroup, DB, R, V, r, []byte("Prover"), []byte("Verifier"), []byte(dst))
verify := dl.Verify(myGroup, DB, R, proof, []byte("Prover"), []byte(dst))
if verify == false {
t.Error("zkRDL verification failed")
t.Error("zk/dl verification failed")
}
}

Expand All @@ -34,11 +35,11 @@ func testzkDLNegative(t *testing.T, myGroup group.Group) {

dst := "zeroknowledge"
rnd := rand.Reader
V, r := ProveGen(myGroup, DB, R, kA, []byte("Prover"), []byte("Verifier"), []byte(dst), rnd)
proof := dl.Prove(myGroup, DB, R, kA, []byte("Prover"), []byte(dst), rnd)

verify := Verify(myGroup, DB, R, V, r, []byte("Prover"), []byte("Verifier"), []byte(dst))
verify := dl.Verify(myGroup, DB, R, proof, []byte("Prover"), []byte(dst))
if verify == true {
t.Error("zkRDL verification should fail")
t.Error("zk/dl verification should fail")
}
}

Expand Down