From 34f485447ee4d79613381df4cd606cb153447906 Mon Sep 17 00:00:00 2001 From: Yuki Kishimoto Date: Tue, 16 May 2023 19:19:10 +0200 Subject: [PATCH] nostr: cleanup --- .githooks/pre-push | 8 +- .github/workflows/ci.yml | 4 +- Cargo.toml | 1 + crates/nostr/Cargo.toml | 37 +-- .../nostr/examples/ensure_no_std/Cargo.toml | 15 -- crates/nostr/examples/no_std/Cargo.toml | 8 + .../{ensure_no_std => no_std}/src/main.rs | 0 crates/nostr/src/event/builder.rs | 252 ++++-------------- crates/nostr/src/event/id.rs | 7 +- crates/nostr/src/event/mod.rs | 25 +- crates/nostr/src/event/tag.rs | 8 +- crates/nostr/src/event/unsigned.rs | 32 +-- crates/nostr/src/key/mod.rs | 149 ++--------- crates/nostr/src/key/vanity.rs | 10 +- crates/nostr/src/lib.rs | 23 +- crates/nostr/src/message/client.rs | 5 +- crates/nostr/src/message/mod.rs | 4 +- crates/nostr/src/message/relay.rs | 1 - crates/nostr/src/message/subscription.rs | 8 +- crates/nostr/src/nips/nip04.rs | 14 +- crates/nostr/src/nips/nip05.rs | 7 +- crates/nostr/src/nips/nip06.rs | 8 +- crates/nostr/src/nips/nip11.rs | 5 +- crates/nostr/src/nips/nip13.rs | 4 +- crates/nostr/src/nips/nip19.rs | 5 +- crates/nostr/src/nips/nip21.rs | 4 +- crates/nostr/src/nips/nip26.rs | 95 +------ crates/nostr/src/nips/nip46.rs | 6 +- crates/nostr/src/nips/nip58.rs | 45 ++-- crates/nostr/src/prelude.rs | 2 +- crates/nostr/src/types/channel_id.rs | 12 +- crates/nostr/src/types/metadata.rs | 9 +- crates/nostr/src/types/profile.rs | 15 +- .../nostr/src/types/{time.rs => time/mod.rs} | 137 ++-------- crates/nostr/src/types/time/supplier.rs | 109 ++++++++ crates/nostr/src/types/url.rs | 11 +- 36 files changed, 324 insertions(+), 761 deletions(-) delete mode 100644 crates/nostr/examples/ensure_no_std/Cargo.toml create mode 100644 crates/nostr/examples/no_std/Cargo.toml rename crates/nostr/examples/{ensure_no_std => no_std}/src/main.rs (100%) rename crates/nostr/src/types/{time.rs => time/mod.rs} (58%) create mode 100644 crates/nostr/src/types/time/supplier.rs diff --git a/.githooks/pre-push b/.githooks/pre-push index 82c014691..13aef07df 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -4,10 +4,10 @@ cargo fmt --all -- --config format_code_in_doc_comments=true buildargs=( "-p nostr" - "-p nostr --no-default-features" - "-p nostr --no-default-features --features all-nips" - "-p nostr --no-default-features --features vanity" - "-p nostr --features blocking" + "-p nostr --no-default-features" std + "-p nostr --no-default-features --features 'std all-nips'" + "-p nostr --no-default-features --features 'std vanity'" + "-p nostr --features 'std blocking'" "-p nostr-sdk" "-p nostr-sdk --no-default-features" "-p nostr-sdk --features blocking" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db834aa83..9aa567abd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,7 +105,7 @@ jobs: - version: nightly build-args: [ - --no-default-features, + -p no_std_example, ] steps: - name: Checkout @@ -124,8 +124,6 @@ jobs: run: rustup set profile minimal && rustup component add clippy - name: Build run: cargo build ${{ matrix.build-args }} - working-directory: ./crates/nostr/examples/ensure_no_std - name: Clippy run: cargo clippy ${{ matrix.build-args }} -- -D warnings - working-directory: ./crates/nostr/examples/ensure_no_std \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 93a14a4a3..26b6a79cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "bindings/nostr-sdk-ffi", "bindings/nostr-sdk-js", "crates/nostr", + "crates/nostr/examples/no_std", "crates/nostr-sdk", "crates/nostr-sdk-net", ] diff --git a/crates/nostr/Cargo.toml b/crates/nostr/Cargo.toml index ab568cb3d..485cb5d30 100644 --- a/crates/nostr/Cargo.toml +++ b/crates/nostr/Cargo.toml @@ -16,21 +16,23 @@ default = ["all-nips", "std"] std = [ "bech32?/std", "bitcoin_hashes/std", + "once_cell/std", + "secp256k1/rand-std", "serde/std", "serde_json/std", "url", - "secp256k1/global-context", - "secp256k1/rand-std", ] alloc = [ "bech32?/alloc", "bitcoin_hashes/alloc", + "once_cell/alloc", + "rand/alloc", + "rand/getrandom", + "secp256k1/alloc", + "secp256k1/rand", "serde/alloc", "serde_json/alloc", "url_no_std", - "secp256k1/alloc", - "secp256k1/rand", - "rand", ] blocking = ["reqwest?/blocking"] vanity = ["nip19"] @@ -50,30 +52,17 @@ base64 = { version = "0.21", optional = true } bech32 = { git = "https://github.com/rust-bitcoin/rust-bech32", rev = "360af7e0647fa94bce892fa69f31c0ef02452b63", optional = true, default-features = false } bip39 = { version = "2.0", optional = true } bitcoin = { version = "0.30", optional = true } -bitcoin_hashes = { version = "0.12", default-features = false, features = [ - "serde", -] } +bitcoin_hashes = { version = "0.12", default-features = false, features = [ "serde"] } cbc = { version = "0.1", features = ["alloc"], optional = true } -log = "0.4" # no_std compatible by-default nostr-ots = { version = "0.2", optional = true } -reqwest = { version = "0.11", default-features = false, features = [ - "json", - "rustls-tls-webpki-roots", - "socks", -], optional = true } +once_cell = "1.17" +rand = { version = "0.8", default-features = false } +reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls-webpki-roots", "socks"], optional = true } secp256k1 = { version = "0.27", default-features = false, features = ["serde"] } - -serde = { version = "1.0", features = [ - "derive", -], default-features = false, optional = true } +serde = { version = "1.0", features = ["derive"], default-features = false, optional = true } serde_json = { version = "1.0", optional = true, default-features = false } - url = { version = "2", features = ["serde"], optional = true } -url_no_std = { package = "url", features = [ - "alloc", -], git = "https://github.com/OverOrion/rust-url", branch = "no_std_net", optional = true, default-features = false } - -rand = { version = "0.8", features = ["alloc", "getrandom"], default-features = false, optional = true } +url_no_std = { package = "url", features = ["alloc"], git = "https://github.com/OverOrion/rust-url", branch = "no_std_net", optional = true, default-features = false } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2", features = ["js"] } diff --git a/crates/nostr/examples/ensure_no_std/Cargo.toml b/crates/nostr/examples/ensure_no_std/Cargo.toml deleted file mode 100644 index 6ddd520df..000000000 --- a/crates/nostr/examples/ensure_no_std/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "ensure_no_std" -version = "0.7.0" -authors = ["Supercomputing Systems AG "] -license = "Apache-2.0" -edition = "2021" - -[dependencies] -libc = { version = "0.2.119", default-features = false } - -nostr = { path = "../../../nostr", default-features = false, features = [ - "alloc", -] } - -[workspace] diff --git a/crates/nostr/examples/no_std/Cargo.toml b/crates/nostr/examples/no_std/Cargo.toml new file mode 100644 index 000000000..20ccea0d6 --- /dev/null +++ b/crates/nostr/examples/no_std/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "no_std_example" +version = "0.1.0" +edition = "2021" + +[dependencies] +libc = { version = "0.2", default-features = false } +nostr = { path = "../../../nostr", default-features = false, features = ["alloc"] } diff --git a/crates/nostr/examples/ensure_no_std/src/main.rs b/crates/nostr/examples/no_std/src/main.rs similarity index 100% rename from crates/nostr/examples/ensure_no_std/src/main.rs rename to crates/nostr/examples/no_std/src/main.rs diff --git a/crates/nostr/src/event/builder.rs b/crates/nostr/src/event/builder.rs index ebf810c25..d3f55525a 100644 --- a/crates/nostr/src/event/builder.rs +++ b/crates/nostr/src/event/builder.rs @@ -2,22 +2,18 @@ // Distributed under the MIT software license //! Event builder -use core::fmt; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::string::{String, ToString}; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::{vec, vec::Vec}; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; #[cfg(feature = "std")] use std::error::Error as StdError; -use secp256k1::schnorr::Signature; -use secp256k1::{Message, XOnlyPublicKey}; -use secp256k1::{Secp256k1, Signing}; +use secp256k1::XOnlyPublicKey; use serde_json::{json, Value}; use url::Url; @@ -30,7 +26,6 @@ use crate::nips::nip04; use crate::nips::nip13; #[cfg(feature = "nip46")] use crate::nips::nip46::Message as NostrConnectMessage; -use crate::types::time::TimeSupplier; use crate::types::{ChannelId, Contact, Metadata, Timestamp}; /// [`EventBuilder`] error @@ -115,242 +110,109 @@ impl EventBuilder { content: content.into(), } } +} +#[cfg(feature = "std")] +impl EventBuilder { /// Build [`Event`] - #[cfg(feature = "std")] pub fn to_event(self, keys: &Keys) -> Result { let pubkey: XOnlyPublicKey = keys.public_key(); Ok(self.to_unsigned_event(pubkey).sign(keys)?) } - /// Build [`Event`] with a `timestamp` - #[cfg(not(feature = "std"))] - pub fn to_event_with_timestamp_with_secp( - self, - keys: &Keys, - created_at: Timestamp, - secp: &Secp256k1, - ) -> Result { - let pubkey: XOnlyPublicKey = keys.public_key(); - let id = EventId::new(&pubkey, created_at, &self.kind, &self.tags, &self.content); - let message = Message::from_slice(id.as_bytes())?; - let signature = keys.sign_schnorr_with_secp(&message, secp)?; - - Self::into_event_internal(self, keys, created_at, id, signature) - } - - fn into_event_internal( - self, - keys: &Keys, - created_at: Timestamp, - id: EventId, - sig: Signature, - ) -> Result { - let pubkey: XOnlyPublicKey = keys.public_key(); - - Ok(Event { - id, - pubkey, - created_at, - kind: self.kind, - tags: self.tags, - content: self.content, - sig, - }) + /// Build [`UnsignedEvent`] + pub fn to_unsigned_event(self, pubkey: XOnlyPublicKey) -> UnsignedEvent { + let created_at: Timestamp = Timestamp::now(); + self.to_unsigned_event_with_timestamp(pubkey, created_at) } /// Build POW [`Event`] - #[cfg(feature = "std")] pub fn to_pow_event(self, keys: &Keys, difficulty: u8) -> Result { let pubkey: XOnlyPublicKey = keys.public_key(); Ok(self.to_unsigned_pow_event(pubkey, difficulty).sign(keys)?) } /// Build unsigned POW [`Event`] - #[cfg(feature = "std")] pub fn to_unsigned_pow_event(self, pubkey: XOnlyPublicKey, difficulty: u8) -> UnsignedEvent { - #[cfg(target_arch = "wasm32")] - use instant::Instant; - #[cfg(all(feature = "std", not(target_arch = "wasm32")))] - use std::time::Instant; - - let now = Instant::now(); - - use secp256k1::SECP256K1; - self.to_unsigned_pow_event_with_time_supplier_with_secp::( - pubkey, difficulty, &now, SECP256K1, - ) + let created_at = Timestamp::now(); + self.to_unsigned_pow_event_with_timestamp(pubkey, created_at, difficulty) } +} - /// Build POW [`Event`] using the given time supplier - pub fn to_pow_event_with_time_supplier_with_secp( +impl EventBuilder { + /// Build [`Event`] with custom [`Timestamp`] + pub fn to_event_with_timestamp( self, keys: &Keys, - difficulty: u8, - time_supplier: &impl TimeSupplier, - secp: &Secp256k1, - ) -> Result - where - T: TimeSupplier, - { - self.into_pow_event_internal(keys, difficulty, time_supplier, secp) + created_at: Timestamp, + ) -> Result { + let pubkey: XOnlyPublicKey = keys.public_key(); + Ok(self + .to_unsigned_event_with_timestamp(pubkey, created_at) + .sign(keys)?) } - fn into_pow_event_internal( + /// Build [`UnsignedEvent`] with custom [`Timestamp`] + pub fn to_unsigned_event_with_timestamp( self, - keys: &Keys, - difficulty: u8, - time_supplier: &T, - _secp: &Secp256k1, - ) -> Result - where - T: TimeSupplier, - { - #[cfg(feature = "std")] - use std::cmp; - - #[cfg(all(feature = "alloc", not(feature = "std")))] - use core::cmp; - - let mut nonce: u128 = 0; - let mut tags: Vec = self.tags.clone(); - - let pubkey = keys.public_key(); - - let now = time_supplier.now(); - - loop { - nonce += 1; - - tags.push(Tag::POW { nonce, difficulty }); - - let new_now = time_supplier.now(); - let created_at = time_supplier.duration_since_starting_point(now.clone()); - let created_at = time_supplier.to_timestamp(created_at); - let id = EventId::new(&pubkey, created_at, &self.kind, &tags, &self.content); - - if nip13::get_leading_zero_bits(id.inner()) >= difficulty { - log::debug!( - "{} iterations in {} ms. Avg rate {} hashes/second", - nonce, - time_supplier - .elapsed_since(now.clone(), new_now.clone()) - .as_millis(), - nonce * 1000 - / cmp::max(1, time_supplier.elapsed_since(now, new_now).as_millis()) - ); - - let message = Message::from_slice(id.as_bytes())?; - - #[cfg(all(feature = "alloc", not(feature = "std")))] - let sig = keys.sign_schnorr_with_secp(&message, &_secp)?; - - #[cfg(feature = "std")] - let sig = keys.sign_schnorr(&message)?; - - return self.into_event_internal(keys, created_at, id, sig); - } - - tags.pop(); + pubkey: XOnlyPublicKey, + created_at: Timestamp, + ) -> UnsignedEvent { + let id = EventId::new(&pubkey, created_at, &self.kind, &self.tags, &self.content); + UnsignedEvent { + id, + pubkey, + created_at, + kind: self.kind, + tags: self.tags, + content: self.content, } } - /// Build POW [`Event`] using the given time supplier - pub fn to_unsigned_pow_event_with_time_supplier_with_secp( + + /// Build POW [`Event`] with custom [`Timestamp`] + pub fn to_pow_event_with_timestamp( self, - pubkey: XOnlyPublicKey, + keys: &Keys, + created_at: Timestamp, difficulty: u8, - time_supplier: &impl TimeSupplier, - secp: &Secp256k1, - ) -> UnsignedEvent - where - T: TimeSupplier, - { - self.into_pow_unsigned_event_internal(pubkey, difficulty, time_supplier, secp) + ) -> Result { + let pubkey: XOnlyPublicKey = keys.public_key(); + Ok(self + .to_unsigned_pow_event_with_timestamp(pubkey, created_at, difficulty) + .sign(keys)?) } - fn into_pow_unsigned_event_internal( + /// Build unsigned POW [`Event`] with custom [`Timestamp`] + pub fn to_unsigned_pow_event_with_timestamp( self, pubkey: XOnlyPublicKey, + created_at: Timestamp, difficulty: u8, - time_supplier: &T, - _secp: &Secp256k1, - ) -> UnsignedEvent - where - T: TimeSupplier, - { - #[cfg(feature = "std")] - use std::cmp; - - #[cfg(all(feature = "alloc", not(feature = "std")))] - use core::cmp; - + ) -> UnsignedEvent { let mut nonce: u128 = 0; - let mut tags: Vec = self.tags.clone(); - - let now = time_supplier.now(); + let mut tags: Vec = self.tags; loop { nonce += 1; tags.push(Tag::POW { nonce, difficulty }); - let new_now = time_supplier.now(); - let created_at = time_supplier.duration_since_starting_point(now.clone()); - let created_at = time_supplier.to_timestamp(created_at); let id = EventId::new(&pubkey, created_at, &self.kind, &tags, &self.content); if nip13::get_leading_zero_bits(id.inner()) >= difficulty { - log::debug!( - "{} iterations in {} ms. Avg rate {} hashes/second", - nonce, - time_supplier - .elapsed_since(now.clone(), new_now.clone()) - .as_millis(), - nonce * 1000 - / cmp::max(1, time_supplier.elapsed_since(now, new_now).as_millis()) - ); - - return self.to_unsigned_event_with_timestamp(pubkey, created_at); + return UnsignedEvent { + id, + pubkey, + created_at, + kind: self.kind, + tags, + content: self.content, + }; } tags.pop(); } } - - /// Build [`UnsignedEvent`] - #[cfg(feature = "std")] - pub fn to_unsigned_event(self, pubkey: XOnlyPublicKey) -> UnsignedEvent { - let created_at: Timestamp = Timestamp::now(); - - Self::into_unsigned_event_internal(self, pubkey, created_at) - } - - /// Build [`UnsignedEvent`] with the given `Timestamp` - /// Mostly useful for cases where the time source comes from the outside, not from builtin - /// functions - pub fn to_unsigned_event_with_timestamp( - self, - pubkey: XOnlyPublicKey, - created_at: Timestamp, - ) -> UnsignedEvent { - Self::into_unsigned_event_internal(self, pubkey, created_at) - } - - fn into_unsigned_event_internal( - self, - pubkey: XOnlyPublicKey, - created_at: Timestamp, - ) -> UnsignedEvent { - let id = EventId::new(&pubkey, created_at, &self.kind, &self.tags, &self.content); - UnsignedEvent { - id, - pubkey, - created_at, - kind: self.kind, - tags: self.tags, - content: self.content, - } - } } impl EventBuilder { diff --git a/crates/nostr/src/event/id.rs b/crates/nostr/src/event/id.rs index 12b7257f0..0e04a59b7 100644 --- a/crates/nostr/src/event/id.rs +++ b/crates/nostr/src/event/id.rs @@ -3,17 +3,14 @@ //! Event Id -use core::fmt; -use core::str::FromStr; - #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::string::{String, ToString}; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; +use core::str::FromStr; #[cfg(feature = "std")] use std::error::Error as StdError; diff --git a/crates/nostr/src/event/mod.rs b/crates/nostr/src/event/mod.rs index ea96953a9..15b5412fe 100644 --- a/crates/nostr/src/event/mod.rs +++ b/crates/nostr/src/event/mod.rs @@ -4,21 +4,19 @@ //! Event -use core::fmt; -use core::str::FromStr; - #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::string::{String, ToString}; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec::Vec; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; +use core::str::FromStr; #[cfg(feature = "std")] use std::error::Error as StdError; -use secp256k1::{schnorr::Signature, Message, Secp256k1, Verification, XOnlyPublicKey}; +use secp256k1::schnorr::Signature; +use secp256k1::{Message, XOnlyPublicKey}; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -33,9 +31,7 @@ pub use self::id::EventId; pub use self::kind::Kind; pub use self::tag::{Marker, Tag, TagKind}; pub use self::unsigned::UnsignedEvent; -use crate::Timestamp; -#[cfg(feature = "std")] -use crate::SECP256K1; +use crate::{Timestamp, SECP256K1}; /// [`Event`] error #[derive(Debug)] @@ -118,13 +114,7 @@ pub struct Event { impl Event { /// Verify Event - #[cfg(feature = "std")] pub fn verify(&self) -> Result<(), Error> { - self.verify_with_context(SECP256K1) - } - - /// Verify Event - pub fn verify_with_context(&self, secp: &Secp256k1) -> Result<(), Error> { let id = EventId::new( &self.pubkey, self.created_at, @@ -133,13 +123,15 @@ impl Event { &self.content, ); let message = Message::from_slice(id.as_bytes())?; - secp.verify_schnorr(&self.sig, &message, &self.pubkey) + SECP256K1 + .verify_schnorr(&self.sig, &message, &self.pubkey) .map_err(|_| Error::InvalidSignature) } /// New event from [`Value`] pub fn from_value(value: Value) -> Result { let event: Self = serde_json::from_value(value)?; + event.verify()?; Ok(event) } @@ -149,6 +141,7 @@ impl Event { S: Into, { let event: Self = serde_json::from_str(&json.into())?; + event.verify()?; Ok(event) } diff --git a/crates/nostr/src/event/tag.rs b/crates/nostr/src/event/tag.rs index fedda4894..7adb4e4d0 100644 --- a/crates/nostr/src/event/tag.rs +++ b/crates/nostr/src/event/tag.rs @@ -2,9 +2,6 @@ // Distributed under the MIT software license //! Tag -use core::fmt; -use core::num::ParseIntError; -use core::str::FromStr; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::format; @@ -12,10 +9,11 @@ use alloc::format; use alloc::string::{String, ToString}; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::{vec, vec::Vec}; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; +use core::num::ParseIntError; +use core::str::FromStr; #[cfg(feature = "std")] use std::error::Error as StdError; diff --git a/crates/nostr/src/event/unsigned.rs b/crates/nostr/src/event/unsigned.rs index 58ec6747c..aec417757 100644 --- a/crates/nostr/src/event/unsigned.rs +++ b/crates/nostr/src/event/unsigned.rs @@ -3,28 +3,22 @@ //! Unsigned Event -use core::fmt; - #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::string::{String, ToString}; #[cfg(feature = "alloc")] use alloc::vec::Vec; #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; #[cfg(feature = "std")] use std::error::Error as StdError; -use secp256k1::{schnorr::Signature, XOnlyPublicKey}; +use secp256k1::schnorr::Signature; +use secp256k1::{Message, XOnlyPublicKey}; use serde::{Deserialize, Serialize}; -#[cfg(feature = "std")] -use secp256k1::Message; - -use crate::{Event, EventId, Kind, Tag, Timestamp}; - -#[cfg(feature = "std")] use crate::Keys; +use crate::{Event, EventId, Kind, Tag, Timestamp}; /// [`UnsignedEvent`] error #[derive(Debug)] @@ -95,7 +89,6 @@ pub struct UnsignedEvent { impl UnsignedEvent { /// Sign an [`UnsignedEvent`] - #[cfg(feature = "std")] pub fn sign(self, keys: &Keys) -> Result { let message = Message::from_slice(self.id.as_bytes())?; Ok(Event { @@ -111,24 +104,7 @@ impl UnsignedEvent { }) } - /// Sign an [`UnsignedEvent`] with specified signature - #[cfg(not(feature = "std"))] - pub fn sign_with_signature(self, sig: Signature) -> Result { - Ok(Event { - id: self.id, - pubkey: self.pubkey, - created_at: self.created_at, - kind: self.kind, - tags: self.tags, - content: self.content, - sig, - #[cfg(feature = "nip03")] - ots: None, - }) - } - /// Add signature to [`UnsignedEvent`] - #[cfg(feature = "std")] pub fn add_signature(self, sig: Signature) -> Result { let event = Event { id: self.id, diff --git a/crates/nostr/src/key/mod.rs b/crates/nostr/src/key/mod.rs index e3e76394a..ce43de80f 100644 --- a/crates/nostr/src/key/mod.rs +++ b/crates/nostr/src/key/mod.rs @@ -6,35 +6,20 @@ //! //! This module defines the [`Keys`] structure. +#[cfg(all(feature = "alloc", not(feature = "std")))] +use core::error::Error as StdError; use core::fmt; #[cfg(feature = "nip19")] use core::str::FromStr; - -#[cfg(all(feature = "alloc", not(feature = "std")))] -use core::error::Error as StdError; - #[cfg(feature = "std")] use std::error::Error as StdError; -#[cfg(all(feature = "alloc", not(feature = "std")))] -use rand::rngs::OsRng; -#[cfg(feature = "std")] use secp256k1::rand::rngs::OsRng; - -#[cfg(all(feature = "alloc", not(feature = "std")))] -use secp256k1::Secp256k1; -#[cfg(all(feature = "alloc", not(feature = "std")))] -use secp256k1::Signing; - -#[cfg(all(feature = "alloc", not(feature = "std")))] -use rand::Rng; -#[cfg(feature = "std")] use secp256k1::rand::Rng; use secp256k1::schnorr::Signature; use secp256k1::Message; pub use secp256k1::{KeyPair, PublicKey, SecretKey, XOnlyPublicKey}; -#[cfg(feature = "std")] use crate::SECP256K1; #[cfg(feature = "vanity")] @@ -82,21 +67,16 @@ impl From for Error { pub trait FromSkStr: Sized { /// Error type Err; - #[cfg(all(feature = "std", not(feature = "alloc")))] + /// Init [`Keys`] from `hex` or `bech32` secret key string fn from_sk_str(secret_key: &str) -> Result; - #[cfg(all(feature = "alloc", not(feature = "std")))] - /// Init [`Keys`] from `hex` or `bech32` secret key string - fn from_sk_str( - secret_key: &str, - secp: &Secp256k1, - ) -> Result; } /// Trait for [`Keys`] pub trait FromPkStr: Sized { /// Error type Err; + /// Init [`Keys`] from `hex` or `bech32` public key string fn from_pk_str(public_key: &str) -> Result; } @@ -111,25 +91,8 @@ pub struct Keys { impl Keys { /// Initialize from secret key. - #[cfg(feature = "std")] pub fn new(secret_key: SecretKey) -> Self { - let key_pair = KeyPair::from_secret_key(SECP256K1, &secret_key); - let public_key = XOnlyPublicKey::from_keypair(&key_pair).0; - - Self { - public_key, - key_pair: Some(key_pair), - secret_key: Some(secret_key), - } - } - - /// Initialize from secret key. - #[cfg(not(feature = "std"))] - pub fn new_with_secp( - secret_key: SecretKey, - secp: &Secp256k1, - ) -> Self { - let key_pair = KeyPair::from_secret_key(secp, &secret_key); + let key_pair = KeyPair::from_secret_key(&SECP256K1, &secret_key); let public_key = XOnlyPublicKey::from_keypair(&key_pair).0; Self { @@ -149,44 +112,23 @@ impl Keys { } /// Generate new random [`Keys`] - #[cfg(feature = "std")] pub fn generate() -> Self { let mut rng = OsRng::default(); - let (secret_key, _) = SECP256K1.generate_keypair(&mut rng); + let secret_key = SecretKey::new(&mut rng); Self::new(secret_key) } - /// Generate new random [`Keys`] - #[cfg(not(feature = "std"))] - pub fn generate_with_secp(secp: &Secp256k1) -> Self { - let mut rng = OsRng::default(); - let (secret_key, _) = secp.generate_keypair(&mut rng); - Self::new_with_secp(secret_key, secp) - } - /// Generate random [`Keys`] with custom [`Rng`] - #[cfg(feature = "std")] pub fn generate_with_rng(rng: &mut R) -> Self where R: Rng + ?Sized, { - let (secret_key, _) = SECP256K1.generate_keypair(rng); + let secret_key = SecretKey::new(rng); Self::new(secret_key) } - /// Generate random [`Keys`] with custom [`Rng`] and given [`Secp256k1`] - #[cfg(not(feature = "std"))] - pub fn generate_with_rng_with_secp(rng: &mut R, secp: &Secp256k1) -> Self - where - R: Rng + ?Sized, - { - let (secret_key, _) = secp.generate_keypair(rng); - Self::new_with_secp(secret_key, secp) - } - /// Generate random [`Keys`] with custom [`Rng`] and without [`KeyPair`] /// Useful for faster [`Keys`] generation (ex. vanity pubkey mining) - #[cfg(feature = "std")] pub fn generate_without_keypair(rng: &mut R) -> Self where R: Rng + ?Sized, @@ -200,25 +142,6 @@ impl Keys { } } - /// Generate random [`Keys`] with custom [`Rng`] and without [`KeyPair`] - /// Useful for faster [`Keys`] generation (ex. vanity pubkey mining) - #[cfg(not(feature = "std"))] - pub fn generate_without_keypair_with_secp( - rng: &mut R, - secp: &Secp256k1, - ) -> Self - where - R: Rng + ?Sized, - { - let (secret_key, public_key) = secp.generate_keypair(rng); - let (public_key, _) = public_key.x_only_public_key(); - Self { - public_key, - key_pair: None, - secret_key: Some(secret_key), - } - } - /// Get public key pub fn public_key(&self) -> XOnlyPublicKey { self.public_key @@ -233,58 +156,35 @@ impl Keys { } } - /// Get [`PublicKey`] - #[cfg(feature = "std")] + /// Get normalized [`PublicKey`] pub fn normalized_public_key(&self) -> Result { - Ok(self.secret_key()?.public_key(SECP256K1)) + Ok(self.secret_key()?.public_key(&SECP256K1)) } /// Get keypair /// /// If not exists, will be created - #[cfg(feature = "std")] pub fn key_pair(&self) -> Result { if let Some(key_pair) = self.key_pair { Ok(key_pair) } else { let sk = self.secret_key()?; - Ok(KeyPair::from_secret_key(SECP256K1, &sk)) - } - } - - /// Get keypair - /// - /// If not exists, will be created - #[cfg(not(feature = "std"))] - pub fn key_pair_from_secp(&self, secp: &Secp256k1) -> Result { - if let Some(key_pair) = self.key_pair { - Ok(key_pair) - } else { - let sk = self.secret_key()?; - Ok(KeyPair::from_secret_key(secp, &sk)) + Ok(KeyPair::from_secret_key(&SECP256K1, &sk)) } } /// Sign schnorr [`Message`] - #[cfg(feature = "std")] pub fn sign_schnorr(&self, message: &Message) -> Result { let keypair: &KeyPair = &self.key_pair()?; - Ok(SECP256K1.sign_schnorr(message, keypair)) - } - - /// Sign schnorr [`Message`] - #[cfg(not(feature = "std"))] - pub fn sign_schnorr_with_secp( - &self, - message: &Message, - secp: &Secp256k1, - ) -> Result { - let keypair: &KeyPair = &self.key_pair_from_secp(&secp)?; - Ok(secp.sign_schnorr_no_aux_rand(message, keypair)) + #[cfg(feature = "std")] + let sig = SECP256K1.sign_schnorr(message, keypair); + #[cfg(not(feature = "std"))] + let sig = SECP256K1.sign_schnorr_no_aux_rand(message, keypair); + Ok(sig) } } -#[cfg(all(feature = "std", feature = "nip19", not(feature = "alloc")))] +#[cfg(feature = "nip19")] impl FromSkStr for Keys { type Err = Error; @@ -299,24 +199,7 @@ impl FromSkStr for Keys { } } } -#[cfg(all(feature = "alloc", feature = "nip19", not(feature = "std")))] -impl FromSkStr for Keys { - type Err = Error; - /// Init [`Keys`] from `hex` or `bech32` secret key - fn from_sk_str( - secret_key: &str, - secp: &Secp256k1, - ) -> Result { - match SecretKey::from_str(secret_key) { - Ok(secret_key) => Ok(Self::new_with_secp(secret_key, &secp)), - Err(_) => match SecretKey::from_bech32(secret_key) { - Ok(secret_key) => Ok(Self::new_with_secp(secret_key, &secp)), - Err(_) => Err(Error::InvalidSecretKey), - }, - } - } -} #[cfg(feature = "nip19")] impl FromPkStr for Keys { type Err = Error; diff --git a/crates/nostr/src/key/vanity.rs b/crates/nostr/src/key/vanity.rs index 064abad68..a08652f52 100644 --- a/crates/nostr/src/key/vanity.rs +++ b/crates/nostr/src/key/vanity.rs @@ -3,18 +3,16 @@ //! Vanity +#[cfg(all(feature = "alloc", not(feature = "std")))] +use core::error::Error as StdError; use core::fmt; use core::sync::atomic::{AtomicBool, Ordering}; +#[cfg(feature = "std")] +use std::error::Error as StdError; use std::sync::mpsc::{sync_channel, RecvError}; use std::sync::Arc; use std::thread; -#[cfg(all(feature = "alloc", not(feature = "std")))] -use core::error::Error as StdError; - -#[cfg(feature = "std")] -use std::error::Error as StdError; - use secp256k1::rand; use secp256k1::SecretKey; diff --git a/crates/nostr/src/lib.rs b/crates/nostr/src/lib.rs index 76fa8a393..4057f8c5f 100644 --- a/crates/nostr/src/lib.rs +++ b/crates/nostr/src/lib.rs @@ -12,16 +12,12 @@ doc = include_str!("../README.md") )] #![cfg_attr(not(feature = "std"), no_std)] + #[cfg(feature = "alloc")] extern crate alloc; - #[cfg(feature = "alloc")] use alloc::boxed::Box; -#[macro_use] -/// Serde crate -pub extern crate serde; - #[cfg(feature = "nip19")] pub use bech32; #[cfg(feature = "nip06")] @@ -29,16 +25,16 @@ pub use bip39; #[cfg(feature = "nip06")] pub use bitcoin; pub use bitcoin_hashes as hashes; +pub use once_cell; +use once_cell::sync::Lazy; pub use secp256k1; -#[cfg(feature = "std")] -pub use secp256k1::SECP256K1; +use secp256k1::rand::rngs::OsRng; +use secp256k1::{All, Secp256k1}; pub use serde_json; - #[cfg(feature = "std")] pub use url; #[cfg(all(feature = "alloc", not(feature = "std")))] extern crate url_no_std as url; - pub use url::Url; pub mod event; @@ -56,6 +52,13 @@ pub use self::types::{ChannelId, Contact, Entity, Metadata, Profile, Timestamp, /// Result #[cfg(feature = "std")] pub type Result> = std::result::Result; -/// Result #[cfg(all(feature = "alloc", not(feature = "std")))] pub type Result> = core::result::Result; + +/// Secp256k1 global context +pub static SECP256K1: Lazy> = Lazy::new(|| { + let mut ctx = Secp256k1::new(); + let mut rng = OsRng::default(); + ctx.randomize(&mut rng); + ctx +}); diff --git a/crates/nostr/src/message/client.rs b/crates/nostr/src/message/client.rs index fef725a3d..00b7784ac 100644 --- a/crates/nostr/src/message/client.rs +++ b/crates/nostr/src/message/client.rs @@ -9,7 +9,9 @@ use alloc::boxed::Box; #[cfg(feature = "alloc")] use alloc::string::{String, ToString}; #[cfg(feature = "alloc")] -use alloc::{vec, vec::Vec}; +use alloc::vec; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; use serde::de::Error; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -223,7 +225,6 @@ impl ClientMessage { S: Into, { let msg: &str = &msg.into(); - log::trace!("{}", msg); if msg.is_empty() { return Err(MessageHandleError::InvalidMessageFormat); diff --git a/crates/nostr/src/message/mod.rs b/crates/nostr/src/message/mod.rs index 16a34322e..35678051e 100644 --- a/crates/nostr/src/message/mod.rs +++ b/crates/nostr/src/message/mod.rs @@ -3,11 +3,9 @@ //! Messages -use core::fmt; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; #[cfg(feature = "std")] use std::error::Error as StdError; diff --git a/crates/nostr/src/message/relay.rs b/crates/nostr/src/message/relay.rs index 6433f2b5e..f9de8f3de 100644 --- a/crates/nostr/src/message/relay.rs +++ b/crates/nostr/src/message/relay.rs @@ -250,7 +250,6 @@ impl RelayMessage { S: Into, { let msg: &str = &msg.into(); - log::trace!("{}", msg); if msg.is_empty() { return Ok(Self::Empty); diff --git a/crates/nostr/src/message/subscription.rs b/crates/nostr/src/message/subscription.rs index 84ab313c1..35a5f121d 100644 --- a/crates/nostr/src/message/subscription.rs +++ b/crates/nostr/src/message/subscription.rs @@ -5,19 +5,17 @@ //! Subscription filters #![allow(missing_docs)] -use core::fmt; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::string::{String, ToString}; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::{vec, vec::Vec}; +use core::fmt; use bitcoin_hashes::sha256::Hash as Sha256Hash; use bitcoin_hashes::Hash; -#[cfg(all(feature = "alloc", not(feature = "std")))] -use rand::{rngs::OsRng, RngCore}; -#[cfg(feature = "std")] -use secp256k1::rand::{rngs::OsRng, RngCore}; +use secp256k1::rand::rngs::OsRng; +use secp256k1::rand::RngCore; use secp256k1::XOnlyPublicKey; use serde::de::{self, Deserializer, MapAccess, Visitor}; use serde::ser::{SerializeMap, Serializer}; diff --git a/crates/nostr/src/nips/nip04.rs b/crates/nostr/src/nips/nip04.rs index b1ccbae51..6b6193dd6 100644 --- a/crates/nostr/src/nips/nip04.rs +++ b/crates/nostr/src/nips/nip04.rs @@ -7,12 +7,10 @@ //! use core::convert::From; -use core::fmt; -use core::str::FromStr; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; +use core::str::FromStr; #[cfg(feature = "std")] use std::error::Error as StdError; @@ -21,7 +19,7 @@ use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit}; use aes::Aes256; use base64::engine::{general_purpose, Engine}; use cbc::{Decryptor, Encryptor}; -use secp256k1::{ecdh, PublicKey, SecretKey, XOnlyPublicKey}; +use secp256k1::{ecdh, rand, PublicKey, SecretKey, XOnlyPublicKey}; type Aes256CbcEnc = Encryptor; type Aes256CbcDec = Decryptor; @@ -70,7 +68,7 @@ where T: AsRef<[u8]>, { let key: [u8; 32] = generate_shared_key(sk, pk)?; - let iv: [u8; 16] = secp256k1::rand::random(); + let iv: [u8; 16] = rand::random(); let cipher = Aes256CbcEnc::new(&key.into(), &iv.into()); let result: Vec = cipher.encrypt_padded_vec_mut::(text.as_ref()); @@ -142,13 +140,13 @@ mod tests { let sender_sk = SecretKey::from_str( "6b911fd37cdf5c81d4c0adb1ab7fa822ed253ab0ad9aa18d77257c88b29b718e", )?; - let sender_key_pair = KeyPair::from_secret_key(SECP256K1, &sender_sk); + let sender_key_pair = KeyPair::from_secret_key(&SECP256K1, &sender_sk); let sender_pk = XOnlyPublicKey::from_keypair(&sender_key_pair).0; let receiver_sk = SecretKey::from_str( "7b911fd37cdf5c81d4c0adb1ab7fa822ed253ab0ad9aa18d77257c88b29b718e", )?; - let receiver_key_pair = KeyPair::from_secret_key(SECP256K1, &receiver_sk); + let receiver_key_pair = KeyPair::from_secret_key(&SECP256K1, &receiver_sk); let receiver_pk = XOnlyPublicKey::from_keypair(&receiver_key_pair).0; let encrypted_content_from_outside = diff --git a/crates/nostr/src/nips/nip05.rs b/crates/nostr/src/nips/nip05.rs index 7b9a48a43..160875022 100644 --- a/crates/nostr/src/nips/nip05.rs +++ b/crates/nostr/src/nips/nip05.rs @@ -5,15 +5,12 @@ //! //! -use core::fmt; -use core::str::FromStr; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; +use core::str::FromStr; #[cfg(feature = "std")] use std::error::Error as StdError; - #[cfg(not(target_arch = "wasm32"))] use std::net::SocketAddr; diff --git a/crates/nostr/src/nips/nip06.rs b/crates/nostr/src/nips/nip06.rs index bac554f73..d137e05b9 100644 --- a/crates/nostr/src/nips/nip06.rs +++ b/crates/nostr/src/nips/nip06.rs @@ -5,12 +5,10 @@ //! //! -use core::fmt; -use core::str::FromStr; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; +use core::str::FromStr; #[cfg(feature = "std")] use std::error::Error as StdError; @@ -82,7 +80,7 @@ impl FromMnemonic for Keys { let seed = mnemonic.to_seed(passphrase.map(|p| p.into()).unwrap_or_default()); let root_key = ExtendedPrivKey::new_master(Network::Bitcoin, &seed)?; let path = DerivationPath::from_str("m/44'/1237'/0'/0/0")?; - let child_xprv = root_key.derive_priv(SECP256K1, &path)?; + let child_xprv = root_key.derive_priv(&SECP256K1, &path)?; Ok(Self::new(child_xprv.private_key)) } } diff --git a/crates/nostr/src/nips/nip11.rs b/crates/nostr/src/nips/nip11.rs index b78c3e83b..9bc558e5d 100644 --- a/crates/nostr/src/nips/nip11.rs +++ b/crates/nostr/src/nips/nip11.rs @@ -6,14 +6,11 @@ //! //! -use core::fmt; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; #[cfg(feature = "std")] use std::error::Error as StdError; - #[cfg(not(target_arch = "wasm32"))] use std::net::SocketAddr; diff --git a/crates/nostr/src/nips/nip13.rs b/crates/nostr/src/nips/nip13.rs index b67da095b..69d5cf92c 100644 --- a/crates/nostr/src/nips/nip13.rs +++ b/crates/nostr/src/nips/nip13.rs @@ -11,7 +11,7 @@ use alloc::format; #[cfg(feature = "alloc")] use alloc::string::String; #[cfg(feature = "alloc")] -use alloc::{vec, vec::Vec}; +use alloc::vec::Vec; /// Gets the number of leading zero bits. Result is between 0 and 255. pub fn get_leading_zero_bits(h: T) -> u8 @@ -34,7 +34,7 @@ where /// /// Possible values: 0-255 pub fn get_prefixes_for_difficulty(leading_zero_bits: u8) -> Vec { - let mut r = vec![]; + let mut r = Vec::new(); if leading_zero_bits == 0 { return r; diff --git a/crates/nostr/src/nips/nip19.rs b/crates/nostr/src/nips/nip19.rs index c8d0b5c30..f9774bcb3 100644 --- a/crates/nostr/src/nips/nip19.rs +++ b/crates/nostr/src/nips/nip19.rs @@ -11,14 +11,11 @@ use alloc::string::{FromUtf8Error, ToString}; #[cfg(not(feature = "std"))] use alloc::vec::{self, Vec}; -use core::fmt; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; #[cfg(feature = "std")] use std::error::Error as StdError; - #[cfg(feature = "std")] use std::string::FromUtf8Error; diff --git a/crates/nostr/src/nips/nip21.rs b/crates/nostr/src/nips/nip21.rs index 2ac8daf98..b551edc12 100644 --- a/crates/nostr/src/nips/nip21.rs +++ b/crates/nostr/src/nips/nip21.rs @@ -5,11 +5,9 @@ //! //! -use core::fmt; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; #[cfg(feature = "std")] use std::error::Error as StdError; diff --git a/crates/nostr/src/nips/nip26.rs b/crates/nostr/src/nips/nip26.rs index b49e4c27f..0d507e2c5 100644 --- a/crates/nostr/src/nips/nip26.rs +++ b/crates/nostr/src/nips/nip26.rs @@ -5,20 +5,17 @@ //! //! -use core::fmt; -use core::num::ParseIntError; -use core::str::FromStr; - #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::format; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::string::{String, ToString}; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::{vec, vec::Vec}; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; +use core::num::ParseIntError; +use core::str::FromStr; #[cfg(feature = "std")] use std::error::Error as StdError; @@ -32,13 +29,8 @@ use serde_json::{json, Value}; use crate::event::Event; use crate::key::{self, Keys}; - -#[cfg(feature = "std")] use crate::SECP256K1; -#[cfg(not(feature = "std"))] -use secp256k1::{Secp256k1, Signing, Verification}; - const DELEGATION_KEYWORD: &str = "delegation"; /// `NIP26` error @@ -129,7 +121,6 @@ impl fmt::Display for ValidationError { /// Sign delegation. /// See `create_delegation_tag` for more complete functionality. -#[cfg(feature = "std")] pub fn sign_delegation( delegator_keys: &Keys, delegatee_pk: XOnlyPublicKey, @@ -141,23 +132,7 @@ pub fn sign_delegation( Ok(delegator_keys.sign_schnorr(&message)?) } -/// Sign delegation. -/// See `create_delegation_tag` for more complete functionality. -#[cfg(not(feature = "std"))] -pub fn sign_delegation_with_signer( - delegator_keys: &Keys, - delegatee_pk: XOnlyPublicKey, - conditions: Conditions, - secp: &Secp256k1, -) -> Result { - let unhashed_token = DelegationToken::new(delegatee_pk, conditions); - let hashed_token = Sha256Hash::hash(unhashed_token.as_bytes()); - let message = Message::from_slice(hashed_token.as_byte_array())?; - Ok(delegator_keys.sign_schnorr_with_secp(&message, secp)?) -} - /// Verify delegation signature -#[cfg(feature = "std")] pub fn verify_delegation_signature( delegator_public_key: XOnlyPublicKey, signature: Signature, @@ -171,22 +146,6 @@ pub fn verify_delegation_signature( Ok(()) } -/// Verify delegation signature -#[cfg(not(feature = "std"))] -pub fn verify_delegation_signature( - delegator_public_key: XOnlyPublicKey, - signature: Signature, - delegatee_public_key: XOnlyPublicKey, - conditions: Conditions, - secp: &Secp256k1, -) -> Result<(), Error> { - let unhashed_token = DelegationToken::new(delegatee_public_key, conditions); - let hashed_token = Sha256Hash::hash(unhashed_token.as_bytes()); - let message = Message::from_slice(hashed_token.as_byte_array())?; - secp.verify_schnorr(&signature, &message, &delegator_public_key)?; - Ok(()) -} - /// Delegation token #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct DelegationToken(String); @@ -222,7 +181,6 @@ pub struct DelegationTag { impl DelegationTag { /// Create a delegation tag (including the signature). /// See also validate(). - #[cfg(feature = "std")] pub fn new( delegator_keys: &Keys, delegatee_pubkey: XOnlyPublicKey, @@ -236,28 +194,6 @@ impl DelegationTag { }) } - /// Create a delegation tag (including the signature). - /// See also validate(). - #[cfg(not(feature = "std"))] - pub fn new( - delegator_keys: &Keys, - delegatee_pubkey: XOnlyPublicKey, - conditions: Conditions, - signer: Secp256k1, - ) -> Result { - let signature = sign_delegation_with_signer( - delegator_keys, - delegatee_pubkey, - conditions.clone(), - &signer, - )?; - Ok(Self { - delegator_pubkey: delegator_keys.public_key(), - conditions, - signature, - }) - } - /// Get delegator public key pub fn delegator_pubkey(&self) -> XOnlyPublicKey { self.delegator_pubkey @@ -274,7 +210,6 @@ impl DelegationTag { } /// Validate a delegation tag, check signature and conditions. - #[cfg(feature = "std")] pub fn validate( &self, delegatee_pubkey: XOnlyPublicKey, @@ -294,30 +229,6 @@ impl DelegationTag { Ok(()) } - /// Validate a delegation tag, check signature and conditions. - #[cfg(not(feature = "std"))] - pub fn validate( - &self, - delegatee_pubkey: XOnlyPublicKey, - event_properties: &EventProperties, - secp: &Secp256k1, - ) -> Result<(), Error> { - // verify signature - - verify_delegation_signature( - self.delegator_pubkey, - self.signature, - delegatee_pubkey, - self.conditions.clone(), - secp, - ) - .map_err(|_| Error::ConditionsValidation(ValidationError::InvalidSignature))?; - - // validate conditions - self.conditions.evaluate(event_properties)?; - - Ok(()) - } /// Convert to JSON string. pub fn as_json(&self) -> String { diff --git a/crates/nostr/src/nips/nip46.rs b/crates/nostr/src/nips/nip46.rs index 3430e491d..94bd29904 100644 --- a/crates/nostr/src/nips/nip46.rs +++ b/crates/nostr/src/nips/nip46.rs @@ -5,13 +5,11 @@ //! //! +#[cfg(all(feature = "alloc", not(feature = "std")))] +use core::error::Error as StdError; use core::fmt; use core::str::FromStr; use std::borrow::Cow; - -#[cfg(all(feature = "alloc", not(feature = "std")))] -use core::error::Error as StdError; - #[cfg(feature = "std")] use std::error::Error as StdError; diff --git a/crates/nostr/src/nips/nip58.rs b/crates/nostr/src/nips/nip58.rs index 9f80e2940..43a3a1869 100644 --- a/crates/nostr/src/nips/nip58.rs +++ b/crates/nostr/src/nips/nip58.rs @@ -5,28 +5,24 @@ use core::fmt; #[cfg(all(feature = "alloc", not(feature = "std")))] -use crate::alloc::borrow::ToOwned; +use alloc::borrow::ToOwned; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::string::String; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::{vec, vec::Vec}; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - #[cfg(feature = "std")] use std::error::Error as StdError; -#[cfg(all(feature = "alloc", not(feature = "std")))] -use crate::prelude::{Secp256k1, Signing}; -#[cfg(all(feature = "alloc", not(feature = "std")))] -use crate::types::Timestamp; - use secp256k1::XOnlyPublicKey; use crate::event::builder::Error as BuilderError; use crate::{Event, EventBuilder, Keys, Kind, Tag, UncheckedUrl}; +#[cfg(all(feature = "alloc", not(feature = "std")))] +use crate::Timestamp; + #[derive(Debug)] /// [`BadgeAward`] error pub enum Error { @@ -121,23 +117,20 @@ impl BadgeDefinitionBuilder { pub fn build(self, keys: &Keys) -> Result { let event_builder = self.build_internal()?; let event = event_builder.to_event(keys)?; - Ok(BadgeDefinition(event)) } - /// Build [`Event`] #[cfg(all(feature = "alloc", not(feature = "std")))] - pub fn build( + pub fn build( self, keys: &Keys, created_at: Timestamp, - secp: &Secp256k1, ) -> Result { let event_builder = self.build_internal()?; - let event = event_builder.to_event_with_timestamp_with_secp(&keys, created_at, secp)?; - + let event = event_builder.to_event_with_timestamp(keys, created_at)?; Ok(BadgeDefinition(event)) } + /// Build [`Event`] fn build_internal(self) -> Result { let mut tags: Vec = Vec::new(); @@ -199,22 +192,18 @@ impl BadgeAward { ) -> Result { let event_builder = BadgeAward::new_internal(badge_definition, awarded_pub_keys, keys)?; let event = event_builder.to_event(keys)?; - Ok(BadgeAward(event)) } - /// New [`BadgeAward`] #[cfg(all(feature = "alloc", not(feature = "std")))] - pub fn new( + pub fn new( badge_definition: &Event, awarded_pub_keys: Vec, keys: &Keys, created_at: Timestamp, - secp: &Secp256k1, ) -> Result { let event_builder = BadgeAward::new_internal(badge_definition, awarded_pub_keys, keys)?; - let event = event_builder.to_event_with_timestamp_with_secp(&keys, created_at, secp)?; - + let event = event_builder.to_event_with_timestamp(keys, created_at)?; Ok(BadgeAward(event)) } @@ -333,35 +322,33 @@ impl ProfileBadgesEvent { }) } - #[cfg(all(feature = "alloc", not(feature = "std")))] /// Create a new [`ProfileBadgesEvent`] from badge definition and awards events /// [`badge_definitions`] and [`badge_awards`] must be ordered, so on the same position they refer to the same badge - pub fn new( + #[cfg(feature = "std")] + pub fn new( badge_definitions: Vec, badge_awards: Vec, pubkey_awarded: &XOnlyPublicKey, keys: &Keys, - created_at: Timestamp, - secp: &Secp256k1, ) -> Result { let event_builder = ProfileBadgesEvent::new_internal(badge_definitions, badge_awards, pubkey_awarded)?; - let event = event_builder.to_event_with_timestamp_with_secp(keys, created_at, &secp)?; + let event = event_builder.to_event(keys)?; Ok(ProfileBadgesEvent(event)) } - #[cfg(feature = "std")] - /// Create a new [`ProfileBadgesEvent`] from badge definition and awards events - /// [`badge_definitions`] and [`badge_awards`] must be ordered, so on the same position they refer to the same badge + + #[cfg(all(feature = "alloc", not(feature = "std")))] pub fn new( badge_definitions: Vec, badge_awards: Vec, pubkey_awarded: &XOnlyPublicKey, keys: &Keys, + created_at: Timestamp, ) -> Result { let event_builder = ProfileBadgesEvent::new_internal(badge_definitions, badge_awards, pubkey_awarded)?; - let event = event_builder.to_event(keys)?; + let event = event_builder.to_event_with_timestamp(keys, created_at)?; Ok(ProfileBadgesEvent(event)) } diff --git a/crates/nostr/src/prelude.rs b/crates/nostr/src/prelude.rs index 2a20b4473..a6cb85792 100644 --- a/crates/nostr/src/prelude.rs +++ b/crates/nostr/src/prelude.rs @@ -2,7 +2,7 @@ // Distributed under the MIT software license //! Prelude -//#![allow(ambiguous_glob_reexports)] + #![cfg_attr( all(not(feature = "std"), feature = "alloc"), allow(ambiguous_glob_reexports) diff --git a/crates/nostr/src/types/channel_id.rs b/crates/nostr/src/types/channel_id.rs index cd0b57a25..fd80d439e 100644 --- a/crates/nostr/src/types/channel_id.rs +++ b/crates/nostr/src/types/channel_id.rs @@ -3,17 +3,16 @@ //! Channel Id -use core::fmt; -use core::str::FromStr; - #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::string::{String, ToString}; +#[cfg(all(feature = "nip19", feature = "alloc", not(feature = "std")))] +use alloc::vec; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec::Vec; - #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; +use core::str::FromStr; #[cfg(feature = "std")] use std::error::Error as StdError; @@ -165,9 +164,6 @@ impl FromBech32 for ChannelId { } } -#[cfg(all(feature = "nip19", feature = "alloc", not(feature = "std")))] -use alloc::vec; - #[cfg(feature = "nip19")] impl ToBech32 for ChannelId { type Err = Bech32Error; diff --git a/crates/nostr/src/types/metadata.rs b/crates/nostr/src/types/metadata.rs index 9cc539fc8..1e7074f4d 100644 --- a/crates/nostr/src/types/metadata.rs +++ b/crates/nostr/src/types/metadata.rs @@ -3,20 +3,17 @@ //! Metadata -use core::fmt; - +#[cfg(feature = "alloc")] +use alloc::string::{String, ToString}; #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; - +use core::fmt; #[cfg(feature = "std")] use std::error::Error as StdError; use serde::{Deserialize, Serialize}; use url::Url; -#[cfg(feature = "alloc")] -use alloc::string::{String, ToString}; - /// [`Metadata`] error #[derive(Debug)] pub enum Error { diff --git a/crates/nostr/src/types/profile.rs b/crates/nostr/src/types/profile.rs index 5776695b6..652afb974 100644 --- a/crates/nostr/src/types/profile.rs +++ b/crates/nostr/src/types/profile.rs @@ -3,20 +3,23 @@ //! Profile +#[cfg(feature = "alloc")] +use alloc::string::String; #[cfg(all(feature = "nip19", feature = "alloc"))] use alloc::string::ToString; +#[cfg(all(feature = "nip19", feature = "alloc"))] +use alloc::vec; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + #[cfg(feature = "nip19")] use bech32::{self, FromBase32, ToBase32, Variant}; use secp256k1::XOnlyPublicKey; +use serde::{Deserialize, Serialize}; #[cfg(feature = "nip19")] use crate::nips::nip19::{Error, FromBech32, ToBech32, PREFIX_BECH32_PROFILE, RELAY, SPECIAL}; -#[cfg(feature = "alloc")] -use alloc::string::String; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; - /// Profile #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct Profile { @@ -86,8 +89,6 @@ impl FromBech32 for Profile { } } -#[cfg(all(feature = "nip19", feature = "alloc"))] -use alloc::vec; #[cfg(feature = "nip19")] impl ToBech32 for Profile { type Err = Error; diff --git a/crates/nostr/src/types/time.rs b/crates/nostr/src/types/time/mod.rs similarity index 58% rename from crates/nostr/src/types/time.rs rename to crates/nostr/src/types/time/mod.rs index 6c21f92fb..f08396dde 100644 --- a/crates/nostr/src/types/time.rs +++ b/crates/nostr/src/types/time/mod.rs @@ -3,16 +3,6 @@ //! Time -use core::ops::{Add, Sub}; -use core::str::FromStr; -use core::time::Duration; - -#[cfg(feature = "std")] -use std::{ - fmt, num, - time::{SystemTime, UNIX_EPOCH}, -}; - #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::fmt; #[cfg(all(feature = "alloc", not(feature = "std")))] @@ -21,115 +11,19 @@ use alloc::string::String; use alloc::vec::Vec; #[cfg(all(feature = "alloc", not(feature = "std")))] use core::num; +use core::ops::{Add, Sub}; +use core::str::FromStr; +use core::time::Duration; +#[cfg(feature = "std")] +use std::time::{SystemTime, UNIX_EPOCH}; +#[cfg(feature = "std")] +use std::{fmt, num}; use serde::{Deserialize, Serialize}; -/// Helper trait for acquiring time in `no_std` environments. -pub trait TimeSupplier { - /// The current time from the specified `TimeSupplier` - type Now: Clone; - /// The starting point for the specified `TimeSupplier` - type StartingPoint: Clone; - - /// Get the current time as the associated `Now` type - fn instant_now(&self) -> Self::Now; - /// Get the current time as the associated `StartingPoint` type - fn now(&self) -> Self::StartingPoint; - /// Get a duration since the StartingPoint. - fn duration_since_starting_point(&self, now: Self::StartingPoint) -> Duration; - /// Get the starting point from the specified `TimeSupplier` - fn starting_point(&self) -> Self::StartingPoint; - /// Get the elapsed time as `Duration` starting from `since` to `now` - fn elapsed_instant_since(&self, now: Self::Now, since: Self::Now) -> Duration; - /// Get the elapsed time as `Duration` starting from `since` to `now` - fn elapsed_since(&self, now: Self::StartingPoint, since: Self::StartingPoint) -> Duration; - /// Convert the specified `Duration` to `i64` - fn as_i64(&self, duration: Duration) -> i64; - /// Convert the specified `Duration` to `Timestamp` - fn to_timestamp(&self, duration: Duration) -> Timestamp; -} - -#[cfg(target_arch = "wasm32")] -use instant::Instant as InstantWasm32; -#[cfg(target_arch = "wasm32")] -impl TimeSupplier for InstantWasm32 { - type Now = InstantWasm32; - type StartingPoint = std::time::SystemTime; - - fn now(&self) -> Self::StartingPoint { - SystemTime::now() - } - - fn instant_now(&self) -> Self::Now { - InstantWasm32::now() - } - - fn duration_since_starting_point(&self, now: Self::StartingPoint) -> Duration { - now.duration_since(self.starting_point()) - .expect("duration_since panicked") - } - - fn starting_point(&self) -> Self::StartingPoint { - std::time::UNIX_EPOCH - } - - fn elapsed_instant_since(&self, now: Self::Now, since: Self::Now) -> Duration { - now - since - } - - fn elapsed_since(&self, now: Self::StartingPoint, since: Self::StartingPoint) -> Duration { - now.duration_since(since).expect("duration_since panicked") - } - - fn as_i64(&self, duration: Duration) -> i64 { - duration.as_millis() as i64 - } - - fn to_timestamp(&self, duration: Duration) -> Timestamp { - Timestamp(self.as_i64(duration)) - } -} - -#[cfg(all(not(target_arch = "wasm32"), feature = "std"))] -use std::time::Instant; -#[cfg(all(not(target_arch = "wasm32"), feature = "std"))] -impl TimeSupplier for Instant { - type Now = Instant; - type StartingPoint = std::time::SystemTime; - - fn now(&self) -> Self::StartingPoint { - SystemTime::now() - } - - fn instant_now(&self) -> Self::Now { - Instant::now() - } - - fn duration_since_starting_point(&self, now: Self::StartingPoint) -> Duration { - now.duration_since(self.starting_point()) - .expect("duration_since panicked") - } - - fn starting_point(&self) -> Self::StartingPoint { - std::time::UNIX_EPOCH - } - - fn elapsed_instant_since(&self, now: Self::Now, since: Self::Now) -> Duration { - now - since - } - - fn elapsed_since(&self, now: Self::StartingPoint, since: Self::StartingPoint) -> Duration { - now.duration_since(since).expect("duration_since panicked") - } - - fn as_i64(&self, duration: Duration) -> i64 { - duration.as_millis() as i64 - } +pub mod supplier; - fn to_timestamp(&self, duration: Duration) -> Timestamp { - Timestamp(self.as_i64(duration)) - } -} +pub use self::supplier::TimeSupplier; /// Unix timestamp in seconds #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] @@ -146,17 +40,16 @@ impl Timestamp { Self(ts as i64) } - /// Get UNIX timestamp from the specified `TimeSupplier` + /// Get UNIX timestamp from a specified [`TimeSupplier`] #[cfg(not(feature = "std"))] - pub fn now_nostd(time_supplier: &T) -> Self + pub fn now_with_supplier(supplier: &T) -> Self where T: TimeSupplier, { - let now = time_supplier.now(); - let starting_point = time_supplier.starting_point(); - let duration = time_supplier.elapsed_since(now, starting_point); - - time_supplier.to_timestamp(duration) + let now = supplier.now(); + let starting_point = supplier.starting_point(); + let duration = supplier.elapsed_since(now, starting_point); + supplier.to_timestamp(duration) } /// Get timestamp as [`u64`] diff --git a/crates/nostr/src/types/time/supplier.rs b/crates/nostr/src/types/time/supplier.rs new file mode 100644 index 000000000..a84dcca0f --- /dev/null +++ b/crates/nostr/src/types/time/supplier.rs @@ -0,0 +1,109 @@ +// Copyright (c) 2022-2023 Yuki Kishimoto +// Distributed under the MIT software license + +//! Time supplier + +use core::ops::Sub; +use core::time::Duration; +#[cfg(all(feature = "std", not(target_arch = "wasm32")))] +use std::time::Instant; +#[cfg(feature = "std")] +use std::time::{SystemTime, UNIX_EPOCH}; + +#[cfg(target_arch = "wasm32")] +use instant::Instant as InstantWasm32; + +use super::Timestamp; + +/// Helper trait for acquiring time in `no_std` environments. +pub trait TimeSupplier { + /// The current time from the specified `TimeSupplier` + type Now: Clone + Sub; + /// The starting point for the specified `TimeSupplier` + type StartingPoint: Clone; + + /// Get the current time as the associated `StartingPoint` type + fn now(&self) -> Self::StartingPoint; + + /// Get the current time as the associated `Now` type + fn instant_now(&self) -> Self::Now; + + /// Get the starting point from the specified `TimeSupplier` + fn starting_point(&self) -> Self::StartingPoint; + + /// Get a duration since the StartingPoint. + fn duration_since_starting_point(&self, now: Self::StartingPoint) -> Duration; + + /// Get the elapsed time as `Duration` starting from `since` to `now` + fn elapsed_instant_since(&self, now: Self::Now, since: Self::Now) -> Duration; + + /// Get the elapsed time as `Duration` starting from `since` to `now` + fn elapsed_since(&self, now: Self::StartingPoint, since: Self::StartingPoint) -> Duration; + + /// Convert the specified `Duration` to `Timestamp` + fn to_timestamp(&self, duration: Duration) -> Timestamp { + Timestamp::from(duration.as_secs()) + } +} + +#[cfg(all(feature = "std", target_arch = "wasm32"))] +impl TimeSupplier for InstantWasm32 { + type Now = InstantWasm32; + type StartingPoint = std::time::SystemTime; + + fn now(&self) -> Self::StartingPoint { + SystemTime::now() + } + + fn instant_now(&self) -> Self::Now { + InstantWasm32::now() + } + + fn starting_point(&self) -> Self::StartingPoint { + UNIX_EPOCH + } + + fn duration_since_starting_point(&self, now: Self::StartingPoint) -> Duration { + now.duration_since(self.starting_point()) + .unwrap_or_default() + } + + fn elapsed_instant_since(&self, now: Self::Now, since: Self::Now) -> Duration { + now - since + } + + fn elapsed_since(&self, now: Self::StartingPoint, since: Self::StartingPoint) -> Duration { + now.duration_since(since).unwrap_or_default() + } +} + +#[cfg(all(feature = "std", not(target_arch = "wasm32")))] +impl TimeSupplier for Instant { + type Now = Instant; + type StartingPoint = std::time::SystemTime; + + fn now(&self) -> Self::StartingPoint { + SystemTime::now() + } + + fn instant_now(&self) -> Self::Now { + Instant::now() + } + + fn starting_point(&self) -> Self::StartingPoint { + UNIX_EPOCH + } + + fn duration_since_starting_point(&self, now: Self::StartingPoint) -> Duration { + now.duration_since(self.starting_point()) + .unwrap_or_default() + } + + fn elapsed_instant_since(&self, now: Self::Now, since: Self::Now) -> Duration { + now - since + } + + fn elapsed_since(&self, now: Self::StartingPoint, since: Self::StartingPoint) -> Duration { + now.duration_since(since).unwrap_or_default() + } +} diff --git a/crates/nostr/src/types/url.rs b/crates/nostr/src/types/url.rs index 56b2a93fa..4defc6b7b 100644 --- a/crates/nostr/src/types/url.rs +++ b/crates/nostr/src/types/url.rs @@ -3,19 +3,18 @@ //! Url -use core::fmt; -use core::str::FromStr; - -use serde::{Deserialize, Serialize}; -use url::{ParseError, Url}; - #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::string::String; #[cfg(all(feature = "alloc", not(feature = "std")))] use core::error::Error as StdError; +use core::fmt; +use core::str::FromStr; #[cfg(feature = "std")] use std::error::Error as StdError; +use serde::{Deserialize, Serialize}; +use url::{ParseError, Url}; + /// Url Error #[derive(Debug, PartialEq, Eq)] pub enum Error {