github.com/annchain/OG@v0.0.9/poc/vrf/vrf.go (about) 1 // Copyright © 2019 Annchain Authors <EMAIL ADDRESS> 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // Package vrf implements a verifiable random function using the Edwards form 15 // of Curve25519, SHA3 and the Elligator map. 16 // 17 // E is Curve25519 (in Edwards coordinates), h is SHA3. 18 // f is the elligator map (bytes->E) that covers half of E. 19 // 8 is the cofactor of E, the group order is 8*l for prime l. 20 // Setup : the prover publicly commits to a public key (P : E) 21 // H : names -> E 22 // H(n) = f(h(n))^8 23 // VRF : keys -> names -> vrfs 24 // VRF_x(n) = h(n, H(n)^x)) 25 // Prove : keys -> names -> proofs 26 // Prove_x(n) = tuple(c=h(n, g^r, H(n)^r), t=r-c*x, ii=H(n)^x) 27 // where r = h(x, n) is used as a source of randomness 28 // Check : E -> names -> vrfs -> proofs -> bool 29 // Check(P, n, vrf, (c,t,ii)) = vrf == h(n, ii) 30 // && c == h(n, g^t*P^c, H(n)^t*ii^c) 31 package vrf 32 33 import ( 34 "bytes" 35 "crypto/rand" 36 "errors" 37 "io" 38 39 "golang.org/x/crypto/sha3" 40 41 "github.com/annchain/OG/poc/ed25519" 42 "github.com/annchain/OG/poc/extra25519" 43 "golang.org/x/crypto/ed25519" 44 ) 45 46 const ( 47 PublicKeySize = 32 48 PrivateKeySize = 64 49 Size = 32 50 intermediateSize = 32 51 ProofSize = 32 + 32 + intermediateSize 52 ) 53 54 var ( 55 ErrGetPubKey = errors.New("[vrf] Couldn't get corresponding public-key from private-key") 56 ) 57 58 type PrivateKey []byte 59 type PublicKey []byte 60 61 // GenerateKey creates a public/private key pair using rnd for randomness. 62 // If rnd is nil, ogcrypto/rand is used. 63 func GenerateKey(rnd io.Reader) (sk PrivateKey, err error) { 64 if rnd == nil { 65 rnd = rand.Reader 66 } 67 sk = make([]byte, 64) 68 _, err = io.ReadFull(rnd, sk[:32]) 69 if err != nil { 70 return 71 } 72 x, _ := sk.expandSecret() 73 74 var pkP edwards25519.ExtendedGroupElement 75 edwards25519.GeScalarMultBase(&pkP, x) 76 var pkBytes [PublicKeySize]byte 77 pkP.ToBytes(&pkBytes) 78 79 copy(sk[32:], pkBytes[:]) 80 return 81 } 82 83 // Public extracts the public VRF key from the underlying private-key 84 // and returns a boolean indicating if the operation was successful. 85 func (sk PrivateKey) Public() (PublicKey, bool) { 86 pk, ok := ed25519.PrivateKey(sk).Public().(ed25519.PublicKey) 87 return PublicKey(pk), ok 88 } 89 90 func (sk PrivateKey) expandSecret() (x, skhr *[32]byte) { 91 x, skhr = new([32]byte), new([32]byte) 92 hash := sha3.NewShake256() 93 hash.Write(sk[:32]) 94 hash.Read(x[:]) 95 hash.Read(skhr[:]) 96 x[0] &= 248 97 x[31] &= 127 98 x[31] |= 64 99 return 100 } 101 102 // Compute generates the vrf value for the byte slice m using the 103 // underlying private key sk. 104 func (sk PrivateKey) Compute(m []byte) []byte { 105 x, _ := sk.expandSecret() 106 var ii edwards25519.ExtendedGroupElement 107 var iiB [32]byte 108 edwards25519.GeScalarMult(&ii, x, hashToCurve(m)) 109 ii.ToBytes(&iiB) 110 111 hash := sha3.NewShake256() 112 hash.Write(iiB[:]) // const length: Size 113 hash.Write(m) 114 var vrf [Size]byte 115 hash.Read(vrf[:]) 116 return vrf[:] 117 } 118 119 func hashToCurve(m []byte) *edwards25519.ExtendedGroupElement { 120 // H(n) = (f(h(n))^8) 121 var hmb [32]byte 122 sha3.ShakeSum256(hmb[:], m) 123 var hm edwards25519.ExtendedGroupElement 124 extra25519.HashToEdwards(&hm, &hmb) 125 edwards25519.GeDouble(&hm, &hm) 126 edwards25519.GeDouble(&hm, &hm) 127 edwards25519.GeDouble(&hm, &hm) 128 return &hm 129 } 130 131 // Prove returns the vrf value and a proof such that 132 // Verify(m, vrf, proof) == true. The vrf value is the 133 // same as returned by Compute(m). 134 func (sk PrivateKey) Prove(m []byte) (vrf, proof []byte) { 135 x, skhr := sk.expandSecret() 136 var sH, rH [64]byte 137 var r, s, minusS, t, gB, grB, hrB, hxB, hB [32]byte 138 var ii, gr, hr edwards25519.ExtendedGroupElement 139 140 h := hashToCurve(m) 141 h.ToBytes(&hB) 142 edwards25519.GeScalarMult(&ii, x, h) 143 ii.ToBytes(&hxB) 144 145 // use hash of private-, public-key and msg as randomness source: 146 hash := sha3.NewShake256() 147 hash.Write(skhr[:]) 148 hash.Write(sk[32:]) // public key, as in ed25519 149 hash.Write(m) 150 hash.Read(rH[:]) 151 hash.Reset() 152 edwards25519.ScReduce(&r, &rH) 153 154 edwards25519.GeScalarMultBase(&gr, &r) 155 edwards25519.GeScalarMult(&hr, &r, h) 156 gr.ToBytes(&grB) 157 hr.ToBytes(&hrB) 158 gB = edwards25519.BaseBytes 159 160 // H2(g, h, g^x, h^x, g^r, h^r, m) 161 hash.Write(gB[:]) 162 hash.Write(hB[:]) 163 hash.Write(sk[32:]) // ed25519 public-key 164 hash.Write(hxB[:]) 165 hash.Write(grB[:]) 166 hash.Write(hrB[:]) 167 hash.Write(m) 168 hash.Read(sH[:]) 169 hash.Reset() 170 edwards25519.ScReduce(&s, &sH) 171 172 edwards25519.ScNeg(&minusS, &s) 173 edwards25519.ScMulAdd(&t, x, &minusS, &r) 174 175 proof = make([]byte, ProofSize) 176 copy(proof[:32], s[:]) 177 copy(proof[32:64], t[:]) 178 copy(proof[64:96], hxB[:]) 179 180 hash.Write(hxB[:]) 181 hash.Write(m) 182 vrf = make([]byte, Size) 183 hash.Read(vrf[:]) 184 return 185 } 186 187 // Verify returns true iff vrf=Compute(m) for the sk that 188 // corresponds to pk. 189 func (pkBytes PublicKey) Verify(m, vrfBytes, proof []byte) bool { 190 if len(proof) != ProofSize || len(vrfBytes) != Size || len(pkBytes) != PublicKeySize { 191 return false 192 } 193 var pk, s, sRef, t, vrf, hxB, hB, gB, ABytes, BBytes [32]byte 194 copy(vrf[:], vrfBytes) 195 copy(pk[:], pkBytes[:]) 196 copy(s[:32], proof[:32]) 197 copy(t[:32], proof[32:64]) 198 copy(hxB[:], proof[64:96]) 199 200 hash := sha3.NewShake256() 201 hash.Write(hxB[:]) // const length 202 hash.Write(m) 203 var hCheck [Size]byte 204 hash.Read(hCheck[:]) 205 if !bytes.Equal(hCheck[:], vrf[:]) { 206 return false 207 } 208 hash.Reset() 209 210 var P, B, ii, iic edwards25519.ExtendedGroupElement 211 var A, hmtP, iicP edwards25519.ProjectiveGroupElement 212 if !P.FromBytesBaseGroup(&pk) { 213 return false 214 } 215 if !ii.FromBytesBaseGroup(&hxB) { 216 return false 217 } 218 edwards25519.GeDoubleScalarMultVartime(&A, &s, &P, &t) 219 A.ToBytes(&ABytes) 220 gB = edwards25519.BaseBytes 221 222 h := hashToCurve(m) // h = H1(m) 223 h.ToBytes(&hB) 224 edwards25519.GeDoubleScalarMultVartime(&hmtP, &t, h, &[32]byte{}) 225 edwards25519.GeDoubleScalarMultVartime(&iicP, &s, &ii, &[32]byte{}) 226 iicP.ToExtended(&iic) 227 hmtP.ToExtended(&B) 228 edwards25519.GeAdd(&B, &B, &iic) 229 B.ToBytes(&BBytes) 230 231 var sH [64]byte 232 // sRef = H2(g, h, g^x, v, g^t·G^s,H1(m)^t·v^s, m), with v=H1(m)^x=h^x 233 hash.Write(gB[:]) 234 hash.Write(hB[:]) 235 hash.Write(pkBytes) 236 hash.Write(hxB[:]) 237 hash.Write(ABytes[:]) // const length (g^t*G^s) 238 hash.Write(BBytes[:]) // const length (H1(m)^t*v^s) 239 hash.Write(m) 240 hash.Read(sH[:]) 241 242 edwards25519.ScReduce(&sRef, &sH) 243 return sRef == s 244 }