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  }