Skip to content

Commit

Permalink
{Ciphertext,Plaintext}Matrix deserialization
Browse files Browse the repository at this point in the history
  • Loading branch information
fboemer committed Aug 21, 2024
1 parent 7fd11dc commit 4536455
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Sources/HomomorphicEncryption/SerializedPlaintext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ extension Plaintext where Format == Eval {
/// - serialized: Serialized plaintext.
/// - context: Context to associate with the plaintext.
/// - moduliCount: Optional number of moduli to associate with the plaintext. If not set, the plaintext will have
/// the top-level ciphertext context with all themoduli.
/// the top-level ciphertext context with all the moduli.
/// - Throws: Error upon failure to deserialize.
public init(deserialize serialized: SerializedPlaintext, context: Context<Scheme>, moduliCount: Int? = nil) throws {
self.context = context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,25 @@ public struct SerializedCiphertextMatrix<Scalar: ScalarType>: Equatable, Sendabl
}

extension CiphertextMatrix {
/// Deserializes a serialized ciphertext matrix.
/// - Parameters:
/// - serialized: Serialized ciphertext matrix.
/// - context: Context to associate with the ciphertext matrix.
/// - moduliCount: Number of moduli in each serialized ciphertext. If not set, deserialization will use the
/// top-level ciphertext with all the moduli.
/// - Throws: Error upon failure to deserialize the ciphertext matrix.
@inlinable
public init(
deserialize serialized: SerializedCiphertextMatrix<Scheme.Scalar>,
context: Context<Scheme>,
moduliCount: Int? = nil) throws
{
let ciphertexts: [Ciphertext<Scheme, Format>] = try serialized.ciphertexts.map { serializedCiphertext in
try Ciphertext(deserialize: serializedCiphertext, context: context, moduliCount: moduliCount)
}
try self.init(dimensions: serialized.dimensions, packing: serialized.packing, ciphertexts: ciphertexts)
}

/// Serializes the ciphertext matrix.
/// - Parameter forDecryption: If true, serialization may use a more concise format, yielding ciphertexts which,
/// once deserialized, are only compatible with decryption, and not any other HE operations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,37 @@ extension PlaintextMatrix {
plaintexts: plaintexts.map { plaintext in plaintext.serialize() })
}
}

extension PlaintextMatrix where Format == Coeff {
/// Deserializes a plaintext matrix.
/// - Parameters:
/// - serialized: Serialized plaintext matrix.
/// - context: Context to associate with the plaintext matrix.
/// - Throws: Error upon failure to deserialize.
init(deserialize serialized: SerializedPlaintextMatrix, context: Context<Scheme>) throws {
let plaintexts = try serialized.plaintexts.map { serializedPlaintext in
try Plaintext(deserialize: serializedPlaintext, context: context)
}
try self.init(dimensions: serialized.dimensions, packing: serialized.packing, plaintexts: plaintexts)
}
}

extension PlaintextMatrix where Format == Eval {
/// Deserializes a plaintext matrix.
/// - Parameters:
/// - serialized: Serialized plaintext matrix.
/// - context: Context to associate with the plaintext matrix.
/// - moduliCount: Optional number of moduli to associate with each plaintext. If not set, each plaintext will
/// have the top-level ciphertext context with all the moduli.
/// - Throws: Error upon failure to deserialize.
init(
deserialize serialized: SerializedPlaintextMatrix,
context: Context<Scheme>,
moduliCount: Int? = nil) throws
{
let plaintexts = try serialized.plaintexts.map { serializedPlaintext in
try Plaintext(deserialize: serializedPlaintext, context: context, moduliCount: moduliCount)
}
try self.init(dimensions: serialized.dimensions, packing: serialized.packing, plaintexts: plaintexts)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,19 @@ class ConversionTests: XCTestCase {
values: scalars.flatMap { $0 })
let serialized = try plaintextMatrix.serialize()
XCTAssertEqual(try serialized.proto().native(), serialized)
let deserialized = try PlaintextMatrix(deserialize: serialized, context: context)
XCTAssertEqual(deserialized, plaintextMatrix)

for moduliCount in 1..<encryptionParams.coefficientModuli.count {
let evalPlaintextMatrix = try plaintextMatrix.convertToEvalFormat(moduliCount: moduliCount)
let serialized = try evalPlaintextMatrix.serialize()
XCTAssertEqual(try serialized.proto().native(), serialized)
let deserialized = try PlaintextMatrix(
deserialize: serialized,
context: context,
moduliCount: moduliCount)
XCTAssertEqual(deserialized, evalPlaintextMatrix)
}
}

try runTest(Bfv<UInt32>.self)
Expand Down Expand Up @@ -135,10 +148,25 @@ class ConversionTests: XCTestCase {
XCTAssertEqual(try serializedProto.native(), serialized)
let serializedSize = try serializedProto.serializedData().count

// TODO: test deserialization
let serializedForDecryption = try ciphertextMatrix.serialize(forDecryption: true)
let serializedForDecryptionSize = try serializedForDecryption.proto().serializedData().count
XCTAssertLessThanOrEqual(serializedForDecryptionSize, serializedSize)
let deserialized = try CiphertextMatrix<Scheme, Scheme.CanonicalCiphertextFormat>(
deserialize: serializedForDecryption,
context: context)
let decrypted = try deserialized.decrypt(using: secretKey)
XCTAssertEqual(decrypted, plaintextMatrix)

// Check Evaluation format
do {
let evalCiphertextMatrix = try ciphertextMatrix.convertToEvalFormat()
let serialized = try evalCiphertextMatrix.serialize()
XCTAssertEqual(try serialized.proto().native(), serialized)
let deserialized = try CiphertextMatrix<Scheme, Eval>(
deserialize: serialized,
context: context)
XCTAssertEqual(deserialized, evalCiphertextMatrix)
}
}

try runTest(Bfv<UInt32>.self)
Expand Down

0 comments on commit 4536455

Please sign in to comment.