mirror of https://github.com/zcash/pasta.git
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:
parent
15f7108bbc
commit
035fd2b2ce
|
@ -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")
|
Loading…
Reference in New Issue