github.com/Finschia/finschia-sdk@v0.48.1/types/address/hash.go (about)

     1  package address
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"fmt"
     7  	"sort"
     8  
     9  	"github.com/Finschia/finschia-sdk/internal/conv"
    10  	"github.com/Finschia/finschia-sdk/types/errors"
    11  )
    12  
    13  // Len is the length of base addresses
    14  const Len = sha256.Size
    15  
    16  // Addressable represents any type from which we can derive an address.
    17  type Addressable interface {
    18  	Address() []byte
    19  }
    20  
    21  // Hash creates a new address from address type and key
    22  func Hash(typ string, key []byte) []byte {
    23  	hasher := sha256.New()
    24  	_, err := hasher.Write(conv.UnsafeStrToBytes(typ))
    25  	// the error always nil, it's here only to satisfy the io.Writer interface
    26  	errors.AssertNil(err)
    27  	th := hasher.Sum(nil)
    28  
    29  	hasher.Reset()
    30  	_, err = hasher.Write(th)
    31  	errors.AssertNil(err)
    32  	_, err = hasher.Write(key)
    33  	errors.AssertNil(err)
    34  	return hasher.Sum(nil)
    35  }
    36  
    37  // Compose creates a new address based on sub addresses.
    38  func Compose(typ string, subAddresses []Addressable) ([]byte, error) {
    39  	as := make([][]byte, len(subAddresses))
    40  	totalLen := 0
    41  	var err error
    42  	for i := range subAddresses {
    43  		a := subAddresses[i].Address()
    44  		as[i], err = LengthPrefix(a)
    45  		if err != nil {
    46  			return nil, fmt.Errorf("not compatible sub-adddress=%v at index=%d [%w]", a, i, err)
    47  		}
    48  		totalLen += len(as[i])
    49  	}
    50  
    51  	sort.Slice(as, func(i, j int) bool { return bytes.Compare(as[i], as[j]) <= 0 })
    52  	key := make([]byte, totalLen)
    53  	offset := 0
    54  	for i := range as {
    55  		copy(key[offset:], as[i])
    56  		offset += len(as[i])
    57  	}
    58  	return Hash(typ, key), nil
    59  }
    60  
    61  // Module is a specialized version of a composed address for modules. Each module account
    62  // is constructed from a module name and module account key.
    63  func Module(moduleName string, key []byte) []byte {
    64  	mKey := append([]byte(moduleName), 0)
    65  	return Hash("module", append(mKey, key...))
    66  }
    67  
    68  // Derive derives a new address from the main `address` and a derivation `key`.
    69  func Derive(address []byte, key []byte) []byte {
    70  	return Hash(conv.UnsafeBytesToStr(address), key)
    71  }