// Copyright 2020-2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package secp256k1

// References:
//   [SECG]: Recommended Elliptic Curve Domain Parameters
//     https://www.secg.org/sec2-v2.pdf
//
//   [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)

import (
	
	
	
)

// CurveParams contains the parameters for the secp256k1 curve.
type CurveParams struct {
	// P is the prime used in the secp256k1 field.
	P *big.Int

	// N is the order of the secp256k1 curve group generated by the base point.
	N *big.Int

	// Gx and Gy are the x and y coordinate of the base point, respectively.
	Gx, Gy *big.Int

	// BitSize is the size of the underlying secp256k1 field in bits.
	BitSize int

	// H is the cofactor of the secp256k1 curve.
	H int

	// ByteSize is simply the bit size / 8 and is provided for convenience
	// since it is calculated repeatedly.
	ByteSize int
}

// Curve parameters taken from [SECG] section 2.4.1.
var curveParams = CurveParams{
	P:        fromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),
	N:        fromHex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),
	Gx:       fromHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
	Gy:       fromHex("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"),
	BitSize:  256,
	H:        1,
	ByteSize: 256 / 8,
}

// Params returns the secp256k1 curve parameters for convenience.
func () *CurveParams {
	return &curveParams
}

// KoblitzCurve provides an implementation for secp256k1 that fits the ECC Curve
// interface from crypto/elliptic.
type KoblitzCurve struct {
	*elliptic.CurveParams
}

// bigAffineToJacobian takes an affine point (x, y) as big integers and converts
// it to Jacobian point with Z=1.
func bigAffineToJacobian(,  *big.Int,  *JacobianPoint) {
	.X.SetByteSlice(.Bytes())
	.Y.SetByteSlice(.Bytes())
	.Z.SetInt(1)
}

// jacobianToBigAffine takes a Jacobian point (x, y, z) as field values and
// converts it to an affine point as big integers.
func jacobianToBigAffine( *JacobianPoint) (*big.Int, *big.Int) {
	.ToAffine()

	// Convert the field values for the now affine point to big.Ints.
	,  := new(big.Int), new(big.Int)
	.SetBytes(.X.Bytes()[:])
	.SetBytes(.Y.Bytes()[:])
	return , 
}

// Params returns the parameters for the curve.
//
// This is part of the elliptic.Curve interface implementation.
func ( *KoblitzCurve) () *elliptic.CurveParams {
	return .CurveParams
}

// IsOnCurve returns whether or not the affine point (x,y) is on the curve.
//
// This is part of the elliptic.Curve interface implementation.  This function
// differs from the crypto/elliptic algorithm since a = 0 not -3.
func ( *KoblitzCurve) (,  *big.Int) bool {
	// Convert big ints to a Jacobian point for faster arithmetic.
	var  JacobianPoint
	bigAffineToJacobian(, , &)
	return isOnCurve(&.X, &.Y)
}

// Add returns the sum of (x1,y1) and (x2,y2).
//
// This is part of the elliptic.Curve interface implementation.
func ( *KoblitzCurve) (, , ,  *big.Int) (*big.Int, *big.Int) {
	// The point at infinity is the identity according to the group law for
	// elliptic curve cryptography.  Thus, ∞ + P = P and P + ∞ = P.
	if .Sign() == 0 && .Sign() == 0 {
		return , 
	}
	if .Sign() == 0 && .Sign() == 0 {
		return , 
	}

	// Convert the affine coordinates from big integers to Jacobian points,
	// do the point addition in Jacobian projective space, and convert the
	// Jacobian point back to affine big.Ints.
	var , ,  JacobianPoint
	bigAffineToJacobian(, , &)
	bigAffineToJacobian(, , &)
	AddNonConst(&, &, &)
	return jacobianToBigAffine(&)
}

// Double returns 2*(x1,y1).
//
// This is part of the elliptic.Curve interface implementation.
func ( *KoblitzCurve) (,  *big.Int) (*big.Int, *big.Int) {
	if .Sign() == 0 {
		return new(big.Int), new(big.Int)
	}

	// Convert the affine coordinates from big integers to Jacobian points,
	// do the point doubling in Jacobian projective space, and convert the
	// Jacobian point back to affine big.Ints.
	var ,  JacobianPoint
	bigAffineToJacobian(, , &)
	DoubleNonConst(&, &)
	return jacobianToBigAffine(&)
}

// moduloReduce reduces k from more than 32 bytes to 32 bytes and under.  This
// is done by doing a simple modulo curve.N.  We can do this since G^N = 1 and
// thus any other valid point on the elliptic curve has the same order.
func moduloReduce( []byte) []byte {
	// Since the order of G is curve.N, we can use a much smaller number by
	// doing modulo curve.N
	if len() > curveParams.ByteSize {
		 := new(big.Int).SetBytes()
		.Mod(, curveParams.N)
		return .Bytes()
	}

	return 
}

// ScalarMult returns k*(bx, by) where k is a big endian integer.
//
// This is part of the elliptic.Curve interface implementation.
func ( *KoblitzCurve) (,  *big.Int,  []byte) (*big.Int, *big.Int) {
	// Convert the affine coordinates from big integers to Jacobian points,
	// do the multiplication in Jacobian projective space, and convert the
	// Jacobian point back to affine big.Ints.
	var  ModNScalar
	.SetByteSlice(moduloReduce())
	var ,  JacobianPoint
	bigAffineToJacobian(, , &)
	ScalarMultNonConst(&, &, &)
	return jacobianToBigAffine(&)
}

// ScalarBaseMult returns k*G where G is the base point of the group and k is a
// big endian integer.
//
// This is part of the elliptic.Curve interface implementation.
func ( *KoblitzCurve) ( []byte) (*big.Int, *big.Int) {
	// Perform the multiplication and convert the Jacobian point back to affine
	// big.Ints.
	var  ModNScalar
	.SetByteSlice(moduloReduce())
	var  JacobianPoint
	ScalarBaseMultNonConst(&, &)
	return jacobianToBigAffine(&)
}

// X returns the x coordinate of the public key.
func ( *PublicKey) () *big.Int {
	return new(big.Int).SetBytes(.x.Bytes()[:])
}

// Y returns the y coordinate of the public key.
func ( *PublicKey) () *big.Int {
	return new(big.Int).SetBytes(.y.Bytes()[:])
}

// ToECDSA returns the public key as a *ecdsa.PublicKey.
func ( *PublicKey) () *ecdsa.PublicKey {
	return &ecdsa.PublicKey{
		Curve: S256(),
		X:     .X(),
		Y:     .Y(),
	}
}

// ToECDSA returns the private key as a *ecdsa.PrivateKey.
func ( *PrivateKey) () *ecdsa.PrivateKey {
	var  [PrivKeyBytesLen]byte
	.Key.PutBytes(&)
	var  JacobianPoint
	ScalarBaseMultNonConst(&.Key, &)
	,  := jacobianToBigAffine(&)
	 := &ecdsa.PrivateKey{
		PublicKey: ecdsa.PublicKey{
			Curve: S256(),
			X:     ,
			Y:     ,
		},
		D: new(big.Int).SetBytes([:]),
	}
	zeroArray32(&)
	return 
}

// fromHex converts the passed hex string into a big integer pointer and will
// panic is there is an error.  This is only provided for the hard-coded
// constants so errors in the source code can bet detected. It will only (and
// must only) be called for initialization purposes.
func fromHex( string) *big.Int {
	if  == "" {
		return big.NewInt(0)
	}
	,  := new(big.Int).SetString(, 16)
	if ! {
		panic("invalid hex in source file: " + )
	}
	return 
}

// secp256k1 is a global instance of the KoblitzCurve implementation which in
// turn embeds and implements elliptic.CurveParams.
var secp256k1 = &KoblitzCurve{
	CurveParams: &elliptic.CurveParams{
		P:       curveParams.P,
		N:       curveParams.N,
		B:       fromHex("0000000000000000000000000000000000000000000000000000000000000007"),
		Gx:      curveParams.Gx,
		Gy:      curveParams.Gy,
		BitSize: curveParams.BitSize,
		Name:    "secp256k1",
	},
}

// S256 returns an elliptic.Curve which implements secp256k1.
func () *KoblitzCurve {
	return secp256k1
}