diff --git a/constantine/isogeny/frobenius.nim b/constantine/isogeny/frobenius.nim index f9d36b7..69e2335 100644 --- a/constantine/isogeny/frobenius.nim +++ b/constantine/isogeny/frobenius.nim @@ -44,7 +44,19 @@ func frobenius_map*(r: var Fp2, a: Fp2, k: static int = 1) {.inline.} = r = a template mulCheckSparse[Fp2](a: var Fp2, b: Fp2) = - when b.c0.isZero().bool: + when b.c0.isOne().bool and b.c1.isZero().bool: + discard + elif b.c0.isZero().bool and b.c1.isOne().bool: + var t {.noInit.}: type(b.c0) + when fromComplexExtension(b.c0): + t.neg(a.c1) + a.c1 = a.c0 + a.c0 = t + else: + t = a.c1 * NonResidue + a.c1 = a.c0 + a.c0 = t + elif b.c0.isZero().bool: a.mul_sparse_by_0y(b) elif b.c1.isZero().bool: a.mul_sparse_by_x0(b) @@ -54,24 +66,92 @@ template mulCheckSparse[Fp2](a: var Fp2, b: Fp2) = # Frobenius map - on extension fields # ----------------------------------------------------------------- -{.experimental: "dynamicBindSym".} - -macro frobMapConst(C: static Curve, coefpow, frobpow: static int): untyped = - return bindSym("FrobMapConst_" & $C & "_coef" & $coefpow & "_pow" & $frobpow) - -# SNR^((p-1)/6)^3 -const FrobMapConst_BLS12_381_coef3_pow1 = Fp2[BLS12_381].fromHex( +# c = (SNR^((p-1)/6)^coef). +# Then for frobenius(2): c * conjugate(c) +# And for frobenius(2): c² * conjugate(c) +const FrobMapConst_BLS12_381 = [ + # frobenius(1) + [Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^0 + "0x1", + "0x0" + ), + Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^1 + "0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8", + "0xfc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3" + ), + Fp2[BLS12_381].fromHex( + "0x0", + "0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac" + ), + Fp2[BLS12_381].fromHex( "0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09", "0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09" - ) + ), + Fp2[BLS12_381].fromHex( + "0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad", + "0x0" + ), + Fp2[BLS12_381].fromHex( + "0x5b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116", + "0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995" + )], + # frobenius(2) + [Fp2[BLS12_381].fromHex( + "0x1", + "0x0" + ), + Fp2[BLS12_381].fromHex( + "0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff", + "0x0" + ), + Fp2[BLS12_381].fromHex( + "0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe", + "0x0" + ), + Fp2[BLS12_381].fromHex( + "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa", + "0x0" + ), + Fp2[BLS12_381].fromHex( + "0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac", + "0x0" + ), + Fp2[BLS12_381].fromHex( + "0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad", + "0x0" + )], + # frobenius(3) + [Fp2[BLS12_381].fromHex( + "0x1", + "0x0" + ), + Fp2[BLS12_381].fromHex( + "0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2", + "0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09" + ), + Fp2[BLS12_381].fromHex( + "0x0", + "0x1" + ), + Fp2[BLS12_381].fromHex( + "0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2", + "0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2" + ), + Fp2[BLS12_381].fromHex( + "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa", + "0x0" + ), + Fp2[BLS12_381].fromHex( + "0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09", + "0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2" + )]] func frobenius_map*(r: var Fp4, a: Fp4, k: static int = 1) {.inline.} = ## Computes a^(p^k) ## The p-power frobenius automorphism on 𝔽p4 r.c0.frobenius_map(a.c0, k) r.c1.frobenius_map(a.c1, k) - - r.c1.mulCheckSparse frobMapConst(Fp4.C, 3, k) + r.c1.mulCheckSparse FrobMapConst_BLS12_381[k-1][4-1] # ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves # ----------------------------------------------------------------- @@ -166,6 +246,8 @@ const FrobPsiConst_BLS12_381_psi2_coef2 = Fp2[BLS12_381].fromHex( "0x0" ) +{.experimental: "dynamicBindSym".} + macro frobPsiConst(C: static Curve, psipow, coefpow: static int): untyped = return bindSym("FrobPsiConst_" & $C & "_psi" & $psipow & "_coef" & $coefpow) diff --git a/sage/frobenius_bls12_381.sage b/sage/frobenius_bls12_381.sage index 3da1701..ccde57b 100644 --- a/sage/frobenius_bls12_381.sage +++ b/sage/frobenius_bls12_381.sage @@ -48,14 +48,24 @@ print('') # Utilities def fp2_to_hex(a): v = vector(a) - return Integer(v[0]).hex() + ' + β * ' + Integer(v[1]).hex() + return '0x' + Integer(v[0]).hex() + ' + β * ' + '0x' + Integer(v[1]).hex() # Frobenius map constants (D type: use SNR, M type use 1/SNR) print('\nFrobenius extension field constants') FrobConst_map = SNR^((p-1)/6) -print('FrobConst_map : ' + fp2_to_hex(FrobConst_map)) -FrobConst_map_fp4 = FrobConst_map^(12//4) -print('FrobConst_map_fp4_y : ' + fp2_to_hex(FrobConst_map_fp4)) +FrobConst_map_list = [] +cur = Fp2([1, 0]) + +for i in range(6): + FrobConst_map_list.append(cur) + print(f'FrobConst_map_{i} : {fp2_to_hex(cur)}') + cur *= FrobConst_map +print('') +for i in range(6): + print(f'FrobConst_map_{i}_pow2 : {fp2_to_hex(FrobConst_map_list[i]*conjugate(FrobConst_map_list[i]))}') +print('') +for i in range(6): + print(f'FrobConst_map_{i}_pow3 : {fp2_to_hex(FrobConst_map_list[i]**2 * conjugate(FrobConst_map_list[i]))}') # Frobenius psi constants (D type: use SNR, M type use 1/SNR) print('\nψ (Psi) - Untwist-Frobenius-Twist constants') diff --git a/tests/t_fp_tower_frobenius_template.nim b/tests/t_fp_tower_frobenius_template.nim index 939b5d8..8e9864d 100644 --- a/tests/t_fp_tower_frobenius_template.nim +++ b/tests/t_fp_tower_frobenius_template.nim @@ -81,35 +81,43 @@ proc runFrobeniusTowerTests*[N]( test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight) test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence) - # test "Frobenius(a, 2) = a^(p^2) (mod p^" & $ExtDegree & ")": - # proc test(Field: typedesc, Iters: static int, gen: RandomGen) = - # for _ in 0 ..< Iters: - # var a = rng.random_elem(Field, gen) - # var fa {.noInit.}: typeof(a) - # fa.frobenius_map(a, k = 2) + test "Frobenius(a, 2) = a^(p^2) (mod p^" & $ExtDegree & ")": + proc test(Field: typedesc, Iters: static int, gen: RandomGen) = + for _ in 0 ..< 1: + var a = rng.random_elem(Field, gen) + var fa {.noInit.}: typeof(a) + fa.frobenius_map(a, k = 2) - # a.powUnsafeExponent(Field.C.Mod, window = 3) - # a.powUnsafeExponent(Field.C.Mod, window = 3) - # check: bool(a == fa) + var fa2 {.noInit.}: typeof(a) + fa2.frobenius_map(a, k = 1) + fa2.frobenius_map(fa2, k = 1) - # staticFor(curve, TestCurves): - # test(ExtField(ExtDegree, curve), Iters, gen = Uniform) - # test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight) - # test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence) + a.powUnsafeExponent(Field.C.Mod, window = 3) + a.powUnsafeExponent(Field.C.Mod, window = 3) - # test "Frobenius(a, 3) = a^(p^3) (mod p^" & $ExtDegree & ")": - # proc test(Field: typedesc, Iters: static int, gen: RandomGen) = - # for _ in 0 ..< Iters: - # var a = rng.random_elem(Field, gen) - # var fa {.noInit.}: typeof(a) - # fa.frobenius_map(a, k = 3) + check: + bool(a == fa) + bool(a == fa2) + bool(fa == fa2) - # a.powUnsafeExponent(Field.C.Mod, window = 3) - # a.powUnsafeExponent(Field.C.Mod, window = 3) - # a.powUnsafeExponent(Field.C.Mod, window = 3) - # check: bool(a == fa) + staticFor(curve, TestCurves): + test(ExtField(ExtDegree, curve), Iters, gen = Uniform) + test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight) + test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence) - # staticFor(curve, TestCurves): - # test(ExtField(ExtDegree, curve), Iters, gen = Uniform) - # test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight) - # test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence) + test "Frobenius(a, 3) = a^(p^3) (mod p^" & $ExtDegree & ")": + proc test(Field: typedesc, Iters: static int, gen: RandomGen) = + for _ in 0 ..< Iters: + var a = rng.random_elem(Field, gen) + var fa {.noInit.}: typeof(a) + fa.frobenius_map(a, k = 3) + + a.powUnsafeExponent(Field.C.Mod, window = 3) + a.powUnsafeExponent(Field.C.Mod, window = 3) + a.powUnsafeExponent(Field.C.Mod, window = 3) + check: bool(a == fa) + + staticFor(curve, TestCurves): + test(ExtField(ExtDegree, curve), Iters, gen = Uniform) + test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight) + test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence)