Refs #3331 -- added initial wycheproof integration, starting with x25519, rsa, and keywrap (#4310)

* Refs #3331 -- added initial wycheproof integration, starting with x25519 tests
diff --git a/tests/utils.py b/tests/utils.py
index b721f34..ccc3b7c 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -6,7 +6,9 @@
 
 import binascii
 import collections
+import json
 import math
+import os
 import re
 from contextlib import contextmanager
 
@@ -884,3 +886,42 @@
             test_data[name.lower()] = value.encode("ascii")
 
     return data
+
+
+class WycheproofTest(object):
+    def __init__(self, testgroup, testcase):
+        self.testgroup = testgroup
+        self.testcase = testcase
+
+    def __repr__(self):
+        return "<WycheproofTest({!r}, {!r}, tcId={})>".format(
+            self.testgroup, self.testcase, self.testcase["tcId"],
+        )
+
+    @property
+    def valid(self):
+        return self.testcase["result"] == "valid"
+
+    @property
+    def acceptable(self):
+        return self.testcase["result"] == "acceptable"
+
+    def has_flag(self, flag):
+        return flag in self.testcase["flags"]
+
+
+def skip_if_wycheproof_none(wycheproof):
+    # This is factored into its own function so we can easily test both
+    # branches
+    if wycheproof is None:
+        pytest.skip("--wycheproof-root not provided")
+
+
+def load_wycheproof_tests(wycheproof, test_file):
+    path = os.path.join(wycheproof, "testvectors", test_file)
+    with open(path) as f:
+        data = json.load(f)
+        for group in data["testGroups"]:
+            cases = group.pop("tests")
+            for c in cases:
+                yield WycheproofTest(group, c)