1 Introduction

Program obfuscation is the process of making a program “unintelligible” to any polynomial-time entity while preserving its functionality. A formal study of program obfuscation was initiated more than a decade ago in the works of [10, 41]. In the recent years, this research area has seen renewed activity with the emergence of candidate constructions [30] for a type of general-purpose program obfuscation called indistinguishability obfuscation. This notion has proven to be both extremely useful and the most plausible of existing notions of program obfuscation.

A major limitation of existing notions of program obfuscation is that they only consider “static” programs that do not change with time. In reality, however, programs are rarely changeless. We typically alter programs over time, with patches (a.k.a updates) causing the programs to grow and vary, in response to demands for greater or new functionality. Can program obfuscation be adapted to deal with this reality? Specifically, can we obfuscate programs that evolve over time? The central intellectual and theoretical focus of this work is to answer this question.

Obfuscation for Evolving Software. A trivial solution to obfuscating evolving software would be to simply apply the obfuscator afresh to each updated version of a particular program. For example, to modify an obfuscation of a program M, the obfuscator may simply release a fresh obfuscation of \(M'\) where \(M'\) is the patched version of M. Note, however, that in this solution, the total communication complexity is at least \(|M|+|M'|\). In particular, this is the case even if the difference between the programs M and \(M'\) can be described in the form of a small patch P. In contrast, if M was not obfuscated, then we could modify it by simply communicating the patch P to a user, yielding a total communication complexity of only \(|M|+|P|\). Our goal is to develop a mechanism for program obfuscation that approximately preserves this communication complexity.

A bit more precisely, we define a notion of patchable obfuscation where, informally, there are four algorithms:

  • \(\mathsf {Obf}(M; r)\) taking as input a program M, and outputting an obfuscated program \(\langle {M}\rangle \), using randomness r.

  • \(\mathsf {GenPatch}(P; r, r')\) taking as input a patch P, and outputting an encoded patch \(\langle {P}\rangle \), using a combination of the original randomness r and new randomness \(r'\).

  • \(\mathsf {AppPatch}\left( \langle {M}\rangle ,\langle {P}\rangle \right) \) taking as input an obfuscated program \(\langle {M}\rangle \) and a patch encoding \(\langle {P}\rangle \), and outputting an obfuscated patched program \(\langle {M'=P(M)}\rangle \).

  • \(\mathsf {Eval}\left( \langle {M}\rangle ,x\right) \), taking as input an obfuscated program \(\langle {M}\rangle \) and an input x, and outputting the value \(y=M(x)\).

The key efficiency requirement is that the size of a patch encoding should not depend on the size of the original program M. Specifically, we want that \(|\langle {P}\rangle |={\mathrm {poly}}(|P|,\lambda )\), where \(\lambda \) is the security parameter.

Beyond this basic efficiency requirement, we also discuss some other important considerations w.r.t. patchable obfuscation.

I. No restriction on patches: An important consideration for patchable obfuscation is the class of patches that we wish to allow. Clearly, the larger the class of patches that we can support, the larger the potential application pool.

To maximize the applicability of our notion, we allow for arbitrary patches. Specifically, we model a patch P as a Turing machine that takes as input a program M (also modeled as a TM) and outputs a new program \(M'\). We allow for the unpatched program to grow in size after patching. That is, \(M'\) may be arbitrarily bigger than M.

II. Multiple patches: Another consideration is the number of patches that we wish to allow. In reality, it may be difficult to anticipate in advance how many times a program may need to be patched. Thus, we allow for an unlimited number of patches.

Specifically, we consider two modes of patching:

  • Sequential patching: Here, given an obfuscated program \(\langle {M_0}\rangle \) and a sequence of patch encodings \(\langle {P_1}\rangle ,\ldots ,\langle {P_n}\rangle \), one can apply the patches one-by-one, in order, to obtain \(\langle {M_1}\rangle ,\ldots ,\langle {M_n}\rangle \) s.t. \(M_i=P_i(M_{i-1})\).

  • Parallel patching: Here, given an obfuscated program \(\langle {M_0}\rangle \) and a sequence of patch encodings \(\langle {P_1}\rangle ,\ldots ,\langle {P_n}\rangle \), one can apply each patch to \(\langle {M}\rangle \), in parallel, to obtain \(\langle {M_1}\rangle ,\ldots ,\langle {M_n}\rangle \) s.t. \(M_i=P_i(M_0)\).

While sequential patching seems to better capture patching of programs in reality, as we discuss later, parallel patching also enables interesting applications of patchable obfuscation. Thus, we consider both patching modes in this work.

III. Support for multiple programs: So far, we have only discussed patching for a single obfuscated program. Now consider the case where an authority wishes to patch multiple obfuscated programs \(\langle {M_1}\rangle ,\ldots ,\langle {M_n}\rangle \). Such a situation often arises in practice where, for example, the programs \(M_1,\ldots ,M_n\) may correspond to different copies of the same core program M that are individualized to different users.

One approach to address this scenario would be to release a separate patch for every obfuscated program. In this case, however, the communication complexity grows linearly with the number of obfuscated programs and may quickly become prohibitive. Instead, we would like to build patchable obfuscation where the obfuscator can release one patch that can be applied to all of the obfuscated programs. We refer to this notion as multi-program patchable obfuscation.

How to Define Security? Of course, we must define security for patchable obfuscation. The natural direction is to start with a “base” notion of obfuscation (without patching) and extend it to the setting of patching. Our goal in this work is to obtain general positive results for patchable obfuscation. With this viewpoint, we identify indistinguishability obfuscation (\({i\mathcal {O}} \)) [10] as a natural choice for the base notion. Indeed, over the last few years, several general-purpose candidate constructions, (for example: [9, 22, 30]) for \({i\mathcal {O}} \) have been proposed, and no impossibility results are known. Furthermore, it was shown by [39] that \({i\mathcal {O}} \) is, in fact, “best-possible” obfuscation. \({i\mathcal {O}} \) has already enabled a long sequence of exciting applications (see e.g., [18, 28, 30, 51]) and its patchable analogue can be expected to find even more applications. Finally, we stress that while the security of \({i\mathcal {O}}\) remains an area of intense study, there are several known \({i\mathcal {O}}\) candidates and even universal \({i\mathcal {O}}\) candidates under well-studied assumptions [3].

In contrast, powerful (base) notions such as virtual black-box obfuscation [10] and differing-inputs obfuscation [1, 10, 20] have been shown to be impossible to realize for general functions [10, 13, 15, 31, 36]. This, in turn, means that patchable analogues of these notions are also impossible, in general. The notion of virtual grey-box obfuscation [14, 16] is impossible for general Turing Machines but seems to circumvent general impossibility results for circuits; however, it has found rather limited applicability so far.

In light of the above, in this work, we focus on patching in the context of \({i\mathcal {O}} \). We do believe that the study of patchable obfuscation for other base obfuscation notions (e.g., obfuscation in weaker adversarial models such as virtual black-box obfuscation in hardware token model [34, 38, 40] or generic model [9, 22]) is interesting, and we leave this study to future work. We remark that many of the ideas that we develop in this work should be more widely applicable to other notions of obfuscation, and are not intrinsically tied to \({i\mathcal {O}} \). As such, we envision these ideas to be portable to other notions of patchable obfuscation.

Patchable Indistinguishability Obfuscation. We develop a notion of patchable indistinguishability obfuscation (\(pa\text {-}{i\mathcal {O}} \)) that naturally extends the standard notion of \({i\mathcal {O}} \) to the setting of patching. Let us explain our notion for the single-program case, for sequential and parallel patches.

  • Sequential patches: Recall that \({i\mathcal {O}} \) security dictates that given two equivalent programs \(M_0\) and \(M_1\), obfuscations of \(M_0\) and \(M_1\) are computationally indistinguishable. In single-program \(pa\text {-}{i\mathcal {O}} \) for sequential patches, we require that given two equivalent programs \(M^0_0\) and \(M^0_1\) and a sequence of patch pairs \((P^1_0,P^1_1),\ldots ,(P^n_0,P^n_1)\) such that for every “level” \(i\in [n]\), the patched programs \(M^i_0=P^i_0(M^{i-1}_0)\) and \(M^i_1=P^i_1(M^{i-1}_1)\) are also equivalent, it should be hard to distinguish the tuples \((\langle {M^0_0}\rangle , \{\langle {P^i_0}\rangle \}_{i=1}^{n})\) and \((\langle {M^0_1}\rangle , \{\langle {P^i_1}\rangle \}_{i=1}^{n})\). Intuitively, the equivalence requirement at every patch level i rules out the trivial attack of using a splitting input for the patched programs \(M^i_0\) and \(M^i_1\) to distinguish the tuples.

  • Parallel patches: Single-program \(pa\text {-}{i\mathcal {O}} \) for parallel patches is defined similarly to above, except that here we require equivalence for the patched programs \(M^i_0=P^i_0(M^{0}_0)\) and \(M^i_1=P^i_1(M^{0}_1)\) at every (parallel) “branch” \(i\in [n]\).

A few remarks are in order: (1) It is easy to see that these definitions ensure patch hiding, which is crucial for some of the applications discussed later. (2) Our definitions naturally extend to multi-program \(pa\text {-}{i\mathcal {O}} \) where we start with multiple pairs of programs and equivalence is required for every pair at every level/branch. (3) We, in fact, consider adaptive security, where the adversary can make the patch queries in an adaptive fashion. See Sect. 2 for further details.

Implications of \(pa\text {-}{i\mathcal {O}} \) . We view \(pa\text {-}{i\mathcal {O}} \) as a powerful primitive that is likely to have several applications in the future. To see the power of \(pa\text {-}{i\mathcal {O}} \), it is instructive to first compare it with \({i\mathcal {O}} \). While \({i\mathcal {O}} \) exists if P=NP,Footnote 1 we show that multi-program \(pa\text {-}{i\mathcal {O}} \) for parallel patches implies secret-key functional encryption (FE) [19, 49, 50]. The construction is remarkably simple: let \(M_{f,x}\) be an input-less machine that simply outputs f(x). We construct an FE scheme as follows:

  • A secret key for a function f is computed as \(\langle {M_{f,\bot }}\rangle \), i.e., an obfuscation of \(M_{f,x}\) where \(x=\bot \).

  • Encryption of a message m corresponds to generating an encoding \(\langle {P_{m}}\rangle \) for a patch \(P_m\) that modifies \(M_{f,\bot }\) to \(M_{f,m}\).

  • Decryption simply corresponds to applying the patch encoding \(\langle {P_{m}}\rangle \) on \(\langle {M_{f,\bot }}\rangle \) to obtain \(\langle {M_{f,m}}\rangle \) and then evaluating it to obtain f(m).

Correctness and security of the construction follow in a straightforward manner from the correctness and security of \(pa\text {-}{i\mathcal {O}} \).Footnote 2 As we discuss later, the above basic idea can, in fact, be easily extended to multi-input functional encryption [35], yielding new results.

Alternate Viewpoint: Obfuscation with Private Homomorphism. Another way of looking at our notion of \(pa\text {-}{i\mathcal {O}} \) is as a form of \({i\mathcal {O}} \) that supports a kind of semi-private homomorphism: the generation of the patch encoding is private – requiring secret information that was used to obfuscate the original program – although the application of the patch encoding is public. Note that unlike encryption, for the security of obfuscation it is critical that this homomorphism is semi-private – if an adversary was allowed to use public information to arbitrarily modify the program underlying an obfuscation, this would trivially allow the adversary to break the security of the original obfuscated program. On the other hand, our notion of \(pa\text {-}{i\mathcal {O}} \) and the notion of fully homomorphic encryption [33] share a similarity in that they both require a form of compactness for the notions to be non-trivial.

1.1 Our Results

We state our results below.

I. Patchable Indistinguishability Obfuscation. In this work, we formalize the notion of patchable indistinguishability obfuscation. We focus on the setting where programs to be obfuscated and patched are described as Turing Machines.

Our main result is a construction of a multi-program \(pa\text {-}{i\mathcal {O}} \) scheme from sub-exponentially secure \({i\mathcal {O}} \) and sub-exponentially secure DDH.

Theorem 1

(Multi-program \(pa\text {-}{i\mathcal {O}} \) : Sequential patches). Assuming the existence of sub-exponentially secure \({i\mathcal {O}}\) for circuits, sub-exponentially secure DDH, there exists an adaptively secure multi-program \(pa\text {-}{i\mathcal {O}} \) scheme with unbounded sequential patches, for Turing Machines where the running time of the patch generation algorithm for a patch P is bounded by \(poly(\lambda ,|P|,\ell )\), where \(\lambda \) is a security parameter and \(\ell \) is a bound on the input size to the patched program.

Note that the runtime efficiency of the patch generation algorithm in the above theorem implies the necessary size efficiency for a patch encoding, namely, the size of the encoding of a patch P is bounded by \(poly(\lambda ,|P|,\ell )\).

We obtain the above result in two steps. Our first, and key step is to construct a single-program \(pa\text {-}{i\mathcal {O}} \) scheme for TMs which achieves the desired size efficiency for patches but requires a large state (proportional to the size of the TM being updated) as well as a large patch generation time.

Theorem 2

(Single-program \(pa\text {-}{i\mathcal {O}} \) : Sequential patches). Assuming the existence of sub-exponentially secure \({i\mathcal {O}}\) for circuits and sub-exponentially secure re-randomizable encryption schemes, there exists an adaptively secure single-program \(pa\text {-}{i\mathcal {O}} \) scheme with unbounded sequential patches, for Turing Machines where the size of the obfuscation of a patch P is bounded by \(poly(\lambda ,|P|,\ell )\), where \(\lambda \) is a security parameter and \(\ell \) is a bound on the input size to the patched program.

The main tool in our construction of single-program is an intermediate notion between \({i\mathcal {O}} \) and patchable \({i\mathcal {O}} \), that we refer to as splittable \({i\mathcal {O}}\). Very roughly, splittable \({i\mathcal {O}} \) allows us to reduce the problem of building patchable \({i\mathcal {O}} \) to the problem of building a patchable “encoding” scheme, a seemingly simpler problem. Very roughly, an obfuscation of M w.r.t. splittable \({i\mathcal {O}} \) consists of two parts: an encoding of M w.r.t. a patchable encoding scheme, and some auxiliary information z computed on the encoding as well as the secret key used to encode M. We place suitable efficiency and security requirements on the auxiliary information so as to allow us to transfer the patching property of the encoding scheme to the setting of \({i\mathcal {O}} \). We refer the reader to the technical overview section for further details on this notion.

Next, we devise a generic transformation from any such single-program \(pa\text {-}{i\mathcal {O}} \) scheme to a multi-program \(pa\text {-}{i\mathcal {O}} \) scheme with the aforementioned efficient patch generation property.

Theorem 3

(Single-program to Multi-program \(pa\text {-}{i\mathcal {O}} \) ). Assuming the existence of a succinct garbled TM scheme with persistent memory and a compact secret-key functional encryption scheme for general circuits, there exists a general transformation from any single-program \(pa\text {-}{i\mathcal {O}} \) scheme to a multi-program \(pa\text {-}{i\mathcal {O}} \) scheme for TMs with efficient patch generation.

In particular, when the underlying primitives are all adaptively secure, then the resulting multi-program \(pa\text {-}{i\mathcal {O}} \) scheme is also adaptively secure. An adaptively secure succinct garbled TM scheme with persistent memory is known from the works of [2, 24] based on sub-exponentially secure \({i\mathcal {O}} \) and DDH assumption, while a compact secret-key functional encryption scheme is known from \({i\mathcal {O}} \) for general circuits.

For the theorems above, we stress that we place no restrictions on the patches. A patch P can be an arbitrary Turing Machine that takes the original program description M as input, and outputs an arbitrary Turing Machine description \(M' = P(M)\) that can differ in arbitrary ways from M. In particular, the description size of P(M) can be any unbounded polynomial in the security parameter, and thus the program size can grow by arbitrary polynomial factors. Furthermore any unbounded polynomial number of patches can be applied sequentially, and the adversary can specify these patches adaptively given all obfuscated programs and patches constructed earlier.

Parallel Patching: We can obtain a similar result for multi-program \(pa\text {-}{i\mathcal {O}} \) in the context of parallel patches. This result follows the same approach as the case of sequential patches. The first step is to obtain single-program \(pa\text {-}{i\mathcal {O}} \) scheme with unbounded parallel patches and the second step is to obtain multi-program \(pa\text {-}{i\mathcal {O}} \) from single-program \(pa\text {-}{i\mathcal {O}} \). The construction of single-program \(pa\text {-}{i\mathcal {O}} \) with parallel patches will be identical to the one in the sequential patch setting. The transformation from single-program \(pa\text {-}{i\mathcal {O}} \) to multi-program \(pa\text {-}{i\mathcal {O}} \) is, however, different from the sequential setting to enable this transformation. Instead of using garbled TM scheme with persistent memory, we instead employ functional encryption for TMs [7, 37] scheme. Since the techniques employed in the parallel patch setting are similar to the sequential patch setting, we omit the transformation. We have the following theorem.

Theorem 4

(Multi-program \(pa\text {-}{i\mathcal {O}} \) : Parallel patches). Assuming the existence of sub-exponentially secure \({i\mathcal {O}}\) for circuits, sub-exponentially secure DDH, there exists an adaptively secure multi-program \(pa\text {-}{i\mathcal {O}} \) scheme with unbounded parallel patches, for Turing Machines where the running time of the patch generation algorithm for a patch P is bounded by \(poly(\lambda ,|P|,\ell )\), where \(\lambda \) is a security parameter and \(\ell \) is a bound on the input size to the patched program.

II. Applications of \(pa\text {-}{i\mathcal {O}} \) . We view \(pa\text {-}{i\mathcal {O}} \), and especially multi-program \(pa\text {-}{i\mathcal {O}} \) as a powerful primitive that is likely to have several applications in the future. As initial evidence of this, we demonstrate implications of \(pa\text {-}{i\mathcal {O}} \) to functional encryption and \({i\mathcal {O}} \) for TMs. In our eyes, the main appeal of these implications is their remarkable simplicity that highlights the potential of \(pa\text {-}{i\mathcal {O}} \) as a replacement for \({i\mathcal {O}} \) in cryptographic applications.

Multi-input FE for Unbounded Arity Functions: We first show that multi-program \(pa\text {-}{i\mathcal {O}} \) for parallel updates implies secret-key multi-input functional encryption (MIFE) [4, 21, 35] for unbounded arity functions. This implication follows from a straightforward extension of the \(pa\text {-}{i\mathcal {O}} \) to (single-input) FE implication discussed earlier.

Theorem 5

(Unbounded-Arity MIFE). Adaptively secure multi-program \(pa\text {-}{i\mathcal {O}} \) with unbounded parallel updates implies secret-key MIFE for unbounded arity functions with security against pre-ciphertext key queries.

Combining the above with Theorem 4, we obtain secret-key MIFE for unbounded arity functions from sub-exponentially secure \({i\mathcal {O}}\) for circuits, sub-exponentially secure DDH. Previously, this result was only known [8] from a knowledge assumption, namely public-coin differing-input obfuscation [42] and one-way functions.

FE for TMs with Unbounded Length Inputs: The following implication follows as a simple corollary of Theorem 5.

Theorem 6

(Unbounded-Input FE). Adaptively secure multi-program \(pa\text {-}{i\mathcal {O}} \) implies secret-key functional encryption for TMs with unbounded input length with security against pre-ciphertext key queries.

A construction of FE for TMs with unbounded input was recently given by [7] based on \({i\mathcal {O}}\). We emphasize that our construction from multi-program \(pa\text {-}{i\mathcal {O}} \) is extremely simple, in contrast to the involved construction of [7].

We now discuss implications of \(pa\text {-}{i\mathcal {O}} \) to \({i\mathcal {O}} \) for TMs. We first recall that all recent progress on achieving \({i\mathcal {O}}\) for TMs/RAMs [17, 25,26,27, 44] from \({i\mathcal {O}}\) for circuits has required a polynomial bound \(\ell \) to be placed on the input length to the obfuscated Turing Machine. We share this need for a polynomial bound \(\ell \) on the input size, and the size of our obfuscated patches do grow with this bound. Indeed, if we could remove this restriction, then we would show how to bootstrap \({i\mathcal {O}}\) for circuits to \({i\mathcal {O}}\) for Turing Machines without any input length restriction from \({i\mathcal {O}}\) for circuits – this remains a major open question. Achieving \({i\mathcal {O}}\) for Turing Machines without any input length restriction currently requires strong assumption such as output-compressing randomized encodings [45] or knowledge-type assumptions such as public-coin d \({i\mathcal {O}}\)  [1, 20, 42]. We do not know how to achieve these objects using only \({i\mathcal {O}}\) for circuits.

So far, in our definition of \(pa\text {-}{i\mathcal {O}} \), we have only considered “single-use” patches. More accurately, in our definition of single-program (resp., multi-program) \(pa\text {-}{i\mathcal {O}} \) for sequential patching, the \(i^{th}\) patch \(P_i\) can only be applied to the updated machine (resp., machines) at level \(i-1\). As we discuss now, such “single-use” patches are, in fact, inherent given the current state of art in \({i\mathcal {O}} \) for TMs.

In particular, is not difficult to see that single-program \(pa\text {-}{i\mathcal {O}} \) with reusable patches (i.e., where a patch P is not tied to any “level” and can be applied an arbitrary number of times, to any machine) in fact, implies \({i\mathcal {O}} \) for TMs with unbounded length inputs. The construction is extremely simple: let \(M_{x}\) be a family of (input-less) machines parameterized by strings x of arbitrary length, where every machine simply outputs M(x). Obfuscation of a TM M consists of an obfuscation of a machine \(M_{\bot }\) w.r.t. the \(pa\text {-}{i\mathcal {O}} \) scheme along with encodings of two reusable patches \(P_0\) and \(P_1\). Patch \(P_0\) is such that it updates any machine \(M_{x}\) to \(M_{x\Vert 0}\) while \(P_1\) updates any machine \(M_{x}\) to \(M_{x\Vert 1}\).

To evaluate the above obfuscation on any input \(x=x_1,\ldots ,x_{\ell }\) for an arbitrary \(\ell \), a user can transform obfuscation of \(M_{\bot }\) to \(M_{x}\) by applying the patches \(P_{x_1},\ldots ,P_{x_{n}}\) and then execute \(M_x\) to obtain M(x). The correctness of the construction is easy to verify.

While we do not consider security for reusable patches in this work, we view the above as a potential new template for building \({i\mathcal {O}} \) for TMs with unbounded length inputs.

1.2 Technical Overview

We now give an overview of the main technical ideas in our constructions. We start by building a general template for building \(pa\text {-}{i\mathcal {O}} \), and then discuss our ideas for implementing this template.

1.2.1 A Template for \(pa\text {-}{i\mathcal {O}} \)

In this section, we devise a general template for building \(pa\text {-}{i\mathcal {O}} \) starting from any non-patchable obfuscation scheme. We keep the discussion in this section to a high-level, focusing on issues directly related to patching, and largely ignoring implementation issues that may arise due to the specific properties of the underlying non-patchable obfuscation scheme. For simplicity, in this section, we advise the reader to think of the non-patchable obfuscation scheme as general-purpose virtual-black-box obfuscation. Later, in Sect. 1.2, we discuss the additional challenges that arise in implementing our template when the non-patchable obfuscation scheme is \({i\mathcal {O}} \), and our solutions for the same.

Let us start with the weaker goal of building single-program \(pa\text {-}{i\mathcal {O}} \) where the authority issues a single obfuscated program that can then be patched multiple times, in a sequential order. Our initial idea towards achieving this goal is to identify an encoding scheme that supports patching and then combine it with a non-patchable obfuscation scheme to build a \(pa\text {-}{i\mathcal {O}} \) scheme. Intuitively, we say that an encoding scheme is patchable if given an encoding of a machine M and an encoding of a patch P, it is possible to derive an encoding of \(M'=P(M)\). The hope here is that the patching property of the encoding scheme can be translated into patching property for obfuscation.

A natural candidate for a patchable encoding scheme is fully homomorphic encryption (FHE). Indeed, given an encryption (i.e., encoding) of a machine M and an encryption of a patch P, one can obtain an encryption of the patched machine \(M'=P(M)\) by homomorphically evaluating the function \(f(M,P) = P(M)\). Starting with FHE and any non-patchable obfuscation scheme, we can build an initial template for \(pa\text {-}{i\mathcal {O}} \) as follows: to obfuscate M, first encrypt M using FHE and then provide an obfuscation of the FHE decryption circuit that has the FHE decryption key hardcoded into it. Evaluation on an input x can be done as follows: first use FHE evaluation to transform encryption of M into an encryption of M(x), and then use the obfuscated decryption circuit to obtain M(x). To patch the obfuscated program, we can simply patch the encryption of M in the manner as described above.

While this solution seems to offer the functionality of patching, it does not offer any security. Specifically, in the above template, an adversary can choose an arbitrary patch \(P^*\) on its own and then use FHE evaluation of the function \(f_{P^*}(M) = P^*(M)\) to transform encryption of M into an encryption of \(P^{*}(M)\). If this patch \(P^*\) is such that for two equivalent machines \(M_0\) and \(M_1\), \(P^*(M_0)\) and \(P^*(M_1)\) are not equivalent, then the adversary can easily break the security of \(pa\text {-}{i\mathcal {O}} \). Indeed, the security of \(pa\text {-}{i\mathcal {O}} \) prevents an adversary from creating patches on its own, while the above template does not place this restriction in any way. In particular, we need to crucially use the fact that patch generation is a secret key operation.

Towards that end, we modify the above template such that an evaluator can only apply authenticated patches. The obfuscation of M consists of an FHE encryption of M as before but the obfuscated FHE decryption circuit now takes as input old encryption Enc(M), updated encryption \(Enc(M')\), encrypted patch Enc(P), a signature \(\sigma \) on Enc(P) and an input x. It checks if the signature is valid and also if \(Enc(M')\) is obtained by updating Enc(M) using P. If the check passes, then it decrypts \(Enc(M')\) and evaluates \(M'\) on x. During the patching phase, the authority sends both Enc(P) and the signature \(\sigma \). This signature now prevents a user from applying “invalid” patches to the obfuscation; however, we note that in the context of \({i\mathcal {O}} \), this authentication will need to be done in a much more careful manner, as we elaborate below.

Enforcing Ordered Executions of Patches. While the above template does not seem to suffer from any immediate issues when we consider a single patch, unfortunately, its security breaks down when we consider the setting of multiple patches. Indeed, in the above template, given (say) two patch encodings \((Enc(P_1),\sigma _1)\), \((Enc(P_2),\sigma _2)\), an adversary may first apply the second patch and then the first patch, which may break the equivalence requirement on the patched machines in the security definition of \(pa\text {-}{i\mathcal {O}} \). In fact, an adversary can also repeatedly apply the same patch multiple times in the above template, which may also break the equivalence requirement on the patched machines in the security definition of \(pa\text {-}{i\mathcal {O}} \). Indeed, the definition of \(pa\text {-}{i\mathcal {O}} \) requires that the patch encodings can only be applied in order, namely, the \(i^{th}\) patch encoding can only be applied to the \((i-1)^{th}\) patched obfuscation, once.

Towards this, we introduce a mechanism to force a user to apply the patches in order. We begin by observing that instead of authenticating the encrypted patch in the above template, if we instead authenticate the encrypted patched machine, then we can enforce ordered executions of patches. That is, suppose we want to update the machine M using patch P, the authority first computes Enc(P) and then updates Enc(M) using Enc(P) to obtain \(Enc(M')\). It then signs \(Enc(M')\) and sends the signatureFootnote 3 \(\sigma \) and the encrypted patch Enc(P) to the user. The user now updates Enc(M) using Enc(P) to obtain \(Enc(M')\). To evaluate the patched obfuscation on an input x, it inputs \((Enc(M'),\sigma ,x)\) to the obfuscated FHE decryption circuit that first checks for validity of the signature and then decrypts \(Enc(M')\) followed by computation of \(M'(x)\), as before. Crucially, by shifting the authentication to the updated encrypted machine instead of encrypted patch, we are now able to prevent the “out-of-order patching” attacks (as well as “repeated patching” attacks) by an adversary discussed above.

A disadvantage of the above solution is that it requires the authority to maintain large state. In particular, at any time, the authority must remember the last patched machine \(M_{i-1}\) in order to generate a valid encoding for the \(i^{th}\) patch \(P_i\). Furthermore, the patch encoding generation time now depends on the size of the machine \(M_{i-1}\). While this loss in efficiency may be acceptable for the setting of single-program \(pa\text {-}{i\mathcal {O}} \), it unfortunately becomes a significant barrier for the setting of multi-program \(pa\text {-}{i\mathcal {O}} \). Indeed, in the multi-program setting, the number of obfuscated programs are not a priori bounded; as such, if we were to extend the above template to this case, then the authority’s state size becomes unbounded! (This is because the authority would need to maintain a separate state for every obfuscated program.)

Compressing the State of Authority. In order to resolve this issue we introduce the next idea: “delegating” the state of the authority to the user. That is, the authority now maintains the state at the user’s end. Implementing this idea introduces several issues: not only should the state be encrypted at the user’s end but it should also be possible to repeatedly update and also compute on this (updated) encrypted state. To address these issues, we turn to a cryptographic primitive called garbled RAMs with persistent memory. This notion allows for encoding a database and repeatedly update this encoding and compute on the updated encodings. The updating and computation operations are enabled by using encodings of RAM programs which are issued by the authority. Using this primitive, we propose a solution template.

  • To obfuscate M, the authority computes: (i) Enc(M) and a signature upon it. (ii) An obfuscation of the FHE decryption circuit (as before) that takes an input x, Enc(M) and a signature \(\sigma \), and outputs M(x) if the signature is valid. (iii) A database encoding \(\widetilde{Enc(M)}\) of Enc(M). It then sends \(\widetilde{Enc(M)}\), Enc(M), \(\sigma \) and the obfuscated decryption circuit to the user.

  • To evaluate the obfuscation on an input x, the user inputs \((x,Enc(M),\sigma )\) to the obfuscated decryption circuit to recover the output M(x).

  • To compute a patch encoding of P, the authority first computes Enc(P) (as before) and then computes a garbled RAM encoding \(\widetilde{T}\) of a RAM machine T that has Enc(P) hardcoded in it. The machine T uses FHE evaluation over Enc(M) (in the database encoding) and Enc(P) to compute \(Enc(M')\) and additionally computes signature \(\sigma '\) over \(Enc(M)'\). It outputs \(\sigma '\) in the clear. The user, upon receiving the patch encoding, first computes \(Enc(M')\) using Enc(P). It then updates the database encoding \(\widetilde{Enc(M)}\) using \(\widetilde{T}\). The result is an updated database encoding \(\widetilde{Enc(M')}\) and the signature \(\sigma '\) on \(Enc(M')\). The user can now evaluate the updated machine on any input in the same manner as before.

Some remarks are in order: first, from an efficiency viewpoint, we need the garbled RAM scheme to be succinct where the size of RAM machine encoding is independent of its running time. This is because we are applying the above idea on a single-program \(pa\text {-}{i\mathcal {O}} \) scheme where the patch generation time depends on the size of the machine being updated. Second, in order to argue security in the setting of adaptively chosen patches, we need the garbled RAM scheme to satisfy adaptive security as well. Such a garbled RAM scheme (with persistent memory) was recently constructed in the independent works of [2, 24].

Finally, we note that while the above idea successfully compresses the state size of the authority, it still does not suffice for the multi-program setting. This is because in the above solution, when extended to the multi-program case, the authority would need to maintain some small state, namely, the garbling key, for every obfuscated machine, which still leads to a state of unbounded size. We address this problem by developing a generic transformation from any single-program \(pa\text {-}{i\mathcal {O}} \) scheme with small state (or alternatively, a stateless scheme) into a multi-program \(pa\text {-}{i\mathcal {O}} \) scheme by using a compact secret-key functional encryption scheme for general circuits. We defer the discussion of this transformation to the next section.

1.2.2 Implementation

Issues Related to Indistinguishability Obfuscation. While the above template seems promising, several issues arise when we have to implement it only assuming indistinguishability obfuscation for circuits. For starters, the above template requires an obfuscation scheme for Turing machines with unbounded length inputs. This is because, the size of the encrypted machine M can grow arbitrarily over a sequence of updates and thus the input to the obfuscated circuit cannot be a priori bounded. We currently know how to realize this only based on strong knowledge-type assumptions [1, 20, 42]. Another technical issue is that standard signature schemes are not “compatible” with iO and more generally, using iO restricts the type of cryptographic primitives that we can use. These challenges were encountered in many recent works [17, 26, 44] whose main goal was reducing the problem of constructing iO for Turing machines, where the length of inputs to be evaluated are a priori bounded, to the problem of constructing iO for circuits. We build upon the primitives and notions introduced in the work of [44] to address these challenges. We recall the Turing machine randomized encodingsFootnote 4 construction by [44].

The core idea in the randomized encodings construction of Koppula et al. [44] is to leverage an obfuscated circuit to perform step-by-step computation of the machine M that is encoded. In more detail, a randomized encoding of (Mx) consists of: (a) input tape initialized with an encoding of M and, (b) an obfuscated circuit \(C_{x}\) that performs “step-by-step” computation of a machine \(U_x(\cdot )\). Here, \(U_x(\cdot )\) is a universal TM that takes as input machine M and outputs M(x). By step-by-step computation, we mean that the circuit \(C_x\) takes as input time step i, encoded symbol and partial information about the current state in an encrypted form and produces a new encoded symbol and state, again in encrypted form, by executing the transition function of \(U_x\). This enables the size of the circuit \(C_x\) to be independent of the length of M.

To see how the randomized encodings construction might be useful to our setting, note that we could potentially encode the machine M using a patchable encoding scheme that will allow us to patch M. Furthermore, we can allow the machine size to arbitrarily grow, over a sequence of updates, since the size of the circuit \(C_x\) is independent of the machine size M. However, the main issue is that their approach is tied to just a single computation M(x) whereas we require that M be reused on multiple inputs. They propose an approach to achieve reusability by using another layer of obfuscation, with M hardwired in it, that produces fresh encodings of M for every computation. This is highly problematic for us, since patching M would now correspond to patching the underlying obfuscated circuit.

We need to make the randomized encodings construction of KLW reusable while preserving the underlying encoding of M. A recent work of Ananth et al. [5], proposed in a different context of building iO with constant overhead, achieves this goal. In more detail, they showed how to achieve iO for TMs, with a priori bound in the input length, such that an obfuscation of M proceeds in two phases: (a) M is encoded using a suitable encoding scheme and, (b) an obfuscation of a circuit that takes as input x and produces an encoding of x. The evaluation of the obfuscation on an input x proceeds by first obtaining an encoding of x (using the obfuscated circuit) and then decoding this using the encoding of M to recover M(x).

While their work offers a starting point for building patchable iO, we still need to address several issues that specifically arise in the context of patching. For instance, their work only considers the setting when the adversary is given one obfuscated machine whereas in our setting she also receives additionally, patches that share some common randomness with the obfuscated machine. We need to argue that the security holds even with this additional information. Instead of directly digging into the details of [5] to apply it in the context of patching, we undertake a more modular approach. First, we propose an intermediate primitive called splittable iO and show that it suffices for building single-program patchable iO. We then show that splittable iO can be implemented assuming only iO for circuits by using the framework of [5]. We describe this primitive in detail next.

Splittable iO: Intermediate Notion Between iO and Patchable iO. A splittable iO scheme is a strengthening of iO and is associated with respect to a patchable encoding scheme. A patchable encoding scheme consists of algorithms: Setup, Encode and Decode. Setup generates a secret key \(sk\) that will be used by Encode procedure to obtain an encoding of M, \({\mathcal {E}}_{sk}(M)\). Decode recovers the Turing machine M from the encoding \({\mathcal {E}}_{sk}(M)\) using the secret key \(sk\). Additionally, it is associated with two algorithms: patch generation algorithm, used to generate secure patches and patch application algorithm, that enables applying secure patches on encodings of TMs. The security property requires that the encodings and patches hide the underlying TMs and patches, respectively.

We start with a oversimplified template of splittable iO and make suitable modifications later. An obfuscation of M, with respect to splittable iO, consists of two parts: \(({\mathcal {E}}_{sk}(M),aux_M)\), where (i) \({\mathcal {E}}_{sk}(M)\) is a patchable encoding of M computed using secret key \(sk\), (ii) \(aux_M\) computed as a function of an additional PPT algorithm \(\mathsf {AuxGen}\), on \((sk,{\mathcal {E}}_{sk}(M))\).

Armed with the notion of splittable iO, we show how to construct single-program patchable iO. At first glance, it seems that splittable iO already allows for patching: indeed, since M is encoded with respect to a patchable encoding scheme, we can use the patching algorithm to update this encoding. However, this does not work because the obfuscation also contains \(aux_M\) that is tied to encoding of M. Indeed, this is necessary for the security of obfuscation to hold. So if the encoding of M is updated, it is necessary to also update \(aux_M\). A naive way of achieving this is to issue a fresh \(aux_M\) every time the encoding is patched. That is, initially the user is issued an encoding of M, \({\mathcal {E}}_{sk}(M)\) and auxiliary information \(aux_M\). During the patching phase, a secure version of patch P with respect to the patchable encoding scheme is issued. Along with this, a fresh \(aux_{M'}\) is issued, which is generated by first patching \({\mathcal {E}}_{sk}(M)\) using \(\widetilde{P}\), secure patch of P, and then executing \(\mathsf {AuxGen}\) on input \((sk,{\mathcal {E}}_{sk}(M'))\).

However this raises the question of efficiency: the patch size now grows with the size of \(aux_{M'}\). This can be taken care of imposing an efficiency constraint on splittable iO: we require that the size of aux be a polynomial in security parameter and specifically, independent of the size of the machine obfuscated. The next issue is correctness: why should the patched obfuscated machine be correct? for instance: \(\mathsf {AuxGen}\) could abort on input patched encodings. To take care of this issue, we impose an additional property on splittable iO: the correctness of the obfuscated machine should hold irrespective of whether fresh encodings or patched encodings of the machine are fed to \(\mathsf {AuxGen}\).

Finally, we move on to proving the security of patchable iO. A first attempt is to use the security of the underlying patchable encoding scheme to argue this. However, it is unclear why the security of encoding scheme is guaranteed at all given that aux contains information about the secret key of the encoding scheme. If we additionally impose aux to hide the secret key, we can then hope to invoke the security of patchable encoding scheme to argue the security of patchable iO. A natural approach of formalizing this is to use a simulation-based argument – there exists a simulator that can simulate the aux even without knowing the secret key. But this would mean that aux will not able to decode any information about the encoding of M. In order to maintain correctness of the obfuscation of M, we need to hardwire all possible outputs which is clearly infeasible. Instead we use an indistinguishability-based definition: instead of having one encoding of M, we will consider a pair of encodings of M. That is, obfuscation of M consists of \(({\mathcal {E}}_{sk_0}(M),{\mathcal {E}}_{sk_1}(M))\), computed with respect to secret keys \(sk_0,sk_1\). In addition, it consists of aux generated using \(\mathsf {AuxGen}(sk_0,{\mathcal {E}}_{sk_0}(M),{\mathcal {E}}_{sk_1}(M))\). Now, we impose a security property that says that aux generated using \(sk_0\) is computationally indistinguishable from aux generated using \(sk_1\).

We summarize the (informal) definition of splittable iO below. The formal definition can be found in Sect. 3.2. In addition to the properties of any iO scheme, a splittable iO scheme has the following properties.

  1. 1.

    Splittable Property: An obfuscation of M can be performed in two steps: the first step is encoding M twice using two secret keys \(sk_0\) and \(sk_1\) of a patchable encoding scheme. The second step is generation of aux by computing \(\mathsf {AuxGen}\) on input \((sk_0,{\mathcal {E}}_{sk_0}(M),{\mathcal {E}}_{sk_1}(M))\), where \({\mathcal {E}}_{sk_0}(M)\) and \({\mathcal {E}}_{sk_1}(M)\) are two encodings of M and \(sk_0\) is the secret key used to encode \({\mathcal {E}}_{sk_0}(M)\).

  2. 2.

    Correctness of \(\mathsf {AuxGen}\): The correctness of obfuscation of M holds irrespective of whether \(\mathsf {AuxGen}\) is executed on fresh encodings of M or whether it is executed on encodings of M obtained as a result of patching. This will be used to argue the correctness of the resulting patchable iO scheme.

  3. 3.

    Efficiency of aux: We require that the size of aux is a polynomial in \(\lambda \) and in particular, independent of the size of the machine obfuscated. This will be used to argue the patch size efficiency of patchable iO.

  4. 4.

    Indistinguishability of aux: We require that it is computationally hard to distinguish aux generated using secret key \(sk_0\) from aux generated using \(sk_1\). This property will be helpful to argue security of patchable iO.

Going from Single-Program to Multi-program Patchable Obfuscation. In the solution sketched above, every time the authority has to generate a patch, she has to spend time proportional to the size of the obfuscated machine. In particular, recall that one of the steps in the generation of secure patch is computing \(aux_{M}\): this step involves first patching the old encoding \({\mathcal {E}}_{sk}(M)\) and then executing \(\mathsf {AuxGen}\). We will use the trick described earlier to solve the problem: we delegate the state of the authority as well as the computation of the secure patches to the user. This can be implemented by using a suitable garbling scheme that works in the persistent memory setting. Once this mechanism is implemented, the authority is only required to store the garbling key.

While this is a viable solution in the single-program setting, this is undesirable when the authority is issuing multiple obfuscated programs. She has to store the garbling keys corresponding to all the machines in this case. The storage space of the authority thus puts a bound on the number of obfuscated machines it can issue.

To overcome this difficulty, we employ another idea for delegating responsibility to the user! The garbling key of every user is maintained at her own storage space in an encrypted form. The computation of the garbled program encodings are then delegated to every user. This mechanism is implemented by using a functional encryption scheme. Every user along with the obfuscated machine, garbled encoding of state, also contains an FE encryption of the garbling key. During the patching phase, the authority sends a FE key containing patch P, that takes as input a garbling key and produces a garbled encoding of P with respect to this garbling key. To carry this out, we only require a secret-key FE scheme for circuits.

Putting it Together: A Framework for (Multi-program) Patchable Obfuscation. Putting all the components together, we construct a multi-program patchable iO in the following steps:

  1. 1.

    The first step involves formalizing the notion of splittable iO. This is shown in Sect. 3.

  2. 2.

    Next, we show how to obtain single-program patchable iO from splittable iO. This is shown in Sect. 4. The resulting single-program patchable iO scheme is statefull, i.e., the authority is required to maintain a large state.

  3. 3.

    We show how to overcome this problem by giving a transformation from any statefull to a stateless single-program patchable iO scheme. This is presented in the full version.

  4. 4.

    In the next step, we give a transformation from single-program to multi-program patchable iO. This is presented in the full version.

  5. 5.

    In the last step, we instantiate splittable iO using the framework of [5]. This is presented in the full version.

1.3 Related Work: Incremental Cryptography

The area of incremental cryptography was pioneered by Bellare et al. [11]. Subsequently, this concept of incremental updates has been studied for various standard primitives such as encryption schemes, signature schemes and so on [12, 23, 29, 46, 47]. We remark that none of these works handled the setting of arbitrary updates.

In a concurrent and independent work, [32] consider a related notion called incremental obfuscation. In incremental obfuscation, individual bits of an existing obfuscated program can be updated one-by-one. While their work shares much in spirit with our work, there are several important differences that we describe below.

Our work focuses on support for arbitrary, adaptively chosen patches that may potentially increase the size of the program(s) being patched, and we consider both single-program and multi-program setting. In contrast, their work considers the single-program setting where bit-wise, non-adaptively chosen patches can be applied such that the size of the circuit being patched remains unchanged. Our main efficiency requirement is that the size of the secure patches (or more strongly, the time to generate the secure patches) is independent of the size of the program. In contrast, their work considers the stronger runtime efficiency requirement where the time to apply the secure patch is also independent of the size of the circuit.

2 Patchable \({i\mathcal {O}} \): Definitions and Implications

In this section, we present the formal definitions of patchable indistinguishability obfuscation (\(pa\text {-}{i\mathcal {O}} \)) in the single program and multi program setting.

2.1 Definition: Single-Program \(pa\text {-}{i\mathcal {O}} \)

In this section, we present a formal definition of single-program patchable indistinguishability obfuscation, denoted as \(pa\text {-}{i\mathcal {O}} _{\mathsf {sp}}\). We start by presenting the syntax, and then proceed to give a security definition for sequential updates.

Syntax. A \(pa\text {-}{i\mathcal {O}} _{\mathsf {sp}}\) scheme, defined for a class of Turing machines \(\mathcal {M}\) with an associated family of patches \(\mathcal {P}\) and update algorithm \({\mathsf {Update}}\), consists of a tuple of probabilistic polynomial-time algorithms \(pa\text {-}{i\mathcal {O}} _{\mathsf {sp}}=(\mathsf {Setup},\mathsf {Obf},\mathsf {GenPatch},\mathsf {AppPatch}, \mathsf {Eval})\) which are defined below.

  • Setup, \(\mathsf {Setup}(1^{\lambda })\): It takes as input the security parameter \(\lambda \) and outputs the secret key \(\mathsf {SK}\).

  • Obfuscate, \(\mathsf {Obf}(\mathsf {SK},M)\): It takes as input the secret key \(\mathsf {SK}\) and a TM \(M \in \mathcal {M}\). It outputs an obfuscated TM \(\langle {M}\rangle \) along with state \(\mathsf {st}\).

  • (Stateful) Patch Generation, \(\mathsf {GenPatch}(\mathsf {SK},P,\mathsf {st})\): It takes as input the secret key \(\mathsf {SK}\), a description of a patch \(P \in \mathcal {P}\), and state \(\mathsf {st}\). It outputs a patch encoding \(\langle {P}\rangle \) along with the updated state \(\mathsf {st}'\).

  • Applying Patch, \(\mathsf {AppPatch}\Big (\langle {M}\rangle ,\langle {P}\rangle \Big )\): It takes as input an obfuscated TM \(\langle {M}\rangle \) and a patch encoding \(\langle {P}\rangle \). It outputs an updated obfuscation \(\langle {M'}\rangle \).

  • Evaluation, \(\mathsf {Eval}\Big (\langle {M}\rangle ,x\Big )\): It takes as input an obfuscated TM \(\langle {M}\rangle \) and an input x. It outputs a value y.

Efficiency. We define two efficiency properties:

  • Patch Size Efficiency: For every patch \(P \in \mathcal {P}\), we require that the size of the patch encoding \(|\langle {P}\rangle |\) is a fixed polynomial in \((|P|,\lambda )\), where \((\langle {P}\rangle ,\mathsf {st}') \leftarrow \mathsf {GenPatch}(\mathsf {SK},P,\mathsf {st})\).

  • Patch Generation Efficiency: For every patch \(P \in \mathcal {P}\), we require that the running time of \(\mathsf {GenPatch}(\mathsf {SK},P,\mathsf {st})\) to be a fixed polynomial in \((|P|,\lambda )\). The length of \(\mathsf {st}\) could depend on the size of the obfuscated machine its associated with and we require that the running time of \(\mathsf {GenPatch}\) to be independent of \(|\mathsf {st}|\).

It is easy to see that the second property implies the first property. Our first construction of \(pa\text {-}{i\mathcal {O}} _{\mathsf {sp}}\) only satisfies the first property. In the full version, we describe a modified construction that also achieves the second property.

Correctness for Sequential Patches. At a high level, the correctness property states that executing \({\mathsf {Update}}\) on a TM M and a patch P is equivalent to executing \(\mathsf {AppPatch}\) on the obfuscation of M and a secure patch of P. In fact we require that this holds even if there are multiple patches that are applied sequentially.

For any TM \(M_0 \in \mathcal {M}\), \(L> 0\), sequence of patches \(P_1,\ldots ,P_{L}\in \mathcal {P}\), consider two processes:

  • Obfuscate-then-Update: Compute the following: (a) \(\mathsf {SK}\leftarrow \mathsf {Setup}(1^{\lambda })\), (b) \(\Big (\langle {M_0}\rangle ,\mathsf {st}_0\Big ) \leftarrow \mathsf {Obf}(\mathsf {SK},M_0)\), (c) \(\Big (\langle {P_{i}}\rangle ,\mathsf {st}_{i}\Big ) \leftarrow \mathsf {GenPatch}(\mathsf {SK},P_i,\mathsf {st}_{i-1})\), (d) \(\langle {M_{i}}\rangle \leftarrow \mathsf {AppPatch}\Big (\langle {M_{i-1}}\rangle ,\langle {P_{i}}\rangle \Big )\).

  • Update: \(M_{i} \leftarrow {\mathsf {Update}}(M_{i-1},P_{i})\).

We require that for all \(x \in \{0,1\}^{*}\), every \(i \in [L]\), \(\mathsf {Eval}\Big (\langle {M_{i}}\rangle ,x\Big )=M_{i}(x)\).

Remark 1

For the case of parallel patching, we require that \(\langle {M_i}\rangle \leftarrow \mathsf {AppPatch}\Big (\langle {M_{0}}\rangle ,\langle {P_{i}}\rangle \Big )\) is a valid obfuscation of machine \(M_i\). We emphasize that for the case of parallel patching, the patches are applied only on the original machine.

Adaptive Security for Sequential Patches. We next give an indistinguishability (IND)-style definition for modeling the security of an \(pa\text {-}{i\mathcal {O}} _{\mathsf {sp}}\) scheme for the case of sequential patches. In an IND-security definition, we consider a security game between the challenger and the adversary. In this game, the adversary sends two machines \((M^0_0,M^0_1)\) to the challenger and in response receives an obfuscation \(\langle {M^0_b}\rangle \), where b is the challenge bit chosen randomly by the challenger. Then the adversary submits patch queries, adaptively, to the challenger in a series of phases. In each phase, the adversary chooses a pair of patches \((P^i_0,P^i_1)\) and in return gets the patch encoding \(\langle {P^i_b}\rangle \). The patch queries of the adversary are restricted in the following manner: suppose \(\Big ( (P_0^1,P_1^1),\ldots ,(P_{0}^L,P_1^{L}) \Big )\) is a sequence of adaptive patch queries made by the adversary. We require that the machine \(M_0^{i}\) is functionally equivalent with \(M_1^i\), for every \(i \in [L]\), where \(M_0^i\leftarrow {\mathsf {Update}}(M_0^{i-1},P_0^i)\) (resp., \(M_1^i\leftarrow {\mathsf {Update}}(M_{1}^{i-1},P_1^i)\)). At the end of the game, the adversary attempts to guess the bit b. If the adversary’s guess is the same as b only with probability negligibly close to 1 / 2, then we say that the scheme is secure. Henceforth, we use the term adaptive security to refer to this notion. We proceed to formally defining this notion.

The experiment for the adaptive security definition is formulated below. Let \(\mathcal {A}\) be any PPT adversary.

:

  1. 1.

    \(\mathcal {A}\) sends \((M^0_0,M^0_1)\) to the challenger.

  2. 2.

    Challenger executes the setup algorithm to obtain \(\mathsf {SK}\leftarrow \mathsf {Setup}(1^{\lambda })\). It then sends \(\langle {M^0_b}\rangle \leftarrow \mathsf {Obf}(\mathsf {SK},M^0_b)\) to \(\mathcal {A}\).

  3. 3.

    Repeat the following steps for \(i \in \{1,\ldots ,L\}\), where L is chosen by \(\mathcal {A}\).

    • \(\mathcal {A}\) sends \((P_0^i,P_1^i)\) to the challenger.

    • Challenger checks if \(M_{0}^i \equiv M_1^{i}\), where \(M_0^i \leftarrow {\mathsf {Update}}(M_{0}^{i-1},P_0^i)\) and \(M_1^i \leftarrow {\mathsf {Update}}(M_{1}^{i-1}, P_1^i)\).

    • Challenger computes \(\langle {P^{i}_b}\rangle \leftarrow \mathsf {GenPatch}(\mathsf {SK},P_{b}^{i})\) and sends \(\langle {P_{b}^i}\rangle \) to \(\mathcal {A}\).

  4. 4.

    \(\mathcal {A}\) outputs the bit \(b'\).

Definition 1

(Adaptive Security). A single-program patchable indistinguishability obfuscation scheme \(pa\text {-}{i\mathcal {O}} _{\mathsf {sp}}\) is said to be adaptively secure against sequential updates if for any PPT adversary \(\mathcal {A}\), there exists a negligible function \(\mathsf {negl}(\cdot )\) s.t.

$$\begin{aligned} \left| \mathsf {Pr}\left[ 1 \leftarrow {\mathsf {Expt}}^{pa\text {-}{i\mathcal {O}} _{\mathsf {sp}}}_\mathcal {A}(1^{\lambda },1)\right] -\mathsf {Pr}\left[ 1 \leftarrow {\mathsf {Expt}}^{pa\text {-}{i\mathcal {O}} _{\mathsf {sp}}}_\mathcal {A}(1^{\lambda },0)\right] \right| \le \mathsf {negl}(\lambda ) \end{aligned}$$

Remark 2

For the case of parallel patching, the same security is defined with the only difference being that it is required that the machine \(M_0^i\) is functionally equivalent to \(M_1^i\), where \(M_b^i\) is obtained by patching \(M_b^0\) (the original machine) using \(P_i\).

2.2 Definition: Multi-program \(pa\text {-}{i\mathcal {O}} \)

We now present a formal definition of multi-program \(pa\text {-}{i\mathcal {O}} \), denoted as \(pa\text {-}\mathsf {i}\mathcal {O}_{\mathsf {mp}}\). Informally speaking, \(pa\text {-}\mathsf {i}\mathcal {O}_{\mathsf {mp}}\) allows an authority to obfuscate an arbitrary number of programs in such a way that it is possible to later issue a patch encoding that can be used to update all the obfuscated programs at once. The authority who issues the obfuscated programs stores just a “short” information about all the obfuscated programs issued that enables it to produce a single patch that can act on all these programs. In particular, the size of the storage space of the authority is independent of the joint size of all these programs.Footnote 5 This is in contrast to the single-program setting described above, where the authority maintains state and this state can be as big as the program whose obfuscation is issued. There is another difference between both the settings: in the single-program setting, if we were to relax the size of the secure patch to be proportional to the size of the updated program then achieving a feasibility result is straightforward – the secure patch will just be the obfuscation of the updated program. Hence the primary goal is to reduce the size of the patch. However, in the multi-program setting, even if we relax the size of the secure patch to be proportional to the size of any of the updated programs, achieving a feasibility result is already non-trivial. As mentioned earlier, the authority does not have enough space to store all the updated programs and hence the above naïve solution, of sending a fresh obfuscation of the updated program, does not work. As we will see later we not only give a feasibility result in this setting but we also achieve a solution with optimal efficiency where the size of the secure patches depend only on the size of their original patches and in particular, independent of the size of any obfuscated programs issued.

Syntax. A \(pa\text {-}\mathsf {i}\mathcal {O}_{\mathsf {mp}}\) scheme, defined for a class of Turing machines \(\mathcal {M}\) and a family of patches \(\mathcal {P}\), consists of a tuple of probabilistic polynomial-time algorithms \(pa\text {-}\mathsf {i}\mathcal {O}_{\mathsf {mp}}=(\mathsf {Setup},\mathsf {Obf},\mathsf {GenPatch},\mathsf {AppPatch}, \mathsf {Eval})\) which are defined below. We denote the update algorithm associated with \((\mathcal {M},\mathcal {P})\) to be \({\mathsf {Update}}\).

  • Setup, \(\mathsf {Setup}(1^{\lambda })\): It takes as input the security parameter \(\lambda \) and outputs the secret key \(\mathsf {SK}\).

  • Obfuscate, \(\mathsf {Obf}(\mathsf {SK},M)\): It takes as input the secret key \(\mathsf {SK}\) and a TM \(M \in \mathcal {M}\) \(\mathsf {id}\). It outputs an obfuscated TM \(\langle {M}\rangle \).

  • (Stateless) Patch Generation, \(\mathsf {GenPatch}(\mathsf {SK},P)\): It takes as input the secret key \(\mathsf {SK}\) and a description of a patch \(P \in \mathcal {P}\). It outputs a patch encoding \(\langle {P}\rangle \).

  • Applying Patch, \(\mathsf {AppPatch}\Big (\langle {M}\rangle ,\langle {P}\rangle \Big )\): It takes as input an obfuscated TM \(\langle {M}\rangle \) and a patch encoding \(\langle {P}\rangle \). It outputs an updated obfuscation \(\langle {M'}\rangle \).

  • Evaluation, \(\mathsf {Eval}\Big (\langle {M}\rangle ,x\Big )\): It takes as input an obfuscated TM \(\langle {M}\rangle \) and an input x. It outputs a value y.

Efficiency. Similar to \(pa\text {-}{i\mathcal {O}} _{\mathsf {sp}}\), we define two efficiency properties for \(pa\text {-}\mathsf {i}\mathcal {O}_{\mathsf {mp}}\):

  • Patch Size Efficiency: For every patch \(P \in \mathcal {P}\), we require that the size of the patch encoding \(|\langle {P}\rangle |\) is a fixed polynomial in \((|P|,\lambda )\), where \((\langle {P}\rangle ,\mathsf {st}') \leftarrow \mathsf {GenPatch}(\mathsf {SK},P,\mathsf {st})\).

  • Patch Generation Efficiency: For every patch \(P \in \mathcal {P}\), we require that the running time of \(\mathsf {GenPatch}(\mathsf {SK},P,)\) to be a fixed polynomial in \((|P|,\lambda )\).

It is easy to see that the second property implies the first property. Our construction of \(pa\text {-}\mathsf {i}\mathcal {O}_{\mathsf {mp}}\) presented in the full version achieves both of the properties.

Correctness for Sequential Patches. For every \(Q,L > 0\), any sequence of TMs \(M_{{0}^{1}},\ldots ,M_0^{Q} \in \mathcal {M}\), sequence of patches \(P_1,\ldots ,P_{L}\in \mathcal {P}\), consider the following two processes. For every \(j \in \{1,\ldots ,Q\},i \in \{1,\ldots ,L\}\), we have:

  • Obfuscate-then-Update: Compute the following: (a) \(\mathsf {SK}\leftarrow \mathsf {Setup}(1^{\lambda })\), (b) \(\langle {M_0^{j}}\rangle \leftarrow \mathsf {Obf}(\mathsf {SK},M_0^{j})\), (c) \(\langle {P_{i}}\rangle \leftarrow \mathsf {GenPatch}(\mathsf {SK},P_i)\), (d) \(\langle {M_{i}^{j}}\rangle \leftarrow \mathsf {AppPatch}\Big (\langle {M_{i-1}^{j}}\rangle ,\langle {P_{i}}\rangle \Big )\).

  • Update: \(M_{i}^{j} \leftarrow {\mathsf {Update}}(M_{i-1}^{j},P_{i})\).

We require that \(\forall x \in \{0,1\}^{*}\), \(\forall j \in [Q]\), \(\forall i \in [L]\), we have \(\mathsf {Eval}\Big (\langle {M_{i}^{j}}\rangle ,x\Big )=M_{i}^{j}(x)\).

Adaptive Security for Sequential Patches. We next give indistinguishability (IND)-style definitions for modeling the security of a patchable obfuscation scheme. As in the case of single-program patchable obfuscation, the definition is based on a game between the challenger and the adversary. The adversary makes TM queries and patch queries to the challenger. One important distinction is that in this setting, the adversary can make multiple TM queries whereas in the case of single-program obfuscation, it makes just one TM query. We describe the experiment below.

:

  1. 1.

    \(\mathcal {A}\) submits a sequence of TM pairs \(\Big ((M_{0,0}^1,M_{0,1}^1),\ldots ,(M_{0,0}^{Q},M_{0,1}^{Q}) \Big )\).

  2. 2.

    Challenger executes the setup algorithm to obtain \(\mathsf {SK}\leftarrow \mathsf {Setup}(1^{\lambda })\). For every \(j\in [Q]\), it computes \(\langle {M_{0,b}^j}\rangle \leftarrow \mathsf {Obf}(\mathsf {SK},M_{0,b}^j)\) and sends \(\Big \{\langle {M_{0,b}^j}\rangle \Big \}_{j \in [Q]}\) to the adversary.

  3. 3.

    Repeat the following steps for \(i \in \{1,\ldots ,L\}\), where \(L(\lambda )\) is chosen by \(\mathcal {A}\):

    • \(\mathcal {A}\) sends \((P_0^i,P_1^i)\) to the challenger.

    • Challenger computes \(\langle {P^{i}_b}\rangle \leftarrow \mathsf {GenPatch}(\mathsf {SK},P_{b}^{i})\). It sends \(\langle {P_{b}^i}\rangle \) to \(\mathcal {A}\).

  4. 4.

    For every \(i \in \{1,\ldots ,L\}\), every \(j \in \{1,\ldots ,Q\}\), the challenger checks if \(M_{i,0}^j \equiv M_{i,1}^{j}\), where \(M_{i,0}^j \leftarrow {\mathsf {Update}}(M_{i-1,0}^{j},P_0^i)\) and \(M_{i,1}^j \leftarrow {\mathsf {Update}}(M_{i-1,1}^{j}, P_1^i)\). If check fails then the challenger aborts the experiment.

  5. 5.

    \(\mathcal {A}\) outputs the bit \(b'\).

Definition 2

(Adaptive security). A multi-program patchable obfuscation scheme \(pa\text {-}\mathsf {i}\mathcal {O}_{\mathsf {mp}}\) is said to be adaptively secure if for any PPT adversary \(\mathcal {A}\), there exists a negligible function \(\mathsf {negl}(\cdot )\) s.t.

$$\begin{aligned} \left| \mathsf {Pr}\left[ 0 \leftarrow \mathsf {Expt}^{pa\text {-}\mathsf {i}\mathcal {O}_{\mathsf {mp}}}_\mathcal {A}(1^{\lambda },0)\right] -\mathsf {Pr}\left[ 0 \leftarrow \mathsf {Expt}^{pa\text {-}\mathsf {i}\mathcal {O}_{\mathsf {mp}}}_\mathcal {A}(1^{\lambda },1)\right] \right| \le \mathsf {negl}(\lambda ) \end{aligned}$$

Remark 3

For the case of parallel patching, the correctness and security can be similarly defined.

3 Splittable iO

We describe the notion of splittable iO next. This notion will be associated with a patchable encoding scheme. We define patchable encoding scheme first.

3.1 Patchable Encoding Scheme

A patchable encoding scheme is an encoding scheme associated with a class of Turing machines. This scheme allows for updating an encoding of a machine M using an encoding of a patch P to obtain an encoding of another machine \(M'\), where \(M' \leftarrow {\mathsf {Update}}(M,P)\). The secret key, used in the computation of the encodings, is generated using algorithm \({\mathsf {Gen}}\). Turing machines are encoded using \(\mathsf {Encode}\) and the patches are encoded using \(\mathsf {GenPatch}\). Algorithm \(\mathsf {AppPatch}\) is used to apply update the encoding of machine M using encoding of patch P. Finally, \(\mathsf {Decode}\) is used to decode an encoding of M using the secret key produced by \({\mathsf {Gen}}\).

Syntax. A patchable encoding scheme is described by the algorithms \(\mathsf {UE}=({\mathsf {Gen}}, \mathsf {Encode}, \mathsf {GenPatch}, \mathsf {AppPatch}, \mathsf {Decode})\) which are defined below. We denote by \(\mathcal {M}\), the class of Turing machines it is associated with. We further denote the update algorithm associated with \(\mathcal {M}\) to be \({\mathsf {Update}}\).

  • \(sk\leftarrow {\mathsf {Gen}}(1^{\lambda })\): On input \(\lambda \), it produces the secret key \(sk\).

  • \({\mathcal {E}}_{sk}(M) \leftarrow \mathsf {Encode}(sk,M)\): On input secret key \(sk\), Turing machine M, it produces an encoding of M, namely \({\mathcal {E}}_{sk}(M)\), with respect to \(sk\).

  • \(\widetilde{P} \leftarrow \mathsf {GenPatch}(sk,P)\): On input secret key \(sk\), patch P, it produces a secure patch \(\widetilde{P}\).

  • \({\mathcal {E}}_{sk}(M') \leftarrow \mathsf {AppPatch} \left( {\mathcal {E}}_{sk}(M),\widetilde{P} \right) \): On input encoding \({\mathcal {E}}_{sk}(M)\), secure patch \(\widetilde{P}\), it produces the updated encoding \({\mathcal {E}}_{sk}(M)\).

  • \(M \leftarrow \mathsf {Decode}(sk,{\mathcal {E}}_{sk}(M))\): On input secret key \(sk\), machine encoding \({\mathcal {E}}_{sk}(M)\), it produces the machine M.

Efficiency. We require that the size of the secure patches is a (a priori fixed) polynomial in the security parameter and the size of the underlying patch. That is, \(|\widetilde{P}|=\mathrm {poly}(\lambda ,|P|)\), where \(\widetilde{P} \leftarrow \mathsf {GenPatch}(sk,P)\).

Correctness of Sequential Updating. Consider \(M \in \mathcal {M}\) and a sequence of patches \(P_1,\ldots ,P_{L}\). We consider the following two processes:

  • Encode-then-Update: Compute the following: (a) \(sk\leftarrow {\mathsf {Gen}}(1^{\lambda })\); (b) \({\mathcal {E}}_{sk}(M_1) \leftarrow \mathsf {Encode}(sk, M)\); (c) For every \(i \in [L]\), \(\widetilde{P_i} \leftarrow \mathsf {GenPatch}(sk,P_i)\); (d) \({\mathcal {E}}_{sk}(M_{i+1}) \leftarrow \mathsf {AppPatch} \left( {\mathcal {E}}_{sk}(M_{i}),\widetilde{P_i} \right) \).

  • Update: For every \(i \in [L]\), \(M_{i+1} \leftarrow {\mathsf {Update}}(M_i,P_i)\) with \(M_1=M\).

We require that \(\mathsf {Decode}(sk,{\mathcal {E}}_{sk}(M_L))=M_L\).

Security. We require any patchable encoding scheme to satisfy the following.

Definition 3

A patchable encoding scheme, \(\mathsf {UE}=({\mathsf {Gen}}, \mathsf {Encode}, \mathsf {GenPatch}, \mathsf {AppPatch}, \mathsf {Decode})\) is said to be secure if the following holds: Consider the game between a challenger and an adversary. The adversary submits machines \((M_0^1,M_1^1)\ldots ,(M^{Q}_0,M^Q_1) \in \mathcal {M}\) to the challenger. In return, the adversary receives \(\{{\mathcal {E}}_{sk}(M^j_b) \}_{j \in [Q]}\), where \(b \in \{0,1\}\) is picked at random. The adversary can then make patch queries \((P_0^i,P_1^i)\), for every \(i \in [L]\), adaptively. In return it receives \(\widetilde{P_b^i}\). The probability that the adversary outputs b is negligibly close to 1 / 2.

We can correspondingly define an encoding scheme supporting parallel patches.

In the full version, we present an instantiation of the above primitive using fully homomorphic encryption.

3.2 Definition of Splittable iO

We define the notion of splittable iO next. A splittable iO is an indistinguishability obfuscation scheme, satisfying additional properties. The model of computation is Turing machines and we work in succinct iO setting [17, 26, 44]. Although the algorithms associated with succinct iO take the input length bound as input, we omit this in the description below. For simplicity, set the input length bound to be \(\lambda \). Our results can easily be extended to the case when the input bound is an arbitrary polynomial in \(\lambda \) and our parameter sizes would blow accordingly.

Firstly, we require that the obfuscation of M proceeds in two steps: in the first step, M is encoded (twice) using the underlying patchable encoding scheme \(\mathsf {UE}\). This is done by generating the setup of \(\mathsf {UE}\) twice and encoding M using both these secret keys \(sk_0\) and \(sk_1\). Call the two encodings \({\mathcal {E}}_{sk_0}(M)\) and \({\mathcal {E}}_{sk_1}(M)\). The second step involves generation of auxiliary information as a function of the encodings \({\mathcal {E}}_{sk_0}(M)\) and \({\mathcal {E}}_{sk_1}(M)\) and one of the secret keys. This is enabled via an additional algorithm \(\mathsf {AuxGen}\). This requirement on the structure of the obfuscate algorithm is termed as splittable property. The second property we require is correctness of \(\mathsf {AuxGen}\) – this says that the correctness of the obfuscated machine should not be affected by whether the two encodings (part of the obfuscated machine) fed to \(\mathsf {AuxGen}\) are freshly computed or if they are obtained as a result of patching. The third property, which is efficiency of aux, states that the auxiliary information produced by \(\mathsf {AuxGen}\) should be a fixed polynomial in \(\lambda \). Finally, we have the indistinguishability of aux property that states that the auxiliary information obtained by \(\mathsf {AuxGen}\) on input two encodings \({\mathcal {E}}_{sk_0}(M)\) and \({\mathcal {E}}_{sk_1}(M)\) and secret key \(sk_0\) is indistinguishability the output of \(\mathsf {AuxGen}\) on input \({\mathcal {E}}_{sk_0}(M)\), \({\mathcal {E}}_{sk_1}(M)\) and secret key \(sk_1\).

Definition 4

(Splittable iO). A splittable iO scheme, denoted by \(\mathsf {siO}=(\mathsf {Obf},\mathsf {Eval})\) for a class of Turing machines \(\mathcal {M}\), is an indistinguishability obfuscation scheme that is associated with a patchable encoding scheme \(\mathsf {UE}=({\mathsf {Gen}}, \mathsf {Encode}, \mathsf {GenPatch}, \mathsf {AppPatch}, \mathsf {Decode})\) and satisfies the following properties:

  • Splittable Property: \(\mathsf {Obf}\) consists of \({\mathsf {Gen}},\mathsf {Encode}\) and an additional PPT algorithm \(\mathsf {AuxGen}\). On input \((1^{\lambda },M)\) it proceeds in the following three phases:

    1. 1.

      Encoding of M using \(\mathsf {UE}\): (a) \(sk_0 \leftarrow {\mathsf {Gen}}(1^{\lambda })\); \(sk_1 \leftarrow {\mathsf {Gen}}(1^{\lambda })\). (b) \({\mathcal {E}}_{sk_0}(M) \leftarrow \mathsf {Encode}(sk_0,M)\); \({\mathcal {E}}_{sk_1}(M) \leftarrow \mathsf {Encode}(sk_1,M)\)

    2. 2.

      Generation of aux: \(aux \leftarrow \mathsf {AuxGen}\left( sk_0, {\mathcal {E}}_{sk_0}(M),{\mathcal {E}}_{sk_1}(M) \right) \)

    Output \(\langle {M}\rangle = \left( {\mathcal {E}}_{sk_0}(M), {\mathcal {E}}_{sk_1}(M), aux \right) \). The secret state associated with this execution is set to be \((sk_0,sk_1)\).

  • Correctness of \(\mathsf {AuxGen}\) : Let \(M \in \mathcal {M}\) and let \(P_1,\ldots ,P_L\) be a sequence of patches. Let \(M_i\) be the \(i^{th}\) updated machine, \(M_i \leftarrow {\mathsf {Update}}(M_{i-1},P)\), for every \(i \in [L]\), where \(M_{0}=M\).

    Consider the following process:

    • Let \(sk_0,sk_1\) be such that \(sk_0 \leftarrow \mathsf {UE}.{\mathsf {Gen}}(1^{\lambda })\), \(sk_1 \leftarrow \mathsf {UE}.{\mathsf {Gen}}(1^{\lambda })\).

    • Let \({\mathcal {E}}_{sk_0}(M) \leftarrow \mathsf {UE}.\mathsf {Encode}(sk_0,M)\) and \({\mathcal {E}}_{sk_1}(M) \leftarrow \mathsf {UE}.\mathsf {Encode}( sk_0, M)\).

    • Consider the \(i^{th}\) updated encodings, \({\mathcal {E}}_{sk_0}(M_i) \leftarrow \mathsf {UE}.\mathsf {AppPatch}( {\mathcal {E}}_{sk_0}(M_{i-1}), \mathsf {UE}.\mathsf {GenPatch}(sk_0, P_i))\) and \({\mathcal {E}}_{sk_1}(M_i) \leftarrow \mathsf {UE}.\mathsf {AppPatch}\left( {\mathcal {E}}_{sk_1}(M_{i-1}), \mathsf {UE}.\mathsf {GenPatch}(sk_1,P_i) \right) \).

    • Let \(aux \leftarrow \mathsf {AuxGen}(sk_0,{\mathcal {E}}_{sk_0}(M_L), {\mathcal {E}}_{sk_1}(M_L))\) and set \(\langle {M_L}\rangle =({\mathcal {E}}_{sk_0}(M_L),{\mathcal {E}}_{sk_1}(M_L),aux)\).

    For every x, we have \(\mathsf {Eval}(\langle {M_L}\rangle ,x)=M_L(x)\).

  • Efficiency of aux: There exists a polynomial p such that the following holds. Let \(( {\mathcal {E}}_{sk_0}(M), {\mathcal {E}}_{sk_1}(M), aux) \leftarrow \mathsf {Obf}(1^{\lambda },M)\) for \(M \in \mathcal {M}\). Then, \(|aux|=p(\lambda )\).

  • Indistinguishability of aux: Consider \(M_0,M_1 \in \mathcal {M}\) such that \(M_0(x)=M_1(x)\) for every \(x \in \{0,1\}^*\). Suppose \(E_0,E_1,sk_0,sk_1\) are such that \(M_0 \leftarrow \mathsf {Decode}(sk_0,E_0)\) and \(M_1 \leftarrow \mathsf {Decode}(sk_1,E_1)\). We have,

    $$\begin{aligned} \left\{ E_0,E_1,sk_0,sk_1,aux_{0} \right\} \approx _c \left\{ E_0,E_1,sk_0,sk_1,aux_1 \right\} , \end{aligned}$$

    where \(aux_b \leftarrow \mathsf {AuxGen}(sk_b,E_0,E_1)\) for \(b \in \{0,1\}\).

An instantiation of splittable iO is presented in the full version.

We note that the above definition can be extended to the parallel patches setting if the underlying patchable encoding scheme supports parallel patches.

4 Splittable iO to Single-Program \(pa\text {-}{i\mathcal {O}} \)

We give a generic transformation from splittable iO to single-program patchable iO.

Construction. The main tool we use in our construction is a splittable iO scheme \(\mathsf {siO}=( \mathsf {siO}.\mathsf {Obf}, \mathsf {siO}.\mathsf {Eval})\) associated with the updatable encoding scheme \(\mathsf {UE}=({\mathsf {Gen}}, \mathsf {Encode}, \mathsf {GenPatch}, \mathsf {AppPatch}, \mathsf {Decode})\). We construct a single-program patchable obfuscation scheme \(pa\text {-}{i\mathcal {O}} \) below.

: It outputs \(\mathsf {SK}=\bot \).

: It takes as input the secret key \(\mathsf {SK}=\bot \) and a TM \(M \in \mathcal {M}\). The obfuscation of M is essentially the obfuscation of M with respect to \(\mathsf {siO}\). That is, it executes the obfuscate algorithm of \(\mathsf {siO}\) on M; \(({\mathcal {E}}_{sk_0}(M), {\mathcal {E}}_{sk_1}(M), aux) \leftarrow \mathsf {siO}.\mathsf {Obf}(1^{\lambda },M)\). Denote \(({\mathcal {E}}_{sk_0}(M), {\mathcal {E}}_{sk_1}(M), aux)\) by \(\langle {M}\rangle \). Let the state associated with this execution be \((sk_0,sk_1)\) (refer to Splittable Property in Definition 4).

It outputs the obfuscated TM \(\langle {M}\rangle \). The state is set to be \(\mathsf {st}=\left( sk_0,sk_1,{\mathcal {E}}_{sk_0}(M),{\mathcal {E}}_{sk_1}(M) \right) \). That is, the state consists of the two secret keys and the patchable encodings of M with respect to \(sk_0\) and \(sk_1\).

: It takes as input the secret key \(\mathsf {SK}=\bot \), a description of a patch \(P \in \mathcal {P}\) and state \(\mathsf {st}=\left( sk_0,sk_1,{\mathcal {E}}_{sk_0}(M),{\mathcal {E}}_{sk_1}(M) \right) \). Then,

  • It computes the secure patches, \(\widetilde{P}^0 \leftarrow \mathsf {UE}.\mathsf {GenPatch}(sk_0,P)\) and \(\widetilde{P}^1 \leftarrow \mathsf {UE}.\mathsf {GenPatch}(sk_1,P)\).

  • It applies the secure patches on the encodings, \({\mathcal {E}}_{sk_0}(M') \leftarrow \mathsf {UE}.\mathsf {AppPatch}({\mathcal {E}}_{sk_0}(M),\widetilde{P}^0)\) and \({\mathcal {E}}_{sk_1}(M') \leftarrow \mathsf {UE}.\mathsf {AppPatch}({\mathcal {E}}_{sk_1}(M),\widetilde{P}^1)\).

  • It then executes \(\mathsf {AuxGen}\) algorithm of \(\mathsf {siO}\). It computes \(aux' \leftarrow \mathsf {AuxGen}(sk_0,{\mathcal {E}}_{sk_0}(M_0),{\mathcal {E}}_{sk_1}(M_1))\).

It outputs a secure patch \(\langle {P}\rangle =(\widetilde{P}^0,\widetilde{P}^1,aux')\). It updates the state to be \(\mathsf {st}'=(sk_0,sk_1, {\mathcal {E}}_{sk_0}(M'), {\mathcal {E}}_{sk_1}(M'))\).

Note: It suffices to just include the encodings \((\widetilde{P}^0,\widetilde{P}^1)\) (and not the updated encodings \({\mathcal {E}}_{sk_0}(M'),{\mathcal {E}}_{sk_1}(M')\) ) as part of secure patch because anyone having the original pair of encodings \(({\mathcal {E}}_{sk_0}(M),{\mathcal {E}}_{sk_1}(M))\) can now recompute the \(({\mathcal {E}}_{sk_0}(M'),{\mathcal {E}}_{sk_1}(M'))\) by using just \((\widetilde{P}^0,\widetilde{P}^1)\).

: It takes as input an obfuscated TM \(\langle {M}\rangle =({\mathcal {E}}_{sk_0}(M), {\mathcal {E}}_{sk_1}(M), aux)\) and a secure patch \(\langle {P}\rangle =(\widetilde{P}^0,\widetilde{P}^1,aux')\).

  • It applies the secure patches on the encodings, \({\mathcal {E}}_{sk_0}(M') \leftarrow \mathsf {UE}.\mathsf {AppPatch}({\mathcal {E}}_{sk_0}(M),\widetilde{P}^0)\) and \({\mathcal {E}}_{sk_1}(M') \leftarrow \mathsf {UE}.\mathsf {AppPatch}({\mathcal {E}}_{sk_1}(M),\widetilde{P}^1)\).

  • It replaces aux with \(aux'\) which is sent as part of the patch.

It outputs an updated obfuscation \(\langle {M'}\rangle =({\mathcal {E}}_{sk_0}(M'), {\mathcal {E}}_{sk_1}(M'), aux')\).

: It takes as input an obfuscated TM \(\langle {M}\rangle \) and an input x. It executes the evaluation algorithm of \(\mathsf {siO}\); \(y \leftarrow \mathsf {siO}.\mathsf {Eval}(\langle {M}\rangle ,x)\). Output y.

Efficiency. We claim that the size of the secure patch solely depends on the size of the patch and the security parameter. In particular, it is independent of the size of the machine.

Consider a patch P. Let the output of \(\mathsf {GenPatch}(\mathsf {SK},P,\mathsf {st})\) be \(\langle {P}\rangle =(\widetilde{P}^0,\widetilde{P}^1,aux')\). From the efficiency of the underlying patchable encoding scheme, \(|(\widetilde{P}^0,\widetilde{P}^1)|=\mathrm {poly}(\lambda ,|P|)\). From the efficiency of the underlying spittable iO scheme, \(|aux'|=\mathrm {poly}(\lambda )\).

Remark 4

The secure patch generation time in the above scheme is proportional to the size of the obfuscated machine. This is in general undesirable and we show how to deal with this issue in the full version.

Correctness of Sequential Updating. Consider a TM \(M_0 \in \mathcal {M}\) and a sequence of patches \(P_1,\ldots ,P_{L}\in \mathcal {P}\). Consider the following two processes generated using the above scheme. For every \(i \in \{1,\ldots ,L\}\), we have:

  • Obfuscate-then-Update: Compute the following: (a) \(\mathsf {SK}\leftarrow \mathsf {Setup}(1^{\lambda })\), (b) \((\langle {M_0}\rangle ,\mathsf {st}_0) \leftarrow \mathsf {Obf}(\mathsf {SK},M_0)\), (c) \((\langle {P_{i}}\rangle ,\mathsf {st}_i) \leftarrow \mathsf {GenPatch}(\mathsf {SK},P_i,\mathsf {st}_{i-1})\), (d) \(\langle {M_{i}}\rangle \leftarrow \mathsf {AppPatch}\Big (\langle {M_{i-1}}\rangle ,\langle {P_{i}}\rangle \Big )\).

  • Update: \(M_{i} \leftarrow {\mathsf {Update}}(M_{i-1},P_{i})\).

We have the following claim.

Claim

For every x, we have \(\mathsf {Eval}(\langle {M_L}\rangle ,x)=M_L(x)\).

Proof

Let \(\langle {M_0}\rangle =(E_0^0,E_1^0,aux^0)\), \(\mathsf {st}=(sk_0,sk_1,E_0^0,E_1^0)\) and \(\langle {M_L}\rangle =(E_0^L,E_1^L,aux^L)\). Note that \(E_0\) is the output of an execution of \(\mathsf {Encode}(sk_0,M_0)\) and \(aux^0\) is the output of \(\mathsf {AuxGen}(sk_0,E_0^0,E_1^0)\). From the correctness of patchable encoding scheme, we have \(\mathsf {Decode}(\mathsf {SK}_0,E_0^L)=M_L\). Using this fact along with the correctness of \(\mathsf {AuxGen}\) property of \(\mathsf {siO}\), we get that the output of \(\mathsf {Eval}(\langle {M_L}\rangle ,x)\) to be \(M_L(x)\).

Security of Sequential Updating. We prove,

Theorem 7

\(pa\text {-}{i\mathcal {O}} \) satisfies security of sequential updating property.

A formal proof for the above theorem can be found in the full version.