// Copyright 2022 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 ecdsa

import (
	
	
	
	

	
	
)

// This file contains a math/big implementation of ECDSA that is only used for
// deprecated custom curves.

func generateLegacy( elliptic.Curve,  io.Reader) (*PrivateKey, error) {
	,  := randFieldElement(, )
	if  != nil {
		return nil, 
	}

	 := new(PrivateKey)
	.PublicKey.Curve = 
	.D = 
	.PublicKey.X, .PublicKey.Y = .ScalarBaseMult(.Bytes())
	return , nil
}

// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4,
// we use the left-most bits of the hash to match the bit-length of the order of
// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3.
func hashToInt( []byte,  elliptic.Curve) *big.Int {
	 := .Params().N.BitLen()
	 := ( + 7) / 8
	if len() >  {
		 = [:]
	}

	 := new(big.Int).SetBytes()
	 := len()*8 - 
	if  > 0 {
		.Rsh(, uint())
	}
	return 
}

var errZeroParam = errors.New("zero parameter")

// Sign signs a hash (which should be the result of hashing a larger message)
// using the private key, priv. If the hash is longer than the bit-length of the
// private key's curve order, the hash will be truncated to that length. It
// returns the signature as a pair of integers. Most applications should use
// [SignASN1] instead of dealing directly with r, s.
func ( io.Reader,  *PrivateKey,  []byte) (,  *big.Int,  error) {
	,  := SignASN1(, , )
	if  != nil {
		return nil, nil, 
	}

	,  = new(big.Int), new(big.Int)
	var  cryptobyte.String
	 := cryptobyte.String()
	if !.ReadASN1(&, asn1.SEQUENCE) ||
		!.Empty() ||
		!.ReadASN1Integer() ||
		!.ReadASN1Integer() ||
		!.Empty() {
		return nil, nil, errors.New("invalid ASN.1 from SignASN1")
	}
	return , , nil
}

func signLegacy( *PrivateKey,  io.Reader,  []byte) ( []byte,  error) {
	 := .Curve

	// SEC 1, Version 2.0, Section 4.1.3
	 := .Params().N
	if .Sign() == 0 {
		return nil, errZeroParam
	}
	var , , ,  *big.Int
	for {
		for {
			,  = randFieldElement(, )
			if  != nil {
				return nil, 
			}

			 = new(big.Int).ModInverse(, )

			, _ = .ScalarBaseMult(.Bytes())
			.Mod(, )
			if .Sign() != 0 {
				break
			}
		}

		 := hashToInt(, )
		 = new(big.Int).Mul(.D, )
		.Add(, )
		.Mul(, )
		.Mod(, ) // N != 0
		if .Sign() != 0 {
			break
		}
	}

	return encodeSignature(.Bytes(), .Bytes())
}

// Verify verifies the signature in r, s of hash using the public key, pub. Its
// return value records whether the signature is valid. Most applications should
// use VerifyASN1 instead of dealing directly with r, s.
func ( *PublicKey,  []byte, ,  *big.Int) bool {
	if .Sign() <= 0 || .Sign() <= 0 {
		return false
	}
	,  := encodeSignature(.Bytes(), .Bytes())
	if  != nil {
		return false
	}
	return VerifyASN1(, , )
}

func verifyLegacy( *PublicKey,  []byte,  []byte) bool {
	, ,  := parseSignature()
	if  != nil {
		return false
	}
	,  := new(big.Int).SetBytes(), new(big.Int).SetBytes()

	 := .Curve
	 := .Params().N

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

	// SEC 1, Version 2.0, Section 4.1.4
	 := hashToInt(, )
	 := new(big.Int).ModInverse(, )

	 := .Mul(, )
	.Mod(, )
	 := .Mul(, )
	.Mod(, )

	,  := .ScalarBaseMult(.Bytes())
	,  := .ScalarMult(.X, .Y, .Bytes())
	,  := .Add(, , , )

	if .Sign() == 0 && .Sign() == 0 {
		return false
	}
	.Mod(, )
	return .Cmp() == 0
}

var one = new(big.Int).SetInt64(1)

// randFieldElement returns a random element of the order of the given
// curve using the procedure given in FIPS 186-4, Appendix B.5.2.
func randFieldElement( elliptic.Curve,  io.Reader) ( *big.Int,  error) {
	// See randomPoint for notes on the algorithm. This has to match, or s390x
	// signatures will come out different from other architectures, which will
	// break TLS recorded tests.
	for {
		 := .Params().N
		 := make([]byte, (.BitLen()+7)/8)
		if _,  = io.ReadFull(, );  != nil {
			return
		}
		if  := len()*8 - .BitLen();  > 0 {
			[0] >>= 
		}
		 = new(big.Int).SetBytes()
		if .Sign() != 0 && .Cmp() < 0 {
			return
		}
	}
}