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 }