package srp

import (
	
	
	

	
	
)

// Hash computes user password hash using parameters from server.
//
// See https://core.telegram.org/api/srp#checking-the-password-with-srp.
func ( SRP) (, ,  []byte,  Input) (Answer, error) {
	 := .bigFromBytes(.P)
	if  := checkInput(.G, );  != nil {
		return Answer{}, errors.Wrap(, "validate algo")
	}

	 := big.NewInt(int64(.G))
	// It is safe to use FillBytes directly because we know that 64-bit G always smaller than
	// 256-bit destination array.
	var  [256]byte
	.FillBytes([:])

	// random 2048-bit number a
	 := .bigFromBytes()

	// `g_a = pow(g, a) mod p`
	,  := .pad256FromBig(.bigExp(, , ))
	if ! {
		return Answer{}, errors.New("g_a is too big")
	}

	// `g_b = srp_B`
	 := .pad256()

	// `u = H(g_a | g_b)`
	 := .bigFromBytes(.hash([:], [:]))

	// `x = PH2(password, salt1, salt2)`
	// `v = pow(g, x) mod p`
	,  := .computeXV(, .Salt1, .Salt2, , )

	// `k = (k * v) mod p`
	 := .bigFromBytes(.hash(.P, [:]))

	// `k_v = (k * v) % p`
	 := .Mul(, ).Mod(, )

	// `t = (g_b - k_v) % p`
	 := .bigFromBytes()
	if .Sub(, ).Cmp(big.NewInt(0)) == -1 {
		.Add(, )
	}

	// `s_a = pow(t, a + u * x) mod p`
	,  := .pad256FromBig(.bigExp(, .Mul(, ).Add(, ), ))
	if ! {
		return Answer{}, errors.New("s_a is too big")
	}

	// `k_a = H(s_a)`
	 := sha256.Sum256([:])

	// `M1 = H(H(p) xor H(g) | H2(salt1) | H2(salt2) | g_a | g_b | k_a)`
	 := xor32(sha256.Sum256(.P), sha256.Sum256([:]))
	 := .hash(
		[:],
		.hash(.Salt1),
		.hash(.Salt2),
		[:],
		[:],
		[:],
	)

	return Answer{
		A:  [:],
		M1: ,
	}, nil
}

// The main hashing function H is sha256:
//
// H(data) := sha256(data)
func ( SRP) ( ...[]byte) []byte {
	 := sha256.New()
	for  := range  {
		.Write([])
	}
	return .Sum(nil)
}

// The salting hashing function SH is defined as follows:
//
// SH(data, salt) := H(salt | data | salt)
func ( SRP) (,  []byte) []byte {
	return .hash(, , )
}

// The primary password hashing function is defined as follows:
//
// PH1(password, salt1, salt2) := SH(SH(password, salt1), salt2)
func ( SRP) (, ,  []byte) []byte {
	return .saltHash(.saltHash(, ), )
}

// The secondary password hashing function is defined as follows:
//
// PH2(password, salt1, salt2) := SH(pbkdf2(sha512, PH1(password, salt1, salt2), salt1, 100000), salt2)
func ( SRP) (, ,  []byte) []byte {
	return .saltHash(.pbkdf2(.primary(, , ), , 100000), )
}

func ( SRP) (,  []byte,  int) []byte {
	return pbkdf2.Key(, , , 64, sha512.New)
}