mirror of
https://github.com/luxfi/blst.git
synced 2026-10-30 17:01:37 +00:00
959 lines
37 KiB
C++
959 lines
37 KiB
C++
/*
|
|
* Copyright Supranational LLC
|
|
* Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#ifndef __BLST_HPP__
|
|
#define __BLST_HPP__
|
|
|
|
#if !defined(SWIG) && __cplusplus < 201103L \
|
|
&& (!defined(_MSVC_LANG) || _MSVC_LANG < 201103L)
|
|
# error "C++11 or later is required to compile <blst>/bindings/blst.hpp"
|
|
#endif
|
|
|
|
#include <string>
|
|
#include <cstring>
|
|
#include <vector>
|
|
#include <memory>
|
|
|
|
namespace blst {
|
|
|
|
#ifdef __clang__
|
|
# pragma GCC diagnostic push
|
|
# pragma GCC diagnostic ignored "-Wextern-c-compat"
|
|
#endif
|
|
|
|
#include "blst.h"
|
|
|
|
#ifdef __clang__
|
|
# pragma GCC diagnostic pop
|
|
#endif
|
|
|
|
struct bytes_t {
|
|
const byte* ptr;
|
|
size_t len;
|
|
|
|
bytes_t() = default;
|
|
bytes_t(const byte* p, size_t l) : ptr{p}, len{l} {}
|
|
template<template<typename, typename...> class C, typename T>
|
|
bytes_t(const C<T>& c)
|
|
{
|
|
static_assert(sizeof(T) == 1, "unsupported type");
|
|
ptr = reinterpret_cast<const byte*>(c.data());
|
|
len = c.size();
|
|
}
|
|
template<template<typename, size_t> class C, typename T, size_t N>
|
|
bytes_t(const C<T, N>& c)
|
|
{
|
|
static_assert(sizeof(T) == 1, "unsupported type");
|
|
ptr = reinterpret_cast<const byte*>(c.data());
|
|
len = c.size();
|
|
}
|
|
};
|
|
|
|
class P1_Affine;
|
|
class P1;
|
|
class P2_Affine;
|
|
class P2;
|
|
class Pairing;
|
|
|
|
inline const byte *C_bytes(const void *ptr)
|
|
{ return static_cast<const byte*>(ptr); }
|
|
|
|
/*
|
|
* As for SecretKey being struct and not class, and lack of constructors
|
|
* with one accepting for example |IKM|. We can't make assumptions about
|
|
* application's policy toward handling secret key material. Hence it's
|
|
* argued that application is entitled for transparent structure, not
|
|
* opaque or semi-opaque class. And in the context it's appropriate not
|
|
* to "entice" developers with idiomatic constructors:-) Though this
|
|
* doesn't really apply to SWIG-assisted interfaces...
|
|
*/
|
|
struct SecretKey {
|
|
#ifdef SWIG
|
|
private:
|
|
#endif
|
|
blst_scalar key;
|
|
|
|
#ifdef SWIG
|
|
public:
|
|
#endif
|
|
#ifndef SWIG
|
|
void keygen(const byte* IKM, size_t IKM_len,
|
|
const std::string& info = "")
|
|
{ blst_keygen(&key, IKM, IKM_len, C_bytes(info.data()), info.size()); }
|
|
void keygen_v3(const byte* IKM, size_t IKM_len,
|
|
const std::string& info = "")
|
|
{ blst_keygen_v3(&key, IKM, IKM_len, C_bytes(info.data()), info.size()); }
|
|
void keygen_v4_5(const byte* IKM, size_t IKM_len,
|
|
const byte* salt, size_t salt_len,
|
|
const std::string& info = "")
|
|
{ blst_keygen_v4_5(&key, IKM, IKM_len, salt, salt_len,
|
|
C_bytes(info.data()), info.size());
|
|
}
|
|
void keygen_v5(const byte* IKM, size_t IKM_len,
|
|
const byte* salt, size_t salt_len,
|
|
const std::string& info = "")
|
|
{ blst_keygen_v5(&key, IKM, IKM_len, salt, salt_len,
|
|
C_bytes(info.data()), info.size());
|
|
}
|
|
#endif
|
|
void keygen(bytes_t IKM, const std::string& info = "")
|
|
{ keygen(IKM.ptr, IKM.len, info); }
|
|
void keygen_v3(bytes_t IKM, const std::string& info = "")
|
|
{ keygen_v3(IKM.ptr, IKM.len, info); }
|
|
void keygen_v4_5(bytes_t IKM, bytes_t salt, const std::string& info = "")
|
|
{ keygen_v4_5(IKM.ptr, IKM.len, salt.ptr, salt.len, info); }
|
|
void keygen_v5(bytes_t IKM, bytes_t salt, const std::string& info = "")
|
|
{ keygen_v5(IKM.ptr, IKM.len, salt.ptr, salt.len, info); }
|
|
void derive_master_eip2333(const byte* IKM, size_t IKM_len)
|
|
{ blst_derive_master_eip2333(&key, IKM, IKM_len); }
|
|
void derive_child_eip2333(const SecretKey& SK, unsigned int child_index)
|
|
{ blst_derive_child_eip2333(&key, &SK.key, child_index); }
|
|
|
|
void from_bendian(const byte in[32]) { blst_scalar_from_bendian(&key, in); }
|
|
void from_lendian(const byte in[32]) { blst_scalar_from_lendian(&key, in); }
|
|
|
|
void to_bendian(byte out[32]) const
|
|
{ blst_bendian_from_scalar(out, &key); }
|
|
void to_lendian(byte out[32]) const
|
|
{ blst_lendian_from_scalar(out, &key); }
|
|
};
|
|
|
|
class Scalar {
|
|
private:
|
|
blst_scalar val;
|
|
|
|
public:
|
|
Scalar() { memset(&val, 0, sizeof(val)); }
|
|
Scalar(const byte* scalar, size_t nbits)
|
|
{ blst_scalar_from_le_bytes(&val, scalar, (nbits+7)/8); }
|
|
#ifndef SWIG
|
|
Scalar(const byte *msg, size_t msg_len, const std::string& DST)
|
|
{ (void)hash_to(msg, msg_len, DST); }
|
|
|
|
Scalar* hash_to(const byte *msg, size_t msg_len, const std::string& DST = "")
|
|
{ byte elem[48];
|
|
blst_expand_message_xmd(elem, sizeof(elem), msg, msg_len,
|
|
C_bytes(DST.data()), DST.size());
|
|
blst_scalar_from_be_bytes(&val, elem, sizeof(elem));
|
|
return this;
|
|
}
|
|
#endif
|
|
Scalar(bytes_t msg, const std::string& DST)
|
|
{ (void)hash_to(msg.ptr, msg.len, DST); }
|
|
Scalar* hash_to(bytes_t msg, const std::string& DST = "")
|
|
{ return hash_to(msg.ptr, msg.len, DST); }
|
|
|
|
Scalar dup() const { return *this; }
|
|
Scalar* from_bendian(const byte *msg, size_t msg_len)
|
|
{ blst_scalar_from_be_bytes(&val, msg, msg_len); return this; }
|
|
Scalar* from_lendian(const byte *msg, size_t msg_len)
|
|
{ blst_scalar_from_le_bytes(&val, msg, msg_len); return this; }
|
|
void to_bendian(byte out[32]) const
|
|
{ blst_bendian_from_scalar(out, &val); }
|
|
void to_lendian(byte out[32]) const
|
|
{ blst_lendian_from_scalar(out, &val); }
|
|
|
|
Scalar* add(const Scalar& a)
|
|
{ if (!blst_sk_add_n_check(&val, &val, a))
|
|
throw BLST_BAD_SCALAR;
|
|
return this;
|
|
}
|
|
Scalar* add(const SecretKey& a)
|
|
{ if (!blst_sk_add_n_check(&val, &val, &a.key))
|
|
throw BLST_BAD_SCALAR;
|
|
return this;
|
|
}
|
|
Scalar* sub(const Scalar& a)
|
|
{ if (!blst_sk_sub_n_check(&val, &val, a))
|
|
throw BLST_BAD_SCALAR;
|
|
return this;
|
|
}
|
|
Scalar* mul(const Scalar& a)
|
|
{ if (!blst_sk_mul_n_check(&val, &val, a))
|
|
throw BLST_BAD_SCALAR;
|
|
return this;
|
|
}
|
|
Scalar* inverse()
|
|
{ blst_sk_inverse(&val, &val); return this; }
|
|
|
|
private:
|
|
friend class P1;
|
|
friend class P2;
|
|
operator const blst_scalar*() const { return &val; }
|
|
operator const byte*() const { return val.b; }
|
|
};
|
|
|
|
class P1_Affine {
|
|
private:
|
|
blst_p1_affine point;
|
|
|
|
P1_Affine(const blst_p1_affine *cptr) { point = *cptr; }
|
|
public:
|
|
P1_Affine() { memset(&point, 0, sizeof(point)); }
|
|
#ifndef SWIG
|
|
P1_Affine(const byte *in)
|
|
{ BLST_ERROR err = blst_p1_deserialize(&point, in);
|
|
if (err != BLST_SUCCESS)
|
|
throw err;
|
|
}
|
|
#endif
|
|
P1_Affine(const byte *in, size_t len)
|
|
{ if (len == 0 || len != (in[0]&0x80 ? 48 : 96))
|
|
throw BLST_BAD_ENCODING;
|
|
BLST_ERROR err = blst_p1_deserialize(&point, in);
|
|
if (err != BLST_SUCCESS)
|
|
throw err;
|
|
}
|
|
P1_Affine(const P1& jacobian);
|
|
|
|
P1_Affine dup() const { return *this; }
|
|
P1 to_jacobian() const;
|
|
void serialize(byte out[96]) const
|
|
{ blst_p1_affine_serialize(out, &point); }
|
|
void compress(byte out[48]) const
|
|
{ blst_p1_affine_compress(out, &point); }
|
|
bool on_curve() const { return blst_p1_affine_on_curve(&point); }
|
|
bool in_group() const { return blst_p1_affine_in_g1(&point); }
|
|
bool is_inf() const { return blst_p1_affine_is_inf(&point); }
|
|
bool is_equal(const P1_Affine& p) const
|
|
{ return blst_p1_affine_is_equal(&point, &p.point); }
|
|
#ifndef SWIG
|
|
BLST_ERROR core_verify(const P2_Affine& pk, bool hash_or_encode,
|
|
const byte* msg, size_t msg_len,
|
|
const std::string& DST = "",
|
|
const byte* aug = nullptr, size_t aug_len = 0) const;
|
|
#endif
|
|
BLST_ERROR core_verify(const P2_Affine& pk, bool hash_or_encode,
|
|
bytes_t msg, const std::string& DST = "",
|
|
bytes_t aug = {nullptr, 0}) const
|
|
{ return core_verify(pk, hash_or_encode, msg.ptr, msg.len, DST,
|
|
aug.ptr, aug.len);
|
|
}
|
|
static P1_Affine generator()
|
|
{ return P1_Affine(blst_p1_affine_generator()); }
|
|
|
|
private:
|
|
friend class Pairing;
|
|
friend class P2_Affine;
|
|
friend class PT;
|
|
friend class P1;
|
|
friend class P1_Affines;
|
|
operator const blst_p1_affine*() const { return &point; }
|
|
operator blst_p1_affine*() { return &point; }
|
|
};
|
|
|
|
class P1 {
|
|
private:
|
|
blst_p1 point;
|
|
|
|
P1(const blst_p1 *cptr) { point = *cptr; }
|
|
public:
|
|
P1() { memset(&point, 0, sizeof(point)); }
|
|
P1(const SecretKey& sk) { blst_sk_to_pk_in_g1(&point, &sk.key); }
|
|
#ifndef SWIG
|
|
P1(const byte *in)
|
|
{ blst_p1_affine a;
|
|
BLST_ERROR err = blst_p1_deserialize(&a, in);
|
|
if (err != BLST_SUCCESS)
|
|
throw err;
|
|
blst_p1_from_affine(&point, &a);
|
|
}
|
|
#endif
|
|
P1(const byte *in, size_t len)
|
|
{ if (len == 0 || len != (in[0]&0x80 ? 48 : 96))
|
|
throw BLST_BAD_ENCODING;
|
|
blst_p1_affine a;
|
|
BLST_ERROR err = blst_p1_deserialize(&a, in);
|
|
if (err != BLST_SUCCESS)
|
|
throw err;
|
|
blst_p1_from_affine(&point, &a);
|
|
}
|
|
P1(const P1_Affine& affine) { blst_p1_from_affine(&point, affine); }
|
|
|
|
P1 dup() const { return *this; }
|
|
P1_Affine to_affine() const { return P1_Affine(*this); }
|
|
void serialize(byte out[96]) const { blst_p1_serialize(out, &point); }
|
|
void compress(byte out[48]) const { blst_p1_compress(out, &point); }
|
|
bool on_curve() const { return blst_p1_on_curve(&point); }
|
|
bool in_group() const { return blst_p1_in_g1(&point); }
|
|
bool is_inf() const { return blst_p1_is_inf(&point); }
|
|
bool is_equal(const P1& p) const
|
|
{ return blst_p1_is_equal(&point, &p.point); }
|
|
void aggregate(const P1_Affine& in)
|
|
{ if (blst_p1_affine_in_g1(in))
|
|
blst_p1_add_or_double_affine(&point, &point, in);
|
|
else
|
|
throw BLST_POINT_NOT_IN_GROUP;
|
|
}
|
|
P1* sign_with(const SecretKey& sk)
|
|
{ blst_sign_pk_in_g2(&point, &point, &sk.key); return this; }
|
|
P1* sign_with(const Scalar& scalar)
|
|
{ blst_sign_pk_in_g2(&point, &point, scalar); return this; }
|
|
P1* hash_to(bytes_t msg, const std::string& DST = "",
|
|
bytes_t aug = {nullptr, 0})
|
|
{ blst_hash_to_g1(&point, msg.ptr, msg.len, C_bytes(DST.data()), DST.size(),
|
|
aug.ptr, aug.len);
|
|
return this;
|
|
}
|
|
P1* encode_to(bytes_t msg, const std::string& DST = "",
|
|
bytes_t aug = {nullptr, 0})
|
|
{ blst_encode_to_g1(&point, msg.ptr, msg.len, C_bytes(DST.data()), DST.size(),
|
|
aug.ptr, aug.len);
|
|
return this;
|
|
}
|
|
#ifndef SWIG
|
|
P1* hash_to(const byte* msg, size_t msg_len,
|
|
const std::string& DST = "",
|
|
const byte* aug = nullptr, size_t aug_len = 0)
|
|
{ blst_hash_to_g1(&point, msg, msg_len, C_bytes(DST.data()), DST.size(),
|
|
aug, aug_len);
|
|
return this;
|
|
}
|
|
P1* encode_to(const byte* msg, size_t msg_len,
|
|
const std::string& DST = "",
|
|
const byte* aug = nullptr, size_t aug_len = 0)
|
|
{ blst_encode_to_g1(&point, msg, msg_len, C_bytes(DST.data()), DST.size(),
|
|
aug, aug_len);
|
|
return this;
|
|
}
|
|
#endif
|
|
P1* mult(const byte* scalar, size_t nbits)
|
|
{ blst_p1_mult(&point, &point, scalar, nbits); return this; }
|
|
P1* mult(const Scalar& scalar)
|
|
{ blst_p1_mult(&point, &point, scalar, 255); return this; }
|
|
P1* cneg(bool flag)
|
|
{ blst_p1_cneg(&point, flag); return this; }
|
|
P1* neg()
|
|
{ blst_p1_cneg(&point, true); return this; }
|
|
P1* add(const P1& a)
|
|
{ blst_p1_add_or_double(&point, &point, a); return this; }
|
|
P1* add(const P1_Affine &a)
|
|
{ blst_p1_add_or_double_affine(&point, &point, a); return this; }
|
|
P1* dbl()
|
|
{ blst_p1_double(&point, &point); return this; }
|
|
#ifndef SWIG
|
|
static P1 add(const P1& a, const P1& b)
|
|
{ P1 ret; blst_p1_add_or_double(ret, a, b); return ret; }
|
|
static P1 add(const P1& a, const P1_Affine& b)
|
|
{ P1 ret; blst_p1_add_or_double_affine(ret, a, b); return ret; }
|
|
static P1 dbl(const P1& a)
|
|
{ P1 ret; blst_p1_double(ret, a); return ret; }
|
|
#endif
|
|
static P1 generator()
|
|
{ return P1(blst_p1_generator()); }
|
|
|
|
private:
|
|
friend class P1_Affine;
|
|
friend class P1_Affines;
|
|
operator const blst_p1*() const { return &point; }
|
|
operator blst_p1*() { return &point; }
|
|
};
|
|
|
|
class P1_Affines {
|
|
private:
|
|
struct p1_affine_no_init {
|
|
blst_p1_affine point;
|
|
p1_affine_no_init() { }
|
|
operator blst_p1_affine*() { return &point; }
|
|
operator const blst_p1_affine*() const { return &point; }
|
|
};
|
|
|
|
std::vector<p1_affine_no_init> table;
|
|
size_t wbits, npoints;
|
|
|
|
public:
|
|
#ifndef SWIG
|
|
P1_Affines() {}
|
|
P1_Affines(size_t wbits, const P1_Affine* const points[], size_t npoints)
|
|
{ this->wbits = wbits;
|
|
this->npoints = npoints;
|
|
table.resize(npoints << (wbits-1));
|
|
blst_p1s_mult_wbits_precompute(table.at(0), wbits,
|
|
reinterpret_cast<const blst_p1_affine *const*>(points),
|
|
npoints);
|
|
}
|
|
P1_Affines(size_t wbits, const P1_Affine points[], size_t npoints)
|
|
{ const P1_Affine* const ptrs[2] = { points, nullptr };
|
|
P1_Affines(wbits, ptrs, npoints);
|
|
}
|
|
P1_Affines(size_t wbits, const std::vector<P1_Affine>& points)
|
|
{ P1_Affines(wbits, &points.at(0), points.size()); }
|
|
|
|
P1_Affines(size_t wbits, const P1* const points[], size_t npoints)
|
|
{ size_t cap = npoints << (wbits-1);
|
|
|
|
this->wbits = wbits;
|
|
this->npoints = npoints;
|
|
table.resize(cap);
|
|
blst_p1s_to_affine(table.at(cap-npoints),
|
|
reinterpret_cast<const blst_p1 *const*>(points),
|
|
npoints);
|
|
const blst_p1_affine* const ptrs[2] = { table[cap-npoints], nullptr };
|
|
blst_p1s_mult_wbits_precompute(table[0], wbits, ptrs, npoints);
|
|
}
|
|
P1_Affines(size_t wbits, const P1 points[], size_t npoints)
|
|
{ const P1* const ptrs[2] = { points, nullptr };
|
|
P1_Affines(wbits, ptrs, npoints);
|
|
}
|
|
P1_Affines(size_t wbits, const std::vector<P1>& points)
|
|
{ P1_Affines(wbits, &points.at(0), points.size()); }
|
|
|
|
P1_Affines(const P1* const points[], size_t npoints)
|
|
{ this->wbits = 0;
|
|
this->npoints = npoints;
|
|
table.resize(npoints);
|
|
blst_p1s_to_affine(table.at(0),
|
|
reinterpret_cast<const blst_p1 *const*>(points),
|
|
npoints);
|
|
}
|
|
P1_Affines(const P1 points[], size_t npoints)
|
|
{ const P1* const ptrs[2] = { points, nullptr };
|
|
P1_Affines(ptrs, npoints);
|
|
}
|
|
P1_Affines(const std::vector<P1>& points)
|
|
{ P1_Affines(&points.at(0), points.size()); }
|
|
|
|
P1 mult(const byte* const scalars[], size_t nbits) const
|
|
{ P1 ret;
|
|
|
|
if (wbits != 0) {
|
|
size_t sz = blst_p1s_mult_wbits_scratch_sizeof(npoints);
|
|
std::unique_ptr<limb_t[]> scratch{new limb_t[sz/sizeof(limb_t)]};
|
|
blst_p1s_mult_wbits(ret, table.at(0), wbits, npoints,
|
|
scalars, nbits, scratch.get());
|
|
} else {
|
|
size_t sz = blst_p1s_mult_pippenger_scratch_sizeof(npoints);
|
|
std::unique_ptr<limb_t[]> scratch{new limb_t[sz/sizeof(limb_t)]};
|
|
const blst_p1_affine* const ptrs[2] = { table.at(0), nullptr };
|
|
blst_p1s_mult_pippenger(ret, ptrs, npoints,
|
|
scalars, nbits, scratch.get());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static std::vector<P1_Affine> from(const P1* const points[], size_t npoints)
|
|
{ std::vector<P1_Affine> ret;
|
|
ret.resize(npoints);
|
|
blst_p1s_to_affine(reinterpret_cast<blst_p1_affine*>(&ret.at(0)),
|
|
reinterpret_cast<const blst_p1 *const*>(points),
|
|
npoints);
|
|
return ret;
|
|
}
|
|
static std::vector<P1_Affine> from(const P1 points[], size_t npoints)
|
|
{ const P1* const ptrs[2] = { points, nullptr };
|
|
return from(ptrs, npoints);
|
|
}
|
|
static std::vector<P1_Affine> from(const std::vector<P1>& points)
|
|
{ return from(&points.at(0), points.size()); }
|
|
#endif
|
|
|
|
static P1 mult_pippenger(const P1_Affine* const points[], size_t npoints,
|
|
const byte* const scalars[], size_t nbits)
|
|
{ P1 ret;
|
|
size_t sz = blst_p1s_mult_pippenger_scratch_sizeof(npoints);
|
|
std::unique_ptr<limb_t[]> scratch{new limb_t[sz/sizeof(limb_t)]};
|
|
blst_p1s_mult_pippenger(ret,
|
|
reinterpret_cast<const blst_p1_affine *const*>(points),
|
|
npoints, scalars, nbits, scratch.get());
|
|
return ret;
|
|
}
|
|
#ifndef SWIG
|
|
static P1 mult_pippenger(const P1_Affine points[], size_t npoints,
|
|
const byte* const scalars[], size_t nbits)
|
|
{ const P1_Affine* const ptrs[2] = { points, nullptr };
|
|
return mult_pippenger(ptrs, npoints, scalars, nbits);
|
|
}
|
|
static P1 mult_pippenger(const std::vector<P1_Affine>& points,
|
|
const byte* const scalars[], size_t nbits)
|
|
{ return mult_pippenger(&points.at(0), points.size(), scalars, nbits); }
|
|
#endif
|
|
|
|
static P1 add(const P1_Affine* const points[], size_t npoints)
|
|
{ P1 ret;
|
|
blst_p1s_add(ret,
|
|
reinterpret_cast<const blst_p1_affine *const*>(points),
|
|
npoints);
|
|
return ret;
|
|
}
|
|
#ifndef SWIG
|
|
static P1 add(const P1_Affine points[], size_t npoints)
|
|
{ const P1_Affine* const ptrs[2] = { points, nullptr };
|
|
return add(ptrs, npoints);
|
|
}
|
|
static P1 add(const std::vector<P1_Affine>& points)
|
|
{ return add(&points.at(0), points.size()); }
|
|
#endif
|
|
};
|
|
|
|
class P2_Affine {
|
|
private:
|
|
blst_p2_affine point;
|
|
|
|
P2_Affine(const blst_p2_affine *cptr) { point = *cptr; }
|
|
public:
|
|
P2_Affine() { memset(&point, 0, sizeof(point)); }
|
|
#ifndef SWIG
|
|
P2_Affine(const byte *in)
|
|
{ BLST_ERROR err = blst_p2_deserialize(&point, in);
|
|
if (err != BLST_SUCCESS)
|
|
throw err;
|
|
}
|
|
#endif
|
|
P2_Affine(const byte *in, size_t len)
|
|
{ if (len == 0 || len != (in[0]&0x80 ? 96 : 192))
|
|
throw BLST_BAD_ENCODING;
|
|
BLST_ERROR err = blst_p2_deserialize(&point, in);
|
|
if (err != BLST_SUCCESS)
|
|
throw err;
|
|
}
|
|
P2_Affine(const P2& jacobian);
|
|
|
|
P2_Affine dup() const { return *this; }
|
|
P2 to_jacobian() const;
|
|
void serialize(byte out[192]) const
|
|
{ blst_p2_affine_serialize(out, &point); }
|
|
void compress(byte out[96]) const
|
|
{ blst_p2_affine_compress(out, &point); }
|
|
bool on_curve() const { return blst_p2_affine_on_curve(&point); }
|
|
bool in_group() const { return blst_p2_affine_in_g2(&point); }
|
|
bool is_inf() const { return blst_p2_affine_is_inf(&point); }
|
|
bool is_equal(const P2_Affine& p) const
|
|
{ return blst_p2_affine_is_equal(&point, &p.point); }
|
|
#ifndef SWIG
|
|
BLST_ERROR core_verify(const P1_Affine& pk, bool hash_or_encode,
|
|
const byte* msg, size_t msg_len,
|
|
const std::string& DST = "",
|
|
const byte* aug = nullptr, size_t aug_len = 0) const;
|
|
#endif
|
|
BLST_ERROR core_verify(const P1_Affine& pk, bool hash_or_encode,
|
|
bytes_t msg, const std::string& DST = "",
|
|
bytes_t aug = {nullptr, 0}) const
|
|
{ return core_verify(pk, hash_or_encode, msg.ptr, msg.len, DST,
|
|
aug.ptr, aug.len);
|
|
}
|
|
static P2_Affine generator()
|
|
{ return P2_Affine(blst_p2_affine_generator()); }
|
|
|
|
private:
|
|
friend class Pairing;
|
|
friend class P1_Affine;
|
|
friend class PT;
|
|
friend class P2;
|
|
friend class P2_Affines;
|
|
operator const blst_p2_affine*() const { return &point; }
|
|
operator blst_p2_affine*() { return &point; }
|
|
};
|
|
|
|
class P2 {
|
|
private:
|
|
blst_p2 point;
|
|
|
|
P2(const blst_p2 *cptr) { point = *cptr; }
|
|
public:
|
|
P2() { memset(&point, 0, sizeof(point)); }
|
|
P2(const SecretKey& sk) { blst_sk_to_pk_in_g2(&point, &sk.key); }
|
|
#ifndef SWIG
|
|
P2(const byte *in)
|
|
{ blst_p2_affine a;
|
|
BLST_ERROR err = blst_p2_deserialize(&a, in);
|
|
if (err != BLST_SUCCESS)
|
|
throw err;
|
|
blst_p2_from_affine(&point, &a);
|
|
}
|
|
#endif
|
|
P2(const byte *in, size_t len)
|
|
{ if (len == 0 || len != (in[0]&0x80 ? 96 : 192))
|
|
throw BLST_BAD_ENCODING;
|
|
blst_p2_affine a;
|
|
BLST_ERROR err = blst_p2_deserialize(&a, in);
|
|
if (err != BLST_SUCCESS)
|
|
throw err;
|
|
blst_p2_from_affine(&point, &a);
|
|
}
|
|
P2(const P2_Affine& affine) { blst_p2_from_affine(&point, affine); }
|
|
|
|
P2 dup() const { return *this; }
|
|
P2_Affine to_affine() const { return P2_Affine(*this); }
|
|
void serialize(byte out[192]) const { blst_p2_serialize(out, &point); }
|
|
void compress(byte out[96]) const { blst_p2_compress(out, &point); }
|
|
bool on_curve() const { return blst_p2_on_curve(&point); }
|
|
bool in_group() const { return blst_p2_in_g2(&point); }
|
|
bool is_inf() const { return blst_p2_is_inf(&point); }
|
|
bool is_equal(const P2& p) const
|
|
{ return blst_p2_is_equal(&point, &p.point); }
|
|
void aggregate(const P2_Affine& in)
|
|
{ if (blst_p2_affine_in_g2(in))
|
|
blst_p2_add_or_double_affine(&point, &point, in);
|
|
else
|
|
throw BLST_POINT_NOT_IN_GROUP;
|
|
}
|
|
P2* sign_with(const SecretKey& sk)
|
|
{ blst_sign_pk_in_g1(&point, &point, &sk.key); return this; }
|
|
P2* sign_with(const Scalar& scalar)
|
|
{ blst_sign_pk_in_g1(&point, &point, scalar); return this; }
|
|
P2* hash_to(bytes_t msg, const std::string& DST = "",
|
|
bytes_t aug = {nullptr, 0})
|
|
{ blst_hash_to_g2(&point, msg.ptr, msg.len, C_bytes(DST.data()), DST.size(),
|
|
aug.ptr, aug.len);
|
|
return this;
|
|
}
|
|
P2* encode_to(bytes_t msg, const std::string& DST = "",
|
|
bytes_t aug = {nullptr, 0})
|
|
{ blst_encode_to_g2(&point, msg.ptr, msg.len, C_bytes(DST.data()), DST.size(),
|
|
aug.ptr, aug.len);
|
|
return this;
|
|
}
|
|
#ifndef SWIG
|
|
P2* hash_to(const byte* msg, size_t msg_len,
|
|
const std::string& DST = "",
|
|
const byte* aug = nullptr, size_t aug_len = 0)
|
|
{ blst_hash_to_g2(&point, msg, msg_len, C_bytes(DST.data()), DST.size(),
|
|
aug, aug_len);
|
|
return this;
|
|
}
|
|
P2* encode_to(const byte* msg, size_t msg_len,
|
|
const std::string& DST = "",
|
|
const byte* aug = nullptr, size_t aug_len = 0)
|
|
{ blst_encode_to_g2(&point, msg, msg_len, C_bytes(DST.data()), DST.size(),
|
|
aug, aug_len);
|
|
return this;
|
|
}
|
|
#endif
|
|
|
|
P2* mult(const byte* scalar, size_t nbits)
|
|
{ blst_p2_mult(&point, &point, scalar, nbits); return this; }
|
|
P2* mult(const Scalar& scalar)
|
|
{ blst_p2_mult(&point, &point, scalar, 255); return this; }
|
|
P2* cneg(bool flag)
|
|
{ blst_p2_cneg(&point, flag); return this; }
|
|
P2* neg()
|
|
{ blst_p2_cneg(&point, true); return this; }
|
|
P2* add(const P2& a)
|
|
{ blst_p2_add_or_double(&point, &point, a); return this; }
|
|
P2* add(const P2_Affine &a)
|
|
{ blst_p2_add_or_double_affine(&point, &point, a); return this; }
|
|
P2* dbl()
|
|
{ blst_p2_double(&point, &point); return this; }
|
|
#ifndef SWIG
|
|
static P2 add(const P2& a, const P2& b)
|
|
{ P2 ret; blst_p2_add_or_double(ret, a, b); return ret; }
|
|
static P2 add(const P2& a, const P2_Affine& b)
|
|
{ P2 ret; blst_p2_add_or_double_affine(ret, a, b); return ret; }
|
|
static P2 dbl(const P2& a)
|
|
{ P2 ret; blst_p2_double(ret, a); return ret; }
|
|
#endif
|
|
static P2 generator()
|
|
{ return P2(blst_p2_generator()); }
|
|
|
|
private:
|
|
friend class P2_Affine;
|
|
friend class P2_Affines;
|
|
operator const blst_p2*() const { return &point; }
|
|
operator blst_p2*() { return &point; }
|
|
};
|
|
|
|
class P2_Affines {
|
|
private:
|
|
struct p2_affine_no_init {
|
|
blst_p2_affine point;
|
|
p2_affine_no_init() { }
|
|
operator blst_p2_affine*() { return &point; }
|
|
operator const blst_p2_affine*() const { return &point; }
|
|
};
|
|
|
|
std::vector<p2_affine_no_init> table;
|
|
size_t wbits, npoints;
|
|
|
|
public:
|
|
#ifndef SWIG
|
|
P2_Affines() {}
|
|
P2_Affines(size_t wbits, const P2_Affine* const points[], size_t npoints)
|
|
{ this->wbits = wbits;
|
|
this->npoints = npoints;
|
|
table.resize(npoints << (wbits-1));
|
|
blst_p2s_mult_wbits_precompute(table.at(0), wbits,
|
|
reinterpret_cast<const blst_p2_affine *const*>(points),
|
|
npoints);
|
|
}
|
|
P2_Affines(size_t wbits, const P2_Affine points[], size_t npoints)
|
|
{ const P2_Affine* const ptrs[2] = { points, nullptr };
|
|
P2_Affines(wbits, ptrs, npoints);
|
|
}
|
|
P2_Affines(size_t wbits, const std::vector<P2_Affine>& points)
|
|
{ P2_Affines(wbits, &points.at(0), points.size()); }
|
|
|
|
P2_Affines(size_t wbits, const P2* const points[], size_t npoints)
|
|
{ size_t cap = npoints << (wbits-1);
|
|
|
|
this->wbits = wbits;
|
|
this->npoints = npoints;
|
|
table.resize(cap);
|
|
blst_p2s_to_affine(table.at(cap-npoints),
|
|
reinterpret_cast<const blst_p2 *const*>(points),
|
|
npoints);
|
|
const blst_p2_affine* const ptrs[2] = { table[cap-npoints], nullptr };
|
|
blst_p2s_mult_wbits_precompute(table[0], wbits, ptrs, npoints);
|
|
}
|
|
P2_Affines(size_t wbits, const P2 points[], size_t npoints)
|
|
{ const P2* const ptrs[2] = { points, nullptr };
|
|
P2_Affines(wbits, ptrs, npoints);
|
|
}
|
|
P2_Affines(size_t wbits, const std::vector<P2>& points)
|
|
{ P2_Affines(wbits, &points.at(0), points.size()); }
|
|
|
|
P2_Affines(const P2* const points[], size_t npoints)
|
|
{ this->wbits = 0;
|
|
this->npoints = npoints;
|
|
table.resize(npoints);
|
|
blst_p2s_to_affine(table.at(0),
|
|
reinterpret_cast<const blst_p2 *const*>(points),
|
|
npoints);
|
|
}
|
|
P2_Affines(const P2 points[], size_t npoints)
|
|
{ const P2* const ptrs[2] = { points, nullptr };
|
|
P2_Affines(ptrs, npoints);
|
|
}
|
|
P2_Affines(const std::vector<P2>& points)
|
|
{ P2_Affines(&points.at(0), points.size()); }
|
|
|
|
P2 mult(const byte* const scalars[], size_t nbits) const
|
|
{ P2 ret;
|
|
|
|
if (wbits != 0) {
|
|
size_t sz = blst_p2s_mult_wbits_scratch_sizeof(npoints);
|
|
std::unique_ptr<limb_t[]> scratch{new limb_t[sz/sizeof(limb_t)]};
|
|
blst_p2s_mult_wbits(ret, table.at(0), wbits, npoints,
|
|
scalars, nbits, scratch.get());
|
|
} else {
|
|
size_t sz = blst_p2s_mult_pippenger_scratch_sizeof(npoints);
|
|
std::unique_ptr<limb_t[]> scratch{new limb_t[sz/sizeof(limb_t)]};
|
|
const blst_p2_affine* const ptrs[2] = { table.at(0), nullptr };
|
|
blst_p2s_mult_pippenger(ret, ptrs, npoints,
|
|
scalars, nbits, scratch.get());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static std::vector<P2_Affine> from(const P2* const points[], size_t npoints)
|
|
{ std::vector<P2_Affine> ret;
|
|
ret.resize(npoints);
|
|
blst_p2s_to_affine(reinterpret_cast<blst_p2_affine*>(&ret.at(0)),
|
|
reinterpret_cast<const blst_p2 *const*>(points),
|
|
npoints);
|
|
return ret;
|
|
}
|
|
static std::vector<P2_Affine> from(const P2 points[], size_t npoints)
|
|
{ const P2* const ptrs[2] = { points, nullptr };
|
|
return from(ptrs, npoints);
|
|
}
|
|
static std::vector<P2_Affine> from(const std::vector<P2>& points)
|
|
{ return from(&points.at(0), points.size()); }
|
|
#endif
|
|
|
|
static P2 mult_pippenger(const P2_Affine* const points[], size_t npoints,
|
|
const byte* const scalars[], size_t nbits)
|
|
{ P2 ret;
|
|
size_t sz = blst_p2s_mult_pippenger_scratch_sizeof(npoints);
|
|
std::unique_ptr<limb_t[]> scratch{new limb_t[sz/sizeof(limb_t)]};
|
|
blst_p2s_mult_pippenger(ret,
|
|
reinterpret_cast<const blst_p2_affine *const*>(points),
|
|
npoints, scalars, nbits, scratch.get());
|
|
return ret;
|
|
}
|
|
#ifndef SWIG
|
|
static P2 mult_pippenger(const P2_Affine points[], size_t npoints,
|
|
const byte* const scalars[], size_t nbits)
|
|
{ const P2_Affine* const ptrs[2] = { points, nullptr };
|
|
return mult_pippenger(ptrs, npoints, scalars, nbits);
|
|
}
|
|
static P2 mult_pippenger(const std::vector<P2_Affine>& points,
|
|
const byte* const scalars[], size_t nbits)
|
|
{ return mult_pippenger(&points.at(0), points.size(), scalars, nbits); }
|
|
#endif
|
|
|
|
static P2 add(const P2_Affine* const points[], size_t npoints)
|
|
{ P2 ret;
|
|
blst_p2s_add(ret,
|
|
reinterpret_cast<const blst_p2_affine *const*>(points),
|
|
npoints);
|
|
return ret;
|
|
}
|
|
#ifndef SWIG
|
|
static P2 add(const P2_Affine points[], size_t npoints)
|
|
{ const P2_Affine* const ptrs[2] = { points, nullptr };
|
|
return add(ptrs, npoints);
|
|
}
|
|
static P2 add(const std::vector<P2_Affine>& points)
|
|
{ return add(&points.at(0), points.size()); }
|
|
#endif
|
|
};
|
|
|
|
inline P1_Affine::P1_Affine(const P1& jacobian)
|
|
{ blst_p1_to_affine(&point, jacobian); }
|
|
inline P2_Affine::P2_Affine(const P2& jacobian)
|
|
{ blst_p2_to_affine(&point, jacobian); }
|
|
|
|
inline P1 P1_Affine::to_jacobian() const { P1 ret(*this); return ret; }
|
|
inline P2 P2_Affine::to_jacobian() const { P2 ret(*this); return ret; }
|
|
|
|
inline P1 G1() { return P1::generator(); }
|
|
inline P2 G2() { return P2::generator(); }
|
|
|
|
#ifndef SWIG
|
|
inline BLST_ERROR P1_Affine::core_verify(const P2_Affine& pk,
|
|
bool hash_or_encode,
|
|
const byte* msg, size_t msg_len,
|
|
const std::string& DST,
|
|
const byte* aug, size_t aug_len) const
|
|
{ return blst_core_verify_pk_in_g2(pk, &point, hash_or_encode,
|
|
msg, msg_len,
|
|
C_bytes(DST.data()), DST.size(),
|
|
aug, aug_len);
|
|
}
|
|
inline BLST_ERROR P2_Affine::core_verify(const P1_Affine& pk,
|
|
bool hash_or_encode,
|
|
const byte* msg, size_t msg_len,
|
|
const std::string& DST,
|
|
const byte* aug, size_t aug_len) const
|
|
{ return blst_core_verify_pk_in_g1(pk, &point, hash_or_encode,
|
|
msg, msg_len,
|
|
C_bytes(DST.data()), DST.size(),
|
|
aug, aug_len);
|
|
}
|
|
#endif
|
|
|
|
class PT {
|
|
private:
|
|
blst_fp12 value;
|
|
|
|
PT(const blst_fp12 *v) { value = *v; }
|
|
public:
|
|
PT(const P1_Affine& p) { blst_aggregated_in_g1(&value, p); }
|
|
PT(const P2_Affine& q) { blst_aggregated_in_g2(&value, q); }
|
|
PT(const P2_Affine& q, const P1_Affine& p)
|
|
{ blst_miller_loop(&value, q, p); }
|
|
PT(const P1_Affine& p, const P2_Affine& q) : PT(q, p) {}
|
|
PT(const P2& q, const P1& p)
|
|
{ blst_miller_loop(&value, P2_Affine(q), P1_Affine(p)); }
|
|
PT(const P1& p, const P2& q) : PT(q, p) {}
|
|
|
|
PT dup() const { return *this; }
|
|
bool is_one() const { return blst_fp12_is_one(&value); }
|
|
bool is_equal(const PT& p) const
|
|
{ return blst_fp12_is_equal(&value, p); }
|
|
PT* sqr() { blst_fp12_sqr(&value, &value); return this; }
|
|
PT* mul(const PT& p) { blst_fp12_mul(&value, &value, p); return this; }
|
|
PT* final_exp() { blst_final_exp(&value, &value); return this; }
|
|
bool in_group() const { return blst_fp12_in_group(&value); }
|
|
void to_bendian(byte out[48*12]) const
|
|
{ blst_bendian_from_fp12(out, &value); }
|
|
|
|
static bool finalverify(const PT& gt1, const PT& gt2)
|
|
{ return blst_fp12_finalverify(gt1, gt2); }
|
|
static PT one() { return PT(blst_fp12_one()); }
|
|
|
|
private:
|
|
friend class Pairing;
|
|
operator const blst_fp12*() const { return &value; }
|
|
};
|
|
|
|
class Pairing {
|
|
private:
|
|
operator blst_pairing*()
|
|
{ return reinterpret_cast<blst_pairing *>(this); }
|
|
operator const blst_pairing*() const
|
|
{ return reinterpret_cast<const blst_pairing *>(this); }
|
|
|
|
void init(bool hash_or_encode, const byte* DST, size_t DST_len)
|
|
{ // Copy DST to heap, std::string can be volatile, especially in SWIG:-(
|
|
byte *dst = new byte[DST_len];
|
|
memcpy(dst, DST, DST_len);
|
|
blst_pairing_init(*this, hash_or_encode, dst, DST_len);
|
|
}
|
|
|
|
public:
|
|
#ifndef SWIG
|
|
void* operator new(size_t)
|
|
{ return new uint64_t[blst_pairing_sizeof()/sizeof(uint64_t)]; }
|
|
void operator delete(void *ptr)
|
|
{ delete[] static_cast<uint64_t*>(ptr); }
|
|
|
|
Pairing(bool hash_or_encode, const std::string& DST)
|
|
{ init(hash_or_encode, C_bytes(DST.data()), DST.size()); }
|
|
#endif
|
|
#ifndef SWIGJAVA
|
|
Pairing(bool hash_or_encode, const byte* DST, size_t DST_len)
|
|
{ init(hash_or_encode, DST, DST_len); }
|
|
~Pairing() { delete[] blst_pairing_get_dst(*this); }
|
|
#endif
|
|
|
|
BLST_ERROR aggregate(const P1_Affine* pk, const P2_Affine* sig,
|
|
bytes_t msg, bytes_t aug = {nullptr, 0})
|
|
{ return blst_pairing_aggregate_pk_in_g1(*this, *pk, *sig,
|
|
msg.ptr, msg.len, aug.ptr, aug.len);
|
|
}
|
|
BLST_ERROR aggregate(const P2_Affine* pk, const P1_Affine* sig,
|
|
bytes_t msg, bytes_t aug = {nullptr, 0})
|
|
{ return blst_pairing_aggregate_pk_in_g2(*this, *pk, *sig,
|
|
msg.ptr, msg.len, aug.ptr, aug.len);
|
|
}
|
|
BLST_ERROR mul_n_aggregate(const P1_Affine* pk, const P2_Affine* sig,
|
|
const byte* scalar, size_t nbits,
|
|
bytes_t msg, bytes_t aug = {nullptr, 0})
|
|
{ return blst_pairing_mul_n_aggregate_pk_in_g1(*this, *pk, *sig,
|
|
scalar, nbits, msg.ptr, msg.len, aug.ptr, aug.len);
|
|
}
|
|
BLST_ERROR mul_n_aggregate(const P2_Affine* pk, const P1_Affine* sig,
|
|
const byte* scalar, size_t nbits,
|
|
bytes_t msg, bytes_t aug = {nullptr, 0})
|
|
{ return blst_pairing_mul_n_aggregate_pk_in_g2(*this, *pk, *sig,
|
|
scalar, nbits, msg.ptr, msg.len, aug.ptr, aug.len);
|
|
}
|
|
#ifndef SWIG
|
|
BLST_ERROR aggregate(const P1_Affine* pk, const P2_Affine* sig,
|
|
const byte* msg, size_t msg_len,
|
|
const byte* aug = nullptr, size_t aug_len = 0)
|
|
{ return blst_pairing_aggregate_pk_in_g1(*this, *pk, *sig,
|
|
msg, msg_len, aug, aug_len);
|
|
}
|
|
BLST_ERROR aggregate(const P2_Affine* pk, const P1_Affine* sig,
|
|
const byte* msg, size_t msg_len,
|
|
const byte* aug = nullptr, size_t aug_len = 0)
|
|
{ return blst_pairing_aggregate_pk_in_g2(*this, *pk, *sig,
|
|
msg, msg_len, aug, aug_len);
|
|
}
|
|
BLST_ERROR mul_n_aggregate(const P1_Affine* pk, const P2_Affine* sig,
|
|
const byte* scalar, size_t nbits,
|
|
const byte* msg, size_t msg_len,
|
|
const byte* aug = nullptr, size_t aug_len = 0)
|
|
{ return blst_pairing_mul_n_aggregate_pk_in_g1(*this, *pk, *sig,
|
|
scalar, nbits, msg, msg_len, aug, aug_len);
|
|
}
|
|
BLST_ERROR mul_n_aggregate(const P2_Affine* pk, const P1_Affine* sig,
|
|
const byte* scalar, size_t nbits,
|
|
const byte* msg, size_t msg_len,
|
|
const byte* aug = nullptr, size_t aug_len = 0)
|
|
{ return blst_pairing_mul_n_aggregate_pk_in_g2(*this, *pk, *sig,
|
|
scalar, nbits, msg, msg_len, aug, aug_len);
|
|
}
|
|
#endif
|
|
void commit()
|
|
{ blst_pairing_commit(*this); }
|
|
BLST_ERROR merge(const Pairing* ctx)
|
|
{ return blst_pairing_merge(*this, *ctx); }
|
|
bool finalverify(const PT* sig = nullptr) const
|
|
{ return sig == nullptr ? blst_pairing_finalverify(*this, nullptr)
|
|
: blst_pairing_finalverify(*this, *sig);
|
|
}
|
|
void raw_aggregate(const P2_Affine* q, const P1_Affine* p)
|
|
{ blst_pairing_raw_aggregate(*this, *q, *p); }
|
|
PT as_fp12()
|
|
{ return PT(blst_pairing_as_fp12(*this)); }
|
|
};
|
|
|
|
} // namespace blst
|
|
|
|
#endif
|