diff --git a/cost_pairing.py b/cost_pairing.py index 864b4f52f4d03f78ed126cc378003330173d64cc..e6364128c2c1669f4d69f2cae11271eaf15977ba 100644 --- a/cost_pairing.py +++ b/cost_pairing.py @@ -9,23 +9,11 @@ from BN import * from MNT6 import * from final_expo_k57 import * - -# Set this flag to make sure that the changes we've done to the -# computation code do *NOT* affect the costs that we had computed thus -# far. -# -# Once we check that, we are confident that the change in machinery did -# not introduce new bugs. Then we can set OLDCOUNTS to False (and delete -# the associated code when relevant). -OLDCOUNTS=False - -# if OLDCOUNTS is True, these two are ignored (or are forced to False, -# so to say). -mystery_201903151748_simon_a_raison=False - # TODO: take into account h_t not always being 0 in the k=6 or k=8 # cases... [WIP for k=8 -- want to automate a bit] +mystery_201903151748_simon_a_raison=False + Qmsi = QQ['m,s,inv'] m,s,inv = Qmsi.gens() @@ -110,8 +98,6 @@ def cost_i(k) : # # ni = inv(n) # # ai = ni * a # return 6*cost_f(k) + 3*cost_m(k) + inv + 2*k*m - elif OLDCOUNTS and (k==5 or k==7): - return (k-1)*cost_f(k) + (k-1)*cost_m(k) + inv elif k%2 == 1: # generalization of the above. # Note that we can go further. If (k-1)/2 >= 4, then we may apply @@ -125,7 +111,7 @@ def cost_i(k) : def cost_f(k, d=1) : # return the cost of a d-Frobenius over F_{p^k} assert k % d == 0 - if (k//d) % 2 == 0 and not OLDCOUNTS: + if (k//d) % 2 == 0 : # for F_{p^{k/d}} a tower defined by binomials, the multipliers in # the Frobenius (p^d-th power) expressions are all powers of a # k/d-th root of unity. If k/d is even, one of them is -1. At any @@ -136,7 +122,7 @@ def cost_f(k, d=1) : return (k//d-1) * d * cost_m(1) def cost_i_and_f(k) : - if OLDCOUNTS or k % 2 == 0 or k % 3 == 0: + if k % 2 == 0 or k % 3 == 0: return cost_i(k) + cost_f(k) elif k == 5 or k == 7: # Then we know that the inversion computes the Frobenius anyway. @@ -185,20 +171,6 @@ C6=CocksPinchVariantResult(6,3,0xefffffffffffffe00000000000000000,1,ht=-1,hy=0xf C7=CocksPinchVariantResult(7,20,0x5fffb820248,6,ht=-2,allowed_cofactor=1232,allowed_size_cofactor=10,max_B1=600) C8=CocksPinchVariantResult(8,4,0xffffffffeff7c200,5,ht=5,hy=-0xd700,allowed_cofactor=420,allowed_size_cofactor=10,max_B1=600) -C8old=CocksPinchVariantResult(8,4,0xe000000000001010,5,ht=1,hy=0x177dc) -C6old=CocksPinchVariantResult(6,3,0xc0000000000000000040000000000000,5,hy=0x20000000000000000000f) -C5old=CocksPinchVariantResult(5,1001035,0xe000000000000036,4,ht=1,hy=0xb5f94915f3db71cae) -C7old=CocksPinchVariantResult(7,312916,0x60000000002,5,ht=-1) - -if OLDCOUNTS: - # Curves as they were at least on the printout I have here. But I'm - # not sure these are the curves we used to base our counts on anyway. - C5 = C5old - C6 = C6old - C7 = C7old - C8 = C8old - - CBN12=BN(eval(preparse("2^114+2^101-2^14-1"))) CBLS12=BLS12(eval(preparse("-2^77+2^50+2^33"))) CKSS16=KSS16(eval(preparse("2^35-2^32-2^18+2^8+1"))) @@ -212,10 +184,7 @@ def finite_field_cost(logp): if words == 6 : time_m = 69 #relic benchmark if words == 8 : - if OLDCOUNTS: - time_m = 130 #relic benchmark - else: - time_m = 120 #relic benchmark + time_m = 120 #relic benchmark elif words == 9 : time_m = 1.9*9**2 elif words == 10 : @@ -343,7 +312,7 @@ def millerLoopCost(C): cost_update1 = cost_s(k)+densexsparse_m8(k) cost_update2 = densexsparse_m8(k) if name == 'KSS16' : # extra partial add and partial double + 3 frob and 2 multiplications - if not OLDCOUNTS and mystery_201903151748_simon_a_raison: + if mystery_201903151748_simon_a_raison: miller_fixup = (cost_m(k//4) + 5 *cost_s(k//4) + k//2 * cost_m(1)) + \ + (5*cost_m(k//4) + 2*cost_s(k//4) + k//2 * cost_m(1)) else: @@ -378,10 +347,6 @@ def millerLoopCost(C): logT = T.nbits() HwT = Hw(T) - if OLDCOUNTS: - if k==8: - HwT=3 - tot_miller = (logT-1) * (cost_doubleline + cost_verticalline) \ + (logT-2) * cost_update1 \ + (HwT-1) * (cost_addline + cost_verticalline + cost_update2) \ @@ -394,8 +359,6 @@ def cost_firstexp(k): assert k in [5,6,7,8] if Integer(k).is_prime(): return cost_i_and_f(k)+cost_m(k) - if OLDCOUNTS and k==6 : - return 4*cost_f(k) + cost_i(k) + 3*cost_m(k) if k == 6 : # a <- a^(1+p) c0 = cost_f(k) + cost_m(k) @@ -449,19 +412,6 @@ def finalExpoCost(C): loghy=hy.nbits(); Hwhy=Hw(hy) loght=ht.nbits(); Hwht=Hw(ht) - - if OLDCOUNTS: - if k==5: - logp=665 - HwCofr=206 - elif k==7: - HwCofr=133 - # This had us trip over word size limits. - logp=513 - elif k==8: - HwT=3 - loghy=18 - c1 = cost_firstexp(k) # Now compute c2 (second part of FE) @@ -470,64 +420,27 @@ def finalExpoCost(C): cost_T = (logT-1)*cost_s(k) + (HwT-1)*cost_m(k) - if OLDCOUNTS: - # number of frobenius exponentiations in the second part - c_frobenius = (k - 2) * cost_f(k) - c2 = c_frobenius - - # k-2 exponentations to T: - c2 += (k - 2) * cost_T - # exponentation to cofactor c: - logc = logp - logr - c2 += (logc -1)*cost_s(k) + (HwCofr-1)*cost_m(k) - - # FIXME: the formulas below are not generic. They're specific - # to one chosen value of i. And among the different - # possibilities, i=1 is arguably nicest, so that we're - # tempted to use that as a default. Maybe it's unwanted - # pressure for the k=7 case, though. - - # multiplying together the (k - 2) terms costs (k - 3) M: - c2 += (k - 3)*cost_m(k) - ### XXX ? really ? I count (k-1) terms, not (k-2) - - # assume one inversion costs (k-1) Frobenius since the norm is 1 at this point - if OLDCOUNTS: - cost_inv_torus = (k-1) * c_frobenius - else: - # 99% sure that the formula above is a bug. - cost_inv_torus = (k-1) * cost_f(k) - - # This adds (k-1)*cost_m(k) (don't know where this comes - # from, but anyway this seems to match our 2(k-2)) and - # cost_inv_torus, which I think is potentially unneeded - if k == 5: - c2 += 4*cost_m(k) + cost_inv_torus - elif k == 7: - c2 += 6*cost_m(k) + 3*cost_inv_torus - # checked in sage, see params-k7-512.sage and params-k5-664.sage - else: - # see final-expo-k57.sage - c2 = (k-2)*(cost_f(k) + cost_T + 2*cost_m(k)) + cost_m(k) - logc = logp - logr - c2 += (logc -1)*cost_s(k) + (HwCofr-1)*cost_m(k) - # one inversion costs (k-1) Frobenius since norm == 1 - cost_inv_torus = (k-1) * cost_f(k) - if i > 1: - c2 += cost_inv_torus - if i < k-1 and 2*i > k: - # this just happens to match the formulas that we have. - c2 += cost_inv_torus - # 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 + # see final-expo-k57.sage + c2 = (k-2)*(cost_f(k) + cost_T + 2*cost_m(k)) + cost_m(k) + logc = logp - logr + c2 += (logc -1)*cost_s(k) + (HwCofr-1)*cost_m(k) + # one inversion costs (k-1) Frobenius since norm == 1 + cost_inv_torus = (k-1) * cost_f(k) + if i > 1: + c2 += cost_inv_torus + if i < k-1 and 2*i > k: + # this just happens to match the formulas that we have. + c2 += cost_inv_torus + # 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 elif k == 6 : # See: @@ -536,50 +449,35 @@ def finalExpoCost(C): assert D==3 - if OLDCOUNTS: - c_exp_T = (logT-1)*cyclo_s6 + (HwT-1)*cost_m(k) - c_exp_hy = (loghy-1)*cyclo_s6 + (Hwhy-1)*cost_m(k) - - c21 = 2*c_exp_T + 2*c_exp_hy + cyclo_s6 + 5*cost_m(k) - c22 = 0 - c23 = c_exp_T + cost_f(k) + cyclo_s6 + 4*cost_m(k) - - # - # c21 = 2*c_exp_T + 2*c_exp_hy + 5*cyclo_s6 + 8*cost_m(k) # + cost_i(k) NO inversions are free at this point - # c22 = c_exp_T + cost_m(k) # + cost_i(k) NO inversion - # c23 = 2*cost_m(k) + cost_f(k) - - c2 = c21 + c22+c23 - else: - # start with this: - - c_exp_T = (logT-1)*cyclo_s6 + (HwT-1)*cost_m(k) - c2 = c_exp_T + cost_f(k) + cyclo_s6 + 4*cost_m(k) - if i == 5: - # extra cost for raising to the power p+t0 = p+2-T: we - # need a square... - c2 += cyclo_s6 - - # Then, see code/formules-familles-CocksPinch.sage - # it's a slight mess, to be honest. - - assert (1 + ht + hy) % 2 == 0 - if ht % 2 == 0: - hu = ht//2 - hz = -1 if T%3 == 0 else 1 - hw = (hy-hz)//2 - else: - hu = (ht+1)//2 + # start with this: + + c_exp_T = (logT-1)*cyclo_s6 + (HwT-1)*cost_m(k) + c2 = c_exp_T + cost_f(k) + cyclo_s6 + 4*cost_m(k) + if i == 5: + # extra cost for raising to the power p+t0 = p+2-T: we + # need a square... + c2 += cyclo_s6 + + # Then, see code/formules-familles-CocksPinch.sage + # it's a slight mess, to be honest. + + assert (1 + ht + hy) % 2 == 0 + if ht % 2 == 0: + hu = ht//2 + hz = -1 if T%3 == 0 else 1 + hw = (hy-hz)//2 + else: + hu = (ht+1)//2 hw = hy//2 - U = T - (T % 3) - logU=U.nbits(); HwU=Hw(U) - loghu=hu.nbits(); Hwhu=Hw(hu) - loghw=hw.nbits(); Hwhw=Hw(hw) - c_exp_U = (logU-1)*cyclo_s6 + (HwU-1)*cost_m(k) - c_exp_hu = (loghu-1)*cyclo_s6 + (Hwhu-1)*cost_m(k) - c_exp_hw = (loghw-1)*cyclo_s6 + (Hwhw-1)*cost_m(k) - - c2 += 12*cost_m(k) + 2*cost_s(k) + 2*(c_exp_U + c_exp_hu + c_exp_hw) + U = T - (T % 3) + logU=U.nbits(); HwU=Hw(U) + loghu=hu.nbits(); Hwhu=Hw(hu) + loghw=hw.nbits(); Hwhw=Hw(hw) + c_exp_U = (logU-1)*cyclo_s6 + (HwU-1)*cost_m(k) + c_exp_hu = (loghu-1)*cyclo_s6 + (Hwhu-1)*cost_m(k) + c_exp_hw = (loghw-1)*cyclo_s6 + (Hwhw-1)*cost_m(k) + + c2 += 12*cost_m(k) + 2*cost_s(k) + 2*(c_exp_U + c_exp_hu + c_exp_hw) elif k == 8 : # See: # sage: attach("formules-familles-CocksPinch.sage") @@ -594,37 +492,27 @@ def finalExpoCost(C): # and maybe one multiplication less. Note also that ht+1 is # necessarily even. - if OLDCOUNTS: - c21 = 0 # c21 = 2*cost_s(k) - c_exp_hy = (loghy-1)*cyclo_s8 + (Hwhy-1)*cost_m(k) - c_exp_T = (logT-1)*cyclo_s8 + (HwT-1)*cost_m(k) - c22 = 2*c_exp_hy + 4*c_exp_T + 6*cost_m(k) #+ 3*cyclo_s8 not needed if we compute C/4 instead of C - c23 = 3*c_exp_T + 3*cost_f(8) + 3*cost_m(k) #+ 2*cost_i(k) inversions are free at this point ! - c24 = 0 # c24 = cost_m(k) - - c2 = c21+c22+c23+c24 - else: - c_exp_T = (logT-1)*cyclo_s8 + (HwT-1)*cost_m(k) - - # first, this: (because phi_8(p)/r = 1 + c(T^2+p^2)(p-T)) - c2 = 3*c_exp_T + 2*cost_f(8) + 3*cost_m(k) - - # Then, see code/formules-familles-CocksPinch.sage - - # for raising to the power c, we get: - # 11M + 2u + 4T + 2y - # with one of the multiplies that (for i=3 and i=7) can be - # elided if T=0 mod 4. This is with u = multiplication by - # (h_t+1)//2. - hu = (ht+1)//2; - loghu=hu.nbits(); Hwhu=Hw(hu) - c_exp_hy = (loghy-1)*cyclo_s8 + (Hwhy-1)*cost_m(k) - c_exp_hu = (loghu-1)*cyclo_s8 + (Hwhu-1)*cost_m(k) - - c2 += 4 * c_exp_T + 2 * c_exp_hu + 2 * c_exp_hy + 10 * cost_m(k) - if (T%4 == 2 or i == 1 or i == 5): - c2 += cost_m(k) - + c_exp_T = (logT-1)*cyclo_s8 + (HwT-1)*cost_m(k) + + # first, this: (because phi_8(p)/r = 1 + c(T^2+p^2)(p-T)) + c2 = 3*c_exp_T + 2*cost_f(8) + 3*cost_m(k) + + # Then, see code/formules-familles-CocksPinch.sage + + # for raising to the power c, we get: + # 11M + 2u + 4T + 2y + # with one of the multiplies that (for i=3 and i=7) can be + # elided if T=0 mod 4. This is with u = multiplication by + # (h_t+1)//2. + hu = (ht+1)//2; + loghu=hu.nbits(); Hwhu=Hw(hu) + c_exp_hy = (loghy-1)*cyclo_s8 + (Hwhy-1)*cost_m(k) + c_exp_hu = (loghu-1)*cyclo_s8 + (Hwhu-1)*cost_m(k) + + c2 += 4 * c_exp_T + 2 * c_exp_hu + 2 * c_exp_hy + 10 * cost_m(k) + if (T%4 == 2 or i == 1 or i == 5): + c2 += cost_m(k) + tot_expo = c1 + c2 return tot_expo(m=1,s=1,inv=25) @@ -634,13 +522,7 @@ def pairingCost(C): costFinalExp = finalExpoCost(C) logp = polymorphic_get_logp(C) - if OLDCOUNTS: - k = polymorphic_get_embedding_degree(C) - if k==5: - logp=665 - elif k==7: - logp=513 - + time_m = finite_field_cost(logp) tot_miller = costMiller[-1] @@ -667,13 +549,6 @@ def table_cost_pairing() : for C in [C5,C6,C7,C8,CBN12,CBLS12,CKSS16,C1]: L=pairingCost(C) - if OLDCOUNTS: - if L['k'] == 7: - scale = 130/L['time_m'] - for kk in L.keys(): - if re.match("^time_.*", kk): - L[kk] = round(L[kk] * scale, 1) - timing_recap.append(L) #timing recap is generated