ipfs / specs

Technical specifications for the IPFS protocol stack
https://specs.ipfs.tech
1.15k stars 232 forks source link

IPNS: support Ethereum wallet signing #323

Open paulgmiller opened 1 year ago

paulgmiller commented 1 year ago

I think it would be pretty useful if ipns recognized the signing prefix used by ethereum wallets. That way users with metamask or other wallets could sign ipns records to send to trusted nodes or providers like cloudflare, web3-storage, pinata without having to manage their own set of keys.

I think this would open up some interesting possibilities of distributed blogs other frequently updated content.

I think this would be pretty possilble to do in both go|js-ipns. Been poking around with a branch that can validate thos sigs But if desired not sure if it would be best to

  1. Always check the eth prefix.
  2. Make this a new nodeid in libp2p so we could go off its type.
  3. use some other data in the ipns record to indicate it's a eth signed record.

Happy to try and contribute if wanted and someone is willing to guide preferences.

Some background here

lidel commented 1 year ago

Thank you for filling this. go-ipns repository is not the right place to propose this change. I am moving this to ipfs/specs repo :)


FYSA the modern IPNS specification, including details how records are created and validated, is being documented in https://github.com/ipfs/specs/pull/319. Give it a read – that PR documents how go-ipns and js-ipns work today.

See "Backward Compatibility" section to understand the constraints and our policy around not breaking legacy clients (tldr: IoT device must be able to fetch and validate IPNS record with firmware update).

Something you may find useful, are Extensible IPNS Records. IPNS records have IpnsEntry.data field, which is an extensible DAG-CBOR document. Implementations are free to put additional data there, such as additional audit information.

Our libraries do not expose easy way of adding fields to IpnsEntry.data yet, but the specification and the wire format already support it. Sounds like this is the best place for storing these additional signatures.

paulgmiller commented 1 year ago

THanks for the link to #319 the existing spec didn't say much about data (nor did it talk about the v2 sig thats in the code). So excited to give this a look!

paulgmiller commented 1 year ago

Left a comment on #319 could totally see how we could add extra CBOR fields.

SignaturePrework : Ethereum or seperate fields SignatureHash: None | keccak256 SignaturePrefix: \x19Ethereum Signed Message:\n

But those would be replacements not additions to signature v2 for those records becasue we wallets won't give out access to the private keys in any reasonable UI flow.

Would it be fine for only some nodes accept and circulate these records? Is it different from adding a new Public Key type in the future?

Thanks again.

https://github.com/ethereum/go-ethereum/commit/b59c8399fbe42390a3d41e945d03b1f21c1a9b8d

lidel commented 1 year ago

Would it be fine for only some nodes accept and circulate these records?

I mean, the network does not care – it will simply ignore these additional fields. If the IPNS signature is invalid, records are simply ignored. Same for unknown key types.

It is more a question of your use case: If you are creating software that will both create and validate this additional metadata, then you can do whatever you want: as long you also include a valid IPNS signature that is in the spec, DHT nodes and PubSub routers will accept IPNS PUT your software does.

lidel commented 1 year ago

@paulgmiller, some additional notes around "signing IPNS record with Metamask" use case. Apologies for wall of text, but I wanted to give a comprehensive explainer that we could reference in the future.

On signing IPNS records with Metamask

Discussed this with @2color today in the context of https://github.com/ipfs/js-ipns/pull/192 (making it possible to sign valid IPNS records with secp256k1 keys outside of IPNS node) and the underlying problem is that even though IPNS supports signing records with secp256k1 keys, the way these signatures are performed is different than one (out of four+ ways) signing happens in Ethereum.

Multiple types of secp256k1 signatures

iiuc Ethereum and IPNS use different hash functions and prefix signed payload with different bytes:

Ethereum (metamask) signature with secp256k1 (one of four options?) IPNS signature (V2) with secp256k1
signA(keccak256(\x19Ethereum Signed Message:\n + len(data) + data)) sign_bip62_der(sha256(ipns-signature: + data))
signA() defined by EIP-712 (v4)
(but it is similar story for 4 other types listed here)
sign_bip62_der() defined by BIP0062, see libp2p specs

IPNS should not depend on any blockchain specifics

Given the above, we have incompatible signatures. One could argue IPNS spec could be extended to with Ethereum-specific signatures, but why should we tie IPNS spec to Ethereum-specific signatures, and not Some Other Blockchain?

This raises even more questions:

Finally, Ethereum ecosystem seems to have competing signature standards: there are 4 standards, and they already discuss adding v5. This does not bring a lot of confidence into stability and interoperability.

:point_right: I think all these questions and rabbit holes should be avoided. IPNS signatures must be chain-agnostic.

IPNS is routing-agnostic (records can be resolved via DHT, PubSub, and soon Gateways).

We allow multiple key types, but the way signatures are created must remain IPFS-specific to

  1. avoid the discussion which blockchain is "worthy",
  2. avoid ballooning complexity on the client side by requiring support for multiple key types (and / or signature types)
  3. ensure signatures can't be used outside of IPNS record context

What are the next steps?

For "signing IPNS with Metamask" use case, I see three paths forward:

paulgmiller commented 1 year ago

This is a great write up and way more than I expected from this issue. Thank you very much. I totally get the concerns about ipns not chaining itself to any of the many blockchain standards maybe if that stabilizes it coming years there might be a defacto standard but probably too early to tell.

Speaking towards the next steps.

I think the main issue with "dual signing" is that ipfs nodes will only keep the latest revision so an ipfs node has to generate a new key for each "eth/metamask" user that wants to use it otherwise it will only be able to serve one forieng user. So if that user moves between nodes it'll be lost what public key to look up. So you need another global source of truth like ens/dns to be updated when that happens.

For "using current ipns spec" you need not just metamask but all wallets to pick this up doable but very long term in my mind.

My current plan is to just create an application specific version of ipns that publishes via pubsub so apps that want this can get it. The BIG downside of this is only apps that know about it participate. You can't get all the ipfs nodes to participate. But it does let us get ipns pointers passed around and we can come back to "modify ipns spec" if there is every any successful app here.

Thanks again!

bumblefudge commented 1 year ago

Wow, there's a lot to take in here! I would recommend, before picking a path and getting to work, doing a tiny bit of research on the metamask Snaps project and its custom signing and deterministic key derivation capabilties! Snaps are basically MM plug-ins, and AFAIK the preferred way for external teams to extend metamask signing and key handling capabilities...

2color commented 1 year ago

To elaborate on (or summarise) what @lidel mentioned, all current signing methods in the Ethereum ecosystem ((https://eips.ethereum.org/EIPS/eip-191 and https://eips.ethereum.org/EIPS/eip-712)) are unsuitable for interoperability with IPNS for two reasons:


This leads to the three options laid out:

I'll be getting in touch with the Metamask folks via CASA to make them aware and investigate some possible future paths.

ritave commented 1 year ago

Hello from an engineer working on MetaMask Snaps.

There have been quite a few requests to us for different cryptographic primitives and signature schemes, including JWT tokens, Bitcoin signatures, IPLD through CACAO, plain RSA, etc.

We can't support all of them due to their sheer count.

What we're trying to achieve is to allow the community to agree on common standards themselves and then allow people to extend MetaMask using Snaps to support that specific use-case.

We're allowing Snaps access to raw private key entropy so a Snap that provides IPNS signatures is possible.


In short, I'm suggesting it might be easier to write a plugin for MetaMask to support IPNS rather than updating the IPNS spec to support MetaMask, and our team will do everything what we can support you on that route.

2color commented 1 year ago

Thanks for the update @ritave

I suppose the Filsnap might be worth looking at for how to do so signing with Metamask Snaps, e.g. https://github.com/ChainSafe/filsnap/blob/master/packages/snap/src/rpc/signMessage.ts#L102