Skip to content
Merged
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
1 change: 1 addition & 0 deletions nostr-java-api/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

requires lombok;
requires java.logging;
requires nostr.crypto;

exports nostr.api;
}
17 changes: 17 additions & 0 deletions nostr-java-api/src/main/java/nostr/api/Nostr.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import nostr.client.Client;
import nostr.context.RequestContext;
import nostr.context.impl.DefaultRequestContext;
import nostr.crypto.schnorr.Schnorr;
import nostr.event.BaseEvent;
import nostr.event.BaseMessage;
import nostr.event.BaseTag;
Expand All @@ -33,6 +34,7 @@
import nostr.event.message.EventMessage;
import nostr.event.message.ReqMessage;
import nostr.id.Identity;
import nostr.util.NostrUtil;

import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -146,6 +148,21 @@ public Nostr sign(@NonNull Identity identity, @NonNull ISignable signable) {
return this;
}

public boolean verify(@NonNull GenericEvent event) {
if (!event.isSigned()) {
throw new IllegalStateException("The event is not signed");
}

var signature = event.getSignature();

try {
var message = NostrUtil.sha256(event.get_serializedEvent());
return Schnorr.verify(message, event.getPubKey().getRawData(), signature.getRawData());
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static Map<String, String> toMapRelays(List<Relay> relayList) {
Map<String, String> relays = new HashMap<>();
relayList.forEach(r -> relays.put(r.getName(), r.getUri()));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package nostr.crypto.schnorr;

import nostr.crypto.Point;
import nostr.util.NostrUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
Expand All @@ -12,11 +16,6 @@
import java.security.spec.ECGenParameterSpec;
import java.util.Arrays;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import nostr.crypto.Point;
import nostr.util.NostrUtil;

public class Schnorr {

/**
Expand Down Expand Up @@ -86,9 +85,11 @@ public static byte[] sign(byte[] msg, byte[] secKey, byte[] auxRand) throws Exce
* @throws Exception
*/
public static boolean verify(byte[] msg, byte[] pubkey, byte[] sig) throws Exception {

if (msg.length != 32) {
throw new Exception("The message must be a 32-byte array.");
}

if (pubkey.length != 32) {
throw new Exception("The public key must be a 32-byte array.");
}
Expand Down
34 changes: 31 additions & 3 deletions nostr-java-test/src/test/java/nostr/test/crypto/CryptoTest.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package nostr.test.crypto;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import nostr.crypto.bech32.Bech32;
import nostr.crypto.bech32.Bech32Prefix;
import nostr.crypto.schnorr.Schnorr;
import nostr.event.impl.GenericEvent;
import nostr.id.Identity;
import nostr.util.NostrException;
import nostr.util.NostrUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import static nostr.test.EntityFactory.Events.createTextNoteEvent;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
*
Expand All @@ -27,4 +34,25 @@ public void testBech32() {
Assertions.fail(ex);
}
}

@Test
public void testVerifySignature() throws Exception {
System.out.println("testVerifySignature");

Identity identity = Identity.generateRandomIdentity();
GenericEvent event = createTextNoteEvent(identity.getPublicKey(), "Hello World");
event.update();
var message = NostrUtil.sha256(event.get_serializedEvent());
var signature = identity.sign(event);
var verification = Schnorr.verify(message, identity.getPublicKey().getRawData(), signature.getRawData());
assertTrue(verification);

event = createTextNoteEvent(identity.getPublicKey(), "Guten Tag");
event.update();
message = NostrUtil.sha256(event.get_serializedEvent());
verification = Schnorr.verify(message, identity.getPublicKey().getRawData(), signature.getRawData());

assertFalse(verification);
}

}