/ sage / derive_square_root.sage
derive_square_root.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 genSqrtFp2Constants(curve_name, curve_config):
 71    embdeg = curve_config[curve_name]['tower']['embedding_degree']
 72    twdeg = curve_config[curve_name]['tower']['twist_degree']
 73    g2field = f'Fp{embdeg//twdeg}' if (embdeg//twdeg) > 1 else 'Fp'
 74  
 75    p = curve_config[curve_name]['field']['modulus']
 76    Fp = GF(p)
 77    K.<u> = PolynomialRing(Fp)
 78    if g2field == 'Fp2':
 79      QNR_Fp = curve_config[curve_name]['tower']['QNR_Fp']
 80      Fp2.<beta> = Fp.extension(u^2 - QNR_Fp)
 81    else:
 82      SNR_Fp = curve_config[curve_name]['tower']['SNR_Fp']
 83      Fp2.<beta> = Fp.extension(u^2 - SNR_Fp)
 84  
 85    sqrt_QNR = Fp2([0, 1])
 86    sqrt_sqrt_QNR = sqrt_QNR.sqrt()
 87    sqrt_minus_sqrt_QNR = (-sqrt_QNR).sqrt()
 88  
 89    print('\n----> Square root on Fp2 constants <----\n')
 90    buf = inspect.cleandoc(f"""
 91        # Square Root Fp2 constants
 92        # -----------------------------------------------------------------
 93    """)
 94    buf += '\n'
 95  
 96    buf += f'const {curve_name}_sqrt_QNR* = '
 97    buf += field_to_nim(sqrt_QNR, 'Fp2', curve_name)
 98    buf += '\n'
 99  
100    buf += f'const {curve_name}_sqrt_sqrt_QNR* = '
101    buf += field_to_nim(sqrt_sqrt_QNR, 'Fp2', curve_name)
102    buf += '\n'
103  
104    buf += f'const {curve_name}_sqrt_minus_sqrt_QNR* = '
105    buf += field_to_nim(sqrt_minus_sqrt_QNR, 'Fp2', curve_name)
106    buf += '\n'
107  
108    return buf
109  
110  # CLI
111  # ---------------------------------------------------------
112  
113  if __name__ == "__main__":
114    # Usage
115    # BLS12-381
116    # sage sage/derive_sqrt.sage BLS12_381
117  
118    from argparse import ArgumentParser
119  
120    parser = ArgumentParser()
121    parser.add_argument("curve",nargs="+")
122    args = parser.parse_args()
123  
124    curve = args.curve[0]
125  
126    if curve not in Curves:
127      raise ValueError(
128        curve +
129        ' is not one of the available curves: ' +
130        str(Curves.keys())
131      )
132    else:
133      sqrt = genSqrtFp2Constants(curve, Curves)
134  
135      with open(f'{curve.lower()}_square_root.nim', 'w') as f:
136        f.write(copyright())
137        f.write('\n\n')
138  
139        f.write(inspect.cleandoc("""
140            import
141              ../config/curves,
142              ../io/io_extfields
143        """))
144  
145        f.write('\n\n')
146        f.write(sqrt)
147  
148      print(f'Successfully created {curve}_sqrt_fp2.nim')