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  }