github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-377/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/bls12-377/fr"
    27  	"github.com/consensys/gnark-crypto/ecc/bls12-377/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  	// hash(h) = private_key || random_source, on 32 bytes each
    69  	seed := make([]byte, 32)
    70  	_, err := r.Read(seed)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	h := blake2b.Sum512(seed[:])
    75  	for i := 0; i < 32; i++ {
    76  		priv.randSrc[i] = h[i+32]
    77  	}
    78  
    79  	// prune the key
    80  	// https://tools.ietf.org/html/rfc8032#section-5.1.5, key generation
    81  	h[0] &= 0xF8
    82  	h[31] &= 0x7F
    83  	h[31] |= 0x40
    84  
    85  	// reverse first bytes because setBytes interpret stream as big endian
    86  	// but in eddsa specs s is the first 32 bytes in little endian
    87  	for i, j := 0, sizeFr-1; i < sizeFr; i, j = i+1, j-1 {
    88  		priv.scalar[i] = h[j]
    89  	}
    90  
    91  	var bScalar big.Int
    92  	bScalar.SetBytes(priv.scalar[:])
    93  	pub.A.ScalarMultiplication(&c.Base, &bScalar)
    94  
    95  	priv.PublicKey = pub
    96  
    97  	return &priv, nil
    98  }
    99  
   100  // Equal compares 2 public keys
   101  func (pub *PublicKey) Equal(x signature.PublicKey) bool {
   102  	xx, ok := x.(*PublicKey)
   103  	if !ok {
   104  		return false
   105  	}
   106  	bpk := pub.Bytes()
   107  	bxx := xx.Bytes()
   108  	return subtle.ConstantTimeCompare(bpk, bxx) == 1
   109  }
   110  
   111  // Public returns the public key associated to the private key.
   112  func (privKey *PrivateKey) Public() signature.PublicKey {
   113  	var pub PublicKey
   114  	pub.A.Set(&privKey.PublicKey.A)
   115  	return &pub
   116  }
   117  
   118  // Sign sign a sequence of field elements
   119  // For arbitrary strings use fr.Hash first
   120  // Pure Eddsa version (see https://tools.ietf.org/html/rfc8032#page-8)
   121  func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) {
   122  
   123  	// hFunc cannot be nil.
   124  	// We need a hash function for the Fiat-Shamir.
   125  	if hFunc == nil {
   126  		return nil, errHashNeeded
   127  	}
   128  
   129  	curveParams := twistededwards.GetEdwardsCurve()
   130  
   131  	var res Signature
   132  
   133  	// blinding factor for the private key
   134  	// blindingFactorBigInt must be the same size as the private key,
   135  	// blindingFactorBigInt = h(randomness_source||message)[:sizeFr]
   136  	var blindingFactorBigInt big.Int
   137  
   138  	// randSrc = privKey.randSrc || msg (-> message = MSB message .. LSB message)
   139  	randSrc := make([]byte, 32+len(message))
   140  	copy(randSrc, privKey.randSrc[:])
   141  	copy(randSrc[32:], message)
   142  
   143  	// randBytes = H(randSrc)
   144  	blindingFactorBytes := blake2b.Sum512(randSrc[:]) // TODO ensures that the hash used to build the key and the one used here is the same
   145  	blindingFactorBigInt.SetBytes(blindingFactorBytes[:sizeFr])
   146  
   147  	// compute R = randScalar*Base
   148  	res.R.ScalarMultiplication(&curveParams.Base, &blindingFactorBigInt)
   149  	if !res.R.IsOnCurve() {
   150  		return nil, errNotOnCurve
   151  	}
   152  
   153  	// compute H(R, A, M), all parameters in data are in Montgomery form
   154  	hFunc.Reset()
   155  
   156  	resRX := res.R.X.Bytes()
   157  	resRY := res.R.Y.Bytes()
   158  	resAX := privKey.PublicKey.A.X.Bytes()
   159  	resAY := privKey.PublicKey.A.Y.Bytes()
   160  	toWrite := [][]byte{resRX[:], resRY[:], resAX[:], resAY[:], message}
   161  	for _, bytes := range toWrite {
   162  		if _, err := hFunc.Write(bytes); err != nil {
   163  			return nil, err
   164  		}
   165  	}
   166  
   167  	var hramInt big.Int
   168  	hramBin := hFunc.Sum(nil)
   169  	hramInt.SetBytes(hramBin)
   170  
   171  	// Compute s = randScalarInt + H(R,A,M)*S
   172  	// going with big int to do ops mod curve order
   173  	var bscalar, bs big.Int
   174  	bscalar.SetBytes(privKey.scalar[:])
   175  	bs.Mul(&hramInt, &bscalar).
   176  		Add(&bs, &blindingFactorBigInt).
   177  		Mod(&bs, &curveParams.Order)
   178  	sb := bs.Bytes()
   179  	if len(sb) < sizeFr {
   180  		offset := make([]byte, sizeFr-len(sb))
   181  		sb = append(offset, sb...)
   182  	}
   183  	copy(res.S[:], sb[:])
   184  
   185  	return res.Bytes(), nil
   186  }
   187  
   188  // Verify verifies an eddsa signature
   189  func (pub *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) {
   190  
   191  	// hFunc cannot be nil.
   192  	// We need a hash function for the Fiat-Shamir.
   193  	if hFunc == nil {
   194  		return false, errHashNeeded
   195  	}
   196  
   197  	curveParams := twistededwards.GetEdwardsCurve()
   198  
   199  	// verify that pubKey and R are on the curve
   200  	if !pub.A.IsOnCurve() {
   201  		return false, errNotOnCurve
   202  	}
   203  
   204  	// Deserialize the signature
   205  	var sig Signature
   206  	if _, err := sig.SetBytes(sigBin); err != nil {
   207  		return false, err
   208  	}
   209  
   210  	// compute H(R, A, M), all parameters in data are in Montgomery form
   211  
   212  	hFunc.Reset()
   213  
   214  	sigRX := sig.R.X.Bytes()
   215  	sigRY := sig.R.Y.Bytes()
   216  	sigAX := pub.A.X.Bytes()
   217  	sigAY := pub.A.Y.Bytes()
   218  
   219  	toWrite := [][]byte{sigRX[:], sigRY[:], sigAX[:], sigAY[:], message}
   220  	for _, bytes := range toWrite {
   221  		if _, err := hFunc.Write(bytes); err != nil {
   222  			return false, err
   223  		}
   224  	}
   225  
   226  	var hramInt big.Int
   227  	hramBin := hFunc.Sum(nil)
   228  	hramInt.SetBytes(hramBin)
   229  
   230  	// lhs = cofactor*S*Base
   231  	var lhs twistededwards.PointAffine
   232  	var bCofactor, bs big.Int
   233  	curveParams.Cofactor.BigInt(&bCofactor)
   234  	bs.SetBytes(sig.S[:])
   235  	lhs.ScalarMultiplication(&curveParams.Base, &bs).
   236  		ScalarMultiplication(&lhs, &bCofactor)
   237  
   238  	if !lhs.IsOnCurve() {
   239  		return false, errNotOnCurve
   240  	}
   241  
   242  	// rhs = cofactor*(R + H(R,A,M)*A)
   243  	var rhs twistededwards.PointAffine
   244  	rhs.ScalarMultiplication(&pub.A, &hramInt).
   245  		Add(&rhs, &sig.R).
   246  		ScalarMultiplication(&rhs, &bCofactor)
   247  	if !rhs.IsOnCurve() {
   248  		return false, errNotOnCurve
   249  	}
   250  
   251  	// verifies that cofactor*S*Base=cofactor*(R + H(R,A,M)*A)
   252  	if !lhs.X.Equal(&rhs.X) || !lhs.Y.Equal(&rhs.Y) {
   253  		return false, nil
   254  	}
   255  
   256  	return true, nil
   257  }