From 7eeb780bdbaf146f79d4016ff779dcf753910a4a Mon Sep 17 00:00:00 2001 From: sergeych Date: Sat, 22 Jun 2024 12:22:39 +0700 Subject: [PATCH] refactoring in progress --- .../kotlin/net/sergeych/crypto2/Asymmetric.kt | 6 +- .../kotlin/net/sergeych/crypto2/Container.kt | 16 ++-- .../net/sergeych/crypto2/DecryptingKey.kt | 2 +- .../net/sergeych/crypto2/EncryptingKey.kt | 2 +- .../sergeych/crypto2/{KeyTag.kt => KeyId.kt} | 4 +- .../net/sergeych/crypto2/MagickNumbers.kt | 1 + .../net/sergeych/crypto2/SafeKeyExchange.kt | 8 +- .../kotlin/net/sergeych/crypto2/Seal.kt | 6 +- .../kotlin/net/sergeych/crypto2/SealedBox.kt | 10 +-- .../crypto2/{SigningKey.kt => Signing.kt} | 46 +++++++--- .../net/sergeych/crypto2/SymmetricKey.kt | 2 +- .../net/sergeych/crypto2/UniversalKey.kt | 62 +++++++++++--- .../net/sergeych/crypto2/UniversalRing.kt | 85 ++++++++++++++----- src/commonTest/kotlin/KeysTest.kt | 19 ++--- src/commonTest/kotlin/RingTest.kt | 48 +++++++++-- 15 files changed, 223 insertions(+), 94 deletions(-) rename src/commonMain/kotlin/net/sergeych/crypto2/{KeyTag.kt => KeyId.kt} (86%) rename src/commonMain/kotlin/net/sergeych/crypto2/{SigningKey.kt => Signing.kt} (55%) diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/Asymmetric.kt b/src/commonMain/kotlin/net/sergeych/crypto2/Asymmetric.kt index 7b82a33..4c2f4c0 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/Asymmetric.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/Asymmetric.kt @@ -123,8 +123,8 @@ object Asymmetric { @Serializable class PublicKey(val keyBytes: UByteArray) { - val tag: KeyTag by lazy { - KeyTag(KeysMagickNumbers.defaultAssymmetric, blake2b(keyBytes)) + val tag: KeyId by lazy { + KeyId(KeysMagickNumbers.defaultAssymmetric, blake2b(keyBytes)) } override fun equals(other: Any?): Boolean { @@ -250,7 +250,7 @@ object Asymmetric { return message.decrypt(this) } - override val tag: KeyTag by lazy { publicKey.tag } + override val id: KeyId by lazy { publicKey.tag } override val nonceBytesLength: Int get() = 0 diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt b/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt index 9e0a643..73fea70 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt @@ -143,7 +143,7 @@ sealed class Container { @Serializable @SerialName("1") internal class Single( - val keyTag: KeyTag, val encryptedMessage: UByteArray, + val keyId: KeyId, val encryptedMessage: UByteArray, @Transient private val creationData: UByteArray? = null, @Transient private val reEncryptionKey: EncryptingKey? = null, @Transient private var encryptionPair: AsymmetricEncryptionPair? = null, @@ -158,8 +158,8 @@ sealed class Container { override fun decryptWith(keyRing: UniversalRing): UByteArray? { decryptedData?.let { return it } - for (k in keyRing) { - if (k.tag == keyTag) { + for (k in keyRing.decryptingKeys) { + if (k.id == keyId) { kotlin.runCatching { k.decrypt(encryptedMessage) }.getOrNull()?.let { decryptedData = it decryptedWithKey = k @@ -226,9 +226,9 @@ sealed class Container { @Transient internal var knownPlainData: UByteArray? = null, ) : Container() { @Serializable - class EncryptedKey(val tag: KeyTag, val cipherData: UByteArray) { + class EncryptedKey(val tag: KeyId, val cipherData: UByteArray) { constructor(key: EncryptingKey, encodeMainKey: UByteArray) : - this(key.tag, key.encrypt(encodeMainKey)) + this(key.id, key.encrypt(encodeMainKey)) constructor(sender: Asymmetric.SecretKey?, recipient: Asymmetric.PublicKey, encodeMainKey: UByteArray) : this( @@ -246,8 +246,8 @@ sealed class Container { override fun decryptWith(keyRing: UniversalRing): UByteArray? { decryptedData?.let { return it } - for (key in keyRing) { - val tag = key.tag + for (key in keyRing.decryptingKeys) { + val tag = key.id for (encryptedKey in encryptedKeys) { if (tag == encryptedKey.tag) { kotlin.runCatching { @@ -384,7 +384,7 @@ sealed class Container { } private fun createSingle() = plainKeys.firstOrNull()?.let { - Single(it.tag, it.encrypt(plainData, fillRange), plainData, reEncryptionKey = it) + Single(it.id, it.encrypt(plainData, fillRange), plainData, reEncryptionKey = it) } ?: run { val pair = keyPairs.first() val (sk, pk) = pair diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/DecryptingKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/DecryptingKey.kt index b9d8fcf..9b47585 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/DecryptingKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/DecryptingKey.kt @@ -28,7 +28,7 @@ interface DecryptingKey : NonceBased { fun decryptString(cipherData: UByteArray): String = decrypt(cipherData).decodeFromUByteArray() - val tag: KeyTag + val id: KeyId } diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/EncryptingKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/EncryptingKey.kt index fb4b538..5145bf0 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/EncryptingKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/EncryptingKey.kt @@ -27,7 +27,7 @@ interface EncryptingKey : NonceBased { fun encrypt(plainText: String,randomFill: IntRange? = null): UByteArray = encrypt(plainText.encodeToUByteArray(),randomFill) - val tag: KeyTag + val id: KeyId fun encryptWithNonce(plainData: UByteArray, nonce: UByteArray, randomFill: IntRange? = null): UByteArray } diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/KeyTag.kt b/src/commonMain/kotlin/net/sergeych/crypto2/KeyId.kt similarity index 86% rename from src/commonMain/kotlin/net/sergeych/crypto2/KeyTag.kt rename to src/commonMain/kotlin/net/sergeych/crypto2/KeyId.kt index 5cbe0da..2316315 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/KeyTag.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/KeyId.kt @@ -7,13 +7,13 @@ import kotlinx.serialization.Serializable * containers to fast find a proper key */ @Serializable -data class KeyTag(val id: BinaryId,val kdp: KeyDerivationParams?=null ) { +data class KeyId(val id: BinaryId, val kdp: KeyDerivationParams?=null ) { val tag: UByteArray by lazy { id.id } override fun equals(other: Any?): Boolean { if (this === other) return true - if (other !is KeyTag) return false + if (other !is KeyId) return false return id == other.id } diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/MagickNumbers.kt b/src/commonMain/kotlin/net/sergeych/crypto2/MagickNumbers.kt index 14ee677..ae081bb 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/MagickNumbers.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/MagickNumbers.kt @@ -4,6 +4,7 @@ enum class KeysMagickNumbers(val number: Int) { defaultAssymmetric(0), defaultSymmetric(1), defaultSession(2), + defaultSigning(3), ; companion object { diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/SafeKeyExchange.kt b/src/commonMain/kotlin/net/sergeych/crypto2/SafeKeyExchange.kt index 02e0137..117d58a 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/SafeKeyExchange.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/SafeKeyExchange.kt @@ -47,13 +47,13 @@ class SafeKeyExchange { @Suppress("unused") val sessionTag: UByteArray by lazy { if (!isClient) - blake2b(tag.tag + tag.tag) + blake2b(id.tag + id.tag) else - blake2b(tag.tag + tag.tag) + blake2b(id.tag + id.tag) } - override val tag: KeyTag - get() = if( isClient ) sendingKey.tag else receivingKey.tag + override val id: KeyId + get() = if( isClient ) sendingKey.id else receivingKey.id override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/Seal.kt b/src/commonMain/kotlin/net/sergeych/crypto2/Seal.kt index 33a04d6..7a913d0 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/Seal.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/Seal.kt @@ -23,7 +23,7 @@ import net.sergeych.utools.now */ @Serializable class Seal( - val publicKey: SigningKey.Public, + val publicKey: Signing.PublicKey, val signature: UByteArray, val nonce: UByteArray?, val createdAt: Instant, @@ -95,7 +95,7 @@ class Seal( * Seal [message] with a [key]. * * Seals are kotlinx-serializable and can be used - * to check the authenticity of the arbitrary [message] using a public key, [SigningKey.Public] + * to check the authenticity of the arbitrary [message] using a public key, [Signing.PublicKey] * instance, using public-key signing algorithms. * * Unlike a regular binary signature, Seal contains the signer's [publicKey], and also @@ -130,7 +130,7 @@ class Seal( * rare case so default os false. */ fun create( - key: SigningKey.Secret, + key: Signing.SecretKey, message: UByteArray, createdAt: Instant = now(), expiresAt: Instant? = null, diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/SealedBox.kt b/src/commonMain/kotlin/net/sergeych/crypto2/SealedBox.kt index 1c32dc0..b295cb8 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/SealedBox.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/SealedBox.kt @@ -30,7 +30,7 @@ class SealedBox( ) { @Suppress("unused") - constructor(message: UByteArray, vararg keys: SigningKey.Secret) : + constructor(message: UByteArray, vararg keys: Signing.SecretKey) : this(message, keys.map { it.seal(message) } ) /** @@ -38,7 +38,7 @@ class SealedBox( * key, or return unchanged (same) object if it is already signed by this key; you * _can't assume it always returns a copied object!_ */ - operator fun plus(key: SigningKey.Secret): SealedBox = + operator fun plus(key: Signing.SecretKey): SealedBox = if (key.publicKey in this) this else SealedBox(message, seals + key.seal(message),false) @@ -46,7 +46,7 @@ class SealedBox( * Add expiring seal, otherwise use [plus]. Overrides exising seal for [key] * if present: */ - fun addSeal(key: SigningKey.Secret,expresAt: Instant): SealedBox { + fun addSeal(key: Signing.SecretKey, expresAt: Instant): SealedBox { val filtered = seals.filter { it.publicKey != key.publicKey } return SealedBox(message, filtered + key.seal(message, expresAt), false) } @@ -54,7 +54,7 @@ class SealedBox( /** * Check that it is signed with a specified key. */ - operator fun contains(publicKey: SigningKey.Public): Boolean { + operator fun contains(publicKey: Signing.PublicKey): Boolean { return seals.any { it.publicKey == publicKey } } @@ -77,7 +77,7 @@ class SealedBox( * @param keys a list of keys to sign with, should be at least one key. * @throws IllegalArgumentException if keys are not specified. */ - fun create(data: UByteArray, vararg keys: SigningKey.Secret): SealedBox { + fun create(data: UByteArray, vararg keys: Signing.SecretKey): SealedBox { return SealedBox(data, keys.map { it.seal(data) }, false) } } diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/SigningKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/Signing.kt similarity index 55% rename from src/commonMain/kotlin/net/sergeych/crypto2/SigningKey.kt rename to src/commonMain/kotlin/net/sergeych/crypto2/Signing.kt index 20fe8f9..6278066 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/SigningKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/Signing.kt @@ -5,9 +5,24 @@ import com.ionspin.kotlin.crypto.signature.Signature import kotlinx.datetime.Instant import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import net.sergeych.crypto2.SigningKey.Companion.pair +import net.sergeych.crypto2.Signing.Companion.pair import net.sergeych.utools.now +interface VerifyingKey { + val id: KeyId + + /** + * Verify the signature and return true if it is correct. + */ + fun verify(signature: UByteArray, message: UByteArray): Boolean +} + +interface SigningKey { + val publicKey: Signing.PublicKey + fun sign(message: UByteArray): UByteArray + fun seal(message: UByteArray, expiresAt: Instant? = null): Seal +} + /** * Keys in general: public, secret and later symmetric too. * Keys could be compared to each other for equality and used @@ -16,11 +31,13 @@ import net.sergeych.utools.now * Use [pair] to create new keys. */ @Serializable -sealed class SigningKey { +sealed class Signing { + abstract val id: KeyId + abstract val packed: UByteArray override fun equals(other: Any?): Boolean { - return other is SigningKey && other.packed contentEquals packed + return other is Signing && other.packed contentEquals packed } override fun hashCode(): Int { @@ -34,11 +51,11 @@ sealed class SigningKey { */ @Serializable @SerialName("p") - class Public(override val packed: UByteArray) : SigningKey() { + class PublicKey(override val packed: UByteArray) : Signing(), VerifyingKey { /** * Verify the signature and return true if it is correct. */ - fun verify(signature: UByteArray, message: UByteArray): Boolean = try { + override fun verify(signature: UByteArray, message: UByteArray): Boolean = try { Signature.verifyDetached(signature, message, packed) true } catch (_: InvalidSignatureException) { @@ -47,6 +64,9 @@ sealed class SigningKey { override fun toString(): String = "Pub:${super.toString()}" + override val id: KeyId by lazy { + KeyId(KeysMagickNumbers.defaultSigning, packed) + } } /** @@ -54,27 +74,29 @@ sealed class SigningKey { */ @Serializable @SerialName("s") - class Secret(override val packed: UByteArray) : SigningKey() { + class SecretKey(override val packed: UByteArray) : Signing(), SigningKey { - val publicKey: Public by lazy { - Public(Signature.ed25519SkToPk(packed)) + override val publicKey: PublicKey by lazy { + PublicKey(Signature.ed25519SkToPk(packed)) } - fun sign(message: UByteArray): UByteArray = Signature.detached(message, packed) + override fun sign(message: UByteArray): UByteArray = Signature.detached(message, packed) - fun seal(message: UByteArray, expiresAt: Instant? = null): Seal = + override fun seal(message: UByteArray, expiresAt: Instant?): Seal = Seal.create(this, message, now(), expiresAt) override fun toString(): String = "Sct:${super.toString()}" + override val id: KeyId + get() = publicKey.id } companion object { - data class Pair(val secretKey: Secret, val publicKey: Public) + data class Pair(val secretKey: SecretKey, val publicKey: PublicKey) fun pair(): Pair { val p = Signature.keypair() - return Pair(Secret(p.secretKey), Public(p.publicKey)) + return Pair(SecretKey(p.secretKey), PublicKey(p.publicKey)) } } } diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/SymmetricKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/SymmetricKey.kt index f4d23f6..78d474a 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/SymmetricKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/SymmetricKey.kt @@ -37,7 +37,7 @@ class SymmetricKey( override val nonceBytesLength: Int = nonceByteLength - override val tag by lazy { KeyTag(KeysMagickNumbers.defaultSymmetric,blake2b3l(keyBytes)) } + override val id by lazy { KeyId(KeysMagickNumbers.defaultSymmetric,blake2b3l(keyBytes)) } override fun decryptWithNonce(cipherData: UByteArray, nonce: UByteArray): UByteArray = protectDecryption { diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt index aea47d0..4313f6d 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt @@ -5,45 +5,79 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.Transient @Serializable -sealed class UniversalKey : DecryptingKey { - -// abstract val tag: KeyTag - - +sealed class UniversalKey { + abstract val id: KeyId + @Transient + open val canEncrypt = false + @Transient + open val canDecrypt = false + @Transient + open val canSign = false + @Transient + open val canVerify = false @Serializable - @SerialName("sy") + @SerialName("sym") data class Symmetric(val key: SymmetricKey) : UniversalKey(), EncryptingKey by key, DecryptingKey by key { @Transient - override val tag: KeyTag = key.tag + override val id: KeyId = key.id @Transient override val nonceBytesLength: Int = key.nonceBytesLength - override fun toString() = "U.Sym:$tag" + override fun toString() = "U.Sym:$id" + + @Transient + override val canDecrypt: Boolean = true + @Transient + override val canEncrypt: Boolean = true } @Serializable - @SerialName("sn") + @SerialName("ssn") data class Session(val key: SafeKeyExchange.SessionKey) : UniversalKey(), EncryptingKey by key, DecryptingKey by key { @Transient - override val tag: KeyTag = key.tag + override val id: KeyId = key.id @Transient override val nonceBytesLength: Int = key.nonceBytesLength + @Transient + override val canDecrypt: Boolean = true + @Transient + override val canEncrypt: Boolean = true } @Serializable - @SerialName("se") + @SerialName("sec") data class Secret(val key: Asymmetric.SecretKey) : UniversalKey(), DecryptingKey by key { - override val tag: KeyTag by lazy { key.tag } - override fun toString() = "U.Sec:$tag" + override val id: KeyId by lazy { key.id } + override fun toString() = "U.Sec:$id" + @Transient + override val canDecrypt: Boolean = true + } + + @Serializable + @SerialName("sig") + data class Signing(val key: net.sergeych.crypto2.Signing.SecretKey) : UniversalKey() { + override val id: KeyId by lazy { key.id } + override fun toString() = "U.Sig:$id" + @Transient + override val canDecrypt: Boolean = true + } + + @Serializable + @SerialName("ver") + data class Verifying(val key: net.sergeych.crypto2.Signing.PublicKey) : UniversalKey() { + override val id: KeyId by lazy { key.id } + override fun toString() = "U.Sig:$id" + @Transient + override val canDecrypt: Boolean = true } companion object { - fun from(key: DecryptingKey) = + fun from(key: DecryptingKey): UniversalKey = when (key) { is UniversalKey -> key is Asymmetric.SecretKey -> Secret(key) diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/UniversalRing.kt b/src/commonMain/kotlin/net/sergeych/crypto2/UniversalRing.kt index 73892ad..7df4d9e 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/UniversalRing.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/UniversalRing.kt @@ -1,48 +1,91 @@ package net.sergeych.crypto2 import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient @Serializable class UniversalRing( - private val keys: Collection -): Collection by keys { - constructor(vararg keys: UniversalKey) : this(keys.toSet()) - constructor(vararg keys: DecryptingKey) : this(keys.map { UniversalKey.from(it) }.toSet()) - @Transient - val keySet = if( keys is Set ) keys else keys.toSet() + private val keyWithTags: Map> +) { + val decryptingKeys: Set by lazy { + keyWithTags.keys.mapNotNull { it as? DecryptingKey }.toSet() + } - private val byTag by lazy { keySet.associateBy { it.tag } } + constructor(vararg keys: UniversalKey) : this(keys.associateWith { setOf() }) + constructor(vararg keys: DecryptingKey) : this(keys.associate { UniversalKey.from(it) to setOf() }) + constructor(vararg keyTags: Pair) + : this(keyTags.associate { it.first to setOf(it.second) }) - operator fun get(keyTag: KeyTag): UniversalKey? = byTag[keyTag] + private val byId by lazy { keyWithTags.keys.associateBy { it.id } } + private val byIdWithTags by lazy { keyWithTags.entries.associate { it.key.id to (it.key to it.value) } } - override operator fun contains(element: UniversalKey): Boolean = byTag.containsKey(element.tag) + operator fun get(keyId: KeyId): UniversalKey? = byId[keyId] + + fun getTags(key: UniversalKey): Set? = keyWithTags[key] + + fun keyWithTags(keyId: KeyId?): Pair>? = byIdWithTags[keyId] + + operator fun contains(element: UniversalKey): Boolean = byId.containsKey(element.id) operator fun plus(key: UniversalKey): UniversalRing = - if( key in this ) this else UniversalRing(keySet + key ) + if( key in this ) this else UniversalRing(keyWithTags + (key to setOf()) ) + + operator fun plus(keyTag: Pair): UniversalRing = + if( keyTag.first in this ) + addTags(keyTag.first,keyTag.second) + else UniversalRing(keyWithTags + keyWithTags) + + fun add(key: UniversalKey, vararg tags: String): UniversalRing = + UniversalRing(keyWithTags + (key to tags.toSet()) ) + + fun add(key: UniversalKey, tags: Collection): UniversalRing = + UniversalRing(keyWithTags + (key to tags.toSet()) ) + + fun addTags(key: UniversalKey,tags: Set): UniversalRing { + val kt1 = keyWithTags.toMutableMap() + kt1[key]?.let { + kt1[key] = it + tags + } ?: run { + kt1[key] = tags + } + return UniversalRing(kt1) + } + + fun addTags(key: UniversalKey,vararg tags: String): UniversalRing = + addTags(key,tags.toSet()) operator fun minus(key: UniversalKey): UniversalRing = - if( key in this ) UniversalRing(keySet.filter { it.tag != key.tag }) else this + if( key in this ) UniversalRing(keyWithTags.filter { it.key != key }) else this - operator fun minus(keyTag: KeyTag): UniversalRing = - if( keyTag in byTag ) UniversalRing(keySet.filter { it.tag != keyTag }) else this + operator fun minus(keyId: KeyId): UniversalRing = + if( keyId in byId ) UniversalRing(keyWithTags.filter { it.key.id != keyId }) else this override fun equals(other: Any?): Boolean { - println("compare1\r\n") if (this === other) return true - println("compare2\r\n") if (other !is UniversalRing) return false - - println("compare2 ${size == other.size}: $size : ${other.size} | ${keySet == other.keySet}\r\n") - return size == other.size && keySet.containsAll(other.keySet) + return keyWithTags == other.keyWithTags } override fun toString(): String { - return "Kr[${keys.joinToString(",")}]" + val ss = keyWithTags.entries + .joinToString(","){"${it.value.joinToString{ ":" }}:${it.key}"} + return "Kr[$ss]" } override fun hashCode(): Int { - return keySet.hashCode() + return keyWithTags.hashCode() } + infix fun equalKeys(other: UniversalRing): Boolean = keyWithTags.keys == other.keyWithTags.keys + + fun removeTags(key: UniversalKey, vararg tags: String): UniversalRing = removeTags(key, tags.toSet()) + + fun removeTags(key: UniversalKey, tags: Set): UniversalRing { + val kt1 = keyWithTags.toMutableMap() + kt1[key]?.let { + kt1[key] = it - tags + } + return UniversalRing(kt1) + } + + } diff --git a/src/commonTest/kotlin/KeysTest.kt b/src/commonTest/kotlin/KeysTest.kt index 5fe5739..98b6667 100644 --- a/src/commonTest/kotlin/KeysTest.kt +++ b/src/commonTest/kotlin/KeysTest.kt @@ -13,11 +13,11 @@ class KeysTest { @Test fun testSigningCreationAndMap() = runTest { initCrypto() - val (stk,pbk) = SigningKey.pair() + val (stk,pbk) = Signing.pair() val x = mapOf( stk to "STK!", pbk to "PBK!") assertEquals("STK!", x[stk]) - val s1 = SigningKey.Secret(stk.packed) + val s1 = Signing.SecretKey(stk.packed) assertEquals(stk, s1) assertEquals("STK!", x[s1]) assertEquals("PBK!", x[pbk]) @@ -29,8 +29,8 @@ class KeysTest { data1[0] = 0x01u assertFalse(s.isValid(data1)) - val p2 = SigningKey.pair() - val p3 = SigningKey.pair() + val p2 = Signing.pair() + val p3 = Signing.pair() val ms = SealedBox.create(data, s1) + p2.secretKey @@ -50,7 +50,7 @@ class KeysTest { fun testNonDeterministicSeals() = runTest { initCrypto() val data = "Welcome to the Miami, bitch!".encodeToUByteArray() - val (sk,_) = SigningKey.pair() + val (sk,_) = Signing.pair() val t = now() val s1 = Seal.create(sk, data, createdAt = t) val s2 = Seal.create(sk, data, createdAt = t) @@ -212,13 +212,8 @@ class KeysTest { assertEquals(usk2, usk1) assertFalse { usk1 == usk3 } - var a = setOf(sy1, sy2, sk1, sk2) - var b = setOf(sk1, sk2, sy2, sy1) - - assertEquals(a,b) - - a = setOf(usk1, usk2, usk3, usk4) - b = setOf(usk1, usk2, usk3, usk4) + var a = setOf(usk1, usk2, usk3, usk4) + var b = setOf(usk1, usk2, usk3, usk4) assertEquals(a, b) // usk1 and usk2 are equal so set with only one of should be the same diff --git a/src/commonTest/kotlin/RingTest.kt b/src/commonTest/kotlin/RingTest.kt index ca22c68..09097d2 100644 --- a/src/commonTest/kotlin/RingTest.kt +++ b/src/commonTest/kotlin/RingTest.kt @@ -31,8 +31,8 @@ class RingTest { // val r = UniversalRing(k1, k2) // val r = UniversalRing(k1) - assertContains(r, k2) - assertContains(r, k1) + assertTrue(k2 in r) + assertTrue(k1 in r) assertFalse { k3 in r } println(Asymmetric.randomSecretKey().keyBytes.size) @@ -42,8 +42,8 @@ class RingTest { println(encoded.size) assertTrue { encoded.size < 80 } val r2: UniversalRing = BipackDecoder.decode(encoded) - assertContains(r2, k2) - assertContains(r2, k1) + assertTrue { k2 in r2 } + assertTrue { k1 in r2 } assertFalse { k3 in r2 } println("\r\n") @@ -57,8 +57,42 @@ class RingTest { } @Test - @Ignore - fun testKeysWithSameTags() { - // it should be able to keep keys with same tags + fun testTags() = runTest { + initCrypto() + + val y1 = SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()) + val y2 = SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()) + + val e1 = Asymmetric.randomSecretKey() + val e2: Asymmetric.SecretKey = BipackDecoder.decode(BipackEncoder.encode(e1)) + + val k1 = UniversalKey.from(SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray())) + val k11 = UniversalKey.from(SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray())) + val k2 = UniversalKey.from(Asymmetric.randomSecretKey()) + val k3 = UniversalKey.from(Asymmetric.randomSecretKey()) + + val r1 = UniversalRing(k1, k2) + var r2 = UniversalRing(deepCopy(k1), deepCopy(k2)) + assertEquals(r2, r1) + val r3 = UniversalRing(k1 to "foo", k2 to "bar") + assertNotEquals(r3, r2) + assertTrue { r3 equalKeys r2 } + + r2 += (k1 to "foo") + r2 = r2.addTags(k2, "bar") + assertEquals(r2, r3) + assertEquals(deepCopy(r2), r3) + + r2 += k1 to "buzz" + r2 = deepCopy(r2) + assertEquals(setOf("foo", "buzz"), r2.getTags(k1)) + assertNotEquals(r2, r3) + r2 = deepCopy(r2.removeTags(k1, "buzz")) + assertEquals(r2, r3) + } + + @Test + fun testSize() = runTest { +// val sy1 = SymmetricKey.random().toUniversal() } } \ No newline at end of file