https://github.com/python/cpython/commit/d6da6803a1a20cc34795c501b7cdb6b53b6a23b6
commit: d6da6803a1a20cc34795c501b7cdb6b53b6a23b6
branch: main
author: Serhiy Storchaka <storch...@gmail.com>
committer: serhiy-storchaka <storch...@gmail.com>
date: 2025-04-29T16:16:05+03:00
summary:

gh-132987: Support __index__() in hashlib.scrypt() (GH-133100)

Even if such signature is not supported by PyArg_ParseTupleAndKeywords(),
Argument Clinic supports it with inlined converters.

files:
M Modules/_hashopenssl.c
M Modules/clinic/_hashopenssl.c.h

diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
index 469a39cde7a2f7..48eed5eac975ed 100644
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -1388,19 +1388,15 @@ pbkdf2_hmac_impl(PyObject *module, const char 
*hash_name,
 
 #ifdef PY_OPENSSL_HAS_SCRYPT
 
-/* XXX: Parameters salt, n, r and p should be required keyword-only parameters.
-   They are optional in the Argument Clinic declaration only due to a
-   limitation of PyArg_ParseTupleAndKeywords. */
-
 /*[clinic input]
 _hashlib.scrypt
 
     password: Py_buffer
     *
-    salt: Py_buffer = None
-    n as n_obj: object(subclass_of='&PyLong_Type') = None
-    r as r_obj: object(subclass_of='&PyLong_Type') = None
-    p as p_obj: object(subclass_of='&PyLong_Type') = None
+    salt: Py_buffer
+    n: unsigned_long
+    r: unsigned_long
+    p: unsigned_long
     maxmem: long = 0
     dklen: long = 64
 
@@ -1410,14 +1406,13 @@ scrypt password-based key derivation function.
 
 static PyObject *
 _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
-                     PyObject *n_obj, PyObject *r_obj, PyObject *p_obj,
+                     unsigned long n, unsigned long r, unsigned long p,
                      long maxmem, long dklen)
-/*[clinic end generated code: output=14849e2aa2b7b46c input=48a7d63bf3f75c42]*/
+/*[clinic end generated code: output=d424bc3e8c6b9654 input=0c9a84230238fd79]*/
 {
     PyObject *key_obj = NULL;
     char *key;
     int retval;
-    unsigned long n, r, p;
 
     if (password->len > INT_MAX) {
         PyErr_SetString(PyExc_OverflowError,
@@ -1425,43 +1420,18 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer 
*password, Py_buffer *salt,
         return NULL;
     }
 
-    if (salt->buf == NULL) {
-        PyErr_SetString(PyExc_TypeError,
-                        "salt is required");
-        return NULL;
-    }
     if (salt->len > INT_MAX) {
         PyErr_SetString(PyExc_OverflowError,
                         "salt is too long.");
         return NULL;
     }
 
-    n = PyLong_AsUnsignedLong(n_obj);
-    if (n == (unsigned long) -1 && PyErr_Occurred()) {
-        PyErr_SetString(PyExc_TypeError,
-                        "n is required and must be an unsigned int");
-        return NULL;
-    }
     if (n < 2 || n & (n - 1)) {
         PyErr_SetString(PyExc_ValueError,
                         "n must be a power of 2.");
         return NULL;
     }
 
-    r = PyLong_AsUnsignedLong(r_obj);
-    if (r == (unsigned long) -1 && PyErr_Occurred()) {
-        PyErr_SetString(PyExc_TypeError,
-                        "r is required and must be an unsigned int");
-        return NULL;
-    }
-
-    p = PyLong_AsUnsignedLong(p_obj);
-    if (p == (unsigned long) -1 && PyErr_Occurred()) {
-        PyErr_SetString(PyExc_TypeError,
-                        "p is required and must be an unsigned int");
-        return NULL;
-    }
-
     if (maxmem < 0 || maxmem > INT_MAX) {
         /* OpenSSL 1.1.0 restricts maxmem to 32 MiB. It may change in the
            future. The maxmem constant is private to OpenSSL. */
diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h
index bfb2d9afc870a1..59ab46ca3f0978 100644
--- a/Modules/clinic/_hashopenssl.c.h
+++ b/Modules/clinic/_hashopenssl.c.h
@@ -7,6 +7,7 @@ preserve
 #  include "pycore_runtime.h"     // _Py_ID()
 #endif
 #include "pycore_abstract.h"      // _PyNumber_Index()
+#include "pycore_long.h"          // _PyLong_UnsignedLong_Converter()
 #include "pycore_modsupport.h"    // _PyArg_UnpackKeywords()
 
 PyDoc_STRVAR(EVP_copy__doc__,
@@ -1381,8 +1382,7 @@ pbkdf2_hmac(PyObject *module, PyObject *const *args, 
Py_ssize_t nargs, PyObject
 #if defined(PY_OPENSSL_HAS_SCRYPT)
 
 PyDoc_STRVAR(_hashlib_scrypt__doc__,
-"scrypt($module, /, password, *, salt=None, n=None, r=None, p=None,\n"
-"       maxmem=0, dklen=64)\n"
+"scrypt($module, /, password, *, salt, n, r, p, maxmem=0, dklen=64)\n"
 "--\n"
 "\n"
 "scrypt password-based key derivation function.");
@@ -1392,7 +1392,7 @@ PyDoc_STRVAR(_hashlib_scrypt__doc__,
 
 static PyObject *
 _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
-                     PyObject *n_obj, PyObject *r_obj, PyObject *p_obj,
+                     unsigned long n, unsigned long r, unsigned long p,
                      long maxmem, long dklen);
 
 static PyObject *
@@ -1427,63 +1427,37 @@ _hashlib_scrypt(PyObject *module, PyObject *const 
*args, Py_ssize_t nargs, PyObj
     };
     #undef KWTUPLE
     PyObject *argsbuf[7];
-    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 
1;
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 
5;
     Py_buffer password = {NULL, NULL};
     Py_buffer salt = {NULL, NULL};
-    PyObject *n_obj = Py_None;
-    PyObject *r_obj = Py_None;
-    PyObject *p_obj = Py_None;
+    unsigned long n;
+    unsigned long r;
+    unsigned long p;
     long maxmem = 0;
     long dklen = 64;
 
     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
-            /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+            /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 4, /*varpos*/ 0, argsbuf);
     if (!args) {
         goto exit;
     }
     if (PyObject_GetBuffer(args[0], &password, PyBUF_SIMPLE) != 0) {
         goto exit;
     }
-    if (!noptargs) {
-        goto skip_optional_kwonly;
+    if (PyObject_GetBuffer(args[1], &salt, PyBUF_SIMPLE) != 0) {
+        goto exit;
     }
-    if (args[1]) {
-        if (PyObject_GetBuffer(args[1], &salt, PyBUF_SIMPLE) != 0) {
-            goto exit;
-        }
-        if (!--noptargs) {
-            goto skip_optional_kwonly;
-        }
+    if (!_PyLong_UnsignedLong_Converter(args[2], &n)) {
+        goto exit;
     }
-    if (args[2]) {
-        if (!PyLong_Check(args[2])) {
-            _PyArg_BadArgument("scrypt", "argument 'n'", "int", args[2]);
-            goto exit;
-        }
-        n_obj = args[2];
-        if (!--noptargs) {
-            goto skip_optional_kwonly;
-        }
+    if (!_PyLong_UnsignedLong_Converter(args[3], &r)) {
+        goto exit;
     }
-    if (args[3]) {
-        if (!PyLong_Check(args[3])) {
-            _PyArg_BadArgument("scrypt", "argument 'r'", "int", args[3]);
-            goto exit;
-        }
-        r_obj = args[3];
-        if (!--noptargs) {
-            goto skip_optional_kwonly;
-        }
+    if (!_PyLong_UnsignedLong_Converter(args[4], &p)) {
+        goto exit;
     }
-    if (args[4]) {
-        if (!PyLong_Check(args[4])) {
-            _PyArg_BadArgument("scrypt", "argument 'p'", "int", args[4]);
-            goto exit;
-        }
-        p_obj = args[4];
-        if (!--noptargs) {
-            goto skip_optional_kwonly;
-        }
+    if (!noptargs) {
+        goto skip_optional_kwonly;
     }
     if (args[5]) {
         maxmem = PyLong_AsLong(args[5]);
@@ -1499,7 +1473,7 @@ _hashlib_scrypt(PyObject *module, PyObject *const *args, 
Py_ssize_t nargs, PyObj
         goto exit;
     }
 skip_optional_kwonly:
-    return_value = _hashlib_scrypt_impl(module, &password, &salt, n_obj, 
r_obj, p_obj, maxmem, dklen);
+    return_value = _hashlib_scrypt_impl(module, &password, &salt, n, r, p, 
maxmem, dklen);
 
 exit:
     /* Cleanup for password */
@@ -1897,4 +1871,4 @@ _hashlib_compare_digest(PyObject *module, PyObject *const 
*args, Py_ssize_t narg
 #ifndef _HASHLIB_SCRYPT_METHODDEF
     #define _HASHLIB_SCRYPT_METHODDEF
 #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */
-/*[clinic end generated code: output=d908fa85e0251426 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=2c78822e38be64a8 input=a9049054013a1b77]*/

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to