Last Notes
Same here. There are minimum holding periods before I can move crypto I have purchased to self-custody. It's not really a problem in principle with the small amounts I'm transacting in, but there are counterparty / clearing risks that would bug me with larger amounts. Also it's annoying that I can't just buy it and use it right away. I guess I should just make sure to always keep some at hand for everyday use. Just a matter of getting organized.
Yes, I had a terrible time trying to get ETH for testing. I actually don't have any especially good way of getting BTC either. Other people seem to have better channels for acquiring cryptocurrency. When they talk about it, I always sort of wonder where they are getting it from.
Also if you'd ever like to take a closer look, please feel free to log in and poke around. I've put your pubkey on the allow list for the identity features, so you should be able to access these. For an initial "tour guide" please see below:
#nevent1q…lh57
Yes, you may be thinking of OpenTimestamps. And Inkan does in fact use OpenTimestamps to timestamp individual Nostr events on Bitcoin. Inkan only works when there is proof that a signed version of an event existed as of some particular time, and this proof is provided through BTC timestamping using OpenTimestamps.
However, the declarations of "delegation of signing authority" and "revocation of signing authority" that I mentioned also need to be timestamped. Unlike in the case of regular Nostr events, this timestamping needs to be done in a manner that allows you to later retrieve the substantive content of the declaration by querying the blockchain. Bitcoin timestamping does not allow for this, at least not in any straightforward way, because what's actually recorded on Bitcoin is a *hash* that is the root of a Merkle tree. And you can't extract the content of the timestamped items from that hash. Ethereum, on the other hand, has easy mechanisms for recording these "delegations of signing authority" and "revocations of signing authority" in a manner that makes their content queriable / retrievable.
So in both cases, the ultimate purpose of using blockchains is to provide timestamps. The reason Ethereum is used for delegation and revocation declarations is that Ethereum provides straightforward methods for retrieving the content of these declarations from the chain.
"I can't say I know enough of the technical stuff to know how well this can work in practice."
I made the prototype to find out. I've been using it for a few months and it works well enough for me so far.
There's tons of rough edges, but I don't currently see any insurmountable obstacles in principle. If anyone sees anything fundamentally amiss, please point it out. That will save me a lot of time.
You need some sort of blockchain. It doesn't have to be Ethereum, but it seemed easiest to implement it through a smart contract. In other words, I'm not especially wedded to Ethereum at all, I just needed a blockchain to implement a proof of concept.
The reason you need a blockchain is that there has to be a decentralized and objective way of recording the *time* at which a pubkey delegates signing authority to another pubkey / revokes signing authority from another pubkey. That's what allows you to then create an objective historical record of the periods during which a pubkey delegated signing authority to other keys. So Ethereum is basically just being used as a timestamping system.
Incidentally, Inkan also timetamps individual events on Bitcoin using OpenTimestamps. But the recording of delegation / revocation declarations is a little more complicated than the recording of regular events - it may be possible to do it on Bitcoin, but I haven't figured out how.
Once you have both (i) timestamped delegation and revocation declarations and (ii) timestamps for individual events recorded on blockchains, that gives you all the raw materials to implement the following basic idea:
If an event was signed by key pair Y at a time at which key pair X delegated signing authority to key pair Y, then the event is attributed to key pair X.
That's what Inkan does.
That's why we need a key rotation system that allows you to replace keys that have been lost or compromised. Prototype below.
#nevent1q…hqmf
Agree, I think it's using public key cryptography for authentication. That's the core of the protocol, and that's what makes it distinctive and liberating.
This feature shouldn't be played down when introducing Nostr to "normies" (whatever exactly that means), but instead it should be highlighted. We should make clear that Nostr requires a bit of learning, re-thinking and adjustment of one's practices.
It requires an effort, but once a person has made that effort they then have a sense of ownership in the new skill they have acquired. And I don't think any of this stands in the way of broad-based adoption. It's still much easier to learn to manage a key pair than, say, to learn skateboarding, or become a vegetarian. People can be quite motivated once they put their mind to something.
If the above explanations aren't sufficiently helpful, please feel free to let me know. If the product gets misunderstood due to my not explaining it properly, I'm not doing my job.
Thought I'd be preaching to the choir, but it turns out that isn't so.
I guess the attestation events can have whatever semantics I want them to have in the intended context of use. For example, if I intend the attestation event to mean "I audited the information in the reference event against what's recorded on the blockchain and the audit succeeded" or in the negative case "I audited the information in the reference event against what's recorded on the blockchain and the audit failed," then the attestation event can have these meanings.
I have a feature where the client uses only timestamp / delegation info events that were signed by "trusted pubkeys." The trusted pubkeys are settable by the user, or otherwise the client reverts to reasonable default settings.
One could maybe expand this filter to also accept events that have an attestation from a trusted pubkey, regardless of whether the event itself was signed by a trusted pubkey. And maybe also have a feature that causes the client to audit an event against the blockchain if a trusted pubkey attests that it tried to audit the event and failed.
It would be nice if the attestations can play that role - I'll take a closer look. This would obviate the need to implement "audit" events myself just for my particular use case.
I wonder whether there may be a use for these attestations in connection with the 31045 timestamp events or the 31055 delegation info events that are produced by Inkan.
When I implemented these, I was thinking of adding an event type that gives other pubkeys the ability to attest that they have confirmed the correctness of the content of the 31045 / 31055 event against what's recorded on the blockchain. I actually also thought of implementing an event type that gives other pubkeys the ability to also disconfirm the 31045 / 31055 events, i.e. to state that they tried to confirm what the 31045 / 31055 event is saying by checking the blockchain but were unable to confirm.
I ultimately decided against implementing these additional event types since it seemed to create epicycles that seemed unnecessary. Rather than attesting to the correctness of the content of the target event, it seemed easier for the auditing pubkey to simply republish that content itself. In other words, rather than publishing an event confirming that the timestamp information in a 31045 event is indeed recorded on Bitcoin, it seemed easier for the auditing pubkey to simply republish that information in its own 31045 event.
Still it feels like there may be a use for these attestations. Maybe.
What's the single most marketable feature of Nostr?
I mean the thing with the greatest potential to engage a person's attention and hold their interest, and something that is sufficiently distinctive as compared to other offerings to make them want to re-use Nostr rather than something else.
My answer: It's the practice of deliberately self-authenticating on the internet through public key cryptography on an everyday basis.
The idea of decentralization, relays, etc. are just consequences of that practice. What is basically empowering about Nostr is that it provides mechanisms for distributing content that has been deliberately authenticated by the user with a digital signature from a private key.
If that's right, then the tendency among developers to try to hide this authentication mechanism from users rather than highlight it is very unfortunate. It's hiding precisely the thing that makes Nostr interesting. It's not a good way to market something.
Took the night train through Transylvania. Just got off. The trees are all ready for spring here.
There is no official spec, but see below for some previous discussion and explanation of how it works.
I think the best way to understand it is to log in and access the identity features of the client. This allows you to observe the existing permanent identities and click through the delegation / timestamp backup data that supports these identities. I think these backup data are sort of self-documenting.
I've put your pubkey on the allow list for accessing the identity features of the client at https://www.inkan.cc. The third note below includes an initial "tour guide" that helps one get started / oriented. If you're interested, please log in and take a look, or please feel free to comment or ask questions. I'm happy to explain or talk about any aspect of it.
#nevent1q…ya9r
#nevent1q…f4cd
#nevent1q…rgs2
I just found this in your book:
"Key rotation is something that we have to figure out if Nostr is going to succeed in
the long term. There have been some proposals, but none of them have gained
enough traction to be implemented. Key rotation is an inherently difficult problem,
because you need to borrow the reputation of the old key in order to validate the
new key in such a way that an attacker wouldn't be able to do the same thing."
I wanted to let you know that Inkan implements a fully functional key rotation system. It's a prototype but it works. I've been using it for several months.
Please see below for screenshots, which contain many hints as to how it works. Happy to discuss, explain, address scepticism etc. ...
#nevent1q…dmgj
This sounds like it still requires a fair amount of supervision and micro-management.
I guess it depends on the task. At times I've been astonished by its independently solving what seemed to me complex novel conceptual tasks, and at other times it produces sort of diffuse / unfocused outputs that leave me underwhelmed.
I should probably take comfort from the fact that I seem to be needed full-time to review and give directions for it to produce something useful. That's my value add. At the same time I wonder whether the fact that I'm still so involved in the process means that I'm just using it inefficiently.
Having it work on multiple jobs at once does sound like a way to speed things up a lot. The trick is to be able to supervise these. Even with the way I'm doing it now that doesn't involve all that much multi-tasking, there's a pretty intense cognitive burden just trying to hang on and understand what is being produced and thinking of next steps.
I'd be curious about the quality of the output. In my experience so far, even when programming with AI, I have to stay constantly engaged to give instructions, review, discuss, revise, etc. Otherwise things would go in a completely different direction from where I want them to go. In other words, it remains a full-time job for me. It's hard to imagine that, in its current form, AI could independently produce something I'd really want without this constant engagement and supervision from me. But then I haven't seriously tried to use agents. So I'm curious as to the quality of the output they are capable of producing if left to their own devices.
Set up my first instance of strfry.
But I'm a bit confused about plugins.
The way plugins.md talks about "event-sifter plugins" sounds a bit as if there are are plugins *other than* event-sifter plugins. Is that so?
Or are *all* strfry plugins event-sifter plugins, i.e. that's the only type of plugin there is?
(... or correct the sentence in the NIP draft ...) 👾
I agree that the signature is recorded on Bitcoin in the sense of its being (together with the event_id) merkle-included in the hash that's placed in the relevant Bitcoin block. Of course you cannot re-construct the signature from the merkle root that's recorded on Bitcoin.
But the above does not explain what purpose would be served by "appending" the signature to the OTS proof.
I mean an OTS proof in human-readable form looks like the below - what would be achieved by appending the signature to that?
https://image.nostr.build/7aca480ae01ce0eaedeb0b5e767137155679cf049a2b6d12c1c30c3e9cfa1e02.jpg
https://image.nostr.build/404d82af2916e35be15da1deffa18bfb0161523c78e6a015dd037f1a828ea7fd.jpg
https://image.nostr.build/fe384e45a0ea29037d141715ce045fd681dd7498c368a4e53c2ad64244adff29.jpg
https://image.nostr.build/879b5c65a524af4031a2bb969cc0c13bb18331faa5e186abe8d8c75628408ab2.jpg
But what is the purpose of slapping the signature onto the proof?
I mean nothing further gets recorded on Bitcoin or otherwise proven by appending the signature to the proof, as far as I can see?
So why would one want to do so?
The notes below have some initial discussion of how Inkan works. The screenshots in the first note contain useful hints indicating what exactly it is doing.
I think, however, that the best way to understand it is to log in and access the identity features of the client. This allows you to observe the existing permanent identities and click through the delegation / timestamp backup data that supports these identities.
I've put your pubkey on the allow list for accessing the identity features. One of the notes below includes an initial "tour guide" that helps one get started / oriented. If you're interested, please log in and take a look, or please feel free to ask questions, express scepticism, etc. Happy to talk about anything related to it.
#nevent1q…j79t
#nevent1q…wr8s
#nevent1q…dmhu
#nevent1q…q0ge
#nevent1q…3lcs
I'm not completely following these two bits:
-- "you just add the sign to the merkle proof, extending it 1 step"
In what sense can one manually "add" a signature to a merkle proof? Not sure how this is supposed to work.
-- "The proof still resolves to the event ID"
If, as you seem to stipulte above, you "submit the hash of the id-+sig", then the proof will not resolve to the event ID. It will resolve to a hash of the id+sig. Neither the ID nor the sig can be reconstructed from that hash. However, if you already have the id+sig, you can reconstruct the hash from these.
As for this:
"Side not on that; when comparing times, the time of the original event might be later than the time of the block the proof for that event refers to, because blocktime is fuzzy, so people should take such edgecases into account."
Agree that the target event's created_at being later than the time of the block that encodes the proof is not a problem.
The only problem is if the time of the block is much later than the created_at of the target event.
In Inkan, I let users manually set the maximum permitted time differential between the created_at of the target event and the time of the block that records the event. The default setting is 4 hours. If the time differential is greater than that, the target event gets filtered out.
Actually the signature is *not* in the proof, and you can't extract it from the proof. Only a hash of a string that combines the event_id and the signature is in the proof. Including the signature in a tag is not redundant.
To verify that the proof in the content field of the OTS event is consistent with the information provided in the tags, you do need both the "d" tag for the target event ID and the "s" tag for the target event signature. Or otherwise you'll have to fetch the target event to inspect its signature, which can under some circumstances be inconvenient.
I wish I had realized these things earlier while working with these events, would have saved me a lot of hours ...
Thanks, I think including the signature will be a crucial improvement to NIP-3.
FYI, for the example 31045 event that I pasted below, here's the string that was hashed for timestamping:
{"ID":"dbe68638908a66bb601f681b5a92a41d9fd9683fb97330a1f6e7f8fe687b4277","sig":"88a9c8fa5dd283ecbd279b4fa685e52538a56023e5b156888101e3bc110df10f10e18cc50929dc26c4357b8e1508eebc0690da6159bf29882f1233e2821efd2f"}
And here is the hash that was timestamped:
17c8b1d66c0d8d28b5c774036968804cb146d45785370a94cd43360f0ae0d169
You can verify this using the OTS proof in the content field of the event. If you're interested, I'm happy to send a quick script that produces this string and the hash from a given event_id and sig pair.
In my above list of tags that I recommend be included, I had forgotten to mention one: I think an s-tag for the signature of the target event should be included as well. This is necessary to be able to verify the "internal consistency" of the OTS event without needing to fetch the target event. The 31045 sample event I sent you includes this tag.
A few further thoughts on including p-tag, c-tag, s-tag, b-tag, t-tag : While working on Inkan I was frequently running into situations where I needed timestamp information quickly without fetching the target event and without doing a verification against Bitcoin. I realized that, in some circumstances, you can make limited trust assumptions regarding OTS events that are signed by trusted keys. Often you will trust the signer of the target event already to some extent, and if the OTS event is signed by the same signer, you can tentatively trust the content of the OTS event to a certain extent. For that reason, reading info like bitcoin block and bitcoin timestamp directly from tags in the OTS event can be quite helpful in practice in certain situations. And if there are any doubts as to the correctness of that information, you can always audit it against Bitcoin.
FYI, here is an example of an OTS event that I think has a genuinely useful shape:
{"kind":31045,"id":"7093fe9f8c41bbb8164400b02602692bd231779683aed2df4015d35cf6983223","pubkey":"d1a61498f4b1dc26df0becd1a3e9e88f355fb614b771e8b5b277d0ff99a82a23","created_at":1773959239,"tags":[["d","dbe68638908a66bb601f681b5a92a41d9fd9683fb97330a1f6e7f8fe687b4277"],["p","d1a61498f4b1dc26df0becd1a3e9e88f355fb614b771e8b5b277d0ff99a82a23"],["s","88a9c8fa5dd283ecbd279b4fa685e52538a56023e5b156888101e3bc110df10f10e18cc50929dc26c4357b8e1508eebc0690da6159bf29882f1233e2821efd2f"],["b","941226"],["t","1773885646"],["alt","Complete Bitcoin Timestamp"],["c","1773869515"]],"content":"AE9wZW5UaW1lc3RhbXBzAABQcm9vZgC/ieLohOiSlAEIF8ix1mwNjSi1x3QDaWiATLFG1FeFNwqUzUM2Dwrg0WnwEJqGZ+Q8rtYicUfEAW5jkT8I8CB8KXAv2mx0tQeLRWlZbL+kbJD6Ssxx4UrsMG1JtNeVzQjwCLOXttmKfifZCPAQ9UNbNUqqIUotzkiYUwu18gjwIMb81Y7BHsiD6bU8J3rGgosReKIpWZ78B2p8g0cC6qTZCPAgtabc7DMwqS1WLAy2OSaWKkUtkg8r34CgvKwlcVwVCYsI8CCSX0Z2KX7lq/OFyrcdZ0VbVfrMXqjnDMKQe68VTfB71AjxBGm7VFrwCOfo3bNvvtLu/wCD3+MNLvkMji4taHR0cHM6Ly9hbGljZS5idGMuY2FsZW5kYXIub3BlbnRpbWVzdGFtcHMub3JnCPEg2mZxBLwldRmJuuB21O0dKjsWofBWf+iwZGTnepTJfAYI8SATG/+UVekcsl3ctl6P/WpxlgiiJzWY2hbrdphFdieFEQjxIFjLlCaepfhN+V8DLt0YR3StDhipbg2CysJ4KPXik0C8CPAg0i7rEsb2vhLM4aArpzd5/AdzZw77ohKNRrJp5k6FuZAI8CAOlXet5AnHEr0Bbj03yJEuoE2vE07KYzzN66o5gNZg+gjxIK5RQVFLDfbf4rFYEFti8w1ZuvsnXm9OHU858GQlXZ+fCPAg9yDD1lmTqLNtNF8LyEsv/4rlrTixXOGemd95xkj1SIMI8SA5qNPArCPbagMK1SZcqOlZ1DIIx4gBqODIFDkHPlFc9QjwICC4oOB2zpJV6Dld2tqfKgDty5lLKkAtv5Qp/F+Oj9pkCPAg+CotBs1A7T/29J+wx0qyk0lpKJ13o2wbKkVYq3zlDGwI8VkBAAAAAQtrFQrxPs1mMb5QvPQggkThTuO35P4Z5BmBJ0GPCSUzAAAAAAD+////AmrTAQAAAAAAFgAUKeXwHpjozmyTVzqFtvo+hN6fdJcAAAAAAAAAACJqIPAEqVwOAAgI8SDlO0E2ZEReuEAXK64wU4gCtlACyaeWh5fJIzJFEolvJwgI8CDPx2heltL2U7BGCh/fubw9ZrsMfaT7EL92dwEfR1/CrwgI8SAUUtj8gA6ZEaJbiEAQYeDTPy7utv7SR1qcSsbZw9VWmggI8CDxMRe7nTdYmw4s+5LegP2Ys79vcqzowpBwxxI7pobpBggI8CADsy2twW7hhOWeH4wOPQETd83gIgm5RA8u6B5pWJ3bUAgI8SA6LixY6ofZMVzQBV0x6bG+nVOzVK1vyhZr9ej5iazYkAgI8CC7EpcskiXBYFW53WhYjwbCBC8T9qgUFKOE/ESO0WPU6wgI8SAtfcDaUyUnguG2MSzQwMKS0ha8FpU8BoDG7hK7DqEGYQgI8SBn3y+8o3STgJYcwd3fVa2x0uqBbYlao5g3CmLCfSq/iwgI8SA2sVBmSpaKZ2NPUn+dvoZEb0olcrvxF2eTLBV8uE10KAgI8SCtSpu38MlirqgD/dQxVOlYtzGjV/VyCf6yZHINuW1BVQgI8CBBIrMQvkQOzs4H6Huhuu6aSO24eMoq6wnWqj4RDabOLwgI8CBvE1xbeLllbcHoy6YdR5HUOgh8sCDp18jJCjmROp36RQgIAAWIlg1z1xkBA6q5OQ==","sig":"2aa6c46117b27171a5aab7e72266ec603402746cea74ab83ebf467d6ad4589b629e1640b94ae55a552aed6674fd098c686d1930bca8464a68ba8ffe2cc27891b"}
If NIP-3 is going to change, the most important thing to incorporate into the updated specification is that the item that gets timestamped must include both the *event_id* and the *signature* of the target event. I think including the signature is quite crucial. See below for discussion with @npub1gzu…a5ds about this issue.
The ideal shape for an OTS event should also include something like a p-tag for the pubkey of the target event, a c-tag for the created_at time of the target event, a b-tag for the bitcoin block that anchors the timestamp, and a t-tag for the time of that bitcoin block.
I'm using OTS timestamping extensively as part of the Inkan key revocation and replacement system. The above is what I've concluded is needed after a lot of experimenting.
#nevent1q…zw87
In other words, I disagree with the following sentence in your NIP draft:
"In decentralized systems such as Nostr, there is no [...] mechanism that can conclusively determine identity continuity after key loss or compromise."
Such a mechanism exists. It's been implemented at Inkan.
Another script is now up on the Inkan website. This one lets users check a given Ethereum block directly to see which Inkan declarations were actually recorded there, rather than just taking the client’s word for it. The output also includes transaction hashes and other on-chain details for anyone who wants to cross-check further in a block explorer. It’s again in the spirit of making Inkan easier to audit.
You can again download it under Settings >> Inkan Management Utility.
FYI, there already exists a key revocation and replacement mechanism for Nostr. It is fully implemented at Inkan.
It's a prototype and has rough edges, but it works. I've been using it for several months now. It's open for testing - you can try it out now if you like. See below for screenshots.
#nevent1q…j79t
I’ve added a Python script to the Inkan website that parses the signed Ethereum transactions produced by the Inkan Management Utility.
The script should be useful for anyone who wants to independently inspect / audit what these transactions encode.
You can download it under Settings >> Inkan Management Utility.
I would have offered Inkan, but it's not fun. It is however unique.
This is useful for detecting compromised keys. If you've created an identity with Inkan, you can then revoke the compromised key and replace it with a new one, without losing your followers.
Key rotation is already a reality. At least in the form of a prototype I've been using for the last two months. See below.
#nevent1q…j79t
Actually it's all about carburetors:
https://www.youtube.com/watch?v=EhEboKJY_wo
とても懐かしい。また日本へ行きたくなった。来月行ける可能性がある。
Fair enough - I think I need the signatures for my purposes, but there may be other uses of timestamping where they are not needed.
If both event_id and signature are encoded in a Bitcoin block, you have information about the time at which the signing of the event took place. The act of signing must have taken place prior to the creation of the Bitcoin block.
If you encode only event_id in the Bitcoin block, then the block does not give you any information about when the event was signed.
So when you say that "the id contains all necessary stuff," I'm noting that the id does not contain any information as to whether or not the event has been signed.
I think including the signature records an important additional piece of information.
Take an event containing Odell's pubkey that says "Good Morning."
Suppose you find that the event_id (but not the sig) of that event has been encoded in a Bitcoin block dated time T. Then you know that, at some time prior to T, someone must have created an event of that form.
But suppose that you find that both the event_id plus the sig of that event has been encoded in a Bitcoin block dated time T. Then you know that, at some time prior to T, Odell said "Good morning."
The management utility allows users to create (x) key pairs and (y) Ethereum transactions.
The Ethereum transactions fall into three types, namely declarations of (i) delegation of signing authority, (ii) revocation of signing authority, and (iii) permanent invalidation of a key pair.
The first type of transaction records in an Ethereum block a declaration in which key pair X says that it delegates signing authority to another key pair Y.
The second type records in an Ethereum block a declaration in which key pair X says that it revokes signing authority from another key pair Y.
The third type records in an Ethereum block a declaration in which key pair X says that it should from now on be treated as invalid, i.e. unable to enter into any further transactions in the future.
After declarations of this kind have been recorded on Ethereum, the Inkan client then has the ability to fetch these declarations from Ethereum for key pairs the user has chosen to track. The client then uses the fetched declarations as a basis for calculating time periods during which a key pair delegated signing authority to another key pair. These delegation relationships can be both direct or indirect through chains of delegation (i.e. if key pair X directly delegates to key pair Y and key pair Y directly delegates to key pair Z, this will be interpreted by the client as key pair X indirectly delegating to key pair Z).
You can see these calculated delegation relationships in the tables / backup data that is displayed by the client when you click on the green "D"s on the avatars.
I'll leave it at this for now. There is more to be explained, but it may be better to do so in smaller chunks as one gets used to it. Please feel free to ask questions and I can further explain any part of Inkan that you're looking at.
It should also start displaying a full completed profile with avatar and banner pictures shortly after the initial login.
I've only tested it logging in with nip-7 browser extensions using Chrome (nos2x) and Firefox (nos2fox) on my laptop. I don't know whether / how it works with other signers - I'd probably stick with browser extensions and a laptop or desktop.
You can also find downloads for the management utility under Settings >> Inkan Management Utility when you are logged in.
Let me know any questions ...
got it relay need time to sync https://image.nostr.build/e66a6f5b764e66ae1011bb0fe44369544d2d6c20fa3ec4b7f7df0c5e440f0f03.png
seems no note to test step 4
https://image.nostr.build/76cdad370f4f135eaa4787fd4cfb6f39f83ad4fe4eeffdd475bb886132bf6403.png