github.com/consensys/gnark-crypto@v0.14.0/ecc/bw6-633/twistededwards/eddsa/eddsa.go (about)

     1  // Copyright 2020 Consensys Software Inc.
     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  
    15  // Code generated by consensys/gnark-crypto DO NOT EDIT
    16  
    17  package eddsa
    18  
    19  import (
    20  	"crypto/subtle"
    21  	"errors"
    22  	"hash"
    23  	"io"
    24  	"math/big"
    25  
    26  	"github.com/consensys/gnark-crypto/ecc/bw6-633/fr"
    27  	"github.com/consensys/gnark-crypto/ecc/bw6-633/twistededwards"
    28  	"github.com/consensys/gnark-crypto/signature"
    29  	"golang.org/x/crypto/blake2b"
    30  )
    31  
    32  var errNotOnCurve = errors.New("point not on curve")
    33  var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir")
    34  
    35  const (
    36  	sizeFr         = fr.Bytes
    37  	sizePublicKey  = sizeFr
    38  	sizeSignature  = 2 * sizeFr
    39  	sizePrivateKey = 2*sizeFr + 32
    40  )
    41  
    42  // PublicKey eddsa signature object
    43  // cf https://en.wikipedia.org/wiki/EdDSA for notation
    44  type PublicKey struct {
    45  	A twistededwards.PointAffine
    46  }
    47  
    48  // PrivateKey private key of an eddsa instance
    49  type PrivateKey struct {
    50  	PublicKey PublicKey    // copy of the associated public key
    51  	scalar    [sizeFr]byte // secret scalar, in big Endian
    52  	randSrc   [32]byte     // source
    53  }
    54  
    55  // Signature represents an eddsa signature
    56  // cf https://en.wikipedia.org/wiki/EdDSA for notation
    57  type Signature struct {
    58  	R twistededwards.PointAffine
    59  	S [sizeFr]byte
    60  }
    61  
    62  // GenerateKey generates a public and private key pair.
    63  func GenerateKey(r io.Reader) (*PrivateKey, error) {
    64  	c := twistededwards.GetEdwardsCurve()
    65  
    66  	var pub PublicKey
    67  	var priv PrivateKey
    68  	// The source of randomness and the secret scalar must come
    69  	// from 2 distinct sources. Since the scalar is the size of the
    70  	// field of definition (48 bytes), the scalar must come from a
    71  	// different digest so there is no overlap between the source of
    72  	// randomness and the scalar.
    73  
    74  	// used for random scalar (aka private key)
    75  	seed := make([]byte, 32)
    76  	_, err := r.Read(seed)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	h1 := blake2b.Sum512(seed[:])
    81  
    82  	// used for the source of randomness when hashing the message
    83  	h2 := blake2b.Sum512(h1[:])
    84  	for i := 0; i < 32; i++ {
    85  		priv.randSrc[i] = h2[i]
    86  	}
    87  
    88  	// prune the key
    89  	// https://tools.ietf.org/html/rfc8032#section-5.1.5, key generation
    90  	h1[0] &= 0xF8
    91  	h1[sizeFr-1] &= 0x7F
    92  	h1[sizeFr-1] |= 0x40
    93  
    94  	// reverse first bytes because setBytes interpret stream as big endian
    95  	// but in eddsa specs s is the first 32 bytes in little endian
    96  	for i, j := 0, sizeFr-1; i < sizeFr; i, j = i+1, j-1 {
    97  		priv.scalar[i] = h1[j]
    98  	}
    99  
   100  	var bScalar big.Int
   101  	bScalar.SetBytes(priv.scalar[:])
   102  	pub.A.ScalarMultiplication(&c.Base, &bScalar)
   103  
   104  	priv.PublicKey = pub
   105  
   106  	return &priv, nil
   107  }
   108  
   109  // Equal compares 2 public keys
   110  func (pub *PublicKey) Equal(x signature.PublicKey) bool {
   111  	xx, ok := x.(*PublicKey)
   112  	if !ok {
   113  		return false
   114  	}
   115  	bpk := pub.Bytes()
   116  	bxx := xx.Bytes()
   117  	return subtle.ConstantTimeCompare(bpk, bxx) == 1
   118  }
   119  
   120  // Public returns the public key associated to the private key.
   121  func (privKey *PrivateKey) Public() signature.PublicKey {
   122  	var pub PublicKey
   123  	pub.A.Set(&privKey.PublicKey.A)
   124  	return &pub
   125  }
   126  
   127  // Sign sign a sequence of field elements
   128  // For arbitrary strings use fr.Hash first
   129  // Pure Eddsa version (see https://tools.ietf.org/html/rfc8032#page-8)
   130  func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) {
   131  
   132  	// hFunc cannot be nil.
   133  	// We need a hash function for the Fiat-Shamir.
   134  	if hFunc == nil {
   135  		return nil, errHashNeeded
   136  	}
   137  
   138  	curveParams := twistededwards.GetEdwardsCurve()
   139  
   140  	var res Signature
   141  
   142  	// blinding factor for the private key
   143  	// blindingFactorBigInt must be the same size as the private key,
   144  	// blindingFactorBigInt = h(randomness_source||message)[:sizeFr]
   145  	var blindingFactorBigInt big.Int
   146  
   147  	// randSrc = privKey.randSrc || msg (-> message = MSB message .. LSB message)
   148  	randSrc := make([]byte, 32+len(message))
   149  	copy(randSrc, privKey.randSrc[:])
   150  	copy(randSrc[32:], message)
   151  
   152  	// randBytes = H(randSrc)
   153  	blindingFactorBytes := blake2b.Sum512(randSrc[:]) // TODO ensures that the hash used to build the key and the one used here is the same
   154  	blindingFactorBigInt.SetBytes(blindingFactorBytes[:sizeFr])
   155  
   156  	// compute R = randScalar*Base
   157  	res.R.ScalarMultiplication(&curveParams.Base, &blindingFactorBigInt)
   158  	if !res.R.IsOnCurve() {
   159  		return nil, errNotOnCurve
   160  	}
   161  
   162  	// compute H(R, A, M), all parameters in data are in Montgomery form
   163  	hFunc.Reset()
   164  
   165  	resRX := res.R.X.Bytes()
   166  	resRY := res.R.Y.Bytes()
   167  	resAX := privKey.PublicKey.A.X.Bytes()
   168  	resAY := privKey.PublicKey.A.Y.Bytes()
   169  	toWrite := [][]byte{resRX[:], resRY[:], resAX[:], resAY[:], message}
   170  	for _, bytes := range toWrite {
   171  		if _, err := hFunc.Write(bytes); err != nil {
   172  			return nil, err
   173  		}
   174  	}
   175  
   176  	var hramInt big.Int
   177  	hramBin := hFunc.Sum(nil)
   178  	hramInt.SetBytes(hramBin)
   179  
   180  	// Compute s = randScalarInt + H(R,A,M)*S
   181  	// going with big int to do ops mod curve order
   182  	var bscalar, bs big.Int
   183  	bscalar.SetBytes(privKey.scalar[:])
   184  	bs.Mul(&hramInt, &bscalar).
   185  		Add(&bs, &blindingFactorBigInt).
   186  		Mod(&bs, &curveParams.Order)
   187  	sb := bs.Bytes()
   188  	if len(sb) < sizeFr {
   189  		offset := make([]byte, sizeFr-len(sb))
   190  		sb = append(offset, sb...)
   191  	}
   192  	copy(res.S[:], sb[:])
   193  
   194  	return res.Bytes(), nil
   195  }
   196  
   197  // Verify verifies an eddsa signature
   198  func (pub *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) {
   199  
   200  	// hFunc cannot be nil.
   201  	// We need a hash function for the Fiat-Shamir.
   202  	if hFunc == nil {
   203  		return false, errHashNeeded
   204  	}
   205  
   206  	curveParams := twistededwards.GetEdwardsCurve()
   207  
   208  	// verify that pubKey and R are on the curve
   209  	if !pub.A.IsOnCurve() {
   210  		return false, errNotOnCurve
   211  	}
   212  
   213  	// Deserialize the signature
   214  	var sig Signature
   215  	if _, err := sig.SetBytes(sigBin); err != nil {
   216  		return false, err
   217  	}
   218  
   219  	// compute H(R, A, M), all parameters in data are in Montgomery form
   220  
   221  	hFunc.Reset()
   222  
   223  	sigRX := sig.R.X.Bytes()
   224  	sigRY := sig.R.Y.Bytes()
   225  	sigAX := pub.A.X.Bytes()
   226  	sigAY := pub.A.Y.Bytes()
   227  
   228  	toWrite := [][]byte{sigRX[:], sigRY[:], sigAX[:], sigAY[:], message}
   229  	for _, bytes := range toWrite {
   230  		if _, err := hFunc.Write(bytes); err != nil {
   231  			return false, err
   232  		}
   233  	}
   234  
   235  	var hramInt big.Int
   236  	hramBin := hFunc.Sum(nil)
   237  	hramInt.SetBytes(hramBin)
   238  
   239  	// lhs = cofactor*S*Base
   240  	var lhs twistededwards.PointAffine
   241  	var bCofactor, bs big.Int
   242  	curveParams.Cofactor.BigInt(&bCofactor)
   243  	bs.SetBytes(sig.S[:])
   244  	lhs.ScalarMultiplication(&curveParams.Base, &bs).
   245  		ScalarMultiplication(&lhs, &bCofactor)
   246  
   247  	if !lhs.IsOnCurve() {
   248  		return false, errNotOnCurve
   249  	}
   250  
   251  	// rhs = cofactor*(R + H(R,A,M)*A)
   252  	var rhs twistededwards.PointAffine
   253  	rhs.ScalarMultiplication(&pub.A, &hramInt).
   254  		Add(&rhs, &sig.R).
   255  		ScalarMultiplication(&rhs, &bCofactor)
   256  	if !rhs.IsOnCurve() {
   257  		return false, errNotOnCurve
   258  	}
   259  
   260  	// verifies that cofactor*S*Base=cofactor*(R + H(R,A,M)*A)
   261  	if !lhs.X.Equal(&rhs.X) || !lhs.Y.Equal(&rhs.Y) {
   262  		return false, nil
   263  	}
   264  
   265  	return true, nil
   266  }