/ sage / g2_params.sage
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')