Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ build/
.flutter-plugins-dependencies
/packages/ndk/coverage/*
/packages/ndk/coverage.lcov
pubspec_overrides.yaml
pubspec_overrides.yaml
/packages/ndk/rust/target/
10 changes: 10 additions & 0 deletions packages/ndk/hook/build.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:hooks/hooks.dart';
import 'package:native_toolchain_rust/native_toolchain_rust.dart';

void main(List<String> args) async {
await build(args, (input, output) async {
await RustBuilder(
assetName: 'src/rust_lib.dart',
).run(input: input, output: output);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// Rust-based event verifier with platform-specific implementations.
///
/// On native platforms (Android, iOS, Linux, macOS, Windows), this uses FFI
/// to call Rust code for high-performance event verification.
///
/// On web platforms, this exports a stub that throws [UnsupportedError].
/// Use [Bip340EventVerifier] instead for web platforms.
library;

export 'rust_event_verifier_stub.dart'
if (dart.library.ffi) 'rust_event_verifier_native.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import 'dart:ffi';

import 'package:ffi/ffi.dart';

import '../../../domain_layer/entities/nip_01_event.dart';
import '../../../domain_layer/repositories/event_verifier.dart';
import '../../../src/rust_lib.dart' as rust_lib;

/// An implementation of [EventVerifier] that uses native Rust for event verification.
///
/// This class provides a bridge between Dart and Rust via FFI using native assets,
/// allowing for efficient verification of Nostr events using Rust's performance capabilities.
class RustEventVerifier implements EventVerifier {
/// Creates a new instance of [RustEventVerifier].
RustEventVerifier();

@override
Future<bool> verify(Nip01Event event) async {
// Convert strings to native pointers
final eventIdPtr = event.id.toNativeUtf8();
final pubKeyPtr = event.pubKey.toNativeUtf8();
final contentPtr = event.content.toNativeUtf8();
final signaturePtr = event.sig.toNativeUtf8();

// Prepare tags data
final tags = event.tags;
final tagsCount = tags.length;

// Calculate total number of strings across all tags
int totalStrings = 0;
for (final tag in tags) {
totalStrings += tag.length;
}

// Allocate arrays for tags
final tagsLengths = calloc<Uint32>(tagsCount == 0 ? 1 : tagsCount);
final tagsData =
calloc<Pointer<Utf8>>(totalStrings == 0 ? 1 : totalStrings);

try {
// Fill tag data
int stringIndex = 0;
for (int i = 0; i < tagsCount; i++) {
tagsLengths[i] = tags[i].length;
for (final element in tags[i]) {
tagsData[stringIndex] = element.toNativeUtf8();
stringIndex++;
}
}

// Call the native function
final result = rust_lib.verifyNostrEventNative(
eventIdPtr,
pubKeyPtr,
event.createdAt,
event.kind,
tagsData,
tagsLengths,
tagsCount,
contentPtr,
signaturePtr,
);

return result == 1;
} finally {
// Free all allocated memory
calloc.free(eventIdPtr);
calloc.free(pubKeyPtr);
calloc.free(contentPtr);
calloc.free(signaturePtr);

// Free tag string pointers
for (int i = 0; i < totalStrings; i++) {
calloc.free(tagsData[i]);
}
calloc.free(tagsData);
calloc.free(tagsLengths);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import '../../../domain_layer/entities/nip_01_event.dart';
import '../../../domain_layer/repositories/event_verifier.dart';

/// Stub implementation of [RustEventVerifier] for platforms that don't support FFI (e.g., web).
///
/// This class throws [UnsupportedError] for all operations since Rust FFI
/// is not available on web platforms.
class RustEventVerifier implements EventVerifier {
/// Creates a new instance of [RustEventVerifier].
///
/// Note: On web platforms, this verifier is not functional and will throw
/// [UnsupportedError] when [verify] is called.
RustEventVerifier();

@override
Future<bool> verify(Nip01Event event) async {
throw UnsupportedError(
'RustEventVerifier is not available on this platform. '
'Use Bip340EventVerifier instead for web platforms.',
);
}
}
1 change: 1 addition & 0 deletions packages/ndk/lib/ndk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export 'domain_layer/entities/account.dart';
export 'domain_layer/repositories/event_verifier.dart';
export 'domain_layer/repositories/event_signer.dart';
export 'data_layer/repositories/verifiers/bip340_event_verifier.dart';
export 'data_layer/repositories/verifiers/rust_event_verifier.dart';
export 'data_layer/repositories/signers/bip340_event_signer.dart';

/// cache
Expand Down
48 changes: 48 additions & 0 deletions packages/ndk/lib/src/rust_lib.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'dart:ffi';

import 'package:ffi/ffi.dart';

/// FFI bindings to the native Rust library.
/// This file is referenced by the native assets build hook.

/// Verifies a Nostr event signature.
///
/// Returns 1 if valid, 0 if invalid.
@Native<
Int32 Function(
Pointer<Utf8>, // eventIdHex
Pointer<Utf8>, // pubKeyHex
Uint64, // createdAt
Uint32, // kind
Pointer<Pointer<Utf8>>, // tagsData
Pointer<Uint32>, // tagsLengths
Uint32, // tagsCount
Pointer<Utf8>, // content
Pointer<Utf8>, // signatureHex
)>(symbol: 'verify_nostr_event')
external int verifyNostrEventNative(
Pointer<Utf8> eventIdHex,
Pointer<Utf8> pubKeyHex,
int createdAt,
int kind,
Pointer<Pointer<Utf8>> tagsData,
Pointer<Uint32> tagsLengths,
int tagsCount,
Pointer<Utf8> content,
Pointer<Utf8> signatureHex,
);

/// Verifies a Schnorr signature.
///
/// Returns 1 if valid, 0 if invalid.
@Native<
Int32 Function(
Pointer<Utf8>, // pubKeyHex
Pointer<Utf8>, // eventIdHex
Pointer<Utf8>, // signatureHex
)>(symbol: 'verify_schnorr_signature')
external int verifySchnorrSignatureNative(
Pointer<Utf8> pubKeyHex,
Pointer<Utf8> eventIdHex,
Pointer<Utf8> signatureHex,
);
74 changes: 73 additions & 1 deletion packages/ndk/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.0"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
url: "https://pub.dev"
source: hosted
version: "0.4.2"
code_assets:
dependency: transitive
description:
name: code_assets
sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
code_builder:
dependency: transitive
description:
Expand Down Expand Up @@ -202,13 +218,21 @@ packages:
source: hosted
version: "2.0.7"
ffi:
dependency: transitive
dependency: "direct main"
description:
name: ffi
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
ffigen:
dependency: "direct dev"
description:
name: ffigen
sha256: b7803707faeec4ce3c1b0c2274906504b796e3b70ad573577e72333bd1c9b3ba
url: "https://pub.dev"
source: hosted
version: "20.1.1"
file:
dependency: transitive
description:
Expand Down Expand Up @@ -257,6 +281,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.2"
hooks:
dependency: "direct main"
description:
name: hooks
sha256: "5d309c86e7ce34cd8e37aa71cb30cb652d3829b900ab145e4d9da564b31d59f7"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
http:
dependency: "direct main"
description:
Expand Down Expand Up @@ -361,6 +393,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.5.1"
native_toolchain_rust:
dependency: "direct main"
description:
name: native_toolchain_rust
sha256: b0e0a60c847db5ebc20939b78df5f17bcb63b2ff7fe75f437affeeab3dfed09d
url: "https://pub.dev"
source: hosted
version: "1.0.1"
node_preamble:
dependency: transitive
description:
Expand All @@ -385,6 +425,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.1"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
url: "https://pub.dev"
source: hosted
version: "7.0.1"
pointycastle:
dependency: "direct main"
description:
Expand Down Expand Up @@ -417,6 +465,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.0"
quiver:
dependency: transitive
description:
name: quiver
sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
url: "https://pub.dev"
source: hosted
version: "3.2.2"
rxdart:
dependency: "direct main"
description:
Expand Down Expand Up @@ -561,6 +617,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.6.12"
toml:
dependency: transitive
description:
name: toml
sha256: "35cd2a1351c14bd213f130f8efcbd3e0c18181bff0c8ca7a08f6822a2bede786"
url: "https://pub.dev"
source: hosted
version: "0.17.0"
typed_data:
dependency: transitive
description:
Expand Down Expand Up @@ -641,5 +705,13 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.3"
yaml_edit:
dependency: transitive
description:
name: yaml_edit
sha256: ec709065bb2c911b336853b67f3732dd13e0336bd065cc2f1061d7610ddf45e3
url: "https://pub.dev"
source: hosted
version: "2.2.3"
sdks:
dart: ">=3.9.0 <4.0.0"
5 changes: 5 additions & 0 deletions packages/ndk/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ dependencies:
cryptography: ^2.7.0
meta: ">=1.10.0 <2.0.0"
xxh3: ^1.2.0
hooks: ^1.0.0
native_toolchain_rust: ^1.0.1
ffi: ^2.1.4


dev_dependencies:
build_runner: ^2.10.0
Expand All @@ -44,3 +48,4 @@ dev_dependencies:
# shelf used for blossom mock server
shelf: ^1.4.2
shelf_router: ^1.1.4
ffigen: ^20.1.1
Loading