Migrates EventStore from Android's SQLLite to KMP
Fixes testing of libsodium between java and android
This commit is contained in:
@@ -21,5 +21,7 @@
|
||||
package com.vitorpamplona.quartz
|
||||
|
||||
expect class TestResourceLoader() {
|
||||
fun loadDecompressString(file: String): String
|
||||
|
||||
fun loadString(file: String): String
|
||||
}
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import androidx.sqlite.SQLiteException
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync
|
||||
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class AddressableTest : BaseDBTest() {
|
||||
val signer = NostrSignerSync()
|
||||
|
||||
@Test
|
||||
fun testReplacingAddressables() =
|
||||
forEachDB { db ->
|
||||
val time = TimeUtils.now()
|
||||
val version1 = signer.sign(LongTextNoteEvent.build("my cool blog, version 1", "title", dTag = "my-cool-blog", createdAt = time))
|
||||
val version2 = signer.sign(LongTextNoteEvent.build("my cool blog, version 2", "title", dTag = "my-cool-blog", createdAt = time + 1))
|
||||
val version3 = signer.sign(LongTextNoteEvent.build("my cool blog, version 3", "title", dTag = "my-cool-blog", createdAt = time + 2))
|
||||
|
||||
val addressableQuery = Filter(kinds = listOf(version1.kind), authors = listOf(version1.pubKey), tags = mapOf("d" to listOf(version1.dTag())))
|
||||
|
||||
db.insert(version1)
|
||||
|
||||
db.assertQuery(version1, Filter(ids = listOf(version1.id)))
|
||||
db.assertQuery(version1, addressableQuery)
|
||||
|
||||
db.insert(version2)
|
||||
|
||||
db.assertQuery(null, Filter(ids = listOf(version1.id)))
|
||||
db.assertQuery(version2, Filter(ids = listOf(version2.id)))
|
||||
db.assertQuery(version2, addressableQuery)
|
||||
|
||||
db.insert(version3)
|
||||
|
||||
db.assertQuery(null, Filter(ids = listOf(version1.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(version2.id)))
|
||||
db.assertQuery(version3, Filter(ids = listOf(version3.id)))
|
||||
db.assertQuery(version3, addressableQuery)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBlockingOldAddressables() =
|
||||
forEachDB { db ->
|
||||
val time = TimeUtils.now()
|
||||
val version1 = signer.sign(LongTextNoteEvent.build("my cool blog, version 1", "title", dTag = "my-cool-blog", createdAt = time))
|
||||
val version2 = signer.sign(LongTextNoteEvent.build("my cool blog, version 2", "title", dTag = "my-cool-blog", createdAt = time + 1))
|
||||
val version3 = signer.sign(LongTextNoteEvent.build("my cool blog, version 3", "title", dTag = "my-cool-blog", createdAt = time + 2))
|
||||
|
||||
val addressableQuery = Filter(kinds = listOf(version1.kind), authors = listOf(version1.pubKey), tags = mapOf("d" to listOf(version1.dTag())))
|
||||
|
||||
db.insert(version3)
|
||||
|
||||
db.assertQuery(version3, Filter(ids = listOf(version3.id)))
|
||||
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(version2)
|
||||
}
|
||||
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(version1)
|
||||
}
|
||||
|
||||
db.assertQuery(version3, Filter(ids = listOf(version3.id)))
|
||||
db.assertQuery(version3, addressableQuery)
|
||||
db.assertQuery(null, Filter(ids = listOf(version2.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(version1.id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTriggersIndexUsage() =
|
||||
forEachDB { db ->
|
||||
val explainer =
|
||||
db.store.explainQuery(
|
||||
"""
|
||||
SELECT * FROM event_headers
|
||||
WHERE
|
||||
event_headers.kind = 30000 AND
|
||||
event_headers.pubkey = 'aa' AND
|
||||
event_headers.d_tag = 'test-tag' AND
|
||||
event_headers.created_at < 1766686500 AND
|
||||
event_headers.kind >= 30000 AND event_headers.kind < 40000
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
SELECT * FROM event_headers
|
||||
WHERE
|
||||
event_headers.kind = 30000 AND
|
||||
event_headers.pubkey = 'aa' AND
|
||||
event_headers.d_tag = 'test-tag' AND
|
||||
event_headers.created_at < 1766686500 AND
|
||||
event_headers.kind >= 30000 AND event_headers.kind < 40000
|
||||
└── SEARCH event_headers USING INDEX addressable_idx (kind=? AND pubkey=? AND d_tag=?)
|
||||
""".trimIndent(),
|
||||
explainer,
|
||||
)
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
fun <T : Event> EventStore.assertQuery(
|
||||
expected: T?,
|
||||
filter: Filter,
|
||||
) {
|
||||
val queryResult = query<T>(filter)
|
||||
val countResult = count(filter)
|
||||
if (expected == null) {
|
||||
assertEquals(0, queryResult.size)
|
||||
assertEquals(0, countResult)
|
||||
} else {
|
||||
assertEquals(1, queryResult.size)
|
||||
assertEquals(1, countResult)
|
||||
assertEquals(expected.toJson(), queryResult.first().toJson())
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Event> EventStore.assertQuery(
|
||||
expected: List<T>,
|
||||
filter: Filter,
|
||||
) {
|
||||
val queryResult = query<T>(filter)
|
||||
val countResult = count(filter)
|
||||
assertEquals(expected.size, queryResult.size)
|
||||
assertEquals(expected.size, countResult)
|
||||
expected.forEachIndexed { index, event ->
|
||||
assertEquals(event.toJson(), queryResult[index].toJson())
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Event> SQLiteEventStore.assertQuery(
|
||||
expected: T?,
|
||||
filter: Filter,
|
||||
) {
|
||||
val queryResult = query<T>(filter)
|
||||
val countResult = count(filter)
|
||||
if (expected == null) {
|
||||
assertEquals(0, queryResult.size)
|
||||
assertEquals(0, countResult)
|
||||
} else {
|
||||
assertEquals(1, queryResult.size)
|
||||
assertEquals(1, countResult)
|
||||
assertEquals(expected.toJson(), queryResult.first().toJson())
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Event> SQLiteEventStore.assertQuery(
|
||||
expected: List<T>,
|
||||
filter: Filter,
|
||||
) {
|
||||
val queryResult = query<T>(filter)
|
||||
val countResult = count(filter)
|
||||
assertEquals(expected.size, queryResult.size)
|
||||
assertEquals(expected.size, countResult)
|
||||
expected.forEachIndexed { index, event ->
|
||||
assertEquals(event.toJson(), queryResult[index].toJson())
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.store.sqlite.DefaultIndexingStrategy
|
||||
import com.vitorpamplona.quartz.nip01Core.store.sqlite.EventStore
|
||||
import kotlin.test.AfterTest
|
||||
import kotlin.test.BeforeTest
|
||||
|
||||
open class BaseDBTest {
|
||||
private lateinit var dbs: MutableMap<String, EventStore>
|
||||
|
||||
fun DefaultIndexingStrategy.name(): String =
|
||||
"""
|
||||
indexEventsByCreatedAtAlone=$indexEventsByCreatedAtAlone
|
||||
indexTagsByCreatedAtAlone=$indexTagsByCreatedAtAlone
|
||||
indexTagsWithKindAndPubkey=$indexTagsWithKindAndPubkey
|
||||
useAndIndexIdOnOrderBy=$useAndIndexIdOnOrderBy
|
||||
""".trimIndent()
|
||||
|
||||
@BeforeTest
|
||||
fun setup() {
|
||||
val booleans = listOf(true, false)
|
||||
|
||||
dbs = mutableMapOf<String, EventStore>()
|
||||
|
||||
// tests all possible DBs
|
||||
for (indexEventsByCreatedAtAlone in booleans) {
|
||||
for (indexTagsByCreatedAtAlone in booleans) {
|
||||
for (indexTagsWithKindAndPubkey in booleans) {
|
||||
for (useAndIndexIdOnOrderBy in booleans) {
|
||||
val indexStrategy =
|
||||
DefaultIndexingStrategy(
|
||||
indexEventsByCreatedAtAlone,
|
||||
indexTagsByCreatedAtAlone,
|
||||
indexTagsWithKindAndPubkey,
|
||||
useAndIndexIdOnOrderBy,
|
||||
)
|
||||
dbs[indexStrategy.name()] =
|
||||
EventStore(
|
||||
dbName = null,
|
||||
indexStrategy = indexStrategy,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
fun tearDown() {
|
||||
dbs.forEach { it.value.close() }
|
||||
}
|
||||
|
||||
fun forEachDB(action: (EventStore) -> Unit) {
|
||||
dbs.forEach {
|
||||
println("--------------------")
|
||||
println(it.key)
|
||||
println("--------------------")
|
||||
action(it.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.hashtags.isTaggedHash
|
||||
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class BasicTest : BaseDBTest() {
|
||||
val signer = NostrSignerSync()
|
||||
|
||||
companion object {
|
||||
val profile =
|
||||
MetadataEvent(
|
||||
id = "490d7439e530423f2540d4f2bdb73a0a2935f3df9e1f2a6f699a140c7db311fe",
|
||||
pubKey = "70a9b3c312a6b83e476739bd29d60ca700da1d5b982cbca87b5f3d27d4038d67",
|
||||
createdAt = 1740669816,
|
||||
tags =
|
||||
arrayOf(
|
||||
arrayOf("alt", "User profile for Vitor"),
|
||||
arrayOf("name", "Vitor"),
|
||||
),
|
||||
content = "{\"name\":\"Vitor\"}",
|
||||
sig = "977a6152199f17d103d8d56736ed1b7767054464cf9423d017c01c8cdd2344698f0a5e13da8dff98d01bb1f798837e3b6271e1fd1cac861bb90686f622ae6ef4",
|
||||
)
|
||||
|
||||
val comment =
|
||||
CommentEvent(
|
||||
id = "fecb2ecf61a1433d417a784d10bd1e8ec19a916170a53ca8fb3a15fc666a6592",
|
||||
pubKey = "f8ff11c7a7d3478355d3b4d174e5a473797a906ea4aa61aa9b6bc0652c1ea17a",
|
||||
createdAt = 1747753115,
|
||||
tags =
|
||||
arrayOf(
|
||||
arrayOf("alt", "Reply to geo:drt3n"),
|
||||
arrayOf("I", "geo:drt3n"),
|
||||
arrayOf("I", "geo:drt3"),
|
||||
arrayOf("I", "geo:drt"),
|
||||
arrayOf("I", "geo:dr"),
|
||||
arrayOf("I", "geo:d"),
|
||||
arrayOf("K", "geo"),
|
||||
arrayOf("i", "geo:drt3n"),
|
||||
arrayOf("i", "geo:drt3"),
|
||||
arrayOf("i", "geo:drt"),
|
||||
arrayOf("i", "geo:dr"),
|
||||
arrayOf("i", "geo:d"),
|
||||
arrayOf("k", "geo"),
|
||||
),
|
||||
content = "testing",
|
||||
sig = "12070e663272f1227c639fb834eb2122fc7bb995f4c49e55ebb1dfe2135ef7347d44810bacd2e64fd26b8826fd47d2800ce6c3d3b579bb3afe39088ffd4faa60",
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInsertDeleteEvent() =
|
||||
forEachDB { db ->
|
||||
val note = signer.sign(TextNoteEvent.build("test1"))
|
||||
|
||||
db.store.insertEvent(note)
|
||||
|
||||
db.store.assertQuery(note, Filter(ids = listOf(note.id)))
|
||||
|
||||
db.store.delete(note.id)
|
||||
|
||||
db.store.assertQuery(null, Filter(ids = listOf(note.id)))
|
||||
|
||||
db.store.insertEvent(note)
|
||||
|
||||
db.store.assertQuery(note, Filter(ids = listOf(note.id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEmptyFilter() =
|
||||
forEachDB { db ->
|
||||
val note1 = signer.sign(TextNoteEvent.build("test1", createdAt = 1))
|
||||
val note2 = signer.sign(TextNoteEvent.build("test2", createdAt = 2))
|
||||
|
||||
db.store.insertEvent(note1)
|
||||
|
||||
db.store.assertQuery(note1, Filter())
|
||||
|
||||
db.store.insertEvent(note2)
|
||||
|
||||
db.store.assertQuery(listOf(note2, note1), Filter())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLimitFilter() =
|
||||
forEachDB { db ->
|
||||
val note1 = signer.sign(TextNoteEvent.build("test1", createdAt = 1))
|
||||
val note2 = signer.sign(TextNoteEvent.build("test2", createdAt = 2))
|
||||
val note3 = signer.sign(TextNoteEvent.build("test3", createdAt = 3))
|
||||
val note4 = signer.sign(TextNoteEvent.build("test4", createdAt = 4))
|
||||
|
||||
db.store.insertEvent(note1)
|
||||
|
||||
db.store.assertQuery(note1, Filter(limit = 1))
|
||||
|
||||
db.store.insertEvent(note2)
|
||||
db.store.insertEvent(note3)
|
||||
db.store.insertEvent(note4)
|
||||
|
||||
db.store.assertQuery(listOf(note4), Filter(limit = 1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPubkeyTag() =
|
||||
forEachDB { db ->
|
||||
db.store.insertEvent(comment)
|
||||
db.store.insertEvent(profile)
|
||||
|
||||
db.store.assertQuery(
|
||||
comment,
|
||||
Filter(authors = listOf(comment.pubKey), tags = mapOf("I" to listOf("geo:drt3n"))),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTagOnly() =
|
||||
forEachDB { db ->
|
||||
db.store.insertEvent(comment)
|
||||
db.store.insertEvent(profile)
|
||||
|
||||
db.store.assertQuery(comment, Filter(tags = mapOf("I" to listOf("geo:drt3n"))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTagWithSinceOnly() =
|
||||
forEachDB { db ->
|
||||
db.store.insertEvent(comment)
|
||||
db.store.insertEvent(profile)
|
||||
|
||||
db.store.assertQuery(
|
||||
comment,
|
||||
Filter(tags = mapOf("I" to listOf("geo:drt3n")), since = comment.createdAt - 1),
|
||||
)
|
||||
db.store.assertQuery(
|
||||
comment,
|
||||
Filter(tags = mapOf("I" to listOf("geo:drt3n")), since = comment.createdAt),
|
||||
)
|
||||
db.store.assertQuery(
|
||||
null,
|
||||
Filter(tags = mapOf("I" to listOf("geo:drt3n")), since = comment.createdAt + 1),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTagWithUntilOnly() =
|
||||
forEachDB { db ->
|
||||
db.store.insertEvent(comment)
|
||||
db.store.insertEvent(profile)
|
||||
|
||||
db.store.assertQuery(
|
||||
null,
|
||||
Filter(tags = mapOf("I" to listOf("geo:drt3n")), until = comment.createdAt - 1),
|
||||
)
|
||||
db.store.assertQuery(
|
||||
comment,
|
||||
Filter(tags = mapOf("I" to listOf("geo:drt3n")), until = comment.createdAt),
|
||||
)
|
||||
db.store.assertQuery(
|
||||
comment,
|
||||
Filter(tags = mapOf("I" to listOf("geo:drt3n")), until = comment.createdAt + 1),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTagWithUntilOnlyEmitting() =
|
||||
forEachDB { db ->
|
||||
db.store.insertEvent(comment)
|
||||
db.store.insertEvent(profile)
|
||||
|
||||
db.store.query<Event>(Filter(tags = mapOf("I" to listOf("geo:drt3n")))) { event ->
|
||||
assertEquals(comment.toJson(), event.toJson())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hashCodeTest() =
|
||||
forEachDB { db ->
|
||||
val note1 =
|
||||
signer.sign(
|
||||
TextNoteEvent.build("test1") {
|
||||
hashtag("AaAa")
|
||||
},
|
||||
)
|
||||
val note2 =
|
||||
signer.sign(
|
||||
TextNoteEvent.build("test2") {
|
||||
hashtag("AaAa")
|
||||
},
|
||||
)
|
||||
val note3 =
|
||||
signer.sign(
|
||||
TextNoteEvent.build("test3") {
|
||||
hashtag("BBBB")
|
||||
},
|
||||
)
|
||||
|
||||
db.store.insertEvent(note1)
|
||||
db.store.insertEvent(note2)
|
||||
db.store.insertEvent(note3)
|
||||
|
||||
val list =
|
||||
db.query<TextNoteEvent>(
|
||||
Filter(
|
||||
tags = mapOf("t" to listOf("AaAa")),
|
||||
),
|
||||
)
|
||||
|
||||
assertEquals(2, list.size)
|
||||
list.forEach {
|
||||
assertTrue(it.isTaggedHash("AaAa"))
|
||||
}
|
||||
}
|
||||
}
|
||||
+408
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import androidx.sqlite.SQLiteException
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Address
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync
|
||||
import com.vitorpamplona.quartz.nip01Core.store.sqlite.TagNameValueHasher
|
||||
import com.vitorpamplona.quartz.nip01Core.store.sqlite.explainQuery
|
||||
import com.vitorpamplona.quartz.nip09Deletions.DeletionEvent
|
||||
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class DeletionTest : BaseDBTest() {
|
||||
val signer = NostrSignerSync()
|
||||
|
||||
@Test
|
||||
fun testInsertDeleteEvent() =
|
||||
forEachDB { db ->
|
||||
val note1 = signer.sign(TextNoteEvent.build("test1"))
|
||||
val note2 = signer.sign(TextNoteEvent.build("test2"))
|
||||
val note3 = signer.sign(TextNoteEvent.build("test3"))
|
||||
|
||||
db.insert(note1)
|
||||
db.insert(note2)
|
||||
db.insert(note3)
|
||||
|
||||
db.assertQuery(note1, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(note2, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(note3, Filter(ids = listOf(note3.id)))
|
||||
|
||||
val deletion = signer.sign(DeletionEvent.build(listOf(note1)))
|
||||
|
||||
db.insert(deletion)
|
||||
|
||||
db.assertQuery(deletion, Filter(ids = listOf(deletion.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(note2, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(note3, Filter(ids = listOf(note3.id)))
|
||||
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(note1)
|
||||
}
|
||||
|
||||
db.assertQuery(deletion, Filter(ids = listOf(deletion.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(note2, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(note3, Filter(ids = listOf(note3.id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInsertDeleteEventOfAddressable() =
|
||||
forEachDB { db ->
|
||||
val time = TimeUtils.now()
|
||||
val note1 = signer.sign(LongTextNoteEvent.build("my cool blog, version 1", "title", dTag = "my-cool-blog", createdAt = time))
|
||||
val note2 = signer.sign(LongTextNoteEvent.build("my cool blog, version 2", "title", dTag = "my-cool-blog", createdAt = time + 1))
|
||||
val note3 = signer.sign(LongTextNoteEvent.build("my cool blog, version 3", "title", dTag = "my-cool-blog", createdAt = time + 2))
|
||||
|
||||
db.insert(note1)
|
||||
|
||||
db.assertQuery(note1, Filter(ids = listOf(note1.id)))
|
||||
|
||||
db.insert(note2)
|
||||
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(note2, Filter(ids = listOf(note2.id)))
|
||||
|
||||
db.insert(note3)
|
||||
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(note3, Filter(ids = listOf(note3.id)))
|
||||
|
||||
val deletion = signer.sign(DeletionEvent.build(listOf(note1)))
|
||||
|
||||
db.insert(deletion)
|
||||
|
||||
db.assertQuery(deletion, Filter(ids = listOf(deletion.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note3.id)))
|
||||
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(note1)
|
||||
}
|
||||
|
||||
db.assertQuery(deletion, Filter(ids = listOf(deletion.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note3.id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInsertDeleteEventOfAddressable2() =
|
||||
forEachDB { db ->
|
||||
val time = TimeUtils.now()
|
||||
val note1 = signer.sign(LongTextNoteEvent.build("my cool blog, version 1", "title", dTag = "my-cool-blog", createdAt = time))
|
||||
val note2 = signer.sign(LongTextNoteEvent.build("my cool blog, version 2", "title", dTag = "my-cool-blog", createdAt = time + 1))
|
||||
val note3 = signer.sign(LongTextNoteEvent.build("my cool blog, version 3", "title", dTag = "my-cool-blog", createdAt = time + 2))
|
||||
|
||||
db.insert(note1)
|
||||
db.insert(note2)
|
||||
db.insert(note3)
|
||||
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(note3, Filter(ids = listOf(note3.id)))
|
||||
|
||||
val deletion = signer.sign(DeletionEvent.buildAddressOnly(listOf(note1)))
|
||||
|
||||
db.insert(deletion)
|
||||
|
||||
db.assertQuery(deletion, Filter(ids = listOf(deletion.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note3.id)))
|
||||
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(note1)
|
||||
}
|
||||
|
||||
db.assertQuery(deletion, Filter(ids = listOf(deletion.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note3.id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInsertDeleteWrap() =
|
||||
forEachDB { db ->
|
||||
val me = NostrSignerSync()
|
||||
val myFriend = NostrSignerSync()
|
||||
|
||||
val note1 = me.sign(TextNoteEvent.build("test1"))
|
||||
val wrap1 = GiftWrapEvent.create(note1, me.pubKey)
|
||||
val wrap2 = GiftWrapEvent.create(note1, myFriend.pubKey)
|
||||
|
||||
db.insert(wrap1)
|
||||
db.insert(wrap2)
|
||||
|
||||
db.assertQuery(wrap1, Filter(ids = listOf(wrap1.id)))
|
||||
db.assertQuery(wrap2, Filter(ids = listOf(wrap2.id)))
|
||||
|
||||
val randomDeletionToWrap = signer.sign(DeletionEvent.build(listOf(wrap1)))
|
||||
|
||||
db.insert(randomDeletionToWrap)
|
||||
|
||||
db.assertQuery(randomDeletionToWrap, Filter(ids = listOf(randomDeletionToWrap.id)))
|
||||
db.assertQuery(wrap1, Filter(ids = listOf(wrap1.id)))
|
||||
db.assertQuery(wrap2, Filter(ids = listOf(wrap2.id)))
|
||||
|
||||
val deletion = me.sign(DeletionEvent.build(listOf(wrap1)))
|
||||
|
||||
db.insert(deletion)
|
||||
|
||||
db.assertQuery(deletion, Filter(ids = listOf(deletion.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(wrap1.id)))
|
||||
db.assertQuery(wrap2, Filter(ids = listOf(wrap2.id)))
|
||||
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(wrap1)
|
||||
}
|
||||
|
||||
db.assertQuery(deletion, Filter(ids = listOf(deletion.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(wrap1.id)))
|
||||
db.assertQuery(wrap2, Filter(ids = listOf(wrap2.id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTriggersIndexUsage() =
|
||||
forEachDB { db ->
|
||||
var sql = db.store.deletionModule.rejectDeletedEventsSQLTemplate()
|
||||
|
||||
sql = sql.replace("NEW.etag_hash", "3221122")
|
||||
sql = sql.replace("NEW.atag_hash", "223322")
|
||||
sql = sql.replace("NEW.pubkey_owner_hash", "22332323")
|
||||
sql = sql.replace("NEW.created_at", "1766686500")
|
||||
|
||||
val explainer = db.store.explainQuery(sql)
|
||||
|
||||
if (db.indexStrategy.indexTagsWithKindAndPubkey) {
|
||||
assertEquals(
|
||||
"""
|
||||
|$sql
|
||||
|└── SEARCH event_tags USING COVERING INDEX query_by_tags_hash_kind_pubkey (tag_hash=? AND kind=? AND pubkey_hash=? AND created_at>?)
|
||||
""".trimMargin(),
|
||||
explainer,
|
||||
)
|
||||
} else {
|
||||
assertEquals(
|
||||
"""
|
||||
|$sql
|
||||
|└── SEARCH event_tags USING INDEX query_by_tags_hash_kind (tag_hash=? AND kind=? AND created_at>?)
|
||||
""".trimMargin(),
|
||||
explainer,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeleteById() =
|
||||
forEachDB { db ->
|
||||
val sql =
|
||||
db.store.deletionModule
|
||||
.deleteSQL(
|
||||
pubkey = "key1",
|
||||
idValues = listOf("ca29c211f", "ca29c211d"),
|
||||
addresses = emptyList(),
|
||||
hasher =
|
||||
TagNameValueHasher(
|
||||
0,
|
||||
),
|
||||
).first()
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
DELETE FROM event_headers
|
||||
WHERE
|
||||
id IN ("ca29c211f","ca29c211d") AND
|
||||
pubkey_owner_hash = "1573573083296714675"
|
||||
├── SEARCH event_headers USING INDEX event_headers_id (id=?)
|
||||
├── SEARCH event_vanish USING INTEGER PRIMARY KEY (rowid=?)
|
||||
├── SEARCH event_expirations USING INTEGER PRIMARY KEY (rowid=?)
|
||||
└── SEARCH event_tags USING COVERING INDEX fk_event_tags_header_id (event_header_row_id=?)
|
||||
""".trimIndent(),
|
||||
db.store.explainQuery(sql.sql, sql.args),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeleteAddressable() =
|
||||
forEachDB { db ->
|
||||
val sql =
|
||||
db.store.deletionModule
|
||||
.deleteSQL(
|
||||
pubkey = "key1",
|
||||
idValues = emptyList(),
|
||||
addresses =
|
||||
listOf(
|
||||
Address(30000, "key1", "a"),
|
||||
),
|
||||
hasher =
|
||||
TagNameValueHasher(
|
||||
0,
|
||||
),
|
||||
).first()
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
DELETE FROM event_headers
|
||||
WHERE (
|
||||
(kind = "30000" AND pubkey = "key1" AND d_tag = "a")
|
||||
) AND
|
||||
kind >= 30000 AND kind < 40000
|
||||
├── SEARCH event_headers USING COVERING INDEX addressable_idx (kind=? AND pubkey=? AND d_tag=?)
|
||||
├── SEARCH event_vanish USING INTEGER PRIMARY KEY (rowid=?)
|
||||
├── SEARCH event_expirations USING INTEGER PRIMARY KEY (rowid=?)
|
||||
└── SEARCH event_tags USING COVERING INDEX fk_event_tags_header_id (event_header_row_id=?)
|
||||
""".trimIndent(),
|
||||
db.store.explainQuery(sql.sql, sql.args),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeleteAddressablesSingleKind() =
|
||||
forEachDB { db ->
|
||||
val sql =
|
||||
db.store.deletionModule
|
||||
.deleteSQL(
|
||||
pubkey = "key1",
|
||||
idValues = emptyList(),
|
||||
addresses =
|
||||
listOf(
|
||||
Address(30000, "key1", "a"),
|
||||
Address(30000, "key1", "b"),
|
||||
Address(30000, "key1", "c"),
|
||||
Address(30000, "key1", "d"),
|
||||
),
|
||||
hasher =
|
||||
TagNameValueHasher(
|
||||
0,
|
||||
),
|
||||
).first()
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
DELETE FROM event_headers
|
||||
WHERE (
|
||||
(kind = "30000" AND pubkey = "key1" AND d_tag IN ("a","b","c","d"))
|
||||
) AND
|
||||
kind >= 30000 AND kind < 40000
|
||||
├── SEARCH event_headers USING COVERING INDEX addressable_idx (kind=? AND pubkey=? AND d_tag=?)
|
||||
├── SEARCH event_vanish USING INTEGER PRIMARY KEY (rowid=?)
|
||||
├── SEARCH event_expirations USING INTEGER PRIMARY KEY (rowid=?)
|
||||
└── SEARCH event_tags USING COVERING INDEX fk_event_tags_header_id (event_header_row_id=?)
|
||||
""".trimIndent(),
|
||||
db.store.explainQuery(sql.sql, sql.args),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeleteAddressablesMultipleKinds() =
|
||||
forEachDB { db ->
|
||||
val sql =
|
||||
db.store.deletionModule
|
||||
.deleteSQL(
|
||||
pubkey = "key1",
|
||||
idValues = emptyList(),
|
||||
addresses =
|
||||
listOf(
|
||||
Address(30000, "key1", "a"),
|
||||
Address(30000, "key1", "b"),
|
||||
Address(30101, "key1", "c"),
|
||||
Address(30101, "key1", "d"),
|
||||
Address(30001, "key2", "e"),
|
||||
Address(30001, "key2", "f"),
|
||||
),
|
||||
hasher =
|
||||
TagNameValueHasher(
|
||||
0,
|
||||
),
|
||||
).first()
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
DELETE FROM event_headers
|
||||
WHERE (
|
||||
(kind = "30000" AND pubkey = "key1" AND d_tag IN ("a","b"))
|
||||
OR
|
||||
(kind = "30101" AND pubkey = "key1" AND d_tag IN ("c","d"))
|
||||
) AND
|
||||
kind >= 30000 AND kind < 40000
|
||||
├── MULTI-INDEX OR
|
||||
│ ├── INDEX 1
|
||||
│ │ └── SEARCH event_headers USING COVERING INDEX addressable_idx (kind=? AND pubkey=? AND d_tag=?)
|
||||
│ └── INDEX 2
|
||||
│ └── SEARCH event_headers USING COVERING INDEX addressable_idx (kind=? AND pubkey=? AND d_tag=?)
|
||||
├── SEARCH event_vanish USING INTEGER PRIMARY KEY (rowid=?)
|
||||
├── SEARCH event_expirations USING INTEGER PRIMARY KEY (rowid=?)
|
||||
└── SEARCH event_tags USING COVERING INDEX fk_event_tags_header_id (event_header_row_id=?)
|
||||
""".trimIndent(),
|
||||
db.store.explainQuery(sql.sql, sql.args),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeleteReplaceables() =
|
||||
forEachDB { db ->
|
||||
val sql =
|
||||
db.store.deletionModule
|
||||
.deleteSQL(
|
||||
pubkey = "key1",
|
||||
idValues = emptyList(),
|
||||
addresses =
|
||||
listOf(
|
||||
Address(10000, "key1", ""),
|
||||
Address(10000, "key1", ""),
|
||||
Address(10001, "key1", ""),
|
||||
Address(10001, "key1", ""),
|
||||
Address(10001, "key2", ""),
|
||||
Address(10001, "key2", ""),
|
||||
),
|
||||
hasher =
|
||||
TagNameValueHasher(
|
||||
0,
|
||||
),
|
||||
).first()
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
DELETE FROM event_headers
|
||||
WHERE
|
||||
kind IN ("10000","10001") AND
|
||||
pubkey = "key1" AND
|
||||
((kind in (0,3)) OR (kind >= 10000 AND kind < 20000))
|
||||
├── SEARCH event_headers USING COVERING INDEX replaceable_idx (kind=? AND pubkey=?)
|
||||
├── SEARCH event_vanish USING INTEGER PRIMARY KEY (rowid=?)
|
||||
├── SEARCH event_expirations USING INTEGER PRIMARY KEY (rowid=?)
|
||||
└── SEARCH event_tags USING COVERING INDEX fk_event_tags_header_id (event_header_row_id=?)
|
||||
""".trimIndent(),
|
||||
db.store.explainQuery(sql.sql, sql.args),
|
||||
)
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import androidx.sqlite.SQLiteException
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync
|
||||
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip40Expiration.expiration
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class ExpirationTest : BaseDBTest() {
|
||||
val signer = NostrSignerSync()
|
||||
|
||||
@Test
|
||||
fun testDeletingExpiredEvents() =
|
||||
forEachDB { db ->
|
||||
val time = TimeUtils.now()
|
||||
|
||||
val noteSafe =
|
||||
signer.sign(
|
||||
TextNoteEvent.build("test1", createdAt = time + 1) {
|
||||
expiration(time + 100)
|
||||
},
|
||||
)
|
||||
|
||||
db.insert(noteSafe)
|
||||
|
||||
val noteToExpire =
|
||||
signer.sign(
|
||||
TextNoteEvent.build("test1", createdAt = time + 1) {
|
||||
expiration(time + 1)
|
||||
},
|
||||
)
|
||||
|
||||
db.insert(noteToExpire)
|
||||
|
||||
db.assertQuery(noteToExpire, Filter(ids = listOf(noteToExpire.id)))
|
||||
|
||||
runBlocking {
|
||||
delay(2000)
|
||||
}
|
||||
|
||||
db.deleteExpiredEvents()
|
||||
|
||||
db.assertQuery(null, Filter(ids = listOf(noteToExpire.id)))
|
||||
db.assertQuery(noteSafe, Filter(ids = listOf(noteSafe.id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInsertingExpiredEvents() =
|
||||
forEachDB { db ->
|
||||
val time = TimeUtils.now()
|
||||
|
||||
val note1 =
|
||||
signer.sign(
|
||||
TextNoteEvent.build("test1", createdAt = time - 12) {
|
||||
expiration(time - 10)
|
||||
},
|
||||
)
|
||||
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(note1)
|
||||
}
|
||||
}
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import kotlin.test.Test
|
||||
|
||||
class FilterMatcherTest : BaseDBTest() {
|
||||
val id = "98b574c3527f0ffb30b7271084e3f07480733c7289f8de424d29eae82e36c758"
|
||||
val pubkey = "46fcbe3065eaf1ae7811465924e48923363ff3f526bd6f73d7c184b16bd8ce4d"
|
||||
val createdAt: Long = 1683596206
|
||||
val kind = 1
|
||||
|
||||
val pTag1 = "22aa81510ee63fe2b16cae16e0921f78e9ba9882e2868e7e63ad6d08ae9b5954"
|
||||
val pTag2 = "3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24"
|
||||
val pTag3 = "ec4d241c334311b3a304433ee3442be29d0e88e7ec19b85edf2bba29b93565e2"
|
||||
val pTag4 = "0fe0b18b4dbf0e0aa40fcd47209b2a49b3431fc453b460efcf45ca0bd16bd6ac"
|
||||
val pTag5 = "8c0da4862130283ff9e67d889df264177a508974e2feb96de139804ea66d6168"
|
||||
val pTag6 = "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed"
|
||||
val pTag7 = "4523be58d395b1b196a9b8c82b038b6895cb02b683d0c253a955068dba1facd0"
|
||||
val pTag8 = "460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c"
|
||||
|
||||
val rootETag = "27ac621d7dc4a932e1a79f984308e7d20656dd6fddb2ce9cdfcb6a67b9a7bcc3"
|
||||
val replyETag = "be7245af96210a0dd048cab4ad38e52dbd6c09a53ea21a7edb6be8898e5727cc"
|
||||
|
||||
val note =
|
||||
Event(
|
||||
id,
|
||||
pubkey,
|
||||
createdAt,
|
||||
kind,
|
||||
arrayOf(
|
||||
arrayOf("e", rootETag, "", "root"),
|
||||
arrayOf("e", replyETag, "", "reply"),
|
||||
arrayOf("p", pTag1),
|
||||
arrayOf("p", pTag1),
|
||||
arrayOf("p", pTag2),
|
||||
arrayOf("p", pTag3),
|
||||
arrayOf("p", pTag4),
|
||||
arrayOf("p", pTag5),
|
||||
arrayOf("p", pTag6),
|
||||
arrayOf("p", pTag7),
|
||||
arrayOf("p", pTag8),
|
||||
),
|
||||
"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 ",
|
||||
"4aa5264965018fa12a326686ad3d3bd8beae3218dcc83689b19ca1e6baeb791531943c15363aa6707c7c0c8b2d601deca1f20c32078b2872d356cdca03b04cce",
|
||||
)
|
||||
|
||||
@Test
|
||||
fun matchIds() =
|
||||
forEachDB { db ->
|
||||
db.insert(note)
|
||||
|
||||
db.assertQuery(note, Filter(ids = listOf(id)))
|
||||
db.assertQuery(note, Filter(ids = listOf(id, rootETag)))
|
||||
db.assertQuery(null, Filter(ids = listOf(rootETag)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun matchPubkeys() =
|
||||
forEachDB { db ->
|
||||
db.insert(note)
|
||||
|
||||
db.assertQuery(note, Filter(authors = listOf(pubkey)))
|
||||
db.assertQuery(note, Filter(authors = listOf(pubkey, rootETag)))
|
||||
db.assertQuery(null, Filter(authors = listOf(rootETag)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun matchTags() =
|
||||
forEachDB { db ->
|
||||
db.insert(note)
|
||||
|
||||
db.assertQuery(note, Filter(tags = mapOf("p" to listOf(pTag1))))
|
||||
db.assertQuery(note, Filter(tags = mapOf("p" to listOf(pTag1, pTag2, pTag3))))
|
||||
db.assertQuery(note, Filter(tags = mapOf("p" to listOf(pTag1, id))))
|
||||
db.assertQuery(null, Filter(tags = mapOf("p" to listOf(id))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun matchDualTags() =
|
||||
forEachDB { db ->
|
||||
db.insert(note)
|
||||
|
||||
db.assertQuery(note, Filter(tags = mapOf("p" to listOf(pTag1), "e" to listOf(rootETag))))
|
||||
db.assertQuery(note, Filter(tags = mapOf("p" to listOf(pTag1, pTag2, pTag3), "e" to listOf(rootETag, replyETag))))
|
||||
db.assertQuery(note, Filter(tags = mapOf("p" to listOf(pTag1, id), "e" to listOf(rootETag, replyETag))))
|
||||
db.assertQuery(note, Filter(tags = mapOf("p" to listOf(pTag1, id), "e" to listOf(rootETag, pubkey))))
|
||||
db.assertQuery(null, Filter(tags = mapOf("p" to listOf(pTag1, id), "e" to listOf(id, pubkey))))
|
||||
db.assertQuery(null, Filter(tags = mapOf("p" to listOf(id), "e" to listOf(rootETag))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun matchAllTags() =
|
||||
forEachDB { db ->
|
||||
db.insert(note)
|
||||
|
||||
db.assertQuery(note, Filter(tagsAll = mapOf("p" to listOf(pTag1))))
|
||||
db.assertQuery(note, Filter(tagsAll = mapOf("p" to listOf(pTag1, pTag2, pTag3))))
|
||||
db.assertQuery(null, Filter(tagsAll = mapOf("p" to listOf(pTag1, id))))
|
||||
db.assertQuery(null, Filter(tagsAll = mapOf("p" to listOf(id))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun matchDualAllTags() =
|
||||
forEachDB { db ->
|
||||
db.insert(note)
|
||||
|
||||
db.assertQuery(note, Filter(tagsAll = mapOf("p" to listOf(pTag1), "e" to listOf(rootETag))))
|
||||
db.assertQuery(note, Filter(tagsAll = mapOf("p" to listOf(pTag1, pTag2, pTag3), "e" to listOf(rootETag, replyETag))))
|
||||
db.assertQuery(null, Filter(tagsAll = mapOf("p" to listOf(pTag1, id), "e" to listOf(rootETag, replyETag))))
|
||||
db.assertQuery(null, Filter(tagsAll = mapOf("p" to listOf(pTag1, id), "e" to listOf(rootETag, pubkey))))
|
||||
db.assertQuery(null, Filter(tagsAll = mapOf("p" to listOf(pTag1, id), "e" to listOf(id, pubkey))))
|
||||
db.assertQuery(null, Filter(tagsAll = mapOf("p" to listOf(id), "e" to listOf(rootETag))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun matchKinds() =
|
||||
forEachDB { db ->
|
||||
db.insert(note)
|
||||
|
||||
db.assertQuery(note, Filter(kinds = listOf(kind)))
|
||||
db.assertQuery(note, Filter(kinds = listOf(kind, 1221)))
|
||||
db.assertQuery(null, Filter(kinds = listOf(1221)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun matchSince() =
|
||||
forEachDB { db ->
|
||||
db.insert(note)
|
||||
|
||||
db.assertQuery(note, Filter(since = createdAt))
|
||||
db.assertQuery(note, Filter(since = createdAt - 1))
|
||||
db.assertQuery(null, Filter(since = createdAt + 1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun matchUntil() =
|
||||
forEachDB { db ->
|
||||
db.insert(note)
|
||||
|
||||
db.assertQuery(note, Filter(until = createdAt))
|
||||
db.assertQuery(note, Filter(until = createdAt + 1))
|
||||
db.assertQuery(null, Filter(until = createdAt - 1))
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import androidx.sqlite.SQLiteException
|
||||
import com.vitorpamplona.quartz.TestResourceLoader
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper
|
||||
import com.vitorpamplona.quartz.nip01Core.store.sqlite.EventStore
|
||||
import com.vitorpamplona.quartz.nip40Expiration.isExpired
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import kotlin.test.AfterTest
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.Test
|
||||
|
||||
class LargeDBTests {
|
||||
companion object {
|
||||
fun getEventDB(): List<Event> =
|
||||
OptimizedJsonMapper.fromJsonToEventList(
|
||||
TestResourceLoader().loadDecompressString("nostr_vitor_startup_data.json"),
|
||||
)
|
||||
|
||||
val events by
|
||||
lazy {
|
||||
getEventDB().distinctBy { it.id }.filter { !it.isExpired() }.sortedBy { it.createdAt }
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var db: EventStore
|
||||
|
||||
@BeforeTest
|
||||
fun setup() {
|
||||
db = EventStore(null)
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
fun tearDown() {
|
||||
db.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun insertHeavyEvent() {
|
||||
events.first { it.id == "3f34b8cb682307ec11753de4669ce8948e95fd6fb360d79136446c5547fd235e" }.let { event ->
|
||||
try {
|
||||
db.insert(event)
|
||||
} catch (e: SQLiteException) {
|
||||
Log.w("LargeDBTests", "Error inserting event: ${e.message} for event: ${event.toJson()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun insertDatabase() {
|
||||
events.forEach { event ->
|
||||
try {
|
||||
db.insert(event)
|
||||
} catch (e: SQLiteException) {
|
||||
Log.w("LargeDBTests", "Error inserting event: ${e.message} for event: ${event.toJson()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1021
File diff suppressed because it is too large
Load Diff
+146
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import androidx.sqlite.SQLiteException
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync
|
||||
import com.vitorpamplona.quartz.nip01Core.store.sqlite.explainQuery
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class ReplaceableTest : BaseDBTest() {
|
||||
val signer = NostrSignerSync()
|
||||
|
||||
@Test
|
||||
fun testReplacing() =
|
||||
forEachDB { db ->
|
||||
val time = TimeUtils.now()
|
||||
val version1 = signer.sign(MetadataEvent.createNew("Vitor 1", createdAt = time))
|
||||
val version2 = signer.sign(MetadataEvent.createNew("Vitor 2", createdAt = time + 1))
|
||||
val version3 = signer.sign(MetadataEvent.createNew("Vitor 3", createdAt = time + 2))
|
||||
|
||||
val addressableQuery = Filter(kinds = listOf(version1.kind), authors = listOf(version1.pubKey), tags = mapOf("d" to listOf(version1.dTag())))
|
||||
|
||||
db.insert(version1)
|
||||
|
||||
db.assertQuery(version1, Filter(ids = listOf(version1.id)))
|
||||
db.assertQuery(version1, addressableQuery)
|
||||
|
||||
db.insert(version2)
|
||||
|
||||
db.assertQuery(null, Filter(ids = listOf(version1.id)))
|
||||
db.assertQuery(version2, Filter(ids = listOf(version2.id)))
|
||||
db.assertQuery(version2, addressableQuery)
|
||||
|
||||
db.insert(version3)
|
||||
|
||||
db.assertQuery(null, Filter(ids = listOf(version1.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(version2.id)))
|
||||
db.assertQuery(version3, Filter(ids = listOf(version3.id)))
|
||||
db.assertQuery(version3, addressableQuery)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBlockingOldVersions() =
|
||||
forEachDB { db ->
|
||||
val time = TimeUtils.now()
|
||||
val version1 = signer.sign(MetadataEvent.createNew("Vitor 1", createdAt = time))
|
||||
val version2 = signer.sign(MetadataEvent.createNew("Vitor 2", createdAt = time + 1))
|
||||
val version3 = signer.sign(MetadataEvent.createNew("Vitor 3", createdAt = time + 2))
|
||||
|
||||
val addressableQuery = Filter(kinds = listOf(version1.kind), authors = listOf(version1.pubKey), tags = mapOf("d" to listOf(version1.dTag())))
|
||||
|
||||
db.insert(version3)
|
||||
|
||||
db.assertQuery(version3, Filter(ids = listOf(version3.id)))
|
||||
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(version2)
|
||||
}
|
||||
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(version1)
|
||||
}
|
||||
|
||||
db.assertQuery(version3, Filter(ids = listOf(version3.id)))
|
||||
db.assertQuery(version3, addressableQuery)
|
||||
db.assertQuery(null, Filter(ids = listOf(version2.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(version1.id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTriggersIndexUsageKind0() =
|
||||
forEachDB { db ->
|
||||
val sql =
|
||||
"""
|
||||
SELECT * FROM event_headers
|
||||
WHERE
|
||||
event_headers.kind = 0 AND
|
||||
event_headers.pubkey = 'aa' AND
|
||||
event_headers.created_at < 1766686500
|
||||
""".trimIndent()
|
||||
|
||||
val explainer = db.store.explainQuery(sql)
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
SELECT * FROM event_headers
|
||||
WHERE
|
||||
event_headers.kind = 0 AND
|
||||
event_headers.pubkey = 'aa' AND
|
||||
event_headers.created_at < 1766686500
|
||||
└── SEARCH event_headers USING INDEX query_by_kind_pubkey_created (kind=? AND pubkey=? AND created_at<?)
|
||||
""".trimIndent(),
|
||||
explainer,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTriggersIndexUsageKind3() =
|
||||
forEachDB { db ->
|
||||
val sql =
|
||||
"""
|
||||
SELECT * FROM event_headers
|
||||
WHERE
|
||||
event_headers.kind = 3 AND
|
||||
event_headers.pubkey = 'aa' AND
|
||||
event_headers.created_at < 1766686500
|
||||
""".trimIndent()
|
||||
|
||||
val explainer = db.store.explainQuery(sql)
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
SELECT * FROM event_headers
|
||||
WHERE
|
||||
event_headers.kind = 3 AND
|
||||
event_headers.pubkey = 'aa' AND
|
||||
event_headers.created_at < 1766686500
|
||||
└── SEARCH event_headers USING INDEX query_by_kind_pubkey_created (kind=? AND pubkey=? AND created_at<?)
|
||||
""".trimIndent(),
|
||||
explainer,
|
||||
)
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import androidx.sqlite.SQLiteException
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync
|
||||
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
|
||||
import com.vitorpamplona.quartz.nip62RequestToVanish.RequestToVanishEvent
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class RightToVanishTest : BaseDBTest() {
|
||||
val signer = NostrSignerSync()
|
||||
|
||||
@Test
|
||||
fun testInsertDeleteEvent() =
|
||||
forEachDB { db ->
|
||||
val time = TimeUtils.now()
|
||||
val note1 = signer.sign(TextNoteEvent.build("test1", createdAt = time))
|
||||
val note2 = signer.sign(TextNoteEvent.build("test2", createdAt = time + 1))
|
||||
val note3 = signer.sign(TextNoteEvent.build("test3", createdAt = time + 2))
|
||||
|
||||
db.insert(note1)
|
||||
db.insert(note2)
|
||||
db.insert(note3)
|
||||
|
||||
db.assertQuery(note1, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(note2, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(note3, Filter(ids = listOf(note3.id)))
|
||||
|
||||
val vanish = signer.sign(RequestToVanishEvent.build("wss://quartz.local", createdAt = time + 2))
|
||||
|
||||
db.insert(vanish)
|
||||
|
||||
db.assertQuery(vanish, Filter(ids = listOf(vanish.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(note3, Filter(ids = listOf(note3.id)))
|
||||
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(note1)
|
||||
}
|
||||
|
||||
db.assertQuery(vanish, Filter(ids = listOf(vanish.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note1.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(note2.id)))
|
||||
db.assertQuery(note3, Filter(ids = listOf(note3.id)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInsertDeleteGiftWrap() =
|
||||
forEachDB { db ->
|
||||
val time = TimeUtils.now()
|
||||
|
||||
val me = NostrSignerSync()
|
||||
val myFriend = NostrSignerSync()
|
||||
|
||||
val note1 = me.sign(TextNoteEvent.build("test1", createdAt = time))
|
||||
val wrap1 = GiftWrapEvent.create(note1, me.pubKey)
|
||||
val wrap2 = GiftWrapEvent.create(note1, myFriend.pubKey)
|
||||
|
||||
db.insert(wrap1)
|
||||
db.insert(wrap2)
|
||||
|
||||
db.assertQuery(wrap1, Filter(ids = listOf(wrap1.id)))
|
||||
db.assertQuery(wrap2, Filter(ids = listOf(wrap2.id)))
|
||||
|
||||
val randomVanishToWrap = signer.sign(RequestToVanishEvent.build("wss://quartz.local", createdAt = time + 2))
|
||||
|
||||
db.insert(randomVanishToWrap)
|
||||
|
||||
db.assertQuery(wrap1, Filter(ids = listOf(wrap1.id)))
|
||||
db.assertQuery(wrap2, Filter(ids = listOf(wrap2.id)))
|
||||
|
||||
val vanish = me.sign(RequestToVanishEvent.build("wss://quartz.local", createdAt = time + 2))
|
||||
|
||||
db.insert(vanish)
|
||||
|
||||
db.assertQuery(vanish, Filter(ids = listOf(vanish.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(wrap1.id)))
|
||||
db.assertQuery(wrap2, Filter(ids = listOf(wrap2.id)))
|
||||
|
||||
// trying to insert again should fail.
|
||||
assertFailsWith<SQLiteException> {
|
||||
db.insert(wrap1)
|
||||
}
|
||||
|
||||
db.assertQuery(vanish, Filter(ids = listOf(vanish.id)))
|
||||
db.assertQuery(null, Filter(ids = listOf(wrap1.id)))
|
||||
db.assertQuery(wrap2, Filter(ids = listOf(wrap2.id)))
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2025 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.nip01Core.store.sqlite
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
||||
import kotlin.test.Test
|
||||
|
||||
class SearchTest : BaseDBTest() {
|
||||
companion object {
|
||||
val profile =
|
||||
MetadataEvent(
|
||||
id = "490d7439e530423f2540d4f2bdb73a0a2935f3df9e1f2a6f699a140c7db311fe",
|
||||
pubKey = "70a9b3c312a6b83e476739bd29d60ca700da1d5b982cbca87b5f3d27d4038d67",
|
||||
createdAt = 1740669816,
|
||||
tags =
|
||||
arrayOf(
|
||||
arrayOf("alt", "User profile for Vitor"),
|
||||
arrayOf("name", "Vitor"),
|
||||
),
|
||||
content = "{\"name\":\"Vitor\"}",
|
||||
sig = "977a6152199f17d103d8d56736ed1b7767054464cf9423d017c01c8cdd2344698f0a5e13da8dff98d01bb1f798837e3b6271e1fd1cac861bb90686f622ae6ef4",
|
||||
)
|
||||
|
||||
val comment =
|
||||
CommentEvent(
|
||||
id = "fecb2ecf61a1433d417a784d10bd1e8ec19a916170a53ca8fb3a15fc666a6592",
|
||||
pubKey = "f8ff11c7a7d3478355d3b4d174e5a473797a906ea4aa61aa9b6bc0652c1ea17a",
|
||||
createdAt = 1747753115,
|
||||
tags =
|
||||
arrayOf(
|
||||
arrayOf("alt", "Reply to geo:drt3n"),
|
||||
arrayOf("I", "geo:drt3n"),
|
||||
arrayOf("I", "geo:drt3"),
|
||||
arrayOf("I", "geo:drt"),
|
||||
arrayOf("I", "geo:dr"),
|
||||
arrayOf("I", "geo:d"),
|
||||
arrayOf("K", "geo"),
|
||||
arrayOf("i", "geo:drt3n"),
|
||||
arrayOf("i", "geo:drt3"),
|
||||
arrayOf("i", "geo:drt"),
|
||||
arrayOf("i", "geo:dr"),
|
||||
arrayOf("i", "geo:d"),
|
||||
arrayOf("k", "geo"),
|
||||
),
|
||||
content = "testing",
|
||||
sig = "12070e663272f1227c639fb834eb2122fc7bb995f4c49e55ebb1dfe2135ef7347d44810bacd2e64fd26b8826fd47d2800ce6c3d3b579bb3afe39088ffd4faa60",
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTagWithSearch() =
|
||||
forEachDB { db ->
|
||||
db.store.insertEvent(comment)
|
||||
db.store.insertEvent(profile)
|
||||
|
||||
db.assertQuery(null, Filter(search = "testing1"))
|
||||
db.assertQuery(comment, Filter(search = "testing"))
|
||||
db.assertQuery(comment, Filter(kinds = listOf(CommentEvent.KIND), search = "testing"))
|
||||
db.assertQuery(null, Filter(kinds = listOf(TextNoteEvent.KIND), search = "testing"))
|
||||
|
||||
db.store.delete(comment.id)
|
||||
|
||||
db.assertQuery(null, Filter(search = "testing"))
|
||||
db.assertQuery(null, Filter(kinds = listOf(CommentEvent.KIND), search = "testing"))
|
||||
|
||||
db.store.insertEvent(comment)
|
||||
|
||||
db.assertQuery(comment, Filter(search = "testing"))
|
||||
db.assertQuery(comment, Filter(kinds = listOf(CommentEvent.KIND), search = "testing"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
{
|
||||
"english": [
|
||||
[
|
||||
"00000000000000000000000000000000",
|
||||
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
|
||||
"c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04"
|
||||
],
|
||||
[
|
||||
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
|
||||
"legal winner thank year wave sausage worth useful legal winner thank yellow",
|
||||
"2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607"
|
||||
],
|
||||
[
|
||||
"80808080808080808080808080808080",
|
||||
"letter advice cage absurd amount doctor acoustic avoid letter advice cage above",
|
||||
"d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8"
|
||||
],
|
||||
[
|
||||
"ffffffffffffffffffffffffffffffff",
|
||||
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong",
|
||||
"ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a13332572917f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069"
|
||||
],
|
||||
[
|
||||
"000000000000000000000000000000000000000000000000",
|
||||
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent",
|
||||
"035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa"
|
||||
],
|
||||
[
|
||||
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
|
||||
"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will",
|
||||
"f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c392d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd"
|
||||
],
|
||||
[
|
||||
"808080808080808080808080808080808080808080808080",
|
||||
"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always",
|
||||
"107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ffb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65"
|
||||
],
|
||||
[
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when",
|
||||
"0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528"
|
||||
],
|
||||
[
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
|
||||
"bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8"
|
||||
],
|
||||
[
|
||||
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
|
||||
"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title",
|
||||
"bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87"
|
||||
],
|
||||
[
|
||||
"8080808080808080808080808080808080808080808080808080808080808080",
|
||||
"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless",
|
||||
"c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f"
|
||||
],
|
||||
[
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote",
|
||||
"dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad"
|
||||
],
|
||||
[
|
||||
"77c2b00716cec7213839159e404db50d",
|
||||
"jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge",
|
||||
"b5b6d0127db1a9d2226af0c3346031d77af31e918dba64287a1b44b8ebf63cdd52676f672a290aae502472cf2d602c051f3e6f18055e84e4c43897fc4e51a6ff"
|
||||
],
|
||||
[
|
||||
"b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b",
|
||||
"renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap",
|
||||
"9248d83e06f4cd98debf5b6f010542760df925ce46cf38a1bdb4e4de7d21f5c39366941c69e1bdbf2966e0f6e6dbece898a0e2f0a4c2b3e640953dfe8b7bbdc5"
|
||||
],
|
||||
[
|
||||
"3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982",
|
||||
"dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic",
|
||||
"ff7f3184df8696d8bef94b6c03114dbee0ef89ff938712301d27ed8336ca89ef9635da20af07d4175f2bf5f3de130f39c9d9e8dd0472489c19b1a020a940da67"
|
||||
],
|
||||
[
|
||||
"0460ef47585604c5660618db2e6a7e7f",
|
||||
"afford alter spike radar gate glance object seek swamp infant panel yellow",
|
||||
"65f93a9f36b6c85cbe634ffc1f99f2b82cbb10b31edc7f087b4f6cb9e976e9faf76ff41f8f27c99afdf38f7a303ba1136ee48a4c1e7fcd3dba7aa876113a36e4"
|
||||
],
|
||||
[
|
||||
"72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f",
|
||||
"indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left",
|
||||
"3bbf9daa0dfad8229786ace5ddb4e00fa98a044ae4c4975ffd5e094dba9e0bb289349dbe2091761f30f382d4e35c4a670ee8ab50758d2c55881be69e327117ba"
|
||||
],
|
||||
[
|
||||
"2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416",
|
||||
"clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste",
|
||||
"fe908f96f46668b2d5b37d82f558c77ed0d69dd0e7e043a5b0511c48c2f1064694a956f86360c93dd04052a8899497ce9e985ebe0c8c52b955e6ae86d4ff4449"
|
||||
],
|
||||
[
|
||||
"eaebabb2383351fd31d703840b32e9e2",
|
||||
"turtle front uncle idea crush write shrug there lottery flower risk shell",
|
||||
"bdfb76a0759f301b0b899a1e3985227e53b3f51e67e3f2a65363caedf3e32fde42a66c404f18d7b05818c95ef3ca1e5146646856c461c073169467511680876c"
|
||||
],
|
||||
[
|
||||
"7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78",
|
||||
"kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment",
|
||||
"ed56ff6c833c07982eb7119a8f48fd363c4a9b1601cd2de736b01045c5eb8ab4f57b079403485d1c4924f0790dc10a971763337cb9f9c62226f64fff26397c79"
|
||||
],
|
||||
[
|
||||
"4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef",
|
||||
"exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top",
|
||||
"095ee6f817b4c2cb30a5a797360a81a40ab0f9a4e25ecd672a3f58a0b5ba0687c096a6b14d2c0deb3bdefce4f61d01ae07417d502429352e27695163f7447a8c"
|
||||
],
|
||||
[
|
||||
"18ab19a9f54a9274f03e5209a2ac8a91",
|
||||
"board flee heavy tunnel powder denial science ski answer betray cargo cat",
|
||||
"6eff1bb21562918509c73cb990260db07c0ce34ff0e3cc4a8cb3276129fbcb300bddfe005831350efd633909f476c45c88253276d9fd0df6ef48609e8bb7dca8"
|
||||
],
|
||||
[
|
||||
"18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4",
|
||||
"board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief",
|
||||
"f84521c777a13b61564234bf8f8b62b3afce27fc4062b51bb5e62bdfecb23864ee6ecf07c1d5a97c0834307c5c852d8ceb88e7c97923c0a3b496bedd4e5f88a9"
|
||||
],
|
||||
[
|
||||
"15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419",
|
||||
"beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut",
|
||||
"b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb86a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd"
|
||||
]
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,664 @@
|
||||
{
|
||||
"v2": {
|
||||
"valid": {
|
||||
"get_conversation_key": [
|
||||
{
|
||||
"sec1": "315e59ff51cb9209768cf7da80791ddcaae56ac9775eb25b6dee1234bc5d2268",
|
||||
"pub2": "c2f9d9948dc8c7c38321e4b85c8558872eafa0641cd269db76848a6073e69133",
|
||||
"conversation_key": "3dfef0ce2a4d80a25e7a328accf73448ef67096f65f79588e358d9a0eb9013f1"
|
||||
},
|
||||
{
|
||||
"sec1": "a1e37752c9fdc1273be53f68c5f74be7c8905728e8de75800b94262f9497c86e",
|
||||
"pub2": "03bb7947065dde12ba991ea045132581d0954f042c84e06d8c00066e23c1a800",
|
||||
"conversation_key": "4d14f36e81b8452128da64fe6f1eae873baae2f444b02c950b90e43553f2178b"
|
||||
},
|
||||
{
|
||||
"sec1": "98a5902fd67518a0c900f0fb62158f278f94a21d6f9d33d30cd3091195500311",
|
||||
"pub2": "aae65c15f98e5e677b5050de82e3aba47a6fe49b3dab7863cf35d9478ba9f7d1",
|
||||
"conversation_key": "9c00b769d5f54d02bf175b7284a1cbd28b6911b06cda6666b2243561ac96bad7"
|
||||
},
|
||||
{
|
||||
"sec1": "86ae5ac8034eb2542ce23ec2f84375655dab7f836836bbd3c54cefe9fdc9c19f",
|
||||
"pub2": "59f90272378089d73f1339710c02e2be6db584e9cdbe86eed3578f0c67c23585",
|
||||
"conversation_key": "19f934aafd3324e8415299b64df42049afaa051c71c98d0aa10e1081f2e3e2ba"
|
||||
},
|
||||
{
|
||||
"sec1": "2528c287fe822421bc0dc4c3615878eb98e8a8c31657616d08b29c00ce209e34",
|
||||
"pub2": "f66ea16104c01a1c532e03f166c5370a22a5505753005a566366097150c6df60",
|
||||
"conversation_key": "c833bbb292956c43366145326d53b955ffb5da4e4998a2d853611841903f5442"
|
||||
},
|
||||
{
|
||||
"sec1": "49808637b2d21129478041813aceb6f2c9d4929cd1303cdaf4fbdbd690905ff2",
|
||||
"pub2": "74d2aab13e97827ea21baf253ad7e39b974bb2498cc747cdb168582a11847b65",
|
||||
"conversation_key": "4bf304d3c8c4608864c0fe03890b90279328cd24a018ffa9eb8f8ccec06b505d"
|
||||
},
|
||||
{
|
||||
"sec1": "af67c382106242c5baabf856efdc0629cc1c5b4061f85b8ceaba52aa7e4b4082",
|
||||
"pub2": "bdaf0001d63e7ec994fad736eab178ee3c2d7cfc925ae29f37d19224486db57b",
|
||||
"conversation_key": "a3a575dd66d45e9379904047ebfb9a7873c471687d0535db00ef2daa24b391db"
|
||||
},
|
||||
{
|
||||
"sec1": "0e44e2d1db3c1717b05ffa0f08d102a09c554a1cbbf678ab158b259a44e682f1",
|
||||
"pub2": "1ffa76c5cc7a836af6914b840483726207cb750889753d7499fb8b76aa8fe0de",
|
||||
"conversation_key": "a39970a667b7f861f100e3827f4adbf6f464e2697686fe1a81aeda817d6b8bdf"
|
||||
},
|
||||
{
|
||||
"sec1": "5fc0070dbd0666dbddc21d788db04050b86ed8b456b080794c2a0c8e33287bb6",
|
||||
"pub2": "31990752f296dd22e146c9e6f152a269d84b241cc95bb3ff8ec341628a54caf0",
|
||||
"conversation_key": "72c21075f4b2349ce01a3e604e02a9ab9f07e35dd07eff746de348b4f3c6365e"
|
||||
},
|
||||
{
|
||||
"sec1": "1b7de0d64d9b12ddbb52ef217a3a7c47c4362ce7ea837d760dad58ab313cba64",
|
||||
"pub2": "24383541dd8083b93d144b431679d70ef4eec10c98fceef1eff08b1d81d4b065",
|
||||
"conversation_key": "dd152a76b44e63d1afd4dfff0785fa07b3e494a9e8401aba31ff925caeb8f5b1"
|
||||
},
|
||||
{
|
||||
"sec1": "df2f560e213ca5fb33b9ecde771c7c0cbd30f1cf43c2c24de54480069d9ab0af",
|
||||
"pub2": "eeea26e552fc8b5e377acaa03e47daa2d7b0c787fac1e0774c9504d9094c430e",
|
||||
"conversation_key": "770519e803b80f411c34aef59c3ca018608842ebf53909c48d35250bd9323af6"
|
||||
},
|
||||
{
|
||||
"sec1": "cffff919fcc07b8003fdc63bc8a00c0f5dc81022c1c927c62c597352190d95b9",
|
||||
"pub2": "eb5c3cca1a968e26684e5b0eb733aecfc844f95a09ac4e126a9e58a4e4902f92",
|
||||
"conversation_key": "46a14ee7e80e439ec75c66f04ad824b53a632b8409a29bbb7c192e43c00bb795"
|
||||
},
|
||||
{
|
||||
"sec1": "64ba5a685e443e881e9094647ddd32db14444bb21aa7986beeba3d1c4673ba0a",
|
||||
"pub2": "50e6a4339fac1f3bf86f2401dd797af43ad45bbf58e0801a7877a3984c77c3c4",
|
||||
"conversation_key": "968b9dbbfcede1664a4ca35a5d3379c064736e87aafbf0b5d114dff710b8a946"
|
||||
},
|
||||
{
|
||||
"sec1": "dd0c31ccce4ec8083f9b75dbf23cc2878e6d1b6baa17713841a2428f69dee91a",
|
||||
"pub2": "b483e84c1339812bed25be55cff959778dfc6edde97ccd9e3649f442472c091b",
|
||||
"conversation_key": "09024503c7bde07eb7865505891c1ea672bf2d9e25e18dd7a7cea6c69bf44b5d"
|
||||
},
|
||||
{
|
||||
"sec1": "af71313b0d95c41e968a172b33ba5ebd19d06cdf8a7a98df80ecf7af4f6f0358",
|
||||
"pub2": "2a5c25266695b461ee2af927a6c44a3c598b8095b0557e9bd7f787067435bc7c",
|
||||
"conversation_key": "fe5155b27c1c4b4e92a933edae23726a04802a7cc354a77ac273c85aa3c97a92"
|
||||
},
|
||||
{
|
||||
"sec1": "6636e8a389f75fe068a03b3edb3ea4a785e2768e3f73f48ffb1fc5e7cb7289dc",
|
||||
"pub2": "514eb2064224b6a5829ea21b6e8f7d3ea15ff8e70e8555010f649eb6e09aec70",
|
||||
"conversation_key": "ff7afacd4d1a6856d37ca5b546890e46e922b508639214991cf8048ddbe9745c"
|
||||
},
|
||||
{
|
||||
"sec1": "94b212f02a3cfb8ad147d52941d3f1dbe1753804458e6645af92c7b2ea791caa",
|
||||
"pub2": "f0cac333231367a04b652a77ab4f8d658b94e86b5a8a0c472c5c7b0d4c6a40cc",
|
||||
"conversation_key": "e292eaf873addfed0a457c6bd16c8effde33d6664265697f69f420ab16f6669b"
|
||||
},
|
||||
{
|
||||
"sec1": "aa61f9734e69ae88e5d4ced5aae881c96f0d7f16cca603d3bed9eec391136da6",
|
||||
"pub2": "4303e5360a884c360221de8606b72dd316da49a37fe51e17ada4f35f671620a6",
|
||||
"conversation_key": "8e7d44fd4767456df1fb61f134092a52fcd6836ebab3b00766e16732683ed848"
|
||||
},
|
||||
{
|
||||
"sec1": "5e914bdac54f3f8e2cba94ee898b33240019297b69e96e70c8a495943a72fc98",
|
||||
"pub2": "5bd097924f606695c59f18ff8fd53c174adbafaaa71b3c0b4144a3e0a474b198",
|
||||
"conversation_key": "f5a0aecf2984bf923c8cd5e7bb8be262d1a8353cb93959434b943a07cf5644bc"
|
||||
},
|
||||
{
|
||||
"sec1": "8b275067add6312ddee064bcdbeb9d17e88aa1df36f430b2cea5cc0413d8278a",
|
||||
"pub2": "65bbbfca819c90c7579f7a82b750a18c858db1afbec8f35b3c1e0e7b5588e9b8",
|
||||
"conversation_key": "2c565e7027eb46038c2263563d7af681697107e975e9914b799d425effd248d6"
|
||||
},
|
||||
{
|
||||
"sec1": "1ac848de312285f85e0f7ec208aac20142a1f453402af9b34ec2ec7a1f9c96fc",
|
||||
"pub2": "45f7318fe96034d23ee3ddc25b77f275cc1dd329664dd51b89f89c4963868e41",
|
||||
"conversation_key": "b56e970e5057a8fd929f8aad9248176b9af87819a708d9ddd56e41d1aec74088"
|
||||
},
|
||||
{
|
||||
"sec1": "295a1cf621de401783d29d0e89036aa1c62d13d9ad307161b4ceb535ba1b40e6",
|
||||
"pub2": "840115ddc7f1034d3b21d8e2103f6cb5ab0b63cf613f4ea6e61ae3d016715cdd",
|
||||
"conversation_key": "b4ee9c0b9b9fef88975773394f0a6f981ca016076143a1bb575b9ff46e804753"
|
||||
},
|
||||
{
|
||||
"sec1": "a28eed0fe977893856ab9667e06ace39f03abbcdb845c329a1981be438ba565d",
|
||||
"pub2": "b0f38b950a5013eba5ab4237f9ed29204a59f3625c71b7e210fec565edfa288c",
|
||||
"conversation_key": "9d3a802b45bc5aeeb3b303e8e18a92ddd353375710a31600d7f5fff8f3a7285b"
|
||||
},
|
||||
{
|
||||
"sec1": "7ab65af72a478c05f5c651bdc4876c74b63d20d04cdbf71741e46978797cd5a4",
|
||||
"pub2": "f1112159161b568a9cb8c9dd6430b526c4204bcc8ce07464b0845b04c041beda",
|
||||
"conversation_key": "943884cddaca5a3fef355e9e7f08a3019b0b66aa63ec90278b0f9fdb64821e79"
|
||||
},
|
||||
{
|
||||
"sec1": "95c79a7b75ba40f2229e85756884c138916f9d103fc8f18acc0877a7cceac9fe",
|
||||
"pub2": "cad76bcbd31ca7bbda184d20cc42f725ed0bb105b13580c41330e03023f0ffb3",
|
||||
"conversation_key": "81c0832a669eea13b4247c40be51ccfd15bb63fcd1bba5b4530ce0e2632f301b"
|
||||
},
|
||||
{
|
||||
"sec1": "baf55cc2febd4d980b4b393972dfc1acf49541e336b56d33d429bce44fa12ec9",
|
||||
"pub2": "0c31cf87fe565766089b64b39460ebbfdedd4a2bc8379be73ad3c0718c912e18",
|
||||
"conversation_key": "37e2344da9ecdf60ae2205d81e89d34b280b0a3f111171af7e4391ded93b8ea6"
|
||||
},
|
||||
{
|
||||
"sec1": "6eeec45acd2ed31693c5256026abf9f072f01c4abb61f51cf64e6956b6dc8907",
|
||||
"pub2": "e501b34ed11f13d816748c0369b0c728e540df3755bab59ed3327339e16ff828",
|
||||
"conversation_key": "afaa141b522ddb27bb880d768903a7f618bb8b6357728cae7fb03af639b946e6"
|
||||
},
|
||||
{
|
||||
"sec1": "261a076a9702af1647fb343c55b3f9a4f1096273002287df0015ba81ce5294df",
|
||||
"pub2": "b2777c863878893ae100fb740c8fab4bebd2bf7be78c761a75593670380a6112",
|
||||
"conversation_key": "76f8d2853de0734e51189ced523c09427c3e46338b9522cd6f74ef5e5b475c74"
|
||||
},
|
||||
{
|
||||
"sec1": "ed3ec71ca406552ea41faec53e19f44b8f90575eda4b7e96380f9cc73c26d6f3",
|
||||
"pub2": "86425951e61f94b62e20cae24184b42e8e17afcf55bafa58645efd0172624fae",
|
||||
"conversation_key": "f7ffc520a3a0e9e9b3c0967325c9bf12707f8e7a03f28b6cd69ae92cf33f7036"
|
||||
},
|
||||
{
|
||||
"sec1": "5a788fc43378d1303ac78639c59a58cb88b08b3859df33193e63a5a3801c722e",
|
||||
"pub2": "a8cba2f87657d229db69bee07850fd6f7a2ed070171a06d006ec3a8ac562cf70",
|
||||
"conversation_key": "7d705a27feeedf78b5c07283362f8e361760d3e9f78adab83e3ae5ce7aeb6409"
|
||||
},
|
||||
{
|
||||
"sec1": "63bffa986e382b0ac8ccc1aa93d18a7aa445116478be6f2453bad1f2d3af2344",
|
||||
"pub2": "b895c70a83e782c1cf84af558d1038e6b211c6f84ede60408f519a293201031d",
|
||||
"conversation_key": "3a3b8f00d4987fc6711d9be64d9c59cf9a709c6c6481c2cde404bcc7a28f174e"
|
||||
},
|
||||
{
|
||||
"sec1": "e4a8bcacbf445fd3721792b939ff58e691cdcba6a8ba67ac3467b45567a03e5c",
|
||||
"pub2": "b54053189e8c9252c6950059c783edb10675d06d20c7b342f73ec9fa6ed39c9d",
|
||||
"conversation_key": "7b3933b4ef8189d347169c7955589fc1cfc01da5239591a08a183ff6694c44ad"
|
||||
},
|
||||
{
|
||||
"sec1": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364139",
|
||||
"pub2": "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"conversation_key": "8b6392dbf2ec6a2b2d5b1477fc2be84d63ef254b667cadd31bd3f444c44ae6ba",
|
||||
"note": "sec1 = n-2, pub2: random, 0x02"
|
||||
},
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"pub2": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdeb",
|
||||
"conversation_key": "be234f46f60a250bef52a5ee34c758800c4ca8e5030bf4cc1a31d37ba2104d43",
|
||||
"note": "sec1 = 2, pub2: rand"
|
||||
},
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"pub2": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
||||
"conversation_key": "3b4610cb7189beb9cc29eb3716ecc6102f1247e8f3101a03a1787d8908aeb54e",
|
||||
"note": "sec1 == pub2"
|
||||
}
|
||||
],
|
||||
"get_message_keys": {
|
||||
"conversation_key": "a1a3d60f3470a8612633924e91febf96dc5366ce130f658b1f0fc652c20b3b54",
|
||||
"keys": [
|
||||
{
|
||||
"nonce": "e1e6f880560d6d149ed83dcc7e5861ee62a5ee051f7fde9975fe5d25d2a02d72",
|
||||
"chacha_key": "f145f3bed47cb70dbeaac07f3a3fe683e822b3715edb7c4fe310829014ce7d76",
|
||||
"chacha_nonce": "c4ad129bb01180c0933a160c",
|
||||
"hmac_key": "027c1db445f05e2eee864a0975b0ddef5b7110583c8c192de3732571ca5838c4"
|
||||
},
|
||||
{
|
||||
"nonce": "e1d6d28c46de60168b43d79dacc519698512ec35e8ccb12640fc8e9f26121101",
|
||||
"chacha_key": "e35b88f8d4a8f1606c5082f7a64b100e5d85fcdb2e62aeafbec03fb9e860ad92",
|
||||
"chacha_nonce": "22925e920cee4a50a478be90",
|
||||
"hmac_key": "46a7c55d4283cb0df1d5e29540be67abfe709e3b2e14b7bf9976e6df994ded30"
|
||||
},
|
||||
{
|
||||
"nonce": "cfc13bef512ac9c15951ab00030dfaf2626fdca638dedb35f2993a9eeb85d650",
|
||||
"chacha_key": "020783eb35fdf5b80ef8c75377f4e937efb26bcbad0e61b4190e39939860c4bf",
|
||||
"chacha_nonce": "d3594987af769a52904656ac",
|
||||
"hmac_key": "237ec0ccb6ebd53d179fa8fd319e092acff599ef174c1fdafd499ef2b8dee745"
|
||||
},
|
||||
{
|
||||
"nonce": "ea6eb84cac23c5c1607c334e8bdf66f7977a7e374052327ec28c6906cbe25967",
|
||||
"chacha_key": "ff68db24b34fa62c78ac5ffeeaf19533afaedf651fb6a08384e46787f6ce94be",
|
||||
"chacha_nonce": "50bb859aa2dde938cc49ec7a",
|
||||
"hmac_key": "06ff32e1f7b29753a727d7927b25c2dd175aca47751462d37a2039023ec6b5a6"
|
||||
},
|
||||
{
|
||||
"nonce": "8c2e1dd3792802f1f9f7842e0323e5d52ad7472daf360f26e15f97290173605d",
|
||||
"chacha_key": "2f9daeda8683fdeede81adac247c63cc7671fa817a1fd47352e95d9487989d8b",
|
||||
"chacha_nonce": "400224ba67fc2f1b76736916",
|
||||
"hmac_key": "465c05302aeeb514e41c13ed6405297e261048cfb75a6f851ffa5b445b746e4b"
|
||||
},
|
||||
{
|
||||
"nonce": "05c28bf3d834fa4af8143bf5201a856fa5fac1a3aee58f4c93a764fc2f722367",
|
||||
"chacha_key": "1e3d45777025a035be566d80fd580def73ed6f7c043faec2c8c1c690ad31c110",
|
||||
"chacha_nonce": "021905b1ea3afc17cb9bf96f",
|
||||
"hmac_key": "74a6e481a89dcd130aaeb21060d7ec97ad30f0007d2cae7b1b11256cc70dfb81"
|
||||
},
|
||||
{
|
||||
"nonce": "5e043fb153227866e75a06d60185851bc90273bfb93342f6632a728e18a07a17",
|
||||
"chacha_key": "1ea72c9293841e7737c71567d8120145a58991aaa1c436ef77bf7adb83f882f1",
|
||||
"chacha_nonce": "72f69a5a5f795465cee59da8",
|
||||
"hmac_key": "e9daa1a1e9a266ecaa14e970a84bce3fbbf329079bbccda626582b4e66a0d4c9"
|
||||
},
|
||||
{
|
||||
"nonce": "7be7338eaf06a87e274244847fe7a97f5c6a91f44adc18fcc3e411ad6f786dbf",
|
||||
"chacha_key": "881e7968a1f0c2c80742ee03cd49ea587e13f22699730f1075ade01931582bf6",
|
||||
"chacha_nonce": "6e69be92d61c04a276021565",
|
||||
"hmac_key": "901afe79e74b19967c8829af23617d7d0ffbf1b57190c096855c6a03523a971b"
|
||||
},
|
||||
{
|
||||
"nonce": "94571c8d590905bad7becd892832b472f2aa5212894b6ce96e5ba719c178d976",
|
||||
"chacha_key": "f80873dd48466cb12d46364a97b8705c01b9b4230cb3ec3415a6b9551dc42eef",
|
||||
"chacha_nonce": "3dda53569cfcb7fac1805c35",
|
||||
"hmac_key": "e9fc264345e2839a181affebc27d2f528756e66a5f87b04bf6c5f1997047051e"
|
||||
},
|
||||
{
|
||||
"nonce": "13a6ee974b1fd759135a2c2010e3cdda47081c78e771125e4f0c382f0284a8cb",
|
||||
"chacha_key": "bc5fb403b0bed0d84cf1db872b6522072aece00363178c98ad52178d805fca85",
|
||||
"chacha_nonce": "65064239186e50304cc0f156",
|
||||
"hmac_key": "e872d320dde4ed3487958a8e43b48aabd3ced92bc24bb8ff1ccb57b590d9701a"
|
||||
},
|
||||
{
|
||||
"nonce": "082fecdb85f358367b049b08be0e82627ae1d8edb0f27327ccb593aa2613b814",
|
||||
"chacha_key": "1fbdb1cf6f6ea816349baf697932b36107803de98fcd805ebe9849b8ad0e6a45",
|
||||
"chacha_nonce": "2e605e1d825a3eaeb613db9c",
|
||||
"hmac_key": "fae910f591cf3c7eb538c598583abad33bc0a03085a96ca4ea3a08baf17c0eec"
|
||||
},
|
||||
{
|
||||
"nonce": "4c19020c74932c30ec6b2d8cd0d5bb80bd0fc87da3d8b4859d2fb003810afd03",
|
||||
"chacha_key": "1ab9905a0189e01cda82f843d226a82a03c4f5b6dbea9b22eb9bc953ba1370d4",
|
||||
"chacha_nonce": "cbb2530ea653766e5a37a83a",
|
||||
"hmac_key": "267f68acac01ac7b34b675e36c2cef5e7b7a6b697214add62a491bedd6efc178"
|
||||
},
|
||||
{
|
||||
"nonce": "67723a3381497b149ce24814eddd10c4c41a1e37e75af161930e6b9601afd0ff",
|
||||
"chacha_key": "9ecbd25e7e2e6c97b8c27d376dcc8c5679da96578557e4e21dba3a7ef4e4ac07",
|
||||
"chacha_nonce": "ef649fcf335583e8d45e3c2e",
|
||||
"hmac_key": "04dbbd812fa8226fdb45924c521a62e3d40a9e2b5806c1501efdeba75b006bf1"
|
||||
},
|
||||
{
|
||||
"nonce": "42063fe80b093e8619b1610972b4c3ab9e76c14fd908e642cd4997cafb30f36c",
|
||||
"chacha_key": "211c66531bbcc0efcdd0130f9f1ebc12a769105eb39608994bcb188fa6a73a4a",
|
||||
"chacha_nonce": "67803605a7e5010d0f63f8c8",
|
||||
"hmac_key": "e840e4e8921b57647369d121c5a19310648105dbdd008200ebf0d3b668704ff8"
|
||||
},
|
||||
{
|
||||
"nonce": "b5ac382a4be7ac03b554fe5f3043577b47ea2cd7cfc7e9ca010b1ffbb5cf1a58",
|
||||
"chacha_key": "b3b5f14f10074244ee42a3837a54309f33981c7232a8b16921e815e1f7d1bb77",
|
||||
"chacha_nonce": "4e62a0073087ed808be62469",
|
||||
"hmac_key": "c8efa10230b5ea11633816c1230ca05fa602ace80a7598916d83bae3d3d2ccd7"
|
||||
},
|
||||
{
|
||||
"nonce": "e9d1eba47dd7e6c1532dc782ff63125db83042bb32841db7eeafd528f3ea7af9",
|
||||
"chacha_key": "54241f68dc2e50e1db79e892c7c7a471856beeb8d51b7f4d16f16ab0645d2f1a",
|
||||
"chacha_nonce": "a963ed7dc29b7b1046820a1d",
|
||||
"hmac_key": "aba215c8634530dc21c70ddb3b3ee4291e0fa5fa79be0f85863747bde281c8b2"
|
||||
},
|
||||
{
|
||||
"nonce": "a94ecf8efeee9d7068de730fad8daf96694acb70901d762de39fa8a5039c3c49",
|
||||
"chacha_key": "c0565e9e201d2381a2368d7ffe60f555223874610d3d91fbbdf3076f7b1374dd",
|
||||
"chacha_nonce": "329bb3024461e84b2e1c489b",
|
||||
"hmac_key": "ac42445491f092481ce4fa33b1f2274700032db64e3a15014fbe8c28550f2fec"
|
||||
},
|
||||
{
|
||||
"nonce": "533605ea214e70c25e9a22f792f4b78b9f83a18ab2103687c8a0075919eaaa53",
|
||||
"chacha_key": "ab35a5e1e54d693ff023db8500d8d4e79ad8878c744e0eaec691e96e141d2325",
|
||||
"chacha_nonce": "653d759042b85194d4d8c0a7",
|
||||
"hmac_key": "b43628e37ba3c31ce80576f0a1f26d3a7c9361d29bb227433b66f49d44f167ba"
|
||||
},
|
||||
{
|
||||
"nonce": "7f38df30ceea1577cb60b355b4f5567ff4130c49e84fed34d779b764a9cc184c",
|
||||
"chacha_key": "a37d7f211b84a551a127ff40908974eb78415395d4f6f40324428e850e8c42a3",
|
||||
"chacha_nonce": "b822e2c959df32b3cb772a7c",
|
||||
"hmac_key": "1ba31764f01f69b5c89ded2d7c95828e8052c55f5d36f1cd535510d61ba77420"
|
||||
},
|
||||
{
|
||||
"nonce": "11b37f9dbc4d0185d1c26d5f4ed98637d7c9701fffa65a65839fa4126573a4e5",
|
||||
"chacha_key": "964f38d3a31158a5bfd28481247b18dd6e44d69f30ba2a40f6120c6d21d8a6ba",
|
||||
"chacha_nonce": "5f72c5b87c590bcd0f93b305",
|
||||
"hmac_key": "2fc4553e7cedc47f29690439890f9f19c1077ef3e9eaeef473d0711e04448918"
|
||||
},
|
||||
{
|
||||
"nonce": "8be790aa483d4cdd843189f71f135b3ec7e31f381312c8fe9f177aab2a48eafa",
|
||||
"chacha_key": "95c8c74d633721a131316309cf6daf0804d59eaa90ea998fc35bac3d2fbb7a94",
|
||||
"chacha_nonce": "409a7654c0e4bf8c2c6489be",
|
||||
"hmac_key": "21bb0b06eb2b460f8ab075f497efa9a01c9cf9146f1e3986c3bf9da5689b6dc4"
|
||||
},
|
||||
{
|
||||
"nonce": "19fd2a718ea084827d6bd73f509229ddf856732108b59fc01819f611419fd140",
|
||||
"chacha_key": "cc6714b9f5616c66143424e1413d520dae03b1a4bd202b82b0a89b0727f5cdc8",
|
||||
"chacha_nonce": "1b7fd2534f015a8f795d8f32",
|
||||
"hmac_key": "2bef39c4ce5c3c59b817e86351373d1554c98bc131c7e461ed19d96cfd6399a0"
|
||||
},
|
||||
{
|
||||
"nonce": "3c2acd893952b2f6d07d8aea76f545ca45961a93fe5757f6a5a80811d5e0255d",
|
||||
"chacha_key": "c8de6c878cb469278d0af894bc181deb6194053f73da5014c2b5d2c8db6f2056",
|
||||
"chacha_nonce": "6ffe4f1971b904a1b1a81b99",
|
||||
"hmac_key": "df1cd69dd3646fca15594284744d4211d70e7d8472e545d276421fbb79559fd4"
|
||||
},
|
||||
{
|
||||
"nonce": "7dbea4cead9ac91d4137f1c0a6eebb6ba0d1fb2cc46d829fbc75f8d86aca6301",
|
||||
"chacha_key": "c8e030f6aa680c3d0b597da9c92bb77c21c4285dd620c5889f9beba7446446b0",
|
||||
"chacha_nonce": "a9b5a67d081d3b42e737d16f",
|
||||
"hmac_key": "355a85f551bc3cce9a14461aa60994742c9bbb1c81a59ca102dc64e61726ab8e"
|
||||
},
|
||||
{
|
||||
"nonce": "45422e676cdae5f1071d3647d7a5f1f5adafb832668a578228aa1155a491f2f3",
|
||||
"chacha_key": "758437245f03a88e2c6a32807edfabff51a91c81ca2f389b0b46f2c97119ea90",
|
||||
"chacha_nonce": "263830a065af33d9c6c5aa1f",
|
||||
"hmac_key": "7c581cf3489e2de203a95106bfc0de3d4032e9d5b92b2b61fb444acd99037e17"
|
||||
},
|
||||
{
|
||||
"nonce": "babc0c03fad24107ad60678751f5db2678041ff0d28671ede8d65bdf7aa407e9",
|
||||
"chacha_key": "bd68a28bd48d9ffa3602db72c75662ac2848a0047a313d2ae2d6bc1ac153d7e9",
|
||||
"chacha_nonce": "d0f9d2a1ace6c758f594ffdd",
|
||||
"hmac_key": "eb435e3a642adfc9d59813051606fc21f81641afd58ea6641e2f5a9f123bb50a"
|
||||
},
|
||||
{
|
||||
"nonce": "7a1b8aac37d0d20b160291fad124ab697cfca53f82e326d78fef89b4b0ea8f83",
|
||||
"chacha_key": "9e97875b651a1d30d17d086d1e846778b7faad6fcbc12e08b3365d700f62e4fe",
|
||||
"chacha_nonce": "ccdaad5b3b7645be430992eb",
|
||||
"hmac_key": "6f2f55cf35174d75752f63c06cc7cbc8441759b142999ed2d5a6d09d263e1fc4"
|
||||
},
|
||||
{
|
||||
"nonce": "8370e4e32d7e680a83862cab0da6136ef607014d043e64cdf5ecc0c4e20b3d9a",
|
||||
"chacha_key": "1472bed5d19db9c546106de946e0649cd83cc9d4a66b087a65906e348dcf92e2",
|
||||
"chacha_nonce": "ed02dece5fc3a186f123420b",
|
||||
"hmac_key": "7b3f7739f49d30c6205a46b174f984bb6a9fc38e5ccfacef2dac04fcbd3b184e"
|
||||
},
|
||||
{
|
||||
"nonce": "9f1c5e8a29cd5677513c2e3a816551d6833ee54991eb3f00d5b68096fc8f0183",
|
||||
"chacha_key": "5e1a7544e4d4dafe55941fcbdf326f19b0ca37fc49c4d47e9eec7fb68cde4975",
|
||||
"chacha_nonce": "7d9acb0fdc174e3c220f40de",
|
||||
"hmac_key": "e265ab116fbbb86b2aefc089a0986a0f5b77eda50c7410404ad3b4f3f385c7a7"
|
||||
},
|
||||
{
|
||||
"nonce": "c385aa1c37c2bfd5cc35fcdbdf601034d39195e1cabff664ceb2b787c15d0225",
|
||||
"chacha_key": "06bf4e60677a13e54c4a38ab824d2ef79da22b690da2b82d0aa3e39a14ca7bdd",
|
||||
"chacha_nonce": "26b450612ca5e905b937e147",
|
||||
"hmac_key": "22208152be2b1f5f75e6bfcc1f87763d48bb7a74da1be3d102096f257207f8b3"
|
||||
},
|
||||
{
|
||||
"nonce": "3ff73528f88a50f9d35c0ddba4560bacee5b0462d0f4cb6e91caf41847040ce4",
|
||||
"chacha_key": "850c8a17a23aa761d279d9901015b2bbdfdff00adbf6bc5cf22bd44d24ecabc9",
|
||||
"chacha_nonce": "4a296a1fb0048e5020d3b129",
|
||||
"hmac_key": "b1bf49a533c4da9b1d629b7ff30882e12d37d49c19abd7b01b7807d75ee13806"
|
||||
},
|
||||
{
|
||||
"nonce": "2dcf39b9d4c52f1cb9db2d516c43a7c6c3b8c401f6a4ac8f131a9e1059957036",
|
||||
"chacha_key": "17f8057e6156ba7cc5310d01eda8c40f9aa388f9fd1712deb9511f13ecc37d27",
|
||||
"chacha_nonce": "a8188daff807a1182200b39d",
|
||||
"hmac_key": "47b89da97f68d389867b5d8a2d7ba55715a30e3d88a3cc11f3646bc2af5580ef"
|
||||
}
|
||||
]
|
||||
},
|
||||
"calc_padded_len": [
|
||||
[16, 32],
|
||||
[32, 32],
|
||||
[33, 64],
|
||||
[37, 64],
|
||||
[45, 64],
|
||||
[49, 64],
|
||||
[64, 64],
|
||||
[65, 96],
|
||||
[100, 128],
|
||||
[111, 128],
|
||||
[200, 224],
|
||||
[250, 256],
|
||||
[320, 320],
|
||||
[383, 384],
|
||||
[384, 384],
|
||||
[400, 448],
|
||||
[500, 512],
|
||||
[512, 512],
|
||||
[515, 640],
|
||||
[700, 768],
|
||||
[800, 896],
|
||||
[900, 1024],
|
||||
[1020, 1024],
|
||||
[65536, 65536]
|
||||
],
|
||||
"encrypt_decrypt": [
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"sec2": "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"conversation_key": "c41c775356fd92eadc63ff5a0dc1da211b268cbea22316767095b2871ea1412d",
|
||||
"nonce": "0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"plaintext": "a",
|
||||
"payload": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABee0G5VSK0/9YypIObAtDKfYEAjD35uVkHyB0F4DwrcNaCXlCWZKaArsGrY6M9wnuTMxWfp1RTN9Xga8no+kF5Vsb"
|
||||
},
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"sec2": "0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"conversation_key": "c41c775356fd92eadc63ff5a0dc1da211b268cbea22316767095b2871ea1412d",
|
||||
"nonce": "f00000000000000000000000000000f00000000000000000000000000000000f",
|
||||
"plaintext": "🍕🫃",
|
||||
"payload": "AvAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAPSKSK6is9ngkX2+cSq85Th16oRTISAOfhStnixqZziKMDvB0QQzgFZdjLTPicCJaV8nDITO+QfaQ61+KbWQIOO2Yj"
|
||||
},
|
||||
{
|
||||
"sec1": "5c0c523f52a5b6fad39ed2403092df8cebc36318b39383bca6c00808626fab3a",
|
||||
"sec2": "4b22aa260e4acb7021e32f38a6cdf4b673c6a277755bfce287e370c924dc936d",
|
||||
"conversation_key": "3e2b52a63be47d34fe0a80e34e73d436d6963bc8f39827f327057a9986c20a45",
|
||||
"nonce": "b635236c42db20f021bb8d1cdff5ca75dd1a0cc72ea742ad750f33010b24f73b",
|
||||
"plaintext": "表ポあA鷗ŒéB逍Üߪąñ丂㐀𠀀",
|
||||
"payload": "ArY1I2xC2yDwIbuNHN/1ynXdGgzHLqdCrXUPMwELJPc7s7JqlCMJBAIIjfkpHReBPXeoMCyuClwgbT419jUWU1PwaNl4FEQYKCDKVJz+97Mp3K+Q2YGa77B6gpxB/lr1QgoqpDf7wDVrDmOqGoiPjWDqy8KzLueKDcm9BVP8xeTJIxs="
|
||||
},
|
||||
{
|
||||
"sec1": "8f40e50a84a7462e2b8d24c28898ef1f23359fff50d8c509e6fb7ce06e142f9c",
|
||||
"sec2": "b9b0a1e9cc20100c5faa3bbe2777303d25950616c4c6a3fa2e3e046f936ec2ba",
|
||||
"conversation_key": "d5a2f879123145a4b291d767428870f5a8d9e5007193321795b40183d4ab8c2b",
|
||||
"nonce": "b20989adc3ddc41cd2c435952c0d59a91315d8c5218d5040573fc3749543acaf",
|
||||
"plaintext": "ability🤝的 ȺȾ",
|
||||
"payload": "ArIJia3D3cQc0sQ1lSwNWakTFdjFIY1QQFc/w3SVQ6yvbG2S0x4Yu86QGwPTy7mP3961I1XqB6SFFTzqDZZavhxoWMj7mEVGMQIsh2RLWI5EYQaQDIePSnXPlzf7CIt+voTD"
|
||||
},
|
||||
{
|
||||
"sec1": "875adb475056aec0b4809bd2db9aa00cff53a649e7b59d8edcbf4e6330b0995c",
|
||||
"sec2": "9c05781112d5b0a2a7148a222e50e0bd891d6b60c5483f03456e982185944aae",
|
||||
"conversation_key": "3b15c977e20bfe4b8482991274635edd94f366595b1a3d2993515705ca3cedb8",
|
||||
"nonce": "8d4442713eb9d4791175cb040d98d6fc5be8864d6ec2f89cf0895a2b2b72d1b1",
|
||||
"plaintext": "pepper👀їжак",
|
||||
"payload": "Ao1EQnE+udR5EXXLBA2Y1vxb6IZNbsL4nPCJWisrctGxY3AduCS+jTUgAAnfvKafkmpy15+i9YMwCdccisRa8SvzW671T2JO4LFSPX31K4kYUKelSAdSPwe9NwO6LhOsnoJ+"
|
||||
},
|
||||
{
|
||||
"sec1": "eba1687cab6a3101bfc68fd70f214aa4cc059e9ec1b79fdb9ad0a0a4e259829f",
|
||||
"sec2": "dff20d262bef9dfd94666548f556393085e6ea421c8af86e9d333fa8747e94b3",
|
||||
"conversation_key": "4f1538411098cf11c8af216836444787c462d47f97287f46cf7edb2c4915b8a5",
|
||||
"nonce": "2180b52ae645fcf9f5080d81b1f0b5d6f2cd77ff3c986882bb549158462f3407",
|
||||
"plaintext": "( ͡° ͜ʖ ͡°)",
|
||||
"payload": "AiGAtSrmRfz59QgNgbHwtdbyzXf/PJhogrtUkVhGLzQHv4qhKQwnFQ54OjVMgqCea/Vj0YqBSdhqNR777TJ4zIUk7R0fnizp6l1zwgzWv7+ee6u+0/89KIjY5q1wu6inyuiv"
|
||||
},
|
||||
{
|
||||
"sec1": "d5633530f5bcfebceb5584cfbbf718a30df0751b729dd9a789b9f30c0587d74e",
|
||||
"sec2": "b74e6a341fb134127272b795a08b59250e5fa45a82a2eb4095e4ce9ed5f5e214",
|
||||
"conversation_key": "75fe686d21a035f0c7cd70da64ba307936e5ca0b20710496a6b6b5f573377bdd",
|
||||
"nonce": "e4cd5f7ce4eea024bc71b17ad456a986a74ac426c2c62b0a15eb5c5c8f888b68",
|
||||
"plaintext": "مُنَاقَشَةُ سُبُلِ اِسْتِخْدَامِ اللُّغَةِ فِي النُّظُمِ الْقَائِمَةِ وَفِيم يَخُصَّ التَّطْبِيقَاتُ الْحاسُوبِيَّةُ،",
|
||||
"payload": "AuTNX3zk7qAkvHGxetRWqYanSsQmwsYrChXrXFyPiItoIBsWu1CB+sStla2M4VeANASHxM78i1CfHQQH1YbBy24Tng7emYW44ol6QkFD6D8Zq7QPl+8L1c47lx8RoODEQMvNCbOk5ffUV3/AhONHBXnffrI+0025c+uRGzfqpYki4lBqm9iYU+k3Tvjczq9wU0mkVDEaM34WiQi30MfkJdRbeeYaq6kNvGPunLb3xdjjs5DL720d61Flc5ZfoZm+CBhADy9D9XiVZYLKAlkijALJur9dATYKci6OBOoc2SJS2Clai5hOVzR0yVeyHRgRfH9aLSlWW5dXcUxTo7qqRjNf8W5+J4jF4gNQp5f5d0YA4vPAzjBwSP/5bGzNDslKfcAH"
|
||||
},
|
||||
{
|
||||
"sec1": "d5633530f5bcfebceb5584cfbbf718a30df0751b729dd9a789b9f30c0587d74e",
|
||||
"sec2": "b74e6a341fb134127272b795a08b59250e5fa45a82a2eb4095e4ce9ed5f5e214",
|
||||
"conversation_key": "75fe686d21a035f0c7cd70da64ba307936e5ca0b20710496a6b6b5f573377bdd",
|
||||
"nonce": "38d1ca0abef9e5f564e89761a86cee04574b6825d3ef2063b10ad75899e4b023",
|
||||
"plaintext": "الكل في المجمو عة (5)",
|
||||
"payload": "AjjRygq++eX1ZOiXYahs7gRXS2gl0+8gY7EK11iZ5LAjbOTrlfrxak5Lki42v2jMPpLSicy8eHjsWkkMtF0i925vOaKG/ZkMHh9ccQBdfTvgEGKzztedqDCAWb5TP1YwU1PsWaiiqG3+WgVvJiO4lUdMHXL7+zKKx8bgDtowzz4QAwI="
|
||||
},
|
||||
{
|
||||
"sec1": "d5633530f5bcfebceb5584cfbbf718a30df0751b729dd9a789b9f30c0587d74e",
|
||||
"sec2": "b74e6a341fb134127272b795a08b59250e5fa45a82a2eb4095e4ce9ed5f5e214",
|
||||
"conversation_key": "75fe686d21a035f0c7cd70da64ba307936e5ca0b20710496a6b6b5f573377bdd",
|
||||
"nonce": "4f1a31909f3483a9e69c8549a55bbc9af25fa5bbecf7bd32d9896f83ef2e12e0",
|
||||
"plaintext": "𝖑𝖆𝖟𝖞 社會科學院語學研究所",
|
||||
"payload": "Ak8aMZCfNIOp5pyFSaVbvJryX6W77Pe9MtmJb4PvLhLgh/TsxPLFSANcT67EC1t/qxjru5ZoADjKVEt2ejdx+xGvH49mcdfbc+l+L7gJtkH7GLKpE9pQNQWNHMAmj043PAXJZ++fiJObMRR2mye5VHEANzZWkZXMrXF7YjuG10S1pOU="
|
||||
},
|
||||
{
|
||||
"sec1": "d5633530f5bcfebceb5584cfbbf718a30df0751b729dd9a789b9f30c0587d74e",
|
||||
"sec2": "b74e6a341fb134127272b795a08b59250e5fa45a82a2eb4095e4ce9ed5f5e214",
|
||||
"conversation_key": "75fe686d21a035f0c7cd70da64ba307936e5ca0b20710496a6b6b5f573377bdd",
|
||||
"nonce": "a3e219242d85465e70adcd640b564b3feff57d2ef8745d5e7a0663b2dccceb54",
|
||||
"plaintext": "🙈 🙉 🙊 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 Powerلُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ冗",
|
||||
"payload": "AqPiGSQthUZecK3NZAtWSz/v9X0u+HRdXnoGY7LczOtUf05aMF89q1FLwJvaFJYICZoMYgRJHFLwPiOHce7fuAc40kX0wXJvipyBJ9HzCOj7CgtnC1/cmPCHR3s5AIORmroBWglm1LiFMohv1FSPEbaBD51VXxJa4JyWpYhreSOEjn1wd0lMKC9b+osV2N2tpbs+rbpQem2tRen3sWflmCqjkG5VOVwRErCuXuPb5+hYwd8BoZbfCrsiAVLd7YT44dRtKNBx6rkabWfddKSLtreHLDysOhQUVOp/XkE7OzSkWl6sky0Hva6qJJ/V726hMlomvcLHjE41iKmW2CpcZfOedg=="
|
||||
}
|
||||
],
|
||||
"encrypt_decrypt_long_msg": [
|
||||
{
|
||||
"conversation_key": "8fc262099ce0d0bb9b89bac05bb9e04f9bc0090acc181fef6840ccee470371ed",
|
||||
"nonce": "326bcb2c943cd6bb717588c9e5a7e738edf6ed14ec5f5344caa6ef56f0b9cff7",
|
||||
"pattern": "x",
|
||||
"repeat": 65535,
|
||||
"plaintext_sha256": "09ab7495d3e61a76f0deb12cb0306f0696cbb17ffc12131368c7a939f12f56d3",
|
||||
"payload_sha256": "90714492225faba06310bff2f249ebdc2a5e609d65a629f1c87f2d4ffc55330a"
|
||||
},
|
||||
{
|
||||
"conversation_key": "56adbe3720339363ab9c3b8526ffce9fd77600927488bfc4b59f7a68ffe5eae0",
|
||||
"nonce": "ad68da81833c2a8ff609c3d2c0335fd44fe5954f85bb580c6a8d467aa9fc5dd0",
|
||||
"pattern": "!",
|
||||
"repeat": 65535,
|
||||
"plaintext_sha256": "6af297793b72ae092c422e552c3bb3cbc310da274bd1cf9e31023a7fe4a2d75e",
|
||||
"payload_sha256": "8013e45a109fad3362133132b460a2d5bce235fe71c8b8f4014793fb52a49844"
|
||||
},
|
||||
{
|
||||
"conversation_key": "7fc540779979e472bb8d12480b443d1e5eb1098eae546ef2390bee499bbf46be",
|
||||
"nonce": "34905e82105c20de9a2f6cd385a0d541e6bcc10601d12481ff3a7575dc622033",
|
||||
"pattern": "🦄",
|
||||
"repeat": 16383,
|
||||
"plaintext_sha256": "a249558d161b77297bc0cb311dde7d77190f6571b25c7e4429cd19044634a61f",
|
||||
"payload_sha256": "b3348422471da1f3c59d79acfe2fe103f3cd24488109e5b18734cdb5953afd15"
|
||||
},
|
||||
{
|
||||
"conversation_key": "56adbe3720339363ab9c3b8526ffce9fd77600927488bfc4b59f7a68ffe5eae0",
|
||||
"nonce": "ad68da81833c2a8ff609c3d2c0335fd44fe5954f85bb580c6a8d467aa9fc5dd0",
|
||||
"pattern": "!",
|
||||
"repeat": 65536,
|
||||
"plaintext_sha256": "b007fe445ff5b583c095c4688c75d8afef66d4c93eb6aeebcea0942e670e1cd3",
|
||||
"payload_sha256": "f816ffbcb053a0669488992e2d7c57c2d950d3d4af6e19a16297f3e565a4103f"
|
||||
},
|
||||
{
|
||||
"conversation_key": "56adbe3720339363ab9c3b8526ffce9fd77600927488bfc4b59f7a68ffe5eae0",
|
||||
"nonce": "ad68da81833c2a8ff609c3d2c0335fd44fe5954f85bb580c6a8d467aa9fc5dd0",
|
||||
"pattern": "a",
|
||||
"repeat": 20000000,
|
||||
"plaintext_sha256": "aded0ea9b4d06589b13d00bab483faf479d61ed5de21f1760aa7018a28e330e5",
|
||||
"payload_sha256": "9e683311894d52e48a825837883c539263c7787c7fe024e1590d96776a31684b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"invalid": {
|
||||
"encrypt_msg_lengths": [0, 65536, 100000, 10000000],
|
||||
"get_conversation_key": [
|
||||
{
|
||||
"sec1": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"pub2": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
"note": "sec1 higher than curve.n"
|
||||
},
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"pub2": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
"note": "sec1 is 0"
|
||||
},
|
||||
{
|
||||
"sec1": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364139",
|
||||
"pub2": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"note": "pub2 is invalid, no sqrt, all-ff"
|
||||
},
|
||||
{
|
||||
"sec1": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
|
||||
"pub2": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
"note": "sec1 == curve.n"
|
||||
},
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"pub2": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
"note": "pub2 is invalid, no sqrt"
|
||||
},
|
||||
{
|
||||
"sec1": "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20",
|
||||
"pub2": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"note": "pub2 is point of order 3 on twist"
|
||||
},
|
||||
{
|
||||
"sec1": "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20",
|
||||
"pub2": "eb1f7200aecaa86682376fb1c13cd12b732221e774f553b0a0857f88fa20f86d",
|
||||
"note": "pub2 is point of order 13 on twist"
|
||||
},
|
||||
{
|
||||
"sec1": "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20",
|
||||
"pub2": "709858a4c121e4a84eb59c0ded0261093c71e8ca29efeef21a6161c447bcaf9f",
|
||||
"note": "pub2 is point of order 3319 on twist"
|
||||
}
|
||||
],
|
||||
"decrypt": [
|
||||
{
|
||||
"conversation_key": "ca2527a037347b91bea0c8a30fc8d9600ffd81ec00038671e3a0f0cb0fc9f642",
|
||||
"nonce": "daaea5ca345b268e5b62060ca72c870c48f713bc1e00ff3fc0ddb78e826f10db",
|
||||
"plaintext": "n o b l e",
|
||||
"payload": "#Atqupco0WyaOW2IGDKcshwxI9xO8HgD/P8Ddt46CbxDbrhdG8VmJdU0MIDf06CUvEvdnr1cp1fiMtlM/GrE92xAc1K5odTpCzUB+mjXgbaqtntBUbTToSUoT0ovrlPwzGjyp",
|
||||
"note": "unknown encryption version"
|
||||
},
|
||||
{
|
||||
"conversation_key": "36f04e558af246352dcf73b692fbd3646a2207bd8abd4b1cd26b234db84d9481",
|
||||
"nonce": "ad408d4be8616dc84bb0bf046454a2a102edac937c35209c43cd7964c5feb781",
|
||||
"plaintext": "⚠️",
|
||||
"payload": "AK1AjUvoYW3IS7C/BGRUoqEC7ayTfDUgnEPNeWTF/reBZFaha6EAIRueE9D1B1RuoiuFScC0Q94yjIuxZD3JStQtE8JMNacWFs9rlYP+ZydtHhRucp+lxfdvFlaGV/sQlqZz",
|
||||
"note": "unknown encryption version 0"
|
||||
},
|
||||
{
|
||||
"conversation_key": "ca2527a037347b91bea0c8a30fc8d9600ffd81ec00038671e3a0f0cb0fc9f642",
|
||||
"nonce": "daaea5ca345b268e5b62060ca72c870c48f713bc1e00ff3fc0ddb78e826f10db",
|
||||
"plaintext": "n o s t r",
|
||||
"payload": "Atфupco0WyaOW2IGDKcshwxI9xO8HgD/P8Ddt46CbxDbrhdG8VmJZE0UICD06CUvEvdnr1cp1fiMtlM/GrE92xAc1EwsVCQEgWEu2gsHUVf4JAa3TpgkmFc3TWsax0v6n/Wq",
|
||||
"note": "invalid base64"
|
||||
},
|
||||
{
|
||||
"conversation_key": "cff7bd6a3e29a450fd27f6c125d5edeb0987c475fd1e8d97591e0d4d8a89763c",
|
||||
"nonce": "09ff97750b084012e15ecb84614ce88180d7b8ec0d468508a86b6d70c0361a25",
|
||||
"plaintext": "¯\\_(ツ)_/¯",
|
||||
"payload": "Agn/l3ULCEAS4V7LhGFM6IGA17jsDUaFCKhrbXDANholyySBfeh+EN8wNB9gaLlg4j6wdBYh+3oK+mnxWu3NKRbSvQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||
"note": "invalid MAC"
|
||||
},
|
||||
{
|
||||
"conversation_key": "cfcc9cf682dfb00b11357f65bdc45e29156b69db424d20b3596919074f5bf957",
|
||||
"nonce": "65b14b0b949aaa7d52c417eb753b390e8ad6d84b23af4bec6d9bfa3e03a08af4",
|
||||
"plaintext": "🥎",
|
||||
"payload": "AmWxSwuUmqp9UsQX63U7OQ6K1thLI69L7G2b+j4DoIr0oRWQ8avl4OLqWZiTJ10vIgKrNqjoaX+fNhE9RqmR5g0f6BtUg1ijFMz71MO1D4lQLQfW7+UHva8PGYgQ1QpHlKgR",
|
||||
"note": "invalid MAC"
|
||||
},
|
||||
{
|
||||
"conversation_key": "5254827d29177622d40a7b67cad014fe7137700c3c523903ebbe3e1b74d40214",
|
||||
"nonce": "7ab65dbb8bbc2b8e35cafb5745314e1f050325a864d11d0475ef75b3660d91c1",
|
||||
"plaintext": "elliptic-curve cryptography",
|
||||
"payload": "Anq2XbuLvCuONcr7V0UxTh8FAyWoZNEdBHXvdbNmDZHB573MI7R7rrTYftpqmvUpahmBC2sngmI14/L0HjOZ7lWGJlzdh6luiOnGPc46cGxf08MRC4CIuxx3i2Lm0KqgJ7vA",
|
||||
"note": "invalid padding"
|
||||
},
|
||||
{
|
||||
"conversation_key": "fea39aca9aa8340c3a78ae1f0902aa7e726946e4efcd7783379df8096029c496",
|
||||
"nonce": "7d4283e3b54c885d6afee881f48e62f0a3f5d7a9e1cb71ccab594a7882c39330",
|
||||
"plaintext": "noble",
|
||||
"payload": "An1Cg+O1TIhdav7ogfSOYvCj9dep4ctxzKtZSniCw5MwRrrPJFyAQYZh5VpjC2QYzny5LIQ9v9lhqmZR4WBYRNJ0ognHVNMwiFV1SHpvUFT8HHZN/m/QarflbvDHAtO6pY16",
|
||||
"note": "invalid padding"
|
||||
},
|
||||
{
|
||||
"conversation_key": "0c4cffb7a6f7e706ec94b2e879f1fc54ff8de38d8db87e11787694d5392d5b3f",
|
||||
"nonce": "6f9fd72667c273acd23ca6653711a708434474dd9eb15c3edb01ce9a95743e9b",
|
||||
"plaintext": "censorship-resistant and global social network",
|
||||
"payload": "Am+f1yZnwnOs0jymZTcRpwhDRHTdnrFcPtsBzpqVdD6b2NZDaNm/TPkZGr75kbB6tCSoq7YRcbPiNfJXNch3Tf+o9+zZTMxwjgX/nm3yDKR2kHQMBhVleCB9uPuljl40AJ8kXRD0gjw+aYRJFUMK9gCETZAjjmrsCM+nGRZ1FfNsHr6Z",
|
||||
"note": "invalid padding"
|
||||
},
|
||||
{
|
||||
"conversation_key": "5cd2d13b9e355aeb2452afbd3786870dbeecb9d355b12cb0a3b6e9da5744cd35",
|
||||
"nonce": "b60036976a1ada277b948fd4caa065304b96964742b89d26f26a25263a5060bd",
|
||||
"plaintext": "0",
|
||||
"payload": "",
|
||||
"note": "invalid payload length: 0"
|
||||
},
|
||||
{
|
||||
"conversation_key": "d61d3f09c7dfe1c0be91af7109b60a7d9d498920c90cbba1e137320fdd938853",
|
||||
"nonce": "1a29d02c8b4527745a2ccb38bfa45655deb37bc338ab9289d756354cea1fd07c",
|
||||
"plaintext": "1",
|
||||
"payload": "Ag==",
|
||||
"note": "invalid payload length: 4"
|
||||
},
|
||||
{
|
||||
"conversation_key": "873bb0fc665eb950a8e7d5971965539f6ebd645c83c08cd6a85aafbad0f0bc47",
|
||||
"nonce": "c826d3c38e765ab8cc42060116cd1464b2a6ce01d33deba5dedfb48615306d4a",
|
||||
"plaintext": "2",
|
||||
"payload": "AqxgToSh3H7iLYRJjoWAM+vSv/Y1mgNlm6OWWjOYUClrFF8=",
|
||||
"note": "invalid payload length: 48"
|
||||
},
|
||||
{
|
||||
"conversation_key": "9f2fef8f5401ac33f74641b568a7a30bb19409c76ffdc5eae2db6b39d2617fbe",
|
||||
"nonce": "9ff6484642545221624eaac7b9ea27133a4cc2356682a6033aceeef043549861",
|
||||
"plaintext": "3",
|
||||
"payload": "Ap/2SEZCVFIhYk6qx7nqJxM6TMI1ZoKmAzrO7vBDVJhhuZXWiM20i/tIsbjT0KxkJs2MZjh1oXNYMO9ggfk7i47WQA==",
|
||||
"note": "invalid payload length: 92"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Reference in New Issue
Block a user