Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finalize ADR-028 #8398

Merged
merged 32 commits into from
Feb 4, 2021
Merged
Changes from 16 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7b8173b
Finalize ADR-028
robert-zaremba Jan 20, 2021
8643cae
Merge branch 'master' into robert/adr-28
robert-zaremba Jan 20, 2021
6038410
added note about Named Accounts
robert-zaremba Jan 20, 2021
aecb45b
Update docs/architecture/adr-028-public-key-addresses.md
Jan 20, 2021
9a4e078
add reference to \#8041
robert-zaremba Jan 20, 2021
bbfb1b7
typo fix
robert-zaremba Jan 20, 2021
8129844
Apply suggestions from code review
robert-zaremba Jan 21, 2021
2724c7b
simplification, review updates
robert-zaremba Jan 22, 2021
8c44486
date update
robert-zaremba Jan 22, 2021
1557ef5
update paragraph about proto.MessageName
robert-zaremba Jan 22, 2021
aaf471b
remove the module name section - it's described in other section
robert-zaremba Jan 22, 2021
c230c68
Update docs/architecture/adr-028-public-key-addresses.md
robert-zaremba Jan 22, 2021
9b21ec5
remove blake2b
robert-zaremba Jan 27, 2021
9550d11
move some paragraphs to 'Further Discussion'
robert-zaremba Jan 27, 2021
c0a9b20
renames
robert-zaremba Jan 27, 2021
84f57b8
revert and merge 'Multisig Addresses' section
robert-zaremba Jan 27, 2021
c8fa6cb
Apply suggestions from code review
robert-zaremba Jan 29, 2021
3d29aff
Merge branch 'master' into robert/adr-28
robert-zaremba Jan 29, 2021
e407672
add LengthPrefix to Compose definition
robert-zaremba Jan 29, 2021
889b9c5
Merge branch 'master' into robert/adr-28
Jan 29, 2021
ab4b9d1
move composing module accounts to a new subsectoin
robert-zaremba Jan 30, 2021
834d997
adding appendix from meeting with Alan
robert-zaremba Jan 31, 2021
3ceb0f2
composed addresses: use LengthPrefix before sorting
robert-zaremba Feb 1, 2021
274efce
Update docs/architecture/adr-028-public-key-addresses.md
robert-zaremba Feb 1, 2021
461c703
Update docs/architecture/adr-028-public-key-addresses.md
robert-zaremba Feb 1, 2021
201a19e
adding special case for Module Account Addresses
robert-zaremba Feb 1, 2021
5093022
limit 'account' word usage
robert-zaremba Feb 1, 2021
6fb8701
describe submodule derivation
robert-zaremba Feb 2, 2021
eb23aa6
Add discussion notes for the module addresses + bring back 'account' …
robert-zaremba Feb 3, 2021
963b093
Apply suggestions from code review
robert-zaremba Feb 3, 2021
c79c796
changing back to proposed
robert-zaremba Feb 3, 2021
eae740c
Merge branch 'master' into robert/adr-28
robert-zaremba Feb 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 152 additions & 79 deletions docs/architecture/adr-028-public-key-addresses.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,90 @@
## Changelog

- 2020/08/18: Initial version
- 2021/01/15: Analysis and algorithm update

## Status

Proposed
LAST CALL 2021-01-22

## Abstract

This ADR defines a canonical 20-byte address format for new public key algorithms, multisig public keys, and module
accounts using string prefixes.
This ADR defines an address format for all addressable SDK accounts. That includes: new public key algorithms, multisig public keys, and module
accounts.

## Context

Issue [\#3685](https://github.com/cosmos/cosmos-sdk/issues/3685) identified that public key
address spaces are currently overlapping. One initial proposal was extending the address length and
adding prefixes for different types of addresses.
address spaces are currently overlapping. We confirmed that it significantly decreases security of Cosmos SDK.


### Problem

An attacker can control an input for an address generation function. This leads to a birthday attack, which significantly decreases the security space.
To overcome this, we need to separate the inputs for different kind of account types:
a security break of one account type shouldn't impact the security of other account type.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved


### Initial proposals

One initial proposal was extending the address length and
adding prefixes for different types of addresses.

@ethanfrey explained an alternate approach originally used in https://github.com/iov-one/weave:

> I spent quite a bit of time thinking about this issue while building weave... The other cosmos Sdk.

> Basically I define a condition to be a type and format as human readable string with some binary data appended. This condition is hashed into an Address (again at 20 bytes). The use of this prefix makes it impossible to find a preimage for a given address with a different condition (eg ed25519 vs secp256k1).

> This is explained in depth here https://weave.readthedocs.io/en/latest/design/permissions.html

> And the code is here, look mainly at the top where we process conditions. https://github.com/iov-one/weave/blob/master/conditions.go

And explained how this approach should be sufficiently collision resistant:
> Yeah, AFAIK, 20 bytes should be collision resistance when the preimages are unique and not malleable. A space of 2^160 would expect some collision to be likely around 2^80 elements (birthday paradox). And if you want to find a collision for some existing element in the database, it is still 2^160. 2^80 only is if all these elements are written to state.

> Yeah, AFAIK, 20 bytes should be collision resistance when the preimages are unique and not malleable. A space of 2^160 would expect some collision to be likely around 2^80 elements (birthday paradox). And if you want to find a collision for some existing element in the database, it is still 2^160. 2^80 only is if all these elements are written to state.
> The good example you brought up was eg. a public key bytes being a valid public key on two algorithms supported by the codec. Meaning if either was broken, you would break accounts even if they were secured with the safer variant. This is only as the issue when no differentiating type info is present in the preimage (before hashing into an address).

> I would like to hear an argument if the 20 bytes space is an actual issue for security, as I would be happy to increase my address sizes in weave. I just figured cosmos and ethereum and bitcoin all use 20 bytes, it should be good enough. And the arguments above which made me feel it was secure. But I have not done a deeper analysis.

In discussions in [\#5694](https://github.com/cosmos/cosmos-sdk/issues/5694), we agreed to go with an
approach similar to this where essentially we take the first 20 bytes of the `sha256` hash of
the key type concatenated with the key bytes, summarized as `Sha256(KeyTypePrefix || Keybytes)[:20]`.
This lead to the first proposal (which we proved to be not good enough):
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
we concatenate a key type with a public key, hash it and take the first 20 bytes of that hash, summarized as `sha256(keyTypePrefix || keybytes)[:20]`.


### Review and Discussions

In [\#5694](https://github.com/cosmos/cosmos-sdk/issues/5694) we discussed various solutions.
We agreed that 20 bytes it's not future proof, and extending the address length is the only way to allow addresses of different types, various signature types, etc.
This disqualifies the initial proposal.

In the issue we discussed various modifications:
+ Choice of the hash function.
+ Move the prefix out of the hash function: `keyTypePrefix + sha256(keybytes)[:20]` [post-hash-prefix-proposal].
+ Use double hashing: `sha256(keyTypePrefix + sha256(keybytes)[:20])`.
+ Increase to keybytes hash slice from 20 byte to 32 or 40 bytes. We concluded that 32 bytes, produced by a good hash functions is future secure.

### Requirements

+ Support currently used tools - we don't want to break an ecosystem, or add a long adaptation period. Ref: https://github.com/cosmos/cosmos-sdk/issues/8041
+ Try to keep the address length small - addresses are widely used in state, both as part of a key and object value.


### Scope

This ADR only defines a process for the generation of address bytes. For end-user interactions with addresses (through the API, or CLI, etc.), we still use bech32 to format these addresses as strings. This ADR doesn't change that.
Using bech32 for string encoding gives us support for checsum error codes and handling of user typos.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved


## Decision

We define the following account types, for which we define the address function:

1. simple accounts: represented by a regular public key (ie: secp256k1, sr25519)
2. naive multisig: accounts composed by other addressable objects (ie: naive multisig)
3. composed accounts with a native address key (ie: bls, group module accounts)
4. module accounts: basically any accounts which cannot sign transactions and which are managed internally by modules


### Legacy Public Key Addresses Don't Change

`secp256k1` and multisig public keys are currently in use in existing Cosmos SDK zones. They use the following
address formats:
Currently (Jan 2021), the only officially supported SDK user accounts are `secp256k1` basic accounts and legacy amino multisig.
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
They are used in existing Cosmos SDK zones. They use the following address formats:

- secp256k1: `ripemd160(sha256(pk_bytes))[:20]`
- legacy amino multisig: `sha256(aminoCdc.Marshal(pk))[:20]`
Expand All @@ -56,113 +97,145 @@ The current multisig public keys use amino serialization to generate the address
those public keys and their address formatting, and call them "legacy amino" multisig public keys
in protobuf. We will also create multisig public keys without amino addresses to be described below.

### Hash Function Choice

### Canonical Address Format
As in other parts of the Cosmos SDK, we will use `sha256`.

We have three types of accounts we would like to create addresses for in the future:
- regular public key addresses for new signature algorithms (ex. `sr25519`).
- public key addresses for multisig public keys that don't use amino encoding
- module accounts: basically any accounts which cannot sign transactions and
which are managed internally by modules
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
### Simple Account Address

To address all of these use cases we propose the following basic `AddressHash` function,
based on the discussions in [\#5694](https://github.com/cosmos/cosmos-sdk/issues/5694):
We start with defining a hash base algorithm for generating addresses. Notably, it's used for accounts represented by a single key pair. For each public key schema we have to have an associated `typ` string, which we are discussing in a section below. `hash` is a cryptographic hash function defined in the previous section.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

```go
func AddressHash(prefix string, contents []byte) []byte {
preImage := []byte(prefix)
if len(contents) != 0 {
preImage = append(preImage, 0)
preImage = append(preImage, contents...)
}
return sha256.Sum256(preImage)[:20]
const A_LEN = 32
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved

func Hash(typ string, key []byte) []byte {
return hash(hash(typ) + key)[:A_LEN]
}
```

`AddressHash` always take a string `prefix` as a starting point which should represent the
type of public key (ex. `sr25519`) or module account being used (ex. `staking` or `group`).
For public keys, the `contents` parameter is used to specify the binary contents of the public
key. For module accounts, `contents` can be left empty (for modules which don't manage "sub-accounts"),
or can be some module-specific content to specify different pools (ex. `bonded` or `not-bonded` for `staking`)
or managed accounts (ex. different accounts managed by the `group` module).
The `+` is a bytes concatenation, which doesn't use any separator.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

In the `preImage`, the byte value `0` is used as the separator between `prefix` and `contents`. This is a logical
choice given that `0` is an invalid value for a string character and is commonly used as a null terminator.
This algorithm is an outcome from a consulting session with a cryptographer.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
Motivation: this algorithm keeps the address relatively small (length of the `typ` doesn't impact on the length of the final address)
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
and it's more secure than [post-hash-prefix-proposal] (which uses first 20 bytes of a pubkey hash, that significantly reduce the address space).
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
Moreover the cryptographer motivated the choice to add `typ` in the hash to protect against switch table attack.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

### Canonical Public Key Address Prefixes
We use `address.Hash` function for generating address for all accounts represented by a single key:
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
* simple public keys: `address.Hash(keyType, pubkey)`
+ aggregated keys (eg: BLS): `address.Hash(keyType, aggregatedPubKey)`
+ module accounts: `addoress.Hash("module", moduleID)`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
+ module accounts: `addoress.Hash("module", moduleID)`
+ module accounts: `address.Hash(moduleName, nil)`

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why you want to have a moduleName as a type? I think it make more sense to put is a key.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason, why I think it makes more sense to put a variable moduleName / moduleID as a key argument is the design intuition:

  • type (the first argument) is a schema description (eg: ed25519, schnorr2of4, ....).
  • key (the last argument) is a random sequence.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here you're trying to hedge against the possibility of the module name as the schema description causing weird side effects?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moduleName is not a schema type - so passing it as a first argument there doesn't match our definition.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it is sort of a schema type in that all of the group addresses or cosmwasm addresses define their own sub-address format.

Are there any pros/cons from a security perspective of address.Hash(moduleName, moduleSubKey) vs address.Hash("module", moduleName + moduleSubKey)?

address.Hash(moduleName, moduleSubKey) was the original design and still makes sense to me for simplicity's sake...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue would be if a user is in control of moduleName. He is not - only an app developer is.
So we need to be careful to not have a moduleName same as any scheme name (eg: ed25519).
I don't see any security concern for address.Hash("module", moduleName + moduleSubKey) except the weird conflicts on concatenation (same as in multisig example) - which is solveable with length prefixing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes... So what about address.Hash("module:" + moduleName, moduleSubKey)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we need to be careful to not have a moduleName same as any scheme name (eg: ed25519).

Insecure modules (either explicit or negligent) is a much larger independent discussion. Objectively I don't see the value in the "module" prefix given the context here (module name + module provided sub-keys as components of the address, sourced from the module).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a new section for module sub-accounts.

For module subaccount, or module specific content we append a specific key to the moduleKey:
`address.Hash("module", moduleSubaccountKey)` (note: `moduleSubaccountKey` already composes the `modleKey`).
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
All public key types will have a unique protobuf message type such as:

```proto
package cosmos.crypto.sr25519;
### Composed Account Addresses
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this section and consider reverting to the previous multisig format. As we discussed live generalizing multisig keys to composed addresses is a nice idea but doesn't work because there are too many specifics like threshold which isn't here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted and merged the Multisig Addresses section here. My motivation here is to show a generic function to compose pubkeys, and use multisig as an example. I think it's better to make this abstraction, rather than re-implement it in other account types.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well even so, I don't think this is actually correct, the concatenated addresses each need to be length prefixed because they can be variable length. But otherwise, maybe it works...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's why we use .Address() function for all sub addresses - it will have the required logic. Compose is a one way function, there is nothing to decode.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe my comment wasn't clear but we need to length prefix before concatenation because otherwise the boundary between addresses isn't clear

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me give more context. The motivation to have this section is to:

  1. Show that we are not in the dead end and we have positive consequences of address composability (as outlined in the consequences section)
  2. we have algorithm for that
  3. new multisig is just an example, but the main topic is composition.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's okay, I'm not there's another use case but it looks okay.

This is what I was trying to say: https://github.com/cosmos/cosmos-sdk/pull/8398/files#r566337924

robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

message PubKey {
bytes key = 1;
For simple composed accounts (like new naive multisig), we generalize the `address.Hash`. The address is constructed by recursively creating addresses for the sub accounts, sorting the addresses and composing it into a single address. It ensures that the ordering of keys doesn't impact the created address.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

```go
// We don't need a PubKey interface - we need anything which is addressable.
type Addressable interface {
Address() []byte
}

func Composed(typ string, subaccounts []Addressable) []byte {
addresses = map(subaccounts, \a -> a.Address())
addresses = sort(addresses)
return address.Hash(typ, addresses[0] + ... + addresses[n])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return address.Hash(typ, addresses[0] + ... + addresses[n])
return address.Hash(typ, LengthPrefixAddress(addresses[0]) + ... + LengthPrefixAddress(addresses[n]))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without length prefixing each address here you don't know the boundary. The addresses could be 20 or 32 bytes or some other number of users choose. So you can't successfully compose without that. Otherwise, there could be some weird collisions however unlikely.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Composed is a one-way function - once hashed, we can't go back. We don't need to know boundaries - finding a collision with length prefixing is as hard as finding a collision without them. We can map LengthPrefixAddress to all sub addresses, but I don't see any justification for that. Meaning it obfuscates the code but it doesn't enhance the security.

Copy link
Collaborator Author

@robert-zaremba robert-zaremba Jan 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Practically speaking, the only way we could get a collision is when we have two sequences of addresses which concatenate to the same string:

as, bs [][]byte <- list of addresses

So, the question is not about the hash collision, but key construction. Specifically: is it harder to find 2 different list of addresses (as != bs) for having a match in A or in B?

A:  as[0]+as[1]+...+as[n] =? bs[0]+bs[1]+...+bs[m]
B:  lenpref(as[0])+lenpref(as[1])+...+lenpref(as[n]) =? lenpref(bs[0])+lenpref(bs[1])+...+lenpref(bs[m])

so, lets think...

Copy link
Collaborator Author

@robert-zaremba robert-zaremba Jan 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each problem can be solved by a construction: we map and concatenate. Then for constructing bs we try to slice the concatenate sequence just before some 1 bits.
Specifically, for problem B, here is an example of conflicting addresses in binary form:

as = {0101, 1000, 1}
bs = {00, 101000 11}
map(lenpref, as) = {10 0  100,  10 1000, 11  }
map(lenpref, as) = {10 0, 100   10 1000  11 }

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking more about it. Since the length prefix is always 1 byte, then we can't construct conflicting address sequences unless the individual addresses are the same - so the lenpref in this case will work.
Other solution I had in mind was to hash each subaddress before concatenation - this way all parts have exactly same length.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the collision risk may be small but length-prefixing is cheap and ensures zero collisions in the pre-image.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aaronc , yes, in OP, when you wrote about collision I thought you are writing about hash collision ;) In the (updated) text I use conflict instead of collision.

}
```

All protobuf messages have unique fully qualified names, in this example `cosmos.crypto.sr25519.PubKey`.
These names are derived directly from .proto files in a standardized way and used
in other places such as the type URL in `Any`s. Since there is an easy and obvious
way to get this name for every protobuf type, we can use this message name as the
key type `prefix` when creating addresses. For all basic public keys, `contents`
should just be the raw unencoded public key bytes.

Thus the canonical address for new public key types would be `AddressHash(proto.MessageName(pk), pk.Bytes)`.
The `typ` parameter should contain all significant attributes with deterministic serialization.
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved

### Multisig Addresses
Implementation Tip: account implementations should cache address in their structure.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

For new multisig public keys, we define a custom address format not based on any encoding scheme
(amino or protobuf). This avoids issues with non-determinism in the encoding scheme. It also
ensures that multisig public keys which differ simply in the ordering of keys have the same
address by sorting child public keys first.

First we define a proto message for multisig public keys:
#### Multisig Addresses

For new multisig public keys, we define the `typ` parameter not based on any encoding scheme (amino or protobuf). This avoids issues with non-determinism in the encoding scheme.

Example:

```proto
package cosmos.crypto.multisig;

message PubKey {
uint32 threshold = 1;
repeated google.protobuf.Any public_keys = 2;
repeated google.protobuf.Any pubkeys = 2;
}
```

We define the following `Address()` function for this public key:

```
```go
func (multisig PubKey) Address() {
// first gather all the addresses of each nested public key
var addresses [][]byte
for key := range multisig.Keys {
addresses = append(joinedAddresses, key.Address())
// first gather all nested pub keys
var keys []address.Addressable // cryptotypes.PubKey implements Addressable
for _, _key := range multisig.Pubkeys {
keys = append(keys, key.GetCachedValue().(cryptotypes.PubKey))
}

// then sort them in ascending order
addresses = Sort(addresses)
// form the type from the message name (cosmos.crypto.multisig.PubKey) and the threshold joined together
prefix := fmt.Sprintf("%s/%d", proto.MessageName(multisig), multisig.Threshold)

// then concatenate them together
var joinedAddresses []byte
for addr := range addresses {
joinedAddresses := append(joinedAddresses, addr...)
}
// use the Composed function defined above
return address.Composed(prefix, keys)
}
```

// form the string prefix from the message name (cosmos.crypto.multisig.PubKey) and the threshold joined together
prefix := fmt.Sprintf("%s/%d", proto.MessageName(multisig), multisig.Threshold)

// use the standard AddressHash function
return AddressHash(prefix, joinedAddresses)
### Account Types

The Account Types used in various account classes SHOULD be unique for each class.
Since both public keys and accounts are serialized in the state, we propose to use the protobuf message name string.

Example: all public key types have a unique protobuf message type similar to:

```proto
package cosmos.crypto.sr25519;

message PubKey {
bytes key = 1;
}
```
```

All protobuf messages have unique fully qualified names, in this example `cosmos.crypto.sr25519.PubKey`.
These names are derived directly from .proto files in a standardized way and used
in other places such as the type URL in `Any`s. We can easily obtain the name using
`proto.MessageName(msg)`.



## Consequences

### Backwards Compatibility

This ADR is compatible to what was committed and directly supported in the SDK repository.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

### Positive
- a simple algorithm for generating addresses for new public keys and module accounts

- a simple algorithm for generating addresses for new public keys, complex accounts and module accounts
- the algorithm generalizes for _native composed keys_
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
- increase security and collision resistance of addresses
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
- the approach is extensible for future use-cases - one can use other address types, as long as they don't conflict with the address length specified here (20 or 32 bytes).
- support multiple types accounts.

### Negative

- addresses do not communicate key type, a prefixed approach would have done this
- addresses are 60% longer and will consume more storage space
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
- requires a refactor of KVStore store keys to handle variable length addresses

### Neutral

- protobuf message names are used as key type prefixes


## Further Discussions

Some accounts can have a fixed name or may be constructed in other way (eg: module accounts). We were discussing an idea of an account with a predefined name (eg: `me.regen`), which could be used by institutions.
Without going into details, this kind of addresses are compatible with the hash based addresses described here as long as they don't have the same length.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
More specifically, any special account address, must not have length equal to 20 byte nor 32 bytes.
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved


## References

* [Notes](https://hackmd.io/_NGWI4xZSbKzj1BkCqyZMw) from consulting meeting with [Alan Szepieniec](https://scholar.google.be/citations?user=4LyZn8oAAAAJ&hl=en).
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved