github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/proof/proof.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 proof 18 19 import "fmt" 20 import "encoding/hex" 21 22 import "github.com/deroproject/derosuite/crypto" 23 import "github.com/deroproject/derosuite/address" 24 import "github.com/deroproject/derosuite/transaction" 25 import "github.com/deroproject/derosuite/crypto/ringct" 26 //import "github.com/deroproject/derosuite/walletapi" // to decode encrypted payment ID 27 28 29 // used to encrypt payment id 30 const ENCRYPTED_PAYMENT_ID_TAIL = 0x8d 31 32 // this function is used to encrypt/decrypt payment id 33 // as the operation is symmetric XOR, is the same in both direction 34 func EncryptDecryptPaymentID(derivation crypto.Key, tx_public crypto.Key, input []byte) (output []byte) { 35 // input must be exactly 8 bytes long 36 if len(input) != 8 { 37 panic("Encrypted payment ID must be exactly 8 bytes long") 38 } 39 40 var tmp_buf [33]byte 41 copy(tmp_buf[:], derivation[:]) // copy derivation key to buffer 42 tmp_buf[32] = ENCRYPTED_PAYMENT_ID_TAIL 43 44 // take hash 45 hash := crypto.Keccak256(tmp_buf[:]) // take hash of entire 33 bytes, 32 bytes derivation key, 1 byte tail 46 47 output = make([]byte, 8, 8) 48 for i := range input { 49 output[i] = input[i] ^ hash[i] // xor the bytes with the hash 50 } 51 52 return 53 } 54 55 // this function will prove detect and decode output amount for the tx 56 func Prove(input_key string, input_addr string, input_tx string) (indexes []uint64, amounts []uint64, payids [][]byte, err error) { 57 var tx_secret_key crypto.Key 58 var tx transaction.Transaction 59 60 if len(input_key) != 64 { 61 err = fmt.Errorf("Invalid input key size") 62 return 63 } 64 65 tx_secret_key_raw, err := hex.DecodeString(input_key) 66 if err != nil { 67 return 68 } 69 copy(tx_secret_key[:], tx_secret_key_raw[:32]) 70 71 addr, err := address.NewAddress(input_addr) 72 if err != nil { 73 return 74 } 75 76 tx_hex, err := hex.DecodeString(input_tx) 77 if err != nil { 78 return 79 } 80 81 err = tx.DeserializeHeader(tx_hex) 82 if err != nil { 83 return 84 } 85 86 // okay all inputs have been parsed 87 88 switch tx.RctSignature.Get_Sig_Type() { 89 case 0: // miner tx, for miner tx we can only prove that the output belongs to address, TODO 90 //fmt.Printf("TX is coinbase and does NOT have encrypted OUTPUTS\n") 91 err = fmt.Errorf("TX is coinbase and does NOT have encrypted OUTPUTS") 92 return 93 94 } 95 96 var PayID8 []byte 97 98 if tx.Parse_Extra() { 99 // will decrypt payment ID if encrypted 100 if _, ok := tx.PaymentID_map[transaction.TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID]; ok { 101 PayID8 = tx.PaymentID_map[transaction.TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID].([]byte) 102 } 103 104 } 105 106 // ringct full/simple tx come here 107 derivation := crypto.KeyDerivation(&addr.ViewKey, &tx_secret_key) // keyderivation using output address 108 found := false 109 110 // Vout can be only specific type rest all make th fail case 111 for i := 0; i < len(tx.Vout); i++ { 112 index_within_tx := i 113 114 ehphermal_public_key := derivation.KeyDerivation_To_PublicKey(uint64(index_within_tx), addr.SpendKey) 115 116 if ehphermal_public_key == tx.Vout[i].Target.(transaction.Txout_to_key).Key { 117 found = true 118 //fmt.Printf("Output at index %d belongs to %s\n",i,addr.String()) 119 indexes = append(indexes, uint64(index_within_tx)) 120 121 // we must decode output amounts also 122 scalar_key := *(derivation.KeyDerivationToScalar(uint64(index_within_tx))) 123 124 mask := tx.RctSignature.OutPk[i].Mask 125 126 ECDHTuple := tx.RctSignature.ECdhInfo[i] 127 128 amount, _, result := ringct.Decode_Amount(ECDHTuple, scalar_key, mask) 129 if result { 130 // fmt.Printf("Amount is ~ %0.8f\n", float64(amount)/(1000000000000.0)) 131 amounts = append(amounts, amount) 132 133 134 if len(PayID8) == 8 { 135 decrypted_pay_id := EncryptDecryptPaymentID(derivation,scalar_key,PayID8) 136 payids = append(payids,decrypted_pay_id) 137 } 138 139 }else{ 140 err = fmt.Errorf("TX belongs to user but amount could NOT be decoded") 141 return 142 } 143 144 } 145 146 } 147 148 _ = found 149 /*if found { 150 fmt.Printf("Found outputs\n") 151 }else{ 152 fmt.Printf("Outputs do not belong to this address\n") 153 }*/ 154 155 if !found{ 156 err = fmt.Errorf("Wrong TX Key or wrong address or Outputs do not belong to this address") 157 158 } 159 160 return 161 162 }