github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/crypto/ringct/ringct.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 ringct 18 19 import "io" 20 import "fmt" 21 import "bytes" 22 import "sync" 23 import "sync/atomic" 24 25 import "github.com/deroproject/derosuite/crypto" 26 27 // enable debuggin mode within ringct 28 // if true debugging mode enabled 29 const DEBUGGING_MODE = false 30 31 // XMR testnet bulletproofs are serialized differently than how we do it 32 // XMR pseudoouts are marked as prunable and serialized at the end 33 // while we consider them as base 34 // below switch enables compatibility for developments purposes and should be turned 35 // false after development is finished 36 // some automated tests will automatically enable it temporarily 37 var XMR_COMPATIBILITY bool = false 38 39 func setcompatibility(value bool) { 40 fmt.Printf("compatibility %+v", value) 41 } 42 43 // TODO this package need serious love of atleast few weeks 44 // but atleast the parser and serdes works 45 // we neeed to expand everthing so as chances of a bug slippping in becomes very low 46 // NOTE:DO NOT waste time implmenting pre-RCT code 47 48 const ( 49 RCTTypeNull = iota 50 RCTTypeFull // we do generate these but they are accepted 51 RCTTypeSimple 52 RCTTypeFullBulletproof // we DO NOT parse/support/generate these 53 RCTTypeSimpleBulletproof 54 ) 55 56 // Pedersen Commitment is generated from this struct 57 // C = aG + bH where a = mask and b = amount 58 // senderPk is the one-time public key for ECDH exchange 59 type ECdhTuple struct { 60 Mask crypto.Key `msgpack:"M"` 61 Amount crypto.Key `msgpack:"A"` 62 // senderPk Key 63 } 64 65 // Range proof commitments 66 type Key64 [64]crypto.Key // for Borromean 67 68 // Range Signature 69 // Essentially data for a Borromean Signature 70 type RangeSig struct { 71 asig BoroSig 72 ci Key64 73 } 74 75 // Borromean Signature 76 type BoroSig struct { 77 s0 Key64 78 s1 Key64 79 ee crypto.Key 80 } 81 82 // size of single bullet proof range 83 // we are currently only implementing non-aggregate version only 84 // as aggregate have following benefits and disadvntages 85 // 1) they are logarithmic in size but verification is linear, thus aggregate version may make it very easy to DOD 86 // 2) they can only be used for 2^n outputs not for randon n 87 // 3) are very optimised and speedy to verify 88 // serialised size ((2*6 + 4 + 5)*32 + 3) * n_outputs; 89 type BulletProof struct { 90 V []crypto.Key // 1 * 32 // extra 1 byte for length 91 92 // 4 93 A crypto.Key // 1 * 32 94 S crypto.Key // 1 * 32 95 T1 crypto.Key // 1 * 32 96 T2 crypto.Key // 1 * 32 97 98 // final 2/5 99 taux crypto.Key // 1 * 32 100 mu crypto.Key // 1 * 32 101 102 // 2*6 103 L []crypto.Key // 6 * 32 // space requirements while serializing, extra 1 byte for length 104 R []crypto.Key // 6 * 32 // space requirements while serializing, extra 1 byte for length 105 106 // final 3/5 107 a crypto.Key // 1 * 32 108 b crypto.Key // 1 * 32 109 t crypto.Key // 1 * 32 110 } 111 112 // MLSAG (Multilayered Linkable Spontaneous Anonymous Group) Signature 113 type MlsagSig struct { 114 ss [][]crypto.Key 115 cc crypto.Key // this stores the starting point 116 II []crypto.Key // this stores the keyimage, but is taken from the tx/blockchain,it is NOT serialized 117 } 118 119 // Confidential Transaction Keys, mask is Pedersen Commitment 120 // most of the time, it holds public keys, except (transaction making ) where it holds private keys 121 type CtKey struct { 122 Destination crypto.Key `msgpack:"D"` // this is the destination and needs to expanded from blockchain 123 Mask crypto.Key `msgpack:"M"` // this is the public key amount/commitment homomorphic mask 124 } 125 126 // Ring Confidential Signature parts that we have to keep 127 type RctSigBase struct { 128 sigType uint8 129 Message crypto.Key // transaction prefix hash 130 MixRing [][]CtKey // this is not serialized 131 pseudoOuts []crypto.Key 132 ECdhInfo []ECdhTuple 133 OutPk []CtKey // only mask amount is serialized 134 txFee uint64 135 136 Txid crypto.Hash // this field is extra and only used for logging purposes to track which txid was at fault 137 } 138 139 // Ring Confidential Signature parts that we can just prune later 140 type RctSigPrunable struct { 141 rangeSigs []RangeSig //borrowmean range proof 142 BulletSigs []BulletProof // bulletproofs range proofs 143 MlsagSigs []MlsagSig // there can be as many mlsagsigs as many vins 144 } 145 146 // Ring Confidential Signature struct that can verify everything 147 type RctSig struct { 148 RctSigBase 149 RctSigPrunable 150 } 151 152 func (k *Key64) Serialize() (result []byte) { 153 for _, key := range k { 154 result = append(result, key[:]...) 155 } 156 return 157 } 158 159 func (b *BoroSig) Serialize() (result []byte) { 160 result = append(b.s0.Serialize(), b.s1.Serialize()...) 161 result = append(result, b.ee[:]...) 162 return 163 } 164 165 func (r *RangeSig) Serialize() (result []byte) { 166 result = append(r.asig.Serialize(), r.ci.Serialize()...) 167 return 168 } 169 170 func (m *MlsagSig) Serialize() (result []byte) { 171 for i := 0; i < len(m.ss); i++ { 172 for j := 0; j < len(m.ss[i]); j++ { 173 result = append(result, m.ss[i][j][:]...) 174 } 175 } 176 result = append(result, m.cc[:]...) 177 return 178 } 179 180 func (r *RctSigBase) SerializeBase() (result []byte) { 181 result = []byte{r.sigType} 182 // Null type returns right away 183 if r.sigType == RCTTypeNull { 184 return 185 } 186 result = append(result, Uint64ToBytes(r.txFee)...) 187 if r.sigType == RCTTypeSimple { 188 for _, input := range r.pseudoOuts { 189 result = append(result, input[:]...) 190 } 191 } 192 193 if XMR_COMPATIBILITY == false { // we consider pseudo outs are always part of base 194 if r.sigType == RCTTypeSimpleBulletproof { 195 for _, input := range r.pseudoOuts { 196 result = append(result, input[:]...) 197 } 198 } 199 } 200 201 for _, ecdh := range r.ECdhInfo { 202 result = append(result, ecdh.Mask[:]...) 203 result = append(result, ecdh.Amount[:]...) 204 } 205 for _, ctKey := range r.OutPk { 206 result = append(result, ctKey.Mask[:]...) 207 } 208 return 209 } 210 211 func (r *RctSigBase) BaseHash() (result crypto.Hash) { 212 result = crypto.Keccak256(r.SerializeBase()) 213 return 214 } 215 216 func (r *RctSig) SerializePrunable() (result []byte) { 217 if r.sigType == RCTTypeNull { 218 return 219 } 220 for _, rangeSig := range r.rangeSigs { 221 result = append(result, rangeSig.Serialize()...) 222 } 223 for _, bp := range r.BulletSigs { 224 result = append(result, bp.Serialize()...) 225 } 226 for _, mlsagSig := range r.MlsagSigs { 227 result = append(result, mlsagSig.Serialize()...) 228 } 229 230 if XMR_COMPATIBILITY == true { 231 // XMR pseudoouts are serialized differently and considered prunable and at the end 232 if r.sigType == RCTTypeSimpleBulletproof { 233 for _, input := range r.pseudoOuts { 234 result = append(result, input[:]...) 235 } 236 } 237 } 238 return 239 } 240 241 func (r *RctSig) Get_Sig_Type() byte { 242 return r.sigType 243 } 244 245 func (r *RctSig) Get_TX_Fee() (result uint64) { 246 if r.sigType == RCTTypeNull { 247 panic("RCTTypeNull cannot have TX fee") 248 } 249 return r.txFee 250 } 251 252 func (r *RctSig) PrunableHash() (result crypto.Hash) { 253 if r.sigType == RCTTypeNull { 254 return 255 } 256 result = crypto.Keccak256(r.SerializePrunable()) 257 return 258 } 259 260 // this is the function which should be used by external world 261 // if any exceptions occur while handling, we simply return false 262 // transaction must be expanded before verification 263 // coinbase transactions are always success, since they are tied to PoW of block 264 func (r *RctSig) Verify() (result bool) { 265 266 result = false 267 defer func() { // safety so if anything wrong happens, verification fails 268 if r := recover(); r != nil { 269 //connection.logger.Fatalf("Recovered while Verify transaction", r) 270 fmt.Printf("Recovered while Verify transaction") 271 result = false 272 } 273 }() 274 275 switch r.sigType { 276 case RCTTypeNull: 277 return false /// this is only possible for miner tx 278 case RCTTypeFull: 279 return r.VerifyRctFull() 280 case RCTTypeSimple: 281 return r.VerifyRctSimple() 282 case RCTTypeFullBulletproof: 283 return false // these TX are NOT supported 284 case RCTTypeSimpleBulletproof: 285 return r.VerifyRctSimpleBulletProof() 286 287 default: 288 return false 289 } 290 291 // can never reach here 292 //return false 293 } 294 295 // Verify a RCTTypeSimple RingCT Signature 296 func (r *RctSig) VerifyRctSimple() bool { 297 sumOutPks := identity() 298 for _, ctKey := range r.OutPk { 299 crypto.AddKeys(sumOutPks, sumOutPks, &ctKey.Mask) 300 } 301 //txFeeKey := ScalarMultH(d2h(r.txFee)) 302 txFeeKey := Commitment_From_Amount(r.txFee) 303 crypto.AddKeys(sumOutPks, sumOutPks, &txFeeKey) 304 sumPseudoOuts := identity() 305 for _, pseudoOut := range r.pseudoOuts { 306 crypto.AddKeys(sumPseudoOuts, sumPseudoOuts, &pseudoOut) 307 } 308 if *sumPseudoOuts != *sumOutPks { 309 return false 310 } 311 312 /* 313 // verify range single threaded 314 for i, ctKey := range r.OutPk { 315 if !VerifyRange(&ctKey.Mask, r.rangeSigs[i]) { 316 return false 317 } 318 } 319 */ 320 321 // verify borrowmean range in parallelised form 322 fail_count := uint64(0) 323 wg := sync.WaitGroup{} 324 wg.Add(len(r.OutPk)) 325 326 for i, ctKey := range r.OutPk { 327 go func(index int, ckey CtKey) { 328 if !VerifyRange(&ckey.Mask, r.rangeSigs[index]) { 329 atomic.AddUint64(&fail_count, 1) // increase fail count by 1 330 } 331 wg.Done() 332 }(i, ctKey) 333 } 334 wg.Wait() 335 if fail_count > 0 { // check the result 336 return false 337 } 338 339 if len(r.pseudoOuts) != len(r.MlsagSigs) { //if the signatures are partial reject 340 return false 341 } 342 343 return r.VerifyRCTSimple_Core() 344 } 345 346 // Verify a RCTTypeSimple RingCT Signature 347 func (r *RctSig) VerifyRctSimpleBulletProof() bool { 348 sumOutPks := identity() 349 for _, ctKey := range r.OutPk { 350 crypto.AddKeys(sumOutPks, sumOutPks, &ctKey.Mask) 351 } 352 //txFeeKey := ScalarMultH(d2h(r.txFee)) 353 txFeeKey := Commitment_From_Amount(r.txFee) 354 crypto.AddKeys(sumOutPks, sumOutPks, &txFeeKey) 355 sumPseudoOuts := identity() 356 for _, pseudoOut := range r.pseudoOuts { 357 crypto.AddKeys(sumPseudoOuts, sumPseudoOuts, &pseudoOut) 358 } 359 if *sumPseudoOuts != *sumOutPks { 360 return false 361 } 362 363 if len(r.pseudoOuts) != len(r.MlsagSigs) { //if the signatures are partial reject 364 return false 365 } 366 367 /* verify bulletproof in single threaded */ 368 for i, _ := range r.OutPk { 369 r.BulletSigs[i].V = []crypto.Key{crypto.Key(r.OutPk[i].Mask)} 370 //if !r.BulletSigs[i].BULLETPROOF_Verify() { 371 if !r.BulletSigs[i].BULLETPROOF_Verify_ultrafast() { 372 return false 373 } 374 } 375 376 /* 377 // verify range in parallelised form 378 fail_count := int32(0) 379 wg := sync.WaitGroup{} 380 wg.Add(len(r.OutPk)) 381 382 for i, _ := range r.OutPk { 383 r.BulletSigs[i].V = []crypto.Key{crypto.Key(r.OutPk[i].Mask)} 384 } 385 for i, _ := range r.OutPk { 386 go func(index int){ 387 if !r.BulletSigs[index].BULLETPROOF_Verify() { 388 //if !r.BulletSigs[index].BULLETPROOF_Verify_ultrafast() { 389 atomic.AddInt32(&fail_count, 1) // increase fail count by 1 390 } 391 wg.Done() 392 }(i) 393 } 394 wg.Wait() 395 if fail_count > 0 { // check the result 396 return false 397 } 398 */ 399 400 return r.VerifyRCTSimple_Core() 401 } 402 func (r *RctSig) VerifyRctFull() bool { 403 for i, ctKey := range r.OutPk { 404 if !VerifyRange(&ctKey.Mask, r.rangeSigs[i]) { 405 return false 406 } 407 } 408 409 if 1 != len(r.MlsagSigs) { //if the signatures are partial reject 410 return false 411 } 412 413 return r.VerifyRCTFull_Core() 414 } 415 416 func ParseCtKey(buf io.Reader) (result CtKey, err error) { 417 if result.Mask, err = crypto.ParseKey(buf); err != nil { 418 return 419 } 420 return 421 } 422 423 func ParseKey64(buf io.Reader) (result Key64, err error) { 424 for i := 0; i < 64; i++ { 425 if result[i], err = crypto.ParseKey(buf); err != nil { 426 return 427 } 428 } 429 return 430 } 431 432 // parse Borromean signature 433 func ParseBoroSig(buf io.Reader) (result BoroSig, err error) { 434 if result.s0, err = ParseKey64(buf); err != nil { 435 return 436 } 437 if result.s1, err = ParseKey64(buf); err != nil { 438 return 439 } 440 if result.ee, err = crypto.ParseKey(buf); err != nil { 441 return 442 } 443 return 444 } 445 446 // range data consists of Single Borromean sig and 64 keys for 64 bits 447 func ParseRangeSig(buf io.Reader) (result RangeSig, err error) { 448 if result.asig, err = ParseBoroSig(buf); err != nil { 449 return 450 } 451 if result.ci, err = ParseKey64(buf); err != nil { 452 return 453 } 454 return 455 } 456 457 // parser for ringct signature 458 // we need to be extra cautious as almost anything cam come as input 459 func ParseRingCtSignature(buf io.Reader, nInputs, nOutputs, nMixin int) (result *RctSig, err error) { 460 r := new(RctSig) 461 sigType := make([]byte, 1) 462 _, err = buf.Read(sigType) 463 if err != nil { 464 return 465 } 466 r.sigType = uint8(sigType[0]) 467 if r.sigType == RCTTypeNull { 468 result = r 469 return 470 } 471 472 /* This triggers go vet saying suspect OR 473 if (r.sigType != RCTTypeFull) || (r.sigType != RCTTypeSimple) { 474 err = fmt.Errorf("Bad signature Type %d", r.sigType) 475 return 476 }*/ 477 478 switch r.sigType { 479 case RCTTypeFull: 480 case RCTTypeSimple: 481 case RCTTypeSimpleBulletproof: 482 483 case RCTTypeFullBulletproof: 484 err = fmt.Errorf("Bad signature Type %d", r.sigType) 485 return 486 default: 487 err = fmt.Errorf("Bad signature Type %d", r.sigType) 488 return 489 490 } 491 492 r.txFee, err = ReadVarInt(buf) 493 if err != nil { 494 return 495 } 496 var nMg, nSS int 497 498 // pseudoouts for bulletproofs are serialised at the end 499 if r.sigType == RCTTypeSimple || r.sigType == RCTTypeSimpleBulletproof { 500 nMg = nInputs 501 nSS = 2 502 r.pseudoOuts = make([]crypto.Key, nInputs) 503 504 if r.sigType == RCTTypeSimple { 505 for i := 0; i < nInputs; i++ { 506 if r.pseudoOuts[i], err = crypto.ParseKey(buf); err != nil { 507 return 508 } 509 } 510 } 511 512 if XMR_COMPATIBILITY == false { // parse our serialized 513 if r.sigType == RCTTypeSimpleBulletproof { 514 for i := 0; i < nInputs; i++ { 515 if r.pseudoOuts[i], err = crypto.ParseKey(buf); err != nil { 516 return 517 } 518 } 519 } 520 } 521 } else { 522 nMg = 1 523 nSS = nInputs + 1 524 } 525 r.ECdhInfo = make([]ECdhTuple, nOutputs) 526 for i := 0; i < nOutputs; i++ { 527 if r.ECdhInfo[i].Mask, err = crypto.ParseKey(buf); err != nil { 528 return 529 } 530 if r.ECdhInfo[i].Amount, err = crypto.ParseKey(buf); err != nil { 531 return 532 } 533 } 534 r.OutPk = make([]CtKey, nOutputs) 535 for i := 0; i < nOutputs; i++ { 536 if r.OutPk[i], err = ParseCtKey(buf); err != nil { 537 return 538 } 539 } 540 541 switch r.sigType { 542 case RCTTypeFull, RCTTypeSimple: 543 r.rangeSigs = make([]RangeSig, nOutputs) 544 for i := 0; i < nOutputs; i++ { 545 if r.rangeSigs[i], err = ParseRangeSig(buf); err != nil { 546 return 547 } 548 } 549 550 case RCTTypeFullBulletproof, RCTTypeSimpleBulletproof: 551 r.BulletSigs = make([]BulletProof, nOutputs) 552 for i := 0; i < nOutputs; i++ { 553 if r.BulletSigs[i], err = ParseBulletProof(buf); err != nil { 554 return 555 } 556 557 } 558 } 559 560 r.MlsagSigs = make([]MlsagSig, nMg) 561 for i := 0; i < nMg; i++ { 562 r.MlsagSigs[i].ss = make([][]crypto.Key, nMixin+1) 563 for j := 0; j < nMixin+1; j++ { 564 r.MlsagSigs[i].ss[j] = make([]crypto.Key, nSS) 565 for k := 0; k < nSS; k++ { 566 if r.MlsagSigs[i].ss[j][k], err = crypto.ParseKey(buf); err != nil { 567 return 568 } 569 } 570 } 571 if r.MlsagSigs[i].cc, err = crypto.ParseKey(buf); err != nil { 572 return 573 } 574 } 575 576 if XMR_COMPATIBILITY == true { // parse XMR bulletproofs 577 // parse pseudoouts for bulletproofs 578 if r.sigType == RCTTypeSimpleBulletproof { 579 for i := 0; i < nInputs; i++ { 580 if r.pseudoOuts[i], err = crypto.ParseKey(buf); err != nil { 581 return 582 } 583 } 584 } 585 } 586 587 //fmt.Printf("mlsag sigs %+v \n",r.MlsagSigs) 588 result = r 589 return 590 } 591 592 func ParseBulletProof(buf io.Reader) (b BulletProof, err error) { 593 if b.A, err = crypto.ParseKey(buf); err != nil { 594 return 595 } 596 if b.S, err = crypto.ParseKey(buf); err != nil { 597 return 598 } 599 if b.T1, err = crypto.ParseKey(buf); err != nil { 600 return 601 } 602 if b.T2, err = crypto.ParseKey(buf); err != nil { 603 return 604 } 605 if b.taux, err = crypto.ParseKey(buf); err != nil { 606 return 607 } 608 if b.mu, err = crypto.ParseKey(buf); err != nil { 609 return 610 } 611 612 lcount, err := ReadVarInt(buf) 613 if err != nil { 614 return 615 } 616 617 if lcount > 1024 { 618 err = fmt.Errorf("Detected dos bulletproof bad L %d", lcount) 619 return 620 } 621 b.L = make([]crypto.Key, lcount, lcount) 622 623 for i := range b.L { 624 if b.L[i], err = crypto.ParseKey(buf); err != nil { 625 return 626 } 627 } 628 629 rcount, err := ReadVarInt(buf) 630 if err != nil { 631 return 632 } 633 if rcount > 1024 { 634 err = fmt.Errorf("Detected dos bulletproof bad L %d", rcount) 635 return 636 } 637 b.R = make([]crypto.Key, rcount, rcount) 638 639 for i := range b.R { 640 if b.R[i], err = crypto.ParseKey(buf); err != nil { 641 return 642 } 643 } 644 645 if b.a, err = crypto.ParseKey(buf); err != nil { 646 return 647 } 648 if b.b, err = crypto.ParseKey(buf); err != nil { 649 return 650 } 651 if b.t, err = crypto.ParseKey(buf); err != nil { 652 return 653 } 654 655 return 656 } 657 658 // serialize the bullet proof 659 func (b *BulletProof) Serialize() (result []byte) { 660 var buf bytes.Buffer 661 buf.Write(b.A[:]) 662 buf.Write(b.S[:]) 663 buf.Write(b.T1[:]) 664 buf.Write(b.T2[:]) 665 buf.Write(b.taux[:]) 666 buf.Write(b.mu[:]) 667 buf.Write(Uint64ToBytes(uint64(len(b.L)))) 668 for i := range b.L { 669 buf.Write(b.L[i][:]) 670 } 671 buf.Write(Uint64ToBytes(uint64(len(b.R)))) 672 for i := range b.R { 673 buf.Write(b.R[i][:]) 674 } 675 buf.Write(b.a[:]) 676 buf.Write(b.b[:]) 677 buf.Write(b.t[:]) 678 return buf.Bytes() 679 } 680 681 /* 682 //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a 683 // where C= aG + bH 684 void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec) { 685 key sharedSec1 = hash_to_scalar(sharedSec); 686 key sharedSec2 = hash_to_scalar(sharedSec1); 687 //encode 688 sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes); 689 sc_add(unmasked.amount.bytes, unmasked.amount.bytes, sharedSec2.bytes); 690 } 691 void ecdhDecode(ecdhTuple & masked, const key & sharedSec) { 692 key sharedSec1 = hash_to_scalar(sharedSec); 693 key sharedSec2 = hash_to_scalar(sharedSec1); 694 //decode 695 sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes); 696 sc_sub(masked.amount.bytes, masked.amount.bytes, sharedSec2.bytes); 697 } 698 */ 699 func ecdhEncode(tuple *ECdhTuple, shared_secret crypto.Key) { 700 shared_secret1 := crypto.HashToScalar(shared_secret[:]) 701 shared_secret2 := crypto.HashToScalar(shared_secret1[:]) 702 703 // encode 704 crypto.ScAdd(&tuple.Mask, &tuple.Mask, shared_secret1) 705 crypto.ScAdd(&tuple.Amount, &tuple.Amount, shared_secret2) 706 } 707 708 func ecdhDecode(tuple *ECdhTuple, shared_secret crypto.Key) { 709 shared_secret1 := crypto.HashToScalar(shared_secret[:]) 710 shared_secret2 := crypto.HashToScalar(shared_secret1[:]) 711 712 // decode 713 crypto.ScSub(&tuple.Mask, &tuple.Mask, shared_secret1) 714 crypto.ScSub(&tuple.Amount, &tuple.Amount, shared_secret2) 715 } 716 717 // decode and verify a previously encrypted tuple 718 // the keys come in from the wallet 719 // tuple is the encoded data 720 // skey is the secret scalar key 721 // outpk is public key used to verify whether the decode was sucessfull 722 func Decode_Amount(tuple ECdhTuple, skey crypto.Key, outpk crypto.Key) (amount uint64, mask crypto.Key, result bool) { 723 var Ctmp crypto.Key 724 725 ecdhDecode(&tuple, skey) // decode the amounts 726 727 // saniity check similiar to original one 728 // addKeys2(Ctmp, mask, amount, H); 729 crypto.AddKeys2(&Ctmp, &tuple.Mask, &tuple.Amount, &H) 730 731 if Ctmp != outpk { 732 fmt.Printf("warning, amount decoded incorrectly, will be unable to spend") 733 result = false 734 return 735 } 736 amount = h2d(tuple.Amount) 737 mask = tuple.Mask 738 739 result = true 740 return 741 } 742 743 /* from rctOps.cpp 744 //generates C =aG + bH from b, a is given.. 745 void genC(key & C, const key & a, xmr_amount amount) { 746 key bH = scalarmultH(d2h(amount)); 747 addKeys1(C, a, bH); 748 } 749 */ 750 // Commit X amount to random // see Commitment_From_Amount and ZeroCommitment_From_Amount in key.go 751 func genC(C *crypto.Key, a *crypto.Key, amount uint64) { 752 bH := crypto.ScalarMultH(d2h(amount)) 753 aG := crypto.ScalarmultBase(*a) 754 crypto.AddKeys(C, &aG, bH) 755 }