github.com/cosmos/cosmos-sdk@v0.50.10/types/address/hash.go (about) 1 package address 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "fmt" 7 "sort" 8 9 "github.com/cometbft/cometbft/crypto" 10 11 "cosmossdk.io/errors" 12 13 "github.com/cosmos/cosmos-sdk/internal/conv" 14 ) 15 16 // Len is the length of base addresses 17 const Len = sha256.Size 18 19 // Addressable represents any type from which we can derive an address. 20 type Addressable interface { 21 Address() []byte 22 } 23 24 // Hash creates a new address from address type and key. 25 // The functions should only be used by new types defining their own address function 26 // (eg public keys). 27 func Hash(typ string, key []byte) []byte { 28 hasher := sha256.New() 29 _, err := hasher.Write(conv.UnsafeStrToBytes(typ)) 30 // the error always nil, it's here only to satisfy the io.Writer interface 31 errors.AssertNil(err) 32 th := hasher.Sum(nil) 33 34 hasher.Reset() 35 _, err = hasher.Write(th) 36 errors.AssertNil(err) 37 _, err = hasher.Write(key) 38 errors.AssertNil(err) 39 return hasher.Sum(nil) 40 } 41 42 // Compose creates a new address based on sub addresses. 43 func Compose(typ string, subAddresses []Addressable) ([]byte, error) { 44 as := make([][]byte, len(subAddresses)) 45 totalLen := 0 46 var err error 47 for i := range subAddresses { 48 a := subAddresses[i].Address() 49 as[i], err = LengthPrefix(a) 50 if err != nil { 51 return nil, fmt.Errorf("not compatible sub-adddress=%v at index=%d [%w]", a, i, err) 52 } 53 totalLen += len(as[i]) 54 } 55 56 sort.Slice(as, func(i, j int) bool { return bytes.Compare(as[i], as[j]) <= 0 }) 57 key := make([]byte, totalLen) 58 offset := 0 59 for i := range as { 60 copy(key[offset:], as[i]) 61 offset += len(as[i]) 62 } 63 return Hash(typ, key), nil 64 } 65 66 // Module is a specialized version of a composed address for modules. Each module account 67 // is constructed from a module name and a sequence of derivation keys (at least one 68 // derivation key must be provided). The derivation keys must be unique 69 // in the module scope, and is usually constructed from some object id. Example, let's 70 // a x/dao module, and a new DAO object, it's address would be: 71 // 72 // address.Module(dao.ModuleName, newDAO.ID) 73 func Module(moduleName string, derivationKeys ...[]byte) []byte { 74 mKey := []byte(moduleName) 75 if len(derivationKeys) == 0 { // fallback to the "traditional" ModuleAddress 76 return crypto.AddressHash(mKey) 77 } 78 // need to append zero byte to avoid potential clash between the module name and the first 79 // derivation key 80 mKey = append(mKey, 0) 81 addr := Hash("module", append(mKey, derivationKeys[0]...)) 82 for _, k := range derivationKeys[1:] { 83 addr = Derive(addr, k) 84 } 85 return addr 86 } 87 88 // Derive derives a new address from the main `address` and a derivation `key`. 89 // This function is used to create a sub accounts. To create a module accounts use the 90 // `Module` function. 91 func Derive(address, key []byte) []byte { 92 return Hash(conv.UnsafeBytesToStr(address), key) 93 }