// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package elliptic

import 

// CurveParams contains the parameters of an elliptic curve and also provides
// a generic, non-constant time implementation of Curve.
//
// The generic Curve implementation is deprecated, and using custom curves
// (those not returned by P224(), P256(), P384(), and P521()) is not guaranteed
// to provide any security property.
type CurveParams struct {
	P       *big.Int // the order of the underlying field
	N       *big.Int // the order of the base point
	B       *big.Int // the constant of the curve equation
	Gx, Gy  *big.Int // (x,y) of the base point
	BitSize int      // the size of the underlying field
	Name    string   // the canonical name of the curve
}

func ( *CurveParams) () *CurveParams {
	return 
}

// CurveParams operates, internally, on Jacobian coordinates. For a given
// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
// calculation can be performed within the transform (as in ScalarMult and
// ScalarBaseMult). But even for Add and Double, it's faster to apply and
// reverse the transform than to operate in affine coordinates.

// polynomial returns x³ - 3x + b.
func ( *CurveParams) ( *big.Int) *big.Int {
	 := new(big.Int).Mul(, )
	.Mul(, )

	 := new(big.Int).Lsh(, 1)
	.Add(, )

	.Sub(, )
	.Add(, .B)
	.Mod(, .P)

	return 
}

// IsOnCurve implements Curve.IsOnCurve.
//
// Deprecated: the CurveParams methods are deprecated and are not guaranteed to
// provide any security property. For ECDH, use the crypto/ecdh package.
// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
// from P224(), P256(), P384(), or P521().
func ( *CurveParams) (,  *big.Int) bool {
	// If there is a dedicated constant-time implementation for this curve operation,
	// use that instead of the generic one.
	if ,  := matchesSpecificCurve();  {
		return .IsOnCurve(, )
	}

	if .Sign() < 0 || .Cmp(.P) >= 0 ||
		.Sign() < 0 || .Cmp(.P) >= 0 {
		return false
	}

	// y² = x³ - 3x + b
	 := new(big.Int).Mul(, )
	.Mod(, .P)

	return .polynomial().Cmp() == 0
}

// zForAffine returns a Jacobian Z value for the affine point (x, y). If x and
// y are zero, it assumes that they represent the point at infinity because (0,
// 0) is not on the any of the curves handled here.
func (,  *big.Int) *big.Int {
	 := new(big.Int)
	if .Sign() != 0 || .Sign() != 0 {
		.SetInt64(1)
	}
	return 
}

// affineFromJacobian reverses the Jacobian transform. See the comment at the
// top of the file. If the point is ∞ it returns 0, 0.
func ( *CurveParams) (, ,  *big.Int) (,  *big.Int) {
	if .Sign() == 0 {
		return new(big.Int), new(big.Int)
	}

	 := new(big.Int).ModInverse(, .P)
	 := new(big.Int).Mul(, )

	 = new(big.Int).Mul(, )
	.Mod(, .P)
	.Mul(, )
	 = new(big.Int).Mul(, )
	.Mod(, .P)
	return
}

// Add implements Curve.Add.
//
// Deprecated: the CurveParams methods are deprecated and are not guaranteed to
// provide any security property. For ECDH, use the crypto/ecdh package.
// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
// from P224(), P256(), P384(), or P521().
func ( *CurveParams) (, , ,  *big.Int) (*big.Int, *big.Int) {
	// If there is a dedicated constant-time implementation for this curve operation,
	// use that instead of the generic one.
	if ,  := matchesSpecificCurve();  {
		return .Add(, , , )
	}
	panicIfNotOnCurve(, , )
	panicIfNotOnCurve(, , )

	 := zForAffine(, )
	 := zForAffine(, )
	return .affineFromJacobian(.addJacobian(, , , , , ))
}

// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
// (x2, y2, z2) and returns their sum, also in Jacobian form.
func ( *CurveParams) (, , , , ,  *big.Int) (*big.Int, *big.Int, *big.Int) {
	// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
	, ,  := new(big.Int), new(big.Int), new(big.Int)
	if .Sign() == 0 {
		.Set()
		.Set()
		.Set()
		return , , 
	}
	if .Sign() == 0 {
		.Set()
		.Set()
		.Set()
		return , , 
	}

	 := new(big.Int).Mul(, )
	.Mod(, .P)
	 := new(big.Int).Mul(, )
	.Mod(, .P)

	 := new(big.Int).Mul(, )
	.Mod(, .P)
	 := new(big.Int).Mul(, )
	.Mod(, .P)
	 := new(big.Int).Sub(, )
	 := .Sign() == 0
	if .Sign() == -1 {
		.Add(, .P)
	}
	 := new(big.Int).Lsh(, 1)
	.Mul(, )
	 := new(big.Int).Mul(, )

	 := new(big.Int).Mul(, )
	.Mul(, )
	.Mod(, .P)
	 := new(big.Int).Mul(, )
	.Mul(, )
	.Mod(, .P)
	 := new(big.Int).Sub(, )
	if .Sign() == -1 {
		.Add(, .P)
	}
	 := .Sign() == 0
	if  &&  {
		return .doubleJacobian(, , )
	}
	.Lsh(, 1)
	 := new(big.Int).Mul(, )

	.Set()
	.Mul(, )
	.Sub(, )
	.Sub(, )
	.Sub(, )
	.Mod(, .P)

	.Set()
	.Sub(, )
	.Mul(, )
	.Mul(, )
	.Lsh(, 1)
	.Sub(, )
	.Mod(, .P)

	.Add(, )
	.Mul(, )
	.Sub(, )
	.Sub(, )
	.Mul(, )
	.Mod(, .P)

	return , , 
}

// Double implements Curve.Double.
//
// Deprecated: the CurveParams methods are deprecated and are not guaranteed to
// provide any security property. For ECDH, use the crypto/ecdh package.
// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
// from P224(), P256(), P384(), or P521().
func ( *CurveParams) (,  *big.Int) (*big.Int, *big.Int) {
	// If there is a dedicated constant-time implementation for this curve operation,
	// use that instead of the generic one.
	if ,  := matchesSpecificCurve();  {
		return .Double(, )
	}
	panicIfNotOnCurve(, , )

	 := zForAffine(, )
	return .affineFromJacobian(.doubleJacobian(, , ))
}

// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
// returns its double, also in Jacobian form.
func ( *CurveParams) (, ,  *big.Int) (*big.Int, *big.Int, *big.Int) {
	// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
	 := new(big.Int).Mul(, )
	.Mod(, .P)
	 := new(big.Int).Mul(, )
	.Mod(, .P)
	 := new(big.Int).Sub(, )
	if .Sign() == -1 {
		.Add(, .P)
	}
	 := new(big.Int).Add(, )
	.Mul(, )
	.Set()
	.Lsh(, 1)
	.Add(, )

	 := .Mul(, )

	 := new(big.Int).Mul(, )
	 := new(big.Int).Lsh(, 3)
	.Mod(, .P)
	.Sub(, )
	if .Sign() == -1 {
		.Add(, .P)
	}
	.Mod(, .P)

	 := new(big.Int).Add(, )
	.Mul(, )
	.Sub(, )
	if .Sign() == -1 {
		.Add(, .P)
	}
	.Sub(, )
	if .Sign() == -1 {
		.Add(, .P)
	}
	.Mod(, .P)

	.Lsh(, 2)
	.Sub(, )
	if .Sign() == -1 {
		.Add(, .P)
	}
	 := .Mul(, )

	.Mul(, )
	.Lsh(, 3)
	.Mod(, .P)

	.Sub(, )
	if .Sign() == -1 {
		.Add(, .P)
	}
	.Mod(, .P)

	return , , 
}

// ScalarMult implements Curve.ScalarMult.
//
// Deprecated: the CurveParams methods are deprecated and are not guaranteed to
// provide any security property. For ECDH, use the crypto/ecdh package.
// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
// from P224(), P256(), P384(), or P521().
func ( *CurveParams) (,  *big.Int,  []byte) (*big.Int, *big.Int) {
	// If there is a dedicated constant-time implementation for this curve operation,
	// use that instead of the generic one.
	if ,  := matchesSpecificCurve();  {
		return .ScalarMult(, , )
	}
	panicIfNotOnCurve(, , )

	 := new(big.Int).SetInt64(1)
	, ,  := new(big.Int), new(big.Int), new(big.Int)

	for ,  := range  {
		for  := 0;  < 8; ++ {
			, ,  = .doubleJacobian(, , )
			if &0x80 == 0x80 {
				, ,  = .addJacobian(, , , , , )
			}
			 <<= 1
		}
	}

	return .affineFromJacobian(, , )
}

// ScalarBaseMult implements Curve.ScalarBaseMult.
//
// Deprecated: the CurveParams methods are deprecated and are not guaranteed to
// provide any security property. For ECDH, use the crypto/ecdh package.
// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
// from P224(), P256(), P384(), or P521().
func ( *CurveParams) ( []byte) (*big.Int, *big.Int) {
	// If there is a dedicated constant-time implementation for this curve operation,
	// use that instead of the generic one.
	if ,  := matchesSpecificCurve();  {
		return .ScalarBaseMult()
	}

	return .ScalarMult(.Gx, .Gy, )
}

func ( *CurveParams) (Curve, bool) {
	for ,  := range []Curve{p224, p256, p384, p521} {
		if  == .Params() {
			return , true
		}
	}
	return nil, false
}