Skip to content

Commit

Permalink
Fix VRF uniqueness violation
Browse files Browse the repository at this point in the history
* renamed c, cH, ... with s, sH

it is called s in the CONIKS paper/in KT (in the cfrg draft and other literature it is called c, though)

* Adopt VRF to update in CONIKS paper
- add unique identifier: also hash h=H1(m), g^x and h^x (the VRF output) and not only with random nonce r (g^r, h^r); additionally hash m into H2 (as before)
- like in the paper add the base-point and public-key
- skip outdated test-vectors
- unrelated: remove formatting version of test-output where no placeholder is used

fixes #175
  • Loading branch information
liamsi authored and masomel committed Jun 6, 2017
1 parent 77350b6 commit e9c8209
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 36 deletions.
14 changes: 14 additions & 0 deletions crypto/internal/ed25519/edwards25519/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ var A = FieldElement{
486662, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}

var extendedBaseEl = ExtendedGroupElement{
FieldElement{25485296, 5318399, 8791791, -8299916, -14349720, 6939349, -3324311, -7717049, 7287234, -6577708},
FieldElement{-758052, -1832720, 13046421, -4857925, 6576754, 14371947, -13139572, 6845540, -2198883, -4003719},
FieldElement{-947565, 6097708, -469190, 10704810, -8556274, -15589498, -16424464, -16608899, 14028613, -5004649},
FieldElement{6966464, -2456167, 7033433, 6781840, 28785542, 12262365, -2659449, 13959020, -21013759, -5262166},
}

// BaseBytes can be used to hash the base point if necessary
var BaseBytes [32]byte

func init() {
extendedBaseEl.ToBytes(&BaseBytes)
}

var bi = [8]PreComputedGroupElement{
{
FieldElement{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605},
Expand Down
72 changes: 44 additions & 28 deletions crypto/vrf/vrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,16 @@ func hashToCurve(m []byte) *edwards25519.ExtendedGroupElement {
// same as returned by Compute(m).
func (sk PrivateKey) Prove(m []byte) (vrf, proof []byte) {
x, skhr := sk.expandSecret()
var cH, rH [64]byte
var r, c, minusC, t, grB, hrB, iiB [32]byte
var sH, rH [64]byte
var r, s, minusS, t, gB, grB, hrB, hxB, hB [32]byte
var ii, gr, hr edwards25519.ExtendedGroupElement

hm := hashToCurve(m)
edwards25519.GeScalarMult(&ii, x, hm)
ii.ToBytes(&iiB)
h := hashToCurve(m)
h.ToBytes(&hB)
edwards25519.GeScalarMult(&ii, x, h)
ii.ToBytes(&hxB)

// use hash of private-, public-key and msg as randomness source:
hash := sha3.NewShake256()
hash.Write(skhr[:])
hash.Write(sk[32:]) // public key, as in ed25519
Expand All @@ -137,26 +139,32 @@ func (sk PrivateKey) Prove(m []byte) (vrf, proof []byte) {
edwards25519.ScReduce(&r, &rH)

edwards25519.GeScalarMultBase(&gr, &r)
edwards25519.GeScalarMult(&hr, &r, hm)
edwards25519.GeScalarMult(&hr, &r, h)
gr.ToBytes(&grB)
hr.ToBytes(&hrB)
gB = edwards25519.BaseBytes

// H2(g, h, g^x, h^x, g^r, h^r, m)
hash.Write(gB[:])
hash.Write(hB[:])
hash.Write(sk[32:]) // ed25519 public-key
hash.Write(hxB[:])
hash.Write(grB[:])
hash.Write(hrB[:])
hash.Write(m)
hash.Read(cH[:])
hash.Read(sH[:])
hash.Reset()
edwards25519.ScReduce(&c, &cH)
edwards25519.ScReduce(&s, &sH)

edwards25519.ScNeg(&minusC, &c)
edwards25519.ScMulAdd(&t, x, &minusC, &r)
edwards25519.ScNeg(&minusS, &s)
edwards25519.ScMulAdd(&t, x, &minusS, &r)

proof = make([]byte, ProofSize)
copy(proof[:32], c[:])
copy(proof[:32], s[:])
copy(proof[32:64], t[:])
copy(proof[64:96], iiB[:])
copy(proof[64:96], hxB[:])

hash.Write(iiB[:]) // const length: Size
hash.Write(hxB[:])
hash.Write(m)
vrf = make([]byte, Size)
hash.Read(vrf[:])
Expand All @@ -169,15 +177,15 @@ func (pkBytes PublicKey) Verify(m, vrfBytes, proof []byte) bool {
if len(proof) != ProofSize || len(vrfBytes) != Size || len(pkBytes) != PublicKeySize {
return false
}
var pk, c, cRef, t, vrf, iiB, ABytes, BBytes [32]byte
var pk, s, sRef, t, vrf, hxB, hB, gB, ABytes, BBytes [32]byte
copy(vrf[:], vrfBytes)
copy(pk[:], pkBytes[:])
copy(c[:32], proof[:32])
copy(s[:32], proof[:32])
copy(t[:32], proof[32:64])
copy(iiB[:], proof[64:96])
copy(hxB[:], proof[64:96])

hash := sha3.NewShake256()
hash.Write(iiB[:]) // const length
hash.Write(hxB[:]) // const length
hash.Write(m)
var hCheck [Size]byte
hash.Read(hCheck[:])
Expand All @@ -191,25 +199,33 @@ func (pkBytes PublicKey) Verify(m, vrfBytes, proof []byte) bool {
if !P.FromBytesBaseGroup(&pk) {
return false
}
if !ii.FromBytesBaseGroup(&iiB) {
if !ii.FromBytesBaseGroup(&hxB) {
return false
}
edwards25519.GeDoubleScalarMultVartime(&A, &c, &P, &t)
edwards25519.GeDoubleScalarMultVartime(&A, &s, &P, &t)
A.ToBytes(&ABytes)
gB = edwards25519.BaseBytes

hm := hashToCurve(m)
edwards25519.GeDoubleScalarMultVartime(&hmtP, &t, hm, &[32]byte{})
edwards25519.GeDoubleScalarMultVartime(&iicP, &c, &ii, &[32]byte{})
h := hashToCurve(m) // h = H1(m)
h.ToBytes(&hB)
edwards25519.GeDoubleScalarMultVartime(&hmtP, &t, h, &[32]byte{})
edwards25519.GeDoubleScalarMultVartime(&iicP, &s, &ii, &[32]byte{})
iicP.ToExtended(&iic)
hmtP.ToExtended(&B)
edwards25519.GeAdd(&B, &B, &iic)
B.ToBytes(&BBytes)

var cH [64]byte
hash.Write(ABytes[:]) // const length
hash.Write(BBytes[:]) // const length
var sH [64]byte
// sRef = H2(g, h, g^x, v, g^t·G^s,H1(m)^t·v^s, m), with v=H1(m)^x=h^x
hash.Write(gB[:])
hash.Write(hB[:])
hash.Write(pkBytes)
hash.Write(hxB[:])
hash.Write(ABytes[:]) // const length (g^t*G^s)
hash.Write(BBytes[:]) // const length (H1(m)^t*v^s)
hash.Write(m)
hash.Read(cH[:])
edwards25519.ScReduce(&cRef, &cH)
return cRef == c
hash.Read(sH[:])

edwards25519.ScReduce(&sRef, &sH)
return sRef == s
}
16 changes: 8 additions & 8 deletions crypto/vrf/vrf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ func TestHonestComplete(t *testing.T) {
// fmt.Printf("aliceProof: %X\n", aliceProof)

if !pk.Verify(alice, aliceVRF, aliceProof) {
t.Errorf("Gen -> Compute -> Prove -> Verify -> FALSE")
t.Error("Gen -> Compute -> Prove -> Verify -> FALSE")
}
if !bytes.Equal(aliceVRF, aliceVRFFromProof) {
t.Errorf("Compute != Prove")
t.Error("Compute != Prove")
}
}

Expand Down Expand Up @@ -69,37 +69,37 @@ func sampleVectorTest(pk PublicKey, aliceVRF, aliceProof []byte, t *testing.T) {

// Positive test case
if !pk.Verify(alice, aliceVRF, aliceProof) {
t.Errorf("TestSampleVectors HonestVector Failed")
t.Error("TestSampleVectors HonestVector Failed")
}

// Negative test cases - try increment the first byte of every vector
pk[0]++
if pk.Verify(alice, aliceVRF, aliceProof) {
t.Errorf("TestSampleVectors ForgedVector (pk modified) Passed")
t.Error("TestSampleVectors ForgedVector (pk modified) Passed")
}
pk[0]--

alice[0]++
if pk.Verify(alice, aliceVRF, aliceProof) {
t.Errorf("TestSampleVectors ForgedVector (alice modified) Passed")
t.Error("TestSampleVectors ForgedVector (alice modified) Passed")
}
alice[0]--

aliceVRF[0]++
if pk.Verify(alice, aliceVRF, aliceProof) {
t.Errorf("TestSampleVectors ForgedVector (aliceVRF modified) Passed")
t.Error("TestSampleVectors ForgedVector (aliceVRF modified) Passed")
}
aliceVRF[0]--

aliceProof[0]++
if pk.Verify(alice, aliceVRF, aliceProof) {
t.Errorf("TestSampleVectors ForgedVector (aliceProof modified) Passed")
t.Error("TestSampleVectors ForgedVector (aliceProof modified) Passed")
}
aliceProof[0]--
}

func TestSampleVectorSets(t *testing.T) {

t.Skip("TODO: generate new test vectors or remove test")
var aliceVRF, aliceProof []byte
var pk []byte

Expand Down

0 comments on commit e9c8209

Please sign in to comment.