github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-317/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/bls24-317/fr" 27 "github.com/consensys/gnark-crypto/ecc/bls24-317/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 }