Index: django/utils/checksums.py
===================================================================
--- django/utils/checksums.py	(revision 0)
+++ django/utils/checksums.py	(revision 0)
@@ -0,0 +1,18 @@
+__all__ = ['luhn',]
+
+LUHN_ODD_LOOKUP = (0, 2, 4, 6, 8, 1, 3, 5, 7, 9) # sum_of_digits(index * 2) 
+
+def luhn(candidate):
+    """
+    Checks a candidate number for validity according to the Luhn
+    algorithm (used in validation of, for example, credit cards).
+    Both numeric and string candidates are accepted.
+    """
+    if not isinstance(candidate, basestring):
+        candidate = str(candidate)
+    try:
+        evens = sum([int(c) for c in candidate[-1::-2]]) 
+        odds = sum([LUHN_ODD_LOOKUP[int(c)] for c in candidate[-2::-2]]) 
+        return ((evens + odds) % 10 == 0)
+    except ValueError:  # Raised if an int conversion fails
+        return False
\ No newline at end of file
Index: tests/regressiontests/utils/tests.py
===================================================================
--- tests/regressiontests/utils/tests.py	(revision 6218)
+++ tests/regressiontests/utils/tests.py	(working copy)
@@ -4,7 +4,7 @@
 
 from unittest import TestCase
 
-from django.utils import html
+from django.utils import html, checksums
 
 class TestUtilsHtml(TestCase):
 
@@ -113,3 +113,29 @@
         )
         for value, output in items:
             self.check_output(f, value, output)
+
+class TestUtilsChecksums(TestCase):
+    
+    def check_output(self, function, value, output=None):
+        """
+        Check that function(value) equals output.  If output is None,
+        check that function(value) equals value.
+        """
+        if output is None:
+            output = value
+        self.assertEqual(function(value), output)
+    
+    def test_luhn(self):
+        f = checksums.luhn
+        items = (
+            (4111111111111111, True), ('4111111111111111', True), 
+            (4222222222222, True), (378734493671000, True),
+            (5424000000000015, True), (5555555555554444, True),
+            (1008, True), ('0000001008', True), ('000000001008', True), 
+            (4012888888881881, True), (1234567890123456789012345678909, True),
+            (4111111111211111, False), (42222222222224, False),
+            (100, False), ('100', False), ('0000100', False),
+            ('abc', False), (None, False), (object(), False),
+        )
+        for value, output in items:
+            self.check_output(f, value, output)
