Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
Path: blob/main/SignalServiceKit/Storage/AxolotlStore/PreKey.swift
1 views
//
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation
import GRDB

// TODO: Rename to PreKeyRecord when decodeDeprecatedPreKeys is turned off.
struct PreKey: Codable, FetchableRecord, PersistableRecord {
    static let databaseTableName: String = "PreKey"

    let rowId: Int64

    // The combination of these three fields must be UNIQUE -- keyIds must not
    // be reused within a namespace for a particular identity.

    let identity: OWSIdentity
    let namespace: Namespace
    let keyId: UInt32

    /// Is this a one-time or signed/last-resort pre key?
    ///
    /// "One-time" elliptic curve pre keys are stored in a separate namespace
    /// from "signed/last-resort" elliptic curve pre keys, so this value is
    /// redundant for elliptic curve pre keys. Both types of Kyber pre keys are
    /// stored in the same namespace, so this field is load bearing for them.
    let isOneTime: Bool

    /// The Unix timestamp when the key was replaced/became obsolete.
    let replacedAt: Int64?

    /// The key itself.
    let serializedRecord: Data?

    enum Namespace: Int64, Codable {
        case oneTime = 0
        case signed = 2
        case kyber = 1
    }

    enum CodingKeys: String, CodingKey {
        case rowId
        case identity
        case namespace
        case keyId
        case isOneTime
        case replacedAt
        case serializedRecord
    }

    static func baseQuery(in namespace: PreKey.Namespace, identity: OWSIdentity) -> QueryInterfaceRequest<PreKey> {
        return PreKey
            .filter(Column(PreKey.CodingKeys.identity.rawValue) == identity.rawValue)
            .filter(Column(PreKey.CodingKeys.namespace.rawValue) == namespace.rawValue)
    }
}