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

ADR 028: Public Key Addresses #7086

Merged
merged 18 commits into from
Oct 21, 2020
Merged

Conversation

aaronc
Copy link
Member

@aaronc aaronc commented Aug 18, 2020

ref: #5694

This ADR proposes a canonical extensible address format for new public key types, and addresses the multisig pubkey address issue.


Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.

  • Targeted PR against correct branch (see CONTRIBUTING.md)
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the module structure standards.
  • Wrote unit and integration tests
  • Updated relevant documentation (docs/) or specification (x/<module>/spec/)
  • Added relevant godoc comments.
  • Added a relevant changelog entry to the Unreleased section in CHANGELOG.md
  • Re-reviewed Files changed in the Github PR explorer
  • Review Codecov Report in the comment section below once CI passes

@aaronc aaronc marked this pull request as ready for review August 18, 2020 15:04
@codecov
Copy link

codecov bot commented Aug 18, 2020

Codecov Report

Merging #7086 into master will increase coverage by 0.39%.
The diff coverage is n/a.

@@            Coverage Diff             @@
##           master    #7086      +/-   ##
==========================================
+ Coverage   54.21%   54.60%   +0.39%     
==========================================
  Files         611      547      -64     
  Lines       38464    37121    -1343     
==========================================
- Hits        20852    20270     -582     
+ Misses      15503    15192     -311     
+ Partials     2109     1659     -450     

@aaronc aaronc added the T: ADR An issue or PR relating to an architectural decision record label Aug 18, 2020
Copy link
Contributor

@ethanfrey ethanfrey left a comment

Choose a reason for hiding this comment

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

Sounds good

@clevinson
Copy link
Contributor

clevinson commented Aug 25, 2020

The proposal here looks good to me, in terms of the specification for new addresses. However, I'm a bit confused how this actually relates to existing address formats, and I think the wording around that could be clarified.

If i understand correctly, this means that legacy account addresses would be unchanged and remain in their bech32 prefixed form, but accounts generated with non secp256k1 pubkeys would use the new format (no prefix, just a hash as described above)?

How does one distinguish between a "legacy" or "new" multisig? Is this about addresses that exist onchain on a current zone, vs ones that do not? Or about what pubkey type the multisig address is comprised of (where secp256k1 is deemed "legacy"). How does that then relate to multisig with keys of multiple types?

Copy link
Contributor

@amaury1093 amaury1093 left a comment

Choose a reason for hiding this comment

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

From the comments in this ADR and in the linked issues, the feeling I get is that everyone here is aligned to say "it should be okay" (incl. me).

Would it make sense to run this by a cryptographer, to get validation "yes, this is okay". I'd trust the word of a cryptographer over my gut feeling any day of the week.

docs/architecture/adr-028-public-key-addresses.md Outdated Show resolved Hide resolved
key type prefix when creating addresses.

We define the canonical address format for new (non-legacy) public keys as
`Sha256(fmt.Sprintf("%s/%x, proto.MessageName(key), key.Bytes())[:20]`. This takes
Copy link
Contributor

Choose a reason for hiding this comment

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

Current secp256k1 uses ripemd160 instead of [:20]. The latter is faster to compute, but are there other trade-offs (in particular, security-wise)?

Copy link
Contributor

Choose a reason for hiding this comment

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

It is needed for bitcoin compatibility. There were other designs, but the 2017 fundraiser addresses were generated with a bitcoin secp256k1 address derivation and the go code had to be compatible.

But I cannot tell you if 20 bytes prefix is just as safe

Copy link
Member

Choose a reason for hiding this comment

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

ripemd160 is an odd and basically pointless cryptographic choice and there is no reason to retain it.

It's a slow hash function and doesn't improve security in a meaningful way.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If we are changing this, how about using blake2b? Which is faster, and many believe that it's more secure.

Copy link
Member Author

Choose a reason for hiding this comment

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

Why not blake3 @robert-zaremba ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

So hypothetically it would be easier to find a pre-image for a SHA256 address than a Blake2 address?

Not worse, and it's more random.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Blake3 reduced the number of rounds from Blake2 to get a speed up

It uses a different mechanism, so I can't say if the reduction of number of rounds impacts the security vs Blake2 or not. Probably asking one of the authors (Zooko?) would be the best approach.

Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe we err on the side of caution and go with Blake2

This seams to be the balanced solution. Although it would be still good to check out with zcash about their view. I will try to reach out to some of them.

Copy link
Member Author

Choose a reason for hiding this comment

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

The new draft uses blake2b. Both because it has better library support and has been around longer and vetted more thoroughly (as I understand it).

I'm assuming blake2b is preferable to blake2s for our use case?

Choose a reason for hiding this comment

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

BLAKE2b is designed and optimized for 64-bit CPUs. BLAKE2s is designed and optimized for 8, 16, 32-bit CPUs.
BLAKE2 has indeed excellent Golang and Rust libraries support. Today there are very few BLAKE3 supported implementations. The speed boost observed with BLAKE3 is not really a selling point regarding ADR 028.

@amaury1093
Copy link
Contributor

amaury1093 commented Aug 28, 2020

@clevinson I can try to answer your questions, given my understanding of this ADR:

If i understand correctly, this means that legacy account addresses would be unchanged and remain in their bech32 prefixed form, but accounts generated with non secp256k1 pubkeys would use the new format (no prefix, just a hash as described above)?

There's public key ([]byte), address (also []byte, derived from pubkey & keytype, what we're discussing here) and bech32-encoding of an address (e.g. a cosm-prefixed string). Whatever address format is chosen here, we can still bech32-encode it.

How does one distinguish between a "legacy" or "new" multisig? Is this about addresses that exist onchain on a current zone, vs ones that do not? Or about what pubkey type the multisig address is comprised of (where secp256k1 is deemed "legacy"). How does that then relate to multisig with keys of multiple types?

Given a random 20-byte address, I believe there's no way to distinguish if it's a "legacy" or "new" multisig, or any other single public key type. This ADR describes the other direction, given 1/ threshold and 2/ an array of public keys (each being potentially of a different key type), how to construct "legacy" and "new" multisig addresses.

Also, I don't think secp256k1 is deemed "legacy"; it just has a different address generation algorithm.

@robert-zaremba
Copy link
Collaborator

robert-zaremba commented Aug 28, 2020

For new account address format, how about using the same algorithm as Algorand is using.

They have one of the best cryptographers form the world so they know best what / how to use.

Additional advantage is that it has a checksum, which protects against a wrong copy paste!

@alessio
Copy link
Contributor

alessio commented Aug 28, 2020

The proposal looks good, though I'm interested in understanding better what are the consequences for multisig keys (see Cory's questioin: How does one distinguish between a "legacy" or "new" multisig? )

@aaronc aaronc requested a review from robert-zaremba October 8, 2020 17:48
if len(contents) != 0 {
preImage = append(preImage, 0)
preImage = append(preImage, contents...)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

When implementing this we should use use make([]byte, correctSize) and copy they content using for or copy (into slice starting from index 2).

@robert-zaremba
Copy link
Collaborator

I've sorted the addresses in the current multisig format. Does that address your concerns?

Yes, but we will still need to rethink how to handle dynamic accounts (more about it below).

What about multisig accounts with dynamic addresses? I think the solution will be to use a native multisig address if such one is provided (I proposed it in one comment).

I'm not sure what you mean by this? Would group accounts (https://github.com/regen-network/cosmos-modules/tree/master/incubator/group) satisfy would you mean by dynamic multisig @robert-zaremba ?

Maybe. This will go into the category of a complex / multisig account with a native address. I think we will need to go back to the ADR28 once we will put all accounts together and before we will implement it. So for the moment I would like to mark it only.

@robert-zaremba
Copy link
Collaborator

In general I would use a pseudo code for explaining the algorithm. The reason is that we should discuss implementation details separately, which will involve things like integration and optimization, and language specific things.

@jgimeno jgimeno requested a review from robert-zaremba October 9, 2020 10:38
Comment on lines 92 to 93
We use a 256-bit `blake2b` hash instead of `sha256` because it is generally considered more secure. Blake hashes
are considered "random oracle indifferentiable", a stronger property which `sha256` does not have.
Copy link
Member

Choose a reason for hiding this comment

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

Random oracle indifferentiability is cryptographically irrelevant for constructing addresses.

https://blog.cryptographyengineering.com/2012/07/17/indifferentiability/

Cause see the prefix of an address always specifies the length of suffix. Ie. sr25519 key is always 32bytes. In the context of this protocol, a MD hash like sha256 is "random oracle indeffentiable"

I'm just saying this because I'm always going to strongly advocate for a really high bar for adding a new hash function to the Cosmos trusted computing base.

Copy link
Collaborator

@robert-zaremba robert-zaremba Oct 9, 2020

Choose a reason for hiding this comment

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

@zmanian I agree with your general approach. But we don't propose a any exotic algorithm. Blake2 is a part of at least Go and Python3 stdlib and it's an improvement. Some cryptographers claim that sha256 is easier to break than blake2 because we already know how to break other hash functions from the MD family.

Copy link
Contributor

Choose a reason for hiding this comment

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

Some cryptographers claim that sha256 is easier to break than blake2.

Some references would be appreciated 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm just saying this because I'm always going to strongly advocate for a really high bar for adding a new hash function to the Cosmos trusted computing base.

So I want to summarize what I heard from @zmanian on our last call about this. Basically:

  • there is no consensus on the replacement for SHA256 yet in the crypto community and there's a widespread sense that it won't be broken anytime soon
  • we want to minimize what is needed for someone to implement "cosmos" on a broad array of devices including hardware wallets and embedded devices

Thus for now it's probably preferable to stick with SHA256. Is that accurate @zmanian ?

@alessio any progress on getting the cryptographer at AiB to take a look at this?

Copy link
Collaborator

Choose a reason for hiding this comment

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

W3F Research / Polkadot is using blake2b and avoiding sha2.

@robert-zaremba robert-zaremba mentioned this pull request Oct 9, 2020
9 tasks
@aaronc
Copy link
Member Author

aaronc commented Oct 21, 2020

I have reverted to change to blake2b and this ADR now uses sha256 again. I would reconsider an alternate hash if a good argument is made, but it's contentious for now and I want to at least be able to move forward with the non-contentious parts.

In the interest of progress and the points raised in #7498 can we merge this ADR with status proposed and address remaining issues as follow-up issues and or PRs?

I still would like to get a cryptographer's opinion on the hashing if we can, but I think I have addressed what I can for now.

So basically I would like to get people's opinion as to whether this is a good enough starting point that we can move forward with it at least preliminarily. We need something to work off of within the SDK. Our plan is to include this in the v0.41 release so we can open a few follow-up issues tagged as v0.41 and make sure we address them before release.

Copy link
Collaborator

@robert-zaremba robert-zaremba left a comment

Choose a reason for hiding this comment

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

👍

Copy link
Collaborator

@robert-zaremba robert-zaremba left a comment

Choose a reason for hiding this comment

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

Let's add notes around the parts which:

  • Require opinion of qualified person
  • Are still under consideration

And then merge

@aaronc
Copy link
Member Author

aaronc commented Oct 21, 2020

Let's add notes around the parts which:

  • Require opinion of qualified person
  • Are still under consideration

And then merge

@robert-zaremba could you open an issue documenting those things?

@aaronc aaronc added the A:automerge Automatically merge PR once all prerequisites pass. label Oct 21, 2020
@mergify mergify bot merged commit f24ad5d into master Oct 21, 2020
@mergify mergify bot deleted the aaronc/adr-028-pub-key-addresses branch October 21, 2020 16:03
@robert-zaremba robert-zaremba mentioned this pull request Jan 20, 2021
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A:automerge Automatically merge PR once all prerequisites pass. T: ADR An issue or PR relating to an architectural decision record T: Security
Projects
None yet
Development

Successfully merging this pull request may close these issues.