From 35bbd7c82215783149880275f2342dd203cfffe4 Mon Sep 17 00:00:00 2001 From: ethicnology Date: Fri, 10 Feb 2023 22:55:21 +0200 Subject: [PATCH 1/5] chore: fix doc --- README.md | 92 ++++++++++++++++--------------------------------------- 1 file changed, 27 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index b6ee109..a5989bc 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,10 @@ void main() async { var keys = Keychain( "5ee1c8000ab28edd64d74a7d951ac2dd559814887b1b9e1ac7c5f89e96125c12", ); - print(keys.public == + assert(keys.public == "981cc2078af05b62ee1f98cff325aac755bf5c5836a265c254447b5933c6223b"); - // Generate random keys + // or generate random keys var randomKeys = Keychain.generate(); print(randomKeys.private); @@ -57,9 +57,20 @@ void main() async { content, sig, ); + assert(oneEvent.id == + "4b697394206581b03ca5222b37449a9cdca1741b122d78defc177444e2536f49"); - print(oneEvent.id); - // 4b697394206581b03ca5222b37449a9cdca1741b122d78defc177444e2536f49 + // Create a partial event from nothing and fill it with data until it is valid + var partialEvent = Event.partial(); + assert(partialEvent.isValid() == false); + partialEvent.createdAt = currentUnixTimestampSeconds(); + partialEvent.pubkey = + "981cc2078af05b62ee1f98cff325aac755bf5c5836a265c254447b5933c6223b"; + partialEvent.id = partialEvent.getEventId(); + partialEvent.sig = partialEvent.getSignature( + "5ee1c8000ab28edd64d74a7d951ac2dd559814887b1b9e1ac7c5f89e96125c12", + ); + assert(partialEvent.isValid() == true); // Instantiate an event with a partial data and let the library sign the event with your private key Event anotherEvent = Event.from( @@ -70,8 +81,8 @@ void main() async { "5ee1c8000ab28edd64d74a7d951ac2dd559814887b1b9e1ac7c5f89e96125c12", // DO NOT REUSE THIS PRIVATE KEY ); - print(anotherEvent.pubkey); - // 981cc2078af05b62ee1f98cff325aac755bf5c5836a265c254447b5933c6223b + assert(anotherEvent.pubkey == + "981cc2078af05b62ee1f98cff325aac755bf5c5836a265c254447b5933c6223b"); // Connecting to a nostr relay using websocket WebSocket webSocket = await WebSocket.connect( @@ -101,63 +112,14 @@ import 'dart:io'; import 'package:nostr/nostr.dart'; void main() async { - // Use the Keychain class to manipulate private/public keys and use handy methods encapsulated from dart-bip340 - var keys = Keychain( - "5ee1c8000ab28edd64d74a7d951ac2dd559814887b1b9e1ac7c5f89e96125c12", - ); - assert(keys.public == - "981cc2078af05b62ee1f98cff325aac755bf5c5836a265c254447b5933c6223b"); - - // or generate random keys - var randomKeys = Keychain.generate(); - print(randomKeys.private); - - // Instantiate an event with all the field - String id = - "4b697394206581b03ca5222b37449a9cdca1741b122d78defc177444e2536f49"; - String pubkey = keys.public; - int createdAt = 1672175320; - int kind = 1; - List> tags = []; - String content = "Ceci est une analyse du websocket"; - String sig = - "797c47bef50eff748b8af0f38edcb390facf664b2367d72eb71c50b5f37bc83c4ae9cc9007e8489f5f63c66a66e101fd1515d0a846385953f5f837efb9afe885"; - - Event oneEvent = Event( - id, - pubkey, - createdAt, - kind, - tags, - content, - sig, - ); - assert(oneEvent.id == - "4b697394206581b03ca5222b37449a9cdca1741b122d78defc177444e2536f49"); - - // Create a partial event from nothing and fill it with data until it is valid - var partialEvent = Event.partial(); - assert(partialEvent.isValid() == false); - partialEvent.createdAt = currentUnixTimestampSeconds(); - partialEvent.pubkey = - "981cc2078af05b62ee1f98cff325aac755bf5c5836a265c254447b5933c6223b"; - partialEvent.id = partialEvent.getEventId(); - partialEvent.sig = partialEvent.getSignature( - "5ee1c8000ab28edd64d74a7d951ac2dd559814887b1b9e1ac7c5f89e96125c12", - ); - assert(partialEvent.isValid() == true); - - // Instantiate an event with a partial data and let the library sign the event with your private key - Event anotherEvent = Event.from( - kind: 1, - tags: [], - content: "vi veri universum vivus vici", - privkey: - "5ee1c8000ab28edd64d74a7d951ac2dd559814887b1b9e1ac7c5f89e96125c12", // DO NOT REUSE THIS PRIVATE KEY - ); - - assert(anotherEvent.pubkey == - "981cc2078af05b62ee1f98cff325aac755bf5c5836a265c254447b5933c6223b"); +// Create a subscription message request with one or many filters + Request requestWithFilter = Request(generate64RandomHexChars(), [ + Filter( + kinds: [0, 1, 2, 7], + since: 1674063680, + limit: 450, + ) + ]); // Connecting to a nostr relay using websocket WebSocket webSocket = await WebSocket.connect( @@ -167,8 +129,8 @@ void main() async { // wss://nostr.sandwich.farm // wss://relay.damus.io - // Send an event to the WebSocket server - webSocket.add(anotherEvent.serialize()); + // Send a request message to the WebSocket server + webSocket.add(requestWithFilter.serialize()); // Listen for events from the WebSocket server await Future.delayed(Duration(seconds: 1)); From cccd1c90fba3480ced011c00e796174231562250 Mon Sep 17 00:00:00 2001 From: ryzizub Date: Mon, 13 Feb 2023 14:10:14 +0100 Subject: [PATCH 2/5] fix: pending bip340 issue --- lib/src/keychain.dart | 20 -------------------- pubspec.yaml | 2 +- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/lib/src/keychain.dart b/lib/src/keychain.dart index 56d19ad..975d0d0 100644 --- a/lib/src/keychain.dart +++ b/lib/src/keychain.dart @@ -10,38 +10,18 @@ class Keychain { late String public; /// Instantiate a Keychain with a private key hex-encoded - /// - /// There is a pending issue in dart-bip340 lib where some private keys generates non padded pubkey (missing leading '0'). - /// If you input such private key, I can't let you Instantiates Keychain with the current private key because it will messup all NOSTR signatures. - /// I hope it will be fix asap: https://github.com/nbd-wtf/dart-bip340/issues/4 Keychain(this.private) { assert( private.length == 64, "Private key should be 64 chars length (32 bytes hex encoded)", ); public = bip340.getPublicKey(private); - assert( - public.length == 64, - '''\n - There is a pending issue in dart-bip340 lib where some private keys generates non padded pubkey (missing leading '0'). \n - I can't let you Instantiate Keychain with the current private key because it will messup all NOSTR signatures. \n - I hope it will be fix asap so i can remove this assert. \n - https://github.com/nbd-wtf/dart-bip340/issues/4 - ''', - ); } /// Instantiate a Keychain from random bytes Keychain.generate() { private = generate64RandomHexChars(); public = bip340.getPublicKey(private); - - /// The function getPublicKey() does not pad the returned value with 0 if the calculated public key should have zeros at beginning - /// https://github.com/nbd-wtf/dart-bip340/issues/4 - while (public.length != 64) { - private = generate64RandomHexChars(); - public = bip340.getPublicKey(private); - } } /// Encapsulate dart-bip340 sign() so you don't need to add bip340 as a dependency diff --git a/pubspec.yaml b/pubspec.yaml index eeabd6c..686aad3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,6 @@ dev_dependencies: lints: ^2.0.0 test: ^1.16.0 dependencies: - bip340: ^0.0.4 + bip340: ^0.1.0 convert: ^3.1.1 crypto: ^3.0.2 From 08050370b71ba7e5c40653ff8fd237e48cd9afa7 Mon Sep 17 00:00:00 2001 From: ryzizub Date: Mon, 13 Feb 2023 14:15:52 +0100 Subject: [PATCH 3/5] test: Update test to check public key --- test/keychain_test.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/keychain_test.dart b/test/keychain_test.dart index bae7314..da26afa 100644 --- a/test/keychain_test.dart +++ b/test/keychain_test.dart @@ -14,12 +14,12 @@ void main() { ); }); - test('Keychain with bugged private key', () { - expect( - () => Keychain( - "ea7daa0537b93aa3ae4495a274ecc05077e3dc168809d77a7afa4ec1db0fb3bd", - ), - throwsA(isA())); + test('Keychain with invalid public key (public.length != 64)', () { + var hex = + "ea7daa0537b93aa3ae4495a274ecc05077e3dc168809d77a7afa4ec1db0fb3bd"; + + var keys = Keychain(hex); + expect(keys.public.length, 64); }); test('Keychain with invalid private key (private.length != 64)', () { From f12640539f3eb8b4c7242a5402c931fb0b53e257 Mon Sep 17 00:00:00 2001 From: ryzizub Date: Sun, 12 Feb 2023 22:48:21 +0100 Subject: [PATCH 4/5] refactor: Event partial and from to factories --- lib/src/event.dart | 98 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 20 deletions(-) diff --git a/lib/src/event.dart b/lib/src/event.dart index 353075f..96dbb54 100644 --- a/lib/src/event.dart +++ b/lib/src/event.dart @@ -104,18 +104,27 @@ class Event { /// ); /// assert(partialEvent.isValid() == true); /// ``` - Event.partial({ - this.id = "", - this.pubkey = "", - this.createdAt = 0, - this.kind = 1, - this.tags = const [], - this.content = "", - this.sig = "", - this.subscriptionId, + factory Event.partial({ + id = "", + pubkey = "", + createdAt = 0, + kind = 1, + tags = const >[], + content = "", + sig = "", + subscriptionId, bool verify = false, }) { - if (verify) assert(isValid() == true); + return Event( + id, + pubkey, + createdAt, + kind, + tags, + content, + sig, + verify: verify, + ); } /// Instantiate Event object from the minimum available data @@ -129,19 +138,42 @@ class Event { /// "5ee1c8000ab28edd64d74a7d951ac2dd559814887b1b9e1ac7c5f89e96125c12", ///); ///``` - Event.from({ - this.createdAt = 0, - required this.kind, - required this.tags, - required this.content, + factory Event.from({ + int createdAt = 0, + required int kind, + required List> tags, + required String content, required String privkey, - this.subscriptionId, + String? subscriptionId, + bool verify = false, }) { if (createdAt == 0) createdAt = currentUnixTimestampSeconds(); - assert(createdAt.toString().length == 10); - pubkey = bip340.getPublicKey(privkey).toLowerCase(); - id = getEventId(); - sig = getSignature(privkey); + final pubkey = bip340.getPublicKey(privkey).toLowerCase(); + + final id = _processEventId( + pubkey, + createdAt, + kind, + tags, + content, + ); + + final sig = _processSignature( + privkey, + id, + ); + + return Event( + id, + pubkey, + createdAt, + kind, + tags, + content, + sig, + subscriptionId: subscriptionId, + verify: verify, + ); } /// Deserialize an event from a JSON @@ -250,6 +282,24 @@ class Event { /// ///] String getEventId() { + // Included for minimum breaking changes + return _processEventId( + pubkey, + createdAt, + kind, + tags, + content, + ); + } + + // Support for [getEventId] + static String _processEventId( + String pubkey, + int createdAt, + int kind, + List> tags, + String content, + ) { List data = [0, pubkey.toLowerCase(), createdAt, kind, tags, content]; String serializedEvent = json.encode(data); List hash = sha256.convert(utf8.encode(serializedEvent)).bytes; @@ -259,6 +309,14 @@ class Event { /// Each user has a keypair. Signatures, public key, and encodings are done according to the Schnorr signatures standard for the curve secp256k1 /// 64-bytes signature of the sha256 hash of the serialized event data, which is the same as the "id" field String getSignature(String privateKey) { + return _processSignature(privateKey, id); + } + + // Support for [getSignature] + static String _processSignature( + String privateKey, + String id, + ) { /// aux must be 32-bytes random bytes, generated at signature time. /// https://github.com/nbd-wtf/dart-bip340/blob/master/lib/src/bip340.dart#L10 String aux = generate64RandomHexChars(); From 044050bb494cfc7e5002b7c4916ab3e01b459879 Mon Sep 17 00:00:00 2001 From: ethicnology Date: Tue, 14 Feb 2023 09:02:19 +0200 Subject: [PATCH 5/5] chore: changelog & version --- CHANGELOG.md | 7 +++++++ pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e19c8c4..1b4fdd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,13 @@ - improve coverage ## 1.3.3 + - add comments about verify and fix typo - nip 002 implementation, unit tests, examples and documentation - Event.partial to init an empty event that you validate later, documentation + +## 1.3.4 + +- fix: pending bip340 issue +- test: Update test to check public key +- refactor: Event partial and from to factories diff --git a/pubspec.yaml b/pubspec.yaml index 686aad3..8e9561c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: nostr description: A library for nostr protocol implemented in dart for flutter -version: 1.3.3 +version: 1.3.4 homepage: https://github.com/ethicnology/dart-nostr environment: