# Copyright 2013 Donald Stufft and individual contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import, division, print_function

import binascii

import pytest

from utils import assert_equal, assert_not_equal, read_crypto_test_vectors

from nacl.bindings import crypto_sign_PUBLICKEYBYTES, crypto_sign_SEEDBYTES
from nacl.encoding import Base64Encoder, HexEncoder
from nacl.exceptions import BadSignatureError
from nacl.signing import SignedMessage, SigningKey, VerifyKey


def tohex(b):
    return binascii.hexlify(b).decode("ascii")


def ed25519_known_answers():
    # Known answers taken from: http://ed25519.cr.yp.to/python/sign.input
    # hex-encoded fields on each input line: sk||pk, pk, msg, signature||msg
    # known answer fields: sk, pk, msg, signature, signed
    DATA = "ed25519"
    lines = read_crypto_test_vectors(DATA, delimiter=b":")
    return [
        (
            x[0][:64],  # secret key
            x[1],  # public key
            x[2],  # message
            x[3][:128],  # signature
            x[3],  # signed message
        )
        for x in lines
    ]


class TestSigningKey:
    def test_initialize_with_generate(self):
        SigningKey.generate()

    def test_wrong_length(self):
        with pytest.raises(ValueError):
            SigningKey(b"")

    def test_bytes(self):
        k = SigningKey(b"\x00" * crypto_sign_SEEDBYTES)
        assert bytes(k) == b"\x00" * crypto_sign_SEEDBYTES

    def test_equal_keys_are_equal(self):
        k1 = SigningKey(b"\x00" * crypto_sign_SEEDBYTES)
        k2 = SigningKey(b"\x00" * crypto_sign_SEEDBYTES)
        assert_equal(k1, k1)
        assert_equal(k1, k2)

    def test_equal_keys_have_equal_hashes(self):
        k1 = SigningKey(b"\x00" * crypto_sign_SEEDBYTES)
        k2 = SigningKey(b"\x00" * crypto_sign_SEEDBYTES)
        assert hash(k1) == hash(k2)
        assert id(k1) != id(k2)

    @pytest.mark.parametrize(
        "k2",
        [
            b"\x00" * crypto_sign_SEEDBYTES,
            SigningKey(b"\x01" * crypto_sign_SEEDBYTES),
            SigningKey(b"\x00" * (crypto_sign_SEEDBYTES - 1) + b"\x01"),
        ],
    )
    def test_different_keys_are_not_equal(self, k2):
        k1 = SigningKey(b"\x00" * crypto_sign_SEEDBYTES)
        assert_not_equal(k1, k2)

    @pytest.mark.parametrize(
        "seed",
        [b"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"],
    )
    def test_initialization_with_seed(self, seed):
        SigningKey(seed, encoder=HexEncoder)

    @pytest.mark.parametrize(
        ("seed", "_public_key", "message", "signature", "expected"),
        ed25519_known_answers(),
    )
    def test_message_signing(
        self, seed, _public_key, message, signature, expected
    ):