rearranges the crypto package into separate nips and reduces the amount of circular dependencies.

This commit is contained in:
Vitor Pamplona
2024-06-25 12:13:17 -04:00
parent 79ace7f18c
commit a8a2bda9af
34 changed files with 468 additions and 461 deletions
@@ -43,7 +43,7 @@ class CryptoUtilsTest {
val publicKey = "765cd7cf91d3ad07423d114d5a39c61d52b2cdbc18ba055ddbbeec71fbe2aa2f"
val key =
CryptoUtils.getSharedSecretNIP44v1(
CryptoUtils.nip44.v1.getSharedSecret(
privateKey = privateKey.hexToByteArray(),
pubKey = publicKey.hexToByteArray(),
)
@@ -56,8 +56,8 @@ class CryptoUtilsTest {
val sender = KeyPair()
val receiver = KeyPair()
val sharedSecret1 = CryptoUtils.getSharedSecretNIP44v1(sender.privKey!!, receiver.pubKey)
val sharedSecret2 = CryptoUtils.getSharedSecretNIP44v1(receiver.privKey!!, sender.pubKey)
val sharedSecret1 = CryptoUtils.nip44.v1.getSharedSecret(sender.privKey!!, receiver.pubKey)
val sharedSecret2 = CryptoUtils.nip44.v1.getSharedSecret(receiver.privKey!!, sender.pubKey)
assertEquals(sharedSecret1.toHexKey(), sharedSecret2.toHexKey())
@@ -88,8 +88,8 @@ class CryptoUtilsTest {
val privateKey = CryptoUtils.privkeyCreate()
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
val encrypted = CryptoUtils.encryptNIP44v1(msg, privateKey, publicKey)
val decrypted = CryptoUtils.decryptNIP44v1(encrypted, privateKey, publicKey)
val encrypted = CryptoUtils.nip44.v1.encrypt(msg, privateKey, publicKey)
val decrypted = CryptoUtils.nip44.v1.decrypt(encrypted, privateKey, publicKey)
assertEquals(msg, decrypted)
}
@@ -113,10 +113,10 @@ class CryptoUtilsTest {
val privateKey = CryptoUtils.privkeyCreate()
val publicKey = CryptoUtils.pubkeyCreate(privateKey)
val sharedSecret = CryptoUtils.getSharedSecretNIP44v1(privateKey, publicKey)
val sharedSecret = CryptoUtils.nip44.v1.getSharedSecret(privateKey, publicKey)
val encrypted = CryptoUtils.encryptNIP44v1(msg, sharedSecret)
val decrypted = CryptoUtils.decryptNIP44v1(encrypted, sharedSecret)
val encrypted = CryptoUtils.nip44.v1.encrypt(msg, sharedSecret)
val decrypted = CryptoUtils.nip44.v1.decrypt(encrypted, sharedSecret)
assertEquals(msg, decrypted)
}
@@ -22,42 +22,45 @@ package com.vitorpamplona.quartz.crypto.nip06
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.encoders.toHexKey
import fr.acinq.secp256k1.Secp256k1
import junit.framework.TestCase.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class Bip32SeedDerivationTest {
val seedDerivation = Bip32SeedDerivation(Secp256k1.get())
val masterBitcoin =
Bip32SeedDerivation.generate(
seedDerivation.generate(
Bip39Mnemonics.toSeed("gun please vital unable phone catalog explain raise erosion zoo truly exist", ""),
)
val nostrMnemonic0 =
Bip32SeedDerivation.generate(
seedDerivation.generate(
Bip39Mnemonics.toSeed("leader monkey parrot ring guide accident before fence cannon height naive bean", ""),
)
val nostrMnemonic1 =
Bip32SeedDerivation.generate(
seedDerivation.generate(
Bip39Mnemonics.toSeed("what bleak badge arrange retreat wolf trade produce cricket blur garlic valid proud rude strong choose busy staff weather area salt hollow arm fade", ""),
)
@Test
fun restoreBIP44Wallet() {
val privateKey = Bip32SeedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/44'/1'/0'"))
val privateKey = seedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/44'/1'/0'"))
assertEquals("50b3e7905c642309c8a8b73df5a49757a10f2bebb5804571b9db9004cce8a190", privateKey.toHexKey())
}
@Test
fun restoreBIP49Wallet() {
val privateKey = Bip32SeedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/49'/1'/0'"))
val privateKey = seedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/49'/1'/0'"))
assertEquals("154c02c0b66899291a19012207642ba096a2d3ebf51baf153c9495976feb1b30", privateKey.toHexKey())
}
@Test
fun restoreBIP84Wallet() {
val privateKey = Bip32SeedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/84'/1'/0'"))
val privateKey = seedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/84'/1'/0'"))
assertEquals("53e8c09a0e3ddcd8d68821c1e99e823966e99df91fb253e1f453a443ba543cb2", privateKey.toHexKey())
}
@@ -22,6 +22,7 @@ package com.vitorpamplona.quartz.crypto.nip06
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.encoders.toHexKey
import fr.acinq.secp256k1.Secp256k1
import junit.framework.TestCase.assertEquals
import org.junit.Ignore
import org.junit.Test
@@ -29,6 +30,8 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class Nip06Test {
val nip06 = Nip06(Secp256k1.get())
// private key (hex): 7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a
// nsec: nsec10allq0gjx7fddtzef0ax00mdps9t2kmtrldkyjfs8l5xruwvh2dq0lhhkp
private val menemonic0 = "leader monkey parrot ring guide accident before fence cannon height naive bean"
@@ -43,26 +46,26 @@ class Nip06Test {
@Test
fun fromSeedNip06TestVector0() {
val privateKeyHex = Nip06().privateKeyFromMnemonic(menemonic0).toHexKey()
val privateKeyHex = nip06.privateKeyFromMnemonic(menemonic0).toHexKey()
assertEquals("7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a", privateKeyHex)
val privateKeyHex21 = Nip06().privateKeyFromMnemonic(menemonic0, 21).toHexKey()
val privateKeyHex21 = nip06.privateKeyFromMnemonic(menemonic0, 21).toHexKey()
assertEquals("576390ec69951fcfbf159f2aac0965bb2e6d7a07da2334992af3225c57eaefca", privateKeyHex21)
}
@Test
fun fromSeedNip06TestVector1() {
val privateKeyHex = Nip06().privateKeyFromMnemonic(menemonic1).toHexKey()
val privateKeyHex = nip06.privateKeyFromMnemonic(menemonic1).toHexKey()
assertEquals("c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add", privateKeyHex)
val privateKeyHex21 = Nip06().privateKeyFromMnemonic(menemonic1, 42).toHexKey()
val privateKeyHex21 = nip06.privateKeyFromMnemonic(menemonic1, 42).toHexKey()
assertEquals("ad993054383da74e955f8b86346365b5ffd6575992e1de3738dda9f94407052b", privateKeyHex21)
}
@Test
@Ignore("Snort is not correctly implemented")
fun fromSeedNip06FromSnort() {
val privateKeyNsec = Nip06().privateKeyFromMnemonic(snortTest).toHexKey()
val privateKeyNsec = nip06.privateKeyFromMnemonic(snortTest).toHexKey()
assertEquals("nsec1ppw9ltr2x9qwg9a2qnmgv98tfruy2ejnja7me76mwmsreu3s8u2sscj5nt", privateKeyNsec)
}
}
@@ -18,12 +18,13 @@
* 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.crypto
package com.vitorpamplona.quartz.crypto.nip44
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.vitorpamplona.quartz.crypto.KeyPair
import com.vitorpamplona.quartz.encoders.hexToByteArray
import com.vitorpamplona.quartz.encoders.toHexKey
import fr.acinq.secp256k1.Secp256k1
@@ -79,8 +80,7 @@ class NIP44v2Test {
v.plaintext!!,
conversationKey1,
v.nonce!!.hexToByteArray(),
)
.encodePayload()
).encodePayload()
assertEquals(v.payload, ciphertext)
@@ -107,8 +107,7 @@ class NIP44v2Test {
plaintext,
conversationKey,
v.nonce!!.hexToByteArray(),
)
.encodePayload()
).encodePayload()
assertEquals(v.payloadSha256, sha256Hex(ciphertext.toByteArray(Charsets.UTF_8)))
@@ -18,7 +18,7 @@
* 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.crypto
package com.vitorpamplona.quartz.crypto.nip49
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.encoders.toHexKey
@@ -18,7 +18,7 @@
* 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
package com.vitorpamplona.quartz.encoders
import com.vitorpamplona.quartz.crypto.CryptoUtils
import org.junit.Assert.assertEquals
@@ -31,8 +31,8 @@ class HexEncodingTest {
fun testHexEncodeDecodeOurs() {
assertEquals(
testHex,
com.vitorpamplona.quartz.encoders.Hex.encode(
com.vitorpamplona.quartz.encoders.Hex.decode(testHex),
Hex.encode(
Hex.decode(testHex),
),
)
}
@@ -42,7 +42,8 @@ class HexEncodingTest {
assertEquals(
testHex,
fr.acinq.secp256k1.Hex.encode(
fr.acinq.secp256k1.Hex.decode(testHex),
fr.acinq.secp256k1.Hex
.decode(testHex),
),
)
}
@@ -51,14 +52,17 @@ class HexEncodingTest {
fun testRandoms() {
for (i in 0..1000) {
val bytes = CryptoUtils.privkeyCreate()
val hex = fr.acinq.secp256k1.Hex.encode(bytes)
val hex =
fr.acinq.secp256k1.Hex
.encode(bytes)
assertEquals(
fr.acinq.secp256k1.Hex.encode(bytes),
com.vitorpamplona.quartz.encoders.Hex.encode(bytes),
fr.acinq.secp256k1.Hex
.encode(bytes),
Hex.encode(bytes),
)
assertEquals(
bytes.toList(),
com.vitorpamplona.quartz.encoders.Hex.decode(hex).toList(),
Hex.decode(hex).toList(),
)
}
}
@@ -18,10 +18,9 @@
* 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
package com.vitorpamplona.quartz.encoders
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.encoders.LnInvoiceUtil
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
@@ -18,14 +18,10 @@
* 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
package com.vitorpamplona.quartz.encoders
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.crypto.KeyPair
import com.vitorpamplona.quartz.encoders.Hex
import com.vitorpamplona.quartz.encoders.Nip19Bech32
import com.vitorpamplona.quartz.encoders.decodePrivateKeyAsHexOrNull
import com.vitorpamplona.quartz.encoders.hexToByteArray
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.FhirResourceEvent
import com.vitorpamplona.quartz.events.TextNoteEvent
@@ -18,10 +18,9 @@
* 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
package com.vitorpamplona.quartz.events
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.events.ChatroomKey
import kotlinx.collections.immutable.persistentSetOf
import org.junit.Assert.assertEquals
import org.junit.Test
@@ -18,11 +18,9 @@
* 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
package com.vitorpamplona.quartz.events
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.TextNoteEvent
import junit.framework.TestCase.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@@ -18,10 +18,9 @@
* 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
package com.vitorpamplona.quartz.events
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.events.Event
import org.junit.Test
import org.junit.runner.RunWith
@@ -18,18 +18,13 @@
* 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
package com.vitorpamplona.quartz.events
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.crypto.KeyPair
import com.vitorpamplona.quartz.encoders.Hex
import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.encoders.hexToByteArray
import com.vitorpamplona.quartz.events.ChatMessageEvent
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.GiftWrapEvent
import com.vitorpamplona.quartz.events.NIP17Factory
import com.vitorpamplona.quartz.events.SealedGossipEvent
import com.vitorpamplona.quartz.signers.NostrSignerInternal
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
@@ -276,14 +271,12 @@ class GiftWrapEventTest {
assertTrue(unwrappedMsgForReceiverByReceiver is SealedGossipEvent)
if (unwrappedMsgForReceiverByReceiver is SealedGossipEvent) {
unwrappedMsgForReceiverByReceiver.cachedGossip(receiver) {
unwrappedGossipToReceiverByReceiver ->
unwrappedMsgForReceiverByReceiver.cachedGossip(receiver) { unwrappedGossipToReceiverByReceiver ->
assertEquals("Hi There!", unwrappedGossipToReceiverByReceiver?.content)
countDownDecryptLatch.countDown()
}
unwrappedMsgForReceiverByReceiver.cachedGossip(sender) { unwrappedGossipToReceiverBySender,
->
unwrappedMsgForReceiverByReceiver.cachedGossip(sender) { unwrappedGossipToReceiverBySender ->
fail(
"Should not be able to decrypt msg for the receiver by the receiver but decrypted with the sender",
)
@@ -422,13 +415,11 @@ class GiftWrapEventTest {
assertEquals(SealedGossipEvent.KIND, unwrappedMsgForSenderBySender.kind)
if (unwrappedMsgForSenderBySender is SealedGossipEvent) {
unwrappedMsgForSenderBySender.cachedGossip(receiverA) { unwrappedGossipToSenderByReceiverA,
->
unwrappedMsgForSenderBySender.cachedGossip(receiverA) { unwrappedGossipToSenderByReceiverA ->
fail()
}
unwrappedMsgForSenderBySender.cachedGossip(receiverB) { unwrappedGossipToSenderByReceiverB,
->
unwrappedMsgForSenderBySender.cachedGossip(receiverB) { unwrappedGossipToSenderByReceiverB ->
fail()
}
@@ -459,21 +450,18 @@ class GiftWrapEventTest {
assertEquals(SealedGossipEvent.KIND, unwrappedMsgForReceiverAByReceiverA.kind)
if (unwrappedMsgForReceiverAByReceiverA is SealedGossipEvent) {
unwrappedMsgForReceiverAByReceiverA.cachedGossip(receiverA) {
unwrappedGossipToReceiverAByReceiverA ->
unwrappedMsgForReceiverAByReceiverA.cachedGossip(receiverA) { unwrappedGossipToReceiverAByReceiverA ->
assertEquals(
"Who is going to the party tonight?",
unwrappedGossipToReceiverAByReceiverA.content,
)
}
unwrappedMsgForReceiverAByReceiverA.cachedGossip(sender) {
unwrappedGossipToReceiverABySender ->
unwrappedMsgForReceiverAByReceiverA.cachedGossip(sender) { unwrappedGossipToReceiverABySender ->
fail()
}
unwrappedMsgForReceiverAByReceiverA.cachedGossip(receiverB) {
unwrappedGossipToReceiverAByReceiverB ->
unwrappedMsgForReceiverAByReceiverA.cachedGossip(receiverB) { unwrappedGossipToReceiverAByReceiverB ->
fail()
}
}
@@ -495,13 +483,11 @@ class GiftWrapEventTest {
assertEquals(SealedGossipEvent.KIND, unwrappedMsgForReceiverBByReceiverB.kind)
if (unwrappedMsgForReceiverBByReceiverB is SealedGossipEvent) {
unwrappedMsgForReceiverBByReceiverB.cachedGossip(receiverA) {
unwrappedGossipToReceiverBByReceiverA ->
unwrappedMsgForReceiverBByReceiverB.cachedGossip(receiverA) { unwrappedGossipToReceiverBByReceiverA ->
fail()
}
unwrappedMsgForReceiverBByReceiverB.cachedGossip(receiverB) {
unwrappedGossipToReceiverBByReceiverB ->
unwrappedMsgForReceiverBByReceiverB.cachedGossip(receiverB) { unwrappedGossipToReceiverBByReceiverB ->
assertEquals(
"Who is going to the party tonight?",
unwrappedGossipToReceiverBByReceiverB.content,
@@ -510,8 +496,7 @@ class GiftWrapEventTest {
countDownDecryptLatch.countDown()
}
unwrappedMsgForReceiverBByReceiverB.cachedGossip(sender) {
unwrappedGossipToReceiverBBySender ->
unwrappedMsgForReceiverBByReceiverB.cachedGossip(sender) { unwrappedGossipToReceiverBBySender ->
fail()
}
}
@@ -538,8 +523,7 @@ class GiftWrapEventTest {
]
]
}
"""
.trimIndent()
""".trimIndent()
var gossip: Event? = null
@@ -573,8 +557,7 @@ class GiftWrapEventTest {
]
]
}
"""
.trimIndent()
""".trimIndent()
val privateKey = "409ff7654141eaa16cd2161fe5bd127aeaef71f270c67587474b78998a8e3533"
@@ -612,8 +595,7 @@ class GiftWrapEventTest {
"wss://relay.damus.io/"
]
}
"""
.trimIndent()
""".trimIndent()
val privateKey = "09e0051fdf5fdd9dd7a54713583006442cbdbf87bdcdab1a402f26e527d56771"
var gossip: Event? = null
@@ -647,8 +629,7 @@ class GiftWrapEventTest {
]
]
}
"""
.trimIndent()
""".trimIndent()
val privateKey = "09e0051fdf5fdd9dd7a54713583006442cbdbf87bdcdab1a402f26e527d56771"
@@ -687,8 +668,7 @@ class GiftWrapEventTest {
"id": "d9fc85ece892ce45ffa737b3ddc0f8b752623181d75363b966191f8c03d2debe",
"sig": "1b20416b83f4b5b8eead11e29c185f46b5e76d1960e4505210ddd00f7a6973cc11268f52a8989e3799b774d5f3a55db95bed4d66a1b6e88ab54becec5c771c17"
}
"""
.trimIndent()
""".trimIndent()
val privateKey = "7dd22cafc512c0bc363a259f6dcda515b13ae3351066d7976fd0bb79cbd0d700"
@@ -753,8 +733,7 @@ class GiftWrapEventTest {
"id": "ae625fd43612127d63bfd1967ba32ae915100842a205fc2c3b3fc02ab3827f08",
"sig": "2807a7ab5728984144676fd34686267cbe6fe38bc2f65a3640ba9243c13e8a1ae5a9a051e8852aa0c997a3623d7fa066cf2073a233c6d7db46fb1a0d4c01e5a3"
}
"""
.trimIndent()
""".trimIndent()
val wrap = Event.fromJson(msg) as GiftWrapEvent
wrap.checkSignature()
@@ -18,15 +18,12 @@
* 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
package com.vitorpamplona.quartz.events
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.crypto.KeyPair
import com.vitorpamplona.quartz.encoders.Hex
import com.vitorpamplona.quartz.encoders.toHexKey
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.LnZapEvent
import com.vitorpamplona.quartz.events.LnZapRequestEvent
import com.vitorpamplona.quartz.events.LnZapRequestEvent.Companion.createEncryptionPrivateKey
import com.vitorpamplona.quartz.signers.NostrSignerInternal
import junit.framework.TestCase.assertNotNull
@@ -18,7 +18,7 @@
* 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
package com.vitorpamplona.quartz.ots
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.crypto.KeyPair