While Git is designed in some way for peer-to-peer interactions, there is no deployment of it that works that way. All deployments use the client-server model because Git lacks functionality to be deployed as-is in a peer-to-peer network.
For one, it has no way of verifying that the repository you downloaded after a `git clone` is the one you asked for, which means you need to clone from a trusted source (ie. a known server). This isn't compatible with p2p in any useful way.
Radicle solves this by assigning stable identities[0] to repositories that can be verified locally, allowing repositories to be served by untrusted parties.
> it has no way of verifying that the repository you downloaded after a `git clone` is the one you asked for
Respectfully disagree here. A repository is a(or multiple) chain(s) of commits, if each commit is signed, you know exactly that the clone you got is the one you asked for. You're right that nobody exposes a UI around this feature, but the capability is there if anyone would have any workflows that require to pull from random repositories instead of well established/known ones.
That problem is social you can never be sure of that even with hardware signing of commits. No tech can ever solve that. Just get "pull requests" from contributors you know and pull from maintainers you trust. Is the social model.
That's not quite right, we solved this in Radicle. Each change in ownership (adding/removing maintainers) is signed by the previous set of owners. You can therefore trace the changes in ownership starting from the original set, which is bound to the Repository ID.
Sure, but again, you've added convenience - or what you feel like it's convenience - for something that probably can be achieved right now with open source tools. A "CONTRIBUTORS" file with sign-offs by maintainers is an example of a solution for the same thing.
I don't deny that your improvements can benefit certain teams/developers but I feel like there are very few people that would actually care about them and they're not making use of alternatives.
A CONTRIBUTORS file is easy to change by anyone hosting the repository - it's useless for the purpose of verification, unless you have a toolchain to verify each change to said file. "Sign-offs by maintainers" it not useful either unless you already know who the maintainers are, and you are kept up to date (by a trusted source) when the maintainers change. This is what Radicle does, for free, when you clone a repo.
All good points, but now you moved the trust requirement from me having to trust the people working on the code, to me having to trust the tool that hosts the code. I'm not convinced your model is better. :P
I don't know, for me when I get involved with a project, I'm more likely to be aware of the people involved with it than the place where they host it.
I understand that the disruption Radicle wants to bring is to divorce projects from their developers, but that sounds so foreign to me, that I can't wrap my head around it. I can see its use in some cases: abandoned projects, unethical behaviour from maintainers, but not to the extent where a new platform is required.
Maybe that's why I'm being such a Negative Nancy. I hope u/cloudhead didn't consider my replies too aggressive. :)
How do I verify the “original set”, or the Repository ID, if not out-of-band communication (like a project’s official website)? And then what advantage does this have over the project maintainer signing commits with their SSH key and publishing the public key out-of-band?
I think there’s room for improvements in distributed or self-hosted git, but I think they exist more in the realm of usability than any technological limitations with the protocol. Most people don’t sign git commits because they don’t know it’s possible—not because it’s insecure.
The repository id can be derived via a hash function from the initial set of maintainers, so all you need to know is that you have the correct repository id.
The advantage of this is that (a) it verifies that the code is properly signed by the maintainer keys, and (b) it allows for the maintainer key(s) to evolve. Otherwise you’d have to constantly check the official website for the current key set (which has its own risks as well)
If I am on the internet there is no key or keys that I could definitively say came from the _real_ maintainers. I need to trust some source or sources for that.
In your model, committing to the repo requires a private key. This key claims ownership of the repo. If that key is lost or stolen I have lost ownership of that repo. With no out of band method to recover it.
If that key is unknowing stolen, ownership is switched to a new key, this is a pretty bad scenario.
Basically, I still always need to go to some other out of band source to verify that bad things have not happened.
Radicle developer here :) And yes you're completely right.
The current state of key management has A LOT left to be desired, because `did:key` has no rotation and so if you lose your key then it's game over. We decided to go with something simple first to allow us to develop the collaboration experience as much as possible -- we're a small team so it's hard to tackle all of the large problems all at once, while also getting an experience that's polished :D
Key management and a general "profile" is high on our priority list after we have properly launched. A few of us think DIDs (https://www.w3.org/TR/did-core/) are a good way forward. In particular, `did:keri` seems very interesting because its method involves a merkle-chain log, which can be easily encoded in Git. It includes key pre-rotation -- meaning there's a key that's available to help recover if something goes wrong. It can also delegate to other people, so you can allow the safety of your identity and key be improved by third-parties.
That said maybe there are other DID methods or other methods in general that might better suit. Or maybe we're able to build something that can be more general, and just needs to essentially resolve to a public/private key pair and we don't care after that.
Would definitely be interested in the communities thoughts here :) Or if someone who's got expertise in the area wants to chip in, hit us up ;)
It's seems to me that for security reasons it might be a good idea to support separate signing keys for normal commits and commits that change the ownership set. This would allow you to keep the ownership change keys offline under the assumption they are rarely used. This is something PoS cryptocurrencies tend to do by having a separate withdrawal key for accessing stake to the signing key used for block proposals, attestations etc.
How do you know the repository id is the correct one?
You have just changed the requirement from knowing the maintainers public key, to knowing a different public key. Sounds pretty much the same problem to me.
Yes, but the maintainers can be changed while also keeping the identifier stable.
Updates to the delegate set (read: maintainers) can be made, let's say adding a new delegate. This change is signed by a quorum of the current set of maintainers. This change is kept track of in the Git commit history, so these chain of actions can be walked from the root and verified at each point.
Similarly, a delegate can be removed, the project name changed, etc.
Forking is only necessary if there is a disagreement between maintainers that cannot be resolved so one of them goes off to create a new identifier to differentiate between the two. At this point, it's up to you to decide who you trust more to do a better job :)
When you fork an abandoned repo, you are essentially giving it a new repository identity, which is a new root of trust, with a new maintainer set. You'll then have to communicate the new repository identifier and explain that this is a fork of the old repo.
By the same way I know how the commit signers are who they say they are in "regular" usage of GPG: I have verified the key belongs to them, or their keys are signed by people I trust to have verified, etc, etc. Like a sibling said, the problem is social rather than technical.
Yeah, because for eg. I can publish the given repository from my server with an additional signed commit (signed by me) on top of the original history, and that commit could include a backdoor. You have no way of knowing whether this additional commit is "authorized" by the project leads/owners or not.
That is in fact the point, it's decentralized by nature. The entire idea behind git's decentralization is that your version with an additional backdoor is no lesser of a version than any other. You handle that at the pointer or address level i.e. deciding to trust your server.
Perhaps, but none of that commit history is related to the invocation to git clone. To acquire and verify you need both a url and a hash for each branch head you want to verify
The problem I'd like to see solved is source of truth. It'd be nice if there were a way to sign a repo with an ENS or domain withiut knowing the hash.
Another thing is knowing if the commit history has been tampered with without knowing the hash.
The reason for needing to not know the hash is for cases like tornado cash. The site and repo was taken down. There's a bunch of people sharing a codebase with differing hashes, you have no idea which is real or altered.
This is also important for cases where the domain is hacked.
> The reason for needing to not know the hash is for cases like tornado cash. The site and repo was taken down. There's a bunch of people sharing a codebase with differing hashes, you have no idea which is real or altered.
> This is also important for cases where the domain is hacked.
I think at some point you need to know some sort of root-of-trust to kick off the trusting process. I believe in this case, you would trust a certain DID or set of DIDs (i.e. a Tornado Cash developer's public key). You can clone their version of the project and the history of the project MUST be signed by their private key for it to be legitimate.
To clarify, in Radicle, a peer's set of references are always signed by their key and this data is advertised so that you can always verify, using their public key, that this data is indeed what this peer has/had in their Git history. If this ever diverges then any fetching from that peer is rejected.
This is just another form of the cryptographic key distribution problem. Doesn't matter where the git repository comes from, you can be sure it hasn't been tampered with if the signatures are valid.
Domains with DNSSEC are an interesting solution. PGP public keys are distributable via DNS records.
If you mean collision attacks, this shouldn't be a problem with Git, since it uses Hardened SHA-1. Eventually, when Git fully migrates to SHA-2, we will offer that option as well.
> Is Hardened SHA-1 vulnerable?
> No, SHA-1 hardened with counter-cryptanalysis (see ‘how do I detect the attack’) will detect cryptanalytic collision attacks. In that case it adjusts the SHA-1 computation to result in a safe hash. This means that it will compute the regular SHA-1 hash for files without a collision attack, but produce a special hash for files with a collision attack, where both files will have a different unpredictable hash.
Everything that is replicated on the network is stored as a Git object, using the libgit2[0] library. This library uses hardened SHA-1 internally, which is called sha1dc (for "detect collision"). Will add to the docs, good idea!
For one, it has no way of verifying that the repository you downloaded after a `git clone` is the one you asked for, which means you need to clone from a trusted source (ie. a known server). This isn't compatible with p2p in any useful way.
Radicle solves this by assigning stable identities[0] to repositories that can be verified locally, allowing repositories to be served by untrusted parties.
[0]: https://docs.radicle.xyz/guides/protocol#trust-through-self-...