Skip to content

Commit

Permalink
Merge pull request #16 from AntelopeIO/yarkin/multiple_fixes
Browse files Browse the repository at this point in the history
More restrictive deserialization and add test cases
  • Loading branch information
arhag authored Nov 29, 2023
2 parents 6cac93b + 8871e5e commit 1388808
Show file tree
Hide file tree
Showing 11 changed files with 1,621 additions and 1,120 deletions.
132 changes: 128 additions & 4 deletions bench/eth_bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ fp12 random_fe12()
g1 random_g1()
{
array<uint64_t, 4> k = random_scalar();
return g1::one().mulScalar(k);
return g1::one().scale(k);
}

g2 random_g2()
{
array<uint64_t, 4> k = random_scalar();
return g2::one().mulScalar(k);
return g2::one().scale(k);
}

void benchG1Add() {
Expand All @@ -113,7 +113,20 @@ void benchG1Mul() {
auto start = startStopwatch();

for (int i = 0; i < numIters; i++) {
p.mulScalar(s);
p.scale(s);
}
endStopwatch(testName, start, numIters);
}

void benchG1WeightedSum() {
string testName = "G1 WeightedSum";
const int numIters = 10000;
g1 p = random_g1();
vector<g1> bases{8, p};
vector<array<uint64_t, 4>> scalars{8, {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}};
auto start = startStopwatch();
for (int i = 0; i < numIters; i++) {
g1::weightedSum(bases, scalars);
}
endStopwatch(testName, start, numIters);
}
Expand All @@ -140,7 +153,29 @@ void benchG2Mul() {
auto start = startStopwatch();

for (int i = 0; i < numIters; i++) {
p.mulScalar(s);
p.scale(s);
}
endStopwatch(testName, start, numIters);
}

void benchG2WeightedSum() {
string testName = "G2 WeightedSum";
const int numIters = 10000;
g2 p = random_g2();
vector<g2> bases = {p,p,p,p,p,p,p,p};
vector<array<uint64_t, 4>> scalars = {
{0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff},
{0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff},
{0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff},
{0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff},
{0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff},
{0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff},
{0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff},
{0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}
};
auto start = startStopwatch();
for (int i = 0; i < numIters; i++) {
g2::weightedSum(bases, scalars);
}
endStopwatch(testName, start, numIters);
}
Expand All @@ -161,11 +196,100 @@ void benchPairing() {
endStopwatch(testName, start, numIters);
}

void benchG1Add2() {
string testName = "G1 Addition With different settings";
cout << endl << testName << endl;

const int numIters = 10000;
g1 pbak = random_g1();



array<uint64_t, 4> s = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};


auto performTest = [numIters, s, pbak](bool check, bool raw) {
array<uint8_t, 144> pRaw = {};
g1 p = pbak;
p.toJacobianBytesLE(pRaw, raw);

auto start = startStopwatch();

for (int i = 0; i < numIters; i++) {
p = *g1::fromJacobianBytesLE(pRaw, check, raw);
p.add(p);
p.toJacobianBytesLE(pRaw, raw);
}
endStopwatch(string("check=") + std::to_string(check) + string(", raw=") + std::to_string(raw), start, numIters);

start = startStopwatch();
};

performTest(true, true);
performTest(true, false);
performTest(false, true);
performTest(false, false);

}

void benchG2Add2() {
string testName = "G2 Addition With different settings";
cout << endl << testName << endl;

const int numIters = 10000;
g2 pbak = random_g2();



array<uint64_t, 4> s = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};


auto performTest = [numIters, s, pbak](bool check, bool raw) {
array<uint8_t, 288> pRaw = {};
g2 p = pbak;
p.toJacobianBytesLE(pRaw, raw);

auto start = startStopwatch();

for (int i = 0; i < numIters; i++) {
p = *g2::fromJacobianBytesLE(pRaw, check, raw);
p.add(p);
p.toJacobianBytesLE(pRaw, raw);
}
endStopwatch(string("check=") + std::to_string(check) + string(", raw=") + std::to_string(raw), start, numIters);

start = startStopwatch();
};

performTest(true, true);
performTest(true, false);
performTest(false, true);
performTest(false, false);

}

void benchInverse() {
string testName = "Inverse";
const int numIters = 10000;
fp a = random_fe();
auto start = startStopwatch();

for (int i = 0; i < numIters; i++) {
a.inverse();
}
endStopwatch(testName, start, numIters);
}

int main(int argc, char* argv[])
{
benchG1Add();
benchG1Mul();
benchG1WeightedSum();
benchG2Add();
benchG2Mul();
benchG2WeightedSum();
benchPairing();
benchG1Add2();
benchG2Add2();
benchInverse();
}
27 changes: 15 additions & 12 deletions include/bls12-381/arithmetic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,27 @@ class fp;
void init(bool cpu_features = true);

void _add(fp* z, const fp* x, const fp* y);
void _addAssign(fp* x, const fp* y);
void _ladd(fp* z, const fp* x, const fp* y);
void _laddAssign(fp* x, const fp* y);
void _double(fp* z, const fp* x);
void _doubleAssign(fp* z);
void _ldouble(fp* z, const fp* x);
void _sub(fp* z, const fp* x, const fp* y);
void _subAssign(fp* z, const fp* x);
void _lsubAssign(fp* z, const fp* x);
void _neg(fp* z, const fp* x);
void _subtract(fp* z, const fp* x, const fp* y);
void _negate(fp* z, const fp* x);
void _square(fp* z, const fp* x);

// Those are low level calls that will not perform modular reduction after the operation
// Please use with caution. Overflow will happen.
void _ladd(fp* z, const fp* x, const fp* y);
void _ldouble(fp* z, const fp* x);
void _lsubtract(fp* z, const fp* x, const fp* y);

// Multiplication will work fine as long as both operands are smaller than around 4p.
// The "smaller than 4p" here means the montgomery form itself as number is less than 4p.
// Therefore, at most ONE _ladd/_lsubstract/_ldouble is allowed before passing the result to _multiply,
// unless the algorithm makes sure the number is small.
#if defined(__x86_64__) && defined(__ELF__)
extern void _mul(fp*, const fp*, const fp*);
extern void _multiply(fp*, const fp*, const fp*);
#elif defined(__x86_64__)
extern void (*_mul)(fp*, const fp*, const fp*);
extern void (*_multiply)(fp*, const fp*, const fp*);
#else
void _mul(fp*, const fp*, const fp*);
void _multiply(fp*, const fp*, const fp*);
#endif

// Add64 returns the sum with carry of x, y and carry: sum = x + y + carry.
Expand Down
99 changes: 68 additions & 31 deletions include/bls12-381/fp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ class fp
std::array<uint64_t, 6> d;

fp();
fp(const std::array<uint64_t, 6>& d);
explicit fp(const std::array<uint64_t, 6>& d);
fp(const fp& e);
static std::optional<fp> fromBytesBE(const std::span<const uint8_t, 48> in, const bool check = false, const bool raw = false);
static std::optional<fp> fromBytesLE(const std::span<const uint8_t, 48> in, const bool check = false, const bool raw = false);
static std::optional<fp> fromBytesBE(const std::span<const uint8_t, 48> in, const bool check = true, const bool raw = false);
static std::optional<fp> fromBytesLE(const std::span<const uint8_t, 48> in, const bool check = true, const bool raw = false);
void toBytesBE(const std::span<uint8_t, 48> out, const bool raw = false) const;
void toBytesLE(const std::span<uint8_t, 48> out, const bool raw = false) const;
std::array<uint8_t, 48> toBytesBE(const bool raw = false) const;
Expand All @@ -34,9 +34,35 @@ class fp
bool isEven() const;
bool isZero() const;
bool isOne() const;
std::strong_ordering cmp(const fp& e) const;
constexpr std::strong_ordering cmp(const fp& e) const {
for(int64_t i = 5; i >= 0; i--)
{
if(d[i] < e.d[i])
{
return std::strong_ordering::less;
}
if(d[i] > e.d[i])
{
return std::strong_ordering::greater;
}
}
return std::strong_ordering::equal;
};
bool equal(const fp& e) const;
bool sign() const;

fp add(const fp& e) const;
void addAssign(const fp& e);
fp dbl() const;
void doubleAssign();
fp subtract(const fp& e) const;
void subtractAssign(const fp& e);
fp negate() const;
fp multiply(const fp& e) const;
void multiplyAssign(const fp& e);
fp square() const;
void squareAssign();

void div2(const uint64_t& e);
uint64_t mul2();
fp toMont() const;
Expand All @@ -49,7 +75,11 @@ class fp
bool isLexicographicallyLargest() const;
template<size_t N> static fp modPrime(const std::array<uint64_t, N>& k);

std::strong_ordering operator<=>(const fp& e) const { return cmp(e); }
// Those operators are defined to support set and map.
// They are mathematically correctly in certain cases.
// However, there are still ambiguity there as the fp can be in Montgomery form or not.
// Please avoid using those operators.
constexpr std::strong_ordering operator<=>(const fp& e) const { return cmp(e); }

static const fp MODULUS; // base field modulus: p = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 or 0x1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB
static const uint64_t INP; // INP = -(p^{-1} mod 2^64) mod 2^64
Expand All @@ -74,10 +104,10 @@ class fp2
fp c1;

fp2();
fp2(const std::array<fp, 2>& e2);
explicit fp2(const std::array<fp, 2>& e2);
fp2(const fp2& e);
static std::optional<fp2> fromBytesBE(const std::span<const uint8_t, 96> in, const bool check = false, const bool raw = false);
static std::optional<fp2> fromBytesLE(const std::span<const uint8_t, 96> in, const bool check = false, const bool raw = false);
static std::optional<fp2> fromBytesBE(const std::span<const uint8_t, 96> in, const bool check = true, const bool raw = false);
static std::optional<fp2> fromBytesLE(const std::span<const uint8_t, 96> in, const bool check = true, const bool raw = false);
void toBytesBE(const std::span<uint8_t, 96> out, const bool raw = false) const;
void toBytesLE(const std::span<uint8_t, 96> out, const bool raw = false) const;
std::array<uint8_t, 96> toBytesBE(const bool raw = false) const;
Expand All @@ -90,16 +120,14 @@ class fp2
bool sign() const;
fp2 add(const fp2& e) const;
void addAssign(const fp2& e);
fp2 ladd(const fp2& e) const;
fp2 dbl() const;
void doubleAssign();
fp2 ldouble() const;
fp2 sub(const fp2& e) const;
void subAssign(const fp2& e);
fp2 neg() const;
fp2 conj() const;
fp2 mul(const fp2& e) const;
void mulAssign(const fp2& e);
fp2 subtract(const fp2& e) const;
void subtractAssign(const fp2& e);
fp2 negate() const;
fp2 conjugate() const;
fp2 multiply(const fp2& e) const;
void multiplyAssign(const fp2& e);
fp2 square() const;
void squareAssign();
fp2 mulByNonResidue() const;
Expand All @@ -113,6 +141,9 @@ class fp2
bool isQuadraticNonResidue() const;
bool isLexicographicallyLargest() const;

// Those operators are defined to support set and map.
// They are not mathematically correct.
// DO NOT use them to compare fp2.
auto operator<=>(const fp2&) const = default;

static const fp2 negativeOne2;
Expand All @@ -132,10 +163,10 @@ class fp6
fp2 c2;

fp6();
fp6(const std::array<fp2, 3>& e3);
explicit fp6(const std::array<fp2, 3>& e3);
fp6(const fp6& e);
static std::optional<fp6> fromBytesBE(const std::span<const uint8_t, 288> in, const bool check = false, const bool raw = false);
static std::optional<fp6> fromBytesLE(const std::span<const uint8_t, 288> in, const bool check = false, const bool raw = false);
static std::optional<fp6> fromBytesBE(const std::span<const uint8_t, 288> in, const bool check = true, const bool raw = false);
static std::optional<fp6> fromBytesLE(const std::span<const uint8_t, 288> in, const bool check = true, const bool raw = false);
void toBytesBE(const std::span<uint8_t, 288> out, const bool raw = false) const;
void toBytesLE(const std::span<uint8_t, 288> out, const bool raw = false) const;
std::array<uint8_t, 288> toBytesBE(const bool raw = false) const;
Expand All @@ -149,12 +180,13 @@ class fp6
void addAssign(const fp6& e);
fp6 dbl() const;
void doubleAssign();
fp6 sub(const fp6& e) const;
void subAssign(const fp6& e);
fp6 neg() const;
fp6 mul(const fp6& e) const;
void mulAssign(const fp6& e);
fp6 subtract(const fp6& e) const;
void subtractAssign(const fp6& e);
fp6 negate() const;
fp6 multiply(const fp6& e) const;
void multiplyAssign(const fp6& e);
fp6 square() const;
void squareAssign();
void mulBy01Assign(const fp2& e0, const fp2& e1);
fp6 mulBy01(const fp2& e0, const fp2& e1) const;
fp6 mulBy1(const fp2& e1) const;
Expand All @@ -179,10 +211,10 @@ class fp12
fp6 c1;

fp12();
fp12(const std::array<fp6, 2>& e2);
explicit fp12(const std::array<fp6, 2>& e2);
fp12(const fp12& e);
static std::optional<fp12> fromBytesBE(const std::span<const uint8_t, 576> in, const bool check = false, const bool raw = false);
static std::optional<fp12> fromBytesLE(const std::span<const uint8_t, 576> in, const bool check = false, const bool raw = false);
static std::optional<fp12> fromBytesBE(const std::span<const uint8_t, 576> in, const bool check = true, const bool raw = false);
static std::optional<fp12> fromBytesLE(const std::span<const uint8_t, 576> in, const bool check = true, const bool raw = false);
void toBytesBE(const std::span<uint8_t, 576> out, const bool raw = false) const;
void toBytesLE(const std::span<uint8_t, 576> out, const bool raw = false) const;
std::array<uint8_t, 576> toBytesBE(const bool raw = false) const;
Expand All @@ -194,14 +226,19 @@ class fp12
bool isGtValid() const;
bool equal(const fp12& e) const;
fp12 add(const fp12& e) const;
void addAssign(const fp12& e);
fp12 dbl() const;
fp12 sub(const fp12& e) const;
fp12 neg() const;
void doubleAssign();
fp12 subtract(const fp12& e) const;
void subtractAssign(const fp12& e);
fp12 negate() const;
fp12 conjugate() const;
fp12 square() const;
void squareAssign();
fp12 cyclotomicSquare() const;
fp12 mul(const fp12& e) const;
void mulAssign(const fp12& e);
void cyclotomicSquareAssign();
fp12 multiply(const fp12& e) const;
void multiplyAssign(const fp12& e);
static std::tuple<fp2, fp2> fp4Square(const fp2& e0, const fp2& e1);
fp12 inverse() const;
void mulBy014Assign(const fp2& e0, const fp2& e1, const fp2& e4);
Expand Down
Loading

0 comments on commit 1388808

Please sign in to comment.