0.5.8-SNAPSHOT: Multikeys

This commit is contained in:
Sergey Chernov 2024-09-15 12:29:04 +03:00
parent 8e652e0421
commit 1191de284e
2 changed files with 31 additions and 3 deletions

View File

@ -2,6 +2,7 @@ package net.sergeych.crypto2
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import net.sergeych.bipack.Unsigned
import net.sergeych.crypto2.Multikey.Companion.allOf
import net.sergeych.crypto2.Multikey.Companion.allOfMultikeys
import net.sergeych.crypto2.Multikey.Companion.anyOf
@ -70,7 +71,11 @@ sealed class Multikey {
*/
@Serializable
@SerialName("k")
class Keys internal constructor(val requiredMinimum: Int, val validKeys: Set<VerifyingPublicKey>) : Multikey() {
class Keys internal constructor(
@Unsigned
val requiredMinimum: Int,
val validKeys: Set<VerifyingPublicKey>
) : Multikey() {
override fun check(keys: Iterable<VerifyingPublicKey>): Boolean {
var matches = 0
for( signer in keys ) {
@ -88,7 +93,11 @@ sealed class Multikey {
*/
@Serializable
@SerialName("n")
class SomeOf internal constructor(val requiredMinimum: Int,val validKeys: List<Multikey>) : Multikey() {
class SomeOf internal constructor(
@Unsigned
val requiredMinimum: Int,
val validKeys: List<Multikey>
) : Multikey() {
override fun check(keys: Iterable<VerifyingPublicKey>): Boolean {
var matches = 0
for( k in validKeys ) {

View File

@ -6,6 +6,7 @@ import kotlinx.serialization.Transient
import net.sergeych.bipack.BipackDecoder
import net.sergeych.bipack.BipackEncoder
import net.sergeych.bipack.decodeFromBipack
import net.sergeych.utools.pack
/**
* Multi-signed data box. Do not use the constructori directly, use [SealedBox.create]
@ -60,7 +61,7 @@ class SealedBox(
* Add expiring seal, otherwise use [plus]. Overrides exising seal for [key]
* if present:
*/
fun addSeal(key: SigningKey, expiresAt: Instant): SealedBox {
fun addSeal(key: SigningKey, expiresAt: Instant?): SealedBox {
val filtered = seals.filter { it.publicKey != key.verifyingKey }
return SealedBox(message, filtered + key.seal(message, expiresAt), false)
}
@ -78,6 +79,11 @@ class SealedBox(
@Suppress("unused")
fun isSealedBy(multikey: Multikey) = multikey.check(signedByKeys)
/**
* Unpack bipack-encoded payload
*/
inline fun <reified T>unpack(): T = BipackDecoder.decode(message)
init {
if (seals.isEmpty()) throw IllegalArgumentException("there should be at least one seal")
if (checkOnInit) {
@ -102,6 +108,19 @@ class SealedBox(
return SealedBox(data, keys.map { it.seal(data) }, false)
}
/**
* Create a new instance serializing given data with Bipack and some
* keys. At least one key is required to disallow providing not-signed
* instances, e.g. [SealedBox] is guaranteed to be properly sealed when
* successfully instantiated.
*
* @param payload an object to serialize and sign
* @param keys a list of keys to sign with, should be at least one key.
* @throws IllegalArgumentException if keys are not specified.
*/
inline fun <reified T>new(payload: T,vararg keys: SigningKey): SealedBox =
create(pack(payload), *keys)
inline fun <reified T>encode(value: T, vararg keys: SigningKey): UByteArray =
create(BipackEncoder.encode(value).toUByteArray(), *keys).encoded