Avatar
Bartholomew Joyce⚡️🇫🇷
489ac583fc30cfbee0095dd736ec46468faa8b187e311fda6269c4e18284ed0c
Software developer at nostr.land — working on better privacy on Nostr

I would add another level just below running a full Bitcoin node where you run a light Bitcoin node. Doesn’t take up significant space, you can run it intermittently to just sync the state of the network, and it allows you to verify your personal UTXOs without deferring to anyone else

Replying to Avatar Sirius

Guten morgen! Refactored Iris version is available at https://beta.iris.to and hopefully in production soon. UI freeze bug now resolved. Most of the differences are under the hood, improving content loading and making further development easier.

It uses #[0] 's Relaypool library https://github.com/adamritter/nostr-relaypool-ts . We would like to see web client developers working together on a library that takes care of the tricky stuff like subscription management and feed aggregation.

👆 stove used by the Finnish military, heated up to the point where it's called a strawberry.

Well done, guys!

It’s a Nostr proof-of-work generator library. You just pass in an event and a target difficulty and it returns the event with a nonce tag that produces an event id with your desired difficulty. That’s all, really.

I was just experimenting with how to get the computation to be as fast as possible. It’s a little weird compared to regular PoW in that the nonce is in plaintext, not binary

nostr-pow: A little npm Node module for finding Nostr event nonces.

On my Mac mini 3.2GHz 6-Core i7 I’m getting about 10 megahashes/second. Curious to see what others are getting 🤔

https://github.com/bmewj/nostr-pow

The thing is that once you start re-jigging BitTorrent to adopt a paid incentive structure you might as well opt for a much simpler protocol altogether

BitTorrent gets a whole bunch of things right, but it’s core fault (which I think is just an unfortunate case of its design predating cryptocurrencies) is that it doesn’t distinguish people who want to consume from people who want to provide.

This is something that Nostr gets right, and why it’s got a better chance of scaling vs scuttlebutt. There are people who run relays and there are people who use clients. And it’s possible economically because relay operators can charge for the service they provide.

For the BitTorrent network to be healthy users must try to balance what they take from the network by giving back to the network. This is hardly ever the case, so you end up with leeches on one side ruining the network, and lawful users who suffer for their good will.

If you can incorporate a currency to bridge the gap between consumers and providers you have yourself a much healthier system.

Incognito DMs, let’s go!

After a week of back and forth between #[0] and I we have fine-tuned and finished a first draft for NIP-32 incognito DMs.

I have created a PR for the NIP to open up our idea to discussion and feedback. We will be publishing a reference client implementation for the NIP later this week, forked from #[1] ’s Hamstr client.

https://github.com/nostr-protocol/nips/pull/410

#[0] Not exactly sure what you meant regarding separating the testing and code and tlv parsing into their own functions, but for now I’ve moved all the code out to a separate file to clean things up.

Replying to Avatar jb55

#[0]​ are there any issues with this code?

static int parse_mention_bech32(struct cursor *cur, struct block *block) {

const u8 *start, *start_entity, *end;

start = cur->p;

if (!parse_str(cur, "nostr:"))

return 0;

start_entity = cur->p;

if (!consume_until_whitespace(cur, 1)) {

cur->p = start;

return 0;

}

end = cur->p;

char str[end - start_entity + 1];

str[end - start_entity] = 0;

memcpy(str, start_entity, end - start_entity);

char prefix[end - start_entity];

u8 data[end - start_entity];

size_t data_len;

size_t max_input_len = end - start_entity + 2;

if (bech32_decode(prefix, data, &data_len, str, max_input_len) == BECH32_ENCODING_NONE) {

cur->p = start;

return 0;

}

struct mention_bech32_block mention = { 0 };

mention.kind = -1;

mention.buffer = (u8*)malloc(data_len);

mention.str.start = (const char*)start;

mention.str.end = (const char*)end;

size_t len = 0;

if (!bech32_convert_bits(mention.buffer, &len, 8, data, data_len, 5, 0)) {

goto fail;

}

// Parse type

if (strcmp(prefix, "note") == 0) {

mention.type = NOSTR_BECH32_NOTE;

} else if (strcmp(prefix, "npub") == 0) {

mention.type = NOSTR_BECH32_NPUB;

} else if (strcmp(prefix, "nprofile") == 0) {

mention.type = NOSTR_BECH32_NPROFILE;

} else if (strcmp(prefix, "nevent") == 0) {

mention.type = NOSTR_BECH32_NEVENT;

} else if (strcmp(prefix, "nrelay") == 0) {

mention.type = NOSTR_BECH32_NRELAY;

} else if (strcmp(prefix, "naddr") == 0) {

mention.type = NOSTR_BECH32_NADDR;

} else {

goto fail;

}

// Parse notes and npubs (non-TLV)

if (mention.type == NOSTR_BECH32_NOTE || mention.type == NOSTR_BECH32_NPUB) {

if (len != 32) goto fail;

if (mention.type == NOSTR_BECH32_NOTE) {

mention.event_id = mention.buffer;

} else {

mention.pubkey = mention.buffer;

}

goto ok;

}

// Parse TLV entities

const int MAX_VALUES = 16;

int values_count = 0;

u8 Ts[MAX_VALUES];

u8 Ls[MAX_VALUES];

u8* Vs[MAX_VALUES];

for (int i = 0; i < len - 1;) {

if (values_count == MAX_VALUES) goto fail;

Ts[values_count] = mention.buffer[i++];

Ls[values_count] = mention.buffer[i++];

if (Ls[values_count] > len - i) goto fail;

Vs[values_count] = &mention.buffer[i];

i += Ls[values_count];

++values_count;

}

// Decode and validate all TLV-type entities

if (mention.type == NOSTR_BECH32_NPROFILE) {

for (int i = 0; i < values_count; ++i) {

if (Ts[i] == TLV_SPECIAL) {

if (Ls[i] != 32 || mention.pubkey) goto fail;

mention.pubkey = Vs[i];

} else if (Ts[i] == TLV_RELAY) {

if (mention.relays_count == MAX_RELAYS) goto fail;

Vs[i][Ls[i]] = 0;

mention.relays[mention.relays_count++] = (char*)Vs[i];

} else {

goto fail;

}

}

if (!mention.pubkey) goto fail;

} else if (mention.type == NOSTR_BECH32_NEVENT) {

for (int i = 0; i < values_count; ++i) {

if (Ts[i] == TLV_SPECIAL) {

if (Ls[i] != 32 || mention.event_id) goto fail;

mention.event_id = Vs[i];

} else if (Ts[i] == TLV_RELAY) {

if (mention.relays_count == MAX_RELAYS) goto fail;

Vs[i][Ls[i]] = 0;

mention.relays[mention.relays_count++] = (char*)Vs[i];

} else if (Ts[i] == TLV_AUTHOR) {

if (Ls[i] != 32 || mention.pubkey) goto fail;

mention.pubkey = Vs[i];

} else {

goto fail;

}

}

if (!mention.event_id) goto fail;

} else if (mention.type == NOSTR_BECH32_NRELAY) {

if (values_count != 1 || Ts[0] != TLV_SPECIAL) goto fail;

Vs[0][Ls[0]] = 0;

mention.relays[mention.relays_count++] = (char*)Vs[0];

} else { // entity.type == NOSTR_BECH32_NADDR

for (int i = 0; i < values_count; ++i) {

if (Ts[i] == TLV_SPECIAL) {

Vs[i][Ls[i]] = 0;

mention.identifier = (char*)Vs[i];

} else if (Ts[i] == TLV_RELAY) {

if (mention.relays_count == MAX_RELAYS) goto fail;

Vs[i][Ls[i]] = 0;

mention.relays[mention.relays_count++] = (char*)Vs[i];

} else if (Ts[i] == TLV_AUTHOR) {

if (Ls[i] != 32 || mention.pubkey) goto fail;

mention.pubkey = Vs[i];

} else if (Ts[i] == TLV_KIND) {

if (Ls[i] != sizeof(int) || mention.kind != -1) goto fail;

mention.kind = *(int*)Vs[i];

} else {

goto fail;

}

}

if (!mention.identifier || mention.kind == -1 || !mention.pubkey) goto fail;

}

ok:

block->type = BLOCK_MENTION_BECH32;

block->block.mention_bech32 = mention;

return 1;

fail:

free(mention.buffer);

cur->p = start;

return 0;

}

Lol

Yeah I think clients should pick a default for now and worry about that later. But at the very least it will improve the privacy of DMs