Add a hexary version of injectivitylemma.py.

This is not used by the version of Halo in the paper.

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2020-03-22 13:36:10 +00:00
parent 15f7108bbc
commit 035fd2b2ce
1 changed files with 65 additions and 0 deletions

65
injectivitylemma6.py Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# This checks the cases k = 1 and k = 2 needed to complete the proof of a
# hexary version of the Halo injectivity lemma.
#
# Inputs: r ∈ {0, 1}^λ, s ∈ [0, 2)^λ, P ∈ E \ {O}
#
# (a : Fq, b : Fq, c : Fq) := (2, 2, 2)
#
# for i from λ - 1 down to 0:
# let (d_i, e_i, f_i) = { (0, 0, 2r_i - 1), if s_i = 0
# { (0, 2r_i - 1, 0), if s_i = 1
# { (2r_i - 1, 0, 0), if s_i = 2
# (a, b, c) := (2a + d_i, 2b + e_i, 2c + f_i)
# Output [a.ζ^2 + b.ζ + c] P.
#
# For each i ∈ [0, λ), the mapping (r_i, s_i) ↦ (d_i, e_i, f_i) is injective,
# and exactly one of d_i, e_i, f_i ∈ {-1, 0, +1} is 0.
# Let M_k = {(d, e, f : {-1, 0, +1}^k) for all i, exactly one of d_i, e_i, f_i is 0}.
# So (r, s) ↦ (d, e, f) : M_λ is also injective.
#
# Lemma: For k ≥ 0, (d, e, f) ∈ M_k ↦ (∑_{j ∈ [0, k-1)} d_j 2^j,
# ∑_{j ∈ [0, k-1)} e_j 2^j,
# ∑_{j ∈ [0, k-1)} f_j 2^j) is injective.
#
# Proof (sketch). If (d, e, f) and (d', e', f') coincide on a prefix of length m,
# then the statement reduces to a smaller instance of the lemma with that prefix
# deleted and k reduced by m. So we need only consider the case
# (d_0, e_0, f_0) ≠ (d'_0, e'_0, f'_0) and show that the resulting sums always
# differ. In fact they always differ modulo 4:
#
# (d_0, e_0, f_0) ≠ (d'_0, e'_0, f'_0) ⇒ (∑_{j ∈ [0, k-1)} d_j 2^j, ∑_{j ∈ [0, k-1)} e_j 2^j, ∑_{j ∈ [0, k-1)} f_j 2^j)
# ≠ (∑_{j ∈ [0, k-1)} d'_j 2^j, ∑_{j ∈ [0, k-1)} e'_j 2^j, ∑_{j ∈ [0, k-1)} f'_j 2^j)
#
# Therefore, it is sufficient to verify this property exhaustively for k = 1 and
# k = 2, since terms with j ≥ 2 do not affect the sums modulo 4.
from itertools import product
from collections import namedtuple
def_triple = namedtuple('def_triple', ['d', 'e', 'f'])
def d_e_f():
yield def_triple(-1, 0, 0)
yield def_triple( 1, 0, 0)
yield def_triple( 0, -1, 0)
yield def_triple( 0, 1, 0)
yield def_triple( 0, 0, 1)
yield def_triple( 0, 0, -1)
def sums_mod4(def_):
return ((2**(k+1) + sum([def_[j].d * (2**j) for j in range(k)])) % 4,
(2**(k+1) + sum([def_[j].e * (2**j) for j in range(k)])) % 4,
(2**(k+1) + sum([def_[j].f * (2**j) for j in range(k)])) % 4)
for k in (1, 2):
M_k = [list(s) for s in product(d_e_f(), repeat=k)]
assert(len(M_k) == 6**k)
for (def_, def_dash) in product(M_k, repeat=2):
if def_[0] != def_dash[0]:
assert(sums_mod4(def_) != sums_mod4(def_dash))
print("QED")