diff --git a/bench/eth_bench.cpp b/bench/eth_bench.cpp index 41ddf9b..2046460 100644 --- a/bench/eth_bench.cpp +++ b/bench/eth_bench.cpp @@ -203,25 +203,25 @@ void benchG1Add2() { constexpr int numIters = 10000; g1 pbak = random_g1(); - auto performTest = [pbak](bool check, bool raw) { + auto performTest = [pbak](conv_opt opt) { array pRaw = {}; g1 p = pbak; - p.toJacobianBytesLE(pRaw, raw); + p.toJacobianBytesLE(pRaw, opt.to_mont ? from_mont::yes : from_mont::no); auto start = startStopwatch(); for (int i = 0; i < numIters; i++) { - p = *g1::fromJacobianBytesLE(pRaw, check, raw); + p = *g1::fromJacobianBytesLE(pRaw, opt); p.addAssign(p); - p.toJacobianBytesLE(pRaw, raw); + p.toJacobianBytesLE(pRaw, opt.to_mont ? from_mont::yes : from_mont::no); } - endStopwatch(string("check=") + std::to_string(check) + string(", raw=") + std::to_string(raw), start, numIters); + endStopwatch(string("check_valid=") + std::to_string(opt.check_valid) + string(", to_mont=") + std::to_string(opt.to_mont), start, numIters); }; - performTest(true, true); - performTest(true, false); - performTest(false, true); - performTest(false, false); + performTest({ .check_valid = true, .to_mont = true }); + performTest({ .check_valid = true, .to_mont = false }); + performTest({ .check_valid = false, .to_mont = true }); + performTest({ .check_valid = false, .to_mont = false }); } @@ -232,25 +232,25 @@ void benchG2Add2() { constexpr int numIters = 10000; g2 pbak = random_g2(); - auto performTest = [pbak](bool check, bool raw) { + auto performTest = [pbak](conv_opt opt) { array pRaw = {}; g2 p = pbak; - p.toJacobianBytesLE(pRaw, raw); + p.toJacobianBytesLE(pRaw, opt.to_mont ? from_mont::yes : from_mont::no); auto start = startStopwatch(); for (int i = 0; i < numIters; i++) { - p = *g2::fromJacobianBytesLE(pRaw, check, raw); + p = *g2::fromJacobianBytesLE(pRaw, opt); p.addAssign(p); - p.toJacobianBytesLE(pRaw, raw); + p.toJacobianBytesLE(pRaw, opt.to_mont ? from_mont::yes : from_mont::no); } - endStopwatch(string("check=") + std::to_string(check) + string(", raw=") + std::to_string(raw), start, numIters); + endStopwatch(string("check_valid=") + std::to_string(opt.check_valid) + string(", to_mont=") + std::to_string(opt.to_mont), start, numIters); }; - performTest(true, true); - performTest(true, false); - performTest(false, true); - performTest(false, false); + performTest({ .check_valid = true, .to_mont = true }); + performTest({ .check_valid = true, .to_mont = false }); + performTest({ .check_valid = false, .to_mont = true }); + performTest({ .check_valid = false, .to_mont = false }); } diff --git a/include/bls12-381/fp.hpp b/include/bls12-381/fp.hpp index 4b77374..7feb0d0 100644 --- a/include/bls12-381/fp.hpp +++ b/include/bls12-381/fp.hpp @@ -11,7 +11,19 @@ namespace bls12_381 { +// config when converting from bytes +// --------------------------------- +struct conv_opt { + bool check_valid; // check bytes hold a valid encoding + bool to_mont; // convert to montgomery form +}; + +// config when converting to bytes +// ------------------------------- +enum class from_mont : uint8_t { no = 0, yes }; + // element representation of 'fp' field which is the base field +// ------------------------------------------------------------ class fp { @@ -21,12 +33,14 @@ class fp fp(); explicit fp(const std::array& d); fp(const fp& e); - static std::optional fromBytesBE(const std::span in, const bool check = true, const bool raw = false); - static std::optional fromBytesLE(const std::span in, const bool check = true, const bool raw = false); - void toBytesBE(const std::span out, const bool raw = false) const; - void toBytesLE(const std::span out, const bool raw = false) const; - std::array toBytesBE(const bool raw = false) const; - std::array toBytesLE(const bool raw = false) const; + static std::optional fromBytesBE(const std::span in, + const conv_opt opt = { .check_valid = true, .to_mont = true }); + static std::optional fromBytesLE(const std::span in, + const conv_opt opt = { .check_valid = true, .to_mont = true }); + void toBytesBE(const std::span out, const from_mont fm = from_mont::yes) const; + void toBytesLE(const std::span out, const from_mont fm = from_mont::yes) const; + std::array toBytesBE(const from_mont fm = from_mont::yes) const; + std::array toBytesLE(const from_mont fm = from_mont::yes) const; static fp zero(); static fp one(); bool isValid() const; @@ -107,12 +121,14 @@ class fp2 fp2(); explicit fp2(const std::array& e2); fp2(const fp2& e); - static std::optional fromBytesBE(const std::span in, const bool check = true, const bool raw = false); - static std::optional fromBytesLE(const std::span in, const bool check = true, const bool raw = false); - void toBytesBE(const std::span out, const bool raw = false) const; - void toBytesLE(const std::span out, const bool raw = false) const; - std::array toBytesBE(const bool raw = false) const; - std::array toBytesLE(const bool raw = false) const; + static std::optional fromBytesBE(const std::span in, + const conv_opt opt = { .check_valid = true, .to_mont = true }); + static std::optional fromBytesLE(const std::span in, + const conv_opt opt = { .check_valid = true, .to_mont = true }); + void toBytesBE(const std::span out, const from_mont fm = from_mont::yes) const; + void toBytesLE(const std::span out, const from_mont fm = from_mont::yes) const; + std::array toBytesBE(const from_mont fm = from_mont::yes) const; + std::array toBytesLE(const from_mont fm = from_mont::yes) const; static fp2 zero(); static fp2 one(); bool isZero() const; @@ -166,12 +182,14 @@ class fp6 fp6(); explicit fp6(const std::array& e3); fp6(const fp6& e); - static std::optional fromBytesBE(const std::span in, const bool check = true, const bool raw = false); - static std::optional fromBytesLE(const std::span in, const bool check = true, const bool raw = false); - void toBytesBE(const std::span out, const bool raw = false) const; - void toBytesLE(const std::span out, const bool raw = false) const; - std::array toBytesBE(const bool raw = false) const; - std::array toBytesLE(const bool raw = false) const; + static std::optional fromBytesBE(const std::span in, + const conv_opt opt = { .check_valid = true, .to_mont = true }); + static std::optional fromBytesLE(const std::span in, + const conv_opt opt = { .check_valid = true, .to_mont = true }); + void toBytesBE(const std::span out, const from_mont fm = from_mont::yes) const; + void toBytesLE(const std::span out, const from_mont fm = from_mont::yes) const; + std::array toBytesBE(const from_mont fm = from_mont::yes) const; + std::array toBytesLE(const from_mont fm = from_mont::yes) const; static fp6 zero(); static fp6 one(); bool isZero() const; @@ -214,12 +232,14 @@ class fp12 fp12(); explicit fp12(const std::array& e2); fp12(const fp12& e); - static std::optional fromBytesBE(const std::span in, const bool check = true, const bool raw = false); - static std::optional fromBytesLE(const std::span in, const bool check = true, const bool raw = false); - void toBytesBE(const std::span out, const bool raw = false) const; - void toBytesLE(const std::span out, const bool raw = false) const; - std::array toBytesBE(const bool raw = false) const; - std::array toBytesLE(const bool raw = false) const; + static std::optional fromBytesBE(const std::span in, + const conv_opt opt = { .check_valid = true, .to_mont = true }); + static std::optional fromBytesLE(const std::span in, + const conv_opt opt = { .check_valid = true, .to_mont = true }); + void toBytesBE(const std::span out, const from_mont fm = from_mont::yes) const; + void toBytesLE(const std::span out, const from_mont fm = from_mont::yes) const; + std::array toBytesBE(const from_mont fm = from_mont::yes) const; + std::array toBytesLE(const from_mont fm = from_mont::yes) const; static fp12 zero(); static fp12 one(); bool isZero() const; diff --git a/include/bls12-381/g.hpp b/include/bls12-381/g.hpp index 9daad3a..ab53a7a 100644 --- a/include/bls12-381/g.hpp +++ b/include/bls12-381/g.hpp @@ -4,15 +4,11 @@ #include #include #include +#include namespace bls12_381 { -class fp; -class fp2; -class fp6; -class fp12; - // g1 is type for point in G1. // g1 is both used for Affine and Jacobian point representation. // If z is equal to one the point is considered as in affine form. @@ -27,20 +23,24 @@ class g1 g1(); explicit g1(const std::array& e3); g1(const g1& e); - static std::optional fromJacobianBytesBE(const std::span in, const bool check = false, const bool raw = false); - static std::optional fromJacobianBytesLE(const std::span in, const bool check = false, const bool raw = false); - static std::optional fromAffineBytesBE(const std::span in, const bool check = false, const bool raw = false); - static std::optional fromAffineBytesLE(const std::span in, const bool check = false, const bool raw = false); + static std::optional fromJacobianBytesBE(const std::span in, + conv_opt opt = { .check_valid = false, .to_mont = true }); + static std::optional fromJacobianBytesLE(const std::span in, + conv_opt opt = { .check_valid = false, .to_mont = true }); + static std::optional fromAffineBytesBE(const std::span in, + conv_opt opt = { .check_valid = false, .to_mont = true }); + static std::optional fromAffineBytesLE(const std::span in, + conv_opt opt = { .check_valid = false, .to_mont = true }); static std::optional fromCompressedBytesBE(const std::span in); - void toJacobianBytesBE(const std::span out, const bool raw = false) const; - void toJacobianBytesLE(const std::span out, const bool raw = false) const; - void toAffineBytesBE(const std::span out, const bool raw = false) const; - void toAffineBytesLE(const std::span out, const bool raw = false) const; + void toJacobianBytesBE(const std::span out, const from_mont fm = from_mont::yes) const; + void toJacobianBytesLE(const std::span out, const from_mont fm = from_mont::yes) const; + void toAffineBytesBE(const std::span out, const from_mont fm = from_mont::yes) const; + void toAffineBytesLE(const std::span out, const from_mont fm = from_mont::yes) const; void toCompressedBytesBE(const std::span out) const; - std::array toJacobianBytesBE(const bool raw = false) const; - std::array toJacobianBytesLE(const bool raw = false) const; - std::array toAffineBytesBE(const bool raw = false) const; - std::array toAffineBytesLE(const bool raw = false) const; + std::array toJacobianBytesBE(const from_mont fm = from_mont::yes) const; + std::array toJacobianBytesLE(const from_mont fm = from_mont::yes) const; + std::array toAffineBytesBE(const from_mont fm = from_mont::yes) const; + std::array toAffineBytesLE(const from_mont fm = from_mont::yes) const; std::array toCompressedBytesBE() const; static g1 zero(); static g1 one(); @@ -89,20 +89,24 @@ class g2 g2(); explicit g2(const std::array& e3); g2(const g2& e); - static std::optional fromJacobianBytesBE(const std::span in, const bool check = false, const bool raw = false); - static std::optional fromJacobianBytesLE(const std::span in, const bool check = false, const bool raw = false); - static std::optional fromAffineBytesBE(const std::span in, const bool check = false, const bool raw = false); - static std::optional fromAffineBytesLE(const std::span in, const bool check = false, const bool raw = false); + static std::optional fromJacobianBytesBE(const std::span in, + conv_opt opt = { .check_valid = false, .to_mont = true }); + static std::optional fromJacobianBytesLE(const std::span in, + conv_opt opt = { .check_valid = false, .to_mont = true }); + static std::optional fromAffineBytesBE(const std::span in, + conv_opt opt = { .check_valid = false, .to_mont = true }); + static std::optional fromAffineBytesLE(const std::span in, + conv_opt opt = { .check_valid = false, .to_mont = true }); static std::optional fromCompressedBytesBE(const std::span in); - void toJacobianBytesBE(const std::span out, const bool raw = false) const; - void toJacobianBytesLE(const std::span out, const bool raw = false) const; - void toAffineBytesBE(const std::span out, const bool raw = false) const; - void toAffineBytesLE(const std::span out, const bool raw = false) const; + void toJacobianBytesBE(const std::span out, const from_mont fm = from_mont::yes) const; + void toJacobianBytesLE(const std::span out, const from_mont fm = from_mont::yes) const; + void toAffineBytesBE(const std::span out, const from_mont fm = from_mont::yes) const; + void toAffineBytesLE(const std::span out, const from_mont fm = from_mont::yes) const; void toCompressedBytesBE(const std::span out) const; - std::array toJacobianBytesBE(const bool raw = false) const; - std::array toJacobianBytesLE(const bool raw = false) const; - std::array toAffineBytesBE(const bool raw = false) const; - std::array toAffineBytesLE(const bool raw = false) const; + std::array toJacobianBytesBE(const from_mont fm = from_mont::yes) const; + std::array toJacobianBytesLE(const from_mont fm = from_mont::yes) const; + std::array toAffineBytesBE(const from_mont fm = from_mont::yes) const; + std::array toAffineBytesLE(const from_mont fm = from_mont::yes) const; std::array toCompressedBytesBE() const; static g2 zero(); static g2 one(); diff --git a/src/fp.cpp b/src/fp.cpp index 4379033..61e9a21 100644 --- a/src/fp.cpp +++ b/src/fp.cpp @@ -17,46 +17,46 @@ fp::fp(const fp& e) : d{e.d[0], e.d[1], e.d[2], e.d[3], e.d[4], e.d[5]} { } -optional fp::fromBytesBE(const span in, const bool check, const bool raw) +optional fp::fromBytesBE(const span in, const conv_opt opt) { // We decided to always validate the input here. But we reserve the flag. fp e = fp(scalar::fromBytesBE<6>(in)); - if(check && !e.isValid()) return {}; - if(raw) return e; - else return e.toMont(); + if(opt.check_valid && !e.isValid()) return {}; + if(opt.to_mont) return e.toMont(); + else return e; } -optional fp::fromBytesLE(const span in, const bool check, const bool raw) +optional fp::fromBytesLE(const span in, const conv_opt opt) { // We decided to always validate the input here. But we reserve the flag. fp e = fp(scalar::fromBytesLE<6>(in)); - if(check && !e.isValid()) return {}; - if(raw) return e; - else return e.toMont(); + if(opt.check_valid && !e.isValid()) return {}; + if(opt.to_mont) return e.toMont(); + else return e; } -void fp::toBytesBE(const span out, const bool raw) const +void fp::toBytesBE(const span out, const from_mont fm /* = from_mont::yes */) const { - if(raw) scalar::toBytesBE<6>(d, out); - else scalar::toBytesBE<6>(fromMont().d, out); + if(fm == from_mont::yes) scalar::toBytesBE<6>(fromMont().d, out); + else scalar::toBytesBE<6>(d, out); } -void fp::toBytesLE(const span out, const bool raw) const +void fp::toBytesLE(const span out, const from_mont fm /* = from_mont::yes */) const { - if(raw) scalar::toBytesLE<6>(d, out); - else scalar::toBytesLE<6>(fromMont().d, out); + if(fm == from_mont::yes) scalar::toBytesLE<6>(fromMont().d, out); + else scalar::toBytesLE<6>(d, out); } -array fp::toBytesBE(const bool raw) const +array fp::toBytesBE(const from_mont fm /* = from_mont::yes */) const { - if(raw) return scalar::toBytesBE<6>(d); - else return scalar::toBytesBE<6>(fromMont().d); + if(fm == from_mont::yes) return scalar::toBytesBE<6>(fromMont().d); + else return scalar::toBytesBE<6>(d); } -array fp::toBytesLE(const bool raw) const +array fp::toBytesLE(const from_mont fm /* = from_mont::yes */) const { - if(raw) return scalar::toBytesLE<6>(d); - else return scalar::toBytesLE<6>(fromMont().d); + if(fm == from_mont::yes) return scalar::toBytesLE<6>(fromMont().d); + else return scalar::toBytesLE<6>(d); } fp fp::zero() @@ -465,45 +465,45 @@ fp2::fp2(const fp2& e) : c0(e.c0), c1(e.c1) { } -optional fp2::fromBytesBE(const span in, const bool check, const bool raw) +optional fp2::fromBytesBE(const span in, const conv_opt opt) { - optional c1 = fp::fromBytesBE(span(&in[ 0], &in[48]), check, raw); - optional c0 = fp::fromBytesBE(span(&in[48], &in[96]), check, raw); + optional c1 = fp::fromBytesBE(span(&in[ 0], &in[48]), opt); + optional c0 = fp::fromBytesBE(span(&in[48], &in[96]), opt); if(!c1 || !c0) return {}; return fp2({*c0, *c1}); } -optional fp2::fromBytesLE(const span in, const bool check, const bool raw) +optional fp2::fromBytesLE(const span in, const conv_opt opt) { - optional c0 = fp::fromBytesLE(span(&in[ 0], &in[48]), check, raw); - optional c1 = fp::fromBytesLE(span(&in[48], &in[96]), check, raw); + optional c0 = fp::fromBytesLE(span(&in[ 0], &in[48]), opt); + optional c1 = fp::fromBytesLE(span(&in[48], &in[96]), opt); if(!c1 || !c0) return {}; return fp2({*c0, *c1}); } -void fp2::toBytesBE(const span out, const bool raw) const +void fp2::toBytesBE(const span out, const from_mont fm /* = from_mont::yes */) const { - memcpy(&out[ 0], &c1.toBytesBE(raw)[0], 48); - memcpy(&out[48], &c0.toBytesBE(raw)[0], 48); + memcpy(&out[ 0], &c1.toBytesBE(fm)[0], 48); + memcpy(&out[48], &c0.toBytesBE(fm)[0], 48); } -void fp2::toBytesLE(const span out, const bool raw) const +void fp2::toBytesLE(const span out, const from_mont fm /* = from_mont::yes */) const { - memcpy(&out[ 0], &c0.toBytesLE(raw)[0], 48); - memcpy(&out[48], &c1.toBytesLE(raw)[0], 48); + memcpy(&out[ 0], &c0.toBytesLE(fm)[0], 48); + memcpy(&out[48], &c1.toBytesLE(fm)[0], 48); } -array fp2::toBytesBE(const bool raw) const +array fp2::toBytesBE(const from_mont fm /* = from_mont::yes */) const { array out; - toBytesBE(out, raw); + toBytesBE(out, fm); return out; } -array fp2::toBytesLE(const bool raw) const +array fp2::toBytesLE(const from_mont fm /* = from_mont::yes */) const { array out; - toBytesLE(out, raw); + toBytesLE(out, fm); return out; } @@ -825,49 +825,49 @@ fp6::fp6(const fp6& e) : c0(e.c0), c1(e.c1), c2(e.c2) { } -optional fp6::fromBytesBE(const span in, const bool check, const bool raw) +optional fp6::fromBytesBE(const span in, const conv_opt opt) { - optional c2 = fp2::fromBytesBE(span(&in[ 0], &in[ 96]), check, raw); - optional c1 = fp2::fromBytesBE(span(&in[ 96], &in[192]), check, raw); - optional c0 = fp2::fromBytesBE(span(&in[192], &in[288]), check, raw); + optional c2 = fp2::fromBytesBE(span(&in[ 0], &in[ 96]), opt); + optional c1 = fp2::fromBytesBE(span(&in[ 96], &in[192]), opt); + optional c0 = fp2::fromBytesBE(span(&in[192], &in[288]), opt); if(!c2 || !c1 || !c0) return {}; return fp6({*c0, *c1, *c2}); } -optional fp6::fromBytesLE(const span in, const bool check, const bool raw) +optional fp6::fromBytesLE(const span in, const conv_opt opt) { - optional c0 = fp2::fromBytesLE(span(&in[ 0], &in[ 96]), check, raw); - optional c1 = fp2::fromBytesLE(span(&in[ 96], &in[192]), check, raw); - optional c2 = fp2::fromBytesLE(span(&in[192], &in[288]), check, raw); + optional c0 = fp2::fromBytesLE(span(&in[ 0], &in[ 96]), opt); + optional c1 = fp2::fromBytesLE(span(&in[ 96], &in[192]), opt); + optional c2 = fp2::fromBytesLE(span(&in[192], &in[288]), opt); if(!c2 || !c1 || !c0) return {}; return fp6({*c0, *c1, *c2}); } -void fp6::toBytesBE(const span out, const bool raw) const +void fp6::toBytesBE(const span out, const from_mont fm /* = from_mont::yes */) const { - memcpy(&out[ 0], &c2.toBytesBE(raw)[0], 96); - memcpy(&out[ 96], &c1.toBytesBE(raw)[0], 96); - memcpy(&out[192], &c0.toBytesBE(raw)[0], 96); + memcpy(&out[ 0], &c2.toBytesBE(fm)[0], 96); + memcpy(&out[ 96], &c1.toBytesBE(fm)[0], 96); + memcpy(&out[192], &c0.toBytesBE(fm)[0], 96); } -void fp6::toBytesLE(const span out, const bool raw) const +void fp6::toBytesLE(const span out, const from_mont fm /* = from_mont::yes */) const { - memcpy(&out[ 0], &c0.toBytesLE(raw)[0], 96); - memcpy(&out[ 96], &c1.toBytesLE(raw)[0], 96); - memcpy(&out[192], &c2.toBytesLE(raw)[0], 96); + memcpy(&out[ 0], &c0.toBytesLE(fm)[0], 96); + memcpy(&out[ 96], &c1.toBytesLE(fm)[0], 96); + memcpy(&out[192], &c2.toBytesLE(fm)[0], 96); } -array fp6::toBytesBE(const bool raw) const +array fp6::toBytesBE(const from_mont fm /* = from_mont::yes */) const { array out; - toBytesBE(out, raw); + toBytesBE(out, fm); return out; } -array fp6::toBytesLE(const bool raw) const +array fp6::toBytesLE(const from_mont fm /* = from_mont::yes */) const { array out; - toBytesLE(out, raw); + toBytesLE(out, fm); return out; } @@ -1238,45 +1238,45 @@ fp12::fp12(const fp12& e) : c0(e.c0), c1(e.c1) { } -optional fp12::fromBytesBE(const span in, const bool check, const bool raw) +optional fp12::fromBytesBE(const span in, const conv_opt opt) { - optional c1 = fp6::fromBytesBE(span(&in[ 0], &in[288]), check, raw); - optional c0 = fp6::fromBytesBE(span(&in[288], &in[576]), check, raw); + optional c1 = fp6::fromBytesBE(span(&in[ 0], &in[288]), opt); + optional c0 = fp6::fromBytesBE(span(&in[288], &in[576]), opt); if(!c1 || !c0) return {}; return fp12({*c0, *c1}); } -optional fp12::fromBytesLE(const span in, const bool check, const bool raw) +optional fp12::fromBytesLE(const span in, const conv_opt opt) { - optional c0 = fp6::fromBytesLE(span(&in[ 0], &in[288]), check, raw); - optional c1 = fp6::fromBytesLE(span(&in[288], &in[576]), check, raw); + optional c0 = fp6::fromBytesLE(span(&in[ 0], &in[288]), opt); + optional c1 = fp6::fromBytesLE(span(&in[288], &in[576]), opt); if(!c1 || !c0) return {}; return fp12({*c0, *c1}); } -void fp12::toBytesBE(const span out, const bool raw) const +void fp12::toBytesBE(const span out, const from_mont fm /* = from_mont::yes */) const { - memcpy(&out[ 0], &c1.toBytesBE(raw)[0], 288); - memcpy(&out[288], &c0.toBytesBE(raw)[0], 288); + memcpy(&out[ 0], &c1.toBytesBE(fm)[0], 288); + memcpy(&out[288], &c0.toBytesBE(fm)[0], 288); } -void fp12::toBytesLE(const span out, const bool raw) const +void fp12::toBytesLE(const span out, const from_mont fm /* = from_mont::yes */) const { - memcpy(&out[ 0], &c0.toBytesLE(raw)[0], 288); - memcpy(&out[288], &c1.toBytesLE(raw)[0], 288); + memcpy(&out[ 0], &c0.toBytesLE(fm)[0], 288); + memcpy(&out[288], &c1.toBytesLE(fm)[0], 288); } -array fp12::toBytesBE(const bool raw) const +array fp12::toBytesBE(const from_mont fm /* = from_mont::yes */) const { array out; - toBytesBE(out, raw); + toBytesBE(out, fm); return out; } -array fp12::toBytesLE(const bool raw) const +array fp12::toBytesLE(const from_mont fm /* = from_mont::yes */) const { array out; - toBytesLE(out, raw); + toBytesLE(out, fm); return out; } diff --git a/src/g.cpp b/src/g.cpp index 6aac590..d77e560 100644 --- a/src/g.cpp +++ b/src/g.cpp @@ -17,41 +17,47 @@ g1::g1(const g1& e) : x(e.x), y(e.y), z(e.z) { } -optional g1::fromJacobianBytesBE(const span in, const bool check, const bool raw) +optional g1::fromJacobianBytesBE(const span in, conv_opt opt) { // We decided to always validate the input here. Check flag will only affect on-curve checks. - optional x = fp::fromBytesBE(span(&in[ 0], &in[ 48]), true, raw); - optional y = fp::fromBytesBE(span(&in[48], &in[ 96]), true, raw); - optional z = fp::fromBytesBE(span(&in[96], &in[144]), true, raw); + bool curve_check = opt.check_valid; + opt.check_valid = true; + optional x = fp::fromBytesBE(span(&in[ 0], &in[ 48]), opt); + optional y = fp::fromBytesBE(span(&in[48], &in[ 96]), opt); + optional z = fp::fromBytesBE(span(&in[96], &in[144]), opt); if(!x || !y || !z) return {}; g1 p = g1({*x, *y, *z}); - if(check && !p.isOnCurve()) + if(curve_check && !p.isOnCurve()) { return {}; } return p; } -optional g1::fromJacobianBytesLE(const span in, const bool check, const bool raw) +optional g1::fromJacobianBytesLE(const span in, conv_opt opt) { // We decided to always validate the input here. Check flag will only affect on-curve checks. - optional x = fp::fromBytesLE(span(&in[ 0], &in[ 48]), true, raw); - optional y = fp::fromBytesLE(span(&in[48], &in[ 96]), true, raw); - optional z = fp::fromBytesLE(span(&in[96], &in[144]), true, raw); + bool curve_check = opt.check_valid; + opt.check_valid = true; + optional x = fp::fromBytesLE(span(&in[ 0], &in[ 48]), opt); + optional y = fp::fromBytesLE(span(&in[48], &in[ 96]), opt); + optional z = fp::fromBytesLE(span(&in[96], &in[144]), opt); if(!x || !y || !z) return {}; g1 p = g1({*x, *y, *z}); - if(check && !p.isOnCurve()) + if(curve_check && !p.isOnCurve()) { return {}; } return p; } -optional g1::fromAffineBytesBE(const span in, const bool check, const bool raw) +optional g1::fromAffineBytesBE(const span in, conv_opt opt) { // We decided to always validate the input here. Check flag will only affect on-curve checks. - optional x = fp::fromBytesBE(span(&in[ 0], &in[ 48]), true, raw); - optional y = fp::fromBytesBE(span(&in[48], &in[ 96]), true, raw); + bool curve_check = opt.check_valid; + opt.check_valid = true; + optional x = fp::fromBytesBE(span(&in[ 0], &in[ 48]), opt); + optional y = fp::fromBytesBE(span(&in[48], &in[ 96]), opt); if(!x || !y) return {}; // check if given input points to infinity if(x->isZero() && y->isZero()) @@ -60,18 +66,20 @@ optional g1::fromAffineBytesBE(const span in, const bool } fp z = fp::one(); g1 p = g1({*x, *y, z}); - if(check && !p.isOnCurve()) + if(curve_check && !p.isOnCurve()) { return {}; } return p; } -optional g1::fromAffineBytesLE(const span in, const bool check, const bool raw) +optional g1::fromAffineBytesLE(const span in, conv_opt opt) { // We decided to always validate the input here. Check flag will only affect on-curve checks. - optional x = fp::fromBytesLE(span(&in[ 0], &in[ 48]), true, raw); - optional y = fp::fromBytesLE(span(&in[48], &in[ 96]), true, raw); + bool curve_check = opt.check_valid; + opt.check_valid = true; + optional x = fp::fromBytesLE(span(&in[ 0], &in[ 48]), opt); + optional y = fp::fromBytesLE(span(&in[48], &in[ 96]), opt); if(!x || !y) return {}; // check if given input points to infinity if(x->isZero() && y->isZero()) @@ -80,7 +88,7 @@ optional g1::fromAffineBytesLE(const span in, const bool } fp z = fp::one(); g1 p = g1({*x, *y, z}); - if(check && !p.isOnCurve()) + if(curve_check && !p.isOnCurve()) { return {}; } @@ -129,21 +137,21 @@ optional g1::fromCompressedBytesBE(const span in) return p; } -void g1::toJacobianBytesBE(const span out, const bool raw) const +void g1::toJacobianBytesBE(const span out, const from_mont fm /* = from_mont::yes */) const { - memcpy(&out[ 0], &x.toBytesBE(raw)[0], 48); - memcpy(&out[48], &y.toBytesBE(raw)[0], 48); - memcpy(&out[96], &z.toBytesBE(raw)[0], 48); + memcpy(&out[ 0], &x.toBytesBE(fm)[0], 48); + memcpy(&out[48], &y.toBytesBE(fm)[0], 48); + memcpy(&out[96], &z.toBytesBE(fm)[0], 48); } -void g1::toJacobianBytesLE(const span out, const bool raw) const +void g1::toJacobianBytesLE(const span out, const from_mont fm /* = from_mont::yes */) const { - memcpy(&out[ 0], &x.toBytesLE(raw)[0], 48); - memcpy(&out[48], &y.toBytesLE(raw)[0], 48); - memcpy(&out[96], &z.toBytesLE(raw)[0], 48); + memcpy(&out[ 0], &x.toBytesLE(fm)[0], 48); + memcpy(&out[48], &y.toBytesLE(fm)[0], 48); + memcpy(&out[96], &z.toBytesLE(fm)[0], 48); } -void g1::toAffineBytesBE(const span out, const bool raw) const +void g1::toAffineBytesBE(const span out, const from_mont fm /* = from_mont::yes */) const { if(isZero()) { @@ -151,11 +159,11 @@ void g1::toAffineBytesBE(const span out, const bool raw) const return; } g1 r = affine(); - memcpy(&out[ 0], &r.x.toBytesBE(raw)[0], 48); - memcpy(&out[48], &r.y.toBytesBE(raw)[0], 48); + memcpy(&out[ 0], &r.x.toBytesBE(fm)[0], 48); + memcpy(&out[48], &r.y.toBytesBE(fm)[0], 48); } -void g1::toAffineBytesLE(const span out, const bool raw) const +void g1::toAffineBytesLE(const span out, const from_mont fm /* = from_mont::yes */) const { if(isZero()) { @@ -163,8 +171,8 @@ void g1::toAffineBytesLE(const span out, const bool raw) const return; } g1 r = affine(); - memcpy(&out[ 0], &r.x.toBytesLE(raw)[0], 48); - memcpy(&out[48], &r.y.toBytesLE(raw)[0], 48); + memcpy(&out[ 0], &r.x.toBytesLE(fm)[0], 48); + memcpy(&out[48], &r.y.toBytesLE(fm)[0], 48); } void g1::toCompressedBytesBE(const span out) const @@ -188,31 +196,31 @@ void g1::toCompressedBytesBE(const span out) const out[0] |= 0x80; } -array g1::toJacobianBytesBE(const bool raw) const +array g1::toJacobianBytesBE(const from_mont fm /* = from_mont::yes */) const { array out; - toJacobianBytesBE(out, raw); + toJacobianBytesBE(out, fm); return out; } -array g1::toJacobianBytesLE(const bool raw) const +array g1::toJacobianBytesLE(const from_mont fm /* = from_mont::yes */) const { array out; - toJacobianBytesLE(out, raw); + toJacobianBytesLE(out, fm); return out; } -array g1::toAffineBytesBE(const bool raw) const +array g1::toAffineBytesBE(const from_mont fm /* = from_mont::yes */) const { array out; - toAffineBytesBE(out, raw); + toAffineBytesBE(out, fm); return out; } -array g1::toAffineBytesLE(const bool raw) const +array g1::toAffineBytesLE(const from_mont fm /* = from_mont::yes */) const { array out; - toAffineBytesLE(out, raw); + toAffineBytesLE(out, fm); return out; } @@ -722,41 +730,47 @@ g2::g2(const g2& e) : x(e.x), y(e.y), z(e.z) { } -optional g2::fromJacobianBytesBE(const span in, const bool check, const bool raw) +optional g2::fromJacobianBytesBE(const span in, conv_opt opt) { // We decided to always validate the input here. Check flag will only affect on-curve checks. - optional x = fp2::fromBytesBE(span(&in[ 0], &in[ 96]), true, raw); - optional y = fp2::fromBytesBE(span(&in[ 96], &in[192]), true, raw); - optional z = fp2::fromBytesBE(span(&in[192], &in[288]), true, raw); + bool curve_check = opt.check_valid; + opt.check_valid = true; + optional x = fp2::fromBytesBE(span(&in[ 0], &in[ 96]), opt); + optional y = fp2::fromBytesBE(span(&in[ 96], &in[192]), opt); + optional z = fp2::fromBytesBE(span(&in[192], &in[288]), opt); if(!x || !y || !z) return {}; g2 p = g2({*x, *y, *z}); - if(check && !p.isOnCurve()) + if(curve_check && !p.isOnCurve()) { return {}; } return p; } -optional g2::fromJacobianBytesLE(const span in, const bool check, const bool raw) +optional g2::fromJacobianBytesLE(const span in, conv_opt opt) { // We decided to always validate the input here. Check flag will only affect on-curve checks. - optional x = fp2::fromBytesLE(span(&in[ 0], &in[ 96]), true, raw); - optional y = fp2::fromBytesLE(span(&in[ 96], &in[192]), true, raw); - optional z = fp2::fromBytesLE(span(&in[192], &in[288]), true, raw); + bool curve_check = opt.check_valid; + opt.check_valid = true; + optional x = fp2::fromBytesLE(span(&in[ 0], &in[ 96]), opt); + optional y = fp2::fromBytesLE(span(&in[ 96], &in[192]), opt); + optional z = fp2::fromBytesLE(span(&in[192], &in[288]), opt); if(!x || !y || !z) return {}; g2 p = g2({*x, *y, *z}); - if(check && !p.isOnCurve()) + if(curve_check && !p.isOnCurve()) { return {}; } return p; } -optional g2::fromAffineBytesBE(const span in, const bool check, const bool raw) +optional g2::fromAffineBytesBE(const span in, conv_opt opt) { // We decided to always validate the input here. Check flag will only affect on-curve checks. - optional x = fp2::fromBytesBE(span(&in[ 0], &in[ 96]), true, raw); - optional y = fp2::fromBytesBE(span(&in[ 96], &in[192]), true, raw); + bool curve_check = opt.check_valid; + opt.check_valid = true; + optional x = fp2::fromBytesBE(span(&in[ 0], &in[ 96]), opt); + optional y = fp2::fromBytesBE(span(&in[ 96], &in[192]), opt); if(!x || !y) return {}; // check if given input points to infinity if(x->isZero() && y->isZero()) @@ -765,18 +779,20 @@ optional g2::fromAffineBytesBE(const span in, const bool } fp2 z = fp2::one(); g2 p = g2({*x, *y, z}); - if(check && !p.isOnCurve()) + if(curve_check && !p.isOnCurve()) { return {}; } return p; } -optional g2::fromAffineBytesLE(const span in, const bool check, const bool raw) +optional g2::fromAffineBytesLE(const span in, conv_opt opt) { // We decided to always validate the input here. Check flag will only affect on-curve checks. - optional x = fp2::fromBytesLE(span(&in[ 0], &in[ 96]), true, raw); - optional y = fp2::fromBytesLE(span(&in[ 96], &in[192]), true, raw); + bool curve_check = opt.check_valid; + opt.check_valid = true; + optional x = fp2::fromBytesLE(span(&in[ 0], &in[ 96]), opt); + optional y = fp2::fromBytesLE(span(&in[ 96], &in[192]), opt); if(!x || !y) return {}; // check if given input points to infinity if(x->isZero() && y->isZero()) @@ -785,7 +801,7 @@ optional g2::fromAffineBytesLE(const span in, const bool } fp2 z = fp2::one(); g2 p = g2({*x, *y, z}); - if(check && !p.isOnCurve()) + if(curve_check && !p.isOnCurve()) { return {}; } @@ -839,21 +855,21 @@ optional g2::fromCompressedBytesBE(const span in) return p; } -void g2::toJacobianBytesBE(const span out, const bool raw) const +void g2::toJacobianBytesBE(const span out, const from_mont fm /* = from_mont::yes */) const { - memcpy(&out[ 0], &x.toBytesBE(raw)[0], 96); - memcpy(&out[ 96], &y.toBytesBE(raw)[0], 96); - memcpy(&out[192], &z.toBytesBE(raw)[0], 96); + memcpy(&out[ 0], &x.toBytesBE(fm)[0], 96); + memcpy(&out[ 96], &y.toBytesBE(fm)[0], 96); + memcpy(&out[192], &z.toBytesBE(fm)[0], 96); } -void g2::toJacobianBytesLE(const span out, const bool raw) const +void g2::toJacobianBytesLE(const span out, const from_mont fm /* = from_mont::yes */) const { - memcpy(&out[ 0], &x.toBytesLE(raw)[0], 96); - memcpy(&out[ 96], &y.toBytesLE(raw)[0], 96); - memcpy(&out[192], &z.toBytesLE(raw)[0], 96); + memcpy(&out[ 0], &x.toBytesLE(fm)[0], 96); + memcpy(&out[ 96], &y.toBytesLE(fm)[0], 96); + memcpy(&out[192], &z.toBytesLE(fm)[0], 96); } -void g2::toAffineBytesBE(const span out, const bool raw) const +void g2::toAffineBytesBE(const span out, const from_mont fm /* = from_mont::yes */) const { if(isZero()) { @@ -861,11 +877,11 @@ void g2::toAffineBytesBE(const span out, const bool raw) const return; } g2 r = affine(); - memcpy(&out[ 0], &r.x.toBytesBE(raw)[0], 96); - memcpy(&out[96], &r.y.toBytesBE(raw)[0], 96); + memcpy(&out[ 0], &r.x.toBytesBE(fm)[0], 96); + memcpy(&out[96], &r.y.toBytesBE(fm)[0], 96); } -void g2::toAffineBytesLE(const span out, const bool raw) const +void g2::toAffineBytesLE(const span out, const from_mont fm /* = from_mont::yes */) const { if(isZero()) { @@ -873,8 +889,8 @@ void g2::toAffineBytesLE(const span out, const bool raw) const return; } g2 r = affine(); - memcpy(&out[ 0], &r.x.toBytesLE(raw)[0], 96); - memcpy(&out[96], &r.y.toBytesLE(raw)[0], 96); + memcpy(&out[ 0], &r.x.toBytesLE(fm)[0], 96); + memcpy(&out[96], &r.y.toBytesLE(fm)[0], 96); } void g2::toCompressedBytesBE(const span out) const @@ -899,31 +915,31 @@ void g2::toCompressedBytesBE(const span out) const out[0] |= 0x80; } -array g2::toJacobianBytesBE(const bool raw) const +array g2::toJacobianBytesBE(const from_mont fm /* = from_mont::yes */) const { array out; - toJacobianBytesBE(out, raw); + toJacobianBytesBE(out, fm); return out; } -array g2::toJacobianBytesLE(const bool raw) const +array g2::toJacobianBytesLE(const from_mont fm /* = from_mont::yes */) const { array out; - toJacobianBytesLE(out, raw); + toJacobianBytesLE(out, fm); return out; } -array g2::toAffineBytesBE(const bool raw) const +array g2::toAffineBytesBE(const from_mont fm /* = from_mont::yes */) const { array out; - toAffineBytesBE(out, raw); + toAffineBytesBE(out, fm); return out; } -array g2::toAffineBytesLE(const bool raw) const +array g2::toAffineBytesLE(const from_mont fm /* = from_mont::yes */) const { array out; - toAffineBytesLE(out, raw); + toAffineBytesLE(out, fm); return out; } diff --git a/src/signatures.cpp b/src/signatures.cpp index 63b7f20..7dbc161 100644 --- a/src/signatures.cpp +++ b/src/signatures.cpp @@ -630,7 +630,7 @@ bool aggregate_verify( g2 pop_prove(const array& sk) { g1 pk = public_key(sk); - array msg = pk.toAffineBytesLE(false); + array msg = pk.toAffineBytesLE(from_mont::yes); g2 hashed_key = fromMessage(vector(msg.begin(), msg.end()), POP_CIPHERSUITE_ID); return hashed_key.scale(sk); } @@ -640,7 +640,7 @@ bool pop_verify( const g2& signature_proof ) { - array msg = pubkey.toAffineBytesLE(false); + array msg = pubkey.toAffineBytesLE(from_mont::yes); const g2 hashedPoint = fromMessage(vector(msg.begin(), msg.end()), POP_CIPHERSUITE_ID); if(!pubkey.isOnCurve() || !pubkey.inCorrectSubgroup()) diff --git a/test/unittests.cpp b/test/unittests.cpp index d9738e6..422b087 100644 --- a/test/unittests.cpp +++ b/test/unittests.cpp @@ -231,7 +231,7 @@ void TestFieldElementArithmeticCornerCases() { auto testSqureMul = [](const char* in, const char* expectedSquare, const char* expectedAdd) { // Input should be convert to Montgomery form, so "raw" = false - auto input = fp::fromBytesBE(hexToBytes<48>(in), true, false); + auto input = fp::fromBytesBE(hexToBytes<48>(in), { .check_valid = true, .to_mont = true }); if (0 == strcmp("NA", expectedSquare)) { if (input) { @@ -241,8 +241,8 @@ void TestFieldElementArithmeticCornerCases() { } // Expected result will be compared against numbers converted back from Montgomery form, so "raw" = true - auto fpExpectedSquare = fp::fromBytesBE(hexToBytes<48>(expectedSquare), false, true); - auto fpExpectedAdd = fp::fromBytesBE(hexToBytes<48>(expectedAdd), false, true); + auto fpExpectedSquare = fp::fromBytesBE(hexToBytes<48>(expectedSquare), { .check_valid=false, .to_mont=false }); + auto fpExpectedAdd = fp::fromBytesBE(hexToBytes<48>(expectedAdd), { .check_valid = false, .to_mont = false }); fp s,m,a,d; fp s1,m1,a1,d1; @@ -437,7 +437,7 @@ void TestInverse() { throw invalid_argument("2 * 2^-1 != 1"); } - auto pminus1 = *fp::fromBytesBE(hexToBytes<48>("1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAA"), false, true); + auto pminus1 = *fp::fromBytesBE(hexToBytes<48>("1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAA"), { .check_valid = false, .to_mont = false }); if (!pminus1.multiply(pminus1.inverse()).equal(fp::one())) { throw invalid_argument("(p-1) * (p-1)^-1 != 1"); } @@ -497,7 +497,7 @@ void TestMod() { auto s = hexToBytes<64>(testVectorInput[i]); auto k = scalar::fromBytesBE<8>(s); fp r = fp::modPrime<8>(k); - auto fpExpected = fp::fromBytesBE(hexToBytes<48>(testVectorExpected[i]), false, false); + auto fpExpected = fp::fromBytesBE(hexToBytes<48>(testVectorExpected[i]), { .check_valid = false, .to_mont = true }); if(!fpExpected->equal(r)) { throw invalid_argument("r != expected for Mod"); @@ -531,10 +531,10 @@ void TestExp() { for (size_t i = 0; i < sizeof(testVectorInput)/sizeof(const char*); ++ i) { auto s = hexToBytes<64>(testVectorInput[i]); - auto b = fp::fromBytesBE(hexToBytes<48>(testVectorInput2[i]), false, false); + auto b = fp::fromBytesBE(hexToBytes<48>(testVectorInput2[i]), { .check_valid = false, .to_mont = true }); auto k = scalar::fromBytesBE<8>(s); fp r = b->exp(k); - auto fpExpected = fp::fromBytesBE(hexToBytes<48>(testVectorExpected[i]), false, false); + auto fpExpected = fp::fromBytesBE(hexToBytes<48>(testVectorExpected[i]), { .check_valid = false, .to_mont = true }); if(!fpExpected->equal(r)) { throw invalid_argument("r != expected for Exp"); @@ -750,12 +750,12 @@ void TestG1SerializationGarbage() { array buf; buf.fill(0xff); for (int i = 0 ; i < 4; ++i ) { - auto a = g1::fromJacobianBytesBE(buf, i < 2, i%2); + auto a = g1::fromJacobianBytesBE(buf, { .check_valid = i<2, .to_mont = !(i%2) }); if(a) { throw invalid_argument("g1, jacobianBE: serialization not catching invalid input"); } - auto b = g1::fromJacobianBytesLE(buf, i < 2, i%2); + auto b = g1::fromJacobianBytesLE(buf, { .check_valid = i<2, .to_mont = !(i%2) }); if(b) { throw invalid_argument("g1, jacobianLE: serialization not catching invalid input"); @@ -763,12 +763,12 @@ void TestG1SerializationGarbage() { } for (int i = 0 ; i < 4; ++i ) { - auto a = g1::fromAffineBytesBE(std::span{buf.begin(),96}, i < 2, i%2); + auto a = g1::fromAffineBytesBE(std::span{buf.begin(),96}, { .check_valid = i<2, .to_mont = !(i%2) }); if(a) { throw invalid_argument("g1, affineBE: serialization not catching invalid input"); } - auto b = g1::fromAffineBytesLE(std::span{buf.begin(),96}, i < 2, i%2); + auto b = g1::fromAffineBytesLE(std::span{buf.begin(),96}, { .check_valid = i<2, .to_mont = !(i%2) }); if(b) { throw invalid_argument("g1, affineLE: serialization not catching invalid input"); @@ -1138,24 +1138,24 @@ void TestG2SerializationGarbage() { array buf; buf.fill(0xff); for (int i = 0 ; i < 4; ++i ) { - auto a = g2::fromJacobianBytesBE(buf, i < 2, i%2); + auto a = g2::fromJacobianBytesBE(buf, { .check_valid = i<2, .to_mont = !(i%2) }); if(a) { throw invalid_argument("g2, jacobianBE: serialization not catching invalid input"); } - auto b = g2::fromJacobianBytesLE(buf, i < 2, i%2); + auto b = g2::fromJacobianBytesLE(buf, { .check_valid = i<2, .to_mont = !(i%2) }); if(b) { throw invalid_argument("g2, jacobianLE: serialization not catching invalid input"); } } for (int i = 0 ; i < 4; ++i ) { - auto a = g2::fromAffineBytesBE(std::span{buf.begin(),192}, i < 2, i%2); + auto a = g2::fromAffineBytesBE(std::span{buf.begin(),192}, { .check_valid = i<2, .to_mont = !(i%2) }); if(a) { throw invalid_argument("g2, affineBE: serialization not catching invalid input"); } - auto b = g2::fromAffineBytesLE(std::span{buf.begin(),192}, i < 2, i%2); + auto b = g2::fromAffineBytesLE(std::span{buf.begin(),192}, { .check_valid = i<2, .to_mont = !(i%2) }); if(b) { throw invalid_argument("g2, affineLE: serialization not catching invalid input"); @@ -2227,10 +2227,10 @@ void TestOutOfRangeInputs() { // This test is to make sure multiplication wiil not fail if the inputs is just slightly larger than p // The 4(p-1) limit may be not that strict. But we should only relax this limit if we are absolutely sure this // will not cause problems all the methods calling _ladd/_lsubstract/_ldouble. - auto p = *fp::fromBytesBE(hexToBytes<48>("1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB"), false, true); - auto pminus1 = *fp::fromBytesBE(hexToBytes<48>("1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAA"), false, true); + auto p = *fp::fromBytesBE(hexToBytes<48>("1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB"), { .check_valid = false, .to_mont = false }); + auto pminus1 = *fp::fromBytesBE(hexToBytes<48>("1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAA"), { .check_valid = false, .to_mont = false }); // 2^383, largest possible input to multiplication during the inverse(). - auto two383 = *fp::fromBytesBE(hexToBytes<48>("400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), false, true); + auto two383 = *fp::fromBytesBE(hexToBytes<48>("400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), { .check_valid = false, .to_mont = false }); // 4(p-1) * 4(p-1) will work for (int i = 0 ; i < 3; ++ i) { auto a = pminus1;