Foundations(iOS Sourceset): Provide implementation for MacInstance(using external library). Bring some tests into commonTest to make sure it works.

This commit is contained in:
KotlinGeekDev
2026-02-09 21:57:54 +01:00
parent aa4d586025
commit dcb10b249a
5 changed files with 185 additions and 10 deletions
+1
View File
@@ -253,6 +253,7 @@ kotlin {
implementation(libs.charlietap.cachemap)
implementation(libs.net.thauvin.erik.urlencoder.lib)
implementation(libs.com.ditchoom.buffer.compression)
implementation(libs.dev.whyoleg.cryptography.provider.apple)
}
}
@@ -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 nip06KeyDerivationCommon
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
import com.vitorpamplona.quartz.nip06KeyDerivation.Bip32SeedDerivation
import com.vitorpamplona.quartz.nip06KeyDerivation.Bip39Mnemonics
import com.vitorpamplona.quartz.nip06KeyDerivation.KeyPath
import kotlin.test.Test
import kotlin.test.assertEquals
class Bip32SeedDerivationCommonTest {
val seedDerivation = Bip32SeedDerivation()
val masterBitcoin =
seedDerivation.generate(
Bip39Mnemonics.toSeed("gun please vital unable phone catalog explain raise erosion zoo truly exist", ""),
)
val nostrMnemonic0 =
seedDerivation.generate(
Bip39Mnemonics.toSeed("leader monkey parrot ring guide accident before fence cannon height naive bean", ""),
)
val nostrMnemonic1 =
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 = seedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/44'/1'/0'"))
assertEquals("50b3e7905c642309c8a8b73df5a49757a10f2bebb5804571b9db9004cce8a190", privateKey.toHexKey())
}
@Test
fun restoreBIP49Wallet() {
val privateKey = seedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/49'/1'/0'"))
assertEquals("154c02c0b66899291a19012207642ba096a2d3ebf51baf153c9495976feb1b30", privateKey.toHexKey())
}
@Test
fun restoreBIP84Wallet() {
val privateKey = seedDerivation.derivePrivateKey(masterBitcoin, KeyPath("m/84'/1'/0'"))
assertEquals("53e8c09a0e3ddcd8d68821c1e99e823966e99df91fb253e1f453a443ba543cb2", privateKey.toHexKey())
}
@Test
fun testGenerateMasterKeyForNostrMnemonics0() {
assertEquals(
"dbbcc0e112894d1430d5bc348d1bd72e8ac339952702be1fe572de80fe1b7fcb",
nostrMnemonic0.secretkeybytes.toHexKey(),
)
}
@Test
fun testGenerateMasterKeyForNostrMnemonics1() {
assertEquals(
"d58d40d5724435552fa442350b75e0ff95a19d990e908e3a516bcc88f780108f",
nostrMnemonic1.secretkeybytes.toHexKey(),
)
}
}
@@ -0,0 +1,68 @@
/**
* 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 nip06KeyDerivationCommon
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
import com.vitorpamplona.quartz.nip06KeyDerivation.Nip06
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals
class Nip06CommonTest {
val nip06 = Nip06()
// private key (hex): 7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a
// nsec: nsec10allq0gjx7fddtzef0ax00mdps9t2kmtrldkyjfs8l5xruwvh2dq0lhhkp
private val menemonic0 = "leader monkey parrot ring guide accident before fence cannon height naive bean"
// private key (hex): c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add
// nsec: nsec1c9wh8xy5eqdzln7n5t0ctgxjcrdug73gp5yj0x03gntn67h83twssdfhel
private val menemonic1 = "what bleak badge arrange retreat wolf trade produce cricket blur garlic valid proud rude strong choose busy staff weather area salt hollow arm fade"
// private key (hex): c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add
// nsec: nsec1c9wh8xy5eqdzln7n5t0ctgxjcrdug73gp5yj0x03gntn67h83twssdfhel
private val snortTest = "clog remember sample endorse mountain key rib hurry question supreme palm future stage style swing faith erase thumb then warm truth mule vivid endless"
@Test
fun fromSeedNip06TestVector0() {
val privateKeyHex = nip06.privateKeyFromMnemonic(menemonic0).toHexKey()
assertEquals("7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a", privateKeyHex)
val privateKeyHex21 = nip06.privateKeyFromMnemonic(menemonic0, 21).toHexKey()
assertEquals("576390ec69951fcfbf159f2aac0965bb2e6d7a07da2334992af3225c57eaefca", privateKeyHex21)
}
@Test
fun fromSeedNip06TestVector1() {
val privateKeyHex = nip06.privateKeyFromMnemonic(menemonic1).toHexKey()
assertEquals("c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add", privateKeyHex)
val privateKeyHex21 = nip06.privateKeyFromMnemonic(menemonic1, 42).toHexKey()
assertEquals("ad993054383da74e955f8b86346365b5ffd6575992e1de3738dda9f94407052b", privateKeyHex21)
}
@Test
@Ignore()
fun fromSeedNip06FromSnort() {
val privateKeyNsec = nip06.privateKeyFromMnemonic(snortTest).toHexKey()
assertEquals("nsec1ppw9ltr2x9qwg9a2qnmgv98tfruy2ejnja7me76mwmsreu3s8u2sscj5nt", privateKeyNsec)
}
}
@@ -20,37 +20,60 @@
*/
package com.vitorpamplona.quartz.utils.mac
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.algorithms.HMAC
import dev.whyoleg.cryptography.algorithms.SHA256
import dev.whyoleg.cryptography.algorithms.SHA512
import dev.whyoleg.cryptography.providers.apple.Apple
actual class MacInstance actual constructor(
algorithm: String,
key: ByteArray,
) {
private val cryptoProvider = CryptographyProvider.Apple
private var internalMacInstance: HMAC.Key =
cryptoProvider
.get(HMAC)
.keyDecoder(digestForAlgorithm(algorithm))
.decodeFromByteArrayBlocking(HMAC.Key.Format.RAW, key)
private val hmacSignFunction = internalMacInstance.signatureGenerator().createSignFunction()
actual fun init(
key: ByteArray,
algorithm: String,
) {
TODO("Not yet implemented")
internalMacInstance =
cryptoProvider
.get(HMAC)
.keyDecoder(digestForAlgorithm(algorithm))
.decodeFromByteArrayBlocking(HMAC.Key.Format.RAW, key)
}
actual fun getMacLength(): Int {
TODO("Not yet implemented")
}
actual fun getMacLength(): Int = hmacSignFunction.signIntoByteArray(internalMacInstance.encodeToByteArrayBlocking(HMAC.Key.Format.RAW))
actual fun update(array: ByteArray) {
TODO("Not yet implemented")
hmacSignFunction.update(array)
}
actual fun update(byte: Byte) {
TODO("Not yet implemented")
hmacSignFunction.update(byteArrayOf(byte))
}
actual fun doFinal(): ByteArray {
TODO("Not yet implemented")
}
actual fun doFinal(): ByteArray = hmacSignFunction.signToByteArray()
actual fun doFinal(
output: ByteArray,
offset: Int,
) {
TODO("Not yet implemented")
hmacSignFunction.signIntoByteArray(output, offset)
}
private fun digestForAlgorithm(algorithm: String) =
when (algorithm) {
"HmacSHA256" -> SHA256
"HmacSHA512" -> SHA512
else -> error("Algorithm is not yet supported.")
}
}