<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Mark Schultz-Wu</title>
    <subtitle>Lattice &amp; FHE cryptography, and assorted TCS.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://mark.schultz-wu.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-07-02T00:00:00+00:00</updated>
    <id>https://mark.schultz-wu.com/atom.xml</id>
    <entry xml:lang="en">
        <title>Authoring kit reference</title>
        <published>2026-07-02T00:00:00+00:00</published>
        <updated>2026-07-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com/blog/authoring-kit/"/>
        <id>https://mark.schultz-wu.com/blog/authoring-kit/</id>
        
        <content type="html" xml:base="https://mark.schultz-wu.com/blog/authoring-kit/">&lt;p&gt;A hidden reference page exercising every shortcode in the authoring kit. Not
listed anywhere; reachable only by URL. Use it as a smoke test after template
changes.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;math&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#math&quot; aria-label=&quot;Anchor link for: math&quot;&gt;🔗&lt;&#x2F;a&gt;Math&lt;&#x2F;h1&gt;
&lt;p&gt;Inline math like &lt;span class=&quot;math&quot;&gt;\(e = mc^2\)&lt;&#x2F;span&gt; and a prime &lt;span class=&quot;math&quot;&gt;\(f&#x27;(x)\)&lt;&#x2F;span&gt; (curly-quote-safe), plus a
display block:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\Pr[\,\|e\| &gt; t\,] \le 2\exp\!\left(-\frac{t^2}{2\sigma^2}\right).\]&lt;&#x2F;span&gt;
&lt;p&gt;Math is authored as plain &lt;code&gt;$...$&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;$$...$$&lt;&#x2F;code&gt; in &lt;code&gt;content-src&#x2F;&lt;&#x2F;code&gt; and wrapped into
raw shortcodes by &lt;code&gt;scripts&#x2F;wrap_math.py&lt;&#x2F;code&gt;, so &lt;code&gt;smart_punctuation&lt;&#x2F;code&gt; never touches
it.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;callouts&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#callouts&quot; aria-label=&quot;Anchor link for: callouts&quot;&gt;🔗&lt;&#x2F;a&gt;Callouts&lt;&#x2F;h1&gt;
&lt;aside class=&quot;callout callout-note&quot;&gt;
  &lt;p class=&quot;callout-title&quot;&gt;Aside&lt;&#x2F;p&gt;
  &lt;div class=&quot;callout-body&quot;&gt;

&lt;p&gt;Asides hold tangential remarks. They render &lt;strong&gt;Markdown&lt;&#x2F;strong&gt;, including math such as
&lt;span class=&quot;math&quot;&gt;(\sigma^2)&lt;&#x2F;span&gt; and links like &lt;a href=&quot;https:&#x2F;&#x2F;mark.schultz-wu.com&#x2F;blog&#x2F;lattices-for-programmers-pt1&#x2F;&quot;&gt;the LWE post&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;aside&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;
  &lt;p class=&quot;callout-title&quot;&gt;Warning&lt;&#x2F;p&gt;
  &lt;div class=&quot;callout-body&quot;&gt;

&lt;p&gt;Warnings flag caveats. Math here is also safe: &lt;span class=&quot;math&quot;&gt;(|x|_\infty \le q&#x2F;2)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;aside&gt;
&lt;h1 id=&quot;figure&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#figure&quot; aria-label=&quot;Anchor link for: figure&quot;&gt;🔗&lt;&#x2F;a&gt;Figure&lt;&#x2F;h1&gt;
&lt;figure class=&quot;figure&quot;&gt;
  &lt;img src=&quot;https:&#x2F;&#x2F;upload.wikimedia.org&#x2F;wikipedia&#x2F;commons&#x2F;thumb&#x2F;9&#x2F;93&#x2F;Lattice_of_the_divisibility_of_60.svg&#x2F;320px-Lattice_of_the_divisibility_of_60.svg.png&quot;
       alt=&quot;A *figure* with a Markdown caption.&quot; style=&quot;max-width: 240px&quot; &#x2F;&gt;
  &lt;figcaption&gt;A &lt;em&gt;figure&lt;&#x2F;em&gt; with a Markdown caption.&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h1 id=&quot;interactive-demo&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#interactive-demo&quot; aria-label=&quot;Anchor link for: interactive-demo&quot;&gt;🔗&lt;&#x2F;a&gt;Interactive demo&lt;&#x2F;h1&gt;
&lt;p&gt;The demo below is a real Rust → wasm demo (&lt;code&gt;demos&#x2F;noise-budget&#x2F;&lt;&#x2F;code&gt;) — an LWE
noise-budget visualizer. Build it with &lt;code&gt;just demos&lt;&#x2F;code&gt;; until then it degrades
gracefully to the fallback text.&lt;&#x2F;p&gt;

&lt;div class=&quot;demo&quot; id=&quot;demo-noise-budget&quot; data-demo=&quot;noise-budget&quot;&gt;
  &lt;noscript&gt;This interactive demo requires JavaScript and WebAssembly.&lt;&#x2F;noscript&gt;
  &lt;div class=&quot;demo-fallback&quot;&gt;&lt;p&gt;LWE noise-budget demo (build with &lt;code&gt;just demos&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;script type=&quot;module&quot;&gt;
  (() =&gt; {
    const el = document.getElementById(&quot;demo-noise-budget&quot;);
    const src = &quot;https:&#x2F;&#x2F;mark.schultz-wu.com&#x2F;demos&#x2F;noise-budget&#x2F;noise-budget.js&quot;;
    let started = false;
    const boot = async () =&gt; {
      if (started) return; started = true;
      try {
        const mod = await import(src);
        await (mod.default ? mod.default() : Promise.resolve());
        if (typeof mod.mount === &quot;function&quot;) mod.mount(el);
      } catch (e) {
        el.classList.add(&quot;demo-error&quot;);
        el.innerHTML = &quot;&lt;p&gt;Demo failed to load. Run &lt;code&gt;just demos&lt;&#x2F;code&gt; to build it.&lt;&#x2F;p&gt;&quot;;
        console.error(&quot;demo noise-budget failed:&quot;, e);
      }
    };
    if (&quot;IntersectionObserver&quot; in window) {
      const io = new IntersectionObserver((ents) =&gt; {
        for (const e of ents) if (e.isIntersecting) { io.disconnect(); boot(); }
      }, { rootMargin: &quot;200px&quot; });
      io.observe(el);
    } else { boot(); }
  })();
&lt;&#x2F;script&gt;
&lt;h1 id=&quot;footnotes&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#footnotes&quot; aria-label=&quot;Anchor link for: footnotes&quot;&gt;🔗&lt;&#x2F;a&gt;Footnotes&lt;&#x2F;h1&gt;
&lt;p&gt;Footnotes collect at the bottom.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-ex-1&quot;&gt;&lt;a href=&quot;#fn-ex&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-ex&quot;&gt;
&lt;p&gt;Like this one. &lt;a href=&quot;#fr-ex-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Hintless Single-Server Private Information Retrieval</title>
        <published>2023-11-14T00:00:00+00:00</published>
        <updated>2023-11-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com/blog/hintless-pir/"/>
        <id>https://mark.schultz-wu.com/blog/hintless-pir/</id>
        
        <content type="html" xml:base="https://mark.schultz-wu.com/blog/hintless-pir/">&lt;p&gt;This summer, I was hosted by Mariana Raykova and Baiyu Li at Google to work on Single Server PIR.
This internship led to a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1733&quot;&gt;paper&lt;&#x2F;a&gt;.
Rather than try to put together some tweet-thread (or X-thread? who knows) talking about the result,
I thought it best to write it up somewhere that supports latex, e.g. here.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;private-information-retrieval&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#private-information-retrieval&quot; aria-label=&quot;Anchor link for: private-information-retrieval&quot;&gt;🔗&lt;&#x2F;a&gt;Private Information Retrieval&lt;&#x2F;h1&gt;
&lt;p&gt;Private Information Retrieval is the problem of “securely querying” a database.
In particular, you have a client, and a server, who holds a &lt;em&gt;public&lt;&#x2F;em&gt; database.
The client wants to retrieve a particular record from this database without the server learning which record was retrieved.
Note that there is an obvious trivial protocol — the server transmits the whole database!
The client can then locally retrieve the record they want, and the server learns nothing.&lt;&#x2F;p&gt;
&lt;p&gt;This scheme is actually fairly (computationally) efficient.
The server has a linear scan through the database, and the client can stream the database and only store their desired record,
e.g. the memory requirements on the client are fairily small.
The bandwidth of the scheme is very large though, and the main goal in PIR research is to reduce these bandwidth requirements.&lt;&#x2F;p&gt;
&lt;p&gt;This is done various ways. Typically, authors like to add some “extra tools” to the standard PIR setting, for example&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;949&quot;&gt;SimplePIR&lt;&#x2F;a&gt;: Having a (query-independent) “hint” the client downloads beforehand, that they can amortize over all queries.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;204&quot;&gt;TreePIR&lt;&#x2F;a&gt;: Assuming the database is held by two non-colluding servers.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;452&quot;&gt;Piano&lt;&#x2F;a&gt;: Assume the entire database is streamed to a memory-bound client beforehand.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Under these assumptions, one can get practically efficient schemes, where efficiency metrics tend to be&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;total bandwidth cost, and&lt;&#x2F;li&gt;
&lt;li&gt;server computational cost.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For example, SimplePIR has throughput comperable to the memory bandwidth of certain processors,
or in other words server’s computational cost in SimplePIR is comperable to a linear scan through the database.
And Piano is even faster!&lt;&#x2F;p&gt;
&lt;p&gt;There do exist schemes that avoid these assumptions (for example &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;368&quot;&gt;SpiralPIR&lt;&#x2F;a&gt;) which are still pretty fast, but
there’s a pretty noticable slowdown — in our measurements SpiralPIR was at least an order of magnitude slower than SimplePIR.
Our goal was to bridge this gap — give a scheme that avoided the above three assumptions, but had better server computation than SpiralPIR.
We ended up with a scheme that achieves this goal “asymptotically”, meaning the cost to execute it is (in the limit of large database sizes) identical
to that of SimplePIR.
We measured that this leads to concretely small overhead (for certain “large enough” databases of practically relevant sizes), e.g. we can remove SimplePIR’s hint at low cost.&lt;&#x2F;p&gt;
&lt;p&gt;In the interest of brevity, I’ll focus on describing the main idea behind our main construction, as well as a particular optimization that we introduced that I like quite a bit (and is theoretically an order-of-magnitude speedup, though practically I think we measured it as a 6x speedup).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;single-server-pir-from-lwe&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#single-server-pir-from-lwe&quot; aria-label=&quot;Anchor link for: single-server-pir-from-lwe&quot;&gt;🔗&lt;&#x2F;a&gt;Single Server PIR from LWE&lt;&#x2F;h1&gt;
&lt;p&gt;We start with the SimplePIR (and FrodoPIR) construction.
This leverages the following simple idea.
If you format an &lt;span class=&quot;math&quot;&gt;\(m\)&lt;&#x2F;span&gt;-record database &lt;span class=&quot;math&quot;&gt;\(\mathsf{DB}\)&lt;&#x2F;span&gt; as a matrix &lt;span class=&quot;math&quot;&gt;\(\mathsf{DB}\in \mathbb{Z}_p^{\sqrt{m}\times \sqrt{m}}\)&lt;&#x2F;span&gt;,
then one can retrieve the &lt;span class=&quot;math&quot;&gt;\(i\)&lt;&#x2F;span&gt;th column of this database by multiplying it via the &lt;span class=&quot;math&quot;&gt;\(i\)&lt;&#x2F;span&gt;th basis vector &lt;span class=&quot;math&quot;&gt;\(e_i\)&lt;&#x2F;span&gt;.
This can then be computed using homomorphic encryption, namely&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\mathsf{DB}, \mathsf{Enc}(e_i)\mapsto \mathsf{Enc}(\mathsf{DB}\cdot e_i).\]&lt;&#x2F;span&gt;
&lt;p&gt;All one needs is an encryption scheme that supports efficient homomorphic matrix-vector multiplication.
Learning with Errors (LWE)-based encryption does just this!
I’ve written some &lt;a href=&quot;https:&#x2F;&#x2F;mark.schultz-wu.com&#x2F;blog&#x2F;nist-standard-out&#x2F;&quot;&gt;blog posts&lt;&#x2F;a&gt; on this in the past geared towards a general audience,
so I will be brief below.
LWE-based ciphertexts take the form&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[C := [A, A\cdot s + f + (q&#x2F;p)m]\in\mathbb{Z}_q^{\sqrt{m}\times n} \times \mathbb{Z}_q^{\sqrt{m}\times 1}\]&lt;&#x2F;span&gt;
&lt;p&gt;where &lt;span class=&quot;math&quot;&gt;\(A\)&lt;&#x2F;span&gt; is a uniformly-random matrix, &lt;span class=&quot;math&quot;&gt;\(s\)&lt;&#x2F;span&gt; is a (typically short) secret vector, &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; is a (short and secret) “noise” vector, and &lt;span class=&quot;math&quot;&gt;\(m\in\mathbb{Z}_p^{\sqrt{m}}\)&lt;&#x2F;span&gt; is the message one is encrypting.
One can efficient compute matrix-vector products using this, as&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\mathsf{DB}\cdot C := [\mathsf{DB}\cdot A, \mathsf{DB}\cdot A\cdot s + \mathsf{DB}\cdot f + (q&#x2F;p)\mathsf{DB}\cdot m]\]&lt;&#x2F;span&gt;
&lt;p&gt;There are some (routine) details that one has to get right with the above scheme, but for the most part the fact that it yields a &lt;em&gt;correct&lt;&#x2F;em&gt; homomorphic scheme is standard.
What is harder is getting it to be &lt;em&gt;bandwidth-efficient&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The issue is in the transmission of &lt;span class=&quot;math&quot;&gt;\(A\in\mathbb{Z}_q^{\sqrt{m}\times n}\)&lt;&#x2F;span&gt;, and in particular its dependence on &lt;span class=&quot;math&quot;&gt;\(n\)&lt;&#x2F;span&gt;.
This is the lattice dimension, and is required to be &lt;span class=&quot;math&quot;&gt;\(\geq 500\)&lt;&#x2F;span&gt; for security purposes (though depending on how large &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt; is this can grow much higher, e.g. in the thousands).
This means that the “&lt;span class=&quot;math&quot;&gt;\(A\)&lt;&#x2F;span&gt;” component of ciphertexts is more than &lt;span class=&quot;math&quot;&gt;\(500\times\)&lt;&#x2F;span&gt; larger than the component containing the message.
There is a standard trick to “compress” &lt;span class=&quot;math&quot;&gt;\(A\)&lt;&#x2F;span&gt; to a PRG &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-prg-1&quot;&gt;&lt;a href=&quot;#fn-prg&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; seed &lt;span class=&quot;math&quot;&gt;\(sd\)&lt;&#x2F;span&gt;, which is then expanded to &lt;span class=&quot;math&quot;&gt;\(A := \mathsf{PRG}(sd)\)&lt;&#x2F;span&gt;.
This works to minimize the size of the client’s encryption.
The issue is that when the server computes&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\mathsf{DB}\cdot A = \mathsf{DB}\cdot \mathsf{PRG}(sd)\]&lt;&#x2F;span&gt;
&lt;p&gt;there is no way to compress this back down to a similarly short seed &lt;span class=&quot;math&quot;&gt;\(sd&#x27;\)&lt;&#x2F;span&gt;.
The typical way to circumvent this issue is to using something like Ring Learning with Errors-based schemes, where the “&lt;span class=&quot;math&quot;&gt;\(A\)&lt;&#x2F;span&gt;” component
is the same size as the message-dependent component.
This has two issues in our setting though.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Our homomorphic computation is a matrix-vector multiplication. This is quite efficient for LWE, but less so for RLWE.&lt;&#x2F;li&gt;
&lt;li&gt;For LWE-based encryption, one can freely choose the modulus &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt;. For example, one can set &lt;span class=&quot;math&quot;&gt;\(q \in \{2^{32}, 2^{64}\}\)&lt;&#x2F;span&gt; for fast hardware-based arithmetic.
For RLWE-based encryption, there are often restrictions on &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt;, and &lt;span class=&quot;math&quot;&gt;\(q\in\{2^{32}, 2^{64}\}\)&lt;&#x2F;span&gt; didn’t work for our protocols.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;In our setting we are able to (almost) completely solve the first problem.
In particular, we give an RLWE-based protocol to securely compute matrix-vector multiplication that is practically (when measured in &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}_q\)&lt;&#x2F;span&gt; operations) only a small constant factor larger than the corresponding plaintext computation.
This amounts to &lt;em&gt;heavily&lt;&#x2F;em&gt; optimizing a standard protocol (the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2014&#x2F;106&quot;&gt;“Diagonally Dominant” multiplication algoriothm&lt;&#x2F;a&gt;), including shaving a &lt;span class=&quot;math&quot;&gt;\(O(\log n)\)&lt;&#x2F;span&gt; factor that I will describe at the end of this post.
When measured in &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}_q\)&lt;&#x2F;span&gt; operations, our protocol is within constant factors of the cost of the LWE-based protocol, which is within constant factors of the underlying &lt;em&gt;plaintext&lt;&#x2F;em&gt; computation.
While this is great, recall that existing protocols have server compute comperable to a &lt;em&gt;linear scan&lt;&#x2F;em&gt; through the database.
So losing constant factors (which I expect to be &lt;span class=&quot;math&quot;&gt;\(\approx 10\times\)&lt;&#x2F;span&gt;) isn’t good enough in this setting.
There are some other limitations of our protocol (it defers certain operations to the client post-decryption, and some more techincal things),
in our setting of PIR it is theoretically quite compelling.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;simplepir-as-a-reduction-from-pir-to-linpir&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#simplepir-as-a-reduction-from-pir-to-linpir&quot; aria-label=&quot;Anchor link for: simplepir-as-a-reduction-from-pir-to-linpir&quot;&gt;🔗&lt;&#x2F;a&gt;SimplePIR as a Reduction from PIR to LinPIR&lt;&#x2F;h2&gt;
&lt;p&gt;As mentioned in the above, at a high level one can build PIR from LWE by having&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Clients upload &lt;span class=&quot;math&quot;&gt;\(C := [A, A\cdot s + f + (q&#x2F;p)e_i]\)&lt;&#x2F;span&gt;,&lt;&#x2F;li&gt;
&lt;li&gt;The server compute &lt;span class=&quot;math&quot;&gt;\(\mathsf{DB} \cdot C\)&lt;&#x2F;span&gt;, and&lt;&#x2F;li&gt;
&lt;li&gt;return this to the client, who decrypts.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This requires transmitting &lt;span class=&quot;math&quot;&gt;\(A\)&lt;&#x2F;span&gt; and &lt;span class=&quot;math&quot;&gt;\(\mathsf{DB}\cdot A\)&lt;&#x2F;span&gt;, which are large.
SimplePIR optimizes this simple protocol by “standardizing” a single matrix &lt;span class=&quot;math&quot;&gt;\(A := \mathsf{PRG}(sd)\)&lt;&#x2F;span&gt;, and having the client download &lt;span class=&quot;math&quot;&gt;\((sd, \mathsf{DB}\cdot \mathsf{PRG}(sd))\)&lt;&#x2F;span&gt; before making queries.
Modulo certain technicalities, this allows the client to omit transmitting &lt;span class=&quot;math&quot;&gt;\(A\)&lt;&#x2F;span&gt; from their query,
and the server to omit transmitting &lt;span class=&quot;math&quot;&gt;\(\mathsf{DB}\ast A\)&lt;&#x2F;span&gt;, fixing the issue.&lt;&#x2F;p&gt;
&lt;p&gt;There is an alternative way to view what SimplePIR is doing, which I find useful in describing our protocol.
Recall that one way of viewing a standard PIR scheme is as a way of securely computing&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[M, x \mapsto M\cdot x\]&lt;&#x2F;span&gt;
&lt;p&gt;where &lt;span class=&quot;math&quot;&gt;\(M = \mathsf{DB}\)&lt;&#x2F;span&gt; is a database, formatted as a matrix, and &lt;span class=&quot;math&quot;&gt;\(x =e_i\)&lt;&#x2F;span&gt; is a basis vector.
SimplePIR reduces this to securely computing&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[M, x\mapsto M\cdot x\]&lt;&#x2F;span&gt;
&lt;p&gt;where &lt;span class=&quot;math&quot;&gt;\(M = \mathsf{DB}\ast A\)&lt;&#x2F;span&gt; is the “hint”, and &lt;span class=&quot;math&quot;&gt;\(x = s\)&lt;&#x2F;span&gt; is the LWE secret.
We call this a &lt;em&gt;linear&lt;&#x2F;em&gt; PIR scheme.
So SimplePIR reduces a standard PIR query to the database &lt;span class=&quot;math&quot;&gt;\(\mathsf{DB}\in\mathbb{Z}_p^{\sqrt{m}\times \sqrt{m}}\)&lt;&#x2F;span&gt;
to a linear PIR query to the “hint” &lt;span class=&quot;math&quot;&gt;\(H:=\mathsf{DB}\cdot A\in \mathbb{Z}_q^{\sqrt{m}\times n}\)&lt;&#x2F;span&gt;.
For large-enough &lt;span class=&quot;math&quot;&gt;\(m\)&lt;&#x2F;span&gt; this is a smaller database, yielding a concrete savings.
SimplePIR itself can be viewed as using the trivial PIR protocol of transmitting &lt;span class=&quot;math&quot;&gt;\(H\)&lt;&#x2F;span&gt; to the client to answer these linear PIR queries.&lt;&#x2F;p&gt;
&lt;p&gt;Our protocol modifies this to use our RLWE-based PIR scheme to answer these linear PIR queries.
As mentioned before, this (concretely) loses constant factors compared to SimplePIR.
This yields to a scheme that has server computational costs of the form&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;math&quot;&gt;\(m + O(\sqrt{m}n)\)&lt;&#x2F;span&gt; operations in &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}_{2^{32}}\)&lt;&#x2F;span&gt;, compared with&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;math&quot;&gt;\(m\)&lt;&#x2F;span&gt; operations in &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}_{2^{32}}\)&lt;&#x2F;span&gt; for SimplePIR.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So, for large-enough &lt;span class=&quot;math&quot;&gt;\(m\)&lt;&#x2F;span&gt;, we can replace the trivial linPIR query to &lt;span class=&quot;math&quot;&gt;\(H\)&lt;&#x2F;span&gt; with a linPIR query to our scheme at no asymptotic cost.
This is (theoretically) the content of the main construction of our paper.
Practically, we use several additional optimizations to make sure  that “large-enough” is not too large.
I’ll mention my favorite such optimization below.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;an-speedup-for-many-rlwe-based-linearly-homomorphic-computations&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-speedup-for-many-rlwe-based-linearly-homomorphic-computations&quot; aria-label=&quot;Anchor link for: an-speedup-for-many-rlwe-based-linearly-homomorphic-computations&quot;&gt;🔗&lt;&#x2F;a&gt;An &lt;span class=&quot;math&quot;&gt;\(O(\log n)\)&lt;&#x2F;span&gt; Speedup for many RLWE-based (Linearly) Homomorphic Computations&lt;&#x2F;h1&gt;
&lt;p&gt;RLWE-based cryptography often describes computations in terms of two isomorphic rings.
There is&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;math&quot;&gt;\(R_{n,q} = \mathbb{Z}_q[x] &#x2F; (x^n+1)\)&lt;&#x2F;span&gt;, which is a ring under addition and multiplication of polynomials modulo &lt;span class=&quot;math&quot;&gt;\((q, x^n+1)\)&lt;&#x2F;span&gt;, and&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;math&quot;&gt;\(\widehat{R}_{n,q}\)&lt;&#x2F;span&gt;, e.g. the set &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}_q\)&lt;&#x2F;span&gt; under coordinate-wise addition and multiplication.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These rings are only isomorphic for certain &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt; (“NTT-friendly”), but they allow you to replace polynomial multiplication (naively &lt;span class=&quot;math&quot;&gt;\(O(n^2)\)&lt;&#x2F;span&gt; time) with a linear-time operation.
One can convert between the two rings at cost &lt;span class=&quot;math&quot;&gt;\(O(n\log n)\)&lt;&#x2F;span&gt; operations in &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}_q\)&lt;&#x2F;span&gt;.
This cost is often the asymptotically dominant cost in homomorphic computations, to the point that counting how many conversions (NTTs) one uses
is generally a decent proxy for overall running time.&lt;&#x2F;p&gt;
&lt;p&gt;We find a way to precompute all NTTs that occur in our protocol in a way that is independent of things like&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the particular client making a query, and&lt;&#x2F;li&gt;
&lt;li&gt;the particular database one is issuing a linear PIR query to.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Practically, after executing the protocol once (say during a preprocessing phase) and producing state that may be kept &lt;em&gt;locally&lt;&#x2F;em&gt; on the server,
we get an &lt;span class=&quot;math&quot;&gt;\(O(\log n)\)&lt;&#x2F;span&gt; speedup.&lt;&#x2F;p&gt;
&lt;p&gt;The high-level idea is simple.
Recall that RLWE-based ciphertexts &lt;span class=&quot;math&quot;&gt;\([a(x), b(x)]\)&lt;&#x2F;span&gt; consist of &lt;em&gt;pairs&lt;&#x2F;em&gt; of polynomials, where&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;math&quot;&gt;\(a(x)\)&lt;&#x2F;span&gt; is independent of the message (and should be “random”), and&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;math&quot;&gt;\(b(x) = a(x)\ast s(x) + f(x) + (q&#x2F;p)m(x)\)&lt;&#x2F;span&gt; is “structured”.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;One almost always wants to keep polynomials in the evaluation representation &lt;span class=&quot;math&quot;&gt;\(\widehat{R}_{n,q}\)&lt;&#x2F;span&gt;, as it has more efficient multiplication.
The only time we want to switch back to &lt;span class=&quot;math&quot;&gt;\(R_{n,q}\)&lt;&#x2F;span&gt; is to compute operations that depend on particular coefficients of the polynomial, which happens
when multiplying a ciphertext by a large plaintext polynomial with low noise growth.
For simplicity, say that multiplying &lt;span class=&quot;math&quot;&gt;\([a(x), b(x)]\)&lt;&#x2F;span&gt; by the large plaintext polynomial &lt;span class=&quot;math&quot;&gt;\(d(x)\)&lt;&#x2F;span&gt; &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-polyhom-1&quot;&gt;&lt;a href=&quot;#fn-polyhom&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
produces a ciphertext &lt;span class=&quot;math&quot;&gt;\(c&#x27; = [F_0^d(a), F_1^d(b)]\)&lt;&#x2F;span&gt;.
Our insight is that if one knows &lt;span class=&quot;math&quot;&gt;\(d\)&lt;&#x2F;span&gt; beforehand, the maps &lt;span class=&quot;math&quot;&gt;\(F_0^d, F_1^d\)&lt;&#x2F;span&gt; can (after preprocessing that is &lt;span class=&quot;math&quot;&gt;\(O(\log n)\)&lt;&#x2F;span&gt; slower) be computed in linear time.
Moreover, the map &lt;span class=&quot;math&quot;&gt;\(F_0^d\)&lt;&#x2F;span&gt; is &lt;em&gt;deterministic&lt;&#x2F;em&gt;, and therefore&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;if you start knowing &lt;span class=&quot;math&quot;&gt;\(a(x)\)&lt;&#x2F;span&gt; (say because &lt;span class=&quot;math&quot;&gt;\(a(x)= \mathsf{PRG}(sd)\)&lt;&#x2F;span&gt;), and&lt;&#x2F;li&gt;
&lt;li&gt;also know &lt;span class=&quot;math&quot;&gt;\(d(x)\)&lt;&#x2F;span&gt; (which is generally the &lt;span class=&quot;math&quot;&gt;\(a(x)\)&lt;&#x2F;span&gt; polynomial of a different ciphertext, for example during key-switching),&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;then the result is a ciphertext &lt;span class=&quot;math&quot;&gt;\(c&#x27; =[F_0^d(a), F_1^d(b)] = [a&#x27;(x), b&#x27;(x)]\)&lt;&#x2F;span&gt; that we also know the polynomial &lt;span class=&quot;math&quot;&gt;\(a&#x27;(x)\)&lt;&#x2F;span&gt; for.
This leaves one in the position to iterate this argument, and remove all NTTs from (certain) computations.&lt;&#x2F;p&gt;
&lt;p&gt;We haven’t tried to describe the precise class of circuits which our preprocessing optimization works for.
My current understanding of the limits are that&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Homomorphic multiplications (either “tensor-based” or “gadget-based”) do not preserve our “knowing &lt;span class=&quot;math&quot;&gt;\(a(x)\)&lt;&#x2F;span&gt;” invariant &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-gadget-1&quot;&gt;&lt;a href=&quot;#fn-gadget&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Homomorphic additions work fine&lt;&#x2F;li&gt;
&lt;li&gt;gadget-based key-switching works fine.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So we can preprocess complex linearly-homomorphic computations (for example the matrix-vector multiplication protocol in our work), but not things like FHEW-type bootstrapping.
There are also some costs for this optimization.
We require that &lt;em&gt;the server&lt;&#x2F;em&gt; knows &lt;span class=&quot;math&quot;&gt;\(a(x)\)&lt;&#x2F;span&gt; beforehand.
It is therefore natural to have the server pick the seed &lt;span class=&quot;math&quot;&gt;\(sd\)&lt;&#x2F;span&gt;, and transmit it to all clients.
This works, but requires the the clients resample an RLWE key &lt;span class=&quot;math&quot;&gt;\(s(x)\)&lt;&#x2F;span&gt; for each query to maintain security.
More importantly, they must also resample any encrypted key material.
In our particular setting this comes at low cost, but in other settings it is likely something that must be balanced against
the potential &lt;span class=&quot;math&quot;&gt;\(O(\log n)\)&lt;&#x2F;span&gt; speedup.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, this is skipping plenty of other stuff in our paper (for example, an additional PIR scheme!), but
seems like a decent analogue for putting together some hard-to-read-twitter-thread.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-prg&quot;&gt;
&lt;p&gt;Technically one needs this to be a hashing-based primitive to be able to get provable security out of it. The term to search is “Extendible output function”, but I won’t belabor the point. &lt;a href=&quot;#fr-prg-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-polyhom&quot;&gt;
&lt;p&gt;This is not as simple as computing &lt;span class=&quot;math&quot;&gt;\([c(x)\ast a(x), c(x)\ast b(x)]\)&lt;&#x2F;span&gt;. This works for “small” polynomials &lt;span class=&quot;math&quot;&gt;\(c(x)\)&lt;&#x2F;span&gt;, but increases the
error too much when &lt;span class=&quot;math&quot;&gt;\(c(x)\)&lt;&#x2F;span&gt; is large. As I am trying to avoid discussions of error in (R)LWE here, I will solely point interested readers to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2020&#x2F;086&quot;&gt;this&lt;&#x2F;a&gt;. &lt;a href=&quot;#fr-polyhom-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-gadget&quot;&gt;
&lt;p&gt;This is to say that we can preprocess NTTs in a circuit using gadget-based operations until the first gadget-based homomorphic multiplication, after which we can no longer preprocess things. &lt;a href=&quot;#fr-gadget-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>NIST-PQC Choices Out</title>
        <published>2022-07-05T00:00:00+00:00</published>
        <updated>2022-07-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com/blog/nist-standard-out/"/>
        <id>https://mark.schultz-wu.com/blog/nist-standard-out/</id>
        
        <content type="html" xml:base="https://mark.schultz-wu.com/blog/nist-standard-out/">&lt;p&gt;Today, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;csrc.nist.gov&#x2F;publications&#x2F;detail&#x2F;nistir&#x2F;8413&#x2F;final&quot;&gt;NIST put out its preliminary choice of PQC algorithms to standardize&lt;&#x2F;a&gt;.
I wrote an introduction to lattice-based KEMs (for non-cryptographers) this last weekend in preparation for the report, where one implements an (aggressively unoptimized) variant of FrodoKEM.
FrodoKEM ended up not being standardized, but the “broad picture” of the construction should still be useful to understand Kyber.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, I am writing this small post to collect links to the three posts on a single page.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mark.schultz-wu.com&#x2F;blog&#x2F;lattices-for-programmers-pt1&#x2F;&quot;&gt;Part 1&lt;&#x2F;a&gt; discusses the base underlying hardness assumption (Learning with Errors) some.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mark.schultz-wu.com&#x2F;blog&#x2F;lattices-for-programmers-pt2&#x2F;&quot;&gt;Part 2&lt;&#x2F;a&gt; constructs a simple lattice-based (private-key) cryptosystem, and&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mark.schultz-wu.com&#x2F;blog&#x2F;lattices-for-programmers-pt3&#x2F;&quot;&gt;Part 3&lt;&#x2F;a&gt; constructs a lattice-based (public-key) cryptosystem.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Textbook RSA and LWE</title>
        <published>2022-07-02T00:00:00+00:00</published>
        <updated>2022-07-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com/blog/lattices-for-programmers-pt1/"/>
        <id>https://mark.schultz-wu.com/blog/lattices-for-programmers-pt1/</id>
        
        <content type="html" xml:base="https://mark.schultz-wu.com/blog/lattices-for-programmers-pt1/">&lt;p&gt;This is a first post in a series of blog posts where I plan on building a
relatively simple lattice-based public-key encryption scheme.
This construction is not novel at all [&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-frodoKEM-1&quot;&gt;&lt;a href=&quot;#fn-frodoKEM&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;], but the intention is to&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;simplify certain optimizations that aren’t needed for security, and&lt;&#x2F;li&gt;
&lt;li&gt;present things in straightforward language, in terms of simple mathematical
concepts.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Throughout, I will first present (insecure) constructions (that are &lt;em&gt;exceedingly&lt;&#x2F;em&gt; simple), before describing how we make them secure.
These insecure constructions correspond to “noiseless learning with errors”.
As we will see later in this particular post, the “noise” is central to the overall security of constructions.&lt;&#x2F;p&gt;
&lt;p&gt;Mathematically, this series of posts will be rather simple.
The main things required will be matrix multiplication, and modular arithmetic.
Lattice-based encryption can involve more complex topics (such as lattices, and modules over polynomial rings), but these are needed solely to investigate the security of optimized constructions.
Our construction is (intentionally) far from optimized, allowing us to ignore these complex topics.&lt;&#x2F;p&gt;
&lt;p&gt;In this post I’ll first talk about other elementary approaches to teaching cryptography (namely Textbook RSA), before introducing the underlying hard problem we will use (the Learning with Errors, or LWE problem).
I’ll finish by giving some informal (but formalizable) justifications for why the LWE problem is hard.
Given the practical (and elementary) approach I am taking though, this justification will necessarily be at a high level.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;textbook-rsa&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#textbook-rsa&quot; aria-label=&quot;Anchor link for: textbook-rsa&quot;&gt;🔗&lt;&#x2F;a&gt;Textbook RSA&lt;&#x2F;h1&gt;
&lt;p&gt;If you’re a programmer interested in learning about cryptography, there are some
decent resources available.
One in particular is a scheme that cryptographers call &lt;em&gt;Textbook RSA&lt;&#x2F;em&gt;.
Most websites you might try to learn about RSA from cover this scheme (see
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.geeksforgeeks.org&#x2F;rsa-algorithm-cryptography&#x2F;&quot;&gt;GeeksForGeeks&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;RSA_(cryptosystem)#Operation&quot;&gt;Wikipedia&lt;&#x2F;a&gt;, or
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.simplilearn.com&#x2F;tutorials&#x2F;cryptography-tutorial&#x2F;rsa-algorithm&quot;&gt;Simplilearn&lt;&#x2F;a&gt;).
Really, if you haven’t formally studied cryptography (but have tinkered around
with it a little bit), “textbook RSA” is likely exactly what you think the RSA
cryptosystem is.&lt;&#x2F;p&gt;
&lt;p&gt;Explicitly:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The public-key is a product of two primes &lt;span class=&quot;math&quot;&gt;\(N = pq\)&lt;&#x2F;span&gt;, along with some value &lt;span class=&quot;math&quot;&gt;\(e\)&lt;&#x2F;span&gt;
(typically hard-coded to either 3, or the better choice [&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-better-1&quot;&gt;&lt;a href=&quot;#fn-better&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;] of &lt;span class=&quot;math&quot;&gt;\[2^{16} + 1 =
   65537\]&lt;&#x2F;span&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;The secret-key is the pair &lt;span class=&quot;math&quot;&gt;\((p, q)\)&lt;&#x2F;span&gt;, along with an algorithm to compute “&lt;span class=&quot;math&quot;&gt;\(e\)&lt;&#x2F;span&gt;th roots &lt;span class=&quot;math&quot;&gt;\[\bmod
   N\]&lt;&#x2F;span&gt;”, namely the map &lt;span class=&quot;math&quot;&gt;\(c\mapsto c^{1&#x2F;e}\bmod N\)&lt;&#x2F;span&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Encryption maps &lt;span class=&quot;math&quot;&gt;\(m\mapsto m^e\bmod N\)&lt;&#x2F;span&gt;, and&lt;&#x2F;li&gt;
&lt;li&gt;Decryption maps &lt;span class=&quot;math&quot;&gt;\(c\mapsto c^{1&#x2F;e}\bmod N\)&lt;&#x2F;span&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It is straightforward to see that this scheme is &lt;em&gt;correct&lt;&#x2F;em&gt;.
This is because&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[m\stackrel{\mathsf{Enc}}{\mapsto}m^e\bmod
N\stackrel{\mathsf{Dec}}{\mapsto}(m^e)^{1&#x2F;e}\bmod N \equiv m\bmod N.\]&lt;&#x2F;span&gt;
&lt;p&gt;In words, encryption raises things to the &lt;span class=&quot;math&quot;&gt;\(e\)&lt;&#x2F;span&gt;th power, and decryption takes
&lt;span class=&quot;math&quot;&gt;\(e\)&lt;&#x2F;span&gt;th roots.
Provided these notions are defined sensibly, they are inverses, and everything
works out.&lt;&#x2F;p&gt;
&lt;p&gt;One then shows a variety of things, such as&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;if you know &lt;span class=&quot;math&quot;&gt;\((p,q)\)&lt;&#x2F;span&gt;, you can efficiently take &lt;span class=&quot;math&quot;&gt;\(e\)&lt;&#x2F;span&gt;th roots, and&lt;&#x2F;li&gt;
&lt;li&gt;if you don’t know &lt;span class=&quot;math&quot;&gt;\((p,q)\)&lt;&#x2F;span&gt;, the “obvious” way to take &lt;span class=&quot;math&quot;&gt;\(e\)&lt;&#x2F;span&gt;th roots is factoring
&lt;span class=&quot;math&quot;&gt;\(N\)&lt;&#x2F;span&gt; first [&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-inequivalent-1&quot;&gt;&lt;a href=&quot;#fn-inequivalent&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;].&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;merits-of-textbook-rsa&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#merits-of-textbook-rsa&quot; aria-label=&quot;Anchor link for: merits-of-textbook-rsa&quot;&gt;🔗&lt;&#x2F;a&gt;Merits of Textbook RSA&lt;&#x2F;h2&gt;
&lt;p&gt;Clearly, the above scheme is &lt;em&gt;very simple&lt;&#x2F;em&gt; to describe.
Mathematically, both encryption and decryption are barely a line each.
Key generation is similarly (conceptually) simple.
Moreover, the underlying hard problem can be presented as being “Factoring”.
This isn’t really true, but it’s somewhat close to the truth, and this problem is (conceptually) simple to understand.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;issues-with-textbook-rsa&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#issues-with-textbook-rsa&quot; aria-label=&quot;Anchor link for: issues-with-textbook-rsa&quot;&gt;🔗&lt;&#x2F;a&gt;Issues with Textbook RSA&lt;&#x2F;h2&gt;
&lt;p&gt;There are two broad issues I’d like to highlight, namely &lt;em&gt;implementation complexity&lt;&#x2F;em&gt; and &lt;em&gt;security&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;implementation-complexity&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#implementation-complexity&quot; aria-label=&quot;Anchor link for: implementation-complexity&quot;&gt;🔗&lt;&#x2F;a&gt;Implementation Complexity&lt;&#x2F;h3&gt;
&lt;p&gt;One issue with the above (simple) description of RSA is that it hides a good deal of complexity.
Standard implementations of RSA require the following algorithms be implemented&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;the extended GCD algorithm, and&lt;&#x2F;li&gt;
&lt;li&gt;primality testing.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Neither of these are that bad to do (having beginning programmers do them can be a good exercise).
For example, the following code snippet is a perfectly reasonable approach at implementing primality testing, as well as a simple rejection sampling algorithm to sample random (large) primes.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import random&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;def isprime(n):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if n % 2 == 0:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        i = 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        while i**2 &amp;lt; n:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            if n % i == 0:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                return False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            i += 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return True&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;def sampleprime(n):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    while True:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        p = random.randint(1, 2**n)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if isprime(p):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            return p&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This leverages that Python’s standard library contains native support for big (2048-bit) integer arithmetic, so we can ignore implementing all of that.
Yay!&lt;&#x2F;p&gt;
&lt;p&gt;The issue with this naive approach is that it is utterly infeasible.
As mentioned, RSA requires 2048-bit integers, or 1024-bit primes.
To verify that a number is prime, the above primality test requires (roughly) &lt;span class=&quot;math&quot;&gt;\(\sqrt{n}\)&lt;&#x2F;span&gt; operations, or &lt;span class=&quot;math&quot;&gt;\(2^{512}\)&lt;&#x2F;span&gt;.
This is to say that the above (natural) primality testing algorithm that many students happily write down is secretely an exponential-time algorithm, and therefore cannot be used for any actual instantiation of RSA.&lt;&#x2F;p&gt;
&lt;p&gt;Therefore, to &lt;em&gt;actually&lt;&#x2F;em&gt; implement RSA you need to discuss fast primality testing algorithms (for example &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Miller%E2%80%93Rabin_primality_test&quot;&gt;Miller-Rabin&lt;&#x2F;a&gt;).
This brings a great deal of complexity into the story (and we even got to skip the big integer implementation!).&lt;&#x2F;p&gt;
&lt;p&gt;This is all to say that while RSA is conceptually simple, actually &lt;em&gt;running&lt;&#x2F;em&gt; RSA for parameters that are thought to be secure requires a great deal of complexity.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;security&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#security&quot; aria-label=&quot;Anchor link for: security&quot;&gt;🔗&lt;&#x2F;a&gt;Security&lt;&#x2F;h3&gt;
&lt;p&gt;The second issue is that RSA (as presented above) is not secure.
Cryptography has a minimal acceptable notion of security known as &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Ciphertext_indistinguishability#Indistinguishability_under_chosen-plaintext_attack_(IND-CPA)&quot;&gt;Indistinguishability under Chosen-Plaintext Attack&lt;&#x2F;a&gt;.
Among other things, this implies that you cannot tell if two ciphertexts are encryptions of the same message.
But for the above “textbook RSA”, if you encrypt the same message twice, you get back the same ciphertext (encryption is &lt;em&gt;deterministic&lt;&#x2F;em&gt;).
This is typically fixed by introducing a &lt;em&gt;padding scheme&lt;&#x2F;em&gt;, but these are both complex, and easy to get wrong (there have been &lt;em&gt;many&lt;&#x2F;em&gt; attacks in practice on improper RSA padding).&lt;&#x2F;p&gt;
&lt;p&gt;So Textbook RSA is simple to describe, but moderately complex to implement in a way that is reasonably efficient for parameters people actually use, and quite complex to implement in a way that is known to be secure.
RSA also has the issue that (even when properly padded) it is insecure against quantum computers, so once those develop further it’ll be insecure in all settings.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-solution-textbook-lwe&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-solution-textbook-lwe&quot; aria-label=&quot;Anchor link for: the-solution-textbook-lwe&quot;&gt;🔗&lt;&#x2F;a&gt;The Solution: Textbook LWE&lt;&#x2F;h2&gt;
&lt;p&gt;While in this blog series I will present a simplified variant of lattice-based encryption (you might call it “Textbook LWE”), the simplifications will mean that the scheme is &lt;em&gt;less efficient&lt;&#x2F;em&gt;, rather than &lt;em&gt;less secure&lt;&#x2F;em&gt;.
While it will be less efficient, it’ll still be &lt;em&gt;plenty&lt;&#x2F;em&gt; efficient compared to things like Textbook RSA — for “real parameters” (actually &lt;em&gt;larger&lt;&#x2F;em&gt; parameters than those used in practice, as I’m somewhat lazy), all operations take less than a second.
There will be inefficiences to the scheme (in particular, the size of the ciphertexts will be poor), but these are things that can be easily fixed if one cares.&lt;&#x2F;p&gt;
&lt;p&gt;I will actually present two constructions of each algorithm under discussion, which I will call the &lt;em&gt;noiseless&lt;&#x2F;em&gt; and &lt;em&gt;noisy&lt;&#x2F;em&gt; constructions.
The noiseless construction will always be conceptually simpler, and capture “the essence” of what is happening (while being insecure).
The noisy construction will be secure, albient somewhat more complex than the noiseless construction.&lt;&#x2F;p&gt;
&lt;p&gt;With that, we’ll discuss the underlying hard problem the constructions will be based on (akin to factoring for RSA, or more properly taking modular roots for RSA).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-learning-with-errors-assumption&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-learning-with-errors-assumption&quot; aria-label=&quot;Anchor link for: the-learning-with-errors-assumption&quot;&gt;🔗&lt;&#x2F;a&gt;The Learning with Errors Assumption&lt;&#x2F;h1&gt;
&lt;p&gt;Similarly to the constructions I describe, I’ll go over noiseless and noisy versions of the Learning with Errors Assumption.
Both are most simply phrased in terms of modular matrix arithmetic.
Throughout, all operations are done modulo &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt; for some (not necessairly prime) number &lt;span class=&quot;math&quot;&gt;\(q\in\mathbb{N}\)&lt;&#x2F;span&gt;.
This is true even for “implicit” operations, for example the additions and multiplications that occur as part of a matrix-vector product &lt;span class=&quot;math&quot;&gt;\(A\vec v\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;noiseless&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#noiseless&quot; aria-label=&quot;Anchor link for: noiseless&quot;&gt;🔗&lt;&#x2F;a&gt;Noiseless&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class=&quot;math&quot;&gt;\(n, q\in\mathbb{N}\)&lt;&#x2F;span&gt; be integers. Let &lt;span class=&quot;math&quot;&gt;\(\vec s\gets (\mathbb{Z}&#x2F;q\mathbb{Z})^n\)&lt;&#x2F;span&gt; be a uniformly random (secret) vector. Then, the Noiseless Learning with Errors assumption is that, for &lt;span class=&quot;math&quot;&gt;\(A\gets (\mathbb{Z}&#x2F;q\mathbb{Z})^{n\times n}\)&lt;&#x2F;span&gt; a uniformly random (public) matrix, then &lt;span class=&quot;math&quot;&gt;\((A, A\vec s)\)&lt;&#x2F;span&gt; is hard to distinguish from uniformly random.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;So, the noiseless Learning with Errors assumption is about the pseudo-randomness of matrix-vector products &lt;span class=&quot;math&quot;&gt;\(A\vec s\)&lt;&#x2F;span&gt;.
Without wasting too many words on this assumption, I’ll simply say that standard linear-algebraic techniques (for example Gaussian elimination) suffice to show that this is insecure.
In particular,given &lt;span class=&quot;math&quot;&gt;\((A, A\vec s)\)&lt;&#x2F;span&gt;, it is straightforward to recover &lt;span class=&quot;math&quot;&gt;\(\vec s\)&lt;&#x2F;span&gt;.
This is what we call in cryptography “bad”.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;noisy&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#noisy&quot; aria-label=&quot;Anchor link for: noisy&quot;&gt;🔗&lt;&#x2F;a&gt;Noisy&lt;&#x2F;h2&gt;
&lt;p&gt;One way to attempt to stop this attack is to introduce noise (we will discuss later how Gaussian elimination behaves with respect to noise).&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class=&quot;math&quot;&gt;\(n, q\in\mathbb{N}\)&lt;&#x2F;span&gt; be integers, and let &lt;span class=&quot;math&quot;&gt;\(\chi\)&lt;&#x2F;span&gt; be a distribution on “small” integers modulo &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt;. Let &lt;span class=&quot;math&quot;&gt;\(\vec s\gets (\mathbb{Z}&#x2F;q\mathbb{Z})^n\)&lt;&#x2F;span&gt; be a uniformly random (secret) vector. Then, the Learning with Errors assumption is that, for &lt;span class=&quot;math&quot;&gt;\(A\gets (\mathbb{Z}&#x2F;q\mathbb{Z})^{n\times n}\)&lt;&#x2F;span&gt; a uniformly random (public) matrix and &lt;span class=&quot;math&quot;&gt;\(\vec e\gets \chi^n\)&lt;&#x2F;span&gt;, then &lt;span class=&quot;math&quot;&gt;\((A, A\vec s +\vec e)\)&lt;&#x2F;span&gt; is hard to distinguish from uniformly random.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The hardness of this problem depends &lt;em&gt;heavily&lt;&#x2F;em&gt; on the underlying choice of parameters &lt;span class=&quot;math&quot;&gt;\(n, q, \chi\)&lt;&#x2F;span&gt; (and there are many variants of this problem I will not describe).
As mentioned before, if there is no noise (i.e. &lt;span class=&quot;math&quot;&gt;\(\chi\)&lt;&#x2F;span&gt; is concentrated on &lt;span class=&quot;math&quot;&gt;\(\{0\}\)&lt;&#x2F;span&gt;) the problem is broken.
If &lt;span class=&quot;math&quot;&gt;\(\chi\)&lt;&#x2F;span&gt; is uniform on &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}&#x2F;q\mathbb{Z}\)&lt;&#x2F;span&gt;, is is also straightforward to show that the problem is “perfectly secure” (but unfortunately, it is not known to be useful for cryptographic constructions).
This leaves the intermediate case, where &lt;span class=&quot;math&quot;&gt;\(\chi\)&lt;&#x2F;span&gt; is a distribution on some subset of &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}&#x2F;q\mathbb{Z}\)&lt;&#x2F;span&gt; (that is not solely &lt;span class=&quot;math&quot;&gt;\(\{0\}\)&lt;&#x2F;span&gt;).
For even fairly small subsets (say &lt;span class=&quot;math&quot;&gt;\([-10, 10]\)&lt;&#x2F;span&gt;), this is thought to be secure.
If you actually want to get parameters that are plausibly secure, tools [&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-estimator-1&quot;&gt;&lt;a href=&quot;#fn-estimator&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;] have been built by the community, but I won’t bother formally checking the parameters I use are fine (they’re larger than what everyone else uses, so it should be fine).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;reasons-we-think-lwe-is-hard&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#reasons-we-think-lwe-is-hard&quot; aria-label=&quot;Anchor link for: reasons-we-think-lwe-is-hard&quot;&gt;🔗&lt;&#x2F;a&gt;Reasons we think LWE is Hard&lt;&#x2F;h1&gt;
&lt;p&gt;There are a &lt;em&gt;number&lt;&#x2F;em&gt; of perspectives on the LWE problem for why it is plausibly hard.
I’ll describe a few below, where again given my elementary focus I will keep things&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;at a high level, and&lt;&#x2F;li&gt;
&lt;li&gt;non-technical.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This is to say that the rest of this section will be “informal but formalizable”.&lt;&#x2F;p&gt;
&lt;p&gt;Before proceeding, I will say that the “real reason” why LWE is thought to be hard is because a lot of people have tried breaking it, and haven’t had much success.
In particular, the best attacks take roughly time &lt;span class=&quot;math&quot;&gt;\(2^{cn}\)&lt;&#x2F;span&gt; for &lt;span class=&quot;math&quot;&gt;\(c\approx 0.292\)&lt;&#x2F;span&gt;. This is better than RSA (&lt;span class=&quot;math&quot;&gt;\(2^{\sqrt[3]{n}}\)&lt;&#x2F;span&gt;), and worse than elliptic-curve discrete logarithm (&lt;span class=&quot;math&quot;&gt;\(2^{n&#x2F;2}\)&lt;&#x2F;span&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;It’s an open secret in cryptography that we can’t have “real reasons” why any particular problem is hard, as it is consistent with what is known in complexity theory that P = NP, and cryptography doesn’t exist.
Of course, few cryptographers &lt;em&gt;believe&lt;&#x2F;em&gt; this, but we can’t rule it out!
Still, there are a few interesting things you can say at a high-level about the hardness of LWE, so I’ll briefly recount them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;it-is-a-problem-of-practical-interest&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#it-is-a-problem-of-practical-interest&quot; aria-label=&quot;Anchor link for: it-is-a-problem-of-practical-interest&quot;&gt;🔗&lt;&#x2F;a&gt;It is a Problem of Practical Interest&lt;&#x2F;h2&gt;
&lt;p&gt;This isn’t a reason to think that LWE is hard &lt;em&gt;per se&lt;&#x2F;em&gt;, but it is a reason that a certain community would be happy if LWE was easy.
From this perspective, you could say we have a win-win situation — either cryptographers are happy (LWE is hard), or coding theorists are happy (LWE is easy).
Moreover, coding theorists have been trying to solve problems like LWE for a while (because it would be good for them), but have been so far unable to.
With that teaser, I’ll go over the applications of LWE to coding theory.&lt;&#x2F;p&gt;
&lt;p&gt;Coding theory studies the construction of (among other things) &lt;em&gt;error-correcting codes&lt;&#x2F;em&gt;.
It is well-known in coding theory that&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Random constructions&lt;&#x2F;em&gt; often are “essentially the best” (in terms of amount of information transmitted, amount of errors that can be corrected, etc) among all possible constructions, and&lt;&#x2F;li&gt;
&lt;li&gt;Random &lt;em&gt;linear&lt;&#x2F;em&gt; constructions are often essentially as good as &lt;em&gt;random constructions&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is to say that when I talk about “random linear codes” below, this can be interpreted as “effectively optimal codes”.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, LWE can be interpreted as a problem regarding the decodability of random linear codes.
In particular, the problem of going from &lt;span class=&quot;math&quot;&gt;\((A, A\vec s +\vec e)\)&lt;&#x2F;span&gt; can be interpreted as being given a description of a random linear code (&lt;span class=&quot;math&quot;&gt;\(A\)&lt;&#x2F;span&gt;), and a noisy encoding of a message (&lt;span class=&quot;math&quot;&gt;\(A\vec s + \vec e\)&lt;&#x2F;span&gt;), and being asked to decode it to get back &lt;span class=&quot;math&quot;&gt;\(\vec s\)&lt;&#x2F;span&gt;.
Note that this is slightly different than the statement of LWE that I used (which was simply that of &lt;em&gt;distinguishing&lt;&#x2F;em&gt; &lt;span class=&quot;math&quot;&gt;\((A, A\vec s+\vec e)\)&lt;&#x2F;span&gt; from random — a maybe easier task), but in most settings these problems are known to be equivalent.&lt;&#x2F;p&gt;
&lt;p&gt;In summary, if LWE is easy, coding theorists are able to efficiently decode a certain class of effectively optimal codes [&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-AWGN-1&quot;&gt;&lt;a href=&quot;#fn-AWGN&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;].
Note that this is different from other cryptographic problems — factoring large numbers is not practically useful outside of attacking cryptographic constructions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gaussian-elimination&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#gaussian-elimination&quot; aria-label=&quot;Anchor link for: gaussian-elimination&quot;&gt;🔗&lt;&#x2F;a&gt;Gaussian Elimination&lt;&#x2F;h2&gt;
&lt;p&gt;As we discussed before, Gaussian Elimination breaks noiseless LWE.
How does introducing noise change things?&lt;&#x2F;p&gt;
&lt;p&gt;For a (very) brief refresher on Gaussian elimination, you are given some system of equations&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[ax+by = e,\qquad a&#x27;x+b&#x27;y = e&#x27;,\]&lt;&#x2F;span&gt;
&lt;p&gt;and must try to find some solution &lt;span class=&quot;math&quot;&gt;\((x,y)\)&lt;&#x2F;span&gt; to both of them.
Gaussian Elimination proceeds by taking linear combinations of the equations to “cancel out” unknowns.
For example, multiplying the first equation by &lt;span class=&quot;math&quot;&gt;\(a&#x27;\)&lt;&#x2F;span&gt;, the second by &lt;span class=&quot;math&quot;&gt;\(a\)&lt;&#x2F;span&gt;, and subtracting leads to&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[(a&#x27;b-b&#x27;a)y = a&#x27;e-e&#x27;a.\]&lt;&#x2F;span&gt;
&lt;p&gt;Roughly speaking, this can let us “remove a dimension” from an LWE instance, i.e. convert a dimension &lt;span class=&quot;math&quot;&gt;\(n\)&lt;&#x2F;span&gt; LWE instance to a dimension &lt;span class=&quot;math&quot;&gt;\(n-1\)&lt;&#x2F;span&gt; LWE instance.
Removing this dimension comes at a cost though — the error goes from &lt;span class=&quot;math&quot;&gt;\(|e|\)&lt;&#x2F;span&gt; to &lt;span class=&quot;math&quot;&gt;\(|a&#x27;e-e&#x27;a|\)&lt;&#x2F;span&gt;, which is quite likely larger than &lt;span class=&quot;math&quot;&gt;\(2|e|\)&lt;&#x2F;span&gt;.
This is to say that each dimension we double we (probably) lose a factor 2 in the error, so trying to solve LWE with Gaussian Elimination makes the error grow exponentially, so only works for &lt;em&gt;very&lt;&#x2F;em&gt; small error settings.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-warning-regarding-np-hardness&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#a-warning-regarding-np-hardness&quot; aria-label=&quot;Anchor link for: a-warning-regarding-np-hardness&quot;&gt;🔗&lt;&#x2F;a&gt;A Warning Regarding NP-hardness&lt;&#x2F;h2&gt;
&lt;p&gt;While there are many theoretical justifications for lattice-based encryption, I won’t cover many of them (many are useful “asymptotically but not concretely”).
Still, I’ll explicitly discuss the issue of NP-hardness, as it is one that many people casually get wrong.&lt;&#x2F;p&gt;
&lt;p&gt;First, it is worth mentioning that NP-hardness is subtly the wrong notion for cryptography.
This is because it is a &lt;em&gt;worst-case&lt;&#x2F;em&gt; notion, while cryptography needs &lt;em&gt;average-case&lt;&#x2F;em&gt; hardness.
For example, SAT is both&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;a worst-case hard problem (if you can solve it you can solve any NP problem!)&lt;&#x2F;li&gt;
&lt;li&gt;fairly easy to solve on “practical instances”.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is to say that for many distributions over SAT instances, SAT is actually &lt;em&gt;easy&lt;&#x2F;em&gt;, despite being worst-case hard.
This can happen for cryptographic problems as well — for example it is usually rather straightforward to exhibit &lt;em&gt;some&lt;&#x2F;em&gt; prime factors of random integers (half of them are divisible by 2), which breaks the factoring problem (at least the standard way it is formulated).&lt;&#x2F;p&gt;
&lt;p&gt;Now, the LWE problem is &lt;em&gt;sort of&lt;&#x2F;em&gt; related to an NP-hard problem.
It’s one of the things cryptographers get most excited about (called the “worst-case to average-case reduction”).
The “sort of” there carries a lot of weight though, so lets talk about it.&lt;&#x2F;p&gt;
&lt;p&gt;There is a problem called &lt;span class=&quot;math&quot;&gt;\(\mathsf{SVP}_\gamma\)&lt;&#x2F;span&gt; (the Gap Shortest Vector Problem with approximation factor &lt;span class=&quot;math&quot;&gt;\(\gamma\)&lt;&#x2F;span&gt;).
This is a decision problem, where given a matrix &lt;span class=&quot;math&quot;&gt;\(A\)&lt;&#x2F;span&gt; and number &lt;span class=&quot;math&quot;&gt;\(t\)&lt;&#x2F;span&gt;, one has to decide if&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class=&quot;math&quot;&gt;\(\min_{\vec z \in \mathbb{Z}^n\setminus\{0\}} \lVert A\vec z\rVert &lt; t\)&lt;&#x2F;span&gt;, or&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;math&quot;&gt;\(\min_{\vec z\in\mathbb{Z}^n\setminus\{0\}} \lVert A\vec z\rVert \geq \gamma t\)&lt;&#x2F;span&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;If &lt;span class=&quot;math&quot;&gt;\(t \leq \min_{\vec z\in \mathbb{Z}^n\setminus\{0\}} \lVert A\vec z\rVert &lt; \gamma t\)&lt;&#x2F;span&gt;, the algorithm can say whatever (both “true” and “false” count as correct behavior).
The idea is roughly as follows — when &lt;span class=&quot;math&quot;&gt;\(\gamma = 1\)&lt;&#x2F;span&gt;, the algorithm has to &lt;em&gt;perfectly&lt;&#x2F;em&gt; distinguish between the two cases, while for &lt;span class=&quot;math&quot;&gt;\(\gamma &gt; 1\)&lt;&#x2F;span&gt;, the algorithm only has to distinguish between instances that are “far apart” in a way that is measured by &lt;span class=&quot;math&quot;&gt;\(\gamma\)&lt;&#x2F;span&gt;.
So the problem has gotten easier in some controlled way.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, &lt;span class=&quot;math&quot;&gt;\(\mathsf{SVP}_1\)&lt;&#x2F;span&gt; is (under some reasonable technical assumptions) NP-hard.
With some other technical details omitted, if you can solve LWE you can also solve &lt;span class=&quot;math&quot;&gt;\(\mathsf{SVP}_{\Omega(\sqrt{n})}\)&lt;&#x2F;span&gt;.
Some people mis-interpret this, and say “lattice-based encryption is based on an NP-hard problem”.
This is wrong though — formally, &lt;span class=&quot;math&quot;&gt;\(\mathsf{SVP}_{\Omega(\sqrt{n})}\)&lt;&#x2F;span&gt; is known to be in NP and coNP, so (under even more technical assumptions [&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-PHcollapse-1&quot;&gt;&lt;a href=&quot;#fn-PHcollapse&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;]) &lt;em&gt;can’t&lt;&#x2F;em&gt; be NP-hard.&lt;&#x2F;p&gt;
&lt;p&gt;There are other caveats about concretely applying the aforementioned connection to &lt;span class=&quot;math&quot;&gt;\(\mathsf{SVP}_\gamma\)&lt;&#x2F;span&gt; (that have to do with “tightness” of the reduction).
Roughly speaking, the issue is one of “hidden constants in &lt;span class=&quot;math&quot;&gt;\(O(\cdot)\)&lt;&#x2F;span&gt; notation”.
For example, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2016&#x2F;360.pdf&quot;&gt;one analysis&lt;&#x2F;a&gt; of the aforementioned reduction is that if one can solve LWE in time &lt;span class=&quot;math&quot;&gt;\(T\)&lt;&#x2F;span&gt;, then one can solve &lt;span class=&quot;math&quot;&gt;\(\mathsf{SVP}_{\Omega(\sqrt{n})}\)&lt;&#x2F;span&gt; in time &lt;span class=&quot;math&quot;&gt;\(\approx 2^{500}T\)&lt;&#x2F;span&gt;.
It is possible that more efficient reductions are found, but the current ones are mostly asymptotically interesting.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quantum-hardness&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#quantum-hardness&quot; aria-label=&quot;Anchor link for: quantum-hardness&quot;&gt;🔗&lt;&#x2F;a&gt;Quantum Hardness?&lt;&#x2F;h2&gt;
&lt;p&gt;Lattice-based encryption (unlike RSA, or the elliptic-curve discrete logarithm problem) is thought to be hard for &lt;em&gt;quantum&lt;&#x2F;em&gt; computers to break as well.
I’m no quantum complexity theorist, so I’ll briefly describe the justification I know for the hardness (although, similar to classical hardness, it really boils down to “many smart people have thought about it and failed to get fast algorithms”).&lt;&#x2F;p&gt;
&lt;p&gt;Roughly speaking, many quantum algorithms that obtain &lt;em&gt;large&lt;&#x2F;em&gt; speed increases proceed by solving a very general problem (the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hidden_subgroup_problem&quot;&gt;Hidden subgroup problem&lt;&#x2F;a&gt;).
In particular, Factoring and the Discrete Logarithm problem can both be phrased as HSP instances and then solved in (quantum) polynomial time.
Can lattice-based encryption be phrased as an HSP instance?
The answer is (perhaps surprisingly, given the claimed quantum security) &lt;em&gt;yes&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;HSP instances are parameterzed by a choice of group &lt;span class=&quot;math&quot;&gt;\(G\)&lt;&#x2F;span&gt;.
The HSP instances we know how to solve efficiently are mostly over &lt;em&gt;abelian&lt;&#x2F;em&gt; groups &lt;span class=&quot;math&quot;&gt;\(G\)&lt;&#x2F;span&gt;.
Lattice-based encryption can be phrased as an HSP over a &lt;em&gt;non-abelian&lt;&#x2F;em&gt; group (the Dihedral group).
There are some reasons to think this abelian&#x2F;non-abelian difference should be a structural “switching point” in the complexity of the problem (the HSP heavily relies on the quantum fourier transform, and fourier transforms are &lt;em&gt;much&lt;&#x2F;em&gt; nicer over abelian groups).&lt;&#x2F;p&gt;
&lt;p&gt;That all being said, there is nothing stopping someone from giving a quantum attack on LWE tomorrow, similarly to how there’s nothing stopping someone from giving a linear-time algorithm for SAT tomorrow [&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-SAT-1&quot;&gt;&lt;a href=&quot;#fn-SAT&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;].
Such uncertainty is a core part of cryptography.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-frodoKEM&quot;&gt;
&lt;p&gt;For experts, the intention is to present &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;frodokem.org&#x2F;&quot;&gt;FrodoKEM&lt;&#x2F;a&gt;, without any of
the various compression optimizations, and with a simpler noise distribution. &lt;a href=&quot;#fr-frodoKEM-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-better&quot;&gt;
&lt;p&gt;Small choices of &lt;span class=&quot;math&quot;&gt;\(e\)&lt;&#x2F;span&gt; can &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Coppersmith%27s_attack#Low_public_exponent_attack&quot;&gt;lead to attacks&lt;&#x2F;a&gt; (if other mistakes are made as well). &lt;a href=&quot;#fr-better-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-inequivalent&quot;&gt;
&lt;p&gt;It is known that factoring &lt;em&gt;suffices&lt;&#x2F;em&gt; to take &lt;span class=&quot;math&quot;&gt;\(e\)&lt;&#x2F;span&gt;th roots, but it is not known to be &lt;em&gt;necessary&lt;&#x2F;em&gt;, i.e. there may be faster approaches.
The above is (roughly) a simple presentation of the RSA cryptosystem in a
“textbook” form.
Standard presentations describe in detail how you actually take &lt;span class=&quot;math&quot;&gt;\(e\)&lt;&#x2F;span&gt;th roots
given the factorization &lt;span class=&quot;math&quot;&gt;\((p, q)\)&lt;&#x2F;span&gt;, but this won’t be needed in my series. &lt;a href=&quot;#fr-inequivalent-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-estimator&quot;&gt;
&lt;p&gt;https:&#x2F;&#x2F;lattice-estimator.readthedocs.io&#x2F;en&#x2F;latest&#x2F;?badge=latest &lt;a href=&quot;#fr-estimator-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-AWGN&quot;&gt;
&lt;p&gt;These codes are for the “Additive White Gaussian Noise Channel”, roughly speaking codes for &lt;em&gt;analog&lt;&#x2F;em&gt; problems (like wireless communications) rather than &lt;em&gt;digital problems&lt;&#x2F;em&gt;. &lt;a href=&quot;#fr-AWGN-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-PHcollapse&quot;&gt;
&lt;p&gt;Formally, it is not NP-hard unless the polynomial hierarchy collapses all the way. &lt;a href=&quot;#fr-PHcollapse-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-SAT&quot;&gt;
&lt;p&gt;See &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cstheory.stackexchange.com&#x2F;questions&#x2F;93&#x2F;what-are-the-best-current-lower-bounds-on-3sat&quot;&gt;here&lt;&#x2F;a&gt; for some discussion on explicit bounds on the running time of a SAT algorithm. None preclude an algorithm of both &lt;span class=&quot;math&quot;&gt;\(O(n)\)&lt;&#x2F;span&gt; running time and space. &lt;a href=&quot;#fr-SAT-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Private Key Lattice-based Encryption</title>
        <published>2022-07-02T00:00:00+00:00</published>
        <updated>2022-07-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com/blog/lattices-for-programmers-pt2/"/>
        <id>https://mark.schultz-wu.com/blog/lattices-for-programmers-pt2/</id>
        
        <content type="html" xml:base="https://mark.schultz-wu.com/blog/lattices-for-programmers-pt2/">&lt;p&gt;In the previous post, we discussed&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;how “Textbook RSA” (as presented in tutorials) is often not able to be executed for parameters large enough to be plausibly secure,&lt;&#x2F;li&gt;
&lt;li&gt;what the LWE problem is, and&lt;&#x2F;li&gt;
&lt;li&gt;heuristic justifications for why it is hard.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;We’ll next construct an exceedingly simple (private key) lattice-based encryption scheme.
Throughout all of our implementions, we will need some basic functions, for example&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;sampling uniformly random vectors&#x2F;matrices,&lt;&#x2F;li&gt;
&lt;li&gt;sampling vectors&#x2F;matrices with bounded coordinates,&lt;&#x2F;li&gt;
&lt;li&gt;matrix operations (multiplications, transpose, and addition).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These as straightforward to implement, but code is available &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mark-schultz&#x2F;lwe-for-programmers&#x2F;blob&#x2F;main&#x2F;utils.py&quot;&gt;here&lt;&#x2F;a&gt;.
Anyway, in terms of these operations it is straightforward to implement private-key encryption.
We first go over the (conceptually) simpler noiseless case, before modifying the construction to handle noise.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;noiseless-private-key-lattice-based-encryption&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#noiseless-private-key-lattice-based-encryption&quot; aria-label=&quot;Anchor link for: noiseless-private-key-lattice-based-encryption&quot;&gt;🔗&lt;&#x2F;a&gt;Noiseless (Private-key) Lattice-based Encryption&lt;&#x2F;h1&gt;
&lt;p&gt;Given &lt;span class=&quot;math&quot;&gt;\((A, A\vec s)\)&lt;&#x2F;span&gt;, the (noiseless) LWE assumption states that this is indistinguishable from random.
While this assumption is &lt;em&gt;false&lt;&#x2F;em&gt;, we can still pretend it is true, and construct a cryptosystem that would be secure (were it true).
The main idea we need to leverage is that&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;under the noiseless LWE assumption, &lt;span class=&quot;math&quot;&gt;\((A, A\vec s)\)&lt;&#x2F;span&gt; looks like &lt;span class=&quot;math&quot;&gt;\((A, \vec u)\)&lt;&#x2F;span&gt; for uniform &lt;span class=&quot;math&quot;&gt;\(\vec u\)&lt;&#x2F;span&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;given a uniform vector &lt;span class=&quot;math&quot;&gt;\(\vec u\)&lt;&#x2F;span&gt;, one can obtain secure encryption by an argument similar to the one-time pad.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This second point deserves some more discussion.
First, one might be tempted define &lt;span class=&quot;math&quot;&gt;\(\mathsf{Enc}_{\vec s}(\vec m) = (A, A\vec s \oplus \vec m)\)&lt;&#x2F;span&gt;, where &lt;span class=&quot;math&quot;&gt;\(\oplus\)&lt;&#x2F;span&gt; is an operation such as XOR.
While this is a good instinct, it doesn’t work out well here — all of the arithmetic here is (standard) arithmetic modulo &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt;, which XOR doesn’t behave particularly well with respect to.&lt;&#x2F;p&gt;
&lt;p&gt;Another natural idea is to do the same thing, but with addition modulo &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt; replacing XOR.
This ends up working!
Namely, under the (false) Noiseless LWE assumption, one can show that &lt;span class=&quot;math&quot;&gt;\(\mathsf{Enc}_{\vec s}(\vec m) := (A, A\vec s+\vec m)\)&lt;&#x2F;span&gt; defines a secure encryption function.
Moreover, one can define decryption such that this function is correct — it is straightforward to verify that &lt;span class=&quot;math&quot;&gt;\(\mathsf{Dec}_{\vec s}(A, \vec b)= \vec b - A\vec s\)&lt;&#x2F;span&gt; works (where all arithmetic is done modulo &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;This gives (after we have defined the aforementioned matrix&#x2F;vector&#x2F;sampling operations) the following simple cryptosystem.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import random&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;from utils import *&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;class NoiselessPrivKey:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def __init__(self, n, q):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.n = n&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.q = q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def key_gen(self):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.s = sample_unif_vector(self.n, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def enc(self, m):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Sampling A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        A = sample_unif_matrix(n, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Computing b := As&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b = matrix_vector_multiply(A, self.s, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Adding m to As&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b = vector_vector_add(b, m, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return (A, b)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def dec(self, ctxt):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (A, b) = ctxt[0], ctxt[1]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Recomputing As&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        As = matrix_vector_multiply(A, self.s, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Recovering m = b - As&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        for i in range(self.n):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            b[i] = (b[i] - As[i]) % q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that this code works for cryptographically large parameters (which is &lt;span class=&quot;math&quot;&gt;\(n\in [500,1000]\)&lt;&#x2F;span&gt; roughly and &lt;span class=&quot;math&quot;&gt;\(q\approx 2^{10}\)&lt;&#x2F;span&gt;).
This is because lattice-based encryption is essentially just simple linear algebra on word-size integers [&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-RING-1&quot;&gt;&lt;a href=&quot;#fn-RING&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;]!
With this idea for how lattice-based encryption should work, we can re-introduce the noise, and fix the issues it brings about.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;noisey-private-key-lattice-based-encryption&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#noisey-private-key-lattice-based-encryption&quot; aria-label=&quot;Anchor link for: noisey-private-key-lattice-based-encryption&quot;&gt;🔗&lt;&#x2F;a&gt;Noisey (Private-key) Lattice-based Encryption&lt;&#x2F;h1&gt;
&lt;p&gt;Introducing noise both doesn’t impact the security of our construction at all, and changes everything.
This is because the natural noisy variant of our protocol (where we add &lt;span class=&quot;math&quot;&gt;\(\vec m\)&lt;&#x2F;span&gt; to the second component of &lt;span class=&quot;math&quot;&gt;\((A, A\vec s +\vec e)\)&lt;&#x2F;span&gt;, rather than &lt;span class=&quot;math&quot;&gt;\((A, A\vec s)\)&lt;&#x2F;span&gt;) is secure under the LWE assumption (similarly to how the prior version of our protocol can be shown to be secure under the noiseless LWE assumption).
The main difference is that the noiseless LWE assumption is clearly false, but the LWE assumption is thought to be true, i.e. we now have a secure protocol!&lt;&#x2F;p&gt;
&lt;p&gt;The issue we have to fix is correctness.
If we use the above modified encryption algorithm with our prior decryption algorithm, we get that&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\mathsf{Dec}_{\vec s}(\mathsf{Enc}_{\vec s}(\vec m)) = \mathsf{Dec}_{\vec s}(A, A\vec s + \vec e +\vec m) = \vec m + \vec e\neq \vec m.\]&lt;&#x2F;span&gt;
&lt;p&gt;From this, we can see that the error being zero was key to the correctness of our prior (insecure) protocol.
Can we fix this correctness issue somehow?&lt;&#x2F;p&gt;
&lt;p&gt;The answer is (obviously) yes.
The solution is straightforward — we need a way to encode the message &lt;span class=&quot;math&quot;&gt;\(\vec m\)&lt;&#x2F;span&gt; to tolerate additional noise &lt;span class=&quot;math&quot;&gt;\(\vec e\)&lt;&#x2F;span&gt;.
While one can appeal to fancy techniques from coding theory, typically people just scale &lt;span class=&quot;math&quot;&gt;\(\vec m\mapsto (q&#x2F;2)\vec m\)&lt;&#x2F;span&gt; (when the coordinates of &lt;span class=&quot;math&quot;&gt;\(\vec m\in\{0,1\}^n\)&lt;&#x2F;span&gt;), or &lt;span class=&quot;math&quot;&gt;\((q&#x2F;p)\vec m\)&lt;&#x2F;span&gt; for &lt;span class=&quot;math&quot;&gt;\(\vec m\in\{0,\dots,p-1\}^n\)&lt;&#x2F;span&gt; more generally.&lt;&#x2F;p&gt;
&lt;p&gt;This is to say that encryption of the form&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\mathsf{Enc}_{\vec s}(\vec m) = (A, A\vec s +\vec e + (q&#x2F;2)\vec m)\]&lt;&#x2F;span&gt;
&lt;p&gt;suffices.
For decryption, we again subtract &lt;span class=&quot;math&quot;&gt;\(A\vec s\)&lt;&#x2F;span&gt; from the second component, but then need a way to map &lt;span class=&quot;math&quot;&gt;\((q&#x2F;2)\vec m+\vec e\mapsto \vec m\)&lt;&#x2F;span&gt;.
To do this, we first divide by &lt;span class=&quot;math&quot;&gt;\(q&#x2F;2\)&lt;&#x2F;span&gt; to get &lt;span class=&quot;math&quot;&gt;\(\vec m + \vec e &#x2F; (q&#x2F;2)\)&lt;&#x2F;span&gt;, and then round to the nearest integer.
Provided the coordinates of &lt;span class=&quot;math&quot;&gt;\(\vec e &#x2F; (q&#x2F;2)\)&lt;&#x2F;span&gt; are small enough (concretely less than &lt;span class=&quot;math&quot;&gt;\(1 &#x2F; 2\)&lt;&#x2F;span&gt;, or equivalently the coordinates of &lt;span class=&quot;math&quot;&gt;\(\vec e\)&lt;&#x2F;span&gt; must have absolute value at most &lt;span class=&quot;math&quot;&gt;\(q&#x2F;4\)&lt;&#x2F;span&gt;), this will be correct, and we’ll be done!&lt;&#x2F;p&gt;
&lt;p&gt;This leads to the (slightly different) code than before&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import random&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;from utils import *&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;class LWEPrivKey:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def __init__(self, n, q, B):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.n = n&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.q = q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.B = B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def key_gen(self):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.s = sample_unif_vector(self.n, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def enc(self, m):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Sampling A, e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        A = sample_unif_matrix(n, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        e = sample_bounded_vector(self.n, self.B)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Computing b := As + e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b = matrix_vector_multiply(A, self.s, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b = vector_vector_add(b, e, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Scaling m -&amp;gt; (q&#x2F;&#x2F;2) m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scaled_m = [(self.q&#x2F;&#x2F;2) * m[i] % self.q for i in range(self.n)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Adding (q&#x2F;&#x2F;2)m to b = As + e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b = vector_vector_add(b, scaled_m, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return (A, b)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def dec(self, ctxt):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (A, b) = ctxt[0], ctxt[1]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Recomputing As&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        As = matrix_vector_multiply(A, self.s, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Recovering scaled_m = b - As&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        for i in range(self.n):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            b[i] = (b[i] - As[i]) % q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Scaling (q&#x2F;&#x2F;2)m + e -&amp;gt; m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        m = [0 for _ in range(self.n)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        for i in range(self.n):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            m[i] = round(b[i] &#x2F; (self.q&#x2F;&#x2F;2)) % 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This gives us a complete implementation of (private-key) lattice-based encryption!
There is technically a security issues with this code (it uses pythons default RNG), but this is simple enough to fix.
Note that, even if one uses a secure RNG, you probably don’t want to use this in production — there are &lt;em&gt;much&lt;&#x2F;em&gt; more efficient options if one uses the optimizations we are (intentionally) omitting.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-RING&quot;&gt;
&lt;p&gt;Here, “integers” is somewhat particular to FrodoKEM. Optimized schemes (based on structured lattices) such as Saber and Kyber instead do “linear algebra” with vectors&#x2F;matrices of &lt;em&gt;polynomials&lt;&#x2F;em&gt;. &lt;a href=&quot;#fr-RING-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Public Key Lattice-based Encryption</title>
        <published>2022-07-02T00:00:00+00:00</published>
        <updated>2022-07-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com/blog/lattices-for-programmers-pt3/"/>
        <id>https://mark.schultz-wu.com/blog/lattices-for-programmers-pt3/</id>
        
        <content type="html" xml:base="https://mark.schultz-wu.com/blog/lattices-for-programmers-pt3/">&lt;p&gt;This is a continuation on my series on a simple construction of (public-key) lattice-based encryption.
We’re finally ready to construct public-key encryption!
Similarly to the private-key setting, we will first give a construction in the (simpler, but insecure) &lt;em&gt;noiseless&lt;&#x2F;em&gt; setting, before adapting the construction to handle noise.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;noiseless-public-key-lattice-based-encryption&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#noiseless-public-key-lattice-based-encryption&quot; aria-label=&quot;Anchor link for: noiseless-public-key-lattice-based-encryption&quot;&gt;🔗&lt;&#x2F;a&gt;Noiseless (public-key) Lattice-based Encryption&lt;&#x2F;h1&gt;
&lt;p&gt;For private-key encryption, our construction was easiest to understand in terms of the one-time pad.
For public-key encryption, things are instead easiest in terms of &lt;em&gt;Diffie-Hellman Key Exchange&lt;&#x2F;em&gt;.
Recall that, for a fixed element &lt;span class=&quot;math&quot;&gt;\(g\in \mathbb{F}_p\)&lt;&#x2F;span&gt;, this works by&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;sampling &lt;span class=&quot;math&quot;&gt;\(r, s\gets \mathbb{F}_p\)&lt;&#x2F;span&gt; (technically &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}&#x2F;(p-1)\mathbb{Z}\)&lt;&#x2F;span&gt;, but ignore this detail),&lt;&#x2F;li&gt;
&lt;li&gt;exchanging &lt;span class=&quot;math&quot;&gt;\(g^r, g^s\)&lt;&#x2F;span&gt;, and then&lt;&#x2F;li&gt;
&lt;li&gt;having each party compute &lt;span class=&quot;math&quot;&gt;\((g^r)^s = g^{rs} = (g^s)^r\)&lt;&#x2F;span&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Diffie-Hellman works by computing &lt;span class=&quot;math&quot;&gt;\(g^{rs}\)&lt;&#x2F;span&gt; in two ways, where eacy way involves the “secret key” (&lt;span class=&quot;math&quot;&gt;\(r\)&lt;&#x2F;span&gt; or &lt;span class=&quot;math&quot;&gt;\(s\)&lt;&#x2F;span&gt;) and “public key” (&lt;span class=&quot;math&quot;&gt;\(g^r\)&lt;&#x2F;span&gt; or &lt;span class=&quot;math&quot;&gt;\(g^s\)&lt;&#x2F;span&gt;).
For the (noiseless) LWE assumption, our secret key is &lt;span class=&quot;math&quot;&gt;\(\vec s\)&lt;&#x2F;span&gt;, and public key is &lt;span class=&quot;math&quot;&gt;\(A\vec s\)&lt;&#x2F;span&gt;.
Can we use this to “compute something in two ways” again?&lt;&#x2F;p&gt;
&lt;p&gt;The answer is yes!
In particular, we will compute &lt;span class=&quot;math&quot;&gt;\(\vec r^tA\vec s\)&lt;&#x2F;span&gt; in two ways, namely via &lt;span class=&quot;math&quot;&gt;\(\vec r^t(A\vec s)\)&lt;&#x2F;span&gt;, and &lt;span class=&quot;math&quot;&gt;\((\vec r^t A)\vec s\)&lt;&#x2F;span&gt;.
This means that we need the noiseless LWE sample &lt;span class=&quot;math&quot;&gt;\((A, A\vec s)\)&lt;&#x2F;span&gt;, and the &lt;em&gt;transposed&lt;&#x2F;em&gt; sample &lt;span class=&quot;math&quot;&gt;\((A^t, A^t\vec r)\)&lt;&#x2F;span&gt; (as &lt;span class=&quot;math&quot;&gt;\((A^t\vec r)^t = \vec r^t A\)&lt;&#x2F;span&gt;).
One of them we will store long-term (in the public key), while the other we will generate “fresh” (and store in the ciphertext).
Without further ado, we have the following (noiseless) public-key cryptosystem&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import random&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;from utils import *&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;class NoiselessPubKey:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def __init__(self, n, q):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.n = n&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.q = q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def key_gen(self):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        A = sample_unif_matrix(self.n, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.sk = sample_unif_vector(self.n, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        As = matrix_vector_multiply(A, self.sk, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.pk = (A, As)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def enc(self, m):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (A, As) = self.pk&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Sampling r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        r = sample_unif_vector(self.n, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Computing u := A^tr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        At = matrix_transpose(A)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u = matrix_vector_multiply(At, r, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Computing r^t(As)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rAs = vector_vector_inner_product(r, As, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Using r^t(As) as a random pad&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        v = (rAs + m) % self.q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return (u, v)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def dec(self, ctxt):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (u, v) = ctxt[0], ctxt[1]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        s = self.sk&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Computing (r^tA)s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rAs = vector_vector_inner_product(u, s, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Subtracting rAs from v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        m = (v - rAs) % q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So ciphertexts contain the term &lt;span class=&quot;math&quot;&gt;\(v = \vec r^tA\vec s + m\)&lt;&#x2F;span&gt;, and the share &lt;span class=&quot;math&quot;&gt;\((A^t, A^t\vec r)\)&lt;&#x2F;span&gt; needed to decrypt.
Actually, we can fully omit &lt;span class=&quot;math&quot;&gt;\(A^t\)&lt;&#x2F;span&gt; (as it already in the public key) for some small space savings.&lt;&#x2F;p&gt;
&lt;p&gt;While encryption&#x2F;decryption are quite fast for this scheme (well under &lt;span class=&quot;math&quot;&gt;\(.10\)&lt;&#x2F;span&gt; seconds), it has a &lt;em&gt;significant&lt;&#x2F;em&gt; flaw, namely that it can only encrypt a &lt;em&gt;single&lt;&#x2F;em&gt; element from &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}&#x2F;q\mathbb{Z}\)&lt;&#x2F;span&gt;, which for &lt;span class=&quot;math&quot;&gt;\(q\approx 3000\)&lt;&#x2F;span&gt; is only like 12 bits.
An (unoptimized) way to fix this is to simply break your plaintext up into 12-bit long blocks, and encrypt multiple things.
This introduces quite a bit of redundency that one can optimize away (and this is precisely what FrodoKEM does compared to what I have presented), but I will defer details of this to later.
The main idea is to use the above template scheme, but with many of the matrices&#x2F;vectors “resized” (i.e. with certain parameters tuned).&lt;&#x2F;p&gt;
&lt;p&gt;Well, one shouldn’t use &lt;em&gt;exactly&lt;&#x2F;em&gt; the above scheme, as it isn’t secure!
With that, we’ll discuss how one can make it secure.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;noisy-public-key-lattice-based-encryption&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#noisy-public-key-lattice-based-encryption&quot; aria-label=&quot;Anchor link for: noisy-public-key-lattice-based-encryption&quot;&gt;🔗&lt;&#x2F;a&gt;Noisy (public-key) Lattice-based Encryption&lt;&#x2F;h1&gt;
&lt;p&gt;We again switch every usage of &lt;span class=&quot;math&quot;&gt;\((A, A\vec s)\)&lt;&#x2F;span&gt; to &lt;span class=&quot;math&quot;&gt;\((A, A\vec s + \vec e)\)&lt;&#x2F;span&gt;.
This is fairly mechanical (and simple to verify that you got right), but as this verification step is somewhat technical (write down a security proof!) I will omit it.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import random&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;from utils import *&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;class LWEPubKey:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def __init__(self, n, q, B):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.n = n&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.q = q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.B = B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def key_gen(self):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        A = sample_unif_matrix(self.n, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.sk = sample_bounded_vector(self.n, self.B)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        As = matrix_vector_multiply(A, self.sk, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        e = sample_bounded_vector(self.n, self.B)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b = vector_vector_add(As, e, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.pk = (A, b)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def enc(self, m):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (A, b) = self.pk&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Sampling r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        r = sample_bounded_vector(self.n, self.B)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        e_prime = sample_bounded_vector(self.n, self.B)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Computing u := A^tr + e&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        At = matrix_transpose(A)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u = matrix_vector_multiply(At, r, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u = vector_vector_add(u, e_prime, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Approximately computing r^t(As)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rAs = vector_vector_inner_product(r, b, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Adding e_double_prime so it is a &amp;quot;LWE encryption&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        e_prime_prime = sample_bounded_vector(1, self.B)[0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        v = rAs+ e_prime_prime % self.q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Adding an encoding of m to the &amp;quot;random pad&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        v = (v + (self.q&#x2F;&#x2F;2)*m) % self.q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return (u, v)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    def dec(self, ctxt):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (u, v) = ctxt[0], ctxt[1]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        s = self.sk&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Approximately (r^tA)s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rAs = vector_vector_inner_product(u, s, self.q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Subtracting rAs from v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        v = (v - rAs) % self.q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Decoding (q&#x2F;&#x2F;2)*m + error_terms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return round(v &#x2F; (self.q&#x2F;&#x2F;2)) % 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;One can compute that the scheme is correct provided that &lt;span class=&quot;math&quot;&gt;\(\lfloor (\langle sk, e&#x27;\rangle + \langle r, e\rangle + e&#x27;&#x27;) &#x2F; (q&#x2F;&#x2F;2)\rceil =0\)&lt;&#x2F;span&gt;.
If we choose &lt;span class=&quot;math&quot;&gt;\(sk, \vec r\)&lt;&#x2F;span&gt; as they were before (uniformly at random from &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}&#x2F;q\mathbb{Z}\)&lt;&#x2F;span&gt;, this will barely ever happen.
Instead, we use the known result that one loses no security if one samples the LWE secret from the same distribution as the LWE error to sample &lt;span class=&quot;math&quot;&gt;\(\vec{sk}, \vec r\)&lt;&#x2F;span&gt; with each coefficient at most &lt;span class=&quot;math&quot;&gt;\(B\)&lt;&#x2F;span&gt;.
This yields correct encryption provided that &lt;span class=&quot;math&quot;&gt;\(2nB^2 + B &lt; q&#x2F;4\)&lt;&#x2F;span&gt;.
In practice you’ll get some cancellations between the random terms, but I won’t bother giving a refined analysis — the intention is to point out that one can still get correct encryption, although in the public key setting you have to correct more error than the private key setting.&lt;&#x2F;p&gt;
&lt;p&gt;Note that the noisy setting can encrypt even less useful data than the noiseless setting — a single element of &lt;span class=&quot;math&quot;&gt;\(\{0,1\}\)&lt;&#x2F;span&gt; now, rather than &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}&#x2F;q\mathbb{Z}\)&lt;&#x2F;span&gt;.
Again, this is merely an issue with the unoptimized scheme, and one can easily optimize things to encrypt more data.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot;&gt;🔗&lt;&#x2F;a&gt;Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;With that, we’ve constructed public-key lattice-based encryption!
The construction is an (aggressively unoptimized) version of the FrodoKEM cryptosystem, a NIST PQC round 3 (finalist&#x2F;alternate, I forget).
The main optimizations we are missing out on are&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;the aforementioned technique of encrypting more than just a single bit, and&lt;&#x2F;li&gt;
&lt;li&gt;a technique to compress the random matrix &lt;span class=&quot;math&quot;&gt;\(A\)&lt;&#x2F;span&gt; in the public key (which is &lt;span class=&quot;math&quot;&gt;\(n^2\log_2 q\)&lt;&#x2F;span&gt; bits large — fairly big) to a short 128-bit seed, and&lt;&#x2F;li&gt;
&lt;li&gt;optimizing the choice of bounded error distribution to be a &lt;em&gt;concentrated&lt;&#x2F;em&gt; bounded error distribution (think a Gaussian), allowing one to get tighter bounds on the noise one must correct.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Everything else is essentially the same.
Note that even among NIST candidates, FrodoKEM is an intentionally “unoptimized” one, meaning that it intentionally uses weaker security assumptions (at some cost in potential optimizations).
The (main) optimization it misses out on is that of appealing to &lt;em&gt;algebraically structured lattices&lt;&#x2F;em&gt;.
I might write up a blog post on this topic, but it is fairly advanced in comparison, as it most naturally phrased in terms of modules over quotients of polynomial rings.
While this topics are very possible to concretely work with (i.e. they aren’t “abstract nonsense”), it is decidedly more advanced than simple matrix multiplications and modular arithmetic.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Continuous and Discrete Prime Lattices</title>
        <published>2021-03-05T00:00:00+00:00</published>
        <updated>2021-03-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com/blog/primelattice/"/>
        <id>https://mark.schultz-wu.com/blog/primelattice/</id>
        
        <content type="html" xml:base="https://mark.schultz-wu.com/blog/primelattice/">&lt;p&gt;Earlier this week, a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;232&quot;&gt;paper was posted on eprint&lt;&#x2F;a&gt; claiming
to be authored by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Claus_P._Schnorr&quot;&gt;Schnorr&lt;&#x2F;a&gt;, and
claiming (in the abstract at least) to break RSA.
The paper itself appears to have been a work-in-progress (a version of it made
the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;StefanoMTessaro&#x2F;status&#x2F;1366914461886386176?s=20&quot;&gt;Crypto 2009 rump
session&lt;&#x2F;a&gt;),
and some comments by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;DucasLeo&#x2F;status&#x2F;1366957088954601473?s=20&quot;&gt;Ducas&lt;&#x2F;a&gt; (who is an expert on lattices) make it sound like a known strategy that doesn’t seem to work out (he pointed to the paper &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1003.5461.pdf&quot;&gt;here&lt;&#x2F;a&gt; from 2010, and also &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lducas&#x2F;SchnorrGate&quot;&gt;experimentally tested some of the claims&lt;&#x2F;a&gt;, demonstrating a gap between Schnorr’s claim and experimental evidence).
Of course, this does not mean that RSA is completely safe (see &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;matthew_d_green&#x2F;status&#x2F;1366961403161174021?s=20&quot;&gt;Heninger’s
comments on the
matter&lt;&#x2F;a&gt;),
but it does dampen much of the excitement.&lt;&#x2F;p&gt;
&lt;p&gt;As I am giving a talk to the Crypto student seminar on Friday, I leafed through
the paper before deciding that I would not be able to present it well (both due
to the short notice, and the fairly technical nature of the claimed result).
In doing this, I saw a lattice which is quite similar to one from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;146.pdf&quot;&gt;one of Ducas
and Pierrot’s (DP)
papers&lt;&#x2F;a&gt;.
The lattice itself seems to be defined in my advisor’s book from 2002, but I
can’t seem to get access to a digital copy via institutional access.&lt;&#x2F;p&gt;
&lt;p&gt;In this post I will try to discuss both lattices, although I will focus on
DP’s contruction (which I understand better).
Both are related to the complexity of factoring — Schnorr’s is designed such
that short vectors help &lt;em&gt;break&lt;&#x2F;em&gt; factoring, while DP’s is designed such that
the ability to &lt;em&gt;break factoring&lt;&#x2F;em&gt; allows one to solve the “Bounded Distance
Decoding” problem (which is a typical hard problem on lattices).
In what follows, I will focus on the &lt;span class=&quot;math&quot;&gt;\(\ell_2\)&lt;&#x2F;span&gt; norm (although DP also has
results for the &lt;span class=&quot;math&quot;&gt;\(\ell_1\)&lt;&#x2F;span&gt; norm).
They are also both related to “logarithms of primes”, although the Schnorr
construction uses the (standard) logarithm, while DP uses a &lt;em&gt;discrete&lt;&#x2F;em&gt;
logarithm.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;lattice-preliminaries&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#lattice-preliminaries&quot; aria-label=&quot;Anchor link for: lattice-preliminaries&quot;&gt;🔗&lt;&#x2F;a&gt;Lattice Preliminaries&lt;&#x2F;h1&gt;
&lt;p&gt;A &lt;em&gt;lattice&lt;&#x2F;em&gt; is a discrete subgroup &lt;span class=&quot;math&quot;&gt;\(\mathcal{L}\subseteq \mathbb{Z}^n\)&lt;&#x2F;span&gt;.
Equivalently, it is the image &lt;span class=&quot;math&quot;&gt;\(\mathbf{B}\mathbb{Z}^k\)&lt;&#x2F;span&gt; of the integers under
&lt;span class=&quot;math&quot;&gt;\(\mathbf{B}\in\mathbb{R}^{n\times k}\)&lt;&#x2F;span&gt; (a &lt;em&gt;basis&lt;&#x2F;em&gt; of the lattice).
Here, &lt;span class=&quot;math&quot;&gt;\(n\)&lt;&#x2F;span&gt; is the dimension, and &lt;span class=&quot;math&quot;&gt;\(k\)&lt;&#x2F;span&gt; is the rank.
Generally, one restricts to “full-rank” lattices, i.e. where &lt;span class=&quot;math&quot;&gt;\(k = n\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;An important quantity associated with a lattice is the length of its &lt;em&gt;shortest
vector&lt;&#x2F;em&gt; &lt;span class=&quot;math&quot;&gt;\(\lambda_1(L) = \min_{\ell\in L\setminus\{0\}}\lVert \ell\rVert_2\)&lt;&#x2F;span&gt;.
One can place balls of radii &lt;span class=&quot;math&quot;&gt;\(\lambda_1(L) &#x2F; 2\)&lt;&#x2F;span&gt; centered at each lattice point
in a non-overlapping way.
This means that information theoretically, one can recover &lt;span class=&quot;math&quot;&gt;\(\ell\)&lt;&#x2F;span&gt; from a
perturbation &lt;span class=&quot;math&quot;&gt;\(\ell+e\)&lt;&#x2F;span&gt; for &lt;span class=&quot;math&quot;&gt;\(e\)&lt;&#x2F;span&gt; in one of the aforementioend balls.
The computational problem of doing this is known as the &lt;em&gt;bounded-distance
decoding problem&lt;&#x2F;em&gt;, and being able to solve it efficiently on input a random
lattice already suffices to solve the LWE problem (in fact, the LWE problem can
be interpreted as doing precisely this).&lt;&#x2F;p&gt;
&lt;p&gt;From a different perspective, lattices with “large &lt;span class=&quot;math&quot;&gt;\(\lambda_1(L)\)&lt;&#x2F;span&gt;” can correct “larger amounts of noise”, and
have applications in the construction of error-correcting codes.
There is a boring way to get a lattice with &lt;em&gt;arbitrarily large&lt;&#x2F;em&gt; &lt;span class=&quot;math&quot;&gt;\(\lambda_1(L)\)&lt;&#x2F;span&gt;
though, which is based on the identity:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\lambda_1(\alpha L) = \alpha\lambda_1(L)\]&lt;&#x2F;span&gt;
&lt;p&gt;where &lt;span class=&quot;math&quot;&gt;\(\alpha L\)&lt;&#x2F;span&gt; is the same lattice &lt;span class=&quot;math&quot;&gt;\(L\)&lt;&#x2F;span&gt; with its basis scaled by &lt;span class=&quot;math&quot;&gt;\(\alpha\)&lt;&#x2F;span&gt;.
For this reason, when trying to build “dense” lattices people often work with a
scale-invariant quantity related to &lt;span class=&quot;math&quot;&gt;\(\lambda_1(L)\)&lt;&#x2F;span&gt;.
There are a variety you can choose&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-centerdensity-1&quot;&gt;&lt;a href=&quot;#fn-centerdensity&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but I will discuss the
normalized shortest vector:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\overline{\lambda}_1(L) = \frac{\lambda_1(L)}{\sqrt[n]{\det L}}\]&lt;&#x2F;span&gt;
&lt;p&gt;A fundamental result in the theory of lattices is &lt;em&gt;Minkowski’s Theorem&lt;&#x2F;em&gt;, which
upper bounds &lt;span class=&quot;math&quot;&gt;\(\overline{\lambda}_1(L) \leq 2\mathsf{vol}(\mathcal{B}_n(1))^{-1&#x2F;n}\sim \sqrt{2n&#x2F;\pi e}\)&lt;&#x2F;span&gt;.
There is a natural question — how &lt;em&gt;close&lt;&#x2F;em&gt; can one get to this bound?
Read DP for a summary, but the main idea is that random lattices are within a
constant factor of the bound, and that there exist explicit constructions that
are similarly close (but that the decoding problem is open for).&lt;&#x2F;p&gt;
&lt;p&gt;Before DP, the highest-density lattice one could decode was the Barnes-Wall
lattice of density &lt;span class=&quot;math&quot;&gt;\(\Theta(\sqrt[4]{n})\)&lt;&#x2F;span&gt;, with decoder by Micciancio-Nicolosi.
The lattice of DP can be decoded in &lt;span class=&quot;math&quot;&gt;\(\Theta(\sqrt{n}&#x2F;\log n)\)&lt;&#x2F;span&gt; time, which is a
large improvement.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-lattices-of-schnorr-and-dp&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-lattices-of-schnorr-and-dp&quot; aria-label=&quot;Anchor link for: the-lattices-of-schnorr-and-dp&quot;&gt;🔗&lt;&#x2F;a&gt;The Lattices of Schnorr and DP&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;schnorr&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#schnorr&quot; aria-label=&quot;Anchor link for: schnorr&quot;&gt;🔗&lt;&#x2F;a&gt;Schnorr&lt;&#x2F;h2&gt;
&lt;p&gt;Throughout this, let &lt;span class=&quot;math&quot;&gt;\(p_1,\dots, p_n\)&lt;&#x2F;span&gt; be distinct primes.
Schnorr introduces&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-adleman-1&quot;&gt;&lt;a href=&quot;#fn-adleman&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; the lattice with basis:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[B_{n, c} = \begin{pmatrix}
\sqrt{\ln p_1}&amp; 0 &amp; 0\\
0 &amp; \vdots &amp; 0\\
0 &amp; 0 &amp; \sqrt{\ln p_n}\\
N^c\ln p_1 &amp; \dots &amp; N^c \ln p_n
\end{pmatrix}\]&lt;&#x2F;span&gt;
&lt;p&gt;Here &lt;span class=&quot;math&quot;&gt;\(B_{N, c}\in\mathbb{R}^{(n+1)\times n}\)&lt;&#x2F;span&gt;, and &lt;span class=&quot;math&quot;&gt;\(N = \prod_i p_i\)&lt;&#x2F;span&gt;.
Schnorr then claims that solving the closest vector problem on this lattice with
target point &lt;span class=&quot;math&quot;&gt;\(t = e_{n+1}N^c\ln N\)&lt;&#x2F;span&gt; allows one to construct a triple &lt;span class=&quot;math&quot;&gt;\[(u, v,
|u - vN|)\]&lt;&#x2F;span&gt; that is &lt;span class=&quot;math&quot;&gt;\(p_n\)&lt;&#x2F;span&gt;-smooth, meaning each member of the triple has all
prime divisors &lt;span class=&quot;math&quot;&gt;\(\leq p_n\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Given &lt;span class=&quot;math&quot;&gt;\(n+1\)&lt;&#x2F;span&gt; triples &lt;span class=&quot;math&quot;&gt;\((u_i,v_i, |u_i-v_iN|)\)&lt;&#x2F;span&gt;, one proceeds as follows.
By smoothness, we have that:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[u_j = \prod_i p_i^{e_{i,j}},\qquad u_j-v_jN = \prod_i p_i^{e_{i,j}&#x27;}\]&lt;&#x2F;span&gt;
&lt;p&gt;It is simple to see that &lt;span class=&quot;math&quot;&gt;\((u_j-v_jN)&#x2F;u_j\equiv 1\bmod N\)&lt;&#x2F;span&gt;, so &lt;span class=&quot;math&quot;&gt;\[\prod_i
p_i^{e_{i,j}-e_{i,j}&#x27;}\equiv 1\bmod N\]&lt;&#x2F;span&gt;.
Any solution &lt;span class=&quot;math&quot;&gt;\(t_1,\dots,t_{n+1}\in\{0,1\}\)&lt;&#x2F;span&gt; which solves:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\sum_i t_i(e_{i,j}-e_{i,j}&#x27;)\equiv 0\bmod 2\]&lt;&#x2F;span&gt;
&lt;p&gt;leads to a solution of &lt;span class=&quot;math&quot;&gt;\(X^2 - 1\equiv 0\bmod N\)&lt;&#x2F;span&gt;, which (provided such &lt;span class=&quot;math&quot;&gt;\[X\neq
\pm 1\bmod N\]&lt;&#x2F;span&gt;) yields two non-trivial factors of &lt;span class=&quot;math&quot;&gt;\(N\)&lt;&#x2F;span&gt;.
In particular, one sets:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[X = \prod{i = 1}^{n+1}p_i^{\frac{1}{2}\sum_{j = 1}^{n+1} t_j (e_{i,j} - e_{i,j}&#x27;)}\]&lt;&#x2F;span&gt;
&lt;p&gt;One can see similarities between this and the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Quadratic_sieve&quot;&gt;quadratic
sieve&lt;&#x2F;a&gt;, although they do not
appear to be the same (and the quadratic sieve does not appear to have anything
to do with lattices).&lt;&#x2F;p&gt;
&lt;p&gt;Concretely, the above approach &lt;em&gt;does&lt;&#x2F;em&gt; work, and Leo Ducas has explicit
experiments showing parameter ranges that it works in.
But these parameters are much worse than Schnorr claims (from a cryptanalytic
point of view at least).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dp&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#dp&quot; aria-label=&quot;Anchor link for: dp&quot;&gt;🔗&lt;&#x2F;a&gt;DP&lt;&#x2F;h2&gt;
&lt;p&gt;The lattice of DP is broadly similar, although it is now defined in terms of
&lt;em&gt;discrete&lt;&#x2F;em&gt; logarithms of primes, rather than traditional logarithms (there are
of course other differences as well).
It fixes &lt;span class=&quot;math&quot;&gt;\(n, m\in\mathbb{N}\)&lt;&#x2F;span&gt; such that &lt;span class=&quot;math&quot;&gt;\((\mathbb{Z}&#x2F;m\mathbb{Z})^*\)&lt;&#x2F;span&gt; is a
cyclic group&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-cyclic-1&quot;&gt;&lt;a href=&quot;#fn-cyclic&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and sets:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\mathcal{F} = \{p\in\mathbb{N}\mid p\text{ prime}, p\nmid m, p \leq B\}\]&lt;&#x2F;span&gt;
&lt;p&gt;where &lt;span class=&quot;math&quot;&gt;\(B\)&lt;&#x2F;span&gt; is chosen such that &lt;span class=&quot;math&quot;&gt;\(|\mathcal{F}| = n\)&lt;&#x2F;span&gt;.
Easy arguments show that &lt;span class=&quot;math&quot;&gt;\(B\sim n\log n\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now, consider the group homomorphism:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\psi : \mathbb{Z}^n \to (\mathbb{Z}&#x2F;m\mathbb{Z})^*,\qquad
(x_1,\dots,x_n)\mapsto \prod_{i = 1}^n p_i^{x_i}\bmod m\]&lt;&#x2F;span&gt;
&lt;p&gt;The kernel of this is a subgroup of &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}^n\)&lt;&#x2F;span&gt;, and therefore a lattice.
One can write it as:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\mathcal{L} = \{(x_1,\dots,x_n) \in\mathbb{Z}^n \mid \prod_i p_i^{x_i}\equiv
1\bmod m\} = \{(x_1,\dots,x_n)\in\mathbb{Z}^n \mid \sum_{i = 1}^n x_i\log_g
p_i\equiv 0\bmod \varphi(m)\}\]&lt;&#x2F;span&gt;
&lt;p&gt;Here, &lt;span class=&quot;math&quot;&gt;\(\log_g p_i\)&lt;&#x2F;span&gt; is the &lt;em&gt;discrete log&lt;&#x2F;em&gt; of &lt;span class=&quot;math&quot;&gt;\(p_i\)&lt;&#x2F;span&gt; within the group
&lt;span class=&quot;math&quot;&gt;\((\mathbb{Z}&#x2F;m\mathbb{Z})^*\)&lt;&#x2F;span&gt;.
Lattice cryptographers have a compact way to describe lattices of the above
form, namely via the notation:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\Lambda_q^\perp(g) = \{\vec x\in\mathbb{Z}^n\mid \langle \vec x,\vec g\rangle\equiv
0\bmod q\}\]&lt;&#x2F;span&gt;
&lt;p&gt;where &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt; need not be prime.
One might call this a “rank 1 &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt;-ary lattice”.
Such lattices satisfy a sort of universality property, in that one can
approximate a large class of lattices from lattices of this type&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-approximate-1&quot;&gt;&lt;a href=&quot;#fn-approximate&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;From this description, it is fairy standard to write down an explicit basis:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{pmatrix}
1 &amp; 0 &amp; \dots &amp;0&amp; 0\\
0 &amp; 1 &amp; \dots &amp;0&amp; 0\\
\vdots &amp; &amp; \ddots &amp; \vdots\\
0 &amp; 0 &amp; \dots &amp; 1 &amp; 0\\
-\frac{\log_g p_1}{\log_g p_n} &amp; -\frac{\log_g p_2}{\log_g p_n} &amp;\dots &amp;
-\frac{\log_g p_{n-1} }{\log_g p_{n}} &amp;
\varphi(m)
\end{pmatrix}\]&lt;&#x2F;span&gt;
&lt;p&gt;Besides the last&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, DP writes down an explicit (up to determining &lt;span class=&quot;math&quot;&gt;\(\mathcal{F}\)&lt;&#x2F;span&gt;) lattice,
and shows that:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;It is quite dense&lt;&#x2F;li&gt;
&lt;li&gt;One can efficiently decode it&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The first point is not that surprising — there are various results that
essentially say that &lt;span class=&quot;math&quot;&gt;\(\log_g t\)&lt;&#x2F;span&gt; is distributed “randomly” (where I mean this
in an informal way) within &lt;span class=&quot;math&quot;&gt;\((\mathbb{Z}&#x2F;m\mathbb{Z})^*\)&lt;&#x2F;span&gt;.
As random lattices tend to have good density properties, it is perhaps not
surprising that a “random ish” lattice has good density (as actually
random&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-random-1&quot;&gt;&lt;a href=&quot;#fn-random&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; lattices get within a &lt;em&gt;constant&lt;&#x2F;em&gt; factor of Minkowski’s bound).
For this reason, I will focus on presenting the decoding algorithm.
The proof of correctness of the decoding algorithm itself can be seen as a proof
that &lt;span class=&quot;math&quot;&gt;\(\lambda_1(L)\)&lt;&#x2F;span&gt; is not too small.&lt;&#x2F;p&gt;
&lt;p&gt;DP frame their results in terms of the &lt;span class=&quot;math&quot;&gt;\(\ell_1\)&lt;&#x2F;span&gt; norm, and then use the generic
inequality &lt;span class=&quot;math&quot;&gt;\(\lVert x\rVert_1 \leq \sqrt{n}\lVert x\rVert_2\)&lt;&#x2F;span&gt;.
I will mimic the presentation in their paper, where they first discuss the
&lt;span class=&quot;math&quot;&gt;\(\ell_1\)&lt;&#x2F;span&gt; norm where the errors are &lt;em&gt;positive&lt;&#x2F;em&gt; (i.e. in &lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^n\)&lt;&#x2F;span&gt;),
before extending to arbitrary (discrete) errors.&lt;&#x2F;p&gt;
&lt;p&gt;Say that you are given a perturbed lattice vector &lt;span class=&quot;math&quot;&gt;\(t = x + e\)&lt;&#x2F;span&gt;.
Then, one can compute:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\prod_{i = 1}^n p_i^{t_i} = \prod_{i = 1}^n p_i^{x_i}\prod_{i = 1}^n
p_i^{e_i}\equiv \prod_{i = 1}^n p_i^{e_i}\bmod m\]&lt;&#x2F;span&gt;
&lt;p&gt;This essentially the same as “syndrome decoding” if you are familiar with that.
One then has that &lt;span class=&quot;math&quot;&gt;\(\prod_{i = 1}^n p_i^{e_i} \leq B^{\sum_i e_i} = B^{r}\)&lt;&#x2F;span&gt;&lt;&#x2F;p&gt;
&lt;p&gt;where &lt;span class=&quot;math&quot;&gt;\(r\)&lt;&#x2F;span&gt; is an &lt;span class=&quot;math&quot;&gt;\(\ell_1\)&lt;&#x2F;span&gt; upper bound on the size of decodable errors.
As long as this quantity does not “overflow” (i.e. as long as &lt;span class=&quot;math&quot;&gt;\(B^r &lt; m\)&lt;&#x2F;span&gt;),
everything works great.
This is because &lt;span class=&quot;math&quot;&gt;\(p_i^{e_i} &lt; m\)&lt;&#x2F;span&gt; is a smooth number, so one can efficiently
factor it, and recover the &lt;span class=&quot;math&quot;&gt;\(e_i\)&lt;&#x2F;span&gt;’s.
This leads to an &lt;span class=&quot;math&quot;&gt;\(\ell_1\)&lt;&#x2F;span&gt; bound of &lt;span class=&quot;math&quot;&gt;\(r &lt; \frac{\log_2 m}{\log_2 B}\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For arbitrary errors, the above decomposition no longer works.
This is because one has that:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[f = \prod_i p_i^{t_i} \equiv \prod_{i : e_i &gt; 0}p_i^{e_i} \prod_{i : e_i &lt;0}
p_i^{e_i}\equiv u&#x2F;v\bmod m\]&lt;&#x2F;span&gt;
&lt;p&gt;Is now a “fraction”.
One can recover this fraction by looking at the two-dimensional lattice &lt;span class=&quot;math&quot;&gt;\[x -
fy\]&lt;&#x2F;span&gt;, where &lt;span class=&quot;math&quot;&gt;\(x, y\in\mathbb{Z}\)&lt;&#x2F;span&gt;.
Under certain conditions, the shortest vector &lt;span class=&quot;math&quot;&gt;\((x, y)\)&lt;&#x2F;span&gt; in this lattice is precisely
&lt;span class=&quot;math&quot;&gt;\((u, v)\)&lt;&#x2F;span&gt;.
So recovering &lt;span class=&quot;math&quot;&gt;\((u, v)\)&lt;&#x2F;span&gt; can be reduced to a 2-dimensional SVP instance, which
is efficient to compute.
The “certain conditions” mean that the decoding bound is now &lt;span class=&quot;math&quot;&gt;\(r &lt; \frac{\log_2(m&#x2F;2)}{2\log_2(B)}\)&lt;&#x2F;span&gt;, but this is essentially the same as before.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;extensions&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#extensions&quot; aria-label=&quot;Anchor link for: extensions&quot;&gt;🔗&lt;&#x2F;a&gt;Extensions?&lt;&#x2F;h1&gt;
&lt;p&gt;If one examines the equations, &lt;span class=&quot;math&quot;&gt;\(B\sim n\log n\)&lt;&#x2F;span&gt; is required to get &lt;span class=&quot;math&quot;&gt;\(n\)&lt;&#x2F;span&gt;
distinct primes in the construction, which by the prime number theorem requires
that &lt;span class=&quot;math&quot;&gt;\(B\sim n\log n\)&lt;&#x2F;span&gt;.
The &lt;span class=&quot;math&quot;&gt;\(\ln n\)&lt;&#x2F;span&gt; factor away from optimal in this construction is implicitly a
&lt;span class=&quot;math&quot;&gt;\(\ln B\)&lt;&#x2F;span&gt; factor.
So there is a natural question — can one generalize this construction to allow
for smaller &lt;span class=&quot;math&quot;&gt;\(B\)&lt;&#x2F;span&gt;, to close this gap?&lt;&#x2F;p&gt;
&lt;p&gt;I personally suspect that the answer is no.
I thought about it a bit two years ago, by appealing to generalizations of the
notion of primality.
Essentially, if one was working in a system that had “many more primes” than one
would expect, it is possible that one could port over this argument (say if one
could take &lt;span class=&quot;math&quot;&gt;\(B\sim \ln n\)&lt;&#x2F;span&gt;).
This may seem like nonsense at first, but recall that &lt;span class=&quot;math&quot;&gt;\(B\)&lt;&#x2F;span&gt; is a norm bound on
some objects, so while within a “1D” object like &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}\)&lt;&#x2F;span&gt; there are only
at most &lt;span class=&quot;math&quot;&gt;\(\ln n\)&lt;&#x2F;span&gt; elements of norm below &lt;span class=&quot;math&quot;&gt;\(\ln n\)&lt;&#x2F;span&gt;, in a higher dimensional
object there can be many more.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, I was not able to make this strategy work.
The field of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Abstract_analytic_number_theory&quot;&gt;abstract analytic number
theory&lt;&#x2F;a&gt; studies
such “generalized primes”, and proves things like prime number theorems for
them.
I was unable to find a reasonable system that had dense enough primes (I
initially was hoping working over number fields would work, and only searched
for more abstract things after this failed).&lt;&#x2F;p&gt;
&lt;p&gt;Since then, I like to think of the construction more in terms of “de-randomizing” a construction that meets Minkowski’s bounds by (implicitly) combining:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The fact that &lt;span class=&quot;math&quot;&gt;\(\log_g p_i\)&lt;&#x2F;span&gt; is “pseudorandom”, so &lt;span class=&quot;math&quot;&gt;\[\Lambda_m^\perp((\log_g
   p_i))\]&lt;&#x2F;span&gt; is “pseudorandom” as well.&lt;&#x2F;li&gt;
&lt;li&gt;That rank 1 &lt;span class=&quot;math&quot;&gt;\(q\)&lt;&#x2F;span&gt;-ary lattices approximate arbitrary lattices fairly
well, so &lt;span class=&quot;math&quot;&gt;\(\Lambda_m^\perp((\log_g p_i))\)&lt;&#x2F;span&gt; is “fairly close” to a random
general lattice&lt;&#x2F;li&gt;
&lt;li&gt;That random (general) lattices are within constant factors of Minkowski’s
bound&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It would be interesting to explore this point of view further, and see if the
construction can be formalized in these terms.
In particular, it would be interesting to see where one loses a &lt;span class=&quot;math&quot;&gt;\(\ln n\)&lt;&#x2F;span&gt;
factor in the above steps.
I would guess step 2, but I do not have a great understanding of how strong the
approximation one gets is quantitatively (it is of course stated in the papers I
discussed, but it is generally stated in terms of approximating the entries of
the Gram matrix of the lattice coordinate-wise.
I do not have a great intuition how this impacts things like &lt;span class=&quot;math&quot;&gt;\(\lambda_1(L)\)&lt;&#x2F;span&gt;).&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-centerdensity&quot;&gt;
&lt;p&gt;Namely, you can also work with what I believe is called the
&lt;em&gt;center density&lt;&#x2F;em&gt;, and defined as
&lt;span class=&quot;math&quot;&gt;\[\frac{\mathsf{vol}(\mathcal{B}_n(\lambda_1(L)&#x2F;2))}{\det L}\]&lt;&#x2F;span&gt;
Where &lt;span class=&quot;math&quot;&gt;\(\mathcal{B}_n(R)\)&lt;&#x2F;span&gt; is the &lt;span class=&quot;math&quot;&gt;\(n\)&lt;&#x2F;span&gt;-dimensional ball of radius &lt;span class=&quot;math&quot;&gt;\(r\)&lt;&#x2F;span&gt;.
This is roughly the “&lt;span class=&quot;math&quot;&gt;\(n\)&lt;&#x2F;span&gt;th power” of the quantity we work with, although
there is an additional term related to the volume of the ball of radius 1.
Note that this name might be slightly off, but I believe it is the one that
&lt;em&gt;Conway and Sloane&lt;&#x2F;em&gt; refer to, but will not check for this post. &lt;a href=&quot;#fr-centerdensity-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-adleman&quot;&gt;
&lt;p&gt;I have heard that this construction is initially due to Adleman (although
there are slight differences between Schnorr’s and Adleman’s lattices).
Unfortunately, people have indicated that Adleman’s paper may not be easily
available online. &lt;a href=&quot;#fr-adleman-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-cyclic&quot;&gt;
&lt;p&gt;This assumption is not strictly necessary, but relaxing it does not
lead to better a construction. &lt;a href=&quot;#fr-cyclic-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-approximate&quot;&gt;
&lt;p&gt;This is discussed in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;1604.07800&quot;&gt;Shor and Eldar’s Systematic Normal Form
paper&lt;&#x2F;a&gt;, which is morally similar to &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;neilsloane.com&#x2F;doc&#x2F;FATS.pdf&quot;&gt;Sloane
and Vaishampayan’s investigations of projecting &lt;span class=&quot;math&quot;&gt;\(\mathbb{Z}^n\)&lt;&#x2F;span&gt; orthogonal to a
single vector&lt;&#x2F;a&gt;.
In fact, these kinds of results were behind &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;1611.06999&quot;&gt;Eldar and Shor’s attempt to put &lt;span class=&quot;math&quot;&gt;\(\mathsf{CVP}\)&lt;&#x2F;span&gt; in
&lt;span class=&quot;math&quot;&gt;\(\mathsf{BQP}\)&lt;&#x2F;span&gt; in 2016&lt;&#x2F;a&gt;, which was itself
another exciting time. &lt;a href=&quot;#fr-approximate-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-random&quot;&gt;
&lt;p&gt;Here, while “random” is formal, you have to be careful what you
mean by it. In particular, the space of all lattices can be described as a
``double coset’’ space, and there is a natural probability distribution on
this space known as the &lt;em&gt;Haar measure&lt;&#x2F;em&gt;. Many spaces unrelated to lattices
have Haar measures though (such as any compact group), and I personally have
never gone down this rabbithole deep enough to have good pointers to learn more,
or to have a good idea about what such a distribution explicitly looks like
for lattices. &lt;a href=&quot;#fr-random-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Can you do Quantum Key Distribution without Authenticated Channels?</title>
        <published>2020-10-30T00:00:00+00:00</published>
        <updated>2020-10-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com/blog/qkd/"/>
        <id>https://mark.schultz-wu.com/blog/qkd/</id>
        
        <content type="html" xml:base="https://mark.schultz-wu.com/blog/qkd/">&lt;p&gt;After attending a talk by Psi Vessely on Quantum Key Distribution (in particular
on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;BB84&quot;&gt;BB84&lt;&#x2F;a&gt;), the UCSD
crypto group discussed some of the alleged benefits of QKD.
We mentioned the “standard list”:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;No-cloning theorem provides protection against evesdroppers that “standard”
crypto cannot achieve &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-wiretap-1&quot;&gt;&lt;a href=&quot;#fn-wiretap&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The protocol itself only requires authenticated channels, so can be viewed as
“key exchange within Minicrypt”&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;In our discussion, Adam Suhl pointed out that we don’t &lt;em&gt;strictly&lt;&#x2F;em&gt; need to be
within Minicrypt, as (using previously-shared randomness) you could use a
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Message_authentication_code#One-time_MAC&quot;&gt;one-time
MAC&lt;&#x2F;a&gt; to
authenticate messages.
This leads to a natural question:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you run QKD using a one-time MAC to authenticate communications, can you
“gain” on the amount of shared random bits you have?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;If you could do the above, it gives a construction of information-theoretic
secure cryptography which both &lt;em&gt;doesn’t&lt;&#x2F;em&gt; assume that you’re in minicrypt, and
&lt;em&gt;doesn’t&lt;&#x2F;em&gt; have a limit on the amount of communication you can do.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-heuristic-answer&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-heuristic-answer&quot; aria-label=&quot;Anchor link for: the-heuristic-answer&quot;&gt;🔗&lt;&#x2F;a&gt;The Heuristic Answer&lt;&#x2F;h1&gt;
&lt;p&gt;Even without describing the BB84 protocol, it should be clear that the answer
depends on the (classical) round complexity of the protocol.
In particular, all classical communication must be MAC’d, and therefore expends
&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-one-time-mac-1&quot;&gt;&lt;a href=&quot;#fn-one-time-mac&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
some constant amount of the key material both parties have.
This means that a protocol which is &lt;span class=&quot;math&quot;&gt;\(O(f(n))\)&lt;&#x2F;span&gt; classical rounds must &lt;em&gt;also&lt;&#x2F;em&gt;
have &lt;span class=&quot;math&quot;&gt;\(O(f(n))\)&lt;&#x2F;span&gt; bits of preshared randomness to execute, where &lt;span class=&quot;math&quot;&gt;\(n\)&lt;&#x2F;span&gt; is the
amount of &lt;em&gt;quantum&lt;&#x2F;em&gt; bits communicated.&lt;&#x2F;p&gt;
&lt;p&gt;Provided the algorithm can agree on &lt;span class=&quot;math&quot;&gt;\(\omega(f(n))\)&lt;&#x2F;span&gt; random bits, we would
therefore have a strict “gain” in the number of shared bits upon a single
execution of the protocol.
We could then “bootstrap” this procedure to get an arbitrary number of
pre-shared bits, which we can use with things like the one-time pad to discard
&lt;em&gt;all&lt;&#x2F;em&gt; computational assumptions!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-actual-answer&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-actual-answer&quot; aria-label=&quot;Anchor link for: the-actual-answer&quot;&gt;🔗&lt;&#x2F;a&gt;The Actual Answer&lt;&#x2F;h1&gt;
&lt;p&gt;At this point, I would normally do some computations.
For better or worse, while searching for the round complexity of parts &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-info-reco-1&quot;&gt;&lt;a href=&quot;#fn-info-reco&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; of the BB84 protocol, I found &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;264.pdf&quot;&gt;this
paper&lt;&#x2F;a&gt;.
Section 4 in particular describes a relatively simple protocol which seems to
achieve “OTP-like” encryption by using QKD with one-time MACs to generate enough
key material. Note that I haven’t read the full paper (and do not work in this
area), but the plausible idea we had seems to have been fleshed out by this
paper, and they claim it works.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;issues-with-full-qkd-without-minicrypt&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#issues-with-full-qkd-without-minicrypt&quot; aria-label=&quot;Anchor link for: issues-with-full-qkd-without-minicrypt&quot;&gt;🔗&lt;&#x2F;a&gt;Issues with full QKD without Minicrypt&lt;&#x2F;h1&gt;
&lt;p&gt;The aforementioned scheme &lt;em&gt;seems&lt;&#x2F;em&gt; to provide a construction that allows you to
exchange enough key material to do the one-time pad on arbitrarily large
messages with &lt;em&gt;no&lt;&#x2F;em&gt; computational assumptions.
This is what I was hoping for, and we found it!&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, there’s the following &lt;em&gt;dumb&lt;&#x2F;em&gt; attack an evesdropper can always do
to thwart this plan — measure every quantum message!
This measurement can lead to the key exchange protocol failing, and a
reduction in the jointly shared randomness of Alice and Bob, which will
eventually force them to fallback on using techniques that do not deplete their
jointly shared randomness (such as computationally secure MACs to authenticate
the channel).&lt;&#x2F;p&gt;
&lt;p&gt;So the answer to “Can you do QKD without Authenticated Channels”? seems to be &lt;em&gt;yes, but
no&lt;&#x2F;em&gt;.
Still, the possibility of “bootstrapping” QKD is something I haven’t seen in
casual discussions of it, and was quite interesting to learn about.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-wiretap&quot;&gt;
&lt;p&gt;It’s worth mentioning that QKD is not the only form of key exchange which works
information-theoretically based on some non-standard assumptions on the
communication channel — the “Wire-tap channel” assumes that evesdroppers
recieve “noisier” versions of messages than actual participants, and can achieve
similar results. This is usually
studied by coding theorists, but there can be some overlap with cryptography —
for example, there are lattice-based constructions which rely on a parameter
(known as the “flatness factor”) which looks &lt;em&gt;suspiciously&lt;&#x2F;em&gt; like the smoothing
parameter from lattice cryptography, but I digress. &lt;a href=&quot;#fr-wiretap-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-one-time-mac&quot;&gt;
&lt;p&gt;This is because one-time MACs are information-theoretically
secure provided that you don’t reuse the keys, similarly to the one-time
pad. &lt;a href=&quot;#fr-one-time-mac-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-info-reco&quot;&gt;
&lt;p&gt;In particular of the “information reconciliation” step — all other steps seem to
be obviously a constant number of rounds to me. &lt;a href=&quot;#fr-info-reco-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Obstacles to the Calculus of Sensitivity</title>
        <published>2020-10-16T00:00:00+00:00</published>
        <updated>2020-10-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com/blog/sensitivity-calculus/"/>
        <id>https://mark.schultz-wu.com/blog/sensitivity-calculus/</id>
        
        <content type="html" xml:base="https://mark.schultz-wu.com/blog/sensitivity-calculus/">&lt;p&gt;In my &lt;a href=&quot;https:&#x2F;&#x2F;mark.schultz-wu.com&#x2F;blog&#x2F;dpsensitivity&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;, I discussed how
for an appropriate “discrete” form of the derivative &lt;span class=&quot;math&quot;&gt;\(\nabla\)&lt;&#x2F;span&gt;, that we have
that:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\Delta_{\vec x, p}(f) = \lVert \nabla f(\vec x)\rVert_p\]&lt;&#x2F;span&gt;
&lt;p&gt;Where &lt;span class=&quot;math&quot;&gt;\(\Delta_{\vec x, p}(f)\)&lt;&#x2F;span&gt; is the local &lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; sensitivity of &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; at
&lt;span class=&quot;math&quot;&gt;\(\vec x\)&lt;&#x2F;span&gt;, and &lt;span class=&quot;math&quot;&gt;\(\lVert\cdot\rVert_p\)&lt;&#x2F;span&gt; is a suitably-defined operator norm.
At the end of that post I discussed the potential for a “sensitivity calculus”.
I will further develop this concept in this post, with the aim of developing the
prerequisites for a programmatic sensitivity analysis.
Along the way, I’ll run into a significant roadblock.
I’m writing all of this up to show &lt;em&gt;why&lt;&#x2F;em&gt; the idea I had at the end of the last
post ended up not working out.
As a result, this likely isn’t very interesting to anyone besides myself, but it
means that I’ve tied up a loose end, and can move onto other things after being
&lt;em&gt;waaay&lt;&#x2F;em&gt; too interested in this in the last 24 hours.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-rules-of-discrete-differentiation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-rules-of-discrete-differentiation&quot; aria-label=&quot;Anchor link for: the-rules-of-discrete-differentiation&quot;&gt;🔗&lt;&#x2F;a&gt;The rules of discrete differentiation&lt;&#x2F;h1&gt;
&lt;p&gt;The idea here is to mimic the “differentiation” rules for standard calculus.
Some basic examples of these are the:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Sum rule&lt;&#x2F;li&gt;
&lt;li&gt;Product rule&lt;&#x2F;li&gt;
&lt;li&gt;Quotient rule&lt;&#x2F;li&gt;
&lt;li&gt;Chain rule&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;If we had equivalents of all of these, we would be in a rather good place.
I will first develop equivalents for these for the 1D discrete derivative,
before trying to generalize these to higher dimensions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-1d-case&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-1d-case&quot; aria-label=&quot;Anchor link for: the-1d-case&quot;&gt;🔗&lt;&#x2F;a&gt;The 1D case&lt;&#x2F;h2&gt;
&lt;p&gt;Recall that the 1D discrete derivative (also known as the forward difference
operator) is defined as:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[f&#x27;(n) = f(n+1) - f(n)\]&lt;&#x2F;span&gt;
&lt;p&gt;Its easy to see by inspection that this behaves well with respect to sums (and
is in fact linear).
As a result, I will ignore that case, and examine products.
One can easily compute:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
(fg)&#x27;(n) &amp;= f(n+1)g(n+1) - f(n)g(n)\\
&amp;= (f&#x27;(n) + f(n))g(n+1) - f(n)g(n)\\
&amp;= f&#x27;(n)g(n+1) + f(n)(g(n+1)-g(n))\\
&amp;\stackrel{1}{=} f&#x27;(n)g(n+1) + f(n)g&#x27;(n)\\
&amp;= f&#x27;(n)(g&#x27;(n) + g(n)) + f(n)g&#x27;(n)\\
&amp;= f&#x27;(n)g(n) + f(n)g&#x27;(n) + f&#x27;(n)g&#x27;(n)
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;We see in the above line marked 1 that we come &lt;em&gt;close&lt;&#x2F;em&gt; to the definition of the
standard product rule, but unfortunately fall short.
We still get a well-defined product rule though, so we move on to quotients.&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
(f&#x2F;g)&#x27;(n) &amp;= \frac{f(n+1)}{g(n+1)} - \frac{f(n)}{g(n)}\\
&amp;= \frac{f(n+1)g(n) - f(n)g(n+1)}{g(n+1)g(n)}\\
&amp;= \frac{f(n)g(n) + f&#x27;(n)g(n) - f(n)g(n) - f(n)g&#x27;(n)}{g(n+1)g(n)}\\
&amp;= \frac{f&#x27;(n)g(n) - f(n)g&#x27;(n)}{g(n)^2 + g&#x27;(n)}
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;We again get something &lt;em&gt;close&lt;&#x2F;em&gt; to what we would expect, but not the same.
We finally move onto the chain rule.
We note that this is slightly more subtle than before — the domain and
codomain of &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; and &lt;span class=&quot;math&quot;&gt;\(g\)&lt;&#x2F;span&gt; are not the same.
There are two possible solutions to this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Restrict composition to functions &lt;span class=&quot;math&quot;&gt;\(f : \mathbb{N}^k\to\mathbb{N}^j\)&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Do not make this restriction, and only restrict the “inner” function to have
domain &lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^k\)&lt;&#x2F;span&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;We can worry about this later though, and first try to simplify the expression
&lt;span class=&quot;math&quot;&gt;\((f\circ g)&#x27;(n)\)&lt;&#x2F;span&gt;.
One (again) gets a chain rule, but of a slightly different form:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
(f\circ g)&#x27;(n) &amp;= f(g(n+1)) - f(g(n))\\
&amp;= f(g(n) + g&#x27;(n)) - (f\circ g)(n)
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;Note that we require &lt;em&gt;very little&lt;&#x2F;em&gt; requirements on &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt;, solely that its domain
matches up with &lt;span class=&quot;math&quot;&gt;\(g\)&lt;&#x2F;span&gt;’s codomain.
We quickly mention that this doesn’t mean suddenly that we use standard
“continuous” derivatives in our analysis (even if &lt;span class=&quot;math&quot;&gt;\(f : \mathbb{R}^n\to\mathbb{R}^m\)&lt;&#x2F;span&gt;).
This is because the “top” of our analysis is the discrete Jacobian &lt;span class=&quot;math&quot;&gt;\(\nabla f\)&lt;&#x2F;span&gt;,
and the rules we develop will propegate &lt;em&gt;discrete&lt;&#x2F;em&gt; derivatives “down” our
expression in particular.
So &lt;em&gt;even&lt;&#x2F;em&gt; if we are analyzing a continuous function, we will be analyzing it in
terms of the forward difference operator (i.e. discrete derivative).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;higher-dimensions&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#higher-dimensions&quot; aria-label=&quot;Anchor link for: higher-dimensions&quot;&gt;🔗&lt;&#x2F;a&gt;Higher Dimensions&lt;&#x2F;h2&gt;
&lt;p&gt;What does the calculus of derivatives for a function &lt;span class=&quot;math&quot;&gt;\(f : \mathbb{N}^k\to\mathbb{R}\)&lt;&#x2F;span&gt; look
like?&lt;&#x2F;p&gt;
&lt;p&gt;Recall that we define:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[(\partial&#x2F;\partial x_i)f(\vec x) = f(\vec x + e_i) - f(\vec x)\]&lt;&#x2F;span&gt;
&lt;p&gt;It is routine to check that this leads to (except for the chain rule) precisely the same “rules”, but in
terms of the partial derivatives rather than the standard derivatives.
I will repeat the analysis for the chain rule, as it is both simple, and
illustrates this point fairly well.&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
(\partial&#x2F;\partial x_i)(f\circ g)(\vec x) &amp;= (f\circ g)(\vec x + e_1) - (f\circ g)(\vec x)\\
&amp;= f(g(\vec x + e_1)) - (f\circ g)(\vec x)\\
&amp;= f(g(\vec x) + (\partial&#x2F;\partial x_i)g(\vec x)) - (f\circ g)(\vec x)
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;Given that this situation was simple, what about higher dimensions?
Once our codomain is &lt;span class=&quot;math&quot;&gt;\(\mathbb{R}^m\)&lt;&#x2F;span&gt;, we seem to lose the product and
quotient rules.
This is simply because &lt;span class=&quot;math&quot;&gt;\(\mathbb{R}^m\)&lt;&#x2F;span&gt; does not have a great multiplication or
division operation to use in the first place.
The sum rule will still work for boring reasons, so what about the chain rule?&lt;&#x2F;p&gt;
&lt;p&gt;Let &lt;span class=&quot;math&quot;&gt;\(g : \mathbb{N}^k\to \mathbb{R}^n\)&lt;&#x2F;span&gt;, and let &lt;span class=&quot;math&quot;&gt;\[f :
\mathbb{R}^n\to\mathbb{R}^m\]&lt;&#x2F;span&gt;.
What can we say about &lt;span class=&quot;math&quot;&gt;\(\nabla (f\circ g)(\vec x)\)&lt;&#x2F;span&gt;?
Well, at least the following:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
\nabla (f\circ g)(\vec x) &amp;= ((\partial&#x2F;\partial x_1)(f\circ g)(\vec x),\dots,
(\partial&#x2F;\partial x_k)(f\circ g)(\vec x))\\
&amp;= ((f\circ g)(\vec x + e_1) - (f\circ g)(\vec x),\dots, (f\circ g)(\vec x + e_k) - (f\circ g)(\vec x))\\
&amp;= ((f\circ g)(\vec x + e_1),\dots, (f\circ g)(\vec x + e_k)) -
\mathbf{1}\otimes (f\circ g)(\vec x)\\
&amp;= (f(g(\vec x) + (\partial&#x2F;\partial x_1)g(\vec x)),\dots, f(g(\vec x) +
(\partial&#x2F;\partial x_k)g(\vec x))) - \mathbf{1}\otimes (f\circ g)(\vec x)
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;Here, by &lt;span class=&quot;math&quot;&gt;\(\mathbf{1}\otimes (f\circ g)(\vec x)\)&lt;&#x2F;span&gt;, I mean the tensor product of
&lt;span class=&quot;math&quot;&gt;\(\mathbf{1} = (1,1,\dots,1)\in\mathbb{R}^k\)&lt;&#x2F;span&gt; with &lt;span class=&quot;math&quot;&gt;\((f\circ g)(\vec x)\)&lt;&#x2F;span&gt;.
This is just the matrix &lt;span class=&quot;math&quot;&gt;\(((f\circ g)(\vec x),\dots, (f\circ g)(\vec x))\)&lt;&#x2F;span&gt;, or
equivalently the “vector” of that shape where each entry is an &lt;span class=&quot;math&quot;&gt;\(m\)&lt;&#x2F;span&gt;-dimensional
(column) vector.&lt;&#x2F;p&gt;
&lt;p&gt;This suggests that we &lt;em&gt;do&lt;&#x2F;em&gt; have another chain rule.
It may not be able to be written in a pretty way, but our initial goal was to
use computers to calculate this all anyway, so who cares?
We (in principle) have a chain rule, so can bravely go on to the next step.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-brick-wall-you-run-into&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-brick-wall-you-run-into&quot; aria-label=&quot;Anchor link for: the-brick-wall-you-run-into&quot;&gt;🔗&lt;&#x2F;a&gt;The brick wall you run into&lt;&#x2F;h1&gt;
&lt;p&gt;At this point, I admit defeat.
This may seem premature, given that one &lt;em&gt;should&lt;&#x2F;em&gt; be able to write a computer
program to apply the above rules.
I haven’t yet computed discrete derivatives of simple functions, but this also
seems relatively easy to do.&lt;&#x2F;p&gt;
&lt;p&gt;What isn’t simple is the operator norm.
I was hoping that the sub-additivity and sub-multiplicativity combine with the
calculus we develop to allow us to get (potentially loose) upper bounds on the
various derivatives.
This intuition is right for &lt;em&gt;continuous&lt;&#x2F;em&gt; calculus, but fails in our discrete
setting.&lt;&#x2F;p&gt;
&lt;p&gt;Why is that?
Because of the chain rule.
The multivariable form of it is particularly nice — specificially that:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\nabla (f\circ g)(\vec x) = (\nabla f)(g(\vec x))\cdot (\nabla g)(\vec x)\]&lt;&#x2F;span&gt;
&lt;p&gt;Note that this expresses the derivative of the &lt;em&gt;composition&lt;&#x2F;em&gt; in terms of the
(matrix) product of the derivatives (which are linear maps).
While this allows for compact notation, it &lt;em&gt;also&lt;&#x2F;em&gt; has an important property that
it behaves well with respect to sub-multiplicative norms (such as the operator
norm) — in particular:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\lVert \nabla (f\circ g)(\vec x)\rVert_p \leq \lVert (\nabla f)(g(\vec
x))\rVert_p \lVert \nabla g(\vec x)\rVert_p\]&lt;&#x2F;span&gt;
&lt;p&gt;It is not clear how to upper bound the norms of some of the expressions I was
developing.
So of the two steps:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Rewrite derivative in terms of “simpler” derivatives automatically using a
“differential calculus”&lt;&#x2F;li&gt;
&lt;li&gt;Upper bound this rewritten derivative using sub-additivity and
sub-multiplicativity of the operator norm&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The second step is the one which seems problematic.
In general, one would need a way to upper bound the operator norm of expressions
of the form:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\lVert (f(g(\vec x) + (\partial&#x2F;\partial x_1)g(\vec x)),\dots, f(g(\vec x) +
(\partial&#x2F;\partial x_k)g(\vec x)))\rVert_p\]&lt;&#x2F;span&gt;
&lt;p&gt;This seems intrinsically difficult.
If we unwrap what the operator norm means, this is bounding the expression:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
\lVert \nabla (f\circ g)(\vec x)\rVert_p &amp;= \sup\{\lVert \nabla (f\circ g)(\vec
x)e_i\mid i\in[|\mathcal{X}|]\rVert_p\\
&amp;= \max_i\lVert (\partial&#x2F;\partial x_i) (f\circ g)(\vec x)\rVert_p\\
&amp;= \max_i \lVert f(g(\vec x) + (\partial&#x2F;\partial x_i)g(\vec x)) - f(g(\vec x))\rVert_p
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;One can use triangle inequality to separate this out, but I run into issues even
when trying to upper bound &lt;span class=&quot;math&quot;&gt;\(\lVert f(g(\vec x))\rVert_p\)&lt;&#x2F;span&gt;.
The issue here (compared to the continuous case) is that this is a composition
of &lt;em&gt;potentially non-linear&lt;&#x2F;em&gt; functions.
It looks like with enough “continuous” data, there are areas of math that
attempt to get bounds like this for non-linear functions (for example
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;math&#x2F;0506424v2.pdf&quot;&gt;this&lt;&#x2F;a&gt;).
You could even do simpler things, and find a “suitably good” polynomial
approximation to &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt;.
These techniques feel like they’re starting to lead to incredibly loose bounds
though, so I’ll decide to walk away from the brick wall now rather than continue
to hit my head against it until something breaks.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sensitivity as the Operator Norm of a Derivative</title>
        <published>2020-10-15T00:00:00+00:00</published>
        <updated>2020-10-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://mark.schultz-wu.com/blog/dpsensitivity/"/>
        <id>https://mark.schultz-wu.com/blog/dpsensitivity/</id>
        
        <content type="html" xml:base="https://mark.schultz-wu.com/blog/dpsensitivity/">&lt;p&gt;Differential Privacy is an area which has seen wide interest
(both in academia and real-life) in recent years.
But what &lt;em&gt;is&lt;&#x2F;em&gt; differential privacy?
As I don’t work in this area, I’m rather ill-suited to say anything — but
at least why does it have that name?
Frank McSherry (one of the founders of the area, who shares the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;G%C3%B6del_Prize&quot;&gt;Godel
Prize&lt;&#x2F;a&gt; as a result)
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crypto.stackexchange.com&#x2F;questions&#x2F;77324&#x2F;what-does-the-term-differential-in-differential-privacy-mean&quot;&gt;states that it was one of several names
considered&lt;&#x2F;a&gt;, including others like “Marginal Privacy” or “Incremental Privacy”.
He further states that he thinks the name “stuck” due to an analogy with
differential cryptanalysis.&lt;&#x2F;p&gt;
&lt;p&gt;This post is a relatively quick note on how “differential” objects show up
(implicitly) in differential privacy.
This is somewhat unsurprising, but formalizing this has been sufficiently weird
journey that it seemed like it should be shared with others.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;what-is-differential-privacy&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-is-differential-privacy&quot; aria-label=&quot;Anchor link for: what-is-differential-privacy&quot;&gt;🔗&lt;&#x2F;a&gt;What is Differential Privacy?&lt;&#x2F;h1&gt;
&lt;p&gt;To avoid this post dragging on too long, I’m going to answer “I’m not telling”.
My plan is to do this &lt;em&gt;regardless if I really know&lt;&#x2F;em&gt;, so this response is actually
differentially private (ha).&lt;&#x2F;p&gt;
&lt;p&gt;For people who actually want to know, there are a variety of excellent technical
resources to learn.
In particular &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;privacytools.seas.harvard.edu&#x2F;files&#x2F;privacytools&#x2F;files&#x2F;the_algorithmic_foundations_of_differential_privacy_0.pdf&quot;&gt;The Algorithmic Foundations of Differential
Privacy&lt;&#x2F;a&gt; by Dwork and Roth is great.
I’ll defer to them for an introduction, and even adopt their notation.
Really, the entirety of this post is pointing out that a common parameter within
differential privacy can be interpreted in terms of a deceptively simple
equation.
To cut to the chase:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\Delta_{\vec x, p}(f) = \lVert \nabla f(\vec x)\rVert_p\]&lt;&#x2F;span&gt;
&lt;p&gt;Where &lt;span class=&quot;math&quot;&gt;\(\Delta_{\vec x, p}(f)\)&lt;&#x2F;span&gt; is the local &lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; sensitivity of &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; at
&lt;span class=&quot;math&quot;&gt;\(\vec x\)&lt;&#x2F;span&gt;.
This immediately implies the following for the global sensitivity
&lt;span class=&quot;math&quot;&gt;\(\Delta_p(f)\)&lt;&#x2F;span&gt;:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\Delta_p(f) = \max_{\vec x\in\mathbb{N}^{|\mathcal{X}|}} \lVert \nabla f(\vec
x)\rVert_p\]&lt;&#x2F;span&gt;
&lt;p&gt;So in effect, if you define triangles correctly, you can “flip” one upside
down (or right-side up — I do not know the natural orientation of triangles).
Before discussing the “discrete derivative” definitions which will be needed to
interpret the right-hand side, we should probably talk about the quantity on the
left-hand side.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-sensitivity-of-a-function&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-sensitivity-of-a-function&quot; aria-label=&quot;Anchor link for: the-sensitivity-of-a-function&quot;&gt;🔗&lt;&#x2F;a&gt;The sensitivity of a function&lt;&#x2F;h1&gt;
&lt;p&gt;As mentioned before, I will use the notation of Dwork and Roth’s book.
Definition 3.1 and 3.8 define the (global) &lt;span class=&quot;math&quot;&gt;\(\ell_1\)&lt;&#x2F;span&gt; and &lt;span class=&quot;math&quot;&gt;\(\ell_2\)&lt;&#x2F;span&gt; sensitivities.
Upon reading both of them, there is a straightforward generalization to
&lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; sensitivities, which I give below:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The global &lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; sensitivity of a function &lt;span class=&quot;math&quot;&gt;\[f :
&gt; \mathbb{N}^{|\mathcal{X}|}\to\mathbb{R}^k\]&lt;&#x2F;span&gt; is:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\(\Delta_p(f) = \max_{\vec{x}, \vec{y}\in\mathbb{N}^{|\mathcal{X}|} : \lVert \vec x - \vec y \rVert_1 = 1} \lVert f(\vec x) - f(\vec y)\rVert_p\)&lt;&#x2F;span&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;One can also speak of the “local” sensitivity of a function &lt;em&gt;at&lt;&#x2F;em&gt; at point
&lt;span class=&quot;math&quot;&gt;\(\vec{x}\in\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt;.
This can be viewed as the global sensitivity where
&lt;span class=&quot;math&quot;&gt;\(\vec{x}\in\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt; is &lt;em&gt;fixed&lt;&#x2F;em&gt;.
An &lt;span class=&quot;math&quot;&gt;\(\ell_1\)&lt;&#x2F;span&gt; version of this is mentioned in definition 7.1.
As no notation is given, I will write &lt;span class=&quot;math&quot;&gt;\(\Delta_{p, \vec x}(f)\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The local &lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; sensitivity of a function
&lt;span class=&quot;math&quot;&gt;\(f : \mathbb{N}^{|\mathcal{X}|} \to \mathbb{R}^k\)&lt;&#x2F;span&gt; is:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\Delta_{p, \vec x}(f) = \max_{\vec y\in\mathbb{N}^{|\mathcal{X}|} : \lVert
&gt; \vec x - \vec y\rVert_1 = 1} \lVert f(\vec x) - f(\vec y)\rVert_p\]&lt;&#x2F;span&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;One can easily see that &lt;span class=&quot;math&quot;&gt;\(\Delta_p(f) = \max_{\vec x\in\mathbb{N}^{|\mathcal{X}|}}\Delta_{p, \vec x}(f)\)&lt;&#x2F;span&gt;.
As the global sensitivity is more common, I’ll quickly describe the motivation
for it.&lt;&#x2F;p&gt;
&lt;p&gt;Generally this is explained in a few steps.
First, it is stated (or already known) that &lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt; is
the natural domain of an arbitrary database.
Intuitively, a &lt;em&gt;record&lt;&#x2F;em&gt; in a database is an element &lt;span class=&quot;math&quot;&gt;\(r\in\mathcal{X}\)&lt;&#x2F;span&gt;, for some
finite set &lt;span class=&quot;math&quot;&gt;\(\mathcal{X}\)&lt;&#x2F;span&gt;.
Then the &lt;em&gt;database&lt;&#x2F;em&gt; is a collection of records, where you count the multiplicity
of each record.
It therefore lives in &lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt;.
Next, one notes that the condition that &lt;span class=&quot;math&quot;&gt;\(\lVert \vec x-\vec y\rVert_1 = 1\)&lt;&#x2F;span&gt; can be
interpreted as “the databases &lt;span class=&quot;math&quot;&gt;\(\vec x\)&lt;&#x2F;span&gt; and &lt;span class=&quot;math&quot;&gt;\(\vec y\)&lt;&#x2F;span&gt; are neighboring”, in that they
differ in how many times a particular record occurs by a count of 1.
Finally, the condition &lt;span class=&quot;math&quot;&gt;\(\lVert f(\vec x) - f(\vec y)\rVert_p\)&lt;&#x2F;span&gt; is interpreted as
quantifying how much &lt;span class=&quot;math&quot;&gt;\(f(\vec x) - f(\vec y)\)&lt;&#x2F;span&gt; can change on neighboring records.
The local sensitivity still bounds how much &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; can change on neighboring
records, but it &lt;em&gt;in particular&lt;&#x2F;em&gt; bounds how much &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; can change on records
which neighbor &lt;span class=&quot;math&quot;&gt;\(\vec x\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Given language like “The &lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; sensitivity quantifies how much a function
&lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; can change on adjacent points”, it seems entirely unsurprising that you
can characterize it in terms of a derivative-like concept.
But what &lt;em&gt;is&lt;&#x2F;em&gt; a derivative for a function with the domain &lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt;?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;discrete-derivatives&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#discrete-derivatives&quot; aria-label=&quot;Anchor link for: discrete-derivatives&quot;&gt;🔗&lt;&#x2F;a&gt;Discrete derivatives&lt;&#x2F;h2&gt;
&lt;p&gt;Throughout this section, I will define “discrete” analogus of the:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Derivative &lt;span class=&quot;math&quot;&gt;\(f&#x27;\)&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Partial Derivative &lt;span class=&quot;math&quot;&gt;\((\partial&#x2F;\partial x_i)f\)&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Gradient &lt;span class=&quot;math&quot;&gt;\(\nabla f\)&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I will do this by defining a (reasonable) “discrete” analogue of &lt;span class=&quot;math&quot;&gt;\(f&#x27;\)&lt;&#x2F;span&gt;, and
then showing that in the continuous case, one can define &lt;span class=&quot;math&quot;&gt;\[(\partial&#x2F;\partial
x_i)f\]&lt;&#x2F;span&gt; abstractly in terms of &lt;span class=&quot;math&quot;&gt;\(f&#x27;\)&lt;&#x2F;span&gt;, and &lt;span class=&quot;math&quot;&gt;\(\nabla f\)&lt;&#x2F;span&gt; abstractly in terms of
&lt;span class=&quot;math&quot;&gt;\((\partial&#x2F;\partial x_i)f\)&lt;&#x2F;span&gt;.
I’ll then shove the discrete version of &lt;span class=&quot;math&quot;&gt;\(f&#x27;\)&lt;&#x2F;span&gt; through this set of
transformations to end up with a discrete version of &lt;span class=&quot;math&quot;&gt;\(\nabla f\)&lt;&#x2F;span&gt;.
This “pipeline” is the sense in which I mean that my definition of the discrete
gradient is &lt;em&gt;natural&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To highlight the similarities throughout this, I will use the same notation for
discrete and continuous derivatives.
If one wanted to actually compute with these, you could just check the domain of
&lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; to see which of the two methods to apply.
Anyway, onwards to technical content.&lt;&#x2F;p&gt;
&lt;p&gt;First, I’ll restrict to “1 dimensional” functions &lt;span class=&quot;math&quot;&gt;\[f :
\mathbb{N}\to\mathbb{R}\]&lt;&#x2F;span&gt;, before generalizing to something more useful.&lt;&#x2F;p&gt;
&lt;p&gt;Recall that the (continuous) derivative is traditionally defined via the
&lt;em&gt;difference quotient&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[f&#x27;(x) = \lim_{h\to 0, h\neq 0}\frac{f(x+h) - f(x)}{h}\]&lt;&#x2F;span&gt;
&lt;p&gt;If we want to restrict to discrete domains, we have to make sure that &lt;span class=&quot;math&quot;&gt;\(x+h\)&lt;&#x2F;span&gt; is
discrete (as it must be in the domain of &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt;).
In our setting, this means that &lt;span class=&quot;math&quot;&gt;\(h\in\mathbb{N}\)&lt;&#x2F;span&gt;.
As we need &lt;span class=&quot;math&quot;&gt;\(h\neq 0\)&lt;&#x2F;span&gt;, this itself really means that we need &lt;span class=&quot;math&quot;&gt;\(h = 1\)&lt;&#x2F;span&gt;, so can
define:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[f&#x27;(x) = \frac{f(x+1) - f(x)}{1} = f(x+1) - f(x)\]&lt;&#x2F;span&gt;
&lt;p&gt;This definition is fairly standard (known as the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Finite_difference&quot;&gt;forward difference
operator&lt;&#x2F;a&gt;), and denoted
&lt;span class=&quot;math&quot;&gt;\(\Delta(f)\)&lt;&#x2F;span&gt;.
As &lt;span class=&quot;math&quot;&gt;\(\Delta\)&lt;&#x2F;span&gt; is &lt;em&gt;already&lt;&#x2F;em&gt; a super overloaded symbol in this post, I will
instead refer to it as &lt;span class=&quot;math&quot;&gt;\(f&#x27;(x)\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;How do we generalize (continuous) derivatives to higher dimensions?
The way that most people learn is the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Partial_derivative#Formal_definition&quot;&gt;partial
derivative&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class=&quot;math&quot;&gt;\(f : \mathbb{R}^n\to \mathbb{R}\)&lt;&#x2F;span&gt;.
The &lt;em&gt;partial derivative&lt;&#x2F;em&gt; of &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; with respect to the variable &lt;span class=&quot;math&quot;&gt;\(x_i\)&lt;&#x2F;span&gt; is defined
as:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\frac{\partial}{\partial x_i}f(\vec{x}) = \lim_{h\to 0, h\neq 0}
&gt; \frac{f(\vec{x} +he_i) - f(\vec{x})}{h}\]&lt;&#x2F;span&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;I will interpret the partial derivative as the 1D derivative of a particular
unary function.
The particular function is:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[F_{\vec x, i}(t) = f(\vec x - \vec{x}_i + e_i + te_i)\]&lt;&#x2F;span&gt;
&lt;p&gt;One can check that in the continuous case this is such that &lt;span class=&quot;math&quot;&gt;\[F_{\vec x,
i}&#x27;(\vec x_i) = (\partial&#x2F;\partial x_i)f(\vec x)\]&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When applied to the discrete derivative, one gets that:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class=&quot;math&quot;&gt;\(f : \mathbb{N}^n\to \mathbb{R}\)&lt;&#x2F;span&gt;.
For any &lt;span class=&quot;math&quot;&gt;\(\vec{x}\in\mathbb{N}^n\)&lt;&#x2F;span&gt; and &lt;span class=&quot;math&quot;&gt;\(i\in[n]\)&lt;&#x2F;span&gt;, let &lt;span class=&quot;math&quot;&gt;\(F_{\vec{x}, i}(y) = f(\vec x - \vec{x}_ie_i + te_i)\)&lt;&#x2F;span&gt;
The &lt;em&gt;discrete partial derivative&lt;&#x2F;em&gt; of &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; with respect to the variable
&lt;span class=&quot;math&quot;&gt;\(x_i\)&lt;&#x2F;span&gt; is defined as:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
 (\partial&#x2F;\partial x_i)f(\vec{x}) &amp;= F_{\vec{x}, i}&#x27;(\vec{x}_i)\\
&amp;= f(\vec x + e_i) - f(\vec x)
 \end{aligned}\]&lt;&#x2F;span&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;I’ll quickly mention that (something close to this) &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Finite_difference#Multivariate_finite_differences&quot;&gt;seems like it is used &lt;em&gt;some places&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;.
For further motivation for why this
may be a sensible “discrete partial derivative”, I’ll point to a conceptually close definition of “&lt;span class=&quot;math&quot;&gt;\(\mathbb{F}_2\)&lt;&#x2F;span&gt;-partial derivatives”, which take a similar form (such as in &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;web.cs.ucla.edu&#x2F;~sherstov&#x2F;pdf&#x2F;directional.pdf&quot;&gt;this
paper&lt;&#x2F;a&gt;, near theorem 1.5).&lt;&#x2F;p&gt;
&lt;p&gt;Of course, sensitivity is defined for functions &lt;span class=&quot;math&quot;&gt;\[f :
\mathbb{N}^{|\mathcal{X}|}\to\mathbb{R}^k\]&lt;&#x2F;span&gt;, so we have one final step of
generalization to do.
Recall that the gradient is just a vector containing the partial derivatives in
each direction:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\nabla f(x) = ((\partial&#x2F;\partial x_1)f(x),\dots, (\partial&#x2F;\partial
x_n)f(x))\]&lt;&#x2F;span&gt;
&lt;p&gt;I will then define the “discrete gradiant” in the same way below:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\nabla f(x) = ((\partial&#x2F;\partial x_1)f(x), \dots, (\partial&#x2F;\partial x_n)f(x))\]&lt;&#x2F;span&gt;
&lt;p&gt;Before proceeding, we need to note that (when the codomain of &lt;span class=&quot;math&quot;&gt;\(f\)&lt;&#x2F;span&gt; is dimension
&lt;span class=&quot;math&quot;&gt;\(&gt;1\)&lt;&#x2F;span&gt;) &lt;span class=&quot;math&quot;&gt;\(\nabla f(x)\)&lt;&#x2F;span&gt; is most naturally a &lt;em&gt;matrix&lt;&#x2F;em&gt; (called the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Jacobian_matrix_and_determinant&quot;&gt;&lt;em&gt;Jacobian&lt;&#x2F;em&gt; matrix&lt;&#x2F;a&gt;), whose &lt;span class=&quot;math&quot;&gt;\(i\)&lt;&#x2F;span&gt;th column
is &lt;span class=&quot;math&quot;&gt;\((\partial&#x2F;\partial x_i)f(x)\)&lt;&#x2F;span&gt;.
I will still notate this &lt;span class=&quot;math&quot;&gt;\(\nabla f\)&lt;&#x2F;span&gt;
I will define the norm of a matrix to be its &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Operator_norm&quot;&gt;&lt;em&gt;operator
norm&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;.
The general definition of this is included below:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class=&quot;math&quot;&gt;\(M : V\to W\)&lt;&#x2F;span&gt; be a linear operator, and let &lt;span class=&quot;math&quot;&gt;\(\lVert\cdot\rVert_V\)&lt;&#x2F;span&gt;,
&lt;span class=&quot;math&quot;&gt;\(\lVert\cdot\rVert_W\)&lt;&#x2F;span&gt; be norms on &lt;span class=&quot;math&quot;&gt;\(V\)&lt;&#x2F;span&gt; and &lt;span class=&quot;math&quot;&gt;\(W\)&lt;&#x2F;span&gt; respectively.
Define the norm of &lt;span class=&quot;math&quot;&gt;\(M\)&lt;&#x2F;span&gt; by:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\lVert M\rVert = \sup\{\lVert Mv\rVert_W \mid v\in V, \lVert v\rVert_V =
&gt; 1\}\]&lt;&#x2F;span&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;Of course, our domain is &lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt;.
What norm are we picking on it?
This choice is key to the entire construction, so I will discuss it in a little
more depth.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;viewing-as-a-normed-space&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#viewing-as-a-normed-space&quot; aria-label=&quot;Anchor link for: viewing-as-a-normed-space&quot;&gt;🔗&lt;&#x2F;a&gt;Viewing &lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt; as a normed space&lt;&#x2F;h2&gt;
&lt;p&gt;The natural norm to put on &lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt; is a norm induced by
viewing it as a subset of &lt;span class=&quot;math&quot;&gt;\(\mathbb{R}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt;.
This is precisely the choice I will make.
If this is so straightforward, why does this have its own separate section?&lt;&#x2F;p&gt;
&lt;p&gt;What is &lt;em&gt;less&lt;&#x2F;em&gt; straightforward is what the (closed) unit ball on
&lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt; looks like.
Or actually, it’s a little &lt;em&gt;too straightforward&lt;&#x2F;em&gt;.
This is clearly the intersection of the unit ball in &lt;span class=&quot;math&quot;&gt;\(\mathbb{R}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt; with &lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt;.
What is a little odd is that, for any &lt;span class=&quot;math&quot;&gt;\(p\in (1,\infty)\)&lt;&#x2F;span&gt;, it is &lt;em&gt;also&lt;&#x2F;em&gt; clear
that the only points in this ball are 0, along with the “standard basis vectors”
&lt;span class=&quot;math&quot;&gt;\(e_i\)&lt;&#x2F;span&gt;.
Quickly notice that:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;span class=&quot;math&quot;&gt;\(\ell_\infty\)&lt;&#x2F;span&gt; norm this isn’t the case (for example, &lt;span class=&quot;math&quot;&gt;\[(1,1,\dots,
   1)\]&lt;&#x2F;span&gt; is in the ball).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;This is an “easy” example of where the closed unit ball (things of norm
&lt;span class=&quot;math&quot;&gt;\(\leq 1\)&lt;&#x2F;span&gt;) is not the same as
the closure of the open unit ball (things with norm &lt;span class=&quot;math&quot;&gt;\(&lt;1\)&lt;&#x2F;span&gt;).
The open unit ball, in any &lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; norm, will just be &lt;span class=&quot;math&quot;&gt;\(\{0\}\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is all to say that for &lt;span class=&quot;math&quot;&gt;\(p\in(1,\infty)\)&lt;&#x2F;span&gt;, we have that:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
\{\vec x\in\mathbb{N}^{|\mathcal{X}|} \mid \lVert \vec x\rVert_p \leq 1\} &amp;= \{0\} \cup \{\vec x\in\mathbb{N}^{|\mathcal{X}|} \mid \lVert \vec x\rVert_p = 1\}\\
&amp;= \{0\}\cup \{e_i\mid i\in[|\mathcal{X}|]\}
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;The above implies that when we define the operator norm, the &lt;em&gt;particular&lt;&#x2F;em&gt; norm
we choose on the domain does not really matter (as long as it is not the
&lt;span class=&quot;math&quot;&gt;\(\ell_\infty\)&lt;&#x2F;span&gt; norm), as the elements of norm exactly 1 will always be
precisely the standard basis of the “overlying” vector space.
For this reason, we will write:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
\lVert M\rVert_p &amp;= \sup\{\lVert Mv\rVert_p \mid
v\in\mathbb{N}^{|\mathcal{X}|}, \lVert v\rVert_p = 1\}\\
&amp;= \sup\{\lVert Mv\rVert_p \mid v\in\{e_i\}, i\in[|\mathcal{X}|]\}
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;To denote the operator norm of a linear map &lt;span class=&quot;math&quot;&gt;\[M :
\mathbb{N}^{|\mathcal{X}|}\to\mathbb{R}^k\]&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We could be putting &lt;em&gt;any&lt;&#x2F;em&gt; &lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; norm on the domain while doing this, and
will end up with an equivalent definition.
We’ll next show how this leads to a quite natural interpretation of the
&lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; sensitivity as the maximum of the operator norm of &lt;span class=&quot;math&quot;&gt;\(\nabla f(\vec{x})\)&lt;&#x2F;span&gt; over &lt;span class=&quot;math&quot;&gt;\(\vec{x}\in\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-sensitivity-as-a-norm-bound-on-the-jacobian-matrix&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-sensitivity-as-a-norm-bound-on-the-jacobian-matrix&quot; aria-label=&quot;Anchor link for: the-sensitivity-as-a-norm-bound-on-the-jacobian-matrix&quot;&gt;🔗&lt;&#x2F;a&gt;The &lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; sensitivity as a norm bound on the Jacobian matrix&lt;&#x2F;h1&gt;
&lt;p&gt;Let &lt;span class=&quot;math&quot;&gt;\(f : \mathbb{N}^{|\mathcal{X}|} \to \mathbb{R}^k\)&lt;&#x2F;span&gt;.
We will next show the following:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;span class=&quot;math&quot;&gt;\(\Delta_{\vec x, p}(f) = \lVert \nabla f(\vec x)\rVert_p\)&lt;&#x2F;span&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;By taking maxes over &lt;span class=&quot;math&quot;&gt;\(\vec x\)&lt;&#x2F;span&gt;, this also implies our expression for the global
sensitivity.
The proof is rather straightforward.
By the characteriation of norm-1 elements of &lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt;, we
have that the operator norm will be:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\lVert \nabla f(\vec x)\rVert_p = \sup\{\lVert [\nabla f(\vec x)] e_i\rVert_p\mid i\in[|\mathcal{X}|]\}\]&lt;&#x2F;span&gt;
&lt;p&gt;This is clearly equivalent to &lt;span class=&quot;math&quot;&gt;\(\max_{e_i}\lVert \nabla [f(\vec x)] e_i\rVert_p\)&lt;&#x2F;span&gt;.
Note that &lt;span class=&quot;math&quot;&gt;\([\nabla f(\vec x)] e_i\)&lt;&#x2F;span&gt; is the &lt;span class=&quot;math&quot;&gt;\(i\)&lt;&#x2F;span&gt;th column of &lt;span class=&quot;math&quot;&gt;\(\nabla f(\vec x)\)&lt;&#x2F;span&gt;, which is precisely &lt;span class=&quot;math&quot;&gt;\((\partial&#x2F;\partial x_i)f(\vec x)\)&lt;&#x2F;span&gt;.
It follows that:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
\lVert \nabla f(\vec x)\rVert_p &amp;= \max_{i}\lVert (\partial&#x2F;\partial x_i)f(\vec x)\rVert_p
&amp;= \max_i \lVert f(\vec x + e_i) - f(\vec
x)\rVert_p
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;This is &lt;em&gt;nearly&lt;&#x2F;em&gt; the &lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; sensitivity, except we are maximizing over the
choice of &lt;span class=&quot;math&quot;&gt;\(\vec x + e_i\)&lt;&#x2F;span&gt;, rather than &lt;span class=&quot;math&quot;&gt;\(\vec y\)&lt;&#x2F;span&gt;
such that &lt;span class=&quot;math&quot;&gt;\(\lVert \vec x - \vec y\rVert_1 = 1\)&lt;&#x2F;span&gt;.
But these can readily be seen to be equivalent — as norm 1 elements in
&lt;span class=&quot;math&quot;&gt;\(\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt; are precisely standard basis vectors, we have
that &lt;span class=&quot;math&quot;&gt;\(\vec x, \vec y\)&lt;&#x2F;span&gt; that are adjacent are of the form &lt;span class=&quot;math&quot;&gt;\[\vec x = \vec y \pm
e_i\]&lt;&#x2F;span&gt; for some &lt;span class=&quot;math&quot;&gt;\(i\)&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It follows that:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\Delta_{\vec x, p}(f) = \lVert \nabla f(\vec x)\rVert_p\]&lt;&#x2F;span&gt;
&lt;p&gt;and:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\Delta_{p}(f) = \max_{\vec x\in\mathbb{N}^{|\mathcal{X}|}} \Delta_{\vec x,
p}(f) = \max_{\vec x\in\mathbb{N}^{|\mathcal{X}|}} \lVert \nabla f(\vec
x)\rVert_p\]&lt;&#x2F;span&gt;&lt;h1 id=&quot;an-explicit-calculation-in-this-framework&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-explicit-calculation-in-this-framework&quot; aria-label=&quot;Anchor link for: an-explicit-calculation-in-this-framework&quot;&gt;🔗&lt;&#x2F;a&gt;An explicit calculation in this framework&lt;&#x2F;h1&gt;
&lt;p&gt;To flesh this out a little more, I’ll next do a sensitivity calculation in the
above language.
I imagine this will look essentially like a sensitivity calculation in the
“standard” setting.&lt;&#x2F;p&gt;
&lt;p&gt;Recall that a database &lt;span class=&quot;math&quot;&gt;\(\vec{x}\in \mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt; is a count of
the multiplicities of various records &lt;span class=&quot;math&quot;&gt;\(r\in\mathcal{X}\)&lt;&#x2F;span&gt;.
What does a function of a databse look like then?
For example, if we have a database of names + ages, and want to compute the
average age, how do we do this in the “histogram” representation?&lt;&#x2F;p&gt;
&lt;p&gt;There are at least two ways to interpret this — as I do essentially no differential privacy, I have no clue which is correct.
But the first is much nicer to work with, so I will use it (after briefly
discussing both options).&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A database of ages can be identified with a vector &lt;span class=&quot;math&quot;&gt;\[\vec x = (x_0,x_1,\dots,
   x_{122})\]&lt;&#x2F;span&gt;, where &lt;span class=&quot;math&quot;&gt;\(122\)&lt;&#x2F;span&gt; is an absolute upper bound on the age of a
person (chosen as it is the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;List_of_the_verified_oldest_people&quot;&gt;oldest verified
age&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;A database of peoples ages can be identified with a vector of &lt;em&gt;tagged ages&lt;&#x2F;em&gt;
&lt;span class=&quot;math&quot;&gt;\((x_{n_0, 0}, x_{n_0, 1},\dots, x_{n_0, 122}, x_{n_1,0},\dots)\)&lt;&#x2F;span&gt;, where
&lt;span class=&quot;math&quot;&gt;\(n_i\)&lt;&#x2F;span&gt; are the collection of &lt;em&gt;admissible names&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;While the second definition defines the database itself better (and is a &lt;em&gt;much&lt;&#x2F;em&gt;
more useful definition if we want to query the average number of vowels in each
persons name, or something else), the first leads to significantly “smaller”
databases generically.
Maybe viewing databases as multi-sets instead of vectors is what makes the
second the more appropriate definition — I don’t know.
All I know is I want to compute the sensitivity of the average age of someone,
and the first definition is easier to work with, so I will look at it for this
example.&lt;&#x2F;p&gt;
&lt;p&gt;The average age under the first definition is:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\mathsf{mean}(\vec{x}) = \frac{\sum_{i = 0}^{122} i \vec{x}_i}{\sum_{i = 0}^{122} \vec{x}_i} \sim \frac{123\mathbb{E}[\vec x]}{\lVert \vec x\rVert_1}\]&lt;&#x2F;span&gt;
&lt;p&gt;Here, the expectation is taken with respect to a uniform distribution on
&lt;span class=&quot;math&quot;&gt;\(\{0,1,\dots, 122\}\)&lt;&#x2F;span&gt; (a set of size &lt;span class=&quot;math&quot;&gt;\(123\)&lt;&#x2F;span&gt;).
I use it mostly as compact notation for the sum.
This still has a fairly sensible discrete gradient:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}
(\partial&#x2F;\partial x_i)f(\vec x) &amp;= \mathsf{mean}(\vec x + e_i) - \mathsf{mean}(\vec x) \\
&amp;=\frac{123\mathbb{E}[\vec x + e_i]}{\lVert \vec x + e_i\rVert_1} -
\frac{123\mathbb{E}[\vec x]}{\lVert \vec x\rVert_1}\\
&amp;= 123\left(\frac{\mathbb{E}[\vec x] + i}{\lVert \vec x\rVert_1 + 1} -
\frac{\mathbb{E}[\vec x]}{\lVert \vec x\rVert_1}\right)\\
&amp;= 123\left(\frac{\lVert \vec x\rVert_1\mathbb{E}[\vec x] + i\lVert \vec x\rVert_1 -
(\lVert \vec x\rVert_1 + 1)\mathbb{E}[\vec x]}{\lVert \vec x\rVert_1(\lVert \vec
x\rVert_1 + 1)}\right)\\
&amp;= 123\frac{i - \mathbb{E}[\vec x]}{\lVert \vec x\rVert_1 + 1}\\
&amp;= 123\frac{\mathbb{E}[e_i - \vec x]}{\lVert x \rVert_1 + 1}
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;Note that we can convert from &lt;span class=&quot;math&quot;&gt;\[\lVert \vec x + e_i\rVert_1 \to \lVert \vec
x\rVert_1 + 1\]&lt;&#x2F;span&gt; as &lt;span class=&quot;math&quot;&gt;\(\vec x\in\mathbb{N}^{|\mathcal{X}|}\)&lt;&#x2F;span&gt; (so the absolute value
in the definition of the &lt;span class=&quot;math&quot;&gt;\(\ell_1\)&lt;&#x2F;span&gt; norm is immaterial), but we cannot
necessairly convert back from &lt;span class=&quot;math&quot;&gt;\(\lVert \vec x \rVert_1 + 1\)&lt;&#x2F;span&gt; to &lt;span class=&quot;math&quot;&gt;\(\lVert \vec x - e_i\rVert_1 = \lVert e_i - \vec x\rVert_1\)&lt;&#x2F;span&gt;.
We can instead write:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}(\partial&#x2F;\partial x_i)\mathsf{mean}(\vec x) &amp;= 123\frac{\mathbb{E}[e_i - \vec
x]}{\lVert \vec x\rVert_1 + 1}\\
&amp;= \frac{\lVert e_i - \vec x\rVert_1}{\lVert \vec x\rVert_1 + 1}\mathsf{mean}(e_i - \vec
x)\\
&amp;= -\frac{\lVert \vec x - e_i\rVert_1}{\lVert \vec x + e_i\rVert_1}\mathsf{mean}(\vec x - e_i)
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;If we then want to compute the noise sensitivity from this, we need to compute:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[\begin{aligned}\max_{\vec x \in\mathbb{N}^{|\mathcal{X}|}}\max_i \lVert (\partial&#x2F;\partial
x_i)f(\vec x)\rVert_p&amp;= \max_{\vec x\in \mathbb{N}^{|\mathcal{X}|}}\max_i
\frac{\lVert 123\mathbb{E}[\vec x - e_i]\rVert_p}{\lVert x + e_i\rVert_1}
\end{aligned}\]&lt;&#x2F;span&gt;
&lt;p&gt;The mean is over the set of ages &lt;span class=&quot;math&quot;&gt;\(\{0,1,\dots, 122\}\)&lt;&#x2F;span&gt;.
This mean can be maximized when &lt;span class=&quot;math&quot;&gt;\(i = 122\)&lt;&#x2F;span&gt; and &lt;span class=&quot;math&quot;&gt;\(\vec{x} = 0\)&lt;&#x2F;span&gt; (there are some
small issues with the resulting count being negative which I will ignore), where
the mean is &lt;span class=&quot;math&quot;&gt;\(1\)&lt;&#x2F;span&gt;, and thus the sensitivity is 123, as expected.
I get the impression this is essentially the same computation you would do in
the “standard” framework though.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;potential-extension&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#potential-extension&quot; aria-label=&quot;Anchor link for: potential-extension&quot;&gt;🔗&lt;&#x2F;a&gt;Potential extension&lt;&#x2F;h1&gt;
&lt;p&gt;One application of this representation is to the development of a &lt;em&gt;sensitivity calculus&lt;&#x2F;em&gt;.
Here, “calculus” means a framework for calculating things.
One reason differential calculus has been so successful is that derivatives
give a (mechanically) simple way to do computations with complex functions.
In particular, as derivatives behave well with respect to:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Sums&lt;&#x2F;li&gt;
&lt;li&gt;Products&lt;&#x2F;li&gt;
&lt;li&gt;Quotients&lt;&#x2F;li&gt;
&lt;li&gt;Composition&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;One can usually compute the derivative of an arbitrary function in terms of the
above “rules”, along with the knowledge of some “simple” derivatives.
By framing sensitivity in terms of derivatives, there is a hope that one could
derive such a set of rules for &lt;em&gt;discrete derivatives&lt;&#x2F;em&gt;.
This could “automate” the computation of &lt;span class=&quot;math&quot;&gt;\(\nabla f\)&lt;&#x2F;span&gt; in sensitivity analysis,
by giving a way to write &lt;span class=&quot;math&quot;&gt;\(\nabla f\)&lt;&#x2F;span&gt; as an expression in (known) “simple”
derivatives.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, sensitivity analysis still requires computing the operator norm of
this expression.
The operator norm is sub-additive and sub-multiplicative, which one can leverage
to get an &lt;em&gt;upper bound&lt;&#x2F;em&gt; on the sensitivity in terms of the sensitivities of the
aforementioned “simple” derivatives.
This upper bound is potentially loose though, which would hurt the applicability
of this method.
If the upper bound is tolerable, this should be relatively easy to program.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, the above reasoning seems to be erronous.
I’ve written up some details &lt;a href=&quot;https:&#x2F;&#x2F;mark.schultz-wu.com&#x2F;blog&#x2F;sensitivity-calculus&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;, but “short story” is that the chain rule one can derive involves terms of the form:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[f(g(n) + g&#x27;(n))\]&lt;&#x2F;span&gt;
&lt;p&gt;Its unclear how to upper bound the &lt;span class=&quot;math&quot;&gt;\(\ell_p\)&lt;&#x2F;span&gt; norm of this, which would be
required to derive even (loose) upper bounds on the operator norm.
Note that for “continuous” calculus the chain rule has terms of the form:&lt;&#x2F;p&gt;
&lt;span class=&quot;math&quot;&gt;\[f&#x27;(g(n))g&#x27;(n)\]&lt;&#x2F;span&gt;
&lt;p&gt;So for a sub-multiplicative norm one could hope to get some upper bounds.
Feel free to read the writeup for more details, but as it ends in “failure” it
is likely not very interesting.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
