|
1 |
| -from seal import EncryptionParameters, ChooserEvaluator |
| 1 | +from seal import ChooserEvaluator, \ |
| 2 | + EncryptionParameters, \ |
| 3 | + IntegerEncoder, \ |
| 4 | + MemoryPoolHandle |
2 | 5 |
|
3 | 6 | def example_basics():
|
4 | 7 | """
|
@@ -81,6 +84,69 @@ def example_basics():
|
81 | 84 | # important pre-computation.
|
82 | 85 | parms.validate()
|
83 | 86 |
|
| 87 | + # Plaintext elements in the FV scheme are polynomials (represented by the |
| 88 | + # Plaintext class) with coefficients integers modulo plain_modulus. To |
| 89 | + # encrypt for example integers instead, one must use an "encoding scheme", |
| 90 | + # i.e. a specific way of representing integers as such polynomials. SEAL |
| 91 | + # comes with a few basic encoders: |
| 92 | + # |
| 93 | + # IntegerEncoder: |
| 94 | + # Given an integer base b, encodes integers as plaintext polynomials in the |
| 95 | + # following way. First, a base-b expansion of the integer is computed. This |
| 96 | + # expansion uses a "balanced" set of representatives of integers modulo b as |
| 97 | + # the coefficients. Namely, when b is off the coefficients are integers |
| 98 | + # between -(b-1)/2 and (b-1)/2. When b is even, the integers are between |
| 99 | + # -b/2 and (b-1)/2, except when b is two and the usual binary expansion is |
| 100 | + # used (coefficients 0 and 1). Decoding amounts to evaluating the polynomial |
| 101 | + # at x=b. For example, if b=2, the integer 26 = 2^4 + 2^3 + 2^1 is encoded |
| 102 | + # as the polynomial 1x^4 + 1x^3 + 1x^1. When b=3, 26 = 3^3 - 3^0 is encoded |
| 103 | + # as the polynomial 1x^3 - 1. In reality, coefficients of polynomials are |
| 104 | + # always unsigned integers, and in this case are stored as their smallest |
| 105 | + # non-negative representatives modulo plain_modulus. To create an integer |
| 106 | + # encoder with a base b, use IntegerEncoder(plain_modulus, b). If no b is |
| 107 | + # given to the constructor, the default value of b=2 is used. |
| 108 | + # |
| 109 | + # FractionalEncoder: |
| 110 | + # Encodes fixed-precision rational numbers as follows. First expand the |
| 111 | + # number in a given base b, possibly truncating an infinite fractional part |
| 112 | + # to finite precision, e.g. 26.75 = 2^4 + 2^3 + 2^1 + 2^(-1) + 2^(-2) when |
| 113 | + # =2. For the sake of the example, suppose poly_modulus is 1x^1024 + 1. Next |
| 114 | + # represent the integer part of the number in the same way as in |
| 115 | + # IntegerEncoder (with b=2 here). Finally, represent the fractional part in |
| 116 | + # the leading coefficients of the polynomial, but when doing so invert the |
| 117 | + # signs of the coefficients. So in this example we would represent 26.75 as |
| 118 | + # the polynomial -1x^1023 - 1x^1022 + 1x^4 + 1x^3 + 1x^1. The negative |
| 119 | + # coefficients of the polynomial will again be represented as their |
| 120 | + # negatives modulo plain_modulus. |
| 121 | + # |
| 122 | + # PolyCRTBuilder: |
| 123 | + # If poly_modulus is 1x^N + 1, PolyCRTBuilder allows "batching" of N |
| 124 | + # plaintext integers modulo plain_modulus into one plaintext polynomial, |
| 125 | + # where homomorphic operations can be carried out very efficiently in a SIMD |
| 126 | + # manner by operating on such a "composed" plaintext or ciphertext |
| 127 | + # polynomials. For full details on this very powerful technique we |
| 128 | + # recommend https://eprint.iacr.org/2012/565.pdf and |
| 129 | + # https://eprint.iacr.org/2011/133. |
| 130 | + # |
| 131 | + # A crucial fact to understand is that when homomorphic operations are |
| 132 | + # performed on ciphertexts, they will carry over to the underlying |
| 133 | + # plaintexts, and as a result of additions and multiplications the |
| 134 | + # coefficients in the plaintext polynomials will increase from what they |
| 135 | + # originally were in freshly encoded polynomials. This becomes a problem |
| 136 | + # when the coefficients reach the size of plain_modulus, in which case they |
| 137 | + # will get automatically reduced modulo plain_modulus, and might render the |
| 138 | + # underlying plaintext polynomial impossible to be correctly decoded back |
| 139 | + # into an integer or rational number. Therefore, it is typically crucial to |
| 140 | + # have a good sense of how large the coefficients will grow in the |
| 141 | + # underlying plaintext polynomials when homomorphic computations are carried |
| 142 | + # out on the ciphertexts, and make sure that plain_modulus is chosen to be |
| 143 | + # at least as large as this number. |
| 144 | + |
| 145 | + # Here we choose to create an IntegerEncoder with base b=2. |
| 146 | + encoder = IntegerEncoder(parms.plain_modulus(), |
| 147 | + 2, |
| 148 | + MemoryPoolHandle.acquire_global()) |
| 149 | + |
84 | 150 | def main():
|
85 | 151 | # Example: Basics
|
86 | 152 | example_basics()
|
|
0 commit comments