Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds prefixed labels and updates nomenclature.
- Loading branch information
Showing
2 changed files
with
64 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters