github.com/incognitochain/go-incognito-sdk@v1.0.1/privacy/curve25519/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 curve25519 18 19 import ( 20 "io" 21 ) 22 import "fmt" 23 import "bytes" 24 import "crypto/rand" 25 import "encoding/hex" 26 import "encoding/binary" 27 28 const KeyLength = 32 29 30 // Key can be a Scalar or a Point 31 type Key [KeyLength]byte 32 33 func (k Key) MarshalText() ([]byte ) { 34 return []byte(fmt.Sprintf("%x", k[:])) 35 } 36 37 func (k *Key) UnmarshalText(data []byte) (err error) { 38 byteSlice, _ := hex.DecodeString(string(data)) 39 if len(byteSlice) != 32 { 40 return fmt.Errorf("Incorrect key size") 41 } 42 copy(k[:], byteSlice) 43 return 44 } 45 46 func (k Key) String() string { 47 return fmt.Sprintf("%x", k[:]) 48 } 49 50 func (p *Key) FromBytes(b [KeyLength]byte) { 51 *p = b 52 } 53 54 func (p *Key) ToBytes() (result [KeyLength]byte) { 55 result = [KeyLength]byte(*p) 56 return 57 } 58 59 // convert a hex string to a key 60 func HexToKey(h string) (result Key) { 61 byteSlice, _ := hex.DecodeString(h) 62 if len(byteSlice) != 32 { 63 panic("Incorrect key size") 64 } 65 copy(result[:], byteSlice) 66 return 67 } 68 69 func HexToHash(h string) (result Hash) { 70 byteSlice, _ := hex.DecodeString(h) 71 if len(byteSlice) != 32 { 72 panic("Incorrect key size") 73 } 74 copy(result[:], byteSlice) 75 return 76 } 77 78 // generates a public from the secret key 79 func (p *Key) PublicKey() (pubKey *Key) { 80 point := new(ExtendedGroupElement) 81 GeScalarMultBase(point, p) 82 pubKey = new(Key) 83 point.ToBytes(pubKey) 84 return 85 } 86 87 // tests whether the key is valid ( represents a point on the curve ) 88 // this is equivalent to bool crypto_ops::check_key(const public_key &key) 89 func (k *Key) Public_Key_Valid() bool { 90 var point ExtendedGroupElement 91 return point.FromBytes(k) 92 } 93 94 func (k *Key) Private_Key_Valid() bool { 95 return Sc_check(k) 96 } 97 98 // Creates a point on the Edwards Curve by hashing the key 99 func (p *Key) HashToEC() (result *ExtendedGroupElement) { 100 result = new(ExtendedGroupElement) 101 var p1 ProjectiveGroupElement 102 var p2 CompletedGroupElement 103 h := Key(Keccak256(p[:])) 104 p1.FromBytes(&h) 105 106 // fmt.Printf("p1 %+v\n", p1) 107 GeMul8(&p2, &p1) 108 p2.ToExtended(result) 109 return 110 } 111 112 func (p *Key) HashToPoint() (result *Key) { 113 if result == nil { 114 result = new(Key) 115 } 116 extended := p.HashToEC() 117 extended.ToBytes(result) 118 return 119 } 120 121 // compatible with hashToPointSimple 122 // NOTE: this is incompatible with HashToPoint ( though it should have been) 123 // there are no side-effects or degradtion of curve25519, due to this 124 // however, the mistakes have to kept as they were in original code base 125 // this function is only used to generate H from G 126 func (p *Key) HashToPointSimple() (result Key) { 127 h := Key(Keccak256(p[:])) 128 extended := new(ExtendedGroupElement) 129 extended.FromBytes(&h) 130 131 // convert extended to projective 132 var p1 ProjectiveGroupElement 133 134 extended.ToProjective(&p1) 135 var p2 CompletedGroupElement 136 137 GeMul8(&p2, &p1) 138 p2.ToExtended(extended) 139 extended.ToBytes(&result) 140 return 141 } 142 143 // this uses random number generator from the OS 144 func RandomScalar() (result *Key) { 145 result = new(Key) 146 var reduceFrom [KeyLength * 2]byte 147 tmp := make([]byte, KeyLength*2) 148 rand.Read(tmp) 149 copy(reduceFrom[:], tmp) 150 ScReduce(result, &reduceFrom) 151 return 152 } 153 154 // generate a new private-public key pair 155 func NewKeyPair() (privKey *Key, pubKey *Key) { 156 privKey = RandomScalar() 157 pubKey = privKey.PublicKey() 158 return 159 } 160 161 func ParseKey(buf io.Reader) (result Key, err error) { 162 key := make([]byte, KeyLength) 163 if _, err = buf.Read(key); err != nil { 164 return 165 } 166 copy(result[:], key) 167 return 168 } 169 170 /* 171 //does a * G where a is a scalar and G is the curve basepoint 172 key scalarmultBase(const key & a) { 173 ge_p3 point; 174 key aG; 175 sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand 176 ge_scalarmult_base(&point, aG.bytes); 177 ge_p3_tobytes(aG.bytes, &point); 178 return aG; 179 } 180 */ 181 //does a * G where a is a scalar and G is the curve basepoint 182 183 func ScalarmultBase(a *Key) (aG *Key) { 184 reduce32copy := a 185 ScReduce32(reduce32copy) 186 point := new(ExtendedGroupElement) 187 GeScalarMultBase(point, a) 188 aG = new(Key) 189 point.ToBytes(aG) 190 return aG 191 } 192 193 // generates a key which can be used as private key or mask 194 // this function is similiar to RandomScalar except for reduce32, TODO can we merge both 195 func skGen() Key { 196 skey := RandomScalar() 197 ScReduce32(skey) 198 return *skey 199 } 200 func SkGen() Key { 201 return skGen() 202 } 203 204 func (k *Key) SignedRadix16() [64]int8 { 205 if k[31] > 127 { 206 panic("scalar has high bit set illegally") 207 } 208 209 var digits [64]int8 210 211 // Compute unsigned radix-16 digits: 212 for i := 0; i < 32; i++ { 213 digits[2*i] = int8(k[i] & 15) 214 digits[2*i+1] = int8((k[i] >> 4) & 15) 215 } 216 217 // Recenter coefficients: 218 for i := 0; i < 63; i++ { 219 carry := (digits[i] + 8) >> 4 220 digits[i] -= carry << 4 221 digits[i+1] += carry 222 } 223 224 return digits 225 } 226 227 func (k *Key) ToExtended() (result *ExtendedGroupElement) { 228 result = new(ExtendedGroupElement) 229 result.FromBytes(k) 230 return 231 } 232 233 // bothe the function resturn identity of the ed25519 curve 234 func identity() (result *Key) { 235 result = new(Key) 236 result[0] = 1 237 return 238 } 239 240 func CurveIdentity() (result Key) { 241 result = Identity 242 return result 243 } 244 245 func CurveOrder() (result Key) { 246 result = L 247 return result 248 } 249 250 // convert a uint64 to a scalar 251 func d2h(val uint64) (result *Key) { 252 result = new(Key) 253 for i := 0; val > 0; i++ { 254 result[i] = byte(val & 0xFF) 255 val /= 256 256 } 257 return 258 } 259 260 func HashToScalar(data ...[]byte) (result *Key) { 261 result = new(Key) 262 *result = Key(Keccak256(data...)) 263 ScReduce32(result) 264 return 265 } 266 267 // does a * P where a is a scalar and P is an arbitrary point 268 func ScalarMultKey(Point *Key, scalar *Key) (result *Key) { 269 var P ExtendedGroupElement 270 P.FromBytes(Point) 271 var resultPoint ProjectiveGroupElement 272 GeScalarMult(&resultPoint, scalar, &P) 273 result = new(Key) 274 resultPoint.ToBytes(result) 275 return 276 } 277 // multiply a scalar by H (second curve point of Pedersen Commitment) 278 func ScalarMultH(scalar *Key) (result *Key) { 279 h := new(ExtendedGroupElement) 280 h.FromBytes(&H) 281 resultPoint := new(ProjectiveGroupElement) 282 GeScalarMult(resultPoint, scalar, h) 283 result = new(Key) 284 resultPoint.ToBytes(result) 285 return 286 } 287 288 // add two points together 289 func AddKeys(sum, k1, k2 *Key) { 290 a := k1.ToExtended() 291 var b CachedGroupElement 292 k2.ToExtended().ToCached(&b) 293 var c CompletedGroupElement 294 geAdd(&c, a, &b) 295 var tmp ExtendedGroupElement 296 c.ToExtended(&tmp) 297 tmp.ToBytes(sum) 298 return 299 } 300 301 // compute a*G + b*B 302 func AddKeys2(result, a, b, B *Key) { 303 BPoint := B.ToExtended() 304 var RPoint ProjectiveGroupElement 305 GeDoubleScalarMultVartime(&RPoint, b, BPoint, a) 306 RPoint.ToBytes(result) 307 return 308 } 309 310 //addKeys3 311 //aAbB = a*A + b*B where a, b are scalars, A, B are curve points 312 //B must be input after applying "precomp" 313 func AddKeys3(result *Key, a *Key, A *Key, b *Key, B_Precomputed *[8]CachedGroupElement) { 314 var A_Point ExtendedGroupElement 315 A_Point.FromBytes(A) 316 317 var result_projective ProjectiveGroupElement 318 GeDoubleScalarMultPrecompVartime(&result_projective, a, &A_Point, b, B_Precomputed) 319 result_projective.ToBytes(result) 320 321 } 322 323 //addKeys3_3 this is similiar to addkeys3 except it allows for use of precomputed A,B 324 //aAbB = a*A + b*B where a, b are scalars, A, B are curve points 325 //A,B must be input after applying "precomp" 326 func AddKeys3_3(result *Key, a *Key, A_Precomputed *[8]CachedGroupElement, b *Key, B_Precomputed *[8]CachedGroupElement) { 327 var result_projective ProjectiveGroupElement 328 GeDoubleScalarMultPrecompVartime2(&result_projective, a, A_Precomputed, b, B_Precomputed) 329 result_projective.ToBytes(result) 330 331 } 332 333 // subtract two points A - B 334 func SubKeys(diff, k1, k2 *Key) { 335 a := k1.ToExtended() 336 b := new(CachedGroupElement) 337 k2.ToExtended().ToCached(b) 338 c := new(CompletedGroupElement) 339 geSub(c, a, b) 340 tmp := new(ExtendedGroupElement) 341 c.ToExtended(tmp) 342 tmp.ToBytes(diff) 343 return 344 } 345 346 // zero fill the key 347 func Sc_0(k *Key) { 348 for i := 0; i < 32; i++ { 349 k[i] = 0 350 } 351 } 352 353 // RandomPubKey takes a random scalar, interprets it as a point on the curve 354 // remember the low order bug and do more auditing of the entire thing 355 func RandomPubKey() (result *Key) { 356 result = new(Key) 357 p3 := new(ExtendedGroupElement) 358 var p1 ProjectiveGroupElement 359 var p2 CompletedGroupElement 360 h := RandomScalar() 361 p1.FromBytes(h) 362 GeMul8(&p2, &p1) 363 p2.ToExtended(p3) 364 p3.ToBytes(result) 365 return 366 } 367 368 // this is the main key derivation function and is the crux 369 // when deriving keys in the case user A wants to send DERO to another user B ( this is outgoing case) 370 // public key is B's view key 371 // private keys is TX private key 372 // if user B wants to derive key, he needs to ( this is incoming case ) 373 // public key is TX public key 374 // private is B's private keys 375 // HOPE the above is clean and clear 376 377 func KeyDerivation(pub *Key, priv *Key) (KeyDerivation Key) { 378 var point ExtendedGroupElement 379 var point2 ProjectiveGroupElement 380 var point3 CompletedGroupElement 381 382 if !priv.Private_Key_Valid() { 383 panic("Invalid private key.") 384 } 385 tmp := *pub 386 if !point.FromBytes(&tmp) { 387 panic("Invalid public key.") 388 } 389 390 tmp = *priv 391 GeScalarMult(&point2, &tmp, &point) 392 GeMul8(&point3, &point2) 393 point3.ToProjective(&point2) 394 395 point2.ToBytes(&tmp) 396 return tmp 397 } 398 399 // the origincal c implementation needs to be checked for varint overflow 400 // we also need to check the compatibility of golang varint with cryptonote implemented varint 401 // outputIndex is the position of output within that specific transaction 402 func (k *Key) KeyDerivationToScalar(outputIndex uint64) (scalar *Key) { 403 tmp := make([]byte, 12, 12) 404 405 length := binary.PutUvarint(tmp, outputIndex) 406 tmp = tmp[:length] 407 408 var buf bytes.Buffer 409 buf.Write(k[:]) 410 buf.Write(tmp) 411 scalar = HashToScalar(buf.Bytes()) 412 return 413 } 414 415 // generate ephermal keys from a key derivation 416 // base key is the B's public spend key or A's private spend key 417 // outputIndex is the position of output within that specific transaction 418 func (kd *Key) KeyDerivation_To_PublicKey(outputIndex uint64, baseKey Key) Key { 419 420 var point1, point2 ExtendedGroupElement 421 var point3 CachedGroupElement 422 var point4 CompletedGroupElement 423 var point5 ProjectiveGroupElement 424 425 tmp := baseKey 426 if !point1.FromBytes(&tmp) { 427 panic("Invalid public key.") 428 } 429 scalar := kd.KeyDerivationToScalar(outputIndex) 430 GeScalarMultBase(&point2, scalar) 431 point2.ToCached(&point3) 432 geAdd(&point4, &point1, &point3) 433 point4.ToProjective(&point5) 434 point5.ToBytes(&tmp) 435 return tmp 436 } 437 438 // generate ephermal keys from a key derivation 439 // base key is the A's private spend key 440 // outputIndex is the position of output within that specific transaction 441 func (kd *Key) KeyDerivation_To_PrivateKey(outputIndex uint64, baseKey Key) Key { 442 if !baseKey.Private_Key_Valid() { 443 panic("Invalid private key.") 444 } 445 scalar := kd.KeyDerivationToScalar(outputIndex) 446 447 tmp := baseKey 448 ScAdd(&tmp, &tmp, scalar) 449 450 return tmp 451 } 452 453 // NewKeyImage creates a new KeyImage from the given public and private keys. 454 // The keys are usually the ephemeral keys derived using KeyDerivation. 455 func GenerateKeyImage(pub Key, private Key) Key { 456 var proj ProjectiveGroupElement 457 458 ext := pub.HashToEC() 459 GeScalarMult(&proj, &private, ext) 460 461 var ki Key 462 proj.ToBytes(&ki) 463 return ki 464 } 465 466 func PreComputeForMultiScalar (p *Key) [8]CachedGroupElement { 467 // A,2A,3A,4A,5A,6A,7A,8A 468 var Ai [8]CachedGroupElement 469 var A ExtendedGroupElement 470 t := new(CompletedGroupElement) 471 u := new(ExtendedGroupElement) 472 473 A.FromBytes(p) 474 A.ToCached(&Ai[0]) 475 for j := 0; j < 7; j++ { 476 geAdd(t, &A, &Ai[j]) 477 t.ToExtended(u) 478 u.ToCached(&Ai[j+1]) 479 } 480 return Ai 481 } 482 483 484 func MultiScalarMultKeyCached(AiLs [][8]CachedGroupElement, scalars []*Key, ) (result *Key) { 485 r := new(ProjectiveGroupElement) 486 487 digitsLs := make([][64]int8, len(scalars)) 488 for i:= range digitsLs { 489 digitsLs[i] = scalars[i].SignedRadix16() 490 } 491 492 t := new(CompletedGroupElement) 493 u := new(ExtendedGroupElement) 494 495 r.Zero() 496 cachedBase := new(ExtendedGroupElement) 497 cur := new(CachedGroupElement) 498 minusCur := new(CachedGroupElement) 499 for i := 63; i >= 0; i-- { 500 r.Double(t) 501 t.ToProjective(r) 502 r.Double(t) 503 t.ToProjective(r) 504 r.Double(t) 505 t.ToProjective(r) 506 r.Double(t) 507 t.ToExtended(u) 508 509 cachedBase.Zero() 510 tmpt := new(CompletedGroupElement) 511 for j:= 0; j < len(scalars); j++ { 512 cur.Zero() 513 b := digitsLs[j][i] 514 bNegative := int8(negative(int32(b))) 515 bAbs := b - (((-bNegative) & b) << 1) 516 517 for k := int32(0); k < 8; k++ { 518 if equal(int32(bAbs), k+1) == 1 { // optimisation 519 CachedGroupElementCMove(cur, &AiLs[j][k], equal(int32(bAbs), k+1)) 520 } 521 } 522 FeCopy(&minusCur.yPlusX, &cur.yMinusX) 523 FeCopy(&minusCur.yMinusX, &cur.yPlusX) 524 FeCopy(&minusCur.Z, &cur.Z) 525 FeNeg(&minusCur.T2d, &cur.T2d) 526 CachedGroupElementCMove(cur, minusCur, int32(bNegative)) 527 528 geAdd(tmpt, cachedBase, cur) 529 tmpt.ToExtended(cachedBase) 530 } 531 tmpv := new(CachedGroupElement) 532 cachedBase.ToCached(tmpv) 533 geAdd(t, u, tmpv) 534 t.ToProjective(r) 535 } 536 result = new(Key) 537 r.ToBytes(result) 538 return result 539 } 540 541 func MultiScalarMultKey(points []*Key, scalars []*Key) (result *Key) { 542 r := new(ProjectiveGroupElement) 543 544 545 pointLs := make([]ExtendedGroupElement, len(points)) 546 547 digitsLs := make([][64]int8, len(scalars)) 548 for i:= range digitsLs { 549 digitsLs[i] = scalars[i].SignedRadix16() 550 } 551 552 AiLs := make([][8]CachedGroupElement, len(scalars)) 553 for i:= 0; i < len(scalars); i++ { 554 // A,2A,3A,4A,5A,6A,7A,8A 555 t := new(CompletedGroupElement) 556 u := new(ExtendedGroupElement) 557 pointLs[i].FromBytes(points[i]) 558 pointLs[i].ToCached(&AiLs[i][0]) 559 for j := 0; j < 7; j++ { 560 geAdd(t, &pointLs[i], &AiLs[i][j]) 561 t.ToExtended(u) 562 u.ToCached(&AiLs[i][j+1]) 563 } 564 } 565 566 t := new(CompletedGroupElement) 567 u := new(ExtendedGroupElement) 568 569 r.Zero() 570 cachedBase := new(ExtendedGroupElement) 571 cur := new(CachedGroupElement) 572 minusCur := new(CachedGroupElement) 573 for i := 63; i >= 0; i-- { 574 r.Double(t) 575 t.ToProjective(r) 576 r.Double(t) 577 t.ToProjective(r) 578 r.Double(t) 579 t.ToProjective(r) 580 r.Double(t) 581 t.ToExtended(u) 582 583 cachedBase.Zero() 584 tmpt := new(CompletedGroupElement) 585 for j:= 0; j < len(scalars); j++ { 586 cur.Zero() 587 b := digitsLs[j][i] 588 bNegative := int8(negative(int32(b))) 589 bAbs := b - (((-bNegative) & b) << 1) 590 591 for k := int32(0); k < 8; k++ { 592 if equal(int32(bAbs), k+1) == 1 { // optimisation 593 CachedGroupElementCMove(cur, &AiLs[j][k], equal(int32(bAbs), k+1)) 594 } 595 } 596 FeCopy(&minusCur.yPlusX, &cur.yMinusX) 597 FeCopy(&minusCur.yMinusX, &cur.yPlusX) 598 FeCopy(&minusCur.Z, &cur.Z) 599 FeNeg(&minusCur.T2d, &cur.T2d) 600 CachedGroupElementCMove(cur, minusCur, int32(bNegative)) 601 602 geAdd(tmpt, cachedBase, cur) 603 tmpt.ToExtended(cachedBase) 604 } 605 tmpv := new(CachedGroupElement) 606 cachedBase.ToCached(tmpv) 607 geAdd(t, u, tmpv) 608 t.ToProjective(r) 609 } 610 result = new(Key) 611 r.ToBytes(result) 612 return result 613 }