ERC: Ethereum Claims Registry
oed opened this issue Β· 67 comments
EIP: <to be assigned>
Title: ERC: Ethereum Claims Registry
Author: Joel Torstensson <oed@consensys.net>
Type: Standard
Category: ERC
Status: Discussion
Created: 2017-11-29
Abstract
This text describes a proposal for an Ethereum Claims Registry (ECR) which allows persons, smart contracts, and machines to issue claims about each other, as well as self issued claims. The registry provides a flexible approach for claims that makes no distinction between different types of Ethereum accounts. The goal of the registry is to provide a central point of reference for on-chain claims on Ethereum.
Motivation
On-chain claims is becoming increasingly relevant as lots of different smart contracts might want to verify certain attributes about its users. However that is only one out of a very large space of use cases for on-chain claims. By providing a central repository for claims, developers are equipped with a common ground for experimentation. A standardized registry also makes claim lookup simple and gas efficient. Third party contracts only need to make one external call, no need for adding logic for verifying signatures, lookup identity signing keys, etc.
Specification
The ECR is a contract that is deployed once and can then be commonly used by everyone. Therefore it's important that the code of the registry has been reviewed by lots of people with different use cases in mind. The ECR provides an interface for adding, getting, and removing claims. Claims are issued from an issuer
to a subject
with a key
, which is of type bytes32
. The claims data is stored as type bytes32
.
Claim types
The key
parameter is used to indicate the type of claim that is being made. There are three ways that are encuraged for use in the ECR:
- Standardised claim types use syntax borrowed from HTTP and do not start with
X-
. The key is the hash of the claim type (eg,keccak256('Owner-Address')
) - Private types not intended for interchange use the same syntax, but with X- prefix. The key is the hash of the claim type (eg,
keccak256('X-My-Thing')
) - Ad-hoc types use 32 random bytes for the key, enabling allocation of new globally used keys without the need for standardisation first.
Standard claim types
New claim types can be added by making a PR to modify this table.
Claim type | Description |
---|---|
ERC780Example |
This is an example |
Registry specification
The ECR provides the following functions:
setClaim
Used by an issuer
to set the claim value
with the key
about the subject
.
function setClaim(address subject, bytes32 key, bytes32 value) public;
setSelfClaim
Convenience function for an issuer
to set a claim about themself.
function setSelfClaim(bytes32 key, bytes32 value) public;
getClaim
Used by anyone to get a specific claim.
function getClaim(address issuer, address subject, bytes32 key) public constant returns(bytes32);
removeClaim
Used by an issuer
to remove a claim it has made.
function removeClaim(address issuer, address subject, bytes32 key) public;
Type conversions
The value
parameter was choosen to have the type bytes32
. This in order to make the registry entries as general as possible while maintaining a very simple code base. However it is likely that usecases where other types such as address
and uint
etc. will emerge. Support for this can be added in various ways. We suggest that a library is implemented that can covert between various solidity types. This means that the registry itself keeps its simplicity. Contracts that need specific types can use such a library to convert the bytes32
into their desired type and back.
Deployment
After some discussion on the design of the registry contract it will be deployed and its address should be written in this document. This should include the addresses for the ropsten, rinkeby, and kovan testnets as well.
Updates and governance
In the future there might be new features needed in the registry. In order for such an event to be as transparent as possible the new features should be proposed and approved in a new EIP that contains the new contract code as well as a way of migrating any old claims if deemed necessary.
Appendix: Registry implementation
contract EthereumClaimsRegistry {
mapping(address => mapping(address => mapping(bytes32 => bytes32))) public registry;
event ClaimSet(
address indexed issuer,
address indexed subject,
bytes32 indexed key,
bytes32 value,
uint updatedAt);
event ClaimRemoved(
address indexed issuer,
address indexed subject,
bytes32 indexed key,
uint removedAt);
// create or update clams
function setClaim(address subject, bytes32 key, bytes32 value) public {
registry[msg.sender][subject][key] = value;
emit ClaimSet(msg.sender, subject, key, value, now);
}
function setSelfClaim(bytes32 key, bytes32 value) public {
setClaim(msg.sender, key, value);
}
function getClaim(address issuer, address subject, bytes32 key) public view returns(bytes32) {
return registry[issuer][subject][key];
}
function removeClaim(address issuer, address subject, bytes32 key) public {
require(msg.sender == issuer);
delete registry[issuer][subject][key];
emit ClaimRemoved(msg.sender, subject, key, now);
}
}
I think the submitter's identity should be recovered from a v
,,r
,s
signature rather than requiring msg.sender
be the submitter. I can imagine a claim issuer who doesn't want to interact with Ethereum, but is happy to sign a message and pass that over http. It would be good if this signed claim could be submitted by any party.
@alex-miller-0 The main reason to use msg.sender
is to benefit from ethereums signature abstractions. This allows users to implement other signature schemes in contracts and still be able to use the registry. By having the signature verification in the registry contract itself means that it becomes less future proof.
Aww man I liked the KeyGraph
and src,dst,key,val
nomenclature. Good innovation with updatedAt
though Edit: nvm looks like tau
existed too
Here's a bunch of context for people just catching up: uport-project/uport-registry#24
@oed That make sense, but it still gives me pause because this requires every claim issuer pay gas (maybe not in the future, but for now). Seems like you could still add something like setRemoteECDSAClaim()
. Not pretty, but I do think there are use cases that will be blocked by the gas requirement.
In any event, great use of Ethereum overall π
@oed can you put some example use cases? For me this just look like a generic key value store contract and no specific functions to handle claim(such as validate Claim) but I may be wrong as I am not so sure what kind of usecase you have in mind.
A comment from Pelle on Reddit has more context and use cases https://www.reddit.com/r/ethereum/comments/7gewn7/erc_780_ethereum_claim_registry/
@oed - I'm not sure about this statement:
A standardized registry also makes claim lookup simple and gas efficient.
Say I want to look up all claims made by an issuer
- I can't see that this is possible with the current contract and, although it could be added, it would be pretty inefficient. Also, if I want to look up all claims made about a subject - how could I do this?
Or is the model designed to be augmented by another form of storage that can be queried more easily, meaning the contract storage is used for arbitration?
@nmushegian I know you do ;) But I think that issuer, subject
makes more sense in the context of claims.
@alex-miller-0 setRemoteECDSAClaim()
doesn't really solve the gas problem either right? Someone who is intrested in publishing the claims would still need to pay for the gas for that function call. Then they could just as easily pay for the creation of a thin proxy contract that only allows to send txs to the registry if signed by a specific key. This could also be made into a factory that (in the future) uses copyof for gas efficiency. New factories could then be made for new signature types.
@makoto It is very generic! The goal here is to create something that allows for any type of claim to be issued. As you saw @pelle mention on reddit, the first use case for uport is to store the public signing and encryption key of identities. But other usecases include:
- User A claims that user B is a cool cat
- Exchange C claims that user A is a verified member of tier 3
- Contract D claims that user B has reputation X
The idea of a contract being able to make claims is very interesting. One could construct a contract that for example verifies a zero-knowledge proof and if it is correct issues a claim. So it should be possible to create a contract such that; if a subject has a claim issued by this contract, we can be sure that the subject is a European citizen without revealing which exact country, for example.
@lukehedger You are right, with this design you can't currently look up all the claims made by an issuer
or to a subject
from another contract. This can of course be done off-chain by querying the logs though. The reason we chose this design was that other contracts most likely will have to know the issuer
, subject
, and key
anyway, since there might be hundreds of claims about a speciffic subect
for example.
If there is a speciffic use case for what you are asking about you can of course augment it like you suggested. Good idea btw, had not thought of that :)
@oed Thank you for the clarification.
Do you expect entire Ethereum universe to put their claims into one contract (like ENS Registry contract), or each project (eg: uPort, Gnosis, MelonPort) to have their own repository like ERC20 does for their tokens?
@makoto This would be more similar to ENS where there is one central registry contract, rather then ERC20 which is just an interface. The reason for this is that the contract code itself has to be verified. In the case of ERC20 you just need to have the same interface.
- Can you give example use-cases? What will this be used for?
- Why use
bytes32
for key and value, instead ofbytes
? - It'd be a good idea to follow the lead of other standards, and reserve keys starting with
x-
as nonstandardised ones, while requiring a standards process for non-prefixed keys, to avoid namespace collisions.
Should EthereumClaimRegistry
be EthereumClaimsRegistry
(plural)?
If the function name is setClaim
the event name should be ClaimSet
rather than ClaimAdded
?
In terms of use case, I have something similar which could potentially replace with this Claims registry
https://github.com/makoto/blockparty/blob/master/contracts/InvitationRepository.sol
The above contract manages a set of a unique code which I use to invite a participant to register my event management smart contract (more detail is at http://www.noblockno.party).
I once thought about replacing it with ENS and I gave up because ENS value only allows certain set of record type (eth address, ABI, etc). https://docs.ens.domains/en/latest/implementers.html#writing-a-resolver
The ClaimRegistry is better suited because both key and value can be anything (in fact you don't really need subject
because you can namespace as part of a key just like you use Redis DB).
The big question is what is the benefit of mixing my party invitation data with Uport attestation data which are remotely related under the same contract?
in case of ENS, the more dapp/wallet and exchange implement ENS interface, it allows everybody to lookup naming service in consistent manner. In case of ClaimRegistry I am not sure what benefit brings.
The alternative solution could be to propose more generic ENS record type which Uport can make use of.
@oed My ECDSACall would solve the gas problem because someone else could submit a signed message. But you're right - this functionality could be abstracted to a second layer contract.
@Arachnid I like the use of bytes32
rather than bytes
because it keeps people from storing arbitrary data on-chain; obviously these would be hashes to the actual information you are referencing. There are also advantages to having a consistently sized key/value pair from a parsing perspective.
One immediate use I can think of is providing a hash of customer balances at a given timestamp that can later be verified by an auditor. This could be a hash of some data dump, a database itself, or a blockchain.
Another use could be for identity - someone could submit a claim that I purchased insurance for my car for 6 months. This information is persisted to their system and can be verified based on some lookup schema in this immutable key-value store. Once my insurance expires, they can revoke that claim.
Can you give example use-cases? What will this be used for?
Right now uport uses a similar contract to store public keys of users as a simple PKI. Other than that we will use it for storing claims that needs to be read and verified by smart contracts. It could also potentially be used to revoke off-chain claims.
Why use bytes32 for key and value, instead of bytes?
This was my initial thought, but it seems like retriving a claim couldn't be done by another contract then. Atleast with the current solidity version. For example, this does not compile. Am I doing something wrong here?
It'd be a good idea to follow the lead of other standards, and reserve keys starting with x- as nonstandardised ones, while requiring a standards process for non-prefixed keys, to avoid namespace collisions.
Sounds resonable.
If the function name is setClaim the event name should be ClaimSet rather than ClaimAdded ?
Good point, updating the example code :)
I might suggest another function,
function removeClaim(address issuer, address subject, bytes32 key, bytes32 value) public constant returns(bytes32);
such that the claim is removed iff the passed in value is also equal.
I might also consider returning the previous value on setClaim
and the proposed removeClaim
.
@devinrsmith What would be the usecase for those additions? (I don't have any strong feelings either way)
Added a function called setSelfClaim which allows the caller to not have to specify the subject
. Instead msg.sender
is used.
This is useful if you want to set a claim with a proxy contract which is also created in the same call, so you don't know the address beforehand.
What is the reason for only allowing an issuer to set a claim, but either the issuer or the subject to remove a claim? It seems inconsistent and could lead to potential unexpected outcomes.
For example, there was discussion on reddit about registering a claim that a particular address is malicious. You would not want to enable that malicious contract to unilaterally remove claims about itself.
@machinae Flagging an address as malicious contradicts the very notion of Self-Sovereign Identity, and claims logic. For SSI to work a claim has to be made that the address is safe according to the party.
I bet claim removal is for an erroneous claim only.
@machinae Can you elaborate? Since msg.sender
is used the signatures are verified by ethereum. What kind of validation are you talking about?
@oed I mean more like proof of off-chain validation of the substance of the claim itself.
Sticking with the self-sovereign identity theme, if I submit a claim that my date of birth is 01-01-1970, msg.sender
lets you prove that I am the one who issued that claim, but not that the claim itself is true. You would need a trusted third party that can check my DOB off chain to attest to the validity of the claim.
A simple idea for an implementation would be adding a third entity, validator
, that would attest to the validity of claims using off-chain data.
So you might have something like
function attestClaim(address issuer, address subject, bytes32 key, address validator) public;
which would record that a particular validator entity has attested that claim is valid.
This could fire off an event ClaimAttested
similar to the other events in the proposal.
The idea being that anyone can self-issue claims, and those claims can be confirmed by multiple entities, increasing decentralization and confidence that the claim is proven. Think of it as almost a multisig scenario for claims, where n attestations might be required.
validator in this case could be a government entity, employer, exchange, another smart contract, etc.
@machinae this could be done now by the "validator" calling setClaim with the same data as you (or anyone else) did.
proof of validation of substance of claim
One goal of this kind of spec is to add credibility to claims by letting specific parties validate the claims. If my neighbor claims I have a degree from Harvard that might not mean much, but if Harvard themselves have an identity then they can issue the attestation claiming I have a degree from there, and this would be basically a proof of the substance of the claim.
If the claim is date of birth, then a claim from a local government that this is my date of birth is a good validation. The best would be a claim by the physician that actually delivered me as a baby that I was born. My birthday would then by definition be the time stamp of that claim.
I have been following and reading the various ERC discussions for identity standards, and thanks to the above linked article decided to join the discussion.
An obvious use-case for this, that is being worked on by many already, is a registry for academic degrees. I am currently in the final stage of my master thesis around this subject, and have used the implementation of this standard for a Proof of Concept.
In this PoC, the claims are used as follows:
issuer = Ethereum address/Identity smart contract of University X
subject = Ethereum address/Identity smart contract of Alumni of university X
key = location of "keys" JSON file of University X (for example UniversityX.com/keys
value = Degree title (MSc/BSc + abbreviation used by University X of the study (e.g. BA for Business Administration)) + a context hash.
This context hash is the merkle root of a set of certificates that follow the Blockcerts standard (blockcerts.org/). Each leaf in the merkle tree is a certificate that represents a single verifiable claim issued by the University (e.g. leaf 1: grade A for course X, leaf 2: Grade A- for course Y. etc). These blockcerts are bundled together and send to the alumni off-chain. The alumni has an app that can be used for selective disclosure of these leafs.
Overall, great work. Personally, I believe that verifiable claims in all sorts of use cases /variations will be the "killer-app" for enterprises implementing blockchain.
Would it be an idea to make "subject" also of type "bytes32"? If "subject" is of type "address", it implicitly means imo that the subject is an entity/address in the Ethereum world, but there are use-cases where this is not so.
An example of another type of subject is the usage of DIDs as described in https://w3c-ccg.github.io/did-spec/ . An example of a DID: "did:example:123456789abcdefghi"
As another example, in the project where I am working at now, each claim about an identity is identified by a (hash of) a unique derived HDKey (partly based on http://essay.utwente.nl/71274/1/Baars_MA_BMS.pdf). Technically this fits within the "address" type, but maybe the "bytes32" is better, because it does not refer to an address in Ethereum.
FWIW, in this project we use the semantical concepts of RDF where statements are described as a triple <subject, predicate, object>. This fits very well in the described contract: subject = subject, predicate = key and object = value.
Overall, looks good π I especially like the concept of having one contract for all issuers. This will enforce that all issuers are using the same standard.
@jnr101 It's an interesting idea to use bytes32
instead of address
. I generally really like the DID format, but DIDs can be longer than 32 bytes I'm not sure how much value changing it provides?
The reason I like addresses is because that makes more sense for on-chain contracts that wants to read the registry. I guess converting between bytes32
and address
is easy, but that can just as easily be done off-chain.
First iteration of this is now availiable at uport-project/ethereum-claims-registry!
It's also deployed to the following addresses:
Network | Address |
---|---|
Mainnet (id: 1) | 0xdb55d40684e7dc04655a9789937214b493a2c2c6 |
Ropsten (id: 3) | 0x737f53c0cebf0acd1ea591685351b2a8580702a5 |
Rinkeby (id: 4) | 0xc9ed21ffcc88a5072454c43bdfdbbe3430888b19 |
Kovan (id: 42) | 0x7ed7ceb55167eb71e775a352111dae44db754c40 |
I would suggest using the same deployment method as #820. This method allows to have a single address in all networks.
It'd also be good to define a format for claim keys so people don't collide - maybe one prefix for keys registered in an EIP, and another for ad-hoc ones
I think it would be very interesting to have an historic history of claims. A function like getClaimAt
would be great. This could be very useful to know if a claim was valid some moment in the past. To implement it, you can use the same binary search technique used in MiniMeToken.
@jbaylina I like your idea but, when implementing it, you need to remember also that the subject
is by definition the sovereign over its own identity and therefore should be able to delete the whole history of a claim.
Another thing.
According to this article binary search starts being noticeably better after the array has a length of 64, I see a transaction history of a token growing way past 64 transactions, but in identity, I don't see a claim changing that much over time.
Maybe I'm wrong.
Any thoughts?
I would suggest using the same deployment method as #820. This method allows to have a single address in all networks.
@jbaylina will definately be doing this, super cool.
It'd also be good to define a format for claim keys so people don't collide - maybe one prefix for keys registered in an EIP, and another for ad-hoc ones
@Arachnid Yes I think that is a good idea. Sorry for not picking up on your comment regarding this earlier. Do you think it's best to do one prefix for registered and one for ad-hoc, or just have x-
as you mentioned before? I'm thinking just going with x-
is probably the easiest.
One thing that is worth noting here is that the key can specify what format of the value is. An example that we use is uPortProfileIPFS1220
. In this case the key specify that we use ipfs and which hash function (from multihash) we use, since the entire multihash won't fin in bytes32
. So it would make sense if I register uPortProfile
then I'm allowed to use any key which starts with that.
@oed Yes I think that is a good idea. Sorry for not picking up on your comment regarding this earlier. Do you think it's best to do one prefix for registered and one for ad-hoc, or just have x- as you mentioned before? I'm thinking just going with x- is probably the easiest.
I would suggest the following (or any subset thereof):
- Standardised claim types use syntax borrowed from HTTP and do not start with
X-
. The key is the hash of the claim type (eg,keccak256('Owner-Address')
) - Private types not intended for interchange use the same syntax, but with
X-
prefix. The key is the hash of the claim type (eg,keccak256('X-My-Thing')
) - Ad-hoc types use 32 random bytes for the key, enabling allocation of new globally used keys without the need for standardisation first.
What do you think about approving claims by others? E.g. Person A issues a claim. Person B can approve the claim is correct. Person C who only trusts Person B can look up that Person B approved the claim from Person A.
With the current implementation this can be achieved by Person B issuing the same claim as Person A.
Can you think of any scenario where Person A and Person B issue a claim with the same key but different values? Then the approval is not possible.
by setting every call to external
you will save some gas per transaction but that would mean that setSelfClaim
would need to be changed to avoid making an internal call to setClaim
:
function setSelfClaim(bytes32 key, bytes32 value) external {
registry[msg.sender][msg.sender][key] = value;
ClaimSet(msg.sender, msg.sender, key, value, now);
}
@Arachnid
Thanks, I think that sounds good. One question: Why would anyone use an Ad-hoc type over a Private type? Nothing prevents multiple parties to use the same private one together.
@Janther
How much gas would be saved with that? The solidity documentation says External functions are sometimes more efficient when they receive large arrays of data.
We don't have any arrays here.
@oed Must have done something wrong when I tested last time (I had seen some gas difference).
I did a full test just now on remix and there is no difference in gas usage.
There is a small win (40 gas
without optimization and 59 gas
with optimization) when implementing the setSelfClaim
instead of doing an internal call. The deployment is more expensive though.
Allowing the subject of a claim to call removeClaim seems to invite censorship. If I claim something about a subject I don't want the subject of my claim to remove it. The claim about a subject should stand on its own and carry the weight the issuer's reputation however weak or strong. A claim should be something others can attest to as well, strengthening the claim. An attestation is just a claim about a claim. This allows a claim to be assessed as to its validity by third parties that interpret the validity based on their own metrics (multiple attestations, age of claim, trust graph of attesters, etc.).
Self sovereignty still works without allowing a subject to remove a claim. If a subject wants to make a claim stronger they only need to attest to it. Claims not attested to by the subject would indicate the subject does not approve of or does not care. If a subject does not agree with a claim they can even attest to a counter claim that points to the original claim. This keeps the subject in control without allowing for censorship.
I feel strongly that removeClaim should be allowed by the claim issuer only and the subject should use other means to attest, validate and expose the claims they agree with.
@dwking2000 I don't really have a strong opinion either way anymore. However I think for many use cases though there will be issuers that are trusted so it wouldn't matter if the subject issued a counter claim.
However I think my major concern is the "Right to be forgotten" law in the EU. I know that the claim is still retreivable through the logs, but it seems less troublesome.
@oed "Right to be forgotten" laws are complex and beyond the scope of the EIP so we should probably leave compliance of data removal to the implementor. Anyone opting into a blockchain claims system should either waive their rights to removal of data or agree to storage of claims in some mutable data store (off chain). Allowing the subject to 'remove' only self-claims might be useful and allows for schemes where the subject receives a request to self-claim the data in the request and then the requesting party would add attestations 'verifying' the self-claim as correct or true. In this case the subject would be able to remove the self-claim at some point making future attestations against it impossible, but "because blockchain", any previous claim and attestation data would still be readable. Other solutions preserve sovereignty might involve zero knowledge proofs or proxy re-encryption (such as proposed by the NuCypher project).
@dwking2000 Thanks for your input. I'll go ahead and remove the ability for subject
if no one else have strong feelings for it being kept there.
Made some updates to the proposal:
- Claims can now only be revoked by the issuer, as per suggestion by @dwking2000
- Claim types are now standardizable, as per suggestion by @Arachnid
- Claims can be added with raw signatures, as per suggestion by @alex-miller-0
@dwking2000, @oed. I think this kind of policy discussion (e.g. "whom do we allow to remove a negative claim?") cannot have a definite and consensual answer.
This kind of dilemma arises from the fact of having a central contract in the first place, which is why I'm very dubious about this EIP's approach.
One possible way I'm thinking of (but there are probably more clever ones) to resolve this centralisation problem would be to have spawnable registries -- with varying policies -- and a signaling method to point to them from self-sovereign contracts.
hey @davux @dwking2000 @oed, also have been thinking about the removal of negative claims and other challenges of a central registry contract. These issues seem like something that justifies multiple registry instances. Also unsure about the UX of squashing all claim data into a bytes32 key/val mapping. A richer claims interface might be possible with a federated registry approach. Would love to know your thoughtsβhave been putting together a prototype of sorts! :)
@davux @kern @oed I should be able to make a claim and not have it censored (removed). This is already enforced by the blockchain, so in some respects removing a claim is a moot point except to save space and computation (gas). There is a need to signal a claim is not longer valid according to some criteria. UIs or other contracts can filter or derive meaning (reputation) from that. Given that, I can conceptualize several types of registries.
- a 'centralized' canonical registry that should not be censored or curated, e.g. ENS
- a curated registry that is intended to be 'censored', e.g. a TCR
- a personal (sovereign) registry that only I can censor, e.g. a self claims registry
- linked registries, or registries with linked claims that make claims about other registries or claims
I assume the sovereign registry will be curated by the sovereign entity, and that a canonical registry can in effect be curated by linking claims (attesting to validity or status of existing claims)
The power of linked registries or linked claims is where I see solutions that are interesting. I should be able to make a sovereign claim (which I can revoke at a later date) and expose that for others to attest to. In many cases this self claim would be a request from some other entity that needs to attest to the claim. For example, you send me a claim such as 'IsMember 42 of the l33th4x0r club' requesting I enter it into my sovereign claim registry. You then attest to it as the authority. If I don't pay my dues you remove the IsMember claim in your curated club registry that links to my claim. As the club curator your registry is the authority on the membership status but to be truly believable it would require my acceptance first via the self-claim. I can also imagine linked claims being made that are encrypted but verifiable by specific parties. This allows for 'opt in' claims and gives individuals the ability to expose and self-censor. Further, I can see individuals setting up policies that auto-accept certain types of claim requests or claim requests from whitelisted entities.
I think the problem we are struggling with is the concept of a single central canonical registry when it could be an ecosystem of registries and claims that attest to other claims building out trust graphs.
@oed description for removeClaim
still mentions that subject can remove a claim about self, while in implementation code it's no longer possible.
Being an open registry, the data set (key, value), workflow (claim pending, claim issued, expiration, replacement, update, revocation), semanticsβ wasn't defined yet. This clarity affects the value of the registry, akin to ftp not being as valued as a SQL interface. At the minimum, do you consider adding expiry? I would argue that the use-cases not depending on claim's expiry is not many.
To provide clarity multiple features are needed. e.g. localised (translated) value, set of values (telephoneNumber
can be more than one), set of attributes (e.g. my authentication key, my encryption key as a combined set). Hashed value (instead of actual string value in value
parameter), the type of hash (if keyed hash to counter preimage attack, how to generate the key etc) etc.
In most case, an event of claim
resulted in at least 2 attributes - the pubkey/address the claim is associated with, plus one attribute for each claim statement. These expire together, gets revoked together. That is, in most cases, a claim is not a key-value pair but a dictionary.
β Speaking of semantic, say, the key being "ecdsa pub key" and the value being a public key. What does that mean? There are 2 typical notions: "the subject has, among others, this key"; "the subject is identified by this key". But other cases exist: "I propose the subject has the key (apply for a claim)"; "I know the subject has the key (testify a claim)"; "I recognise the subject has the key (providing context)" etc. If you think I am making the problem look bigger than it really is, compare it to TLS's CSR/DV/OV/EV differences.
Regarding the use of HTTP header style - how do you consider the good old X.509 object identifier? After all thousands of attributes and their meaning is defined on a semantic level. e.g. there is no address
but rather country
, state
, locality
, street
, buildingNumber
etc. Rather well defined with the long-term consistency in mind since signed X.509 data can't be changed. (That is true even before blockchain.)
There is a huge privacy concern: the more claims there are about a subject, the less privacy the subject enjoys. This works to the advantage of detecting fraud (user 0xxxxx is a scammer) and disadvantage to heavy users.
For example, a subject who, as claims show, to be of 18 years old in order to buy a beer, to be of a non-US citizen in order to participate some ICOs, to be of a Computer Science graduate to enjoy alumni club membership, is likely identified and matched to the exact person. (3 connection is all you need in a social network to de-anonymous a person). The more the subject refers to this contract when calling other contracts which call this contract's getClaim
, the quicker it gets linked to his/her real-world identity. Simply assigning these claims to different addresses of the subject (e.g. by key derivation) without additional treatments invites drawbacksβ .
I am a bit surprised my post is the first to mention the word "privacy". Even with the privacy concern, the use-cases that demand entire public verifiable claim sets, e.g. ATL (referring to things like Adobe Approved Trust List), might still be a good fit for this ERC.
β https://github.com/alpha-wallet/ethereum-attestation/releases (I'm one of the authors)
@colourful-land The right solution for correlation issues is managing multiple identifiers. A famous system that uses that approach is Bitcoin. Another one is Sovrin, based on Hyperledger Indy.
Hi guys,
Are there any thoughts for off-chain claims that can be selectively broadcasted?
Example: say we want to distribute a reward between many users.
One way to go about it is that the organisers will make many txs to publish claims for winners (the claim is that a particular user is a winner).
Another possibility is that the organisers sign claims and publish them off chain. The winners can send those claims to the contract, each user on his own, to get the reward.
Example 2: a user has an off-chain asset score that a 3rd party can issue as a claim (For example a platform that connects to his various wallets and exchange accounts to fetch balance data).
The claim has a timestamp and the said score.
The company doesn't broadcast the claim since it has many users and it will cost a significant amount.
Instead it publishes the claims off-chain to anyone to see. The user can broadcast those claims on his own.
Given a claim can now only be removed by the issuer, what is the need for the address issuer
parameter on the removeClaim
method?
Hi @wilfred-centrality, I've got a similar impression that the issuer address is just a leftover after the recent refactor and I've removed it from my implementation.
I'm also curious what do you (@oed, @machinae, @dwking2000) think about the simplest way of attesting/validating claims by issuing a claim with exactly the same data. I prefer that option to one, with referencing the original claim in an external validation contract because there is no need to track updates, as the the attestation is automatically falsified if the author of the original claim change the content or remove the entry?
function approveClaim(address issuer, address subject, bytes32 key) public {
bytes32 value = getClaim(issuer, subject, key);
registry[msg.sender][subject][key] = value;
emit ClaimApproved(msg.sender, issuer, subject, key, value, now);
}
function isApproved(address approver, address issuer, address subject, bytes32 key) public view returns(bool) {
return registry[issuer][subject][key] == registry[approver][subject][key];
}
(https://github.com/alice-si/contracts/blob/claims-registry/contracts/alice/ClaimsRegistry.sol)
Hey @jakub-wojciechowski and everyone else on the thread. I'm no longer active with this ERC since I left uport, and it seems like it's not on their priority list either. Sorry about that.
If you or anyone else would like to champion this ERC please let me know!
Basic Question : Is this proposal (and discussion thread) the same as contract EthereumDIDRegistry {} that is currently in use by uport project code ?
is uPort not using this anymore?
ERC1056 Adds a second verification method with its xxxWithSignature methods. This way, it's possible for an issuer to be an off chain entity. The caller to the method is a "relayer" which is only used to send the claim on chain.
I think it's very appropriate here too.
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.
This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.
Is there currently a way around me having to Pay for Approvals when I am offering a claim/airdrop option to like 10k addresses? A way for me to not pay $5-$10 in fees every time someone wants to claim the coins i am offering?
Is there currently a way around me having to Pay for Approvals when I am offering a claim/airdrop option to like 10k addresses? A way for me to not pay $5-$10 in fees every time someone wants to claim the coins i am offering?