import sys
from typing import Callable, Any, TypeVar, NamedTuple
from math import floor
from itertools import count

import aws_cryptography_primitives.internaldafny.generated.module_ as module_
import _dafny as _dafny
import System_ as System_
import smithy_dafny_standard_library.internaldafny.generated.Wrappers as Wrappers
import smithy_dafny_standard_library.internaldafny.generated.Relations as Relations
import smithy_dafny_standard_library.internaldafny.generated.Seq_MergeSort as Seq_MergeSort
import smithy_dafny_standard_library.internaldafny.generated.Math as Math
import smithy_dafny_standard_library.internaldafny.generated.Seq as Seq
import smithy_dafny_standard_library.internaldafny.generated.BoundedInts as BoundedInts
import smithy_dafny_standard_library.internaldafny.generated.Unicode as Unicode
import smithy_dafny_standard_library.internaldafny.generated.Functions as Functions
import smithy_dafny_standard_library.internaldafny.generated.Utf8EncodingForm as Utf8EncodingForm
import smithy_dafny_standard_library.internaldafny.generated.Utf16EncodingForm as Utf16EncodingForm
import smithy_dafny_standard_library.internaldafny.generated.UnicodeStrings as UnicodeStrings
import smithy_dafny_standard_library.internaldafny.generated.FileIO as FileIO
import smithy_dafny_standard_library.internaldafny.generated.GeneralInternals as GeneralInternals
import smithy_dafny_standard_library.internaldafny.generated.MulInternalsNonlinear as MulInternalsNonlinear
import smithy_dafny_standard_library.internaldafny.generated.MulInternals as MulInternals
import smithy_dafny_standard_library.internaldafny.generated.Mul as Mul
import smithy_dafny_standard_library.internaldafny.generated.ModInternalsNonlinear as ModInternalsNonlinear
import smithy_dafny_standard_library.internaldafny.generated.DivInternalsNonlinear as DivInternalsNonlinear
import smithy_dafny_standard_library.internaldafny.generated.ModInternals as ModInternals
import smithy_dafny_standard_library.internaldafny.generated.DivInternals as DivInternals
import smithy_dafny_standard_library.internaldafny.generated.DivMod as DivMod
import smithy_dafny_standard_library.internaldafny.generated.Power as Power
import smithy_dafny_standard_library.internaldafny.generated.Logarithm as Logarithm
import smithy_dafny_standard_library.internaldafny.generated.StandardLibraryInterop as StandardLibraryInterop
import smithy_dafny_standard_library.internaldafny.generated.StandardLibrary_UInt as StandardLibrary_UInt
import smithy_dafny_standard_library.internaldafny.generated.StandardLibrary_String as StandardLibrary_String
import smithy_dafny_standard_library.internaldafny.generated.StandardLibrary as StandardLibrary
import smithy_dafny_standard_library.internaldafny.generated.UUID as UUID
import smithy_dafny_standard_library.internaldafny.generated.UTF8 as UTF8
import smithy_dafny_standard_library.internaldafny.generated.Time as Time
import smithy_dafny_standard_library.internaldafny.generated.Streams as Streams
import smithy_dafny_standard_library.internaldafny.generated.Sorting as Sorting
import smithy_dafny_standard_library.internaldafny.generated.SortedSets as SortedSets
import smithy_dafny_standard_library.internaldafny.generated.HexStrings as HexStrings
import smithy_dafny_standard_library.internaldafny.generated.GetOpt as GetOpt
import smithy_dafny_standard_library.internaldafny.generated.FloatCompare as FloatCompare
import smithy_dafny_standard_library.internaldafny.generated.ConcurrentCall as ConcurrentCall
import smithy_dafny_standard_library.internaldafny.generated.Base64 as Base64
import smithy_dafny_standard_library.internaldafny.generated.Base64Lemmas as Base64Lemmas
import smithy_dafny_standard_library.internaldafny.generated.Actions as Actions
import smithy_dafny_standard_library.internaldafny.generated.DafnyLibraries as DafnyLibraries
import aws_cryptography_primitives.internaldafny.generated.AwsCryptographyPrimitivesTypes as AwsCryptographyPrimitivesTypes
import aws_cryptography_primitives.internaldafny.generated.ExternRandom as ExternRandom
import aws_cryptography_primitives.internaldafny.generated.Random as Random

# Module: AESEncryption

class default__:
    def  __init__(self):
        pass

    @staticmethod
    def EncryptionOutputFromByteSeq(s, encAlg):
        d_0_cipherText_ = _dafny.Seq((s)[:(len(s)) - ((encAlg).tagLength):])
        d_1_authTag_ = _dafny.Seq((s)[(len(s)) - ((encAlg).tagLength)::])
        return AwsCryptographyPrimitivesTypes.AESEncryptOutput_AESEncryptOutput(d_0_cipherText_, d_1_authTag_)

    @staticmethod
    def AESEncrypt(input):
        res: Wrappers.Result = Wrappers.Result.default(AwsCryptographyPrimitivesTypes.AESEncryptOutput.default())()
        d_0_valueOrError0_: Wrappers.Outcome = Wrappers.Outcome.default()()
        d_0_valueOrError0_ = Wrappers.default__.Need(((len((input).iv)) == (((input).encAlg).ivLength)) and ((len((input).key)) == (((input).encAlg).keyLength)), AwsCryptographyPrimitivesTypes.Error_AwsCryptographicPrimitivesError(_dafny.Seq("Request does not match algorithm.")))
        if (d_0_valueOrError0_).IsFailure():
            res = (d_0_valueOrError0_).PropagateFailure()
            return res
        let_tmp_rhs0_ = input
        d_1_encAlg_ = let_tmp_rhs0_.encAlg
        d_2_iv_ = let_tmp_rhs0_.iv
        d_3_key_ = let_tmp_rhs0_.key
        d_4_msg_ = let_tmp_rhs0_.msg
        d_5_aad_ = let_tmp_rhs0_.aad
        d_6_valueOrError1_: Wrappers.Result = Wrappers.Result.default(AwsCryptographyPrimitivesTypes.AESEncryptOutput.default())()
        out0_: Wrappers.Result
        out0_ = AESEncryption.AES_GCM.AESEncryptExtern(d_1_encAlg_, d_2_iv_, d_3_key_, d_4_msg_, d_5_aad_)
        d_6_valueOrError1_ = out0_
        if (d_6_valueOrError1_).IsFailure():
            res = (d_6_valueOrError1_).PropagateFailure()
            return res
        d_7_value_: AwsCryptographyPrimitivesTypes.AESEncryptOutput
        d_7_value_ = (d_6_valueOrError1_).Extract()
        d_8_valueOrError2_: Wrappers.Outcome = Wrappers.Outcome.default()()
        d_8_valueOrError2_ = Wrappers.default__.Need((len((d_7_value_).cipherText)) == (len(d_4_msg_)), AwsCryptographyPrimitivesTypes.Error_AwsCryptographicPrimitivesError(_dafny.Seq("AESEncrypt did not return cipherText of expected length")))
        if (d_8_valueOrError2_).IsFailure():
            res = (d_8_valueOrError2_).PropagateFailure()
            return res
        d_9_valueOrError3_: Wrappers.Outcome = Wrappers.Outcome.default()()
        d_9_valueOrError3_ = Wrappers.default__.Need((len((d_7_value_).authTag)) == ((d_1_encAlg_).tagLength), AwsCryptographyPrimitivesTypes.Error_AwsCryptographicPrimitivesError(_dafny.Seq("AESEncryption did not return valid tag")))
        if (d_9_valueOrError3_).IsFailure():
            res = (d_9_valueOrError3_).PropagateFailure()
            return res
        res = Wrappers.Result_Success(d_7_value_)
        return res
        return res

    @staticmethod
    def AESDecrypt(input):
        res: Wrappers.Result = Wrappers.Result.default(_dafny.Seq)()
        d_0_valueOrError0_: Wrappers.Outcome = Wrappers.Outcome.default()()
        d_0_valueOrError0_ = Wrappers.default__.Need((((len((input).key)) == (((input).encAlg).keyLength)) and ((len((input).iv)) == (((input).encAlg).ivLength))) and ((len((input).authTag)) == (((input).encAlg).tagLength)), AwsCryptographyPrimitivesTypes.Error_AwsCryptographicPrimitivesError(_dafny.Seq("Request does not match algorithm.")))
        if (d_0_valueOrError0_).IsFailure():
            res = (d_0_valueOrError0_).PropagateFailure()
            return res
        let_tmp_rhs0_ = input
        d_1_encAlg_ = let_tmp_rhs0_.encAlg
        d_2_key_ = let_tmp_rhs0_.key
        d_3_cipherTxt_ = let_tmp_rhs0_.cipherTxt
        d_4_authTag_ = let_tmp_rhs0_.authTag
        d_5_iv_ = let_tmp_rhs0_.iv
        d_6_aad_ = let_tmp_rhs0_.aad
        d_7_valueOrError1_: Wrappers.Result = Wrappers.Result.default(_dafny.Seq)()
        out0_: Wrappers.Result
        out0_ = AESEncryption.AES_GCM.AESDecryptExtern(d_1_encAlg_, d_2_key_, d_3_cipherTxt_, d_4_authTag_, d_5_iv_, d_6_aad_)
        d_7_valueOrError1_ = out0_
        if (d_7_valueOrError1_).IsFailure():
            res = (d_7_valueOrError1_).PropagateFailure()
            return res
        d_8_value_: _dafny.Seq
        d_8_value_ = (d_7_valueOrError1_).Extract()
        d_9_valueOrError2_: Wrappers.Outcome = Wrappers.Outcome.default()()
        d_9_valueOrError2_ = Wrappers.default__.Need((len(d_3_cipherTxt_)) == (len(d_8_value_)), AwsCryptographyPrimitivesTypes.Error_AwsCryptographicPrimitivesError(_dafny.Seq("AESDecrypt did not return plaintext of expected length")))
        if (d_9_valueOrError2_).IsFailure():
            res = (d_9_valueOrError2_).PropagateFailure()
            return res
        res = Wrappers.Result_Success(d_8_value_)
        return res
        return res

    @staticmethod
    def CreateAESEncryptExternSuccess(output):
        return Wrappers.Result_Success(output)

    @staticmethod
    def CreateAESEncryptExternFailure(error):
        return Wrappers.Result_Failure(error)

    @staticmethod
    def CreateAESDecryptExternSuccess(bytes):
        return Wrappers.Result_Success(bytes)

    @staticmethod
    def CreateAESDecryptExternFailure(error):
        return Wrappers.Result_Failure(error)

