// Copyright 2020 Chia Network Inc // 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. #include #include #include #include #include #include #include #include namespace py = pybind11; using namespace bls; PYBIND11_MODULE(blspy, m) { py::class_(m, "PrivateKey") .def_property_readonly_static( "PRIVATE_KEY_SIZE", [](py::object self) { return PrivateKey::PRIVATE_KEY_SIZE; }) .def( "from_bytes", [](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 1) throw std::runtime_error("Incompatible buffer format!"); if ((int)info.size != PrivateKey::PRIVATE_KEY_SIZE) { throw std::invalid_argument( "Length of bytes object not equal to PrivateKey::SIZE"); } auto data_ptr = reinterpret_cast(info.ptr); std::array data; std::copy(data_ptr, data_ptr + PrivateKey::PRIVATE_KEY_SIZE, data.data()); py::gil_scoped_release release; return PrivateKey::FromBytes(data); }) .def( "__bytes__", [](const PrivateKey &k) { uint8_t *output = Util::SecAlloc(PrivateKey::PRIVATE_KEY_SIZE); { py::gil_scoped_release release; k.Serialize(output); } py::bytes ret = py::bytes( reinterpret_cast(output), PrivateKey::PRIVATE_KEY_SIZE); Util::SecFree(output); return ret; }) .def( "__deepcopy__", [](const PrivateKey &k, const py::object &memo) { return PrivateKey(k); }) .def("get_g1", [](const PrivateKey &k) { py::gil_scoped_release release; return k.GetG1Element(); }) .def("aggregate", &PrivateKey::Aggregate, py::call_guard()) .def(py::self == py::self) .def(py::self != py::self) .def("__repr__", [](const PrivateKey &k) { py::gil_scoped_release release; uint8_t *output = Util::SecAlloc(PrivateKey::PRIVATE_KEY_SIZE); k.Serialize(output); std::string ret = ""; Util::SecFree(output); return ret; }); py::class_(m, "Util").def("hash256", [](const py::bytes &message) { std::string str(message); const uint8_t *input = reinterpret_cast(str.data()); uint8_t output[BLS::MESSAGE_HASH_LEN]; { py::gil_scoped_release release; Util::Hash256(output, (const uint8_t *)str.data(), str.size()); } return py::bytes( reinterpret_cast(output), BLS::MESSAGE_HASH_LEN); }); py::class_(m, "BasicSchemeMPL") .def("sk_to_g1", [](const PrivateKey &seckey){ py::gil_scoped_release release; return BasicSchemeMPL().SkToG1(seckey); }) .def( "key_gen", [](const py::bytes &b) { std::string str(b); py::gil_scoped_release release; const vector inputVec(str.begin(), str.end()); return BasicSchemeMPL().KeyGen(inputVec); }) .def("derive_child_sk", [](const PrivateKey& sk, uint32_t index){ py::gil_scoped_release release; return BasicSchemeMPL().DeriveChildSk(sk, index); }) .def("derive_child_sk_unhardened", [](const PrivateKey& sk, uint32_t index){ py::gil_scoped_release release; return BasicSchemeMPL().DeriveChildSkUnhardened(sk, index); }) .def("derive_child_pk_unhardened", [](const G1Element& pk, uint32_t index){ py::gil_scoped_release release; return BasicSchemeMPL().DeriveChildPkUnhardened(pk, index); }) .def("aggregate", [](const vector &signatures) { py::gil_scoped_release release; return BasicSchemeMPL().Aggregate(signatures); }) .def( "sign", [](const PrivateKey &pk, const py::bytes &msg) { std::string s(msg); py::gil_scoped_release release; vector v(s.begin(), s.end()); return BasicSchemeMPL().Sign(pk, v); }) .def( "verify", [](const G1Element &pk, const py::bytes &msg, const G2Element &sig) { std::string s(msg); py::gil_scoped_release release; vector v(s.begin(), s.end()); return BasicSchemeMPL().Verify(pk, v, sig); }) .def( "aggregate_verify", [](const vector &pks, const vector &msgs, const G2Element &sig) { vector> vecs(msgs.size()); for (int i = 0; i < (int)msgs.size(); ++i) { std::string s(msgs[i]); vecs[i] = vector(s.begin(), s.end()); } py::gil_scoped_release release; return BasicSchemeMPL().AggregateVerify(pks, vecs, sig); }) .def( "g2_from_message", [](const py::bytes &msg) { const auto msg_str = std::string(msg); py::gil_scoped_release release; const auto msg_bytes = Bytes((const uint8_t *)msg_str.c_str(), msg_str.size()); return G2Element::FromMessage( msg_bytes, (const uint8_t *)BasicSchemeMPL::CIPHERSUITE_ID.c_str(), BasicSchemeMPL::CIPHERSUITE_ID.size() ); }); py::class_(m, "AugSchemeMPL") .def("sk_to_g1", [](const PrivateKey &seckey){ py::gil_scoped_release release; return AugSchemeMPL().SkToG1(seckey); }) .def( "key_gen", [](const py::bytes &b) { std::string str(b); py::gil_scoped_release release; const vector inputVec(str.begin(), str.end()); return AugSchemeMPL().KeyGen(inputVec); }) .def("derive_child_sk", [](const PrivateKey& sk, uint32_t index){ py::gil_scoped_release release; return AugSchemeMPL().DeriveChildSk(sk, index); }) .def("derive_child_sk_unhardened", [](const PrivateKey& sk, uint32_t index){ py::gil_scoped_release release; return AugSchemeMPL().DeriveChildSkUnhardened(sk, index); }) .def("derive_child_pk_unhardened", [](const G1Element& pk, uint32_t index){ py::gil_scoped_release release; return AugSchemeMPL().DeriveChildPkUnhardened(pk, index); }) .def("aggregate", [](const vector& signatures) { py::gil_scoped_release release; return AugSchemeMPL().Aggregate(signatures); }) .def( "sign", [](const PrivateKey &pk, const py::bytes &msg) { std::string s(msg); py::gil_scoped_release release; vector v(s.begin(), s.end()); return AugSchemeMPL().Sign(pk, v); }) .def( "sign", [](const PrivateKey &pk, const py::bytes &msg, const G1Element &prepend_pk) { std::string s(msg); py::gil_scoped_release release; vector v(s.begin(), s.end()); return AugSchemeMPL().Sign(pk, v, prepend_pk); }) .def( "verify", [](const G1Element &pk, const py::bytes &msg, const G2Element &sig) { std::string s(msg); py::gil_scoped_release release; vector v(s.begin(), s.end()); return AugSchemeMPL().Verify(pk, v, sig); }) .def( "aggregate_verify", [](const vector &pks, const vector &msgs, const G2Element &sig) { vector> vecs(msgs.size()); for (int i = 0; i < (int)msgs.size(); ++i) { std::string s(msgs[i]); vecs[i] = vector(s.begin(), s.end()); } py::gil_scoped_release release; return AugSchemeMPL().AggregateVerify(pks, vecs, sig); }) .def( "g2_from_message", [](const py::bytes &msg) { const auto msg_str = std::string(msg); py::gil_scoped_release release; const auto msg_bytes = Bytes((const uint8_t *)msg_str.c_str(), msg_str.size()); return G2Element::FromMessage( msg_bytes, (const uint8_t *)AugSchemeMPL::CIPHERSUITE_ID.c_str(), AugSchemeMPL::CIPHERSUITE_ID.size() ); }); py::class_(m, "PopSchemeMPL") .def("sk_to_g1", [](const PrivateKey &seckey){ py::gil_scoped_release release; return PopSchemeMPL().SkToG1(seckey); }) .def( "key_gen", [](const py::bytes &b) { std::string str(b); py::gil_scoped_release release; const vector inputVec(str.begin(), str.end()); return PopSchemeMPL().KeyGen(inputVec); }) .def("derive_child_sk", [](const PrivateKey& sk, uint32_t index){ py::gil_scoped_release release; return PopSchemeMPL().DeriveChildSk(sk, index); }) .def("derive_child_sk_unhardened", [](const PrivateKey& sk, uint32_t index){ py::gil_scoped_release release; return PopSchemeMPL().DeriveChildSkUnhardened(sk, index); }) .def("derive_child_pk_unhardened", [](const G1Element& pk, uint32_t index){ py::gil_scoped_release release; return PopSchemeMPL().DeriveChildPkUnhardened(pk, index); }) .def("aggregate", [](const vector& signatures) { py::gil_scoped_release release; return PopSchemeMPL().Aggregate(signatures); }) .def( "sign", [](const PrivateKey &pk, const py::bytes &msg) { std::string s(msg); py::gil_scoped_release release; vector v(s.begin(), s.end()); return PopSchemeMPL().Sign(pk, v); }) .def( "verify", [](const G1Element &pk, const py::bytes &msg, const G2Element &sig) { std::string s(msg); py::gil_scoped_release release; vector v(s.begin(), s.end()); return PopSchemeMPL().Verify(pk, v, sig); }) .def( "aggregate_verify", [](const vector &pks, const vector &msgs, const G2Element &sig) { vector> vecs(msgs.size()); for (int i = 0; i < (int)msgs.size(); ++i) { std::string s(msgs[i]); vecs[i] = vector(s.begin(), s.end()); } py::gil_scoped_release release; return PopSchemeMPL().AggregateVerify(pks, vecs, sig); }) .def( "g2_from_message", [](const py::bytes &msg) { const auto msg_str = std::string(msg); py::gil_scoped_release release; const auto msg_bytes = Bytes((const uint8_t *)msg_str.c_str(), msg_str.size()); return G2Element::FromMessage( msg_bytes, (const uint8_t *)PopSchemeMPL::CIPHERSUITE_ID.c_str(), PopSchemeMPL::CIPHERSUITE_ID.size() ); }) .def("pop_prove", [](const PrivateKey& privateKey){ py::gil_scoped_release release; return PopSchemeMPL().PopProve(privateKey); }) .def("pop_verify", [](const G1Element& pubkey, const G2Element& signature){ py::gil_scoped_release release; return PopSchemeMPL().PopVerify(pubkey, signature); }) .def( "fast_aggregate_verify", [](const vector &pks, const py::bytes &msg, const G2Element &sig) { std::string s(msg); py::gil_scoped_release release; vector v(s.begin(), s.end()); return PopSchemeMPL().FastAggregateVerify(pks, v, sig); }); py::class_(m, "G1Element") .def_property_readonly_static( "SIZE", [](py::object self) { return G1Element::SIZE; }) .def(py::init([](){ py::gil_scoped_release release; return G1Element(); })) .def(py::init(&G1Element::FromByteVector), py::call_guard()) .def(py::init([](py::int_ pyint) { std::array buffer{}; if (_PyLong_AsByteArray( (PyLongObject *)pyint.ptr(), buffer.data(), G1Element::SIZE, 0, 0) < 0) { throw std::invalid_argument("Failed to cast int to G1Element"); } py::gil_scoped_release release; return G1Element::FromBytes(buffer); })) .def(py::init([](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 1) throw std::runtime_error("Incompatible buffer format!"); if ((int)info.size != G1Element::SIZE) { throw std::invalid_argument( "Length of bytes object not equal to G1Element::SIZE"); } auto data_ptr = static_cast(info.ptr); std::array data; std::copy(data_ptr, data_ptr + G1Element::SIZE, data.data()); py::gil_scoped_release release; return G1Element::FromBytes(data); })) .def( "from_bytes", [](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 1) throw std::runtime_error("Incompatible buffer format!"); if ((int)info.size != G1Element::SIZE) { throw std::invalid_argument( "Length of bytes object not equal to G1Element::SIZE"); } auto data_ptr = reinterpret_cast(info.ptr); std::array data; std::copy(data_ptr, data_ptr + G1Element::SIZE, data.data()); py::gil_scoped_release release; return G1Element::FromBytes(data); }) .def( "from_bytes_unchecked", [](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 1) throw std::runtime_error("Incompatible buffer format!"); if ((int)info.size != G1Element::SIZE) { throw std::invalid_argument( "Length of bytes object not equal to G1Element::SIZE"); } auto data_ptr = reinterpret_cast(info.ptr); return G1Element::FromBytesUnchecked({data_ptr, G1Element::SIZE}); }) .def("generator", &G1Element::Generator) .def("from_message", py::overload_cast&, const uint8_t*, int>(&G1Element::FromMessage), py::call_guard()) .def("pair", &G1Element::Pair, py::call_guard()) .def("negate", &G1Element::Negate, py::call_guard()) .def("get_fingerprint", &G1Element::GetFingerprint, py::call_guard()) .def(py::self == py::self) .def(py::self != py::self) .def( "__deepcopy__", [](const G1Element &g1, const py::object &memo) { return G1Element(g1); }) .def( "__add__", [](G1Element &self, G1Element &other) { py::gil_scoped_release release; return self + other; }, py::is_operator()) .def( "__mul__", [](G1Element &self, bn_t other) { py::gil_scoped_release release; return self * (*(bn_t *)&other); }, py::is_operator()) .def( "__rmul__", [](G1Element &self, bn_t other) { py::gil_scoped_release release; return self * (*(bn_t *)&other); }, py::is_operator()) .def( "__and__", [](G1Element &self, G2Element &other) { py::gil_scoped_release release; return self & other; }, py::is_operator()) .def( "__repr__", [](const G1Element &ele) { py::gil_scoped_release release; std::stringstream s; s << ele; return ""; }) .def( "__str__", [](const G1Element &ele) { py::gil_scoped_release release; std::stringstream s; s << ele; return s.str(); }) .def( "__bytes__", [](const G1Element &ele) { vector out; { py::gil_scoped_release release; out = ele.Serialize(); } py::bytes ans = py::bytes( reinterpret_cast(out.data()), G1Element::SIZE); return ans; }) .def("__deepcopy__", [](const G1Element &ele, const py::object &memo) { return G1Element(ele); }); py::class_(m, "G2Element") .def_property_readonly_static( "SIZE", [](py::object self) { return G2Element::SIZE; }) .def(py::init([](){ return G2Element(); })) .def(py::init(&G2Element::FromByteVector), py::call_guard()) .def(py::init([](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 1) throw std::runtime_error("Incompatible buffer format!"); if ((int)info.size != G2Element::SIZE) { throw std::invalid_argument( "Length of bytes object not equal to G2Element::SIZE"); } auto data_ptr = static_cast(info.ptr); std::array data; std::copy(data_ptr, data_ptr + G2Element::SIZE, data.data()); py::gil_scoped_release release; return G2Element::FromBytes(data); })) .def(py::init([](py::int_ pyint) { std::array buffer{}; if (_PyLong_AsByteArray( (PyLongObject *)pyint.ptr(), buffer.data(), G2Element::SIZE, 0, 0) < 0) { throw std::invalid_argument("Failed to cast int to G2Element"); } py::gil_scoped_release release; return G2Element::FromBytes(buffer); })) .def( "from_bytes", [](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 1) throw std::runtime_error("Incompatible buffer format!"); if ((int)info.size != G2Element::SIZE) { throw std::invalid_argument( "Length of bytes object not equal to G2Element::SIZE"); } auto data_ptr = reinterpret_cast(info.ptr); std::array data; std::copy(data_ptr, data_ptr + G2Element::SIZE, data.data()); py::gil_scoped_release release; return G2Element::FromBytes(data); }) .def( "from_bytes_unchecked", [](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 1) throw std::runtime_error("Incompatible buffer format!"); if ((int)info.size != G2Element::SIZE) { throw std::invalid_argument( "Length of bytes object not equal to G2Element::SIZE"); } auto data_ptr = reinterpret_cast(info.ptr); return G2Element::FromBytesUnchecked({data_ptr, G2Element::SIZE}); }) .def("generator", &G2Element::Generator) .def("from_message", py::overload_cast&, const uint8_t*, int, bool>(&G2Element::FromMessage), py::call_guard()) .def("pair", &G2Element::Pair, py::call_guard()) .def("negate", &G2Element::Negate, py::call_guard()) .def( "__deepcopy__", [](const G2Element &g2, const py::object &memo) { return G2Element(g2); }) .def(py::self == py::self) .def(py::self != py::self) .def( "__add__", [](G2Element &self, G2Element &other) { py::gil_scoped_release release; return self + other; }, py::is_operator()) .def( "__mul__", [](G2Element &self, bn_t other) { py::gil_scoped_release release; return self * (*(bn_t *)&other); }, py::is_operator()) .def( "__rmul__", [](G2Element &self, bn_t other) { py::gil_scoped_release release; return self * (*(bn_t *)&other); }, py::is_operator()) .def( "__repr__", [](const G2Element &ele) { py::gil_scoped_release release; std::stringstream s; s << ele; return ""; }) .def( "__str__", [](const G2Element &ele) { py::gil_scoped_release release; std::stringstream s; s << ele; return s.str(); }) .def( "__bytes__", [](const G2Element &ele) { vector out; { py::gil_scoped_release release; out = ele.Serialize(); } py::bytes ans = py::bytes( reinterpret_cast(out.data()), G2Element::SIZE); return ans; }) .def("__deepcopy__", [](const G2Element &ele, const py::object &memo) { return G2Element(ele); }); py::class_(m, "GTElement") .def_property_readonly_static( "SIZE", [](py::object self) { return GTElement::SIZE; }) .def(py::init(>Element::FromByteVector), py::call_guard()) .def(py::init([](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 1) throw std::runtime_error("Incompatible buffer format!"); if ((int)info.size != GTElement::SIZE) { throw std::invalid_argument( "Length of bytes object not equal to G2Element::SIZE"); } auto data_ptr = static_cast(info.ptr); std::array data; std::copy(data_ptr, data_ptr + GTElement::SIZE, data.data()); py::gil_scoped_release release; return GTElement::FromBytes(data); })) .def(py::init([](py::int_ pyint) { std::array buffer{}; if (_PyLong_AsByteArray( (PyLongObject *)pyint.ptr(), buffer.data(), GTElement::SIZE, 0, 0) < 0) { throw std::invalid_argument("Failed to cast int to GTElement"); } py::gil_scoped_release release; return GTElement::FromBytes(buffer); })) .def( "from_bytes", [](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 1) throw std::runtime_error("Incompatible buffer format!"); if ((int)info.size != GTElement::SIZE) { throw std::invalid_argument( "Length of bytes object not equal to GTElement::SIZE"); } auto data_ptr = reinterpret_cast(info.ptr); std::array data; std::copy(data_ptr, data_ptr + GTElement::SIZE, data.data()); py::gil_scoped_release release; return GTElement::FromBytes(data); }) .def( "from_bytes_unchecked", [](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 1) throw std::runtime_error("Incompatible buffer format!"); if ((int)info.size != GTElement::SIZE) { throw std::invalid_argument( "Length of bytes object not equal to GTElement::SIZE"); } auto data_ptr = reinterpret_cast(info.ptr); std::array data; std::copy(data_ptr, data_ptr + GTElement::SIZE, data.data()); py::gil_scoped_release release; return GTElement::FromBytesUnchecked(data); }) .def("unity", >Element::Unity) .def(py::self == py::self) .def(py::self != py::self) .def( "__deepcopy__", [](const GTElement >, const py::object &memo) { return GTElement(gt); }) .def( "__repr__", [](const GTElement &ele) { py::gil_scoped_release release; std::stringstream s; s << ele; return ""; }) .def( "__str__", [](const GTElement &ele) { py::gil_scoped_release release; std::stringstream s; s << ele; return s.str(); }) .def( "__bytes__", [](const GTElement &ele) { uint8_t *out = new uint8_t[GTElement::SIZE]; { py::gil_scoped_release release; ele.Serialize(out); } py::bytes ans = py::bytes(reinterpret_cast(out), GTElement::SIZE); delete[] out; return ans; }) .def( "__mul__", [](GTElement &self, GTElement &other) { py::gil_scoped_release release; return self * other; }, py::is_operator()) .def("__deepcopy__", [](const GTElement &ele, const py::object &memo) { return GTElement(ele); }); m.attr("PublicKeyMPL") = m.attr("G1Element"); m.attr("SignatureMPL") = m.attr("G2Element"); #ifdef VERSION_INFO m.attr("__version__") = VERSION_INFO; #else m.attr("__version__") = "dev"; #endif }