diff --git a/Sources/HomomorphicEncryption/Bfv/Bfv.swift b/Sources/HomomorphicEncryption/Bfv/Bfv.swift index fc7cc4bf..7619a3ba 100644 --- a/Sources/HomomorphicEncryption/Bfv/Bfv.swift +++ b/Sources/HomomorphicEncryption/Bfv/Bfv.swift @@ -1,4 +1,4 @@ -// Copyright 2024-2025 Apple Inc. and the Swift Homomorphic Encryption project authors +// Copyright 2024-2026 Apple Inc. and the Swift Homomorphic Encryption project authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -326,12 +326,14 @@ public enum Bfv: HeScheme { guard var result = ciphertexts.first else { preconditionFailure("Empty ciphertexts") } + precondition(ciphertexts.allSatisfy { $0.polys.count == result.polys.count }, + "All ciphertexts must have the same polynomial count") let poly = result.polys[0] let maxProductCount = poly.context.maxLazyProductAccumulationCount() var accumulator = Array( repeating: Array2d(data: Array(repeating: T.DoubleWidth(0), count: poly.data.count), rowCount: poly.moduli.count, columnCount: poly.degree), - count: Bfv.freshCiphertextPolyCount) + count: result.polys.count) var reduceCount = 0 for (ciphertext, plaintext) in zip(ciphertexts, plaintexts) { diff --git a/Sources/_TestUtilities/HeApiTestUtils.swift b/Sources/_TestUtilities/HeApiTestUtils.swift index 5ce91bd8..9f9ba034 100644 --- a/Sources/_TestUtilities/HeApiTestUtils.swift +++ b/Sources/_TestUtilities/HeApiTestUtils.swift @@ -1,4 +1,4 @@ -// Copyright 2024-2025 Apple Inc. and the Swift Homomorphic Encryption project authors +// Copyright 2024-2026 Apple Inc. and the Swift Homomorphic Encryption project authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -685,6 +685,70 @@ public enum HeAPITestHelpers { } } + /// Testing CT-PT inner product with 3-polynomial ciphertexts (unrelinearized). + /// This specifically tests that inner product works with ciphertexts that have more than 2 polynomials. + @inlinable + public static func schemeThreePolyCiphertextPlaintextInnerProductTest( + context: Scheme.Context, + scheme _: Scheme.Type) async throws + { + guard context.supportsSimdEncoding, context.supportsEvaluationKey else { + return + } + + let testEnv = try TestEnv(context: context, format: .simd, relinearizationKey: false) + + // Create a 3-polynomial ciphertext by multiplying two ciphertexts without relinearization + let ciphertext1 = testEnv.ciphertext1 + let ciphertext2 = testEnv.ciphertext2 + let threePolyCiphertext = try await ciphertext1 * ciphertext2 + + // Verify it has 3 polynomials + guard threePolyCiphertext.polys.count == 3 else { + // For schemes that don't produce 3-poly ciphertexts, skip this test + return + } + + // Convert to Eval format for inner product + let threePolyEvalCiphertext = try await threePolyCiphertext.convertToEvalFormat() + + // Create a vector of this 3-poly ciphertext + let count = 5 + let ciphertexts = Array(repeating: threePolyEvalCiphertext, count: count) + + // Create random plaintext data + let plaintextData: [[Scheme.Scalar]] = (0..(context: Scheme.Context, diff --git a/Tests/HomomorphicEncryptionTests/HeAPITests.swift b/Tests/HomomorphicEncryptionTests/HeAPITests.swift index eef308a0..98afaa11 100644 --- a/Tests/HomomorphicEncryptionTests/HeAPITests.swift +++ b/Tests/HomomorphicEncryptionTests/HeAPITests.swift @@ -1,4 +1,4 @@ -// Copyright 2024-2025 Apple Inc. and the Swift Homomorphic Encryption project authors +// Copyright 2024-2026 Apple Inc. and the Swift Homomorphic Encryption project authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -203,6 +203,7 @@ struct HeAPITests { try await HeAPITestHelpers.schemeCiphertextPlaintextMultiplySubtractPlainTest(context: context, scheme: Bfv.self) try await HeAPITestHelpers.schemeCiphertextCiphertextMultiplicationTest(context: context, scheme: Bfv.self) try await HeAPITestHelpers.schemeCiphertextPlaintextInnerProductTest(context: context, scheme: Bfv.self) + try await HeAPITestHelpers.schemeThreePolyCiphertextPlaintextInnerProductTest(context: context, scheme: Bfv.self) try await HeAPITestHelpers.schemeCiphertextCiphertextInnerProductTest(context: context, scheme: Bfv.self) try await HeAPITestHelpers.schemeCiphertextMultiplyAddTest(context: context, scheme: Bfv.self) try await HeAPITestHelpers.schemeCiphertextNegateTest(context: context, scheme: Bfv.self)