mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-11 00:37:41 +00:00
Spotless fixes.
This commit is contained in:
@@ -1,3 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
@@ -9,12 +29,12 @@ import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ChatroomKeyTest {
|
||||
@Test
|
||||
fun testEquals() {
|
||||
val k1 = ChatroomKey(persistentSetOf("Key1", "Key2"))
|
||||
val k2 = ChatroomKey(persistentSetOf("Key1", "Key2"))
|
||||
@Test
|
||||
fun testEquals() {
|
||||
val k1 = ChatroomKey(persistentSetOf("Key1", "Key2"))
|
||||
val k2 = ChatroomKey(persistentSetOf("Key1", "Key2"))
|
||||
|
||||
assertEquals(k1, k2)
|
||||
assertEquals(k1.hashCode(), k2.hashCode())
|
||||
}
|
||||
assertEquals(k1, k2)
|
||||
assertEquals(k1.hashCode(), k2.hashCode())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
@@ -9,7 +29,8 @@ import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class CitationTests {
|
||||
val json = """
|
||||
val json =
|
||||
"""
|
||||
{
|
||||
"content": "Astral:\n\nhttps://void.cat/d/A5Fba5B1bcxwEmeyoD9nBs.webp\n\nIris:\n\nhttps://void.cat/d/44hTcVvhRps6xYYs99QsqA.webp\n\nSnort:\n\nhttps://void.cat/d/4nJD5TRePuQChM5tzteYbU.webp\n\nAmethyst agrees with Astral which I suspect are both wrong. nostr:npub13sx6fp3pxq5rl70x0kyfmunyzaa9pzt5utltjm0p8xqyafndv95q3saapa nostr:npub1v0lxxxxutpvrelsksy8cdhgfux9l6a42hsj2qzquu2zk7vc9qnkszrqj49 nostr:npub1g53mukxnjkcmr94fhryzkqutdz2ukq4ks0gvy5af25rgmwsl4ngq43drvk nostr:npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z ",
|
||||
"created_at": 1683596206,
|
||||
@@ -73,17 +94,18 @@ class CitationTests {
|
||||
}
|
||||
"""
|
||||
|
||||
@Test
|
||||
fun parseEvent() {
|
||||
val event = Event.fromJson(json) as TextNoteEvent
|
||||
@Test
|
||||
fun parseEvent() {
|
||||
val event = Event.fromJson(json) as TextNoteEvent
|
||||
|
||||
val expectedCitations = setOf(
|
||||
"8c0da4862130283ff9e67d889df264177a508974e2feb96de139804ea66d6168",
|
||||
"63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed",
|
||||
"4523be58d395b1b196a9b8c82b038b6895cb02b683d0c253a955068dba1facd0",
|
||||
"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c"
|
||||
)
|
||||
val expectedCitations =
|
||||
setOf(
|
||||
"8c0da4862130283ff9e67d889df264177a508974e2feb96de139804ea66d6168",
|
||||
"63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed",
|
||||
"4523be58d395b1b196a9b8c82b038b6895cb02b683d0c253a955068dba1facd0",
|
||||
"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c",
|
||||
)
|
||||
|
||||
assertEquals(expectedCitations, event.citedUsers())
|
||||
}
|
||||
assertEquals(expectedCitations, event.citedUsers())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,104 +1,125 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.vitorpamplona.quartz.encoders.hexToByteArray
|
||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||
import com.vitorpamplona.quartz.crypto.CryptoUtils
|
||||
import com.vitorpamplona.quartz.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.encoders.Hex
|
||||
import com.vitorpamplona.quartz.encoders.decodePublicKey
|
||||
import com.vitorpamplona.quartz.encoders.hexToByteArray
|
||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class CryptoUtilsTest {
|
||||
@Test
|
||||
fun testGetPublicFromPrivateKey() {
|
||||
val privateKey =
|
||||
"f410f88bcec6cbfda04d6a273c7b1dd8bba144cd45b71e87109cfa11dd7ed561".hexToByteArray()
|
||||
val publicKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey()
|
||||
assertEquals("7d4b8806f1fd713c287235411bf95aa81b7242ead892733ec84b3f2719845be6", publicKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetPublicFromPrivateKey() {
|
||||
val privateKey = "f410f88bcec6cbfda04d6a273c7b1dd8bba144cd45b71e87109cfa11dd7ed561".hexToByteArray()
|
||||
val publicKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey()
|
||||
assertEquals("7d4b8806f1fd713c287235411bf95aa81b7242ead892733ec84b3f2719845be6", publicKey)
|
||||
}
|
||||
@Test
|
||||
fun testSharedSecretCompatibilityWithCoracle() {
|
||||
val privateKey = "f410f88bcec6cbfda04d6a273c7b1dd8bba144cd45b71e87109cfa11dd7ed561"
|
||||
val publicKey = "765cd7cf91d3ad07423d114d5a39c61d52b2cdbc18ba055ddbbeec71fbe2aa2f"
|
||||
|
||||
@Test
|
||||
fun testSharedSecretCompatibilityWithCoracle() {
|
||||
val privateKey = "f410f88bcec6cbfda04d6a273c7b1dd8bba144cd45b71e87109cfa11dd7ed561"
|
||||
val publicKey = "765cd7cf91d3ad07423d114d5a39c61d52b2cdbc18ba055ddbbeec71fbe2aa2f"
|
||||
val key =
|
||||
CryptoUtils.getSharedSecretNIP44v1(
|
||||
privateKey = privateKey.hexToByteArray(),
|
||||
pubKey = publicKey.hexToByteArray(),
|
||||
)
|
||||
|
||||
val key = CryptoUtils.getSharedSecretNIP44v1(privateKey = privateKey.hexToByteArray(), pubKey = publicKey.hexToByteArray())
|
||||
assertEquals("577c966f499dddd8e8dcc34e8f352e283cc177e53ae372794947e0b8ede7cfd8", key.toHexKey())
|
||||
}
|
||||
|
||||
assertEquals("577c966f499dddd8e8dcc34e8f352e283cc177e53ae372794947e0b8ede7cfd8", key.toHexKey())
|
||||
}
|
||||
@Test
|
||||
fun testSharedSecret() {
|
||||
val sender = KeyPair()
|
||||
val receiver = KeyPair()
|
||||
|
||||
@Test
|
||||
fun testSharedSecret() {
|
||||
val sender = KeyPair()
|
||||
val receiver = KeyPair()
|
||||
val sharedSecret1 = CryptoUtils.getSharedSecretNIP44v1(sender.privKey!!, receiver.pubKey)
|
||||
val sharedSecret2 = CryptoUtils.getSharedSecretNIP44v1(receiver.privKey!!, sender.pubKey)
|
||||
|
||||
val sharedSecret1 = CryptoUtils.getSharedSecretNIP44v1(sender.privKey!!, receiver.pubKey)
|
||||
val sharedSecret2 = CryptoUtils.getSharedSecretNIP44v1(receiver.privKey!!, sender.pubKey)
|
||||
assertEquals(sharedSecret1.toHexKey(), sharedSecret2.toHexKey())
|
||||
|
||||
assertEquals(sharedSecret1.toHexKey(), sharedSecret2.toHexKey())
|
||||
val secretKey1 = KeyPair(privKey = sharedSecret1)
|
||||
val secretKey2 = KeyPair(privKey = sharedSecret2)
|
||||
|
||||
val secretKey1 = KeyPair(privKey = sharedSecret1)
|
||||
val secretKey2 = KeyPair(privKey = sharedSecret2)
|
||||
assertEquals(secretKey1.pubKey.toHexKey(), secretKey2.pubKey.toHexKey())
|
||||
assertEquals(secretKey1.privKey?.toHexKey(), secretKey2.privKey?.toHexKey())
|
||||
}
|
||||
|
||||
assertEquals(secretKey1.pubKey.toHexKey(), secretKey2.pubKey.toHexKey())
|
||||
assertEquals(secretKey1.privKey?.toHexKey(), secretKey2.privKey?.toHexKey())
|
||||
}
|
||||
@Test
|
||||
fun encryptDecryptNIP4Test() {
|
||||
val msg = "Hi"
|
||||
|
||||
@Test
|
||||
fun encryptDecryptNIP4Test() {
|
||||
val msg = "Hi"
|
||||
val privateKey = CryptoUtils.privkeyCreate()
|
||||
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
|
||||
|
||||
val privateKey = CryptoUtils.privkeyCreate()
|
||||
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
|
||||
val encrypted = CryptoUtils.encryptNIP04(msg, privateKey, publicKey)
|
||||
val decrypted = CryptoUtils.decryptNIP04(encrypted, privateKey, publicKey)
|
||||
|
||||
val encrypted = CryptoUtils.encryptNIP04(msg, privateKey, publicKey)
|
||||
val decrypted = CryptoUtils.decryptNIP04(encrypted, privateKey, publicKey)
|
||||
assertEquals(msg, decrypted)
|
||||
}
|
||||
|
||||
assertEquals(msg, decrypted)
|
||||
}
|
||||
@Test
|
||||
fun encryptDecryptNIP44v1Test() {
|
||||
val msg = "Hi"
|
||||
|
||||
val privateKey = CryptoUtils.privkeyCreate()
|
||||
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
|
||||
|
||||
@Test
|
||||
fun encryptDecryptNIP44v1Test() {
|
||||
val msg = "Hi"
|
||||
val encrypted = CryptoUtils.encryptNIP44v1(msg, privateKey, publicKey)
|
||||
val decrypted = CryptoUtils.decryptNIP44v1(encrypted, privateKey, publicKey)
|
||||
|
||||
val privateKey = CryptoUtils.privkeyCreate()
|
||||
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
|
||||
assertEquals(msg, decrypted)
|
||||
}
|
||||
|
||||
val encrypted = CryptoUtils.encryptNIP44v1(msg, privateKey, publicKey)
|
||||
val decrypted = CryptoUtils.decryptNIP44v1(encrypted, privateKey, publicKey)
|
||||
@Test
|
||||
fun encryptSharedSecretDecryptNIP4Test() {
|
||||
val msg = "Hi"
|
||||
|
||||
assertEquals(msg, decrypted)
|
||||
}
|
||||
val privateKey = CryptoUtils.privkeyCreate()
|
||||
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
|
||||
|
||||
@Test
|
||||
fun encryptSharedSecretDecryptNIP4Test() {
|
||||
val msg = "Hi"
|
||||
val encrypted = CryptoUtils.encryptNIP04(msg, privateKey, publicKey)
|
||||
val decrypted = CryptoUtils.decryptNIP04(encrypted, privateKey, publicKey)
|
||||
|
||||
val privateKey = CryptoUtils.privkeyCreate()
|
||||
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
|
||||
assertEquals(msg, decrypted)
|
||||
}
|
||||
|
||||
val encrypted = CryptoUtils.encryptNIP04(msg, privateKey, publicKey)
|
||||
val decrypted = CryptoUtils.decryptNIP04(encrypted, privateKey, publicKey)
|
||||
@Test
|
||||
fun encryptSharedSecretDecryptNIP44v1Test() {
|
||||
val msg = "Hi"
|
||||
|
||||
assertEquals(msg, decrypted)
|
||||
}
|
||||
val privateKey = CryptoUtils.privkeyCreate()
|
||||
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
|
||||
val sharedSecret = CryptoUtils.getSharedSecretNIP44v1(privateKey, publicKey)
|
||||
|
||||
@Test
|
||||
fun encryptSharedSecretDecryptNIP44v1Test() {
|
||||
val msg = "Hi"
|
||||
val encrypted = CryptoUtils.encryptNIP44v1(msg, sharedSecret)
|
||||
val decrypted = CryptoUtils.decryptNIP44v1(encrypted, sharedSecret)
|
||||
|
||||
val privateKey = CryptoUtils.privkeyCreate()
|
||||
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
|
||||
val sharedSecret = CryptoUtils.getSharedSecretNIP44v1(privateKey, publicKey)
|
||||
|
||||
val encrypted = CryptoUtils.encryptNIP44v1(msg, sharedSecret)
|
||||
val decrypted = CryptoUtils.decryptNIP44v1(encrypted, sharedSecret)
|
||||
|
||||
assertEquals(msg, decrypted)
|
||||
}
|
||||
assertEquals(msg, decrypted)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
@@ -7,16 +27,15 @@ import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class EventSigCheck {
|
||||
val payload1 =
|
||||
"[\"EVENT\",\"40b9\",{\"id\":\"48a72b485d38338627ec9d427583551f9af4f016c739b8ec0d6313540a8b12cf\",\"kind\":1,\"pubkey\":\"3d842afecd5e293f28b6627933704a3fb8ce153aa91d790ab11f6a752d44a42d\",\"created_at\":1677940007,\"content\":\"I got asked about follower count again today. Why does my follower count go down when I delete public relays (in our list) and replace them with filter.nostr.wine? \\n\\nI’ll give you one final explanation to rule them all. First, let’s go over how clients calculate your follower count.\\n\\n1. Your client sends a request to all your connected relays asking for accounts who follow you\\n2. Relays answer back with the events requested\\n3. The client aggregates the event total and displays it\\n\\nEach relay has a set limit on how many stored events it will return per request. For some relays it’s 500, others 1000, some as high as 5000. Let’s say for simplicity that all your public relays use 500 as their limit. If you ask 10 relays for your followers the max possible answer you can get is 5000. That won’t change if you have 20,000 followers or 100,000. You may get back a “different” 5000 each time, but you’ll still cap out at 5000 because that is the most events your client will receive.\u2028\u2028Our limit on filter.nostr.wine is 2000 events. If you replace 10 public relays with only filter.nostr.wine, the MOST followers you will ever get back from our filter relay is 2000. That doesn’t mean you only have 2000 followers or that your reach is reduced in any way.\\n\\nAs long as you are writing to and reading from the same public relays, neither your reach nor any content was lost. That concludes my TED talk. I hope you all have a fantastic day and weekend.\",\"tags\":[],\"sig\":\"dcaf8ab98bb9179017b35bd814092850d1062b26c263dff89fb1ae8c019a324139d1729012d9d05ff0a517f76b1117d869b2cc7d36bea8aa5f4b94c5e2548aa8\"}]"
|
||||
|
||||
val payload1 = "[\"EVENT\",\"40b9\",{\"id\":\"48a72b485d38338627ec9d427583551f9af4f016c739b8ec0d6313540a8b12cf\",\"kind\":1,\"pubkey\":\"3d842afecd5e293f28b6627933704a3fb8ce153aa91d790ab11f6a752d44a42d\",\"created_at\":1677940007,\"content\":\"I got asked about follower count again today. Why does my follower count go down when I delete public relays (in our list) and replace them with filter.nostr.wine? \\n\\nI’ll give you one final explanation to rule them all. First, let’s go over how clients calculate your follower count.\\n\\n1. Your client sends a request to all your connected relays asking for accounts who follow you\\n2. Relays answer back with the events requested\\n3. The client aggregates the event total and displays it\\n\\nEach relay has a set limit on how many stored events it will return per request. For some relays it’s 500, others 1000, some as high as 5000. Let’s say for simplicity that all your public relays use 500 as their limit. If you ask 10 relays for your followers the max possible answer you can get is 5000. That won’t change if you have 20,000 followers or 100,000. You may get back a “different” 5000 each time, but you’ll still cap out at 5000 because that is the most events your client will receive.\u2028\u2028Our limit on filter.nostr.wine is 2000 events. If you replace 10 public relays with only filter.nostr.wine, the MOST followers you will ever get back from our filter relay is 2000. That doesn’t mean you only have 2000 followers or that your reach is reduced in any way.\\n\\nAs long as you are writing to and reading from the same public relays, neither your reach nor any content was lost. That concludes my TED talk. I hope you all have a fantastic day and weekend.\",\"tags\":[],\"sig\":\"dcaf8ab98bb9179017b35bd814092850d1062b26c263dff89fb1ae8c019a324139d1729012d9d05ff0a517f76b1117d869b2cc7d36bea8aa5f4b94c5e2548aa8\"}]"
|
||||
|
||||
@Test
|
||||
fun testUnicode2028and2029ShouldNotBeEscaped() {
|
||||
val msg = Event.mapper.readTree(payload1)
|
||||
val event = Event.fromJson(msg[2])
|
||||
|
||||
// Should pass
|
||||
event.checkSignature()
|
||||
}
|
||||
@Test
|
||||
fun testUnicode2028and2029ShouldNotBeEscaped() {
|
||||
val msg = Event.mapper.readTree(payload1)
|
||||
val event = Event.fromJson(msg[2])
|
||||
|
||||
// Should pass
|
||||
event.checkSignature()
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz
|
||||
|
||||
import com.vitorpamplona.quartz.crypto.CryptoUtils
|
||||
@@ -5,43 +25,41 @@ import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class HexEncodingTest {
|
||||
val testHex = "48a72b485d38338627ec9d427583551f9af4f016c739b8ec0d6313540a8b12cf"
|
||||
|
||||
val TestHex = "48a72b485d38338627ec9d427583551f9af4f016c739b8ec0d6313540a8b12cf"
|
||||
@Test
|
||||
fun testHexEncodeDecodeOurs() {
|
||||
assertEquals(
|
||||
testHex,
|
||||
com.vitorpamplona.quartz.encoders.Hex.encode(
|
||||
com.vitorpamplona.quartz.encoders.Hex.decode(testHex),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHexEncodeDecodeOurs() {
|
||||
assertEquals(
|
||||
TestHex,
|
||||
com.vitorpamplona.quartz.encoders.Hex.encode(
|
||||
com.vitorpamplona.quartz.encoders.Hex.decode(TestHex)
|
||||
)
|
||||
)
|
||||
@Test
|
||||
fun testHexEncodeDecodeSecp256k1() {
|
||||
assertEquals(
|
||||
testHex,
|
||||
fr.acinq.secp256k1.Hex.encode(
|
||||
fr.acinq.secp256k1.Hex.decode(testHex),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRandoms() {
|
||||
for (i in 0..1000) {
|
||||
val bytes = CryptoUtils.privkeyCreate()
|
||||
val hex = fr.acinq.secp256k1.Hex.encode(bytes)
|
||||
assertEquals(
|
||||
fr.acinq.secp256k1.Hex.encode(bytes),
|
||||
com.vitorpamplona.quartz.encoders.Hex.encode(bytes),
|
||||
)
|
||||
assertEquals(
|
||||
bytes.toList(),
|
||||
com.vitorpamplona.quartz.encoders.Hex.decode(hex).toList(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHexEncodeDecodeSecp256k1() {
|
||||
assertEquals(
|
||||
TestHex,
|
||||
fr.acinq.secp256k1.Hex.encode(
|
||||
fr.acinq.secp256k1.Hex.decode(TestHex)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRandoms() {
|
||||
for (i in 0..1000) {
|
||||
val bytes = CryptoUtils.privkeyCreate()
|
||||
val hex = fr.acinq.secp256k1.Hex.encode(bytes)
|
||||
assertEquals(
|
||||
fr.acinq.secp256k1.Hex.encode(bytes),
|
||||
com.vitorpamplona.quartz.encoders.Hex.encode(bytes)
|
||||
)
|
||||
assertEquals(
|
||||
bytes.toList(),
|
||||
com.vitorpamplona.quartz.encoders.Hex.decode(hex).toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import java.io.InputStreamReader
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertTrue
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.io.InputStreamReader
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class LargeDBSignatureCheck {
|
||||
@Test
|
||||
fun insertDatabaseSample() = runBlocking {
|
||||
val fullDBInputStream = getInstrumentation().context.assets.open("nostr_vitor_short.json")
|
||||
|
||||
@Test
|
||||
fun insertDatabaseSample() = runBlocking {
|
||||
val fullDBInputStream = getInstrumentation().context.assets.open("nostr_vitor_short.json")
|
||||
val eventArray =
|
||||
Event.mapper.readValue<ArrayList<Event>>(
|
||||
InputStreamReader(fullDBInputStream),
|
||||
) as List<Event>
|
||||
|
||||
val eventArray = Event.mapper.readValue<ArrayList<Event>>(
|
||||
InputStreamReader(fullDBInputStream)
|
||||
) as List<Event>
|
||||
|
||||
var counter = 0
|
||||
eventArray.forEach {
|
||||
assertTrue(it.hasValidSignature())
|
||||
counter ++
|
||||
}
|
||||
|
||||
assertEquals(eventArray.size, counter)
|
||||
var counter = 0
|
||||
eventArray.forEach {
|
||||
assertTrue(it.hasValidSignature())
|
||||
counter++
|
||||
}
|
||||
|
||||
}
|
||||
assertEquals(eventArray.size, counter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
@@ -8,17 +28,19 @@ import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class LnInvoiceUtilTest {
|
||||
@Test
|
||||
fun test100KAmountCalculation() {
|
||||
val bolt11 = "lnbc1m1pjt9u0qsp553q90pj5mafzv20w45eqavned9tgwhl4q99n9s5ppcw24nzw3zeqpp5002kd3ktym67du86kj665fgaev7ka8ys7j5yz5fg686lr5e2gfkshp5dkk27nnuax05az3pk2r6ytxtvwn5j4xzsq9ajprhc7crjkmgvr3qxqyjw5qcqpjrzjqtzxvfsuxe4l92pf97tt4rcgpy2xalkmlwexh899wqxf83l8nwv4xzh0gvqq89qqqqqqqqlgqqqqq0gqvs9qxpqysgqx5mz04wd7kqu5zhhel9enr036hjrp4gga0nz084p2asjl36a0zmrk6mhqa249zsgqref2rlvhffm73u7rxgr47gden6rugup4ksvpzsqvds4pz"
|
||||
// Context of the app under test.
|
||||
Assert.assertEquals(100000, LnInvoiceUtil.getAmountInSats(bolt11).toLong())
|
||||
}
|
||||
@Test
|
||||
fun test100KAmountCalculation() {
|
||||
val bolt11 =
|
||||
"lnbc1m1pjt9u0qsp553q90pj5mafzv20w45eqavned9tgwhl4q99n9s5ppcw24nzw3zeqpp5002kd3ktym67du86kj665fgaev7ka8ys7j5yz5fg686lr5e2gfkshp5dkk27nnuax05az3pk2r6ytxtvwn5j4xzsq9ajprhc7crjkmgvr3qxqyjw5qcqpjrzjqtzxvfsuxe4l92pf97tt4rcgpy2xalkmlwexh899wqxf83l8nwv4xzh0gvqq89qqqqqqqqlgqqqqq0gqvs9qxpqysgqx5mz04wd7kqu5zhhel9enr036hjrp4gga0nz084p2asjl36a0zmrk6mhqa249zsgqref2rlvhffm73u7rxgr47gden6rugup4ksvpzsqvds4pz"
|
||||
// Context of the app under test.
|
||||
Assert.assertEquals(100000, LnInvoiceUtil.getAmountInSats(bolt11).toLong())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test100GAmountCalculation() {
|
||||
val bolt11 = "lnbc1000000000000000p1pjtxqf0pp5myqxhcufqy56elfsg9dd4dthnqptusnnpwnul7u86l95xzjgqd8shp5gueg34sgm3u3nxqjqyunvvqdu0pr6jz6mwh4ew4886f2lpf4cmrqxqztgsp5w0cdfd45dfnqwex5gn85x7fru3jcrxhlcx3enx835477m3gdfcuq9qyyssqelrcmm7p9qazgjuxtdg7sd8nq5cscl2tratjlclt5rk5mc7uq2lphq3r2a43j5ua4leakc4emq8yp2yxdnzvzszpw6u2afac0kgl7hspfj67ta"
|
||||
// Context of the app under test.
|
||||
Assert.assertEquals(100000000000, LnInvoiceUtil.getAmountInSats(bolt11).toLong())
|
||||
}
|
||||
@Test
|
||||
fun test100GAmountCalculation() {
|
||||
val bolt11 =
|
||||
"lnbc1000000000000000p1pjtxqf0pp5myqxhcufqy56elfsg9dd4dthnqptusnnpwnul7u86l95xzjgqd8shp5gueg34sgm3u3nxqjqyunvvqdu0pr6jz6mwh4ew4886f2lpf4cmrqxqztgsp5w0cdfd45dfnqwex5gn85x7fru3jcrxhlcx3enx835477m3gdfcuq9qyyssqelrcmm7p9qazgjuxtdg7sd8nq5cscl2tratjlclt5rk5mc7uq2lphq3r2a43j5ua4leakc4emq8yp2yxdnzvzszpw6u2afac0kgl7hspfj67ta"
|
||||
// Context of the app under test.
|
||||
Assert.assertEquals(100000000000, LnInvoiceUtil.getAmountInSats(bolt11).toLong())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,24 @@
|
||||
package com.vitorpamplona.quartz;
|
||||
/**
|
||||
* Copyright (c) 2023 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
||||
@@ -8,195 +28,205 @@ import com.vitorpamplona.quartz.crypto.Nip44v2
|
||||
import com.vitorpamplona.quartz.encoders.hexToByteArray
|
||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||
import fr.acinq.secp256k1.Secp256k1
|
||||
import java.security.MessageDigest
|
||||
import java.security.SecureRandom
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertNotNull
|
||||
import junit.framework.TestCase.assertNull
|
||||
import junit.framework.TestCase.fail
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.security.MessageDigest
|
||||
import java.security.SecureRandom
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
public class NIP44v2Test {
|
||||
val vectors: VectorFile = jacksonObjectMapper().readValue(
|
||||
val vectors: VectorFile =
|
||||
jacksonObjectMapper()
|
||||
.readValue(
|
||||
getInstrumentation().context.assets.open("nip44.vectors.json"),
|
||||
VectorFile::class.java
|
||||
)
|
||||
VectorFile::class.java,
|
||||
)
|
||||
|
||||
val random = SecureRandom()
|
||||
val nip44v2 = Nip44v2(Secp256k1.get(), random)
|
||||
val random = SecureRandom()
|
||||
val nip44v2 = Nip44v2(Secp256k1.get(), random)
|
||||
|
||||
@Test
|
||||
fun conversationKeyTest() {
|
||||
for (v in vectors.v2?.valid?.getConversationKey!!) {
|
||||
val conversationKey = nip44v2.getConversationKey(v.sec1!!.hexToByteArray(), v.pub2!!.hexToByteArray())
|
||||
@Test
|
||||
fun conversationKeyTest() {
|
||||
for (v in vectors.v2?.valid?.getConversationKey!!) {
|
||||
val conversationKey =
|
||||
nip44v2.getConversationKey(v.sec1!!.hexToByteArray(), v.pub2!!.hexToByteArray())
|
||||
|
||||
assertEquals(v.conversationKey, conversationKey.toHexKey())
|
||||
}
|
||||
assertEquals(v.conversationKey, conversationKey.toHexKey())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddingTest() {
|
||||
for (v in vectors.v2?.valid?.calcPaddedLen!!) {
|
||||
val actual = nip44v2.calcPaddedLen(v[0])
|
||||
assertEquals(v[1], actual)
|
||||
}
|
||||
@Test
|
||||
fun paddingTest() {
|
||||
for (v in vectors.v2?.valid?.calcPaddedLen!!) {
|
||||
val actual = nip44v2.calcPaddedLen(v[0])
|
||||
assertEquals(v[1], actual)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun encryptDecryptTest() {
|
||||
for (v in vectors.v2?.valid?.encryptDecrypt!!) {
|
||||
val pub2 = com.vitorpamplona.quartz.crypto.KeyPair(v.sec2!!.hexToByteArray())
|
||||
val conversationKey = nip44v2.getConversationKey(v.sec1!!.hexToByteArray(), pub2.pubKey)
|
||||
assertEquals(v.conversationKey, conversationKey.toHexKey())
|
||||
@Test
|
||||
fun encryptDecryptTest() {
|
||||
for (v in vectors.v2?.valid?.encryptDecrypt!!) {
|
||||
val pub2 = com.vitorpamplona.quartz.crypto.KeyPair(v.sec2!!.hexToByteArray())
|
||||
val conversationKey = nip44v2.getConversationKey(v.sec1!!.hexToByteArray(), pub2.pubKey)
|
||||
assertEquals(v.conversationKey, conversationKey.toHexKey())
|
||||
|
||||
val ciphertext = nip44v2.encryptWithNonce(
|
||||
v.plaintext!!,
|
||||
conversationKey,
|
||||
v.nonce!!.hexToByteArray()
|
||||
).encodePayload()
|
||||
val ciphertext =
|
||||
nip44v2
|
||||
.encryptWithNonce(
|
||||
v.plaintext!!,
|
||||
conversationKey,
|
||||
v.nonce!!.hexToByteArray(),
|
||||
)
|
||||
.encodePayload()
|
||||
|
||||
assertEquals(v.payload, ciphertext)
|
||||
assertEquals(v.payload, ciphertext)
|
||||
|
||||
val decrypted = nip44v2.decrypt(v.payload!!, conversationKey)
|
||||
assertEquals(v.plaintext, decrypted)
|
||||
}
|
||||
val decrypted = nip44v2.decrypt(v.payload!!, conversationKey)
|
||||
assertEquals(v.plaintext, decrypted)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun encryptDecryptLongTest() {
|
||||
for (v in vectors.v2?.valid?.encryptDecryptLongMsg!!) {
|
||||
val conversationKey = v.conversationKey!!.hexToByteArray()
|
||||
val plaintext = v.pattern!!.repeat(v.repeat!!)
|
||||
@Test
|
||||
fun encryptDecryptLongTest() {
|
||||
for (v in vectors.v2?.valid?.encryptDecryptLongMsg!!) {
|
||||
val conversationKey = v.conversationKey!!.hexToByteArray()
|
||||
val plaintext = v.pattern!!.repeat(v.repeat!!)
|
||||
|
||||
assertEquals(v.plaintextSha256, sha256Hex(plaintext.toByteArray(Charsets.UTF_8)))
|
||||
assertEquals(v.plaintextSha256, sha256Hex(plaintext.toByteArray(Charsets.UTF_8)))
|
||||
|
||||
val ciphertext = nip44v2.encryptWithNonce(
|
||||
plaintext,
|
||||
conversationKey,
|
||||
v.nonce!!.hexToByteArray()
|
||||
).encodePayload()
|
||||
val ciphertext =
|
||||
nip44v2
|
||||
.encryptWithNonce(
|
||||
plaintext,
|
||||
conversationKey,
|
||||
v.nonce!!.hexToByteArray(),
|
||||
)
|
||||
.encodePayload()
|
||||
|
||||
assertEquals(v.payloadSha256, sha256Hex(ciphertext.toByteArray(Charsets.UTF_8)))
|
||||
assertEquals(v.payloadSha256, sha256Hex(ciphertext.toByteArray(Charsets.UTF_8)))
|
||||
|
||||
val decrypted = nip44v2.decrypt(ciphertext, conversationKey)
|
||||
val decrypted = nip44v2.decrypt(ciphertext, conversationKey)
|
||||
|
||||
assertEquals(plaintext, decrypted)
|
||||
}
|
||||
assertEquals(plaintext, decrypted)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun invalidMessageLenghts() {
|
||||
for (v in vectors.v2?.invalid?.encryptMsgLengths!!) {
|
||||
val key = ByteArray(32)
|
||||
random.nextBytes(key)
|
||||
try {
|
||||
nip44v2.encrypt("a".repeat(v), key)
|
||||
fail("Should Throw for ${v}")
|
||||
} catch (e: Exception) {
|
||||
assertNotNull(e)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun invalidMessageLenghts() {
|
||||
for (v in vectors.v2?.invalid?.encryptMsgLengths!!) {
|
||||
val key = ByteArray(32)
|
||||
random.nextBytes(key)
|
||||
try {
|
||||
nip44v2.encrypt("a".repeat(v), key)
|
||||
fail("Should Throw for $v")
|
||||
} catch (e: Exception) {
|
||||
assertNotNull(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun invalidDecrypt() {
|
||||
for (v in vectors.v2?.invalid?.decrypt!!) {
|
||||
try {
|
||||
val result = nip44v2.decrypt(v.payload!!, v.conversationKey!!.hexToByteArray())
|
||||
assertNull(result)
|
||||
//fail("Should Throw for ${v.note}")
|
||||
} catch (e: Exception) {
|
||||
assertNotNull(e)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun invalidDecrypt() {
|
||||
for (v in vectors.v2?.invalid?.decrypt!!) {
|
||||
try {
|
||||
val result = nip44v2.decrypt(v.payload!!, v.conversationKey!!.hexToByteArray())
|
||||
assertNull(result)
|
||||
// fail("Should Throw for ${v.note}")
|
||||
} catch (e: Exception) {
|
||||
assertNotNull(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun invalidConversationKey() {
|
||||
for (v in vectors.v2?.invalid?.getConversationKey!!) {
|
||||
try {
|
||||
nip44v2.getConversationKey(v.sec1!!.hexToByteArray(), v.pub2!!.hexToByteArray())
|
||||
fail("Should Throw for ${v.note}")
|
||||
} catch (e: Exception) {
|
||||
assertNotNull(e)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun invalidConversationKey() {
|
||||
for (v in vectors.v2?.invalid?.getConversationKey!!) {
|
||||
try {
|
||||
nip44v2.getConversationKey(v.sec1!!.hexToByteArray(), v.pub2!!.hexToByteArray())
|
||||
fail("Should Throw for ${v.note}")
|
||||
} catch (e: Exception) {
|
||||
assertNotNull(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun sha256Hex(data: ByteArray): String {
|
||||
// Creates a new buffer every time
|
||||
return MessageDigest.getInstance("SHA-256").digest(data).toHexKey()
|
||||
}
|
||||
fun sha256Hex(data: ByteArray): String {
|
||||
// Creates a new buffer every time
|
||||
return MessageDigest.getInstance("SHA-256").digest(data).toHexKey()
|
||||
}
|
||||
}
|
||||
|
||||
data class VectorFile (
|
||||
val v2 : V2? = V2()
|
||||
data class VectorFile(
|
||||
val v2: V2? = V2(),
|
||||
)
|
||||
|
||||
data class V2 (
|
||||
val valid : Valid? = Valid(),
|
||||
val invalid : Invalid? = Invalid()
|
||||
data class V2(
|
||||
val valid: Valid? = Valid(),
|
||||
val invalid: Invalid? = Invalid(),
|
||||
)
|
||||
|
||||
data class Valid (
|
||||
@JsonProperty("get_conversation_key" ) val getConversationKey : ArrayList<GetConversationKey> = arrayListOf(),
|
||||
@JsonProperty("get_message_keys" ) val getMessageKeys : GetMessageKeys? = GetMessageKeys(),
|
||||
@JsonProperty("calc_padded_len" ) val calcPaddedLen : ArrayList<ArrayList<Int>> = arrayListOf(),
|
||||
@JsonProperty("encrypt_decrypt" ) val encryptDecrypt : ArrayList<EncryptDecrypt> = arrayListOf(),
|
||||
@JsonProperty("encrypt_decrypt_long_msg" ) val encryptDecryptLongMsg : ArrayList<EncryptDecryptLongMsg> = arrayListOf()
|
||||
data class Valid(
|
||||
@JsonProperty("get_conversation_key")
|
||||
val getConversationKey: ArrayList<GetConversationKey> = arrayListOf(),
|
||||
@JsonProperty("get_message_keys") val getMessageKeys: GetMessageKeys? = GetMessageKeys(),
|
||||
@JsonProperty("calc_padded_len") val calcPaddedLen: ArrayList<ArrayList<Int>> = arrayListOf(),
|
||||
@JsonProperty("encrypt_decrypt") val encryptDecrypt: ArrayList<EncryptDecrypt> = arrayListOf(),
|
||||
@JsonProperty("encrypt_decrypt_long_msg")
|
||||
val encryptDecryptLongMsg: ArrayList<EncryptDecryptLongMsg> = arrayListOf(),
|
||||
)
|
||||
|
||||
data class Invalid (
|
||||
@JsonProperty("encrypt_msg_lengths" ) val encryptMsgLengths : ArrayList<Int> = arrayListOf(),
|
||||
@JsonProperty("get_conversation_key" ) val getConversationKey : ArrayList<GetConversationKey> = arrayListOf(),
|
||||
@JsonProperty("decrypt" ) val decrypt : ArrayList<Decrypt> = arrayListOf()
|
||||
data class Invalid(
|
||||
@JsonProperty("encrypt_msg_lengths") val encryptMsgLengths: ArrayList<Int> = arrayListOf(),
|
||||
@JsonProperty("get_conversation_key")
|
||||
val getConversationKey: ArrayList<GetConversationKey> = arrayListOf(),
|
||||
@JsonProperty("decrypt") val decrypt: ArrayList<Decrypt> = arrayListOf(),
|
||||
)
|
||||
|
||||
data class GetConversationKey (
|
||||
val sec1 : String? = null,
|
||||
val pub2 : String? = null,
|
||||
val note : String? = null,
|
||||
@JsonProperty("conversation_key" ) val conversationKey : String? = null
|
||||
data class GetConversationKey(
|
||||
val sec1: String? = null,
|
||||
val pub2: String? = null,
|
||||
val note: String? = null,
|
||||
@JsonProperty("conversation_key") val conversationKey: String? = null,
|
||||
)
|
||||
|
||||
data class GetMessageKeys (
|
||||
@JsonProperty("conversation_key" ) val conversationKey : String? = null,
|
||||
val keys : ArrayList<Keys> = arrayListOf()
|
||||
data class GetMessageKeys(
|
||||
@JsonProperty("conversation_key") val conversationKey: String? = null,
|
||||
val keys: ArrayList<Keys> = arrayListOf(),
|
||||
)
|
||||
|
||||
data class Keys (
|
||||
@JsonProperty("nonce" ) val nonce : String? = null,
|
||||
@JsonProperty("chacha_key" ) val chachaKey : String? = null,
|
||||
@JsonProperty("chacha_nonce" ) val chachaNonce : String? = null,
|
||||
@JsonProperty("hmac_key" ) val hmacKey : String? = null
|
||||
data class Keys(
|
||||
@JsonProperty("nonce") val nonce: String? = null,
|
||||
@JsonProperty("chacha_key") val chachaKey: String? = null,
|
||||
@JsonProperty("chacha_nonce") val chachaNonce: String? = null,
|
||||
@JsonProperty("hmac_key") val hmacKey: String? = null,
|
||||
)
|
||||
|
||||
data class EncryptDecrypt (
|
||||
val sec1 : String? = null,
|
||||
val sec2 : String? = null,
|
||||
@JsonProperty("conversation_key" ) val conversationKey : String? = null,
|
||||
val nonce : String? = null,
|
||||
val plaintext : String? = null,
|
||||
val payload : String? = null
|
||||
data class EncryptDecrypt(
|
||||
val sec1: String? = null,
|
||||
val sec2: String? = null,
|
||||
@JsonProperty("conversation_key") val conversationKey: String? = null,
|
||||
val nonce: String? = null,
|
||||
val plaintext: String? = null,
|
||||
val payload: String? = null,
|
||||
)
|
||||
|
||||
data class EncryptDecryptLongMsg (
|
||||
@JsonProperty("conversation_key" ) val conversationKey : String? = null,
|
||||
val nonce : String? = null,
|
||||
val pattern : String? = null,
|
||||
val repeat : Int? = null,
|
||||
@JsonProperty("plaintext_sha256" ) val plaintextSha256 : String? = null,
|
||||
@JsonProperty("payload_sha256" ) val payloadSha256 : String? = null
|
||||
data class EncryptDecryptLongMsg(
|
||||
@JsonProperty("conversation_key") val conversationKey: String? = null,
|
||||
val nonce: String? = null,
|
||||
val pattern: String? = null,
|
||||
val repeat: Int? = null,
|
||||
@JsonProperty("plaintext_sha256") val plaintextSha256: String? = null,
|
||||
@JsonProperty("payload_sha256") val payloadSha256: String? = null,
|
||||
)
|
||||
|
||||
data class Decrypt (
|
||||
@JsonProperty("conversation_key" ) val conversationKey : String? = null,
|
||||
val nonce : String? = null,
|
||||
val plaintext : String? = null,
|
||||
val payload : String? = null,
|
||||
val note : String? = null
|
||||
data class Decrypt(
|
||||
@JsonProperty("conversation_key") val conversationKey: String? = null,
|
||||
val nonce: String? = null,
|
||||
val plaintext: String? = null,
|
||||
val payload: String? = null,
|
||||
val note: String? = null,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,13 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.vitorpamplona.quartz.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.encoders.Hex
|
||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import com.vitorpamplona.quartz.events.LnZapEvent
|
||||
import com.vitorpamplona.quartz.events.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.events.LnZapRequestEvent.Companion.createEncryptionPrivateKey
|
||||
import com.vitorpamplona.quartz.encoders.Hex
|
||||
import com.vitorpamplona.quartz.signers.NostrSignerInternal
|
||||
import junit.framework.TestCase.assertNotNull
|
||||
import junit.framework.TestCase.fail
|
||||
@@ -16,11 +36,11 @@ import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class PrivateZapTests {
|
||||
|
||||
@Test
|
||||
fun testPollZap() {
|
||||
val poll = Event.fromJson(
|
||||
"""{
|
||||
@Test
|
||||
fun testPollZap() {
|
||||
val poll =
|
||||
Event.fromJson(
|
||||
"""{
|
||||
"content": "New poll \n\n #zappoll",
|
||||
"created_at": 1682440713,
|
||||
"id": "16291ba452bb0786a4bf5c278d38de73c96b58c056ed75c5ea466b0795197288",
|
||||
@@ -59,52 +79,57 @@ class PrivateZapTests {
|
||||
"wss://relay.damus.io/"
|
||||
]
|
||||
}
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
val loggedIn = NostrSignerInternal(KeyPair(Hex.decode("e8e7197ccc53c9ed4cf9b1c8dce085475fa1ffdd71f2c14e44fe23d0bdf77598")))
|
||||
val loggedIn =
|
||||
NostrSignerInternal(
|
||||
KeyPair(Hex.decode("e8e7197ccc53c9ed4cf9b1c8dce085475fa1ffdd71f2c14e44fe23d0bdf77598")),
|
||||
)
|
||||
|
||||
var resultPrivateZap: Event? = null
|
||||
var resultPrivateZap: Event? = null
|
||||
|
||||
wait1SecondForResult { onDone ->
|
||||
LnZapRequestEvent.create(
|
||||
originalNote = poll,
|
||||
relays = setOf("wss://relay.damus.io/"),
|
||||
signer = loggedIn,
|
||||
pollOption = 0,
|
||||
message = "",
|
||||
zapType = LnZapEvent.ZapType.PRIVATE,
|
||||
toUserPubHex = null
|
||||
) { privateZapRequest ->
|
||||
val recepientPK = privateZapRequest.zappedAuthor().firstOrNull()
|
||||
val recepientPost = privateZapRequest.zappedPost().firstOrNull()
|
||||
wait1SecondForResult { onDone ->
|
||||
LnZapRequestEvent.create(
|
||||
originalNote = poll,
|
||||
relays = setOf("wss://relay.damus.io/"),
|
||||
signer = loggedIn,
|
||||
pollOption = 0,
|
||||
message = "",
|
||||
zapType = LnZapEvent.ZapType.PRIVATE,
|
||||
toUserPubHex = null,
|
||||
) { privateZapRequest ->
|
||||
val recepientPK = privateZapRequest.zappedAuthor().firstOrNull()
|
||||
val recepientPost = privateZapRequest.zappedPost().firstOrNull()
|
||||
|
||||
if (recepientPK != null && recepientPost != null) {
|
||||
val privateKey = createEncryptionPrivateKey(
|
||||
loggedIn.keyPair.privKey!!.toHexKey(),
|
||||
recepientPost,
|
||||
privateZapRequest.createdAt
|
||||
)
|
||||
val decodedPrivateZap =
|
||||
privateZapRequest.getPrivateZapEvent(privateKey, recepientPK)
|
||||
if (recepientPK != null && recepientPost != null) {
|
||||
val privateKey =
|
||||
createEncryptionPrivateKey(
|
||||
loggedIn.keyPair.privKey!!.toHexKey(),
|
||||
recepientPost,
|
||||
privateZapRequest.createdAt,
|
||||
)
|
||||
val decodedPrivateZap = privateZapRequest.getPrivateZapEvent(privateKey, recepientPK)
|
||||
|
||||
println(decodedPrivateZap?.toJson())
|
||||
println(decodedPrivateZap?.toJson())
|
||||
|
||||
resultPrivateZap = decodedPrivateZap
|
||||
resultPrivateZap = decodedPrivateZap
|
||||
|
||||
onDone()
|
||||
} else {
|
||||
fail("Should not be null")
|
||||
}
|
||||
}
|
||||
onDone()
|
||||
} else {
|
||||
fail("Should not be null")
|
||||
}
|
||||
|
||||
assertNotNull(resultPrivateZap)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKind1PrivateZap() {
|
||||
val textNote = Event.fromJson(
|
||||
"""{
|
||||
assertNotNull(resultPrivateZap)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKind1PrivateZap() {
|
||||
val textNote =
|
||||
Event.fromJson(
|
||||
"""{
|
||||
"content": "Testing copied author. \n\nnostr:npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z",
|
||||
"created_at": 1682369982,
|
||||
"id": "c757e1371d715c711ec9ef9740a3df6475d64b3d0af45ffcbfca08d273baf1c1",
|
||||
@@ -121,45 +146,49 @@ class PrivateZapTests {
|
||||
"wss://relay.damus.io/"
|
||||
]
|
||||
}
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
val loggedIn = NostrSignerInternal(KeyPair(Hex.decode("e8e7197ccc53c9ed4cf9b1c8dce085475fa1ffdd71f2c14e44fe23d0bdf77598")))
|
||||
val loggedIn =
|
||||
NostrSignerInternal(
|
||||
KeyPair(Hex.decode("e8e7197ccc53c9ed4cf9b1c8dce085475fa1ffdd71f2c14e44fe23d0bdf77598")),
|
||||
)
|
||||
|
||||
var resultPrivateZap: Event? = null
|
||||
var resultPrivateZap: Event? = null
|
||||
|
||||
wait1SecondForResult { onDone ->
|
||||
LnZapRequestEvent.create(
|
||||
originalNote = textNote,
|
||||
relays = setOf("wss://relay.damus.io/", "wss://relay.damus2.io/", "wss://relay.damus3.io/"),
|
||||
signer = loggedIn,
|
||||
pollOption = null,
|
||||
message = "test",
|
||||
zapType = LnZapEvent.ZapType.PRIVATE,
|
||||
toUserPubHex = null
|
||||
) { privateZapRequest ->
|
||||
val recepientPK = privateZapRequest.zappedAuthor().firstOrNull()
|
||||
val recepientPost = privateZapRequest.zappedPost().firstOrNull()
|
||||
wait1SecondForResult { onDone ->
|
||||
LnZapRequestEvent.create(
|
||||
originalNote = textNote,
|
||||
relays = setOf("wss://relay.damus.io/", "wss://relay.damus2.io/", "wss://relay.damus3.io/"),
|
||||
signer = loggedIn,
|
||||
pollOption = null,
|
||||
message = "test",
|
||||
zapType = LnZapEvent.ZapType.PRIVATE,
|
||||
toUserPubHex = null,
|
||||
) { privateZapRequest ->
|
||||
val recepientPK = privateZapRequest.zappedAuthor().firstOrNull()
|
||||
val recepientPost = privateZapRequest.zappedPost().firstOrNull()
|
||||
|
||||
if (recepientPK != null && recepientPost != null) {
|
||||
val privateKey = createEncryptionPrivateKey(
|
||||
loggedIn.keyPair.privKey!!.toHexKey(),
|
||||
recepientPost,
|
||||
privateZapRequest.createdAt
|
||||
)
|
||||
val decodedPrivateZap =
|
||||
privateZapRequest.getPrivateZapEvent(privateKey, recepientPK)
|
||||
if (recepientPK != null && recepientPost != null) {
|
||||
val privateKey =
|
||||
createEncryptionPrivateKey(
|
||||
loggedIn.keyPair.privKey!!.toHexKey(),
|
||||
recepientPost,
|
||||
privateZapRequest.createdAt,
|
||||
)
|
||||
val decodedPrivateZap = privateZapRequest.getPrivateZapEvent(privateKey, recepientPK)
|
||||
|
||||
println(decodedPrivateZap?.toJson())
|
||||
println(decodedPrivateZap?.toJson())
|
||||
|
||||
resultPrivateZap = decodedPrivateZap
|
||||
resultPrivateZap = decodedPrivateZap
|
||||
|
||||
onDone()
|
||||
} else {
|
||||
fail("Should not be null")
|
||||
}
|
||||
}
|
||||
onDone()
|
||||
} else {
|
||||
fail("Should not be null")
|
||||
}
|
||||
|
||||
assertNotNull(resultPrivateZap)
|
||||
}
|
||||
}
|
||||
|
||||
assertNotNull(resultPrivateZap)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user