Open paulgmiller opened 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.
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!
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
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.
@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.
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.
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 |
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
For "signing IPNS with Metamask" use case, I see three paths forward:
Dual signing with two sets of keys (no change in Metamask, no change in IPNS spec, but second signature is only used by Ethereum-aware clients).
IpnsEntry.data
, and we then put that signature inside something like IpnsEntry.data[ethereum_personal_sign]
itself and sign entire IpnsEntry.data
with IPNS-specific key and prefix and store result in signatureV2
IpnsEntry.data
, but clients who care about Ethereum identity could verify this second signature for additional confidence or UX.IpnsEntry.data
before signing. And it would work with Ledger (which seems to only support personal_sign
method)Signing using current IPNS signatureV2 spec (no change in IPNS spec, requires Metamask update)
sign_bip62_der(sha256(ipns-signature: + data))
personal_sign
method – they would have to implement IPNS-specific signing method.Modify IPNS specification (hard way, requires changes across specs and IPNS implementations, and if it is chain-agnostic, also Metamask)
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!
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...
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:
keccak256
before signing — this hash function is currently not supported by the IPFS/libp2p librariessign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).
for security 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.
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.
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
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
Happy to try and contribute if wanted and someone is willing to guide preferences.
Some background here