@@ -542,6 +542,51 @@ static PyObject *b_KeyFromBitID(PyObject *cls, PyObject *args, PyObject *kwds) {
542542 return result ;
543543}
544544
545+ static PyObject * b_KeyRecoverPubKey (PyObject * cls , PyObject * args , PyObject * kwds ) {
546+ b_Key * result = NULL ;
547+ PyObject * message = NULL ;
548+ PyObject * signature = NULL ;
549+ static char * kwlist [] = { "message" , "signature" , NULL };
550+ if (!PyArg_ParseTupleAndKeywords (args , kwds , "OS" , kwlist , & message , & signature )) {
551+ return NULL ;
552+ }
553+ if (message == NULL || message == Py_None ) {
554+ PyErr_SetString (PyExc_ValueError , "message must not be NULL" );
555+ return NULL ;
556+ }
557+ UInt256 * toSign ;
558+ PyObject * msgBytes ;
559+ if (PyObject_IsInstance (message , (PyObject * )& PyBytes_Type )) {
560+ msgBytes = message ;
561+ } else if (PyCallable_Check (PyObject_GetAttrString (message , "digest" ))) {
562+ msgBytes = PyObject_CallMethod (message , "digest" , "" );
563+ if (!PyObject_IsInstance (msgBytes , (PyObject * )& PyBytes_Type )) {
564+ PyErr_SetString (PyExc_TypeError , "digest() must return a bytes object" );
565+ return NULL ;
566+ }
567+ } else {
568+ PyErr_SetString (PyExc_TypeError , "message must be either a bytes object with 32 bytes or a hash object "
569+ "with a digest() method" );
570+ return NULL ;
571+ }
572+ if (PyBytes_Size (msgBytes ) != 32 ) {
573+ PyErr_SetString (PyExc_ValueError , "must be 32 bytes of data (a UInt256)" );
574+ return NULL ;
575+ }
576+ toSign = (UInt256 * )PyBytes_AsString (msgBytes );
577+ BRKey * key = calloc (1 , sizeof (BRKey ));
578+ int keyLen = BRKeyRecoverPubKey (key , PyBytes_AsString (signature ), PyBytes_Size (signature ), * toSign );
579+ if (!keyLen ) {
580+ return Py_BuildValue ("" ); // unable to recover, return None
581+ }
582+
583+ result = (b_Key * )PyObject_CallFunction (cls , "" );
584+ if (result != NULL ) {
585+ result -> ob_fval = key ;
586+ }
587+ return (PyObject * )result ;
588+ }
589+
545590static PyObject * b_KeySign (b_Key * self , PyObject * args , PyObject * kwds ) {
546591 PyObject * message ;
547592 static char * kwlist [] = { "message" , NULL };
@@ -615,6 +660,43 @@ static PyObject *b_KeyVerify(b_Key *self, PyObject *args, PyObject *kwds) {
615660 return valid ? Py_True : Py_False ;
616661}
617662
663+ static PyObject * b_KeyCompactSign (b_Key * self , PyObject * args , PyObject * kwds ) {
664+ PyObject * message ;
665+ static char * kwlist [] = { "message" , NULL };
666+ if (!PyArg_ParseTupleAndKeywords (args , kwds , "O" , kwlist , & message )) {
667+ return NULL ;
668+ }
669+ if (message == NULL || message == Py_None ) {
670+ PyErr_SetString (PyExc_ValueError , "message must not be NULL" );
671+ return NULL ;
672+ }
673+ UInt256 * toSign ;
674+ PyObject * msgBytes ;
675+ if (PyObject_IsInstance (message , (PyObject * )& PyBytes_Type )) {
676+ msgBytes = message ;
677+ } else if (PyCallable_Check (PyObject_GetAttrString (message , "digest" ))) {
678+ msgBytes = PyObject_CallMethod (message , "digest" , "" );
679+ if (!PyObject_IsInstance (msgBytes , (PyObject * )& PyBytes_Type )) {
680+ PyErr_SetString (PyExc_TypeError , "digest() must return a bytes object" );
681+ return NULL ;
682+ }
683+ } else {
684+ PyErr_SetString (PyExc_TypeError , "message must be either a bytes object with 32 bytes or a hash object "
685+ "with a digest() method" );
686+ return NULL ;
687+ }
688+ if (PyBytes_Size (msgBytes ) != 32 ) {
689+ PyErr_SetString (PyExc_ValueError , "must be 32 bytes of data (a UInt256)" );
690+ return NULL ;
691+ }
692+
693+ toSign = (UInt256 * )PyBytes_AsString (msgBytes );
694+ uint8_t sig [72 ];
695+ size_t sigLen = BRKeyCompactSign (self -> ob_fval , sig , sizeof (sig ), * toSign );
696+ PyObject * ret = PyBytes_FromStringAndSize ((const char * )& sig , sigLen );
697+ return ret ;
698+ }
699+
618700static PyObject * b_KeyPrivKeyIsValid (PyObject * cls , PyObject * args , PyObject * kwds ) {
619701 PyObject * result = Py_False ;
620702 char * pk ;
@@ -773,11 +855,15 @@ static PyMethodDef b_KeyMethods[] = {
773855 /* Class Methods */
774856 {"from_bitid" , (PyCFunction )b_KeyFromBitID , (METH_VARARGS | METH_KEYWORDS | METH_CLASS ),
775857 "generate a bitid Key from a seed and some bitid parameters" },
858+ {"recover_pubkey" , (PyCFunction )b_KeyRecoverPubKey , (METH_VARARGS | METH_KEYWORDS | METH_CLASS ),
859+ "recover a public key from a compact signature" },
776860 {"privkey_is_valid" , (PyCFunction )b_KeyPrivKeyIsValid , (METH_VARARGS | METH_KEYWORDS | METH_CLASS ),
777861 "determine whether or not a serialized private key is valid" },
778862 /* Instance Methods */
779863 {"sign" , (PyCFunction )b_KeySign , (METH_VARARGS | METH_KEYWORDS ),
780864 "sign a bytes or an object with a digest() method" },
865+ {"sign_compact" , (PyCFunction )b_KeyCompactSign , (METH_VARARGS | METH_KEYWORDS ),
866+ "sign some bytes (or an object with the digest() method) using the compact signature format" },
781867 {"verify" , (PyCFunction )b_KeyVerify , (METH_VARARGS | METH_KEYWORDS ),
782868 "verify the message signature was made by this key" },
783869 {NULL }
0 commit comments