-
Notifications
You must be signed in to change notification settings - Fork 3
Introduce KeyChain and refactor cryptographic traits
#40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -53,28 +53,48 @@ object CipherText: | |||||
| def unapplySeq(cipherText: CipherText): Option[Seq[IArray[Byte]]] = | ||||||
| Option(cipherText.split) | ||||||
|
|
||||||
| /* | ||||||
| type Encrypt = PlainText => CipherText | ||||||
| object Encrypt: | ||||||
| val Empty: Encrypt = _ ⇒ CipherText.Empty | ||||||
|
|
||||||
| type Decrypt = CipherText => Try[PlainText] | ||||||
| type Decrypt = (Crypto[?]) ?=> CipherText => Try[PlainText] | ||||||
| object Decrypt: | ||||||
| val Empty: Decrypt = _ ⇒ Success(PlainText.empty) | ||||||
|
|
||||||
| type Sign = PlainText => Array[Byte] | ||||||
| type Verify = Array[Byte] => Boolean | ||||||
|
|
||||||
| trait Codec[V]: | ||||||
| */ | ||||||
| trait Encrypt[K]: | ||||||
| def encrypt(plainText: PlainText)(using K): CipherText | ||||||
| trait Decrypt[K]: | ||||||
| def decrypt(cipherText: CipherText)(using K): Try[PlainText] | ||||||
| trait Sign[K]: | ||||||
| def sign(plainText: PlainText)(using K): Signature | ||||||
| trait Verify[K]: | ||||||
| def verify(signature: Signature, plainText: PlainText)(using K): Boolean | ||||||
|
|
||||||
| sealed trait Crypto[EK, DK] extends Encrypt[EK] with Decrypt[DK] | ||||||
| object Crypto: | ||||||
| trait Symmetric[Key] extends Crypto[Key, Key] | ||||||
| trait Asymmetric[PublicKey, PrivateKey] | ||||||
| extends Crypto[PublicKey, PrivateKey] | ||||||
| with Sign[PrivateKey] | ||||||
| with Verify[PublicKey] | ||||||
|
|
||||||
| sealed trait Encode[V]: | ||||||
| def encode(v: V, manifest: Manifest = Manifest.empty): PlainText | ||||||
| sealed trait Decode[V]: | ||||||
| def decode(plainText: PlainText): Try[V] | ||||||
|
|
||||||
| trait Codec[V] extends Encode[V] with Decode[V] | ||||||
| /* | ||||||
| object Codec: | ||||||
| trait Companion: | ||||||
| extension [V: Codec](v: V) | ||||||
| def encoded: PlainText = summon[Codec[V]].encode(v) | ||||||
| extension [V: Codec](plainText: PlainText) | ||||||
| def decoded: Try[V] = summon[Codec[V]].decode(plainText) | ||||||
|
|
||||||
| */ | ||||||
| given Codec[Nothing]: | ||||||
| def encode(v: Nothing, manifest: Manifest): PlainText = | ||||||
| PlainText(IArray.emptyByteIArray, manifest) | ||||||
|
|
@@ -85,10 +105,11 @@ given Codec[Nothing]: | |||||
| ) | ||||||
| ) | ||||||
|
|
||||||
| extension [V: Codec](value: V) | ||||||
| def encrypted(using encrypt: Encrypt): Encrypted[V] = | ||||||
| extension [K: Encrypt, V: Encode](value: V) | ||||||
| def encrypted: K ?=> Encrypted[V] = { | ||||||
| Encrypted(value, Manifest.empty) | ||||||
| def encrypted(manifest: Manifest)(using encrypt: Encrypt): Encrypted[V] = | ||||||
| } | ||||||
| def encrypted(manifest: Manifest): K ?=> Encrypted[V] = | ||||||
| Encrypted(value, manifest) | ||||||
|
|
||||||
| extension (array: Array[Byte]) | ||||||
|
|
@@ -127,7 +148,7 @@ extension (iarrayObject: IArray.type) | |||||
| case (buffer, bytes) => buffer.nextBytes(bytes.mutable) | ||||||
| buffer.array().immutable | ||||||
|
|
||||||
| sealed abstract class Cryptic[V: Codec]: | ||||||
| sealed abstract class Cryptic[V]: | ||||||
| import Cryptic.* | ||||||
|
|
||||||
| /** Decrypts the data using the provided given decryption mechanism. | ||||||
|
|
@@ -138,7 +159,7 @@ sealed abstract class Cryptic[V: Codec]: | |||||
| * Returns a Try instance containing the decrypted value of type V if | ||||||
| * successful, or a Failure if the decryption fails. | ||||||
| */ | ||||||
| def decrypted(using decrypt: Decrypt): Try[V] | ||||||
| def decrypted[K]: Decrypt[K] ?=> Try[V] | ||||||
|
|
||||||
| /** Attempts to retrieve the decrypted value. If decryption fails or if the | ||||||
| * value is not present, it returns the provided default value. | ||||||
|
|
@@ -150,9 +171,9 @@ sealed abstract class Cryptic[V: Codec]: | |||||
| * @return | ||||||
| * the decrypted value if successful, otherwise the default value | ||||||
| */ | ||||||
| @inline final def decryptedOrElse[W >: V](default: => W)(using | ||||||
| decrypt: Decrypt | ||||||
| ): W = decrypted.getOrElse(default) | ||||||
| @inline final def decryptedOrElse[K, W >: V]( | ||||||
| default: => W | ||||||
| ): Decrypt[K] ?=> W = decrypted.getOrElse(default) | ||||||
|
|
||||||
| /** Transforms the current operation by applying a function to its result. | ||||||
| * | ||||||
|
|
@@ -165,7 +186,7 @@ sealed abstract class Cryptic[V: Codec]: | |||||
| * A new operation representing the transformation of the original | ||||||
| * operation. | ||||||
| */ | ||||||
| @inline final def map[W: Codec](f: V => W): Operation[W] = | ||||||
| @inline final def map[W: Encode](f: V => W): Decode[V] ?=> Operation[W] = | ||||||
| Mapped(this, f) | ||||||
|
|
||||||
| /** Transforms this `Operation[V]` into an `Operation[W]` by applying the | ||||||
|
|
@@ -179,7 +200,9 @@ sealed abstract class Cryptic[V: Codec]: | |||||
| * an `Operation[W]` resulting from applying the function `f` to each value | ||||||
| * of type `V` produced by this `Operation` | ||||||
| */ | ||||||
| @inline final def flatMap[W: Codec](f: V => Cryptic[W]): Operation[W] = | ||||||
| @inline final def flatMap[W: Encode]( | ||||||
| f: V => Cryptic[W] | ||||||
| ): Decode[V] ?=> Operation[W] = | ||||||
| FlatMapped(this, f) | ||||||
|
|
||||||
| /* | ||||||
|
|
@@ -231,8 +254,8 @@ sealed abstract class Cryptic[V: Codec]: | |||||
| * A new Operation instance representing the original or the alternative | ||||||
| * operation. | ||||||
| */ | ||||||
| @inline final def orElse[W >: V: Codec]( | ||||||
| alternative: => Cryptic[W] | ||||||
| @inline final def orElse[W >: V: Encode]( | ||||||
| alternative: Cryptic[W] | ||||||
| ): Operation[W] = | ||||||
| new OrElsed(this, alternative) | ||||||
| object Cryptic: | ||||||
|
|
@@ -246,26 +269,25 @@ object Cryptic: | |||||
| CipherText | ||||||
| } | ||||||
| import Encrypted.* | ||||||
| sealed abstract class Operation[V: Codec] extends Cryptic[V]: | ||||||
| def run(using encrypt: Encrypt, decrypt: Decrypt): Try[Encrypted[V]] | ||||||
| sealed abstract class BinaryOperation[V: Codec, W: Codec] | ||||||
| extends Operation[W]: | ||||||
| override def run(using | ||||||
| encrypt: Encrypt, | ||||||
| decrypt: Decrypt | ||||||
| ): Try[Encrypted[W]] = | ||||||
| decrypted.map(w => Encrypted(encrypt(summon[Codec[W]].encode(w)))) | ||||||
| final case class Mapped[V: Codec, W: Codec]( | ||||||
| sealed abstract class Operation[V] extends Cryptic[V]: | ||||||
| def run[DK: Decrypt, EK: Encrypt]: Try[Encrypted[V]] | ||||||
| sealed abstract class BinaryOperation[V, W] extends Operation[W]: | ||||||
| override def run[EK: Encrypt, DK: Decrypt] | ||||||
| : (EK, DK, Encode[W]) ?=> Try[Encrypted[W]] = | ||||||
| decrypted.map(w => | ||||||
| Encrypted(summon[Encrypt[EK]].encrypt(summon[Encode[W]].encode(w))) | ||||||
| ) | ||||||
| final case class Mapped[V: Decode, W: Encode]( | ||||||
| src: Cryptic[V], | ||||||
| f: V => W | ||||||
| ) extends BinaryOperation[V, W]: | ||||||
| override def decrypted(using decrypt: Decrypt): Try[W] = | ||||||
| override def decrypted[DK: Decrypt]: Decrypt[DK] ?=> Try[W] = | ||||||
| src.decrypted.map(f) | ||||||
| final case class FlatMapped[V: Codec, W: Codec]( | ||||||
| final case class FlatMapped[V: Decode, W: Encode]( | ||||||
| src: Cryptic[V], | ||||||
| f: V => Cryptic[W] | ||||||
| ) extends BinaryOperation[V, W]: | ||||||
| override def decrypted(using decrypt: Decrypt): Try[W] = | ||||||
| override def decrypted[DK: Decrypt]: Decrypt[DK] ?=> Try[W] = | ||||||
| src.decrypted.flatMap[W](v => f(v).decrypted) | ||||||
| /* | ||||||
| final case class Flattened[V : Codec, W : Codec](src: Cryptic[V])(using ev: V <:< Cryptic[W]) | ||||||
|
|
@@ -275,14 +297,13 @@ object Cryptic: | |||||
| override def decrypted(using decrypt: Decrypt): Try[W] = | ||||||
| src.decrypted.flatMap(v => ev(v).decrypted) | ||||||
| */ | ||||||
| final case class Filtered[V: Codec](src: Cryptic[V], pred: V => Boolean) | ||||||
| final case class Filtered[V](src: Cryptic[V], pred: V => Boolean) | ||||||
| extends Operation[V]: | ||||||
| override def run(using | ||||||
| encrypt: Encrypt, | ||||||
| decrypt: Decrypt | ||||||
| ): Try[Encrypted[V]] = src.decrypted.map[Encrypted[V]]: v => | ||||||
| if pred(v) then v.encrypted else empty[V] | ||||||
| override def decrypted(using decrypt: Decrypt): Try[V] = | ||||||
| override def run[EK: Encrypt, DK: Decrypt] | ||||||
| : (EK, DK, Encode[V]) ?=> Try[Encrypted[V]] = | ||||||
| src.decrypted.map: v => | ||||||
| if pred(v) then v.encrypted else empty[V] | ||||||
| override def decrypted[DK: Decrypt]: Decrypt[DK] ?=> Try[V] = | ||||||
| src.decrypted.flatMap: v => | ||||||
| if pred(v) then Success(v) | ||||||
| else | ||||||
|
|
@@ -291,19 +312,17 @@ object Cryptic: | |||||
| "decrypted called on filtered empty" | ||||||
| ) | ||||||
| ) | ||||||
| final case class Collected[V: Codec, W: Codec]( | ||||||
| final case class Collected[V, W]( | ||||||
|
||||||
| final case class Collected[V, W]( | |
| final case class Collected[V: Decode, W: Encode]( |
Copilot
AI
Aug 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The OrElsed class requires Encode[W] context bound but also needs Decode[V] for the decrypted method to work properly. The missing Decode[V] constraint will cause compilation errors.
| final class OrElsed[V, W >: V: Encode]( | |
| final class OrElsed[V: Decode, W >: V: Encode]( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
Filteredclass is missing required context bounds. It needsEncode[V]for therunmethod andDecode[V]for thedecryptedmethod to compile properly.