github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/types/unlockhash.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  
     8  	"github.com/NebulousLabs/Sia/crypto"
     9  )
    10  
    11  // unlockhash.go contains the unlockhash alias along with usability methods
    12  // such as String and an implementation of sort.Interface.
    13  
    14  const (
    15  	// UnlockHashChecksumSize is the size of the checksum used to verify
    16  	// human-readable addresses. It is not a crypytographically secure
    17  	// checksum, it's merely intended to prevent typos. 6 is chosen because it
    18  	// brings the total size of the address to 38 bytes, leaving 2 bytes for
    19  	// potential version additions in the future.
    20  	UnlockHashChecksumSize = 6
    21  )
    22  
    23  // An UnlockHash is a specially constructed hash of the UnlockConditions type.
    24  // "Locked" values can be unlocked by providing the UnlockConditions that hash
    25  // to a given UnlockHash. See SpendConditions.UnlockHash for details on how the
    26  // UnlockHash is constructed.
    27  type UnlockHash crypto.Hash
    28  
    29  type UnlockHashSlice []UnlockHash
    30  
    31  // MarshalJSON is implemented on the unlock hash to always produce a hex string
    32  // upon marshalling.
    33  func (uh UnlockHash) MarshalJSON() ([]byte, error) {
    34  	return json.Marshal(uh.String())
    35  }
    36  
    37  // UnmarshalJSON is implemented on the unlock hash to recover an unlock hash
    38  // that has been encoded to a hex string.
    39  func (uh *UnlockHash) UnmarshalJSON(b []byte) error {
    40  	// Check the length of b.
    41  	if len(b) != crypto.HashSize*2+UnlockHashChecksumSize*2+2 && len(b) != crypto.HashSize*2+2 {
    42  		return ErrUnlockHashWrongLen
    43  	}
    44  	return uh.LoadString(string(b[1 : len(b)-1]))
    45  }
    46  
    47  // String returns the hex representation of the unlock hash as a string - this
    48  // includes a checksum.
    49  func (uh UnlockHash) String() string {
    50  	uhChecksum := crypto.HashObject(uh)
    51  	return fmt.Sprintf("%x%x", uh[:], uhChecksum[:UnlockHashChecksumSize])
    52  }
    53  
    54  // LoadString loads a hex representation (including checksum) of an unlock hash
    55  // into an unlock hash object. An error is returned if the string is invalid or
    56  // fails the checksum.
    57  func (uh *UnlockHash) LoadString(strUH string) error {
    58  	// Check the length of strUH.
    59  	if len(strUH) != crypto.HashSize*2+UnlockHashChecksumSize*2 && len(strUH) != crypto.HashSize*2 {
    60  		return ErrUnlockHashWrongLen
    61  	}
    62  
    63  	// Decode the unlock hash.
    64  	var byteUnlockHash []byte
    65  	var checksum []byte
    66  	_, err := fmt.Sscanf(strUH[:crypto.HashSize*2], "%x", &byteUnlockHash)
    67  	if err != nil {
    68  		return err
    69  	}
    70  	// Decode the checksum, if provided.
    71  	if len(strUH) == crypto.HashSize*2+UnlockHashChecksumSize*2 {
    72  		_, err = fmt.Sscanf(strUH[crypto.HashSize*2:], "%x", &checksum)
    73  		if err != nil {
    74  			return err
    75  		}
    76  
    77  		// Verify the checksum - leave uh as-is unless the checksum is valid.
    78  		expectedChecksum := crypto.HashBytes(byteUnlockHash)
    79  		if !bytes.Equal(expectedChecksum[:UnlockHashChecksumSize], checksum) {
    80  			return ErrInvalidUnlockHashChecksum
    81  		}
    82  	}
    83  	copy(uh[:], byteUnlockHash[:])
    84  
    85  	return nil
    86  }
    87  
    88  // Len implements the Len method of sort.Interface.
    89  func (uhs UnlockHashSlice) Len() int {
    90  	return len(uhs)
    91  }
    92  
    93  // Less implements the Less method of sort.Interface.
    94  func (uhs UnlockHashSlice) Less(i, j int) bool {
    95  	return bytes.Compare(uhs[i][:], uhs[j][:]) < 0
    96  }
    97  
    98  // Swap implements the Swap method of sort.Interface.
    99  func (uhs UnlockHashSlice) Swap(i, j int) {
   100  	uhs[i], uhs[j] = uhs[j], uhs[i]
   101  }