Commit ad7e77d2 authored by Emmanuel Thomé's avatar Emmanuel Thomé
Browse files

new files

parent a7926c46
Using the search program
========================
`search.sage` is a front-end to the code in `CocksPinchVariant.py`. This
script may be used as a helper to run it conveniently in a distributed
fashion.
Example: search for baby examples
---------------------------------
This does a search for baby examples.
sage search.sage -k 8 -D 1 --T_choice "2-naf<=7" --hty_choice "2-naf<=7" --lambdap 160 --lambdar 70 --save --check_small_subgroup_secure 15 --spawn 4 0 4
This should provide, as output, the file
`curves-data/curves-k8-p160-T:2-naf<=7-hty:2-naf<=7-2-4.sage`, with in
particular the following contents:
C=CocksPinchVariantResult(8,4,0x27d80,7,ht=-0x451,hy=-0x481)
(it takes about 15 minutes on a Intel Core i5-6500 CPU at 3.20GHz without any
other running process).
One day later, these other curves were found:
C=CocksPinchVariantResult(8,4,0x29072,7,ht=0x9bf,hy=-0x10e)
C=CocksPinchVariantResult(8,4,0x29f24,7,ht=-0x289,hy=0x53f)
C=CocksPinchVariantResult(8,4,0x2a1c8,3,ht=0x53f,hy=-0x437)
C=CocksPinchVariantResult(8,4,0x27d80,7,ht=-0x451,hy=-0x481)
C=CocksPinchVariantResult(8,4,0x2617e,5,ht=-0xd93,hy=0x305)
C=CocksPinchVariantResult(8,4,0x28f86,3,ht=0x8cf,hy=0x2e0)
The different parameters above are explained as follows.
* `-k 8` : we search for curves with embedding degree `k=8`
* `-D 1` : we impose CM discriminant `-(4*D) = -4`
* `--T_choice "2-naf<=7"` : and we require that `T` be of 2-naf
weight as most 7.
* `--hty_choice "2-naf<=7"` : we impose the same restriction on
the `2-naf weight` of the `ht` and `hy` cofactors.
* `--lambdap 160` : we search for 160-bit primes `p`
* `--lambdar 70` : we search for 70-bit subgroup order `r`
* `--save` : save our findings in the curves-data/
* `--check_small_subgroup_secure 15` : look for curves that fulfill the
security criteria 1 + 2 + 4 + 8 = 15.
* 1 means that we want E to be small-subgroup-secure (beyond very small
subgroups, no other subgroups that are smaller than the interesting
subgroup order `r`
* 2 is twist-small-subgroup-security: same criterion on the quadratic
twist of E
* 4 is G2-small-subgroup-security: same criterion on the curve E2 in which
the subgroup G2 is defined (a priori E2 is defined over an extension,
but we use the fact that thanks to twists, it is sometimes possible
to arrange for E2 to be defined over an extension smaller than
GF(p^k)).
* 8 is twist-G2-small-subgroup-security: same for the quadratic twist
of E2.
* `--spawn 4` and `0 4`: these two are related. The last `4` indicates
that the search space (on T) is to be divided in 4 roughly equal-size
parts. The `0` indicates that the first one that we intend to handle is the
one with number 0, while `--spawn 4` indicates that we wish to perform
4 searches in parallel, so that we'll actually do parts number 0, 1, 2,
and 3 in parallel.
Here is another example that cheats a bit, because we've arranged for the
search to complete quickly, knowing that a previous search was
successful. It still takes some minutes, though
sage search.sage -k 6 -D 3 --T_choice 'hamming<=4' --hty_choice '2-naf<=4' --lambdap 160 --lambdar 70 --save --check_small_subgroup_secure 15 --spawn 1 --restrict_i '[1]' 57468 65536
For reference, the command above should write the following data to the
file `curves-data/curves-k6-p160-T\:hamming\<\=4-hty\:2-naf\<\=4-57468-65536.sage`:
C=CocksPinchVariantResult(6,3,0x600081000,1,ht=-0x191,hy=-0x7e2)
Using the search within `sage` so as to examine things more closely
===================================================================
When running `search.sage`, the program gives you the equivalent `sage`
code that can be used to run the same search from within `sage` itself
(without the parallelism of the search). For example:
# The search below can be obtained (for child 0) from inside sage as follows:
attach("CocksPinchVariant.py")
CocksPinchVariant(
allowed_cofactor=420,
required_cofactor=4,
verbose=False,
restrict_i=[1],
k=5,
hty_choice='ht:max=4',
Drange=[10000000147],
allowed_automatic_cofactor=4,
check_small_subgroup_secure=7,
T_choice='hamming=4',
lambdap=663,
lambdar=256,
parallel=('T', 3831, 68719476736))
Based on this, you may edit the search parameters (e.g. the `restrict_i`
parameter), or loop on many candidate discriminants to see if some give
wider search spaces than others. A [list of the accepted
parameters](#complete-list-of-parameters) is provided at the end of this document.
The `CocksPinchVariantSearch` object is also useful, as you may first
initiate a search by creating such an object (exact same parameters as
the `CocksPinchVariant` function above), and later run the search by
calling the `.run()` method. Here is an example:
attach("CocksPinchVariant.py")
Ds=[D for D in xsrange(10^10,10^10+10^6) if D.is_prime(proof=False)]
iDs = iter(Ds)
while True:
D=next(iDs)
S=CocksPinchVariantSearch(
allowed_cofactor=420,
allowed_automatic_cofactor=4,
required_cofactor=4,
restrict_i=None,
k=7,
hty_choice='',
Drange=[D],
check_small_subgroup_secure=3,
T_choice='hamming<=4',
lambdap=512,
lambdar=256)
S.run()
Naturally these are just examples, and you probably want to adapt and
tweak to your needs.
The `CocksPinchVariantResult` object
====================================
Results are stored in a Python object called `CocksPinchVariantResult`.
Whenever you look into an output file in the `curves-data` directory, it
starts with a line such as:
C=CocksPinchVariantResult(5,10000000147,0xe000000000008000,1,ht=3,hy=-0x11e36418c7c8b454,max_B1=600)
This contains exactly the data that is necessary to identify the curve
parameters uniquely. Provided the utility software has been attached into
`sage`, e.g. with the command `attach("CocksPinchVariant.py")`, you may
then type the command above, and obtain data on the curve by `print`-ing
the object, as follows
sage: C=CocksPinchVariantResult(5,10000000147,0xe000000000008000,1,ht=3,hy=-0x11e36418c7c8b454,max_B1=600)
sage: print C
# Cocks-Pinch pairing-friendly curve of embedding degree 5:
C=CocksPinchVariantResult(5,10000000147,0xe000000000008000,1,ht=3,hy=-0x11e36418c7c8b454,max_B1=600)
fD = 10000000147
k = 5
p = 0x40000138cd26ab94b86e1b2f7482785fa18f877591d2a4476b4760217f860bfe8674e2a4610d669328bda13044c030e8cc836a5b363f2d4c8abcab71b12091356bb4695c5626bc319d38bf65768c5695f9ad97 # 663 bits
rho = 2.59
T = 0xe000000000008000
r = cyclotomic_polynomial(5)(T)
r = 0x9610000000015700ab80000126012600c4007000a800e000f000200040008001 # 256 bits
i = 1
t0 = (T**i+1) % r
t0 = 0xe000000000008001
ht = 3 # 2 bits, HW=2, HW_{2-NAF}=2
t = t0 + ht * r
t = 0x1c23000000004050202800003720372024c015001f802a003b0006000c0020004
y0 = ZZ((t0-2)/sqrt(Integers(r)(-fD))) - r
y0 = -0x92b4887559e58c5ea3d4f5b681f8d009be6f610cc192e173dc35b3d1c90beae
hy = -0x8f1b20c63e45a2a # 60 bits, HW=27, HW_{2-NAF}=21
y = y0 + 2 * hy * r
y = -0xa7c5adcc69c2e2c3d8451c3ed9d1313d854645adfb5cfd006424b4b362ad2170a2fd04f3e837302
is_small_subgroup_secure = True
is_twist_small_subgroup_secure = True
is_G2_small_subgroup_secure = True
is_twist_G2_small_subgroup_secure = True
is_twist_small_subgroup_secure_all = True
card_E = 19136268507011813102345745679502968108741656052980768772125358458053107229388560784972377216338036093499504796562349965064176841727668172560690929293057463574017700843677002476871882219887122462518676
card_Et = 19136268507011813102345745679502968108741656052980768772125358458053107229388560784972377216338036093499504796562349965064584092908711334342226287125385577193151239257837840457738288364655661268315548
card_E2 = 2566175062983801476251286256606640698771865196388902453689880575318016431991478746936218484367107274439875027091055623885341796634010141373837958152220632927260407915989199779489466783111978431497688590318530350180781766294609670902413354058020341316625927935970058308217962343319043978460005258620389909525508389084168032013999876737612135059641823858258071848378579069879039033326704474913030394343656643332906144776155023356748829630255349715371258056929210442481691877381679922714002610545570945407244343330808434518370943792146485381308013746726551454341902662395337824363444781080760852009660614468829609571835408995635306250320328692189174982461714135718135270824555466856963140844390058385161613263099506744275768324044164515627020707932255820492436278371804937853316577801628205565929045620052815106039336532731141083897446983811172314159397280143949499479956458444723193365460945903488435207152461621716737367365728702971861482873644538870659244869130515550016826287851231155443092968676
card_E2t = 2566175062983801476251286256606640698771865196388902453689880575318016431991478746936218484367107274439875027091055623885341796634010141373837958152220632927260407915989199779489466783111978431497688590318530350180781766294609670902413354058020341316625927935970058308217962343319043978460005258620389909525508389084168032013999876737612135059641823858258071848378579069879039033326704474913030394343656643332906144776155023356748829630255349715371258056929210442481691877381679922714002610545570945407244343330808434519116614132360860408553500275991428066840734695138109614137010620956041486744604452018956179139318486702760635400119295957192341543129435254519305881129790195980204534246049565558694548469651253076488360782578649541871730694598751726993461111829692085095237760274378047521870254313681537724075914775199986132754888903012341276427960725663500029191461793444853546802108775490524715516051659812397640686218204043585900933790628050730110436527966074227200480230745542670239799164428
# card_E = 2^2 * p405 * r
# card_Et = 2^2 * p661
# card_E2 = p2393 * (2^2 * p405 * r) * r
# card_E2t = p2649 * (2^2 * p661)
It is possible to access specific data attached to the curve parameters
by querying some of the data members of `C`, e.g. in:
sage: C.r
67875196840526963589226305388018936522256402360139663477728977161068302336001
Recovering the curve equation
=============================
Note that the `CocksPinchVariantResult` object above only gives the curve
parameters in terms of complex multiplication (CM) theory. A Weil number
in an appropriate quadratic imaginary number field is given via the
`C.fD` (fundamental discriminant), `C.t` (trace) and `C.y` (conductor)
data fields. The following code recovers it more explicitly:
sage: ZP.<x>=PolynomialRing(Integers())
sage: K.<z>=NumberField(x^2+C.fD)
sage: pi=1/2*(C.t + z * C.y)
sage: pi.norm() == C.p
True
sage: pi.trace() == C.t
True
If you wish to recover the j-invariant of a curve within the isogeny
class that corresponds to this Weil number, you must use some complex
multiplication software. You have two options.
* Use `sage` itself. It is possible with `sage` to compute Hilbert class
polynomials (over Z) attached to a given discriminant, and then reduce
them modulo p to find roots (j-invariants). This is done as follows.
sage: H=hilbert_class_polynomial(-C.fD)
sage: rH=H.change_ring(GF(C.p)).roots()
sage: j=rH[0][0]
sage: E=EllipticCurve_from_j(rH[0][0])
sage: (C.p+1-C.t)*E.random_point() == 0
True
sage: (C.p+1+C.t)*E.random_point() == 0
False
(recall that a priori, [`EllipticCurve_from_j`](http://doc.sagemath.org/html/en/reference/curves/sage/schemes/elliptic_curves/constructor.html#sage.schemes.elliptic_curves.constructor.EllipticCurve_from_j) only gives you the curve
up to a twist).
It is also possible to look for an invariant that gives a curve whose
equation can be put in the form `y^2=x^3-3*x+b`, as follows:
sage: for i,jm in enumerate(rH):
j,m=jm
E=EllipticCurve_from_j(j)
u4=E.a4()/-3
if not u4.is_square():
continue
u2=u4.sqrt()
if not u2.is_square():
continue
u=u2.sqrt()
print "j[%d]: ok" % i
E = E.change_weierstrass_model(u)
break
Alas, the approach above only works for `D` quite small. The second
option is more powerful.
* Use the `classpol` package from Andrew Sutherland. (see his
[web page](https://math.mit.edu/~drew/)). A specificity of this
software is that it computes the class polynomial modulo p directly.
To make this program easily usable, we provide an example installation
script that compiles and installs this software in `/tmp`. It can be
found in `cm/install-cm.sh`. All you need to provide is the (opposite
of the) discriminant and the prime number p. (it must be done outside
`sage`). For the example above (see
[there](#the-cockspinchvariantresult-object), we did as follows to
compute the class polynomial modulo p. This computation took less
than two hours on one core.
localhost ~ $ HOME=/tmp/cm-data/ /tmp/cm/bin/classpoly 10000000147 0 19136268507011813102345745679502968108741656052980768772125358458053107229388560784972377216338036093499504796562349965064380467318189753451458608209221520383584470050757421467305085292271391865417111 /tmp/H5.txt
The next step is to edit the resulting file `/tmp/H5.txt` to transform
it into valid sage code (e.g. `/tmp/H5.sage, with all coefficients of
the polynomial in one single line), and then load it into sage. Note
that root finding takes about 20 minutes to complete.
sage: load("/tmp/H5.sage")
sage: %time rH=H.change_ring(GF(C.p)).roots()
CPU times: user 16min 24s, sys: 141 ms, total: 16min 24s
Wall time: 16min 24s
sage: E=EllipticCurve_from_j(rH[0][0])
sage: (C.p+1-C.t)*E.random_point() == 0
True
sage: (C.p+1+C.t)*E.random_point() == 0
False
Running on a cluster
====================
To search for curve parameters on a cluster, the `search.sage` script
provides some bare bones, but keeping track of which parts of the
computations were done, and which failed for some reason, quickly becomes
cumbersome.
We do retain however the fact that `search.sage` identifies the search
space as a set of consecutively numbered tasks that must be processed (in
any order). To deal with this sort of situation, we provide simple and
stupid [job picker](https://gitlab.inria.fr/thome/jobpick) software.
The following set of commands installs the code base here on a computer
cluster, installs the [jobpick](https://gitlab.inria.fr/thome/jobpick)
script, and starts a search for curves with embedding degree k=5. Your
mileage may vary. See the [jobpick
documentation](https://gitlab.inria.fr/thome/jobpick/blob/master/README.md)
for information on the different parameters.
my_machine ~ $ rsync -a pairings/code/ nancy.g5k:pairings-code/
fnancy ~ $ rm -rf ~/jobpick
fnancy ~ $ (cd ~ ; git clone https://gitlab.inria.fr/thome/jobpick)
fnancy ~ $ mkdir -p ~/pairings-code/k5/{todo,done,doing,failed}
fnancy ~ $ mkdir -p ~/pairings-code/k5/curves-data/
fnancy ~ $ for i in {0..1599} ; do touch ~/pairings-code/k5/todo/$((16*i)) ; done
fnancy ~ $ cd ~/pairings-code/k5 ; for i in {1..10} ; do oarsub -n k5 -q production -l "{cluster='grcinq'}/nodes=8,walltime=1" -l "{cluster='grvingt'}/nodes=8,walltime=1" "/home/ethome/jobpick/pick.sh --job-queue-path /home/ethome/pairings-code/k5 --job-weight 16 /grvingt/software/SageMath/sage ../search.sage -k 5 -D 10000000147 --hty_choice ht:max=4 --restrict_i '[1]' --save --T_choice hamming=4 --lambdap 663 --lambdar 256 --check_small_subgroup_secure 7 --required_cofactor 4 --spawn 16 --parallel-mode hy --ntasks 68719476736 --task" ; done
Note that the job duration above, set to one hour (`walltime=1`), was
verified beforehand to be a comfortable upper bound on the running time
for the subtasks we're dealing with.
Interruptible stateful searches
===============================
If the `statefile` (or `--statefile`) option is used, then the search
saves its current state to a file on a regular basis. When the search
resumes, it continues where it left off.
This is mostly useful for small experiments. Larger experiments that get
run on a cluster could conceivable benefit from this, but the potential
benefit seems to be outweighed by the danger of having a great number of
writes to the state file.
Complete list of parameters
===========================
Unless otherwise specified, all parameters are (or should be) recognized
both by the `CocksPinchVariant` function in `sage` (as named arguments),
or by the `search.sage` script, prefixed by one or two dashes.
* `k`: embedding degree
* `l`: consider `cyclotomic_polynomial(k*l)` instead of
`cyclotomic_polynomial(k)`. Mostly unused and untested.
* `Drange`: range of discriminants to test. For `search.sage`, the
shorthand `--D` also works.
* `allowed_cofactor`: product of small subgroup orders that we tolerate
in the produced curves. Those are taken out before any sort of security
check is done.
* `required_cofactor`: force E to have at least this number dividing its
cardinal. This may sometimes reduce the search in case congruence
conditions make this impossible.
* `allowed_automatic_cofactor`: do not mind if we find out that some
factors automatically divide some of the curves we're considering. E.g.
if we know that 11 always divides `#E2` or `#E2t`, a priori we'll move
on to the next search (next i, next D, next T), unless 11 divides
`allowed_automatic_cofactor`.
* `check_small_subgroup_secure`: This is a bitmap, more precisely a sum
of the following bits:
* 1 means that we want E to be small-subgroup-secure (beyond very small
subgroups, no other subgroups that are smaller than the interesting
subgroup order `r`
* 2 is twist-small-subgroup-security: same criterion on the quadratic
twist of E
* 4 is G2-small-subgroup-security: same criterion on the curve E2 in which
the subgroup G2 is defined (a priori E2 is defined over an extension,
but we use the fact that thanks to twists, it is sometimes possible
to arrange for E2 to be defined over an extension smaller than
GF(p^k)).
* 8 is twist-G2-small-subgroup-security: same for the quadratic twist
of E2.
* `verbose`: mostly unused, at least nothing really consistent.
* `restrict_i`: look only at these values for the computation `t=T^i+1`.
* `T_choice`: strategy for picking `T`. The syntax for the strategy
string is in the function `range_with_strategy` in
`CocksPinchVariant.py`. In a nut-shell, strings such as `hamming=4`,
`2-naf<=5`, `random`, `2-naf=2,max=1024,cap=32` are all valid.
* `hty_choice`: strategy for picking cofactors `ht` and `hy`. Same syntax
as above, plus some additional modifiers of the form `ht:foo` or
`hy:foo` that make the strategy modifier (e.g., something like `max=4`)
only applicable to `ht` (resp. `hy`(.
* `lambdap`: search for `p` of exactly this bit length.
* `lambdar`: search for `r` of exactly this bit length.
* `--spawn` (only for the command-line of `search.sage`): start this
number of searches, with consecutive indices.
* `--parallel-mode` (only for the command-line of `search.sage`):
parallelize the search on the given variable. Currently only `T`, `ht`,
and `hy` are supported.
* `--ntasks` (only for the command-line of `search.sage`):
divide the search in `n` parts.
* `--task` (only for the command-line of `search.sage`): process the
part with this index, according to the subdivision given by
`--ntasks`. If we have `--spawn k`, process `k` parts in parallel
with consecutive indices, starting from the index `i0` given by
`--task` (i.e., we process `i0` to `i0+k-1`)
* `<i0> <n>` (two integers at the end of the command line, only for the command-line of `search.sage`): equivalent to `--task <i0>` and `--ntasks <n>`.
* `parallel` (only for the `sage` function`): This is a triple with:
* a string that gives the same thing as in `--parallel-mode`
* an integer as in `--task`
* an integer as in `--ntasks`
* `--save` (only for the command-line of `search.sage`): save the curves
found to files in `curves-data/` (this directory must exist
beforehand).
* `--statefile` (only for the command-line of `search.sage`): use a state
file for each search (see "Interruptible stateful searches")
* `output_file` (only for the `sage` function): use precisely this file
to save the curves found (the command-line `--save` option uses this).
* `statefile` (only for the `sage` function): use precisely this state
file for this search (see "Interruptible stateful searches")
(the command-line `--statefile` option uses this.
* `seed`: use this seed for random picks. Unused for deterministic
searches
Documentation on specific searches
==================================
Search for curves of embedding degree 5
---------------------------------------
For k=5, we are free to choose ht and hy with all bits set. This is
done by passing `--hty_choice ''` (or no `--hty_choice` at all).
We decide to have unrestricted `i`, unrestricted `t`, unrestricted `D` in
our search.
We choose `T` of hamming weight equal to 4 so that we have enough choices
to have `phi_5(T)` prime (we also want `legendre(-D,r) == 1`). (in fact,
only two `T`'s in there yield prime `r`, and only one is such that
`legendre(-D,r) == 1`)
We decide to force `4 | #E` so that Edwards form can be used.
We want to make sure that there is no prime that is an automatic
divisor of `#E * #E2 * #E2 * #E2t`.
This forces us to do some math and exclude some choices.
For prime `D` above `10^10`, the first working discriminant is `fD = 10000000147`,
and `i=1` and `ht = -3` (`ht` is ordered by increasing absolute value,
then positive numbers, then negative numbers). In order to force
exploration of this setting only, we use the following arguments:
`-D 10000000147 --hty_choice ht:max=4 --restrict_i '[1]'`
To do a fraction `2^-32 of the search space`:
sage search.sage -k 5 -D 10000000147 --hty_choice ht:max=4 --restrict_i '[1]' --save --T_choice hamming=4 --lambdap 663 --lambdar 256 --check_small_subgroup_secure 3 --required_cofactor 4 --spawn 4 --parallel-mode hy 0 4294967296
On houblon.loria.fr, a fraction 4/2^39 of the search space is processed
in 128 seconds WCT.
On grvingt we do a fraction 64/2^39 in time 266 seconds WCT (2.1 GHz
per core, 64 hyperthreads).
The following curve was found by job `24165/2^36`.
# C=CocksPinchVariantResult(5,10000000147,0xe000000000008000,1,ht=3,hy=-0x11e36418c7c8b454,max_B1=600)
# card_E = 2^2 * p405 * r
# card_Et = 2^2 * p661
# card_E2 = p2393 * (2^2 * p405 * r) * r
# card_E2t = p2649 * (2^2 * p661)
Search for curves of embedding degree 6
---------------------------------------
For k=6, we fix D=`3` in order to get efficient formulas from sextic twist.
We are free to choose ht and hy with low hamming weight. This is
done by passing `--hty_choice '2-naf<=5'.
We choose `T` of hamming weight less or equal to 5 so that we have enough
choices to have `phi_6(T)` prime.
We decide to force `4 | #E` so that Edwards form can be used.
We decompose the search in 8 fractions of the search space, done in two
computers:
sage search.sage -k 6 -D 3 --required_cofactor 4 --allowed_size_cofactor 10 --T_choice "2-naf<=5" --hty_choice "2-naf<=5" --lambdap 672 --lambdar 256 --save --check_small_subgroup_secure 15 --spawn 4 0 8
sage search.sage -k 6 -D 3 --required_cofactor 4 --allowed_size_cofactor 10 --T_choice "2-naf<=5" --hty_choice "2-naf<=5" --lambdap 672 --lambdar 256 --save --check_small_subgroup_secure 15 --spawn 4 4 8
The following curve was found:
# C=CocksPinchVariantResult(6,3,0xfffffffffffffff00000000000000000,1,ht=0x43fff,hy=-0xffffffffff800007fffe,allowed_size_cofactor=10,max_B1=600)
# card_E = 2^2 * 3 * p412 * r
# card_Et = 2^2 * 13 * p666
# card_E2 = p416 * r
# card_E2t = 3 * p670
Search for curves of embedding degree 6 (second take with small h_t)
--------------------------------------------------------------------
For k=6, allowing arbitrary cofactors in `h_t` and `h_y` leads to an
expensive second part of the final exponentiation. Therefore we restrict
to `|ht|<=4`.
search.sage -k 6 --D 3 --hty_choice '2-naf<=7,ht:max=4' --save --T_choice '2-naf<=5' --lambdap 672 --lambdar 256 --check_small_subgroup_secure 7 --required_cofactor 4 --allowed_automatic_cofactor 720 --allowed_cofactor 420 --allowed_size_cofactor 10
and we obtain four curves for which G2 is also twist-secure :
C=CocksPinchVariantResult(6,3,0xff800000000000200000000000000000,1,ht=-1,hy=0xffffff823ffffe008000,allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
C.set_test_info(allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
print C
C=CocksPinchVariantResult(6,3,0xffe00008000000000000000000000000,1,ht=-1,hy=0xffbfffe3f80200000000,allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
C.set_test_info(allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
print C
C=CocksPinchVariantResult(6,3,0xffe00008000000000000000000000000,1,ht=-1,hy=0xfffffd0010001ffc0000,allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
C.set_test_info(allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
print C
C=CocksPinchVariantResult(6,3,0xefffffffffffffe00000000000000000,1,ht=-1,hy=0xffbbffffffffffffc020,allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
C.set_test_info(allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
print C
Search for curves of embedding degree 7
---------------------------------------
For k=7, we need to restrict to small discriminant D: as 4*p = t**2 + D*y**2,
log_2(p) = 512 and t and y are defined mod r, we need to take D as small as
possible, and D!= 3, 4 that are known discriminant, even if no attack using
this property exist.
We looked for curves of security parameter 7 (i.e G1-subgroup- G1-twist-secure).
For D = 5, HW_{NAF}(T) <= 7 and log_2(h_y) = 7, no curve was found.
We obtain the only G1-subgroup- G1-twist-secure with HW_NAF(T) = 8 with:
C=CocksPinchVariantResult(7,20,0x5fffb820248,6,ht=-2,allowed_cofactor=1232,allowed_size_cofactor=10,max_B1=600)
Search for curves of embedding degree 8
---------------------------------------
For k=8, we fix D=`1` in order to get efficient formulas from quartic twist.
We choose `T` of hamming weight less or equal to 5 so that we have enough
choices to have `phi_8(T)` prime.
We decide to force `4 | #E` so that Edwards form can be used.
The following curve was found:
# C=CocksPinchVariantResult(8,4,0xffffffffffffffc0,1,ht=-0x1821f,hy=0x1fdc,allowed_cofactor=1232,allowed_size_cofactor=10,max_B1=600)
# card_E = 2^4 * p284 * r
# card_Et = 2^2 * p542
# card_E2 = 2 * p830 * r
# card_E2t = 2 * 3^2 * 17 * p1079
Search for curves of embedding degree 8 (second take with small h_t)
--------------------------------------------------------------------
For k=8, allowing arbitrary cofactors in `h_t` and `h_y` leads to an
expensive second part of the final exponentiation. Therefore we restrict
to `|ht|<=4`.
We observe that the following code takes about one hour (with some
variation).
/grvingt/software/SageMath/sage ../search.sage -k 8 --D 1 --hty_choice '2-naf<=7,ht:max=4' --save --T_choice '2-naf<=5' --lambdap 544 --lambdar 256 --check_small_subgroup_secure 7 --required_cofactor 4 --allowed_automatic_cofactor 720 --allowed_cofactor 420 --allowed_size_cofactor 10 --ntasks 4096 --spawn 16 --task 0
Therefore, we can process all the 4096 task idenfiers as follows.
Since we tie jobs together by groups of 16, we must
create `2^(12-4)=2^8` distinct task identifiers. The overall cost is
expected to be `2^12` core-hours, i.e. less than 0.5 core-years.
fnancy ~ $ mkdir -p {todo,done,doing,failed}
fnancy ~ $ mkdir -p curves-data/
fnancy ~ $ (cd todo ; for i in {0..255} ; do touch $((16*i)) ; done)
fnancy ~ $ for i in {1..10} ; do oarsub -n k8 -q production -l "{cluster='grcinq'}/nodes=8,walltime=3" -l "{cluster='grvingt'}/nodes=8,walltime=2" "/home/ethome/jobpick/pick.sh --job-queue-path /home/ethome/pairings/code/k8 --job-weight 16 /grvingt/software/SageMath/sage ../search.sage -k 8 --D 1 --hty_choice '2-naf<=7,ht:max=4' --save --T_choice '2-naf<=5' --lambdap 544 --lambdar 256 --check_small_subgroup_secure 7 --required_cofactor 4 --allowed_automatic_cofactor 720 --allowed_cofactor 420 --allowed_size_cofactor 10 --ntasks 4096 --spawn 16 --task" ; done
This produces the following two curves (subjobs 47/4096 and 2483/4096,
respectively):
C=CocksPinchVariantResult(8,4,0xffffffffeff7c200,5,ht=5,hy=-0xd700,allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
C.set_test_info(allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
print C
C=CocksPinchVariantResult(8,4,0xffdffffc7ffffc00,3,ht=5,hy=0xc5f4,allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
C.set_test_info(allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600)
print C
Note that the former is naturally preferred because hy has 2-naf weight
only 4.
from collections import defaultdict
# This companion file can be used to derive and check generic formulas
# for the final exponentiation for prime k.
# There is no algorithm here. Just inspection of formulas, and
# optimization work. It does seem that number of necessary inversions
# varies, but the rest seems to be pretty constant.
#
# I have no reason to imagine that I haven't missed some optimization.
#
# Results:
#
# sage: load("final-expo-k57.sage")
# cost for k=5 i=1: 1c + 3T + 7M + 3p
# cost for k=5 i=2: 1I + 1c + 3T + 7M + 3p
# cost for k=5 i=3: 2I + 1c + 3T + 7M + 3p
# cost for k=5 i=4: 1I + 1c + 3T + 7M + 3p
# cost for k=7 i=1: 1c + 5T + 11M + 5p
# cost for k=7 i=2: 1I + 1c + 5T + 11M + 5p
# cost for k=7 i=3: 1I + 1c + 5T + 11M + 5p
# cost for k=7 i=4: 2I + 1c + 5T + 11M + 5p
# cost for k=7 i=5: 2I + 1c + 5T + 11M + 5p
# cost for k=7 i=6: 1I + 1c + 5T + 11M + 5p
# This structure keeps track of all the applied operations.
class counter():
def __init__(self):
self._counts=defaultdict(int)
class element:
def __init__(self, count, val=1):
self.val=val
self.count_dict = count
def __mul__(self, other):
w = self.count_dict._MUL(self.val, other.val)
return counter.element(self.count_dict, w)
def __pow__(self, e):
if e == -1:
w = self.count_dict._INV(self.val)
else:
w = self.count_dict._POW(self.val, e)
return counter.element(self.count_dict, w)
def frob(self, e, j):
w = self.count_dict._FROB(self.val, e, j)
return counter.element(self.count_dict, w)
def __str__(self):
return str(self.val)
def __repr__(self):
return repr(self.val)
def get_element(self):
return counter.element(count=self)
def counts(self):
return self._counts
def _POW(self, a, e):
assert a != 0
self._counts[str(e)] += 1
return a * e
def _FROB(self, a, e, j):
assert a != 0
self._counts[str(e)] += 1
return a * e**j
def _MUL(self, a, b):
assert a != 0 and b != 0
self._counts['M'] += 1
return a + b
def _INV(self, a):
assert a != 0
self._counts['I'] += 1
return -a
def mark_free(self, v):
self._counts.pop(str(v), None)
def rename(self, v, w):
n=self._counts.pop(str(v), None)
if n is not None:
self._counts[str(w)]=n
def text_counts(self):
return " + ".join(["%s%s" % (v,k) for k,v in self._counts.items() if v])
def print_final_expo_k57():
ZZc = PolynomialRing(ZZ, names=('c',)); (c,) = ZZc._first_ngens(1)