github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/crypto/key.go (about) 1 // Copyright 2017-2018 DERO Project. All rights reserved. 2 // Use of this source code in any form is governed by RESEARCH license. 3 // license can be found in the LICENSE file. 4 // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 5 // 6 // 7 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 10 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 11 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 12 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 13 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 14 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 15 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 17 package crypto 18 19 import "io" 20 import "fmt" 21 import "bytes" 22 import "crypto/rand" 23 import "encoding/hex" 24 import "encoding/binary" 25 26 const KeyLength = 32 27 28 // Key can be a Scalar or a Point 29 type Key [KeyLength]byte 30 31 func (k Key) MarshalText() ([]byte, error) { 32 return []byte(fmt.Sprintf("%x", k[:])), nil 33 } 34 35 func (k *Key) UnmarshalText(data []byte) (err error) { 36 byteSlice, _ := hex.DecodeString(string(data)) 37 if len(byteSlice) != 32 { 38 return fmt.Errorf("Incorrect key size") 39 } 40 copy(k[:], byteSlice) 41 return 42 } 43 44 func (k Key) String() string { 45 return fmt.Sprintf("%x", k[:]) 46 } 47 48 func (p *Key) FromBytes(b [KeyLength]byte) { 49 *p = b 50 } 51 52 func (p *Key) ToBytes() (result [KeyLength]byte) { 53 result = [KeyLength]byte(*p) 54 return 55 } 56 57 // convert a hex string to a key 58 func HexToKey(h string) (result Key) { 59 byteSlice, _ := hex.DecodeString(h) 60 if len(byteSlice) != 32 { 61 panic("Incorrect key size") 62 } 63 copy(result[:], byteSlice) 64 return 65 } 66 67 func HexToHash(h string) (result Hash) { 68 byteSlice, _ := hex.DecodeString(h) 69 if len(byteSlice) != 32 { 70 panic("Incorrect key size") 71 } 72 copy(result[:], byteSlice) 73 return 74 } 75 76 // generates a public from the secret key 77 func (p *Key) PublicKey() (pubKey *Key) { 78 point := new(ExtendedGroupElement) 79 GeScalarMultBase(point, p) 80 pubKey = new(Key) 81 point.ToBytes(pubKey) 82 return 83 } 84 85 // tests whether the key is valid ( represents a point on the curve ) 86 // this is equivalent to bool crypto_ops::check_key(const public_key &key) 87 func (k *Key) Public_Key_Valid() bool { 88 var point ExtendedGroupElement 89 return point.FromBytes(k) 90 } 91 92 func (k *Key) Private_Key_Valid() bool { 93 return Sc_check(k) 94 } 95 96 // Creates a point on the Edwards Curve by hashing the key 97 func (p *Key) HashToEC() (result *ExtendedGroupElement) { 98 result = new(ExtendedGroupElement) 99 var p1 ProjectiveGroupElement 100 var p2 CompletedGroupElement 101 h := Key(Keccak256(p[:])) 102 p1.FromBytes(&h) 103 104 // fmt.Printf("p1 %+v\n", p1) 105 GeMul8(&p2, &p1) 106 p2.ToExtended(result) 107 return 108 } 109 110 func (p *Key) HashToPoint() (result Key) { 111 extended := p.HashToEC() 112 extended.ToBytes(&result) 113 return 114 } 115 116 // compatible with hashToPointSimple 117 // NOTE: this is incompatible with HashToPoint ( though it should have been) 118 // there are no side-effects or degradtion of crypto, due to this 119 // however, the mistakes have to kept as they were in original code base 120 // this function is only used to generate H from G 121 func (p *Key) HashToPointSimple() (result Key) { 122 h := Key(Keccak256(p[:])) 123 extended := new(ExtendedGroupElement) 124 extended.FromBytes(&h) 125 126 // convert extended to projective 127 var p1 ProjectiveGroupElement 128 129 extended.ToProjective(&p1) 130 var p2 CompletedGroupElement 131 132 GeMul8(&p2, &p1) 133 p2.ToExtended(extended) 134 extended.ToBytes(&result) 135 return 136 } 137 138 // this uses random number generator from the OS 139 func RandomScalar() (result *Key) { 140 result = new(Key) 141 var reduceFrom [KeyLength * 2]byte 142 tmp := make([]byte, KeyLength*2) 143 rand.Read(tmp) 144 copy(reduceFrom[:], tmp) 145 ScReduce(result, &reduceFrom) 146 return 147 } 148 149 // generate a new private-public key pair 150 func NewKeyPair() (privKey *Key, pubKey *Key) { 151 privKey = RandomScalar() 152 pubKey = privKey.PublicKey() 153 return 154 } 155 156 func ParseKey(buf io.Reader) (result Key, err error) { 157 key := make([]byte, KeyLength) 158 if _, err = buf.Read(key); err != nil { 159 return 160 } 161 copy(result[:], key) 162 return 163 } 164 165 /* 166 //does a * G where a is a scalar and G is the curve basepoint 167 key scalarmultBase(const key & a) { 168 ge_p3 point; 169 key aG; 170 sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand 171 ge_scalarmult_base(&point, aG.bytes); 172 ge_p3_tobytes(aG.bytes, &point); 173 return aG; 174 } 175 */ 176 //does a * G where a is a scalar and G is the curve basepoint 177 178 func ScalarmultBase(a Key) (aG Key) { 179 reduce32copy := a 180 ScReduce32(&reduce32copy) 181 point := new(ExtendedGroupElement) 182 GeScalarMultBase(point, &a) 183 point.ToBytes(&aG) 184 return aG 185 } 186 187 // generates a key which can be used as private key or mask 188 // this function is similiar to RandomScalar except for reduce32, TODO can we merge both 189 func skGen() Key { 190 skey := RandomScalar() 191 ScReduce32(skey) 192 return *skey 193 } 194 func SkGen() Key { 195 return skGen() 196 } 197 198 func (k *Key) ToExtended() (result *ExtendedGroupElement) { 199 result = new(ExtendedGroupElement) 200 result.FromBytes(k) 201 return 202 } 203 204 // bothe the function resturn identity of the ed25519 curve 205 func identity() (result *Key) { 206 result = new(Key) 207 result[0] = 1 208 return 209 } 210 211 func CurveIdentity() (result Key) { 212 result = Identity 213 return result 214 } 215 216 func CurveOrder() (result Key) { 217 result = L 218 return result 219 } 220 221 // convert a uint64 to a scalar 222 func d2h(val uint64) (result *Key) { 223 result = new(Key) 224 for i := 0; val > 0; i++ { 225 result[i] = byte(val & 0xFF) 226 val /= 256 227 } 228 return 229 } 230 231 func HashToScalar(data ...[]byte) (result *Key) { 232 result = new(Key) 233 *result = Key(Keccak256(data...)) 234 ScReduce32(result) 235 return 236 } 237 238 // does a * P where a is a scalar and P is an arbitrary point 239 func ScalarMultKey(Point *Key, scalar *Key) (result *Key) { 240 var P ExtendedGroupElement 241 P.FromBytes(Point) 242 var resultPoint ProjectiveGroupElement 243 GeScalarMult(&resultPoint, scalar, &P) 244 result = new(Key) 245 resultPoint.ToBytes(result) 246 return 247 } 248 249 // multiply a scalar by H (second curve point of Pedersen Commitment) 250 func ScalarMultH(scalar *Key) (result *Key) { 251 h := new(ExtendedGroupElement) 252 h.FromBytes(&H) 253 resultPoint := new(ProjectiveGroupElement) 254 GeScalarMult(resultPoint, scalar, h) 255 result = new(Key) 256 resultPoint.ToBytes(result) 257 return 258 } 259 260 // add two points together 261 func AddKeys(sum, k1, k2 *Key) { 262 a := k1.ToExtended() 263 var b CachedGroupElement 264 k2.ToExtended().ToCached(&b) 265 var c CompletedGroupElement 266 geAdd(&c, a, &b) 267 var tmp ExtendedGroupElement 268 c.ToExtended(&tmp) 269 tmp.ToBytes(sum) 270 return 271 } 272 273 // compute a*G + b*B 274 func AddKeys2(result, a, b, B *Key) { 275 BPoint := B.ToExtended() 276 var RPoint ProjectiveGroupElement 277 GeDoubleScalarMultVartime(&RPoint, b, BPoint, a) 278 RPoint.ToBytes(result) 279 return 280 } 281 282 //addKeys3 283 //aAbB = a*A + b*B where a, b are scalars, A, B are curve points 284 //B must be input after applying "precomp" 285 func AddKeys3(result *Key, a *Key, A *Key, b *Key, B_Precomputed *[8]CachedGroupElement) { 286 var A_Point ExtendedGroupElement 287 A_Point.FromBytes(A) 288 289 var result_projective ProjectiveGroupElement 290 GeDoubleScalarMultPrecompVartime(&result_projective, a, &A_Point, b, B_Precomputed) 291 result_projective.ToBytes(result) 292 293 } 294 295 //addKeys3_3 this is similiar to addkeys3 except it allows for use of precomputed A,B 296 //aAbB = a*A + b*B where a, b are scalars, A, B are curve points 297 //A,B must be input after applying "precomp" 298 func AddKeys3_3(result *Key, a *Key, A_Precomputed *[8]CachedGroupElement, b *Key, B_Precomputed *[8]CachedGroupElement) { 299 var result_projective ProjectiveGroupElement 300 GeDoubleScalarMultPrecompVartime2(&result_projective, a, A_Precomputed, b, B_Precomputed) 301 result_projective.ToBytes(result) 302 303 } 304 305 // subtract two points A - B 306 func SubKeys(diff, k1, k2 *Key) { 307 a := k1.ToExtended() 308 b := new(CachedGroupElement) 309 k2.ToExtended().ToCached(b) 310 c := new(CompletedGroupElement) 311 geSub(c, a, b) 312 tmp := new(ExtendedGroupElement) 313 c.ToExtended(tmp) 314 tmp.ToBytes(diff) 315 return 316 } 317 318 // zero fill the key 319 func Sc_0(k *Key) { 320 for i := 0; i < 32; i++ { 321 k[i] = 0 322 } 323 } 324 325 // RandomPubKey takes a random scalar, interprets it as a point on the curve 326 // remember the low order bug and do more auditing of the entire thing 327 func RandomPubKey() (result *Key) { 328 result = new(Key) 329 p3 := new(ExtendedGroupElement) 330 var p1 ProjectiveGroupElement 331 var p2 CompletedGroupElement 332 h := RandomScalar() 333 p1.FromBytes(h) 334 GeMul8(&p2, &p1) 335 p2.ToExtended(p3) 336 p3.ToBytes(result) 337 return 338 } 339 340 // this is the main key derivation function and is the crux 341 // when deriving keys in the case user A wants to send DERO to another user B ( this is outgoing case) 342 // public key is B's view key 343 // private keys is TX private key 344 // if user B wants to derive key, he needs to ( this is incoming case ) 345 // public key is TX public key 346 // private is B's private keys 347 // HOPE the above is clean and clear 348 349 func KeyDerivation(pub *Key, priv *Key) (KeyDerivation Key) { 350 var point ExtendedGroupElement 351 var point2 ProjectiveGroupElement 352 var point3 CompletedGroupElement 353 354 if !priv.Private_Key_Valid() { 355 panic("Invalid private key.") 356 } 357 tmp := *pub 358 if !point.FromBytes(&tmp) { 359 panic("Invalid public key.") 360 } 361 362 tmp = *priv 363 GeScalarMult(&point2, &tmp, &point) 364 GeMul8(&point3, &point2) 365 point3.ToProjective(&point2) 366 367 point2.ToBytes(&tmp) 368 return tmp 369 } 370 371 // the origincal c implementation needs to be checked for varint overflow 372 // we also need to check the compatibility of golang varint with cryptonote implemented varint 373 // outputIndex is the position of output within that specific transaction 374 func (k *Key) KeyDerivationToScalar(outputIndex uint64) (scalar *Key) { 375 tmp := make([]byte, 12, 12) 376 377 length := binary.PutUvarint(tmp, outputIndex) 378 tmp = tmp[:length] 379 380 var buf bytes.Buffer 381 buf.Write(k[:]) 382 buf.Write(tmp) 383 scalar = HashToScalar(buf.Bytes()) 384 return 385 } 386 387 // generate ephermal keys from a key derivation 388 // base key is the B's public spend key or A's private spend key 389 // outputIndex is the position of output within that specific transaction 390 func (kd *Key) KeyDerivation_To_PublicKey(outputIndex uint64, baseKey Key) Key { 391 392 var point1, point2 ExtendedGroupElement 393 var point3 CachedGroupElement 394 var point4 CompletedGroupElement 395 var point5 ProjectiveGroupElement 396 397 tmp := baseKey 398 if !point1.FromBytes(&tmp) { 399 panic("Invalid public key.") 400 } 401 scalar := kd.KeyDerivationToScalar(outputIndex) 402 GeScalarMultBase(&point2, scalar) 403 point2.ToCached(&point3) 404 geAdd(&point4, &point1, &point3) 405 point4.ToProjective(&point5) 406 point5.ToBytes(&tmp) 407 return tmp 408 } 409 410 // generate ephermal keys from a key derivation 411 // base key is the A's private spend key 412 // outputIndex is the position of output within that specific transaction 413 func (kd *Key) KeyDerivation_To_PrivateKey(outputIndex uint64, baseKey Key) Key { 414 if !baseKey.Private_Key_Valid() { 415 panic("Invalid private key.") 416 } 417 scalar := kd.KeyDerivationToScalar(outputIndex) 418 419 tmp := baseKey 420 ScAdd(&tmp, &tmp, scalar) 421 return tmp 422 } 423 424 // NewKeyImage creates a new KeyImage from the given public and private keys. 425 // The keys are usually the ephemeral keys derived using KeyDerivation. 426 func GenerateKeyImage(pub Key, private Key) Key { 427 var proj ProjectiveGroupElement 428 429 ext := pub.HashToEC() 430 GeScalarMult(&proj, &private, ext) 431 432 var ki Key 433 proj.ToBytes(&ki) 434 return ki 435 }