forked from sergeych/crypto2
+Multikey.AnyKey
This commit is contained in:
parent
1191de284e
commit
4cbc17334c
@ -3,6 +3,7 @@ package net.sergeych.crypto2
|
|||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import net.sergeych.bipack.Unsigned
|
import net.sergeych.bipack.Unsigned
|
||||||
|
import net.sergeych.crypto2.Multikey.AnyKey
|
||||||
import net.sergeych.crypto2.Multikey.Companion.allOf
|
import net.sergeych.crypto2.Multikey.Companion.allOf
|
||||||
import net.sergeych.crypto2.Multikey.Companion.allOfMultikeys
|
import net.sergeych.crypto2.Multikey.Companion.allOfMultikeys
|
||||||
import net.sergeych.crypto2.Multikey.Companion.anyOf
|
import net.sergeych.crypto2.Multikey.Companion.anyOf
|
||||||
@ -36,6 +37,7 @@ import net.sergeych.crypto2.Multikey.Companion.someOfMultikeys
|
|||||||
* - [someOfMultikeys], [someOf] family for `n of M` logic
|
* - [someOfMultikeys], [someOf] family for `n of M` logic
|
||||||
* - [anyOfMultikeys], [anyOf], [allOf], and [allOfMultikeys]
|
* - [anyOfMultikeys], [anyOf], [allOf], and [allOfMultikeys]
|
||||||
* - [invoke] for a single-key multikey
|
* - [invoke] for a single-key multikey
|
||||||
|
* - [AnyKey] when you need effectively match any key, useful when you need a `var` `Multikey`.
|
||||||
*
|
*
|
||||||
* __Important__. When serializing, always serialize as root [Multikey] instance to keep
|
* __Important__. When serializing, always serialize as root [Multikey] instance to keep
|
||||||
* it compatible with any combination.
|
* it compatible with any combination.
|
||||||
@ -53,17 +55,17 @@ sealed class Multikey {
|
|||||||
*/
|
*/
|
||||||
fun check(vararg verifyingKeys: VerifyingPublicKey): Boolean = check(verifyingKeys.asIterable())
|
fun check(vararg verifyingKeys: VerifyingPublicKey): Boolean = check(verifyingKeys.asIterable())
|
||||||
|
|
||||||
infix fun or(mk: Multikey): Multikey = SomeOf(1, listOf(this,mk))
|
infix fun or(mk: Multikey): Multikey = SomeOf(1, listOf(this, mk))
|
||||||
|
|
||||||
infix fun or(k: VerifyingPublicKey) = SomeOf( 1, listOf(this, Multikey(k)))
|
infix fun or(k: VerifyingPublicKey) = SomeOf(1, listOf(this, Multikey(k)))
|
||||||
|
|
||||||
infix fun or(k: SigningSecretKey) = SomeOf( 1, listOf(this, Multikey(k.verifyingKey)))
|
infix fun or(k: SigningSecretKey) = SomeOf(1, listOf(this, Multikey(k.verifyingKey)))
|
||||||
|
|
||||||
infix fun and(mk: Multikey): Multikey = SomeOf(2, listOf(this,mk))
|
infix fun and(mk: Multikey): Multikey = SomeOf(2, listOf(this, mk))
|
||||||
|
|
||||||
infix fun and(k: VerifyingPublicKey) = SomeOf( 2, listOf(this, Multikey(k)))
|
infix fun and(k: VerifyingPublicKey) = SomeOf(2, listOf(this, Multikey(k)))
|
||||||
|
|
||||||
infix fun and(k: SigningSecretKey) = SomeOf( 2, listOf(this, Multikey(k.verifyingKey)))
|
infix fun and(k: SigningSecretKey) = SomeOf(2, listOf(this, Multikey(k.verifyingKey)))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multikey instance implementing `m of N` logic against [VerifyingPublicKey] set. Do not use
|
* Multikey instance implementing `m of N` logic against [VerifyingPublicKey] set. Do not use
|
||||||
@ -74,13 +76,13 @@ sealed class Multikey {
|
|||||||
class Keys internal constructor(
|
class Keys internal constructor(
|
||||||
@Unsigned
|
@Unsigned
|
||||||
val requiredMinimum: Int,
|
val requiredMinimum: Int,
|
||||||
val validKeys: Set<VerifyingPublicKey>
|
val validKeys: Set<VerifyingPublicKey>,
|
||||||
) : Multikey() {
|
) : Multikey() {
|
||||||
override fun check(keys: Iterable<VerifyingPublicKey>): Boolean {
|
override fun check(keys: Iterable<VerifyingPublicKey>): Boolean {
|
||||||
var matches = 0
|
var matches = 0
|
||||||
for( signer in keys ) {
|
for (signer in keys) {
|
||||||
if( signer in validKeys) {
|
if (signer in validKeys) {
|
||||||
if( ++matches >= requiredMinimum ) return true
|
if (++matches >= requiredMinimum) return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -96,24 +98,34 @@ sealed class Multikey {
|
|||||||
class SomeOf internal constructor(
|
class SomeOf internal constructor(
|
||||||
@Unsigned
|
@Unsigned
|
||||||
val requiredMinimum: Int,
|
val requiredMinimum: Int,
|
||||||
val validKeys: List<Multikey>
|
val validKeys: List<Multikey>,
|
||||||
) : Multikey() {
|
) : Multikey() {
|
||||||
override fun check(keys: Iterable<VerifyingPublicKey>): Boolean {
|
override fun check(keys: Iterable<VerifyingPublicKey>): Boolean {
|
||||||
var matches = 0
|
var matches = 0
|
||||||
for( k in validKeys ) {
|
for (k in validKeys) {
|
||||||
if( k.check(keys) ) {
|
if (k.check(keys)) {
|
||||||
if( ++matches >= requiredMinimum ) return true
|
if (++matches >= requiredMinimum) return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special `AnyKey`: no restrictions, any key will satisfy this. In the rare case to mark
|
||||||
|
* publicly available operations, etc. Please note it is an object, not a class, and can't
|
||||||
|
* be instantiated.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
object AnyKey : Multikey() {
|
||||||
|
override fun check(keys: Iterable<VerifyingPublicKey>): Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
operator fun invoke(k: SigningSecretKey): Multikey = Keys(1, setOf( k.verifyingKey))
|
operator fun invoke(k: SigningSecretKey): Multikey = Keys(1, setOf(k.verifyingKey))
|
||||||
operator fun invoke(k: VerifyingPublicKey): Multikey = Keys(1, setOf( k))
|
operator fun invoke(k: VerifyingPublicKey): Multikey = Keys(1, setOf(k))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a multikey instance that requires some keys from a list
|
* Create a multikey instance that requires some keys from a list
|
||||||
@ -142,7 +154,7 @@ sealed class Multikey {
|
|||||||
/**
|
/**
|
||||||
* Create a multikey instance that requires any key from a list
|
* Create a multikey instance that requires any key from a list
|
||||||
*/
|
*/
|
||||||
fun anyOf(vararg keys: VerifyingPublicKey): Multikey = someOf(1, *keys)
|
fun anyOf(vararg keys: VerifyingPublicKey): Multikey = someOf(1, *keys)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a multikey instance that requires any key from a list
|
* Create a multikey instance that requires any key from a list
|
||||||
@ -163,7 +175,7 @@ sealed class Multikey {
|
|||||||
/**
|
/**
|
||||||
* Create a multikey instance that requires all keys from a list
|
* Create a multikey instance that requires all keys from a list
|
||||||
*/
|
*/
|
||||||
fun allOf(vararg keys: VerifyingPublicKey): Multikey = someOf(keys.size, *keys)
|
fun allOf(vararg keys: VerifyingPublicKey): Multikey = someOf(keys.size, *keys)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a multikey instance that requires all keys from a list
|
* Create a multikey instance that requires all keys from a list
|
||||||
@ -181,7 +193,5 @@ sealed class Multikey {
|
|||||||
fun allOf(keys: List<VerifyingPublicKey>): Multikey = someOf(keys.size, keys)
|
fun allOf(keys: List<VerifyingPublicKey>): Multikey = someOf(keys.size, keys)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,9 +15,9 @@ class KeysTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testSigningCreationAndMap() = runTest {
|
fun testSigningCreationAndMap() = runTest {
|
||||||
initCrypto()
|
initCrypto()
|
||||||
val (stk,pbk) = SigningSecretKey.generatePair()
|
val (stk, pbk) = SigningSecretKey.generatePair()
|
||||||
|
|
||||||
val x = mapOf( stk to "STK!", pbk to "PBK!")
|
val x = mapOf(stk to "STK!", pbk to "PBK!")
|
||||||
assertEquals("STK!", x[stk])
|
assertEquals("STK!", x[stk])
|
||||||
val s1 = SigningSecretKey(stk.keyBytes)
|
val s1 = SigningSecretKey(stk.keyBytes)
|
||||||
assertEquals(stk, s1)
|
assertEquals(stk, s1)
|
||||||
@ -52,7 +52,7 @@ class KeysTest {
|
|||||||
fun testNonDeterministicSeals() = runTest {
|
fun testNonDeterministicSeals() = runTest {
|
||||||
initCrypto()
|
initCrypto()
|
||||||
val data = "Welcome to the crazy new world!".encodeToUByteArray()
|
val data = "Welcome to the crazy new world!".encodeToUByteArray()
|
||||||
val (sk,_) = SigningSecretKey.generatePair()
|
val (sk, _) = SigningSecretKey.generatePair()
|
||||||
val t = now()
|
val t = now()
|
||||||
val s1 = Seal.create(sk, data, createdAt = t)
|
val s1 = Seal.create(sk, data, createdAt = t)
|
||||||
val s2 = Seal.create(sk, data, createdAt = t)
|
val s2 = Seal.create(sk, data, createdAt = t)
|
||||||
@ -60,11 +60,11 @@ class KeysTest {
|
|||||||
val s3 = Seal.create(sk, data, createdAt = t, nonDeterministic = true)
|
val s3 = Seal.create(sk, data, createdAt = t, nonDeterministic = true)
|
||||||
val s4 = Seal.create(sk, data, createdAt = t, nonDeterministic = true)
|
val s4 = Seal.create(sk, data, createdAt = t, nonDeterministic = true)
|
||||||
|
|
||||||
for( seal in listOf(s1,s2,s3,s4)) {
|
for (seal in listOf(s1, s2, s3, s4)) {
|
||||||
assertTrue { seal.isValid(data) }
|
assertTrue { seal.isValid(data) }
|
||||||
assertTrue { Seal.unpack(seal.packed).isValid(data) }
|
assertTrue { Seal.unpack(seal.packed).isValid(data) }
|
||||||
}
|
}
|
||||||
assertFalse { s2bad.isValid(data)}
|
assertFalse { s2bad.isValid(data) }
|
||||||
assertContentEquals(s1.packed, s2.packed)
|
assertContentEquals(s1.packed, s2.packed)
|
||||||
assertFalse { s1.packed contentEquals s3.packed }
|
assertFalse { s1.packed contentEquals s3.packed }
|
||||||
assertFalse { s4.packed contentEquals s3.packed }
|
assertFalse { s4.packed contentEquals s3.packed }
|
||||||
@ -97,7 +97,7 @@ class KeysTest {
|
|||||||
assertContentEquals(src, k1.decryptWithNonce(k1.encryptWithNonce(src, nonce), nonce))
|
assertContentEquals(src, k1.decryptWithNonce(k1.encryptWithNonce(src, nonce), nonce))
|
||||||
assertThrows<DecryptionFailedException> {
|
assertThrows<DecryptionFailedException> {
|
||||||
val n2 = nonce.copyOf()
|
val n2 = nonce.copyOf()
|
||||||
n2[4] = n2[4].inv()
|
n2[4] = n2[4].inv()
|
||||||
k1.decryptWithNonce(k1.encryptWithNonce(src, nonce), n2)
|
k1.decryptWithNonce(k1.encryptWithNonce(src, nonce), n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +173,7 @@ class KeysTest {
|
|||||||
val (sk0, pk0) = Asymmetric.generateKeys()
|
val (sk0, pk0) = Asymmetric.generateKeys()
|
||||||
|
|
||||||
// println(sk0.publicKey)
|
// println(sk0.publicKey)
|
||||||
val j = Json { prettyPrint = true}
|
val j = Json { prettyPrint = true }
|
||||||
|
|
||||||
val sk1 = j.decodeFromString<SecretKey>(j.encodeToString(sk0))
|
val sk1 = j.decodeFromString<SecretKey>(j.encodeToString(sk0))
|
||||||
assertEquals(sk0, sk1)
|
assertEquals(sk0, sk1)
|
||||||
@ -274,11 +274,11 @@ class KeysTest {
|
|||||||
assertContentEquals(k.verifyingKey.keyBytes, dk2.id.binaryTag.take(32).toUByteArray())
|
assertContentEquals(k.verifyingKey.keyBytes, dk2.id.binaryTag.take(32).toUByteArray())
|
||||||
assertContentEquals(k.verifyingKey.keyBytes, dk1.id.binaryTag.take(32).toUByteArray())
|
assertContentEquals(k.verifyingKey.keyBytes, dk1.id.binaryTag.take(32).toUByteArray())
|
||||||
// and restored from id should be the same:
|
// and restored from id should be the same:
|
||||||
assertEquals( k.verifyingKey, dk2.id.id.asVerifyingKey)
|
assertEquals(k.verifyingKey, dk2.id.id.asVerifyingKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun multiKeyTestSom() = runTest {
|
fun multiKeyTestSome() = runTest {
|
||||||
initCrypto()
|
initCrypto()
|
||||||
val k1 = SigningSecretKey.new()
|
val k1 = SigningSecretKey.new()
|
||||||
val k2 = SigningSecretKey.new()
|
val k2 = SigningSecretKey.new()
|
||||||
@ -301,7 +301,7 @@ class KeysTest {
|
|||||||
println(pack(mk23).toDump())
|
println(pack(mk23).toDump())
|
||||||
println(pack(mk23).size)
|
println(pack(mk23).size)
|
||||||
|
|
||||||
val smk23: Multikey = Multikey.someOf(2, k1.verifyingKey, k2.verifyingKey, k3.verifyingKey)
|
val smk23: Multikey = Multikey.someOf(2, k1.verifyingKey, k2.verifyingKey, k3.verifyingKey)
|
||||||
// val smk13: Multikey = Multikey.Keys(1, setOf(k1.verifyingKey, k2.verifyingKey, k3.verifyingKey))
|
// val smk13: Multikey = Multikey.Keys(1, setOf(k1.verifyingKey, k2.verifyingKey, k3.verifyingKey))
|
||||||
|
|
||||||
assertTrue { smk23.check(k1.verifyingKey, k2.verifyingKey, k4.verifyingKey) }
|
assertTrue { smk23.check(k1.verifyingKey, k2.verifyingKey, k4.verifyingKey) }
|
||||||
@ -342,6 +342,22 @@ class KeysTest {
|
|||||||
assertFalse { s3.check(k1.verifyingKey) }
|
assertFalse { s3.check(k1.verifyingKey) }
|
||||||
assertFalse { s3.check(k2.verifyingKey) }
|
assertFalse { s3.check(k2.verifyingKey) }
|
||||||
assertFalse { s3.check(k1.verifyingKey, k4.verifyingKey) }
|
assertFalse { s3.check(k1.verifyingKey, k4.verifyingKey) }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
|
fun multiKeyTestAny() = runTest {
|
||||||
|
initCrypto()
|
||||||
|
val k1 = SigningSecretKey.new()
|
||||||
|
val k2 = SigningSecretKey.new()
|
||||||
|
val k3 = SigningSecretKey.new()
|
||||||
|
val k4 = SigningSecretKey.new()
|
||||||
|
val k5 = SigningSecretKey.new()
|
||||||
|
// val k6 = SigningSecretKey.new()
|
||||||
|
val mk: Multikey = Multikey.AnyKey
|
||||||
|
assertTrue { mk.check(k1.verifyingKey) }
|
||||||
|
assertTrue { mk.check(k2.verifyingKey) }
|
||||||
|
assertTrue { mk.check(k3.verifyingKey) }
|
||||||
|
assertTrue { mk.check(k4.verifyingKey) }
|
||||||
|
assertTrue { mk.check(k5.verifyingKey) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user