diff --git a/src/_zkapauthorizer/_stack.py b/src/_zkapauthorizer/_stack.py
new file mode 100644
index 0000000000000000000000000000000000000000..6fffe2cd73a6d241322269101f32afef7dfc0d73
--- /dev/null
+++ b/src/_zkapauthorizer/_stack.py
@@ -0,0 +1,47 @@
+# Copyright 2019 PrivateStorage.io, LLC
+#
+# 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 contextlib import (
+    contextmanager,
+)
+
+try:
+    from resource import (
+        RLIMIT_STACK,
+        getrlimit,
+        setrlimit,
+    )
+except ImportError:
+    # Not available on Windows, unfortunately.
+    RLIMIT_STACK = object()
+    def getrlimit(which):
+        return (-1, -1)
+    def setrlimit(which, what):
+        pass
+
+
+
+@contextmanager
+def less_limited_stack():
+    """
+    A context manager which removes the resource limit on stack size, to the
+    extent possible, for execution of the context.
+
+    More precisely, the soft stack limit is raised to the hard limit.
+    """
+    soft, hard = getrlimit(RLIMIT_STACK)
+    # We can raise the soft limit to the hard limit and no higher.
+    setrlimit(RLIMIT_STACK, (hard, hard))
+    yield
+    setrlimit(RLIMIT_STACK, (soft, hard))
diff --git a/src/_zkapauthorizer/controller.py b/src/_zkapauthorizer/controller.py
index 693e3eb18956d6147a3777c014f747b88f3941c0..755397108ee0f10ef7cc8931a5818ccfba1da480 100644
--- a/src/_zkapauthorizer/controller.py
+++ b/src/_zkapauthorizer/controller.py
@@ -41,15 +41,6 @@ from base64 import (
     b64encode,
     b64decode,
 )
-from contextlib import (
-    contextmanager,
-)
-from resource import (
-    RLIMIT_STACK,
-    getrlimit,
-    setrlimit,
-)
-
 import attr
 
 from zope.interface import (
@@ -91,6 +82,9 @@ import privacypass
 from ._base64 import (
     urlsafe_b64decode,
 )
+from ._stack import (
+    less_limited_stack,
+)
 
 from .model import (
     RandomToken,
@@ -478,7 +472,7 @@ class RistrettoRedeemer(object):
         clients_proof = privacypass.BatchDLEQProof.decode_base64(
             marshaled_proof.encode("ascii"),
         )
-        with unlimited_stack():
+        with less_limited_stack():
             self._log.info("Decoded batch proof")
             clients_unblinded_tokens = clients_proof.invalid_or_unblind(
                 random_tokens,
@@ -806,16 +800,3 @@ def bracket(first, last, between):
     else:
         yield last()
         returnValue(result)
-
-
-@contextmanager
-def unlimited_stack():
-    """
-    A context manager which removes the resource limit on stack size for
-    execution of the context.
-    """
-    soft, hard = getrlimit(RLIMIT_STACK)
-    # We can raise the soft limit to the hard limit and no higher.
-    setrlimit(RLIMIT_STACK, (hard, hard))
-    yield
-    setrlimit(RLIMIT_STACK, (soft, hard))