use asByteArray _view_ where possible (optimization)

This commit is contained in:
Sergey Chernov 2024-08-19 11:58:52 +02:00
parent b5ac0c4e7e
commit 6431d4896a
17 changed files with 50 additions and 22 deletions

1
.idea/misc.xml generated
View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration"> <component name="FrameworkDetectionExcludesConfiguration">

View File

@ -6,6 +6,14 @@ Cryptographic API works exactly the same and compiles to any platform supported
All primitives meant to send over the network or store are `kotlinx.serialization` compatible, serializers included. All primitives meant to send over the network or store are `kotlinx.serialization` compatible, serializers included.
# Usage
```kotlin
dependencies {
maven("https://gitea.sergeych.net/api/packages/SergeychWorks/maven")
}
```
# Supported platforms: # Supported platforms:
## Javascript ## Javascript

View File

@ -5,7 +5,7 @@ plugins {
} }
group = "net.sergeych" group = "net.sergeych"
version = "0.4.2" version = "0.4.3"
repositories { repositories {
mavenCentral() mavenCentral()

View File

@ -442,7 +442,7 @@ sealed class Container {
createWith(BipackEncoder.encode<T>(plainData).toUByteArray(), *keys).encoded createWith(BipackEncoder.encode<T>(plainData).toUByteArray(), *keys).encoded
inline fun <reified T>decrypt(cipherData: UByteArray, vararg keys: DecryptingKey): T? = inline fun <reified T>decrypt(cipherData: UByteArray, vararg keys: DecryptingKey): T? =
decryptAsUBytes(cipherData,*keys)?.let { BipackDecoder.decode<T>(it.toByteArray())} decryptAsUBytes(cipherData,*keys)?.let { BipackDecoder.decode<T>(it.asByteArray())}
fun decryptAsUBytes(cipherData: UByteArray, vararg keys: DecryptingKey): UByteArray? = fun decryptAsUBytes(cipherData: UByteArray, vararg keys: DecryptingKey): UByteArray? =
decode(cipherData).decryptWith(*keys) decode(cipherData).decryptWith(*keys)
@ -465,7 +465,7 @@ sealed class Container {
create(plainData) { key(*keys) } create(plainData) { key(*keys) }
fun decode(encoded: UByteArray): Container { fun decode(encoded: UByteArray): Container {
return BipackDecoder.decode(encoded.toByteArray()) return BipackDecoder.decode(encoded.asByteArray())
} }
} }

View File

@ -11,13 +11,13 @@ object Contrail {
/** /**
* Create a contrail by adding a crc byte to the end of [data]. The Result is always one byte longer. * Create a contrail by adding a crc byte to the end of [data]. The Result is always one byte longer.
*/ */
fun create(data: UByteArray): UByteArray = data + CRC.crc8(data.toByteArray()) fun create(data: UByteArray): UByteArray = data + CRC.crc8(data.asByteArray())
/** /**
* Check the contrail is valid. * Check the contrail is valid.
*/ */
fun isValid(data: UByteArray): Boolean = CRC.crc8( fun isValid(data: UByteArray): Boolean = CRC.crc8(
data.copyOfRange(0, data.size - 1).toByteArray() data.copyOfRange(0, data.size - 1).asByteArray()
) == data.last() ) == data.last()

View File

@ -19,7 +19,7 @@ interface DecryptingKey : NonceBased, KeyInstance {
*/ */
fun decrypt(cipherData: UByteArray): UByteArray = fun decrypt(cipherData: UByteArray): UByteArray =
protectDecryption { protectDecryption {
val wn: WithNonce = cipherData.toByteArray().decodeFromBipack() val wn: WithNonce = cipherData.asByteArray().decodeFromBipack()
decryptWithNonce(wn.cipherData, wn.nonce) decryptWithNonce(wn.cipherData, wn.nonce)
} }
@ -31,4 +31,4 @@ interface DecryptingKey : NonceBased, KeyInstance {
} }
inline fun <reified T>DecryptingKey.decryptObject(cipherData: UByteArray): T = inline fun <reified T>DecryptingKey.decryptObject(cipherData: UByteArray): T =
BipackDecoder.decode<T>(decrypt(cipherData).toByteArray()) BipackDecoder.decode<T>(decrypt(cipherData).asByteArray())

View File

@ -9,8 +9,8 @@ import org.komputing.khash.keccak.KeccakParameter
enum class Hash(val perform: (UByteArray)->UByteArray) { enum class Hash(val perform: (UByteArray)->UByteArray) {
Blake2b({ GenericHash.genericHash(it) }), Blake2b({ GenericHash.genericHash(it) }),
Blake2b2l({ blake2b2l(it) }), Blake2b2l({ blake2b2l(it) }),
Sha3_384({ Keccak.digest(it.toByteArray(), KeccakParameter.SHA3_384).toUByteArray()}), Sha3_384({ Keccak.digest(it.asByteArray(), KeccakParameter.SHA3_384).asUByteArray()}),
Sha3_256({ Keccak.digest(it.toByteArray(), KeccakParameter.SHA3_256).toUByteArray()}), Sha3_256({ Keccak.digest(it.asByteArray(), KeccakParameter.SHA3_256).asUByteArray()}),
} }
private val defaultSuffix1 = "All lay loads on a willing horse".encodeToUByteArray() private val defaultSuffix1 = "All lay loads on a willing horse".encodeToUByteArray()

View File

@ -96,7 +96,7 @@ object PBKD {
fun key(kdf: KDF, password: String): BinaryId = fun key(kdf: KDF, password: String): BinaryId =
BinaryId.createFromBytes( BinaryId.createFromBytes(
0, 0,
BipackEncoder.encode(kdf) + blake2b3l(password.encodeToUByteArray()).toByteArray() BipackEncoder.encode(kdf) + blake2b3l(password.encodeToUByteArray()).asByteArray()
) )
private val cache = HashMap<BinaryId, Entry>() private val cache = HashMap<BinaryId, Entry>()

View File

@ -145,6 +145,6 @@ class Seal(
* Int the rare case you need a packed seal alone, unpack it. Normally just add seal to some [Serializable] * Int the rare case you need a packed seal alone, unpack it. Normally just add seal to some [Serializable]
* class, it is serializable. * class, it is serializable.
*/ */
fun unpack(packed: UByteArray): Seal = packed.toByteArray().decodeFromBipack() fun unpack(packed: UByteArray): Seal = packed.asByteArray().decodeFromBipack()
} }
} }

View File

@ -3,7 +3,9 @@ package net.sergeych.crypto2
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import net.sergeych.bipack.BipackDecoder
import net.sergeych.bipack.BipackEncoder import net.sergeych.bipack.BipackEncoder
import net.sergeych.bipack.decodeFromBipack
/** /**
* Multi-signed data box. Do not use the constructori directly, use [SealedBox.create] * Multi-signed data box. Do not use the constructori directly, use [SealedBox.create]
@ -14,7 +16,7 @@ import net.sergeych.bipack.BipackEncoder
* Signatures, [Seal], incorporate creation time and optional expiration which are * Signatures, [Seal], incorporate creation time and optional expiration which are
* also signed and checked upon deserialization. * also signed and checked upon deserialization.
* *
* It is serializable and checks integrity __on deserialization__k. If any of seals does not * It is serializable and checks integrity __on deserialization__. If any of seals does not
* match the signed [message], it throws [IllegalSignatureException] _on deserialization_. * match the signed [message], it throws [IllegalSignatureException] _on deserialization_.
* E.g., if you have it deserialized, it is ok, check it contains all needed keys among * E.g., if you have it deserialized, it is ok, check it contains all needed keys among
* signers. * signers.
@ -79,12 +81,19 @@ class SealedBox(
* @param keys a list of keys to sign with, should be at least one key. * @param keys a list of keys to sign with, should be at least one key.
* @throws IllegalArgumentException if keys are not specified. * @throws IllegalArgumentException if keys are not specified.
*/ */
fun create(data: UByteArray, vararg keys: SigningSecretKey): SealedBox { fun create(data: UByteArray, vararg keys: SigningKey): SealedBox {
return SealedBox(data, keys.map { it.seal(data) }, false) return SealedBox(data, keys.map { it.seal(data) }, false)
} }
inline fun <reified T>encode(value: T, vararg keys: SigningSecretKey): UByteArray = inline fun <reified T>encode(value: T, vararg keys: SigningSecretKey): UByteArray =
create(BipackEncoder.encode(value).toUByteArray(), *keys).encoded create(BipackEncoder.encode(value).toUByteArray(), *keys).encoded
/**
* Unpack and check sealed box, returning deserialized contained value
* @throws IllegalSignatureException
*/
inline fun <reified T>decode(packedSealedBox: UByteArray): T =
BipackDecoder.decode<SealedBox>(packedSealedBox.asByteArray()).message.decodeFromBipack()
} }
} }

View File

@ -62,7 +62,7 @@ class SecretKey(
* Decrypt without a nonce as edwards curve decryption does not need it * Decrypt without a nonce as edwards curve decryption does not need it
*/ */
override fun decrypt(cipherData: UByteArray): UByteArray { override fun decrypt(cipherData: UByteArray): UByteArray {
val message: Asymmetric.Message = BipackDecoder.decode(cipherData.toByteArray()) val message: Asymmetric.Message = BipackDecoder.decode(cipherData.asByteArray())
return message.decrypt(this) return message.decrypt(this)
} }

View File

@ -32,6 +32,6 @@ class WithFill private constructor(
* extract binary data from filled * extract binary data from filled
*/ */
fun decode(data: UByteArray): UByteArray = fun decode(data: UByteArray): UByteArray =
BipackDecoder.decode<WithFill>(data.toByteArray()).data BipackDecoder.decode<WithFill>(data.asByteArray()).data
} }
} }

View File

@ -5,6 +5,6 @@ package net.sergeych.crypto2
import net.sergeych.bintools.toDump import net.sergeych.bintools.toDump
import net.sergeych.mp_tools.encodeToBase64Url import net.sergeych.mp_tools.encodeToBase64Url
fun UByteArray.toDump(wide: Boolean = false) = toByteArray().toDump(wide) fun UByteArray.toDump(wide: Boolean = false) = asByteArray().toDump(wide)
fun UByteArray.encodeToBase64Url(): String = toByteArray().encodeToBase64Url() fun UByteArray.encodeToBase64Url(): String = asByteArray().encodeToBase64Url()

View File

@ -4,7 +4,7 @@ import net.sergeych.bipack.BipackDecoder
import net.sergeych.bipack.BipackEncoder import net.sergeych.bipack.BipackEncoder
inline fun <reified T>bipack(value: T): UByteArray = BipackEncoder.encode(value).toUByteArray() inline fun <reified T>bipack(value: T): UByteArray = BipackEncoder.encode(value).asUByteArray()
inline fun <reified T>biunpack(value: UByteArray): T = BipackDecoder.decode(value.toByteArray()) inline fun <reified T>biunpack(value: UByteArray): T = BipackDecoder.decode(value.asByteArray())

View File

@ -43,4 +43,4 @@ fun <T>pack(serializer: KSerializer<T>, element: T?): UByteArray =
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T: Any?> unpack(serializer: KSerializer<T>, encoded: UByteArray): T = fun <T: Any?> unpack(serializer: KSerializer<T>, encoded: UByteArray): T =
if (encoded.isEmpty()) null as T if (encoded.isEmpty()) null as T
else BipackDecoder.decode(encoded.toByteArray().toDataSource(),serializer) else BipackDecoder.decode(encoded.asByteArray().toDataSource(),serializer)

View File

@ -12,7 +12,7 @@ fun ByteArray.digestKeccak(parameter: KeccakParameter): ByteArray {
} }
fun UByteArray.digestKeccak(parameter: KeccakParameter): UByteArray { fun UByteArray.digestKeccak(parameter: KeccakParameter): UByteArray {
return Keccak.digest(this.toByteArray(), parameter).toUByteArray() return Keccak.digest(this.asByteArray(), parameter).toUByteArray()
} }
/** /**

View File

@ -250,4 +250,16 @@ class KeysTest {
val k1: UniversalKey = biunpack<UniversalKey>(d) as SymmetricKey val k1: UniversalKey = biunpack<UniversalKey>(d) as SymmetricKey
assertEquals(k, k1) assertEquals(k, k1)
} }
@Test
fun verifyingKeySerializationTest() = runTest {
initCrypto()
val k = SigningSecretKey.new()
val s1 = pack(k)
val s2 = pack(k.verifyingKey)
val dk1 = unpack<SigningSecretKey>(s1)
val dk2 = unpack<VerifyingPublicKey>(s2)
assertEquals(k, dk1)
assertEquals(k.verifyingKey, dk2)
}
} }