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

ERC: Claim Holder #735

Open
frozeman opened this issue Oct 9, 2017 · 77 comments
Open

ERC: Claim Holder #735

frozeman opened this issue Oct 9, 2017 · 77 comments
Labels

Comments

@frozeman
Copy link
Contributor

@frozeman frozeman commented Oct 9, 2017

EIP: 735
Title: Claim Holder
Author: Fabian Vogelsteller (@frozeman)
Type: Standard
Category: ERC
Status: Discussion
Created: 2017-10-09

NOTE: Due to the changes in ERC725, this spec is not fully compatible with the current ERC725v2. If you're interested in adopting this spec to work with 725v2, please comment below, or send a gist with changes.

Abstract

The following describes standard functions for adding, removing and holding of claims.
These claims can attested from third parties (issuers) or self attested.

Motivation

This standardised claim holder interface will allow Dapps and smart contracts to check the claims about a claim holder. Trust is here transfered to the issuers of claims.

Definitions

  • claim issuer: is another smart contract or external account, which issues claims about this identity. The claim issuer can be an identity contract itself.
  • claim: A claim is an information an issuer has about the identity holder. This contains the following:
    • topic: A uint256 number which represents the topic of the claim. (e.g. 1 biometric, 2 residence (ToBeDefined: number schemes, sub topics based on number ranges??))
    • scheme : The scheme with which this claim SHOULD be verified or how it should be processed. Its a uint256 for different schemes. E.g. could 3 mean contract verification, where the data will be call data, and the issuer a contract address to call (ToBeDefined). Those can also mean different key types e.g. 1 = ECDSA, 2 = RSA, etc. (ToBeDefined)
    • issuer: The issuers identity contract address, or the address used to sign the above signature. If an identity contract, it should hold the key with which the above message was signed, if the key is not present anymore, the claim SHOULD be treated as invalid. The issuer can also be a contract address itself, at which the claim can be verified using the call data.
    • signature: Signature which is the proof that the claim issuer issued a claim of topic for this identity. it MUST be a signed message of the following structure: keccak256(address identityHolder_address, uint256 _ topic, bytes data) // or keccak256(abi.encode(identityHolder_address, topic, data)) ?
    • data: The hash of the claim data, sitting in another location, a bit-mask, call data, or actual data based on the claim scheme.
    • uri: The location of the claim, this can be HTTP links, swarm hashes, IPFS hashes, and such.

Specification

Claim Holder

claim structure

The claims issued to the identity. Returns the claim properties.

struct Claim {
    uint256 topic;
    uint256 scheme;
    address issuer; // msg.sender
    bytes signature; // this.address + topic + data
    bytes data;
    string uri;
}

getClaim

Returns a claim by ID.

function getClaim(bytes32 _claimId) constant returns(uint256 topic, uint256 scheme, address issuer, bytes signature, bytes data, string uri);

getClaimIdsByTopic

Returns an array of claim IDs by topic.

function getClaimIdsByTopic(uint256 _topic) constant returns(bytes32[] claimIds);

addClaim

Requests the ADDITION or the CHANGE of a claim from an issuer.
Claims can requested to be added by anybody, including the claim holder itself (self issued).

_signature is a signed message of the following structure: keccak256(address identityHolder_address, uint256 topic, bytes data).

Claim IDs are generated using keccak256(address issuer_address + uint256 topic).

This COULD implement an approval process for pending claims, or add them right away.

Possible claim topics:

  • 1: Biometric data
  • 2: Permanent address

(TODO: add more in the initial standard? 3: Claim registry?)

Returns claimRequestId: COULD be send to the approve function, to approve or reject this claim.

Triggers if the claim is new Event and approval process exists: ClaimRequested
Triggers if the claim is new Event and is added: ClaimAdded
Triggers if the claim index existed Event: ClaimChanged

function addClaim(uint256 _topic, uint256 _scheme, address _issuer, bytes _signature, bytes _data, string _uri) returns (uint256 claimRequestId)

removeClaim

Removes a claim.
Can only be removed by the claim issuer, or the claim holder itself.

Triggers Event: ClaimRemoved

function removeClaim(bytes32 _claimId) returns (bool success)

Events

ClaimRequested

COULD be triggered when addClaim was successfully called.

event ClaimRequested(uint256 indexed claimRequestId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri)

ClaimAdded

MUST be triggered when a claim was successfully added.

event ClaimAdded(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri))

ClaimRemoved

MUST be triggered when removeClaim was successfully called.

event ClaimRemoved(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri))

ClaimChanged

MUST be triggered when changeClaim was successfully called.

event ClaimChanged(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri)

Solidity Interface

pragma solidity ^0.4.18;

contract ERC735 {

    event ClaimRequested(uint256 indexed claimRequestId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
    event ClaimAdded(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
    event ClaimRemoved(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
    event ClaimChanged(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);

    struct Claim {
        uint256 topic;
        uint256 scheme;
        address issuer; // msg.sender
        bytes signature; // this.address + topic + data
        bytes data;
        string uri;
    }

    function getClaim(bytes32 _claimId) public constant returns(uint256 topic, uint256 scheme, address issuer, bytes signature, bytes data, string uri);
    function getClaimIdsByTopic(uint256 _ topic) public constant returns(bytes32[] claimIds);
    function addClaim(uint256 _topic, uint256 _scheme, address _issuer, bytes _signature, bytes _data, string _uri) public returns (uint256 claimRequestId);
    changeClaim(bytes32 _claimId, uint256 _topic, uint256 _scheme, address _issuer, bytes _signature, bytes _data, string _uri) returns (bool success);
    function removeClaim(bytes32 _claimId) public returns (bool success);
}

Constraints

  • A claim can only be one per topic per issuer.

Additional References

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 9, 2017

This is implemented by #725

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 9, 2017

I added uint256 signatureType

@Arachnid
Copy link
Collaborator

@Arachnid Arachnid commented Oct 9, 2017

I'm still not sure why you're using signatures here, and thus restricting things to only externally owned accounts using ECDSA sigs. Wouldn't it be more general to rely on caller address?

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 9, 2017

In order to auto-verify an claim - which could have been added by anybody - each claim needs to contain a in smart contract verifiable signature from one key of an issuers identity. The signature must sign, claim type, claim holder address and claim reference hash.

This way any contract can auto-verify claims.

There is no way to enforce this standard, and if a supposed claim holder added a claim with address issuer somebody, but that somebody never made that claim, there is no way to proof that, except using signatures.

I added the uint256 signatureType to also allow different signature in the future.

And yes you need an external owned account, or key to sign, to allow fully on chain verification. Or do you have any other method in mind, how we could solve that problem?

I will repost a pure on chain claim verification process:

  1. getClaim by index, which is the type for a trusted issuer. Index is generated: (keccak256(address issuer_address + uint256 _claimType))
  2. Ecrecover signature, retrieve address k
  3. Check if k is still a key hold by the claim issuers identity contract (issuer address)
@3esmit
Copy link
Contributor

@3esmit 3esmit commented Oct 9, 2017

@frozeman Would be something like this?

pragma solidity ^0.4.15;
import "https://gist.githubusercontent.com/AugustoL/9ddf7996e23a01c6599323761c0deeef/raw/17ae59c3dc2c82df791b2e48e5d05a5c012fec42/ECRecover.sol"; //todo: change to repo
contract IdentityRegistry {
    //(... other logic)
    enum SignatureType {
        DirectCall,
        SignedMessage
    }
    function addClaim(uint256 _claimType, address issuer, uint256 signatureType, bytes _signature, bytes _claim, string _uri) returns (uint256 claimId){
        
        if (signatureType == SignatureType.DirectCall) {
            require(issuer == msg.sender);
        } else if (signatureType == SignatureType.SignedMessage) {
            bytes32 signedMsg = keccak256(address(this), _claimType, _claim);
            require(issuer == ECRecover.ecrecovery(_signature, signedMsg));
        } else { revert(); }
        //(... store claim and do stuff)
    }
    //(... more other logic)
}

With this user could call directly without using signed message, and other account could register the user using the signed message?

@Arachnid
Copy link
Collaborator

@Arachnid Arachnid commented Oct 9, 2017

In order to auto-verify an claim - which could have been added by anybody - each claim needs to contain a in smart contract verifiable signature from one key of an issuers identity. The signature must sign, claim type, claim holder address and claim reference hash.

Why not just have a registry of claims, whose smart contract code ensures that only valid claims can be stored there?

@christianlundkvist
Copy link

@christianlundkvist christianlundkvist commented Oct 9, 2017

@frozeman - interesting stuff! On-chain attestations is an important use case and this is a good outline. I think the general idea of having claim types or categories are good, and the specifications you outlined are also useful. We’ve had some similar ideas in uPort although we have mainly focused on off-chain attestations.

I tend to agree with @Arachnid that the claim architecture would be more general if we were to allow any transaction to define a claim by using the msg.sender construct. Having a registry where claims are registered and where rules are enforced would allow any ethereum address to be the subject of a claim, and it would allow any smart contract capable of sending a transaction to issue a claim.

@3esmit
Copy link
Contributor

@3esmit 3esmit commented Oct 10, 2017

I have a use case for this where a registry is using Oraclize, for example with Oraclize+GitHubGists=user register, and also there will be the organizations in that registry (also by oraclize), so oraclize would be the "claimer", and by default it's a direct message call (not sure if is possible other way). Also they provide a 'bytes proof', which should be stored together with claim? Or this case might be out of ERC735 scope?

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 10, 2017

@3esmit the check shouldn’t be at the addClaim happen, but rather when the claim is verified by third party. There the signature of the claim needs to be checked. The signature type went to support different signatures in the future, e.g. it could hold non ecdsa siagntures as well.

@christianlundkvist good that your are here ;)
Yes sure a registry would allow for “adding” rules and this could be a useful addition, but it could get complicated when we introduce sharding , as all of those calls between the shards need then to go through an async transaction then. Though there could certainly additional registries for claims, but I think the in-contract claims are important for other off chain use cases.

Claims are not only meant to be only from other smart contracts (but they can come from any), but any off chain entity, as long as they attach a valid signature they could even go through a proxy to add claims to contracts.

Concerning adding claims for external accounts, yes that not possible. But I think it’s not really wanted either, your identity should have more than just a public key, which can be lost or stolen.

The reason why I kept the claim so flexible (e.g. sigtype, bytes for claim etc) is to allow all kind of claim type and verification to be added in the future. Only on chain verifications need the signature check. But claims can slow be checked off chain. Issuers could even attest claims about external accounts, but those doesn’t need to be stored in the Blockchain, this can be a transfer of those claims between two parties only. E.g. if I want to have a claim about me form an issuer, but I don’t want that the person which will verify the claim later can connect it to my on chain identity. In this case only the claim issuer need to be able to make that connection.

I will present tomorrow this ERC at the London ethereum Meetup, and there will be a video of that later on attached to this ERC.

I am also available for a call to discuss the details of how I think this works in a skype call. @christianlundkvist and @Arachnid you should have my skype already.

@3esmit
Copy link
Contributor

@3esmit 3esmit commented Oct 11, 2017

Wouldn't be equivalent, or more flexible to have function getClaimIdsByType(uint256 _claimType) constant returns(bytes32[]) over function getClaimsByType(uint256 _claimType) constant returns(Claim[]);?

Also,
function addClaim(uint256 _claimType, address issuer, uint256 signatureType, bytes _signature, bytes _claim, string _uri) returns (uint256 claimId) to returns (bytes32 claimId)?

@m-schmoock
Copy link

@m-schmoock m-schmoock commented Oct 12, 2017

@frozeman
Imagine a claim was self-claimed ('self-signed'), i.e. because a users sets up his identity and claims initial data (like real name and such):

  1. The approval process for this would not be required, correct?
  2. How would a second party 'sign' a self-claim, meaning claiming that the self-claimed data is correct?
  3. How would a third party iterate through the chain of claims?

Maybe you can provide some pseudo code of how this would look like..

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 13, 2017

@3esmit Thanks for the catches, i fixed it and change the function to getClaimIdsByType, which is something we can certainly make work in todays ABI.

I changed the bytes claim to bytes data in the claim, to adhere to @holiman critic of claim being used twice in different contexts.

@m-schmoock for self assigned claims one wouldn't need the approval process and not even a signature, if the address issuer address is the same as the contract itself, there is no verification necessary, as the contract itself holds and returns the claim.

for 3. you could get claims but type using getClaimIdsByType or your know which claim issuer your trust and which claim type you want, then you can recalculate the index using keccak256(address issuer_address + uint256 _claimType) and retrieve the claim directly using getClaim

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 13, 2017

I added a Additional References section.

@realcodywburns
Copy link
Contributor

@realcodywburns realcodywburns commented Oct 13, 2017

A disputeClaim function would be a nice feature. This would allow for an issuer to assert a claimType n that is negative in nature (late payments, poor conduct) that could be pertinent to both claiming identity and character, however, is inaccurate. While in dispute, the claim would be unavailable to getClaim and possibly third party arbitration assigned or timeout to remove the lock.

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 14, 2017

@realcodywburns according to this standard you approve any claim addition, and you can remove claims at any point. So there is no dispute necessary.
But you sure can’t do anything claiming something about you in other places. Like in social media today.

@andrewrd
Copy link

@andrewrd andrewrd commented Oct 14, 2017

@frozeman @realcodywburns Another use case for a disputeClaim would be to flag identities which have been compromised.

@realcodywburns
Copy link
Contributor

@realcodywburns realcodywburns commented Oct 14, 2017

Yes, the inability to remove some claims would be the goal. For example: an issuer assets a claim that identity 0xdeadbeaf has participated in their auction contract and is known to the community. As time passes , addational claims are asserted that timely payments have been received as per terms of the contract; these claims would further add credibility to both the character and validity of the identity. In the event that a shipment comes missing, the issuer then adds a claim to this effect. As the history exists, the issuer has attested that 0xdeadbeaf is trustworthy and can remove any derogatory claims with impunity. Anyone interacting with 0xdeadbeef would not know of her more recent bad actions.

If the situation arises by mistake, 0xdeadbeaf could disputeClaim, resolve the situation, and retain the longstanding credible claim. If 0xdeadbeef has actually done wrong, the claim both establishes identity and character and should be kept as record for sometime.

Allowing only positive assertions my establish identity but may not capture the full picture of an individual. At the same time, one should have the right to self defense

@MikeD123
Copy link

@MikeD123 MikeD123 commented Oct 15, 2017

I'm not sure if I've misunderstood it here @frozeman but I think a common structure for claimType like this would be awesome (if I'm understanding correctly on first glance). I get that this may be out of scope for this EIP in particular, and the list will always grow over time, but something that outlines things like this?

  • 01 - Individual
  • 02 - Business

Then specifying the following:

  • 01 - Social
    • 01 - video
    • 02 - photo
    • 03 - phone
    • 04 - video
    • 05 - platform (e.g. platformURL

//

  • 02 - Sovereign
    • isoNumericM49 // country specification
      • 01 - passport
      • 02 - nationalIdNumber
      • 03 - governmentId
      • 04 - proofOfAddress
      • 05 - bankStatement

//

  • 03 - Device/Machine
    • 01 - ip
    • 02 - os
    • 03 - browser
    • 04 - etc..

Looking up an individual for their sovereign doc, in USA, that is a passport.
function getClaimIdsByType(uint256 010284001) constant returns(bytes32[] claimIds);

Feel like I may have misunderstood something, or this is a bit outside of scope, but either way, really excited for this, and thanks for doing it!

@buendiadas
Copy link

@buendiadas buendiadas commented Oct 15, 2017

Great initiative @frozeman, I think using a unique URI field can lead to mistake when different Unique Resource Ids from different protocols are uploaded. Additionally to the collusion risk, as we are aggregating many different protocols, a resolver would not be able to know where to take the resource (should I request from IPFS?).

A solution could be an additional genericbytes32 protocol identifier inside the claim or a real URI creation outside the contract including the protocol distinction.

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 17, 2017

@realcodywburns @andrewrd the dispute claim is IMO not necessary. This standard is a shell for your own identity. First of you don't want to have every buy transaction references with your real world identity INSIDE you identity smart contract, that would be a huge privacy issue. And second there can be many reputation systems referencing this identity, this doesn't mean, every step needs to be a claim added to your identity.

Technically everybody can issuer a claim and post it anywhere (e.g. a reputation system, or facebook, twitter, etc) You can't defend yourself from that anyway (and shouldn't, as it might be legit). Allowing a claim on YOUR identity means, YOU approve it. Again don't get me wrong, reputation systems should exists, which allow sellers to verify the credibility of a buyer, but this is outside of this standard, and might just happen in a peer2peer way by sending over reputation claims you collected over time, or referencing your identity AND a reputation system you are using (These two don't have to be publicly connected, as long as you can proof owner ship of both)

@MikeD123 I think you get it a bit wrong. The idea of claimTypes is more of the nature of properties of you, e.g. 1: biometric data will obviously means your a person and not a business. 2. address will show that you are based somewhere, means you have a physical address or reference point. We could add claim types for certain social media, but thats up to discussion.

If you want to verify a claim, you most likely will not look for the type, but for a specific issuer you trust, so you can generate the ID of the claim in advance e.g.:

keccak256(address issuer_address + uint256 _claimType) -> keccak256('0x123456789...' + 1)

will generate you the hash of the claim you can get using getClaim(bytes32 _Id). If the claim doesn't exist, you either look for another, or you have to manually verify that person, or not at all. If the claim exists, you verify the signature inside the claim, and see if that recovered key is still hold by the claim issuer.

As over time, there will be trusted claim issuer, like the US gov, or some decentralised service, people can always know the index of the claims they want to retrieve and even hardcode that in their smart contracts.

On the end in most cases we don't care about the data itself, but that somebody verified it.

Concerning the subTypes. I wouldn't go so detailed, as then people can know why sub type of claim was changed when, which could be a privacy leak. For some data it might make sense to give them a separate type, but for example for biometric data, just that might be enough.

To auto verify a person in front of you, the claim issuer for biometric data needs to have some bio matching services, or zero knowledge proof smart contracts, which can take some takes biometric data, and match it against their data set, and return true or false, should the data match the person claim data reference you gave them.

@buendiadas concerning the URI, it should contain the protocol like ipfs://..., or bzz:// or https://

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 17, 2017

As next steps, it would be good to create a collection of PROs and CONs for having claim issues in a registry vs. having them on your identity contract directly.

Some short ideas i gathered when talking to @Arachnid, I put into this wiki page, which everybody can extend and add to it, so we don't have to do this over a series of issues: https://github.com/ethereum/wiki/wiki/ERC-735:-Claim-Holder-Registry-vs.-in-contract

This will allow us gather a good overview over both sides.

@bneiluj
Copy link

@bneiluj bneiluj commented Oct 19, 2017

@frozeman Great idea the wiki page ! https://github.com/ethereum/wiki/wiki/ERC-735:-Claim-Holder-Registry-vs.-in-contract. Let's create a vote counting with some eth ! 😅

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 20, 2017

Keep in mind both can work hand in hand, so a claim registry could be useful for some cases, and for others the attached claims in the contract itself are more useful. So can one claim referencing the claim registry, maybe with claimType 5 :)

@jacqueswww
Copy link

@jacqueswww jacqueswww commented Oct 20, 2017

@frozeman - so one question I had is about the possibility of expiring claims. I can imagine something like a physical address being semi-permanent, and needing re-verification every couple of years. As far as I understand it - with current layout of a Claim one would use the data field in the struct to store a value in the future? OR one would have to look up the date of ClaimAdded in the event log - which we can't do from within another contract right ;)
Simpler option is just returning a date created timestamp as part of the getClaim/claim struct, then a contract/service can decide the the delta from the getClaim call if they are willing to accept the claims' date.
Let me know what you think 😸 (I know it could possibly be scope creep over the standard, however one could argue that timestamping is something that almost anyone would be interested in)

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Oct 22, 2017

@jacqueswww Currently there would be two ways to handle that situation:

  1. One way it would be that you make the date part of the data field, as you described.

  2. Or the claim holder signs specific claims with keys he will expire on his identity himself. As everybody who will verify a claim should definitely check that the claim signing key is still valid, any claim issuer could remove that claim key based on a time frame.

tyleryasaka added a commit to tyleryasaka/identity-proposals that referenced this issue Nov 10, 2018
@aihuawu
Copy link

@aihuawu aihuawu commented Nov 11, 2018

for scheme rsa, should the public key be attached along with signature?

@aihuawu
Copy link

@aihuawu aihuawu commented Nov 11, 2018

topic number should be standardised. otherwise every one just use its own numbers. the claim is not portable.

@nathanawmk
Copy link

@nathanawmk nathanawmk commented Nov 14, 2018

@realcodywburns @andrewrd the dispute claim is IMO not necessary. This standard is a shell for your own identity. First of you don't want to have every buy transaction references with your real world identity INSIDE you identity smart contract, that would be a huge privacy issue. And second there can be many reputation systems referencing this identity, this doesn't mean, every step needs to be a claim added to your identity.

Technically everybody can issuer a claim and post it anywhere (e.g. a reputation system, or facebook, twitter, etc) You can't defend yourself from that anyway (and shouldn't, as it might be legit). Allowing a claim on YOUR identity means, YOU approve it. Again don't get me wrong, reputation systems should exists, which allow sellers to verify the credibility of a buyer, but this is outside of this standard, and might just happen in a peer2peer way by sending over reputation claims you collected over time, or referencing your identity AND a reputation system you are using (These two don't have to be publicly connected, as long as you can proof owner ship of both)

@MikeD123 I think you get it a bit wrong. The idea of claimTypes is more of the nature of properties of you, e.g. 1: biometric data will obviously means your a person and not a business. 2. address will show that you are based somewhere, means you have a physical address or reference point. We could add claim types for certain social media, but thats up to discussion.

If you want to verify a claim, you most likely will not look for the type, but for a specific issuer you trust, so you can generate the ID of the claim in advance e.g.:

keccak256(address issuer_address + uint256 _claimType) -> keccak256('0x123456789...' + 1)

will generate you the hash of the claim you can get using getClaim(bytes32 _Id). If the claim doesn't exist, you either look for another, or you have to manually verify that person, or not at all. If the claim exists, you verify the signature inside the claim, and see if that recovered key is still hold by the claim issuer.

As over time, there will be trusted claim issuer, like the US gov, or some decentralised service, people can always know the index of the claims they want to retrieve and even hardcode that in their smart contracts.

On the end in most cases we don't care about the data itself, but that somebody verified it.

Concerning the subTypes. I wouldn't go so detailed, as then people can know why sub type of claim was changed when, which could be a privacy leak. For some data it might make sense to give them a separate type, but for example for biometric data, just that might be enough.

To auto verify a person in front of you, the claim issuer for biometric data needs to have some bio matching services, or zero knowledge proof smart contracts, which can take some takes biometric data, and match it against their data set, and return true or false, should the data match the person claim data reference you gave them.

@buendiadas concerning the URI, it should contain the protocol like ipfs://..., or bzz:// or https://

@frozeman I am looking to engineer secure enclaves (keystone enclave perhaps?) + zkp for attestations at scale. Is this something that you are looking at as well?

Nathan Aw

@ivica7
Copy link

@ivica7 ivica7 commented Nov 19, 2018

It doesn‘t look intuitive to me that someone else is claiming something about subject’s identity. Isn’t it more natural that the subject states claims about itself and trustworthy endorsers are confirming these claims. Self issued claim would be a claim that has no endorsers. I also think for standardization purposes that it would be better to have separate registry contracts for seprate claim topics. This way the contract’s address is the topic.

@guix77
Copy link

@guix77 guix77 commented Dec 31, 2018

Concerning the topic numbers: http://schema.org/Person could be a good start reference

I like this proposal, but how could be map it exactly ?

Proposal 1

Mapping Schema.org > People => topic in the order. First property on the page is additionalName so = topic 1 and so on. But what if properties get added to Schema.org > People? And additionalName = topic 1 makes no sense.

Proposal 2

We define here a "manual" list for Schema properties that makes sense, like familyName = topic 1, givenName = topic 2, ... Maybe we can find another referential that already has mapped properties to integers, or that is easier to map.

Proposal 3

I like the Schema.org > People reference and I would prefer the mapping to be deterministic. Maybe we could just convert the schema.org property from ASCII to integer.

Example: http://schema.org/Person, givenName property

Storing it from UI to BC

  • g = 103, i = 105, v = 118, e 101, n 110, N 078, a 097, m 109, e 101
  • givenName = 103105118101110078097109101
  • in JS, we store it as a string to pass it as a BigNumber in web3: '103105118101110078097109101'
  • we call contractInstance.addClaim('103105118101110078097109101', ...)

This approach would allow (2^256 - 1) / 3 = about 10^25 triplets = up to 25 characters for properties.

Some properties topic IDs with this conversion:

  • givenName: 103105118101110078097109101
  • familyName: 102097109105108121078097109101
  • jobTitle: 106111098084105116108101
  • url (from Thing, can be the website): 117114108
  • email: 101109097105108
  • description: 100101115099114105112116105111110

For properties that have their first character ASCII code beginning with 0, we'll just remove the first zero:

  • additionalName = 097100100105116105111110097108078097109101 => 97100100105116105111110097108078097109101

This approach could add many other properties of other schemas, the only limits being:

  • that they should all have a unique ASCII name (which I'm not sure they have on Schema.org, but properties should be unique I guess)
  • that they should not exceed 25 characters (the longest People > Thing property is disambiguatingDescription and is already 25 characters)

The other problem with this approach is that it would consume a lot of topics ID distributed more or less randomly according to ASCII to integer conversion and that we have no more ranges for other custom topics not on Schema.org.

One solution could be to treat all those custom topics like if they were in Schema.org with a first ASCII character encoded in integer on 3 decimals but that is not on the alphabet, like for instance | (124).

Example implementation: https://github.com/guix77/erc735example

Example uses a helper module to convert property names from ASCII to BigNumber, and from BigNumber to ASCII: https://github.com/guix77/erc735js

@frozeman
Copy link
Contributor Author

@frozeman frozeman commented Feb 15, 2019

In light of ERC 725 v2, this standard needs a bit of re-work, as now it can sit separate from the ERC725 proxy account, in its own contract.

We would now need to manage the approver different, as well as probably add a subject to the claims.
It could also be transformed into a standard claim registry like #780, but with more a sophisticated claim structure.

@bitcoinbrisbane
Copy link
Contributor

@bitcoinbrisbane bitcoinbrisbane commented Jun 6, 2019

Seems to have a missing function before changeClaim method on the Solidity Interface example code.

@James-Sangalli
Copy link
Contributor

@James-Sangalli James-Sangalli commented Jul 10, 2019

Hi All, I like what this EIP is trying to achieve but think it could be better implemented. I discussed the idea of using a salted merkle tree here and I think it is more sensible because it preserves privacy and enables link-ability to the source e.g. drivers license -> DOB -> above 21.

@m1cm1c
Copy link

@m1cm1c m1cm1c commented Jan 6, 2020

Why does addClaim() return a uint256? Everywhere else, claim IDs are of type bytes32.

Does the plus symbol in keccak256(address issuer_address + uint256 topic) for generation of claim IDs symbolize concatenation or addition? If it symbolizes concatenation, that could be made more explicit. If it symbolizes addition, that's a bad idea to begin with. It might not be obvious to people implementing the interface that they need to check whether the resulting ID is already in use by a different issuer address.

@m1cm1c
Copy link

@m1cm1c m1cm1c commented Feb 2, 2020

If an identity contract, it should hold the key with which the above message was signed

Does that mean that the identity contract's owner should be the address used for signature verification? If not: How is the address / the public key specified?

@m1cm1c
Copy link

@m1cm1c m1cm1c commented Feb 2, 2020

I think that if the identity contract does not "hold the key with which the above message was signed" (whatever this means) anymore, rendering the claim invalid, anyone should be able to remove it. Not just the subject or the issuer. Maybe the standard should even specify a preferred mechanism for removing such claim automatically.

@drgorb
Copy link

@drgorb drgorb commented Jun 17, 2020

a claim should only be removed by the subject (the identity holder) because only they can decide what should be forgotten about them.

@drgorb
Copy link

@drgorb drgorb commented Jun 17, 2020

I would prefer to have an addClaim and a separate updateClaim function. It reduces the potential for confusion and error. When addClaim is called for an existing claim, the transaction is reverted. Same thing for an updateClaim on a missing claim.

@drgorb
Copy link

@drgorb drgorb commented Jun 17, 2020

I believe it is necessary to separate the revocation of claims from their update. While a revocation is a special kind of update, it MUST be available to both the subject and the issuer WITHOUT a permission. It MUST NOT be possible for the subject to prevent the revocation of a claim.

Arguably it is the only permissible update to a claim. If a claim is not current anymore, it should be removed and a new one should be added. The claimId MUST be unique. Indeed, if applications can trust that a claim can not changed (except for early revocation) they will not need to verify the claim each time it is read.

@m1cm1c
Copy link

@m1cm1c m1cm1c commented Jun 17, 2020

a claim should only be removed by the subject (the identity holder) because only they can decide what should be forgotten about them.

A claim's issuer should have the authority to retract his assessment. Besides: Your premise is flawed. The blockchain does not forget.

I would prefer to have an addClaim and a separate updateClaim function. It reduces the potential for confusion and error. When addClaim is called for an existing claim, the transaction is reverted. Same thing for an updateClaim on a missing claim.

addClaim() can do a perfectly good job at updating a claim. Your idea merely makes the interface fatter.

I believe it is necessary to separate the revocation of claims from their update. While a revocation is a special kind of update, it MUST be available to both the subject and the issuer WITHOUT a permission. It MUST NOT be possible for the subject to prevent the revocation of a claim.

Didn't you just say that only the subject should be able to remove a claim?

Arguably it is the only permissible update to a claim. If a claim is not current anymore, it should be removed and a new one should be added. The claimId MUST be unique. Indeed, if applications can trust that a claim can not changed (except for early revocation) they will not need to verify the claim each time it is read.

Couldn't you just store a hash for that purpose?

@drgorb
Copy link

@drgorb drgorb commented Jun 18, 2020

A claim's issuer should have the authority to retract his assessment. Besides: Your premise is flawed. The blockchain does not forget.

retracting the assessment is what revocation is for. A deletion makes the claim disappear from the current state.

I believe it is necessary to separate the revocation of claims from their update. While a revocation is a special kind of update, it MUST be available to both the subject and the issuer WITHOUT a permission. It MUST NOT be possible for the subject to prevent the revocation of a claim.

Didn't you just say that only the subject should be able to remove a claim?

revoking and removing are two very different things. A removed claim will not be returned by getClaim(claimId) whereas a revoked claim will.

Arguably it is the only permissible update to a claim. If a claim is not current anymore, it should be removed and a new one should be added. The claimId MUST be unique. Indeed, if applications can trust that a claim can not changed (except for early revocation) they will not need to verify the claim each time it is read.

Couldn't you just store a hash for that purpose?

Of course you can create workarounds. What is your argument for updating a claim instead of creating a new one?

addClaim() can do a perfectly good job at updating a claim. Your idea merely makes the interface fatter.

there are a few arguments for making the interface fatter:

  1. it should be clear from its name what a function does. At least the name should be changed to upsert (borrowed from Mongo) or similar
  2. it costs more gas to check for the claim's existence every time. If I know that I'm creating new claims why should I pay for the query?
  3. it allows a developer to rely on the fact that only their intention is carried out. I use add in order to create new things, update to make changes and upsert when I don't care
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.