github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/address/address.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 address 18 19 import "fmt" 20 import "bytes" 21 import "encoding/binary" 22 23 import "github.com/deroproject/derosuite/config" 24 import "github.com/deroproject/derosuite/crypto" 25 26 // see https://cryptonote.org/cns/cns007.txt to understand address more 27 28 type Address struct { 29 Network uint64 30 SpendKey crypto.Key // these are public keys only 31 ViewKey crypto.Key // these are public keys only 32 PaymentID []byte //integrated payment id is 8 bytes 33 // 8 byte version is encrypted on the blockchain 34 // 32 byte version is dumped on the chain openly 35 } 36 37 const ChecksumLength = 4 38 39 type Checksum [ChecksumLength]byte 40 41 func GetChecksum(data ...[]byte) (result Checksum) { 42 keccak256 := crypto.Keccak256(data...) 43 copy(result[:], keccak256[:4]) 44 return 45 } 46 47 func (a *Address) Base58() (result string) { 48 prefix := make([]byte, 9, 9) 49 50 n := binary.PutUvarint(prefix, a.Network) 51 prefix = prefix[:n] 52 53 // convert address to string ( include payment ID if prefix says so ) 54 switch a.Network { 55 56 case 19: 57 fallthrough // for testing purpose monero integrated address 58 case config.Mainnet.Public_Address_Prefix_Integrated: 59 fallthrough 60 case config.Testnet.Public_Address_Prefix_Integrated: 61 checksum := GetChecksum(prefix, a.SpendKey[:], a.ViewKey[:], a.PaymentID) 62 result = EncodeDeroBase58(prefix, a.SpendKey[:], a.ViewKey[:], a.PaymentID, checksum[:]) 63 64 // normal addresses without prefix 65 case config.Mainnet.Public_Address_Prefix: 66 fallthrough 67 case config.Testnet.Public_Address_Prefix: 68 fallthrough 69 default: 70 checksum := GetChecksum(prefix, a.SpendKey[:], a.ViewKey[:]) 71 result = EncodeDeroBase58(prefix, a.SpendKey[:], a.ViewKey[:], checksum[:]) 72 } 73 74 return 75 } 76 77 // stringifier 78 func (a Address) String() string { 79 return a.Base58() 80 } 81 82 // tells whether address is mainnet address 83 func (a *Address) IsMainnet() bool { 84 if a.Network == config.Mainnet.Public_Address_Prefix || 85 a.Network == config.Mainnet.Public_Address_Prefix_Integrated { 86 return true 87 } 88 return false 89 } 90 91 // tells whether address is mainnet address 92 func (a *Address) IsIntegratedAddress() bool { 93 if a.Network == config.Testnet.Public_Address_Prefix_Integrated || 94 a.Network == config.Mainnet.Public_Address_Prefix_Integrated { 95 return true 96 } 97 return false 98 } 99 100 // tells whether address belongs to DERO Network 101 func (a *Address) IsDERONetwork() bool { 102 if a.Network == config.Mainnet.Public_Address_Prefix || 103 a.Network == config.Mainnet.Public_Address_Prefix_Integrated || 104 a.Network == config.Testnet.Public_Address_Prefix || 105 a.Network == config.Testnet.Public_Address_Prefix_Integrated { 106 return true 107 } 108 return false 109 } 110 111 func NewAddress(address string) (result *Address, err error) { 112 raw := DecodeDeroBase58(address) 113 114 // donot compare length to support much more user base and be compatible with cryptonote 115 if len(raw) < 69 { // 1 byte prefix + 32 byte key + 32 byte key + 4 byte checksum 116 err = fmt.Errorf("Address is not complete") 117 return 118 } 119 checksum := GetChecksum(raw[:len(raw)-4]) 120 if bytes.Compare(checksum[:], raw[len(raw)-4:]) != 0 { 121 err = fmt.Errorf("Checksum failed") 122 return 123 } 124 raw = raw[0 : len(raw)-4] // remove the checksum 125 126 // parse network first 127 address_prefix, done := binary.Uvarint(raw) 128 if done <= 0 { 129 err = fmt.Errorf("Network could not be parsed in address\n") 130 return 131 } 132 133 raw = raw[done:] 134 135 result = &Address{ 136 Network: address_prefix, 137 //SpendKey: raw[0:32], 138 //ViewKey: raw[32:64], 139 } 140 copy(result.SpendKey[:], raw[0:32]) 141 copy(result.ViewKey[:], raw[32:64]) 142 143 // 144 switch address_prefix { // if network id is integrated address 145 case 19: 146 fallthrough //Monero_MainNetwork_Integrated: for testing purposes only for compatible reasons 147 case config.Mainnet.Public_Address_Prefix_Integrated: 148 fallthrough // DERO mainnet integrated address 149 case config.Testnet.Public_Address_Prefix_Integrated: // DERO testnet integrated address 150 if len(raw[64:]) == 8 { // 8 byte encrypted payment id + 4 bytes 151 result.PaymentID = raw[64:] 152 } else if len(raw[64:]) == 32 { // 32 byte unencrypted payment ID 153 result.PaymentID = raw[64:] 154 } else { 155 err = fmt.Errorf("Invalid payment ID in address\n") 156 return 157 } 158 } 159 160 return 161 } 162 163 // create a new address from keys 164 func NewAddressFromKeys(spendkey, viewkey crypto.Key) (result *Address) { 165 result = &Address{ 166 Network: config.Mainnet.Public_Address_Prefix, 167 SpendKey: spendkey, 168 ViewKey: viewkey, 169 } 170 return 171 }