Skip to content
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

Adds PrivateNearestNeighborsSearchProtobuf with initial protos. #69

Merged
merged 1 commit into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 38 additions & 20 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,21 @@ let package = Package(
.library(
name: "HomomorphicEncryption",
targets: ["HomomorphicEncryption"]),
.library(
name: "HomomorphicEncryptionProtobuf",
targets: ["HomomorphicEncryptionProtobuf"]),
.library(
name: "PrivateInformationRetrieval",
targets: ["PrivateInformationRetrieval"]),
.library(
name: "PrivateInformationRetrievalProtobuf",
targets: ["PrivateInformationRetrievalProtobuf"]),
.library(
name: "PrivateNearestNeighborsSearch",
targets: ["PrivateNearestNeighborsSearch"]),
.library(
name: "HomomorphicEncryptionProtobuf",
targets: ["HomomorphicEncryptionProtobuf"]),
.library(
name: "PrivateInformationRetrievalProtobuf",
targets: ["PrivateInformationRetrievalProtobuf"]),
name: "PrivateNearestNeighborsSearchProtobuf",
targets: ["PrivateNearestNeighborsSearchProtobuf"]),
.executable(name: "PIRGenerateDatabase", targets: ["PIRGenerateDatabase"]),
.executable(name: "PIRProcessDatabase", targets: ["PIRProcessDatabase"]),
.executable(name: "PIRShardDatabase", targets: ["PIRShardDatabase"]),
Expand Down Expand Up @@ -102,6 +105,15 @@ let package = Package(
"HomomorphicEncryption",
],
swiftSettings: librarySettings),
.target(
name: "PrivateNearestNeighborsSearchProtobuf",
dependencies: ["PrivateNearestNeighborsSearch",
"HomomorphicEncryption",
"HomomorphicEncryptionProtobuf",
.product(name: "SwiftProtobuf", package: "swift-protobuf")],
exclude: ["generated/README.md", "protobuf_module_mappings.txtpb"],
swiftSettings: librarySettings),

.target(
name: "TestUtilities",
dependencies: [
Expand Down Expand Up @@ -149,33 +161,39 @@ let package = Package(
"TestUtilities",
], swiftSettings: executableSettings),
.testTarget(
name: "PrivateInformationRetrievalProtobufTests",
dependencies: [
"PrivateInformationRetrieval",
"PrivateInformationRetrievalProtobuf",
"TestUtilities",
], swiftSettings: executableSettings),
name: "PIRGenerateDatabaseTests",
dependencies: ["PIRGenerateDatabase",
"TestUtilities",
.product(name: "Numerics", package: "swift-numerics")], swiftSettings: executableSettings),
.testTarget(
name: "PIRProcessDatabaseTests",
dependencies: ["PIRProcessDatabase",
"TestUtilities",
.product(name: "Numerics", package: "swift-numerics")], swiftSettings: executableSettings),
.testTarget(
name: "PrivateInformationRetrievalTests",
dependencies: [
"PrivateInformationRetrieval", "TestUtilities",
.product(name: "Numerics", package: "swift-numerics"),
], swiftSettings: executableSettings),
.testTarget(
name: "PrivateInformationRetrievalProtobufTests",
dependencies: [
"PrivateInformationRetrieval",
"PrivateInformationRetrievalProtobuf",
"TestUtilities",
], swiftSettings: executableSettings),
.testTarget(
name: "PrivateNearestNeighborsSearchTests",
dependencies: [
"PrivateNearestNeighborsSearch", "HomomorphicEncryption", "TestUtilities",
], swiftSettings: executableSettings),
.testTarget(
name: "PIRGenerateDatabaseTests",
dependencies: ["PIRGenerateDatabase",
"TestUtilities",
.product(name: "Numerics", package: "swift-numerics")], swiftSettings: executableSettings),
.testTarget(
name: "PIRProcessDatabaseTests",
dependencies: ["PIRProcessDatabase",
"TestUtilities",
.product(name: "Numerics", package: "swift-numerics")], swiftSettings: executableSettings),
name: "PrivateNearestNeighborsSearchProtobufTests",
dependencies: [
"PrivateNearestNeighborsSearch",
"PrivateNearestNeighborsSearchProtobuf",
], swiftSettings: executableSettings),
])

// MARK: - Benchmarks
Expand Down
5 changes: 4 additions & 1 deletion Sources/HomomorphicEncryption/Array2d.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ extension Array2d {
indices.map { data[$0] }
}

package func transposed() -> Self {
/// Transposes the values.
/// - Returns: The transposed values.
@inlinable
public func transposed() -> Self {
var transposed = Self(
data: Array(repeating: T.zero, count: count),
rowCount: columnCount,
Expand Down
2 changes: 1 addition & 1 deletion Sources/HomomorphicEncryption/SerializedPlaintext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

/// Serialized ``Plaintext`` type.
public struct SerializedPlaintext: Hashable, Codable {
public struct SerializedPlaintext: Hashable, Codable, Sendable {
/// The serialized polynomial.
public let poly: [UInt8]

Expand Down
3 changes: 2 additions & 1 deletion Sources/HomomorphicEncryptionProtobuf/ConversionHe.swift
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ extension Apple_SwiftHomomorphicEncryption_V1_HeScheme {
extension HeScheme {
/// Converts the native object into a protobuf object.
/// - Returns: The converted protobuf object.
/// - Throws: Error upon unsupported object
/// - Throws: Error upon unsupported object.
public static func proto() throws -> Apple_SwiftHomomorphicEncryption_V1_HeScheme {
if Self.self is Bfv<UInt32>.Type || self is Bfv<UInt64>.Type {
return .bfv
Expand Down Expand Up @@ -364,6 +364,7 @@ extension Apple_SwiftHomomorphicEncryption_V1_EncryptionParameters {
extension EncryptionParameters {
/// Converts the native object into a protobuf object.
/// - Returns: The converted protobuf object.
/// - Throws: Error upon unsupported object.
public func proto() throws -> Apple_SwiftHomomorphicEncryption_V1_EncryptionParameters {
try Apple_SwiftHomomorphicEncryption_V1_EncryptionParameters.with { encParams in
encParams.polynomialDegree = UInt64(polyDegree)
Expand Down
9 changes: 3 additions & 6 deletions Sources/HomomorphicEncryptionProtobuf/generated/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@ See the [dependencies](../../../README.md#dependencies) for the swift-protobuf v

## Generate Swift files
To generate the Swift files:
1. Change directory to `<REPOSITORY_ROOT>/swift-homomorphic-encryption-protobuf`
2. Run the following commands:
1. Change directory to `<REPOSITORY_ROOT>`
2. Run
```sh
find apple/swift_homomorphic_encryption/v1/ -name "*.proto" -exec protoc --swift_opt=Visibility=Public --swift_opt=FileNaming=PathToUnderscores --swift_out ../Sources/HomomorphicEncryptionProtobuf/generated {} \;
./Utilities/generate-protobuf-files.sh
```

> [!NOTE]
> When updating the protobuf files, remember to also update files in [PrivateInformationRetrievalProtobuf](../../PrivateInformationRetrievalProtobuf/generated/README.md) as needed.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ extension Apple_SwiftHomomorphicEncryption_Api_V1_PIRResponse {
extension Response {
/// Converts the native object into a protobuf object.
/// - Returns: The converted protobuf object.
/// - Throws: Error upon unsupported object.
public func proto() throws -> Apple_SwiftHomomorphicEncryption_Api_V1_PIRResponse {
try Apple_SwiftHomomorphicEncryption_Api_V1_PIRResponse.with { pirResponse in
pirResponse.replies = try ciphertexts.map { reply in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ extension Apple_SwiftHomomorphicEncryption_Pir_V1_EncryptedIndices {
extension Query {
/// Converts the native object into a protobuf object.
/// - Returns: The converted protobuf object.
/// - Throws: Error upon unsupported object.
public func proto() throws -> Apple_SwiftHomomorphicEncryption_Pir_V1_EncryptedIndices {
try Apple_SwiftHomomorphicEncryption_Pir_V1_EncryptedIndices.with { encryptedIndices in
encryptedIndices.ciphertexts = try ciphertexts.map { ciphertext in
Expand Down
13 changes: 3 additions & 10 deletions Sources/PrivateInformationRetrievalProtobuf/generated/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,8 @@ See the [dependencies](../../../README.md#dependencies) for the swift-protobuf v
## Generate Swift files
To generate the Swift files:

1. Change directory to `<REPOSITORY_ROOT>/swift-homomorphic-encryption-protobuf`
2. Run the following commands:
1. Change directory to `<REPOSITORY_ROOT>`
2. Run
```sh
find apple/swift_homomorphic_encryption/pir/ apple/swift_homomorphic_encryption/api/ -name "*.proto" -exec protoc \
--swift_opt=ProtoPathModuleMappings=../Sources/PrivateInformationRetrievalProtobuf/protobuf_module_mappings.txtpb \
--swift_opt=Visibility=Public \
--swift_opt=FileNaming=PathToUnderscores \
--swift_out ../Sources/PrivateInformationRetrievalProtobuf/generated {} \;
./Utilities/generate-protobuf-files.sh
```

> [!NOTE]
> When updating the protobuf files, remember to also update files in [HomomorphicEncryptionProtobuf](../../HomomorphicEncryptionProtobuf/generated/README.md) as needed.
14 changes: 8 additions & 6 deletions Sources/PrivateNearestNeighborsSearch/CiphertextMatrix.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import HomomorphicEncryption

/// Stores a matrix of scalars as ciphertexts.
struct CiphertextMatrix<Scheme: HeScheme, Format: PolyFormat>: Equatable, Sendable {
/// Dimensions of the scalars.
public struct CiphertextMatrix<Scheme: HeScheme, Format: PolyFormat>: Equatable, Sendable {
/// Dimensions of the matrix.
@usableFromInline let dimensions: MatrixDimensions

/// Dimensions of the scalar matrix in a SIMD-encoded plaintext.
Expand Down Expand Up @@ -51,12 +51,14 @@ struct CiphertextMatrix<Scheme: HeScheme, Format: PolyFormat>: Equatable, Sendab

/// Creates a new ciphertexts matrix.
/// - Parameters:
/// - dimensions: Ciphertext matrix dimensions
/// - packing: The packing with which the data is stored
/// - ciphertexts: ciphertexts encrypting the data; must not be empty.
/// - dimensions: Ciphertext matrix dimensions.
/// - packing: The packing with which the data is stored.
/// - ciphertexts: Ciphertexts encrypting the data; must not be empty.
/// - Throws: Error upon failure to initialize the ciphertext matrix.
@inlinable
init(dimensions: MatrixDimensions, packing: MatrixPacking, ciphertexts: [Ciphertext<Scheme, Format>]) throws {
public init(dimensions: MatrixDimensions, packing: MatrixPacking,
ciphertexts: [Ciphertext<Scheme, Format>]) throws
{
guard let context = ciphertexts.first?.context else {
throw PnnsError.emptyCiphertextArray
}
Expand Down
89 changes: 89 additions & 0 deletions Sources/PrivateNearestNeighborsSearch/Config.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright 2024 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.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import HomomorphicEncryption

/// Metric for distances between vectors.
public enum DistanceMetric: CaseIterable, Codable, Equatable, Hashable, Sendable {
/// Cosine similarity.
case cosineSimilarity
}

/// Client configuration.
public struct ClientConfig<Scheme: HeScheme>: Codable, Equatable, Hashable, Sendable {
/// Encryption parameters.
public let encryptionParams: EncryptionParameters<Scheme>
/// Factor by which to scale floating-point entries before rounding to integers.
public let scalingFactor: Int
/// Packing for the query.
public let queryPacking: MatrixPacking
/// Number of entries in each vector vector.
public let vectorDimension: Int
/// Evaluation key configuration for nearest neighbors computation.
public let evaluationKeyConfig: EvaluationKeyConfiguration
/// Metric for distances between vectors.
public let distanceMetric: DistanceMetric
/// For plaintext CRT, the list of extra plaintext moduli.
///
/// The first plaintext modulus will be the one in ``ClientConfig/encryptionParams``.
public let extraPlaintextModuli: [Scheme.Scalar]

/// Creates a new ``ClientConfig``.
/// - Parameters:
/// - encryptionParams: Encryption parameters.
/// - scalingFactor: Factor by which to scale floating-point entries before rounding to integers.
/// - queryPacking: Packing for the query.
/// - vectorDimension: Number of entries in each vector vector.
/// - evaluationKeyConfig: Evaluation key configuration for nearest neighbors computation.
/// - distanceMetric: Metric for nearest neighbors computation
/// - extraPlaintextModuli: For plaintext CRT, the list of extra plaintext moduli. The first plaintext modulus
/// will be the one in ``ClientConfig/encryptionParams``.
public init(
encryptionParams: EncryptionParameters<Scheme>,
scalingFactor: Int,
queryPacking: MatrixPacking,
vectorDimension: Int,
evaluationKeyConfig: EvaluationKeyConfiguration,
distanceMetric: DistanceMetric,
extraPlaintextModuli: [Scheme.Scalar] = [])
{
self.encryptionParams = encryptionParams
self.scalingFactor = scalingFactor
self.queryPacking = queryPacking
self.vectorDimension = vectorDimension
self.evaluationKeyConfig = evaluationKeyConfig
self.distanceMetric = distanceMetric
self.extraPlaintextModuli = extraPlaintextModuli
}
}

/// Server configuration.
public struct ServerConfig<Scheme: HeScheme>: Codable, Equatable, Hashable, Sendable {
/// Configuration shared with the client.
public let clientConfig: ClientConfig<Scheme>
/// Packing for the plaintext database.
public let databasePacking: MatrixPacking

/// Creates a new ``ServerConfig``.
/// - Parameters:
/// - clientConfig: Configuration shared with the client.
/// - databasePacking: Packing for the plaintext database.
public init(
clientConfig: ClientConfig<Scheme>,
databasePacking: MatrixPacking)
{
self.clientConfig = clientConfig
self.databasePacking = databasePacking
}
}
48 changes: 48 additions & 0 deletions Sources/PrivateNearestNeighborsSearch/Database.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2024 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.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// One row in a nearest-neighbor search database.
public struct DatabaseRow: Codable, Equatable, Hashable, Sendable {
/// Unique identifier for the database entry.
public let entryID: UInt64

/// Metadata associated with the entry.
public let entryMetadata: [UInt8]

/// Vector for use in nearest neighbors computation.
public let vector: [Float]

/// Creates a new ``DatabaseRow``.
/// - Parameters:
/// - entryID: Unique identifier for the database entry.
/// - entryMetadata: Metadata associated with the entry.
/// - vector: Vector for use in nearest neighbors computation
public init(entryID: UInt64, entryMetadata: [UInt8], vector: [Float]) {
self.entryID = entryID
self.entryMetadata = entryMetadata
self.vector = vector
}
}

/// Database for nearest-neighbor search.
public struct Database: Codable, Equatable, Hashable, Sendable {
/// Rows in the database.
public let rows: [DatabaseRow]

/// Creates a new ``Database``.
/// - Parameter rows: Rows in the database.
public init(rows: [DatabaseRow]) {
self.rows = rows
}
}
19 changes: 13 additions & 6 deletions Sources/PrivateNearestNeighborsSearch/DotProduct.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,28 @@ import Foundation
/// Pre-computed values for matrix-vector multiplication using baby-step, giant-step algorithm.
///
/// - seealso: Section 6.3 of <https://eprint.iacr.org/2018/244.pdf>.
struct BabyStepGiantStep: Codable, Equatable, Hashable, Sendable {
public struct BabyStepGiantStep: Codable, Equatable, Hashable, Sendable {
/// Dimension of the vector; "D" in the reference.
let vectorDimension: Int
public let vectorDimension: Int
/// Baby step; "g" in the reference.
let babyStep: Int
public let babyStep: Int
/// Giant step; "h" in the reference.
let giantStep: Int
public let giantStep: Int

init(vectorDimension: Int, babyStep: Int, giantStep: Int) {
/// Creates a new ``BabyStepGiantStep``.
/// - Parameters:
/// - vectorDimension: Number of entries in each vector.
/// - babyStep: Baby step.
/// - giantStep: Giant step.
public init(vectorDimension: Int, babyStep: Int, giantStep: Int) {
self.vectorDimension = vectorDimension
self.babyStep = babyStep
self.giantStep = giantStep
}

init(vectorDimension: Int) {
/// Creates a new ``BabyStepGiantStep``.
/// - Parameter vectorDimension: Number of entries in each vector.
public init(vectorDimension: Int) {
let dimension = Int32(vectorDimension).nextPowerOfTwo
let babyStep = Int32(Double(dimension).squareRoot().rounded(.up))
let giantStep = dimension.dividingCeil(babyStep, variableTime: true)
Expand Down
2 changes: 1 addition & 1 deletion Sources/PrivateNearestNeighborsSearch/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import Foundation
import HomomorphicEncryption

/// Error type for ``PrivateNearestNeighborsSearch``.
enum PnnsError: Error, Equatable {
public enum PnnsError: Error, Equatable {
case emptyCiphertextArray
case emptyPlaintextArray
case invalidMatrixDimensions(_ dimensions: MatrixDimensions)
Expand Down
Loading
Loading