From d43b04aa5852871f6df7528dfbcf0a9dea222df2 Mon Sep 17 00:00:00 2001 From: Liamsi Date: Sun, 14 May 2017 20:47:06 +0200 Subject: [PATCH] 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 --- crypto/internal/ed25519/edwards25519/const.go | 14 ++++++ crypto/vrf/vrf.go | 46 +++++++++++++------ crypto/vrf/vrf_test.go | 16 +++---- 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/crypto/internal/ed25519/edwards25519/const.go b/crypto/internal/ed25519/edwards25519/const.go index 707e92b..64be9fb 100644 --- a/crypto/internal/ed25519/edwards25519/const.go +++ b/crypto/internal/ed25519/edwards25519/const.go @@ -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}, diff --git a/crypto/vrf/vrf.go b/crypto/vrf/vrf.go index 71c1e80..be7291d 100644 --- a/crypto/vrf/vrf.go +++ b/crypto/vrf/vrf.go @@ -121,13 +121,15 @@ func hashToCurve(m []byte) *edwards25519.ExtendedGroupElement { func (sk PrivateKey) Prove(m []byte) (vrf, proof []byte) { x, skhr := sk.expandSecret() var sH, rH [64]byte - var r, s, minusS, t, grB, hrB, iiB [32]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 @@ -137,10 +139,16 @@ 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) @@ -154,9 +162,9 @@ func (sk PrivateKey) Prove(m []byte) (vrf, proof []byte) { proof = make([]byte, ProofSize) 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[:]) @@ -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, s, sRef, 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(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[:]) @@ -191,14 +199,16 @@ 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, &s, &P, &t) A.ToBytes(&ABytes) + gB = edwards25519.BaseBytes - hm := hashToCurve(m) - edwards25519.GeDoubleScalarMultVartime(&hmtP, &t, hm, &[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) @@ -206,10 +216,16 @@ func (pkBytes PublicKey) Verify(m, vrfBytes, proof []byte) bool { B.ToBytes(&BBytes) var sH [64]byte - hash.Write(ABytes[:]) // const length - hash.Write(BBytes[:]) // const length + // 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(sH[:]) + edwards25519.ScReduce(&sRef, &sH) return sRef == s } diff --git a/crypto/vrf/vrf_test.go b/crypto/vrf/vrf_test.go index 73a8021..dd518d4 100644 --- a/crypto/vrf/vrf_test.go +++ b/crypto/vrf/vrf_test.go @@ -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") } } @@ -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