package crypto

import (
	

	
)

// Side on which encryption is performed.
type Side byte

const (
	// Client side of encryption (e.g. messages from client).
	Client Side = 0
	// Server side of encryption (e.g. RPC responses).
	Server Side = 1
)

// DecryptSide returns Side for decryption.
func ( Side) () Side {
	return  ^ 1 // flips bit, so 0 becomes 1, 1 becomes 0
}

func ( Side) int {
	switch  {
	case Client:
		return 0
	case Server:
		return 8
	default:
		return 0
	}
}

// Message keys are defined here:
// * https://core.telegram.org/mtproto/description#defining-aes-key-and-initialization-vector

// msgKeyLarge returns msg_key_large value.
func ( []byte,  Key,  []byte,  Side) []byte {
	 := sha256.New()

	 := getX()
	_, _ = .Write([88+ : 32+88+])
	_, _ = .Write()
	return .Sum()
}

// messageKey returns msg_key = substr (msg_key_large, 8, 16).
func ( []byte) ( bin.Int128) {
	 := [8 : 16+8]
	copy([:len()], )
	return 
}

// sha256a returns sha256_a value.
//
// sha256_a = SHA256 (msg_key + substr (auth_key, x, 36));
func ( []byte,  *Key,  *bin.Int128,  int) []byte {
	 := sha256.New()

	_, _ = .Write([:])
	_, _ = .Write([ : +36])

	return .Sum()
}

// sha256b returns sha256_b value.
//
// sha256_b = SHA256 (substr (auth_key, 40+x, 36) + msg_key);
func ( []byte,  *Key,  *bin.Int128,  int) []byte {
	 := sha256.New()

	_, _ = .Write([40+ : 40++36])
	_, _ = .Write([:])

	return .Sum()
}

// aesKey returns aes_key value.
//
// aes_key = substr (sha256_a, 0, 8) + substr (sha256_b, 8, 16) + substr (sha256_a, 24, 8);
func (,  []byte,  *bin.Int256) {
	copy([:8], [:8])
	copy([8:], [8:16+8])
	copy([24:], [24:24+8])
}

// aesIV returns aes_iv value.
//
// aes_iv = substr (sha256_b, 0, 8) + substr (sha256_a, 8, 16) + substr (sha256_b, 24, 8);
func (,  []byte,  *bin.Int256) {
	// Same as aes_key, but with swapped params.
	aesKey(, , )
}

// Keys returns (aes_key, aes_iv) pair for AES-IGE.
//
// See https://core.telegram.org/mtproto/description#defining-aes-key-and-initialization-vector
//
// Example:
//
//	key, iv := crypto.Keys(authKey, messageKey, crypto.Client)
//	cipher, err := aes.NewCipher(key[:])
//	if err != nil {
//		return nil, err
//	}
//	encryptor := ige.NewIGEEncrypter(cipher, iv[:])
func ( Key,  bin.Int128,  Side) (,  bin.Int256) {
	 := getX()

	 := make([]byte, 512)
	// `sha256_a = SHA256 (msg_key + substr (auth_key, x, 36));`
	 := sha256a([0:0], &, &, )
	// `sha256_b = SHA256 (substr (auth_key, 40+x, 36) + msg_key);`
	 := sha256b([256:256], &, &, )

	aesKey(, , &)
	aesIV(, , &)
	return , 
}

// MessageKey computes message key for provided auth_key and padded payload.
func ( Key,  []byte,  Side) bin.Int128 {
	 := make([]byte, 0, 256)
	// `msg_key_large = SHA256 (substr (auth_key, 88+x, 32) + plaintext + random_padding);`
	 := msgKeyLarge(, , , )
	// `msg_key = substr (msg_key_large, 8, 16);`
	return messageKey()
}