Skip to content

Commit

Permalink
Adds PrivateNearestNeighborsSearchProtobuf with initial protos. (#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
fboemer authored Aug 21, 2024
1 parent 0877744 commit 7fd11dc
Show file tree
Hide file tree
Showing 32 changed files with 2,065 additions and 70 deletions.
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

0 comments on commit 7fd11dc

Please sign in to comment.