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

Signatures for Commits & the Author model #14

Closed
joepio opened this issue Oct 10, 2020 · 2 comments
Closed

Signatures for Commits & the Author model #14

joepio opened this issue Oct 10, 2020 · 2 comments

Comments

@joepio
Copy link
Member

joepio commented Oct 10, 2020

In Atomic Commits, every change is signed by some author. This makes Commits truly atomic, and means that they can be shared as fully verifiable pieces of information, similar to W3C Verifiable Credentials (although Atomic Commits are specifically made to describe changes instead of current state).

However, this requires some implementation. Here's what I'm thinking:

  1. The Author creates a keypair. The public key is stored publicly at the Author's URL, the private key stores somewhere safe
  2. The Commit should be serialized to some format (I'm thinking JSON-LD). This process should be deterministic - serializing some commit should always result in the exact same string, so perhaps the keys should be sorted alphabetically. Note that the Commit can only be serialized as some partial struct, since the signature is of course missing.
  3. The serialized Commit should be signed by the private key. This signature is included in the Commit that's sent to the server.
  4. The server receives the Commit and checks if the Author has the correct rights.
  5. If it does, it gets the Author resource and its public key.
  6. It generates the same serialized Commit representation from step 2, and it checks the signature using the public key.
@joepio
Copy link
Member Author

joepio commented Oct 26, 2020

I've implemented a version of this process in atomic. Perhaps the most important step of this process is the serialization of the commit, since this process needs to be deterministic. This is what I'm doing now:

 /// Generates a deterministic serialized JSON representation of the Commit.
    /// Does not contain the signature, since this function is used to check if the signature is correct.
    pub fn serialize_deterministically(&self) -> AtomicResult<String> {
        let mut obj = serde_json::Map::new();
        obj.insert(
            "subject".into(),
            serde_json::Value::String(self.subject.clone()),
        );
        obj.insert(
            "createdAt".into(),
            serde_json::Value::Number(self.created_at.into()),
        );
        obj.insert(
            "signer".into(),
            serde_json::Value::String(self.signer.clone()),
        );
        if let Some(set) = self.set.clone() {
            if !set.is_empty() {
                let mut collect: Vec<(String, String)> = set.into_iter().collect();
                // All keys should be ordered alphabetically
                collect.sort();
                // Make sure that the serializer does not mess up the order!
                let mut set_map = serde_json::Map::new();
                for (k, v) in collect.iter() {
                    set_map.insert(k.into(), serde_json::Value::String(v.into()));
                }
                obj.insert("set".into(), serde_json::Value::Object(set_map));
            }
        }
        if let Some(mut remove) = self.remove.clone() {
            if !remove.is_empty() {
                // These, too, should be sorted alphabetically
                remove.sort();
                obj.insert("remove".into(), remove.into());
            }
        }
        if let Some(destroy) = self.destroy {
            // Only include this key if it is true
            if destroy {
                obj.insert("destroy".into(), serde_json::Value::Bool(true));
            }
        }
        let string = serde_json::to_string(&obj)?;
        Ok(string)
    }

Couple of thoughts / dilemmas:

  1. Should the deterministically serialized representation be a valid JSON-LD resource? If that is the case, we'll need to include @context in all responses. Seems a bit much.
  2. Should it use URLS as keys, or shortnames? For now I've gone with shortnames, since that is easier to read, less prone to typos and more compact. However, this could also be confusing, as all resources in Atomic Data actually use URLs for keys. This perhaps is more of a fundamental question for how JSON + Atomic Data interoperability will work.
  3. How to deal with extensions to Commits? Let's assume some developer wants to introduce a new method, e.g. line-based changes to some specific atom. This would probably be a new property on a Commit, which is perfectly fine in

@joepio
Copy link
Member Author

joepio commented Feb 16, 2021

I've updated the docs about this discussion. Long story short, I've opted for deterministic JSON-AD serialization and made two implementations (one in rust and one in typescript)

@joepio joepio closed this as completed Feb 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant