axelarnetwork / tofn

A threshold cryptography library in Rust
Apache License 2.0
112 stars 23 forks source link

Future-proof domain separation for hash inputs #184

Closed ggutoski closed 4 months ago

ggutoski commented 3 years ago

Currently we take an ad hoc approach to domain separation. Sometimes we take a single u8 tag. Sometimes we layer multiple u8 tags. None of these approaches avoids the problem that you need a central repository of all tags in order to avoid tag re-use.

Perhaps a better solution is to use hard-coded randomly-selected 32-byte blobs for tags.

_Originally posted by @ggutoski in https://github.com/axelarnetwork/tofn/pull/182#discussion_r728471667_

milapsheth commented 3 years ago

What I had in mind is hierarchical local layering. Each level has a constants.rs specifying the tags for the distinct applications in it's layer. Each submodule will then recursively have it's own constants.rs with the appropriate application tags. The domain is generated by concatenating all tags from the root layer to the current layer. So, if the hierarchy is as follows:

src
|_ constants.rs
|
|_ tss
|   |_ constants.rs
|
|_ msig
    |_ constants.rs

src/constants.rs will have tags to distinguish tss and msig. And tss/constants.rs and msig/constants.rs will also have their own tags to distinguish their usages. For e.g., for the rng_seed method, tss/constants.rs will have tags for keygen and zksetup, while msig/constants.rs will have one for keygen. The tags internal to tss are not visible to msig and can overlap since they're appropriately domain separated by the layer 1 tags. Both tss and msig will use the tags from layer 1 and layer 2 to generate a domain for the rng_seed method.

ggutoski commented 3 years ago

That could work but I have some ergonimics concerns:

By contrast, the random-blob solution doesn't require enumeration in a separate constants.rs file; individual domains don't need to "know about" other domains. All tags have the same length and so we can have a dedicated newtype like struct DomainTag([u8; 32])

milapsheth commented 3 years ago

Agreed that Point 1. will help with ergonomics. We could have a const function that does that perhaps.

I don't have a good solution to the situation when the code is in different crates.

My concern with using a fixed random 32 byte tag is that it becomes hard to verify if a new tag being added is unique and there wasn't a copy/paste error of a tag etc.