From 8a717ea964177cc05e48a3c2b372ddf71e8165c2 Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Sun, 21 Jul 2024 07:50:58 -0400 Subject: [PATCH 1/3] Add Solinas reduction for sm2p256v1 Common operations are anywhere between 20 and 40% faster --- .../pcurves_sm2p256v1/pcurves_sm2p256v1.cpp | 101 +++++++++++++++++- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/src/lib/math/pcurves/pcurves_sm2p256v1/pcurves_sm2p256v1.cpp b/src/lib/math/pcurves/pcurves_sm2p256v1/pcurves_sm2p256v1.cpp index 6bcb1c4c7b8..2be74494717 100644 --- a/src/lib/math/pcurves/pcurves_sm2p256v1/pcurves_sm2p256v1.cpp +++ b/src/lib/math/pcurves/pcurves_sm2p256v1/pcurves_sm2p256v1.cpp @@ -6,15 +6,108 @@ #include +#include #include namespace Botan::PCurve { namespace { -// clang-format off namespace sm2p256v1 { +template +class Sm2p256v1Rep final { + public: + static constexpr auto P = Params::P; + static constexpr size_t N = Params::N; + typedef typename Params::W W; + + constexpr static std::array redc(const std::array& z) { + const int64_t X00 = get_uint32(z.data(), 0); + const int64_t X01 = get_uint32(z.data(), 1); + const int64_t X02 = get_uint32(z.data(), 2); + const int64_t X03 = get_uint32(z.data(), 3); + const int64_t X04 = get_uint32(z.data(), 4); + const int64_t X05 = get_uint32(z.data(), 5); + const int64_t X06 = get_uint32(z.data(), 6); + const int64_t X07 = get_uint32(z.data(), 7); + const int64_t X08 = get_uint32(z.data(), 8); + const int64_t X09 = get_uint32(z.data(), 9); + const int64_t X10 = get_uint32(z.data(), 10); + const int64_t X11 = get_uint32(z.data(), 11); + const int64_t X12 = get_uint32(z.data(), 12); + const int64_t X13 = get_uint32(z.data(), 13); + const int64_t X14 = get_uint32(z.data(), 14); + const int64_t X15 = get_uint32(z.data(), 15); + + const int64_t S0 = X00 + X08 + X09 + X10 + X11 + X12 + 2 * (X13 + X14 + X15); + const int64_t S1 = X01 + X09 + X10 + X11 + X12 + X13 + 2 * (X14 + X15); + const int64_t S2 = X02 - (X08 + X09 + X13 + X14); + const int64_t S3 = X03 + X08 + X11 + X12 + 2 * X13 + X14 + X15; + const int64_t S4 = X04 + X09 + X12 + X13 + 2 * X14 + X15; + const int64_t S5 = X05 + X10 + X13 + X14 + 2 * X15; + const int64_t S6 = X06 + X11 + X14 + X15; + const int64_t S7 = X07 + X08 + X09 + X10 + X11 + 2 * (X12 + X13 + X14 + X15) + X15; + + std::array r = {}; + + SolinasAccum sum(r); + + sum.accum(S0); + sum.accum(S1); + sum.accum(S2); + sum.accum(S3); + sum.accum(S4); + sum.accum(S5); + sum.accum(S6); + sum.accum(S7); + const auto S = sum.final_carry(0); + + const auto correction = sm2_mul_mod_256(S); + W borrow = bigint_sub2(r.data(), N, correction.data(), N); + + bigint_cnd_add(borrow, r.data(), N, P.data(), N); + + return r; + } + + constexpr static std::array one() { return std::array{1}; } + + constexpr static std::array to_rep(const std::array& x) { return x; } + + constexpr static std::array wide_to_rep(const std::array& x) { return redc(x); } + + constexpr static std::array from_rep(const std::array& z) { return z; } + + private: + // Return (i*P) % 2**256 + // + // Assumes i is small + constexpr static std::array sm2_mul_mod_256(W i) { + static_assert(WordInfo::bits == 32 || WordInfo::bits == 64); + + // For small i, multiples of P have a simple structure so it's faster to + // compute the value directly vs a (constant time) table lookup + + auto r = P; + if constexpr(WordInfo::bits == 32) { + r[7] -= i; + r[3] -= i; + r[2] += i; + r[0] -= i; + } else { + const uint64_t i32 = static_cast(i) << 32; + r[3] -= i32; + r[1] -= i32; + r[1] += i; + r[0] -= i; + } + return r; + } +}; + +// clang-format off + class Params final : public EllipticCurveParameters< "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", @@ -24,11 +117,11 @@ class Params final : public EllipticCurveParameters< "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"> { }; -class Curve final : public EllipticCurve {}; +// clang-format on -} +class Curve final : public EllipticCurve {}; -// clang-format on +} // namespace sm2p256v1 } // namespace From d1c4204fb5fa413eba00de313acbb1a7ed39dcd9 Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Sun, 21 Jul 2024 08:52:50 -0400 Subject: [PATCH 2/3] Add addition chain for sm2p256v1 field inversion --- .../pcurves_sm2p256v1/pcurves_sm2p256v1.cpp | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/lib/math/pcurves/pcurves_sm2p256v1/pcurves_sm2p256v1.cpp b/src/lib/math/pcurves/pcurves_sm2p256v1/pcurves_sm2p256v1.cpp index 2be74494717..d277c0dc732 100644 --- a/src/lib/math/pcurves/pcurves_sm2p256v1/pcurves_sm2p256v1.cpp +++ b/src/lib/math/pcurves/pcurves_sm2p256v1/pcurves_sm2p256v1.cpp @@ -119,7 +119,45 @@ class Params final : public EllipticCurveParameters< // clang-format on -class Curve final : public EllipticCurve {}; +class Curve final : public EllipticCurve { + public: + // Return the square of the inverse of x + static FieldElement fe_invert2(const FieldElement& x) { + // Generated by https://github.com/mmcloughlin/addchain + auto z = x.square(); + auto t0 = x * z; + z = t0.square(); + z *= x; + auto t1 = z; + t1.square_n(3); + t1 *= z; + auto t2 = t1.square(); + z = t2 * x; + t2.square_n(5); + t1 *= t2; + t2 = t1; + t2.square_n(12); + t1 *= t2; + t1.square_n(7); + z *= t1; + t2 = z; + t2.square_n(2); + t1 = t2; + t1.square_n(29); + z *= t1; + t1.square_n(2); + t2 *= t1; + t0 *= t2; + t1.square_n(32); + t1 *= t0; + t1.square_n(64); + t0 *= t1; + t0.square_n(94); + z *= t0; + z.square_n(2); + return z; + } +}; } // namespace sm2p256v1 From cdcd8fbc2ce24f6d3132e7a17b7a1b7533e684d6 Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Sun, 21 Jul 2024 08:53:21 -0400 Subject: [PATCH 3/3] Add more SM2 point multiplication tests --- src/tests/data/pubkey/ecc_base_point_mul.vec | 194 +++++++++++++++++++ 1 file changed, 194 insertions(+) diff --git a/src/tests/data/pubkey/ecc_base_point_mul.vec b/src/tests/data/pubkey/ecc_base_point_mul.vec index 8d7356fa6a6..7bbe2b3462c 100644 --- a/src/tests/data/pubkey/ecc_base_point_mul.vec +++ b/src/tests/data/pubkey/ecc_base_point_mul.vec @@ -1136,3 +1136,197 @@ P = 048EB2D128495074CC7149E19DB2A5CA5A04960EC735A8A6FB77EBC74B2A6BBBD5E623CA71BF k = 770D841A416DDE3072ED0CE570BFF4065643DFF53C4ED38809100EFE479F46D1 P = 04891DC951F8F41D80A124A6675058D305BB97F70E3BB2C13BA8056EDD15323006428DF0068E6BB7DF3B03AA7765B45422995F9AEE89CA2CA1EC400B99A4C331EC + +[sm2p256v1] + +k = 0000000000000000000000000000000000000000000000000000000000000001 +P = 0432C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0 + +k = 0000000000000000000000000000000000000000000000000000000000000002 +P = 0456CEFD60D7C87C000D58EF57FA73BA4D9C0DFA08C08A7331495C2E1DA3F2BD5231B7E7E6CC8189F668535CE0F8EAF1BD6DE84C182F6C8E716F780D3A970A23C3 + +k = 0000000000000000000000000000000000000000000000000000000000000003 +P = 04A97F7CD4B3C993B4BE2DAA8CDB41E24CA13F6BD945302244E26918F1D0509EBF530B5DD88C688EF5CCC5CEC08A72150F7C400EE5CD045292AAACDD037458F6E6 + +k = 0000000000000000000000000000000000000000000000000000000000000004 +P = 04C239507105C683242A81052FF641ED69009A084AD5CC937DB21646CD34A0CED5B1BF7EC4080F3C8735F1294AC0DB19686BEE2E96AB8C71FB7A253666CB66E009 + +k = 0000000000000000000000000000000000000000000000000000000000000005 +P = 04C749061668652E26040E008FDD5EB77A344A417B7FCE19DBA575DA57CC372A9EF2DF5DB2D144E9454504C622B51CF38F5006206EB579FF7DA6976EFF5FBE6480 + +k = 0000000000000000000000000000000000000000000000000000000000000006 +P = 040927AFB57D93483BBB17C93E71F22A3105FF8856A66016892C8B1A1A3C4B0D30150C6B1AB4D1FC7EAC1C0EF6EBF2664581ADF1F0855A064DD572103000088F63 + +k = 0000000000000000000000000000000000000000000000000000000000000007 +P = 04DDF092555409C19DFDBE86A75C139906A80198337744EE78CD27E384D9FCAF15847D18FFB38E87065CD6B6E9C12D2922037937707D6A49A2223B949657E52BC1 + +k = 0000000000000000000000000000000000000000000000000000000000000008 +P = 04B9C3FAEB4B1610713DB4333D4E860E64D4EA35D60C1C29BB675D822DED0BB916C519B309ECF7269C2491D2DE9ACCF2BE0366A8A03024B3E03C286DA2CFD31A3E + +k = 0000000000000000000000000000000000000000000000000000000000000009 +P = 04A27233F3A59595080B4A2444A46A74C5FE8D59CB43619E4F173472A58CCA247E379E72F63722C924768F7689B210F45FC3A8433140D1EBCA85227940922C02E9 + +k = 000000000000000000000000000000000000000000000000000000000000000A +P = 04D3F94862519621C121666061F65C3E32B2D0D065CD219E3284A04814DB5227564B9030CF676F6A742EBD57D146DCA428F6B743F64D1482D147D46FB2BAB82A14 + +k = 000000000000000000000000000000000000000000000000000000000000000B +P = 0404B3CB10C9C6D8E27C1AAB770F67F543125DCDD589C2FF82668C74D78CE20ACE63516355287E39FE4918E5C02E2B0B930C94816E63C4BC72739A8FD805174A4B + +k = 000000000000000000000000000000000000000000000000000000000000000C +P = 04BFC2DF6BB17F971AD89058CA059BE46E5F7B516C5BDADDAD9C9F042D0279270AB145513F59636106CEF696B67939BD7B73C9FC6FD150AAAAB5FBF87B64AF3C26 + +k = 000000000000000000000000000000000000000000000000000000000000000D +P = 04952072D6FF9C65BDFA804513275F58AA7BEA65C6421E189E2B834F1D509B9CD0E6BB9804458BB70F1A473F8D9748F23858D1434AE934BA7503891E105E009B00 + +k = 000000000000000000000000000000000000000000000000000000000000000E +P = 0483B4A4DE96A4D70F4AAF81826982D748EF22EA28BE9D44DE0A44248A36BB0A07E481C0D9EE8A98D4EEB6D6C6D7E74F8E3E707C8A438529492E663CD4373A2F24 + +k = 000000000000000000000000000000000000000000000000000000000000000F +P = 04F73B839F13912C1A3291676C38D393243B424F35F0ECCE4C461B1BBCB80F829C32EC7722695DC7CF5EE9FAB985C12455DC2E788FB170AA144C3533771DB0955E + +k = 0000000000000000000000000000000000000000000000000000000000000010 +P = 0435648233F554AE51BBCE44EF5DB3E419EA133CD248A93E2555645BBC8704FB6804D7AC60F6D975EF6117BCA9CE885DD6154B1870A6A651664411A9A30ECA2046 + +k = 0000000000000000000000000000000000000000000000000000000000000011 +P = 04DD18AA4AEC26EAC41C993F01115C57F7BF5113AB85B5ED4436969F8B77125E6A161E5851969DA8223361493F76FAC50F6CCE6001D7C0B853E0180D54D4AE2221 + +k = 0000000000000000000000000000000000000000000000000000000000000012 +P = 0469FDF8A436FD8E5D221EA8657781CE71A3448557A24554DB427E33AE8ED9C317BAA856D1CAD68AF36B0A9658B33B347BEB7B1AD657C155F571E35709341FDCAB + +k = 0000000000000000000000000000000000000000000000000000000000000013 +P = 04A68B2EC49D1921D0E2E0586BB5DC9419F7C96C55940A47261323F252E493952A96F361A23B3DEB99933EF442FCA7A734B95F2DE69200269EFD4520A63F5CC585 + +k = 0000000000000000000000000000000000000000000000000000000000000014 +P = 0408314765E44847EB7575E3CB2FA9092DABBB1EA1417F958D0588FDD88ABDEE94DF922344FA592A986B443AB4360953787DE3A53937E8A75F5EEB0E99C2EB61E9 + +k = 0000000000000000000000000000000000000000000000000000000000000015 +P = 046407BE639BC5B738137CBF4E8AA505355B551C86A8976933E1DE5F100950C8AB141CAEE612E7AB0712A9423FD80DEA5460FCFD988FFF6DECF945321148E90344 + +k = 0000000000000000000000000000000000000000000000000000000000000016 +P = 04E61120569974C0BC1835A4D0F3E5E2993E7307F46FA550D10755A352DAFA1E1DCFE30AA2C3877E52D08FC10E5056E4BC02855E18D12379B43B86CC142850B0F3 + +k = 0000000000000000000000000000000000000000000000000000000000000017 +P = 04AC8DF677299E828815C07A8C04226FE3BB570A9F430EA7F64DBB2FCD069D45DBAEF82CF361DB1C7130C43BE69B23CC140E9B9643D766DA337BD8B7C847718CE5 + +k = 0000000000000000000000000000000000000000000000000000000000000018 +P = 04DF8A74F904D1715E314FA6C814C7BDA8EC268911CCB79283D7240A35D1F4FFED0FED448A3F2639187A7606EF148AA5FBE1C80E7752BD6499BCB60A9E82017C30 + +k = 0000000000000000000000000000000000000000000000000000000000000019 +P = 04178D1F6BD584AFCCCE1564C3DF7D67EA7E8581FBBCF5DE010263B20D539E4139F575F34E5F6C63C653DA45CEC1CAADA17021AAFC29AC8E869B499A7DA7820BF9 + +k = 000000000000000000000000000000000000000000000000000000000000001A +P = 04A0A1A4FBEB476576BCF26FE238A102C273783EF304251E748E6A9E4FDF8952908DFDD7CD150D25640D09C3F281D4C41CEC73068587361B34E54F7F3A4896D9D3 + +k = 000000000000000000000000000000000000000000000000000000000000001B +P = 04EC6F34CEACAA73A0D7A1F169475B4DDF02A85A7410754529CE37E84FC9541B4B3C85CF62A744817E6F251C63FBBD2927E607F33BE20135EA73306A0FF0485872 + +k = 000000000000000000000000000000000000000000000000000000000000001C +P = 0491CB72DC55F8434694ED53ED581D191D36F0DFE49113C16E6CB2F058C747D33F1957AD4CFFFD491EF7EFB07682931F88F4C600E8B5DFE8113EA6AACE93921F31 + +k = 000000000000000000000000000000000000000000000000000000000000001D +P = 0428221C36398C4C3A625773CAE69BBE05C9816BE068BE66DB9DD4EF421635B9DC3B4D172D6963510BAB2012C41627CD8164C77A81858D4CA12995225E66B162BA + +k = 000000000000000000000000000000000000000000000000000000000000001E +P = 0417A5F74D533AE724C315796922BF13438B1AC02E98D543CEFD23EA021DA51C9D498470EC6752B2ECB9038823D9AD0D5F7BEFA4DB8C8D3EFF57D2E81DBB945DFE + +k = 000000000000000000000000000000000000000000000000000000000000001F +P = 0408DAAE840B2A43EBD6B48259B69E853027D053C0F150FE10AC995C5066BDAAA580CC0A980495AF87C1B8E58150DA662DF7DC310560BBE83A2458B9E3C73BF657 + +k = 0000000000000000000000000000000000000000000000000000000000000020 +P = 0425D3DEBD0950D180A6D5C2B5817F2329791734CD03E5565CA32641E56024666C92D99A70679D61EFB938C406DD5CB0E10458895120E208B4D39E100303FA10A2 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54122 +P = 0432C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C743C8C95C0B098863A642311C9496DEAC2F56788239D5B8C0FD20CD1ADEC60F5F + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54121 +P = 0456CEFD60D7C87C000D58EF57FA73BA4D9C0DFA08C08A7331495C2E1DA3F2BD52CE481818337E760997ACA31F07150E429217B3E6D093718F9087F2C568F5DC3C + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54120 +P = 04A97F7CD4B3C993B4BE2DAA8CDB41E24CA13F6BD945302244E26918F1D0509EBFACF4A2267397710A333A313F758DEAF083BFF11932FBAD6E555322FC8BA70919 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5411F +P = 04C239507105C683242A81052FF641ED69009A084AD5CC937DB21646CD34A0CED54E40813AF7F0C378CA0ED6B53F24E6979411D16854738E0585DAC99934991FF6 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5411E +P = 04C749061668652E26040E008FDD5EB77A344A417B7FCE19DBA575DA57CC372A9E0D20A24C2EBB16BABAFB39DD4AE30C70AFF9DF904A86008359689100A0419B7F + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5411D +P = 040927AFB57D93483BBB17C93E71F22A3105FF8856A66016892C8B1A1A3C4B0D30EAF394E44B2E038153E3F109140D99BA7E520E0E7AA5F9B32A8DEFCFFFF7709C + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5411C +P = 04DDF092555409C19DFDBE86A75C139906A80198337744EE78CD27E384D9FCAF157B82E6FF4C7178F9A32949163ED2D6DDFC86C88E8295B65EDDC46B69A81AD43E + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5411B +P = 04B9C3FAEB4B1610713DB4333D4E860E64D4EA35D60C1C29BB675D822DED0BB9163AE64CF51308D963DB6E2D2165330D41FC99575ECFDB4C20C3D7925D302CE5C1 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5411A +P = 04A27233F3A59595080B4A2444A46A74C5FE8D59CB43619E4F173472A58CCA247EC8618D08C8DD36DB897089764DEF0BA03C57BCCDBF2E14367ADD86BF6DD3FD16 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54119 +P = 04D3F94862519621C121666061F65C3E32B2D0D065CD219E3284A04814DB522756B46FCF2F9890958BD142A82EB9235BD70948BC08B2EB7D2FB82B904D4547D5EB + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54118 +P = 0404B3CB10C9C6D8E27C1AAB770F67F543125DCDD589C2FF82668C74D78CE20ACE9CAE9CA9D781C601B6E71A3FD1D4F46CF36B7E909C3B438E8C657027FAE8B5B4 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54117 +P = 04BFC2DF6BB17F971AD89058CA059BE46E5F7B516C5BDADDAD9C9F042D0279270A4EBAAEBFA69C9EF93109694986C642848C36038F2EAF55564A0407849B50C3D9 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54116 +P = 04952072D6FF9C65BDFA804513275F58AA7BEA65C6421E189E2B834F1D509B9CD0194467FABA7448F0E5B8C07268B70DC7A72EBCB416CB458BFC76E1EFA1FF64FF + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54115 +P = 0483B4A4DE96A4D70F4AAF81826982D748EF22EA28BE9D44DE0A44248A36BB0A071B7E3F251175672B114929392818B071C18F8374BC7AD6B7D199C32BC8C5D0DB + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54114 +P = 04F73B839F13912C1A3291676C38D393243B424F35F0ECCE4C461B1BBCB80F829CCD1388DC96A23830A11605467A3EDBAA23D1876F4E8F55ECB3CACC88E24F6AA1 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54113 +P = 0435648233F554AE51BBCE44EF5DB3E419EA133CD248A93E2555645BBC8704FB68FB28539E09268A109EE843563177A229EAB4E78E5959AE9ABBEE565CF135DFB9 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54112 +P = 04DD18AA4AEC26EAC41C993F01115C57F7BF5113AB85B5ED4436969F8B77125E6AE9E1A7AD696257DDCC9EB6C089053AF093319FFD283F47AD1FE7F2AB2B51DDDE + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54111 +P = 0469FDF8A436FD8E5D221EA8657781CE71A3448557A24554DB427E33AE8ED9C3174557A92D3529750C94F569A74CC4CB841484E528A83EAA0B8E1CA8F6CBE02354 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54110 +P = 04A68B2EC49D1921D0E2E0586BB5DC9419F7C96C55940A47261323F252E493952A690C9E5CC4C214666CC10BBD035858CB46A0D2186DFFD96202BADF59C0A33A7A + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5410F +P = 0408314765E44847EB7575E3CB2FA9092DABBB1EA1417F958D0588FDD88ABDEE94206DDCBA05A6D56794BBC54BC9F6AC87821C5AC5C81758A1A114F1663D149E16 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5410E +P = 046407BE639BC5B738137CBF4E8AA505355B551C86A8976933E1DE5F100950C8ABEBE35118ED1854F8ED56BDC027F215AB9F0302667000921406BACDEEB716FCBB + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5410D +P = 04E61120569974C0BC1835A4D0F3E5E2993E7307F46FA550D10755A352DAFA1E1D301CF55C3C7881AD2F703EF1AFA91B43FD7AA1E62EDC864CC47933EBD7AF4F0C + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5410C +P = 04AC8DF677299E828815C07A8C04226FE3BB570A9F430EA7F64DBB2FCD069D45DB5107D30B9E24E38ECF3BC41964DC33EBF16469BB289925CD84274837B88E731A + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5410B +P = 04DF8A74F904D1715E314FA6C814C7BDA8EC268911CCB79283D7240A35D1F4FFEDF012BB74C0D9C6E78589F910EB755A041E37F187AD429B674349F5617DFE83CF + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D5410A +P = 04178D1F6BD584AFCCCE1564C3DF7D67EA7E8581FBBCF5DE010263B20D539E41390A8A0CB0A0939C39AC25BA313E35525E8FDE5502D653717A64B66582587DF406 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54109 +P = 04A0A1A4FBEB476576BCF26FE238A102C273783EF304251E748E6A9E4FDF89529072022831EAF2DA9BF2F63C0D7E2B3BE3138CF97978C9E4CC1AB080C5B769262C + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54108 +P = 04EC6F34CEACAA73A0D7A1F169475B4DDF02A85A7410754529CE37E84FC9541B4BC37A309C58BB7E8190DAE39C0442D6D819F80CC31DFECA168CCF95F00FB7A78D + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54107 +P = 0491CB72DC55F8434694ED53ED581D191D36F0DFE49113C16E6CB2F058C747D33FE6A852B20002B6E108104F897D6CE0770B39FF164A2017EFC15955316C6DE0CE + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54106 +P = 0428221C36398C4C3A625773CAE69BBE05C9816BE068BE66DB9DD4EF421635B9DCC4B2E8D1969CAEF454DFED3BE9D8327E9B38857D7A72B35FD66ADDA1994E9D45 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54105 +P = 0417A5F74D533AE724C315796922BF13438B1AC02E98D543CEFD23EA021DA51C9DB67B8F1298AD4D1346FC77DC2652F2A084105B237372C101A82D17E2446BA201 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54104 +P = 0408DAAE840B2A43EBD6B48259B69E853027D053C0F150FE10AC995C5066BDAAA57F33F566FB6A50783E471A7EAF2599D20823CEF99F4417C6DBA7461C38C409A8 + +k = FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54103 +P = 0425D3DEBD0950D180A6D5C2B5817F2329791734CD03E5565CA32641E56024666C6D26658E98629E1046C73BF922A34F1EFBA776ADDF1DF74C2C61EFFCFC05EF5D