#include <assert.h>
#include <string.h>

#include "proof.h"
#include "key-map.h"
#include "xalloc.h"

#include "test-utils.h"

/* TODO: Revise to not depend on ASCII parsers. */
int
main (void)
{
  static const struct {
    const char *proof;
    const char *log_key;
    const char *submitter_key;
    const char *witness_key;
  } valid[] = {
    {
      "version=2\n"
      "log=1f8d4547082a5985ad0e59ffe219f7a065e09c6b77a0012daf276e5dd1805b4b\n"
      "leaf=69512577a0f3c2695011ddc549756099017b7e2c8390341cbb24c57e886775f1 262737d935123272b9e3265fe2e38a014a9c1b13951e864737666251ada26dabbc6e699a4e527ec52a0be970e158abef35f087766d18d560853a44855119cf01\n"
      "\n"
      "size=4\n"
      "root_hash=7bca01e88737999fde5c1d6ecac27ae3cb49e14f21bcd3e7245c276877b899c9\n"
      "signature=c60e5151b9d0f0efaf57022c0ec306c0f0275afef69333cc89df4fda328c87949fcfa44564f35020938a4cd6c1c50bc0349b2f54b82f5f6104b9cd52be2cd90e\n"
      "\n"
      "leaf_index=3\n"
      "node_hash=e7d222a285ca81fdc76bfcd5513408c87dd42a18e03d6c3b672a05982163c01b\n"
      "node_hash=15cdc42440689a6f7599e09f61a4d638420cb58662f5994def1624ea4d923879\n",
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN6kw3w2BWjlKLdrtnv4IaN+zg8/RpKGA98AbbTwjpdQ",
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMCMTGNMNe1HP2us/dR5dBpyrSPDgPQ9mX5j9iqbLIS+",
      NULL
    }, {
      "version=2\n"
      "log=7c5fafc796c201e0fcd7567c5033a2777ec28363f54ea0ba97b57bece0d96acd\n"
      "leaf=8a578b9649ba01b7d29dd557906975d68a3aec50e3f9c08690420b8c6426856d 79b489a38548a67d78f06221b014d41be58b703237d17b4f203f0dd4ead9e2597149c2f118894581ce7473a61fa880716af6ff2138bade2cecc4b297099bf104\n"
      "\n"
      "size=4\n"
      "root_hash=3ddc56fd46e71e517b6936b977a457da7d398108141fcdf5c8386cdd724ab7a8\n"
      "signature=ccbdd8c784726b732b8edd2039fbad5506e4acccd56e3e5d86c0ee109b3d2662e6881fe3d09fc48f9ddd31494463c5ec44926ff9158785ad1dd9b5d6434b0804\n"
      "cosignature=bd8385aa82e07c3e1e297a1600c12bb25ce7a9490b5c1287ec30e09ac4c8b884 1683202758 e8d6c447d7847d5c1431ef86f8c60fa0cbacd975388b2a8f202fe4b0f9d0d544989c9d9351752d86aae2df72b9d7135b6b09de2ccaa6d68edf638105d69be609\n"
      "\n"
      "leaf_index=3\n"
      "node_hash=61010ae798308f5b97237615ab8c1b14f2c782c37616e97d0a170b617bc7a4ce\n"
      "node_hash=a5c3752be610d605ce5c64ee2e28ee5b94a1cc0a68742f18f24c9b5c82d07298\n",
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKwmwKhVrEUaZTlHjhoWA4jwJLOF8TY+/NpHAXAHbAHl",
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMdLcxVjCAQUHbD4jCfFP+f8v1nmyjWkq6rXiexrK8II",
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMvjV+a0ZASecDt75siSARk6zCoYwJWwaRqvULmx4VeK"
    }
  };
  for (size_t i = 0; i < sizeof (valid) / sizeof (valid[0]); i++)
    {
      struct sigsum_proof proof;
      struct sigsum_error err;
      if (!sigsum_proof_parse (&proof, strlen (valid[i].proof), valid[i].proof, &err.msg))
	die ("sigsum_proof_parse: failed for test %zu: %s", i, err.msg);

      struct sigsum_key_map submitters;
      if (!sigsum_key_map_parse_ssh (&submitters,
					  strlen (valid[i].submitter_key), valid[i].submitter_key,
					  &err))
	die ("sigsum_ssh_keys_parse: failed for test %zu: %s\nin: %s",
	     i, err.msg, valid[i].submitter_key);

      struct sigsum_policy policy;
      if (!sigsum_key_map_parse_ssh (&policy.logs,
					  strlen (valid[i].log_key), valid[i].log_key,
					  &err))
	die ("sigsum_ssh_keys_parse: failed for test %zu: %s\nin: %s",
	     i, err.msg, valid[i].log_key);

      uint8_t quorum;
      policy.quorum = (struct sigsum_quorum) { 1, &quorum, 1 };

      if (valid[i].witness_key)
	{
	  if (!sigsum_key_map_parse_ssh (&policy.witnesses,
					      strlen (valid[i].witness_key), valid[i].witness_key,
					      &err))
	    die ("sigsum_ssh_parse_public_key: failed for test %zu: %s\nin: %s",
		 i, err.msg, valid[i].witness_key);
	  quorum = 0x40;
	}
      else
	{
	  policy.witnesses = (struct sigsum_key_map) { 0, NULL };
	  quorum = 0x02;
	}

      struct sigsum_hash msg = {{
	  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
	  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'f', 'o', 'o', '-', '4', '\n',
	}};
      bool scratch[2];
      assert (sigsum_policy_verify_tree_head_itch (&policy) <= sizeof (scratch));

      if (!sigsum_proof_verify (&proof, &msg, &submitters, &policy, &err.msg, &scratch))
	die ("sigsum_proof_verify: failed test %zu: %s", i, err.msg);

      sigsum_proof_clear (&proof);
      XFREE (policy.logs.keys);
      XFREE (policy.witnesses.keys);
      XFREE (submitters.keys);
    }
  return 0;
}
