g2_params.sage
1 #!/usr/bin/sage 2 # vim: syntax=python 3 # vim: set ts=2 sw=2 et: 4 5 # Constantine 6 # Copyright (c) 2018-2019 Status Research & Development GmbH 7 # Copyright (c) 2020-Present Mamy André-Ratsimbazafy 8 # Licensed and distributed under either of 9 # * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). 10 # * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). 11 # at your option. This file may not be copied, modified, or distributed except according to those terms. 12 13 # ############################################################ 14 # 15 # Frobenius constants 16 # 17 # ############################################################ 18 19 # Imports 20 # --------------------------------------------------------- 21 22 import os 23 import inspect, textwrap 24 25 # Working directory 26 # --------------------------------------------------------- 27 28 os.chdir(os.path.dirname(__file__)) 29 30 # Sage imports 31 # --------------------------------------------------------- 32 # Accelerate arithmetic by accepting probabilistic proofs 33 from sage.structure.proof.all import arithmetic 34 arithmetic(False) 35 36 load('curves.sage') 37 38 # Utilities 39 # --------------------------------------------------------- 40 41 def fp2_to_hex(a): 42 v = vector(a) 43 return '0x' + Integer(v[0]).hex() + ' + β * ' + '0x' + Integer(v[1]).hex() 44 45 def field_to_nim(value, field, curve, prefix = "", comment_above = "", comment_right = ""): 46 result = '# ' + comment_above + '\n' if comment_above else '' 47 comment_right = ' # ' + comment_right if comment_right else '' 48 49 if field == 'Fp2': 50 v = vector(value) 51 52 result += inspect.cleandoc(f""" 53 {prefix}Fp2[{curve}].fromHex( {comment_right} 54 "0x{Integer(v[0]).hex()}", 55 "0x{Integer(v[1]).hex()}" 56 )""") 57 elif field == 'Fp': 58 result += inspect.cleandoc(f""" 59 {prefix}Fp[{curve}].fromHex( {comment_right} 60 "0x{Integer(value).hex()}") 61 """) 62 else: 63 raise NotImplementedError() 64 65 return result 66 67 # Code generators 68 # --------------------------------------------------------- 69 70 def gen_coef_b_on_G2(curve_name, curve_config): 71 p = curve_config[curve_name]['field']['modulus'] 72 r = curve_config[curve_name]['field']['order'] 73 form = curve_config[curve_name]['curve']['form'] 74 a = curve_config[curve_name]['curve']['a'] 75 b = curve_config[curve_name]['curve']['b'] 76 embedding_degree = curve_config[curve_name]['tower']['embedding_degree'] 77 twist_degree = curve_config[curve_name]['tower']['twist_degree'] 78 twist = curve_config[curve_name]['tower']['twist'] 79 80 G2_field_degree = embedding_degree // twist_degree 81 G2_field = f'Fp{G2_field_degree}' if G2_field_degree > 1 else 'Fp' 82 83 if G2_field_degree == 2: 84 non_residue_fp = curve_config[curve_name]['tower']['QNR_Fp'] 85 elif G2_field_degree == 1: 86 if twist_degree == 6: 87 # Only for complete serialization 88 non_residue_fp = curve_config[curve_name]['tower']['SNR_Fp'] 89 else: 90 raise NotImplementedError() 91 else: 92 raise NotImplementedError() 93 94 Fp = GF(p) 95 K.<u> = PolynomialRing(Fp) 96 97 if G2_field == 'Fp2': 98 Fp2.<beta> = Fp.extension(u^2 - non_residue_fp) 99 G2F = Fp2 100 if twist_degree == 6: 101 non_residue_twist = curve_config[curve_name]['tower']['SNR_Fp2'] 102 else: 103 raise NotImplementedError() 104 elif G2_field == 'Fp': 105 G2F = Fp 106 if twist_degree == 6: 107 non_residue_twist = curve_config[curve_name]['tower']['SNR_Fp'] 108 else: 109 raise NotImplementedError() 110 else: 111 raise NotImplementedError() 112 113 if twist == 'D_Twist': 114 G2B = b/G2F(non_residue_twist) 115 G2 = EllipticCurve(G2F, [0, G2B]) 116 elif twist == 'M_Twist': 117 G2B = b*G2F(non_residue_twist) 118 G2 = EllipticCurve(G2F, [0, G2B]) 119 else: 120 raise ValueError('G2 must be a D_Twist or M_Twist but found ' + twist) 121 122 buf = inspect.cleandoc(f""" 123 # Curve precomputed parameters 124 # ----------------------------------------------------------------- 125 """) 126 buf += '\n' 127 128 buf += f'const {curve_name}_coefB_G2* = ' 129 buf += field_to_nim(G2B, G2_field, curve_name) 130 buf += '\n' 131 132 buf += f'const {curve_name}_coefB_G2_times_3* = ' 133 buf += field_to_nim(3*G2B, G2_field, curve_name) 134 buf += '\n' 135 136 return buf 137 138 # CLI 139 # --------------------------------------------------------- 140 141 if __name__ == "__main__": 142 # Usage 143 # BLS12-381 144 # sage sage/precompute_params.sage BLS12_381 145 146 from argparse import ArgumentParser 147 148 parser = ArgumentParser() 149 parser.add_argument("curve",nargs="+") 150 args = parser.parse_args() 151 152 curve = args.curve[0] 153 154 if curve not in Curves: 155 raise ValueError( 156 curve + 157 ' is not one of the available curves: ' + 158 str(Curves.keys()) 159 ) 160 else: 161 G2B = gen_coef_b_on_G2(curve, Curves) 162 163 with open(f'{curve.lower()}_constants.nim', 'w') as f: 164 f.write(copyright()) 165 f.write('\n\n') 166 167 f.write(inspect.cleandoc(""" 168 import 169 ../config/curves, 170 ../io/[io_fields, io_extfields] 171 """)) 172 173 f.write('\n\n') 174 f.write(G2B) 175 176 print(f'Successfully created {curve.lower()}_constants.nim')