github.com/cloudflare/circl@v1.5.0/dh/csidh/curve.go (about)

     1  package csidh
     2  
     3  // xAdd implements differential arithmetic in P^1 for Montgomery
     4  // curves E(x): x^3 + A*x^2 + x by using x-coordinate only arithmetic.
     5  //
     6  //	x(PaQ) = x(P) + x(Q) by using x(P-Q)
     7  //
     8  // This algorithms is correctly defined only for cases when
     9  // P!=inf, Q!=inf, P!=Q and P!=-Q.
    10  func xAdd(PaQ, P, Q, PdQ *point) {
    11  	var t0, t1, t2, t3 fp
    12  	addRdc(&t0, &P.x, &P.z)
    13  	subRdc(&t1, &P.x, &P.z)
    14  	addRdc(&t2, &Q.x, &Q.z)
    15  	subRdc(&t3, &Q.x, &Q.z)
    16  	mulRdc(&t0, &t0, &t3)
    17  	mulRdc(&t1, &t1, &t2)
    18  	addRdc(&t2, &t0, &t1)
    19  	subRdc(&t3, &t0, &t1)
    20  	mulRdc(&t2, &t2, &t2) // sqr
    21  	mulRdc(&t3, &t3, &t3) // sqr
    22  	mulRdc(&PaQ.x, &PdQ.z, &t2)
    23  	mulRdc(&PaQ.z, &PdQ.x, &t3)
    24  }
    25  
    26  // xDbl implements point doubling on a Montgomery curve
    27  // E(x): x^3 + A*x^2 + x by using x-coordinate only arithmetic.
    28  //
    29  //	x(Q) = [2]*x(P)
    30  //
    31  // It is correctly defined for all P != inf.
    32  func xDbl(Q, P, A *point) {
    33  	var t0, t1, t2 fp
    34  	addRdc(&t0, &P.x, &P.z)
    35  	mulRdc(&t0, &t0, &t0) // sqr
    36  	subRdc(&t1, &P.x, &P.z)
    37  	mulRdc(&t1, &t1, &t1) // sqr
    38  	subRdc(&t2, &t0, &t1)
    39  	mulRdc(&t1, &four, &t1)
    40  	mulRdc(&t1, &t1, &A.z)
    41  	mulRdc(&Q.x, &t0, &t1)
    42  	addRdc(&t0, &A.z, &A.z)
    43  	addRdc(&t0, &t0, &A.x)
    44  	mulRdc(&t0, &t0, &t2)
    45  	addRdc(&t0, &t0, &t1)
    46  	mulRdc(&Q.z, &t0, &t2)
    47  }
    48  
    49  // xDblAdd implements combined doubling of point P
    50  // and addition of points P and Q on a Montgomery curve
    51  // E(x): x^3 + A*x^2 + x by using x-coordinate only arithmetic.
    52  //
    53  //	x(PaP) = x(2*P)
    54  //	x(PaQ) = x(P+Q)
    55  func xDblAdd(PaP, PaQ, P, Q, PdQ *point, A24 *coeff) {
    56  	var t0, t1, t2 fp
    57  
    58  	addRdc(&t0, &P.x, &P.z)
    59  	subRdc(&t1, &P.x, &P.z)
    60  	mulRdc(&PaP.x, &t0, &t0)
    61  	subRdc(&t2, &Q.x, &Q.z)
    62  	addRdc(&PaQ.x, &Q.x, &Q.z)
    63  	mulRdc(&t0, &t0, &t2)
    64  	mulRdc(&PaP.z, &t1, &t1)
    65  	mulRdc(&t1, &t1, &PaQ.x)
    66  	subRdc(&t2, &PaP.x, &PaP.z)
    67  	mulRdc(&PaP.z, &PaP.z, &A24.c)
    68  	mulRdc(&PaP.x, &PaP.x, &PaP.z)
    69  	mulRdc(&PaQ.x, &A24.a, &t2)
    70  	subRdc(&PaQ.z, &t0, &t1)
    71  	addRdc(&PaP.z, &PaP.z, &PaQ.x)
    72  	addRdc(&PaQ.x, &t0, &t1)
    73  	mulRdc(&PaP.z, &PaP.z, &t2)
    74  	mulRdc(&PaQ.z, &PaQ.z, &PaQ.z)
    75  	mulRdc(&PaQ.x, &PaQ.x, &PaQ.x)
    76  	mulRdc(&PaQ.z, &PaQ.z, &PdQ.x)
    77  	mulRdc(&PaQ.x, &PaQ.x, &PdQ.z)
    78  }
    79  
    80  // cswappoint swaps P1 with P2 in constant time. The 'choice'
    81  // parameter must have a value of either 1 (results
    82  // in swap) or 0 (results in no-swap).
    83  func cswappoint(P1, P2 *point, choice uint8) {
    84  	cswap512(&P1.x, &P2.x, choice)
    85  	cswap512(&P1.z, &P2.z, choice)
    86  }
    87  
    88  // xMul implements point multiplication with left-to-right Montgomery
    89  // adder. co is A coefficient of x^3 + A*x^2 + x curve. k must be > 0
    90  //
    91  // Non-constant time!
    92  func xMul(kP, P *point, co *coeff, k *fp) {
    93  	var A24 coeff
    94  	var Q point
    95  	var j uint
    96  	A := point{x: co.a, z: co.c}
    97  	R := *P
    98  
    99  	// Precompyte A24 = (A+2C:4C) => (A24.x = A.x+2A.z; A24.z = 4*A.z)
   100  	addRdc(&A24.a, &co.c, &co.c)
   101  	addRdc(&A24.a, &A24.a, &co.a)
   102  	mulRdc(&A24.c, &co.c, &four)
   103  
   104  	// Skip initial 0 bits.
   105  	for j = 511; j > 0; j-- {
   106  		// performance hit from making it constant-time is actually
   107  		// quite big, so... unsafe branch for now
   108  		if uint8(k[j>>6]>>(j&63)&1) != 0 {
   109  			break
   110  		}
   111  	}
   112  
   113  	xDbl(&Q, P, &A)
   114  	prevBit := uint8(1)
   115  	for i := j; i > 0; {
   116  		i--
   117  		bit := uint8(k[i>>6] >> (i & 63) & 1)
   118  		cswappoint(&Q, &R, prevBit^bit)
   119  		xDblAdd(&Q, &R, &Q, &R, P, &A24)
   120  		prevBit = bit
   121  	}
   122  	cswappoint(&Q, &R, uint8(k[0]&1))
   123  	*kP = Q
   124  }
   125  
   126  // xIso computes the isogeny with kernel point kern of a given order
   127  // kernOrder. Returns the new curve coefficient co and the image img.
   128  //
   129  // During computation function switches between Montgomery and twisted
   130  // Edwards curves in order to compute image curve parameters faster.
   131  // This technique is described by Meyer and Reith in ia.cr/2018/782.
   132  //
   133  // Non-constant time.
   134  func xIso(img *point, co *coeff, kern *point, kernOrder uint64) {
   135  	var t0, t1, t2, S, D fp
   136  	var Q, prod point
   137  	var coEd coeff
   138  	M := [3]point{*kern}
   139  
   140  	// Compute twisted Edwards coefficients
   141  	// coEd.a = co.a + 2*co.c
   142  	// coEd.c = co.a - 2*co.c
   143  	// coEd.a*X^2 + Y^2 = 1 + coEd.c*X^2*Y^2
   144  	addRdc(&coEd.c, &co.c, &co.c)
   145  	addRdc(&coEd.a, &co.a, &coEd.c)
   146  	subRdc(&coEd.c, &co.a, &coEd.c)
   147  
   148  	// Transfer point to twisted Edwards YZ-coordinates
   149  	// (X:Z)->(Y:Z) = (X-Z : X+Z)
   150  	addRdc(&S, &img.x, &img.z)
   151  	subRdc(&D, &img.x, &img.z)
   152  
   153  	subRdc(&prod.x, &kern.x, &kern.z)
   154  	addRdc(&prod.z, &kern.x, &kern.z)
   155  
   156  	mulRdc(&t1, &prod.x, &S)
   157  	mulRdc(&t0, &prod.z, &D)
   158  	addRdc(&Q.x, &t0, &t1)
   159  	subRdc(&Q.z, &t0, &t1)
   160  
   161  	xDbl(&M[1], kern, &point{x: co.a, z: co.c})
   162  
   163  	// NOTE: Not constant time.
   164  	for i := uint64(1); i < kernOrder>>1; i++ {
   165  		if i >= 2 {
   166  			xAdd(&M[i%3], &M[(i-1)%3], kern, &M[(i-2)%3])
   167  		}
   168  		subRdc(&t1, &M[i%3].x, &M[i%3].z)
   169  		addRdc(&t0, &M[i%3].x, &M[i%3].z)
   170  		mulRdc(&prod.x, &prod.x, &t1)
   171  		mulRdc(&prod.z, &prod.z, &t0)
   172  		mulRdc(&t1, &t1, &S)
   173  		mulRdc(&t0, &t0, &D)
   174  		addRdc(&t2, &t0, &t1)
   175  		mulRdc(&Q.x, &Q.x, &t2)
   176  		subRdc(&t2, &t0, &t1)
   177  		mulRdc(&Q.z, &Q.z, &t2)
   178  	}
   179  
   180  	mulRdc(&Q.x, &Q.x, &Q.x)
   181  	mulRdc(&Q.z, &Q.z, &Q.z)
   182  	mulRdc(&img.x, &img.x, &Q.x)
   183  	mulRdc(&img.z, &img.z, &Q.z)
   184  
   185  	// coEd.a^kernOrder and coEd.c^kernOrder
   186  	modExpRdc64(&coEd.a, &coEd.a, kernOrder)
   187  	modExpRdc64(&coEd.c, &coEd.c, kernOrder)
   188  
   189  	// prod^8
   190  	mulRdc(&prod.x, &prod.x, &prod.x)
   191  	mulRdc(&prod.x, &prod.x, &prod.x)
   192  	mulRdc(&prod.x, &prod.x, &prod.x)
   193  	mulRdc(&prod.z, &prod.z, &prod.z)
   194  	mulRdc(&prod.z, &prod.z, &prod.z)
   195  	mulRdc(&prod.z, &prod.z, &prod.z)
   196  
   197  	// Compute image curve params
   198  	mulRdc(&coEd.c, &coEd.c, &prod.x)
   199  	mulRdc(&coEd.a, &coEd.a, &prod.z)
   200  
   201  	// Convert curve coefficients back to Montgomery
   202  	addRdc(&co.a, &coEd.a, &coEd.c)
   203  	subRdc(&co.c, &coEd.a, &coEd.c)
   204  	addRdc(&co.a, &co.a, &co.a)
   205  }
   206  
   207  // montEval evaluates x^3 + Ax^2 + x.
   208  func montEval(res, A, x *fp) {
   209  	var t fp
   210  
   211  	*res = *x
   212  	mulRdc(res, res, res)
   213  	mulRdc(&t, A, x)
   214  	addRdc(res, res, &t)
   215  	addRdc(res, res, &one)
   216  	mulRdc(res, res, x)
   217  }