Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functions to Python binding to support pairing cache #237

Merged
merged 6 commits into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions python-bindings/pythonbindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,17 @@ PYBIND11_MODULE(blspy, m)
}
PythonGIL release_lock;
return BasicSchemeMPL().AggregateVerify(pks, vecs, sig);
})
.def(
"g2_from_message",
[](const py::bytes &msg) {
const auto msg_str = std::string(msg);
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_<AugSchemeMPL>(m, "AugSchemeMPL")
Expand Down Expand Up @@ -217,6 +228,17 @@ PYBIND11_MODULE(blspy, m)
}
PythonGIL release_lock;
return AugSchemeMPL().AggregateVerify(pks, vecs, sig);
})
.def(
"g2_from_message",
[](const py::bytes &msg) {
const auto msg_str = std::string(msg);
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_<PopSchemeMPL>(m, "PopSchemeMPL")
Expand Down Expand Up @@ -272,6 +294,17 @@ PYBIND11_MODULE(blspy, m)
PythonGIL release_lock;
return PopSchemeMPL().AggregateVerify(pks, vecs, sig);
})
.def(
"g2_from_message",
[](const py::bytes &msg) {
const auto msg_str = std::string(msg);
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){
return PopSchemeMPL().PopProve(privateKey);
})
Expand Down Expand Up @@ -339,6 +372,7 @@ PYBIND11_MODULE(blspy, m)
})
.def("generator", &G1Element::Generator)
.def("from_message", py::overload_cast<const std::vector<uint8_t>&, const uint8_t*, int>(&G1Element::FromMessage))
.def("pair", &G1Element::Pair)
.def("negate", &G1Element::Negate)
.def("get_fingerprint", &G1Element::GetFingerprint)

Expand All @@ -365,6 +399,10 @@ PYBIND11_MODULE(blspy, m)
return self * (*(bn_t *)&other);
},
py::is_operator())
.def(
"__and__",
[](G1Element &self, G2Element &other) { return self & other; },
py::is_operator())
.def(
"__repr__",
[](const G1Element &ele) {
Expand Down Expand Up @@ -442,6 +480,7 @@ PYBIND11_MODULE(blspy, m)
})
.def("generator", &G2Element::Generator)
.def("from_message", py::overload_cast<const std::vector<uint8_t>&, const uint8_t*, int>(&G2Element::FromMessage))
.def("pair", &G2Element::Pair)
.def("negate", &G2Element::Negate)
.def(
"__deepcopy__",
Expand Down Expand Up @@ -494,6 +533,93 @@ PYBIND11_MODULE(blspy, m)
return G2Element(ele);
});

py::class_<GTElement>(m, "GTElement")
.def_property_readonly_static(
"SIZE", [](py::object self) { return GTElement::SIZE; })
.def(py::init(&GTElement::FromByteVector))
.def(py::init([](py::buffer const b) {
py::buffer_info info = b.request();
if (info.format != py::format_descriptor<uint8_t>::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<uint8_t *>(info.ptr);
std::vector<uint8_t> data(data_ptr, data_ptr + info.size);
return GTElement::FromByteVector(data);
}))
.def(py::init([](py::int_ pyint) {
std::vector<uint8_t> buffer(GTElement::SIZE, 0);
if (_PyLong_AsByteArray(
(PyLongObject *)pyint.ptr(),
buffer.data(),
GTElement::SIZE,
0,
0) < 0) {
throw std::invalid_argument("Failed to cast int to GTElement");
}
return GTElement::FromByteVector(buffer);
}))
.def(
"from_bytes",
[](py::buffer const b) {
py::buffer_info info = b.request();
if (info.format != py::format_descriptor<uint8_t>::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<const uint8_t *>(info.ptr);
return GTElement::FromBytes(Bytes(data_ptr, GTElement::SIZE));
})
.def("unity", &GTElement::Unity)
.def(py::self == py::self)
.def(py::self != py::self)
.def(
"__deepcopy__",
[](const GTElement &gt, const py::object &memo) {
return GTElement(gt);
})
.def(
"__repr__",
[](const GTElement &ele) {
std::stringstream s;
s << ele;
return "<GTElement " + s.str() + ">";
})
.def(
"__str__",
[](const GTElement &ele) {
std::stringstream s;
s << ele;
return s.str();
})
.def(
"__bytes__",
[](const GTElement &ele) {
uint8_t *out = new uint8_t[GTElement::SIZE];
ele.Serialize(out);
py::bytes ans =
py::bytes(reinterpret_cast<char *>(out), GTElement::SIZE);
delete[] out;
return ans;
})
.def(
"__mul__",
[](GTElement &self, GTElement &other) {
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");

Expand Down
14 changes: 14 additions & 0 deletions python-bindings/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ def test_schemes():
agg_sig = Scheme.aggregate([sig1, sig2])
assert Scheme.aggregate_verify([pk1, pk2], [msg, msg2], agg_sig)

# Manual pairing calculation and verification
if Scheme is AugSchemeMPL:
# AugSchemeMPL requires prepending the public key to message
aug_msg1 = bytes(pk1) + msg
aug_msg2 = bytes(pk2) + msg2
else:
aug_msg1 = msg
aug_msg2 = msg2
pair1 = pk1.pair(Scheme.g2_from_message(aug_msg1))
pair2 = pk2.pair(Scheme.g2_from_message(aug_msg2))
pair = pair1 * pair2
agg_sig_pair = G1Element.generator().pair(agg_sig)
assert pair == agg_sig_pair

# HD keys
child = Scheme.derive_child_sk(sk1, 123)
childU = Scheme.derive_child_sk_unhardened(sk1, 123)
Expand Down
8 changes: 8 additions & 0 deletions src/bls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <cstring>
#include <set>
#include <string>

#include "bls.hpp"

#if BLSALLOC_SODIUM
Expand All @@ -20,6 +25,9 @@

namespace bls {

const char BLS::GROUP_ORDER[] =
"73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001";

bool BLSInitResult = BLS::Init();

Util::SecureAllocCallback Util::secureAllocCallback;
Expand Down
18 changes: 18 additions & 0 deletions src/bls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,29 @@
#ifndef SRC_BLS_HPP_
#define SRC_BLS_HPP_

#include <vector>
#include <map>
#include <string>
#include <stdexcept>

#include "relic_conf.h"

#if defined GMP && ARITH == GMP
#include <gmp.h>
#endif

#include "privatekey.hpp"
#include "util.hpp"
#include "schemes.hpp"
#include "elements.hpp"
#include "hkdf.hpp"
#include "hdkeys.hpp"

extern "C" {
#include "relic.h"
}
#include "relic_test.h"

namespace bls {

/*
Expand All @@ -30,6 +46,8 @@ namespace bls {
*/
class BLS {
public:
// Order of g1, g2, and gt. Private keys are in {0, GROUP_ORDER}.
static const char GROUP_ORDER[];
static const size_t MESSAGE_HASH_LEN = 32;

// Initializes the BLS library (called automatically)
Expand Down
95 changes: 95 additions & 0 deletions src/elements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <cstring>
#include <string>

#include "bls.hpp"
#include "elements.hpp"
#include "privatekey.hpp"
#include "util.hpp"

namespace bls {


G1Element G1Element::FromBytes(const Bytes& bytes)
{
if (bytes.size() != SIZE) {
Expand Down Expand Up @@ -128,6 +134,8 @@ G1Element G1Element::Negate() const
return ans;
}

GTElement G1Element::Pair(const G2Element& b) const { return (*this) & b; }

uint32_t G1Element::GetFingerprint() const
{
uint8_t buffer[G1Element::SIZE];
Expand All @@ -137,6 +145,7 @@ uint32_t G1Element::GetFingerprint() const
return Util::FourBytesToInt(hash);
}


std::vector<uint8_t> G1Element::Serialize() const {
uint8_t buffer[G1Element::SIZE + 1];
g1_write_bin(buffer, G1Element::SIZE + 1, p, 1);
Expand Down Expand Up @@ -311,6 +320,8 @@ G2Element G2Element::Negate() const
return ans;
}

GTElement G2Element::Pair(const G1Element& a) const { return a & (*this); }

std::vector<uint8_t> G2Element::Serialize() const {
uint8_t buffer[G2Element::SIZE + 1];
g2_write_bin(buffer, G2Element::SIZE + 1, (g2_st*)q, 1);
Expand Down Expand Up @@ -374,4 +385,88 @@ G2Element operator*(const G2Element& a, const bn_t& k)

G2Element operator*(const bn_t& k, const G2Element& a) { return a * k; }



// GTElement

GTElement GTElement::FromBytes(const Bytes& bytes)
{
if (bytes.size() != SIZE) {
throw std::invalid_argument("GTElement::FromBytes: Invalid size");
}
GTElement ele = GTElement();
gt_read_bin(ele.r, bytes.begin(), GTElement::SIZE);
if (gt_is_valid(*(gt_t*)&ele) == 0)
throw std::invalid_argument("GTElement is invalid");
BLS::CheckRelicErrors();
return ele;
}

GTElement GTElement::FromByteVector(const std::vector<uint8_t>& bytevec)
{
return GTElement::FromBytes(Bytes(bytevec));
}

GTElement GTElement::FromNative(const gt_t* element)
{
GTElement ele = GTElement();
gt_copy(ele.r, *(gt_t*)element);
return ele;
}

GTElement GTElement::Unity() {
GTElement ele = GTElement();
gt_set_unity(ele.r);
return ele;
}


bool operator==(GTElement const& a, GTElement const& b)
{
return gt_cmp(*(gt_t*)(a.r), *(gt_t*)(b.r)) == RLC_EQ;
}

bool operator!=(GTElement const& a, GTElement const& b) { return !(a == b); }

std::ostream& operator<<(std::ostream& os, GTElement const& ele)
{
return os << Util::HexStr(ele.Serialize());
}

GTElement operator&(const G1Element& a, const G2Element& b)
{
G1Element nonConstA(a);
gt_t ans;
gt_new(ans);
g2_t tmp;
g2_null(tmp);
g2_new(tmp);
b.ToNative(tmp);
pp_map_oatep_k12(ans, nonConstA.p, tmp);
GTElement ret = GTElement::FromNative(&ans);
gt_free(ans);
g2_free(tmp);
return ret;
}

GTElement operator*(GTElement& a, GTElement& b)
{
GTElement ans;
fp12_mul(ans.r, a.r, b.r);
BLS::CheckRelicErrors();
return ans;
}

void GTElement::Serialize(uint8_t* buffer) const
{
gt_write_bin(buffer, GTElement::SIZE, *(gt_t*)&r, 1);
}

std::vector<uint8_t> GTElement::Serialize() const
{
std::vector<uint8_t> data(GTElement::SIZE);
Serialize(data.data());
return data;
}

} // end namespace bls
Loading