Added Montgomery support
This check-in enables support for elliptic curves over prime fields using the Montgomery equation. Support for Edwards curves will follow as soon as all bugs are eliminated.pull/114/head
parent
76b2f9387d
commit
c8aaa5aae3
70
eccrypto.cpp
70
eccrypto.cpp
|
|
@ -122,6 +122,24 @@ template<> struct EcRecommendedParameters<ECP>
|
||||||
unsigned int h;
|
unsigned int h;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<> struct EcRecommendedParameters<ECPM>
|
||||||
|
{
|
||||||
|
EcRecommendedParameters(const OID &oid, const char *p, const char *A, const char *B, const char *g, const char *n, unsigned int h)
|
||||||
|
: oid(oid), p(p), A(A), B(B), g(g), n(n), h(h) {}
|
||||||
|
ECPM *NewEC() const
|
||||||
|
{
|
||||||
|
StringSource ssP(p, true, new HexDecoder);
|
||||||
|
StringSource ssA(A, true, new HexDecoder);
|
||||||
|
StringSource ssB(B, true, new HexDecoder);
|
||||||
|
return new ECPM(Integer(ssP, (size_t)ssP.MaxRetrievable()), ECPM::FieldElement(ssA, (size_t)ssA.MaxRetrievable()), ECPM::FieldElement(ssB, (size_t)ssB.MaxRetrievable()));
|
||||||
|
};
|
||||||
|
|
||||||
|
OID oid;
|
||||||
|
const char *p;
|
||||||
|
const char *A, *B, *g, *n;
|
||||||
|
unsigned int h;
|
||||||
|
};
|
||||||
|
|
||||||
struct OIDLessThan
|
struct OIDLessThan
|
||||||
{
|
{
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
@ -430,6 +448,58 @@ static void GetRecommendedParameters(const EcRecommendedParameters<ECP> *&begin,
|
||||||
end = rec + sizeof(rec)/sizeof(rec[0]);
|
end = rec + sizeof(rec)/sizeof(rec[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void GetRecommendedParameters(const EcRecommendedParameters<ECPM> *&begin, const EcRecommendedParameters<ECPM> *&end)
|
||||||
|
{
|
||||||
|
// this array must be sorted by OID
|
||||||
|
static const EcRecommendedParameters<ECPM> rec[] =
|
||||||
|
{
|
||||||
|
EcRecommendedParameters<ECPM>(ASN1::cryptoppM221(),
|
||||||
|
"1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD",
|
||||||
|
"0000000000000000000000000000000000000000000000000001C93A",
|
||||||
|
"00000000000000000000000000000000000000000000000000000001",
|
||||||
|
"04000000000000000000000000000000000000000000000000000000040F7ACDD2A4939571D1CEF14ECA37C228E61DBFF10707DC6C08C5056D",
|
||||||
|
"040000000000000000000000000015A08ED730E8A2F77F005042605B",
|
||||||
|
8),
|
||||||
|
EcRecommendedParameters<ECPM>(ASN1::cryptoppM383(),
|
||||||
|
"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45",
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001F82FE",
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C1EC7ED04AAF834AF310E304B2DA0F328E7C165F0E8988ABD3992861290F617AA1F1B2E7D0B6E332E969991B62555E77E",
|
||||||
|
"10000000000000000000000000000000000000000000000006C79673AC36BA6E7A32576F7B1B249E46BBC225BE9071D7",
|
||||||
|
8),
|
||||||
|
EcRecommendedParameters<ECPM>(ASN1::cryptoppM511(),
|
||||||
|
"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45",
|
||||||
|
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081806",
|
||||||
|
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052fbdc0ad8530803d28fdbad354bb488d32399ac1cf8f6e01ee3f96389b90c809422b9429e8a43dbf49308ac4455940abe9f1dbca542093a895e30a64af056fa5",
|
||||||
|
"100000000000000000000000000000000000000000000000000000000000000017B5FEFF30C7F5677AB2AEEBD13779A2AC125042A6AA10BFA54C15BAB76BAF1B",
|
||||||
|
8),
|
||||||
|
EcRecommendedParameters<ECPM>(ASN1::cryptoppCurve383187(),
|
||||||
|
"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45",
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038251",
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051EEBE07DC1871896732B12D5504A32370471965C7A11F2C89865F855AB3CBD7C224E3620C31AF3370788457DD5CE46DF",
|
||||||
|
"1000000000000000000000000000000000000000000000000e85a85287a1488acd41ae84b2b7030446f72088b00a0e21",
|
||||||
|
8),
|
||||||
|
EcRecommendedParameters<ECPM>(ASN1::ietfCurve25519(),
|
||||||
|
"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000076D06",
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"04000000000000000000000000000000000000000000000000000000000000000920AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9",
|
||||||
|
"1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed",
|
||||||
|
8),
|
||||||
|
EcRecommendedParameters<ECPM>(ASN1::ietfCurve448(),
|
||||||
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||||
|
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000262A6",
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057D235D1295F5B1F66C98AB6E58326FCECBAE5D34F55545D060F75DC28DF3F6EDB8027E2346430D211312C4B150677AF76FD7223D457B5B1A",
|
||||||
|
"3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3",
|
||||||
|
4),
|
||||||
|
};
|
||||||
|
begin = rec;
|
||||||
|
end = rec + sizeof(rec) / sizeof(rec[0]);
|
||||||
|
}
|
||||||
|
|
||||||
template <class EC> OID DL_GroupParameters_EC<EC>::GetNextRecommendedParametersOID(const OID &oid)
|
template <class EC> OID DL_GroupParameters_EC<EC>::GetNextRecommendedParametersOID(const OID &oid)
|
||||||
{
|
{
|
||||||
const EcRecommendedParameters<EllipticCurve> *begin, *end;
|
const EcRecommendedParameters<EllipticCurve> *begin, *end;
|
||||||
|
|
|
||||||
|
|
@ -319,18 +319,24 @@ NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC<ECP>;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC<ECP>;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC<EC2N>;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC<EC2N>;
|
||||||
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC<ECPM>
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl<DL_GroupParameters_EC<ECP> >;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl<DL_GroupParameters_EC<ECP> >;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl<DL_GroupParameters_EC<EC2N> >;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl<DL_GroupParameters_EC<EC2N> >;
|
||||||
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl<DL_GroupParameters_EC<ECPM> >;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC<ECP>;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC<ECP>;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC<EC2N>;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC<EC2N>;
|
||||||
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC<ECPM>;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl<DL_GroupParameters_EC<ECP> >;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl<DL_GroupParameters_EC<ECP> >;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl<DL_GroupParameters_EC<EC2N> >;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl<DL_GroupParameters_EC<EC2N> >;
|
||||||
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl<DL_GroupParameters_EC<ECPM> >;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<ECP>;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<ECP>;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<EC2N>;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<EC2N>;
|
||||||
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<ECPM>;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<ECP::Point>;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<ECP::Point>;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<EC2N::Point>;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<EC2N::Point>;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<ECP>, ECDSA<ECP, SHA256> >;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<ECP>, ECDSA<ECP, SHA256> >;
|
||||||
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<EC2N>, ECDSA<EC2N, SHA256> >;
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<EC2N>, ECDSA<EC2N, SHA256> >;
|
||||||
|
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<ECPM>, ECDSA<ECPM, SHA256> >;
|
||||||
|
|
||||||
NAMESPACE_END
|
NAMESPACE_END
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,396 @@
|
||||||
|
// ecpm.cpp - written and placed in public domain by Jean-Pierre Muench. Copyright assigned to the Crypto++ project.
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#ifndef CRYPTOPP_IMPORTS
|
||||||
|
|
||||||
|
#include "ecp.h"
|
||||||
|
#include "ecpm.h"
|
||||||
|
#include "asn.h"
|
||||||
|
#include "integer.h"
|
||||||
|
#include "nbtheory.h"
|
||||||
|
#include "modarith.h"
|
||||||
|
#include "filters.h"
|
||||||
|
#include "algebra.cpp"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
|
ANONYMOUS_NAMESPACE_BEGIN
|
||||||
|
static inline ECP::Point ToMontgomery(const ModularArithmetic &mr, const ECP::Point &P) // straight from ecp.cpp
|
||||||
|
{
|
||||||
|
return P.identity ? P : ECP::Point(mr.ConvertIn(P.x), mr.ConvertIn(P.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ECP::Point FromMontgomery(const ModularArithmetic &mr, const ECP::Point &P) // straight from ecp.cpp
|
||||||
|
{
|
||||||
|
return P.identity ? P : ECP::Point(mr.ConvertOut(P.x), mr.ConvertOut(P.y));
|
||||||
|
}
|
||||||
|
static inline ECP* GenerateWeierstrassCurve(const ECPM& MontgomeryCurve)
|
||||||
|
{
|
||||||
|
const Integer& A = MontgomeryCurve.GetA();
|
||||||
|
const Integer& B = MontgomeryCurve.GetB();
|
||||||
|
const ModularArithmetic& Field = MontgomeryCurve.GetField();
|
||||||
|
|
||||||
|
// now construct the equivalent Weierstrass curve
|
||||||
|
// refer to https://crypto.stackexchange.com/q/27842 for the details
|
||||||
|
// use m_FieldPtr to ensure encoding (eventual Montgomery Representation) is handled correctly
|
||||||
|
//the transformations also appear independently on http ://safecurves.cr.yp.to/equation.html
|
||||||
|
|
||||||
|
// a = (3-A)/(3B^2)
|
||||||
|
Integer aWeierstrass = Field.Subtract(3, Field.Square(A)); // a = 3 - A
|
||||||
|
aWeierstrass = Field.Divide(aWeierstrass, Field.Multiply(3, Field.Square(B))); // a = a / (3B^2)
|
||||||
|
// b = (2A^3-9A) / (27 B^3)
|
||||||
|
Integer bWeierstrass = Field.Multiply(A, Field.Subtract(Field.Multiply(2, Field.Square(A)), 9)); // b = A(2A^2-9)
|
||||||
|
bWeierstrass = Field.Divide(bWeierstrass, Field.Multiply(27, Field.Exponentiate(B, 3))); // b = b / (27 B^3)
|
||||||
|
|
||||||
|
return new ECP(MontgomeryCurve.GetField().GetModulus(), aWeierstrass, bWeierstrass);
|
||||||
|
}
|
||||||
|
NAMESPACE_END
|
||||||
|
|
||||||
|
ECPM::ECPM(const Integer &modulus, const FieldElement &A, const FieldElement &B):
|
||||||
|
m_fieldPtr(new Field(modulus))
|
||||||
|
{
|
||||||
|
// store A and B for later use
|
||||||
|
m_A = A.IsNegative() ? (A + modulus) : A;// straight from ecp.cpp
|
||||||
|
m_B = B.IsNegative() ? (B + modulus) : B;// straight from ecp.cpp
|
||||||
|
|
||||||
|
m_ComputeEngine.reset(GenerateWeierstrassCurve(*this));
|
||||||
|
|
||||||
|
// to speed up the conversions
|
||||||
|
m_AThirds = m_fieldPtr->Divide(m_A, 3);
|
||||||
|
m_BInv = m_fieldPtr->MultiplicativeInverse(m_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
ECPM::ECPM(const ECPM &ecpm, bool convertToMontgomeryRepresentation)
|
||||||
|
{
|
||||||
|
if (convertToMontgomeryRepresentation && !ecpm.GetField().IsMontgomeryRepresentation())
|
||||||
|
{
|
||||||
|
m_fieldPtr.reset(new MontgomeryRepresentation(ecpm.GetField().GetModulus()));
|
||||||
|
m_ComputeEngine.reset(new ECP(*ecpm.m_ComputeEngine.get(),convertToMontgomeryRepresentation));
|
||||||
|
m_A = GetField().ConvertIn(ecpm.m_A);
|
||||||
|
m_B = GetField().ConvertIn(ecpm.m_B);
|
||||||
|
m_AThirds = GetField().ConvertIn(ecpm.m_AThirds);
|
||||||
|
m_BInv = GetField().ConvertIn(ecpm.m_BInv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
operator=(ecpm);
|
||||||
|
}
|
||||||
|
|
||||||
|
ECPM::ECPM(BufferedTransformation &bt)
|
||||||
|
: m_fieldPtr(new Field(bt))
|
||||||
|
{
|
||||||
|
BERSequenceDecoder seq(bt);
|
||||||
|
GetField().BERDecodeElement(seq, m_A);
|
||||||
|
GetField().BERDecodeElement(seq, m_B);
|
||||||
|
// skip optional seed
|
||||||
|
if (!seq.EndReached())
|
||||||
|
{
|
||||||
|
SecByteBlock seed;
|
||||||
|
unsigned int unused;
|
||||||
|
BERDecodeBitString(seq, seed, unused);
|
||||||
|
}
|
||||||
|
seq.MessageEnd();
|
||||||
|
|
||||||
|
m_ComputeEngine.reset(GenerateWeierstrassCurve(*this));
|
||||||
|
|
||||||
|
m_AThirds = m_fieldPtr->Divide(m_A, 3);
|
||||||
|
m_BInv = m_fieldPtr->MultiplicativeInverse(m_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
void ECPM::DEREncode(BufferedTransformation &bt) const
|
||||||
|
{
|
||||||
|
GetField().DEREncode(bt);
|
||||||
|
DERSequenceEncoder seq(bt);
|
||||||
|
GetField().DEREncodeElement(seq, m_A);
|
||||||
|
GetField().DEREncodeElement(seq, m_B);
|
||||||
|
seq.MessageEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
bool ECPM::DecodePoint(ECPM::Point &P, const byte *encodedPoint, size_t encodedPointLen) const
|
||||||
|
{
|
||||||
|
StringStore store(encodedPoint, encodedPointLen);
|
||||||
|
return DecodePoint(P, store, encodedPointLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
bool ECPM::DecodePoint(ECPM::Point &P, BufferedTransformation &bt, size_t encodedPointLen) const
|
||||||
|
{
|
||||||
|
byte type;
|
||||||
|
if (encodedPointLen < 1 || !bt.Get(type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
P.identity = true;
|
||||||
|
return true;
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
if (encodedPointLen != EncodedPointSize(true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Integer p = FieldSize();
|
||||||
|
|
||||||
|
P.identity = false;
|
||||||
|
P.x.Decode(bt, GetField().MaxElementByteLength());
|
||||||
|
// curve is: By^2=x^3+Ax^2+x <=> y=sqrt(x/B(x(A+x)+1)
|
||||||
|
P.y = (m_BInv * P.x *(P.x * (P.x + m_A) + Integer::One()))%p;
|
||||||
|
|
||||||
|
if (Jacobi(P.y, p) != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
P.y = ModularSquareRoot(P.y, p);
|
||||||
|
|
||||||
|
if ((type & 1) != P.y.GetBit(0))
|
||||||
|
P.y = p - P.y;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
if (encodedPointLen != EncodedPointSize(false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned int len = GetField().MaxElementByteLength();
|
||||||
|
P.identity = false;
|
||||||
|
P.x.Decode(bt, len);
|
||||||
|
P.y.Decode(bt, len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
void ECPM::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const
|
||||||
|
{
|
||||||
|
if (P.identity)
|
||||||
|
NullStore().TransferTo(bt, EncodedPointSize(compressed));
|
||||||
|
else if (compressed)
|
||||||
|
{
|
||||||
|
bt.Put(2 + P.y.GetBit(0));
|
||||||
|
P.x.Encode(bt, GetField().MaxElementByteLength());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int len = GetField().MaxElementByteLength();
|
||||||
|
bt.Put(4); // uncompressed
|
||||||
|
P.x.Encode(bt, len);
|
||||||
|
P.y.Encode(bt, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
void ECPM::EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const
|
||||||
|
{
|
||||||
|
ArraySink sink(encodedPoint, EncodedPointSize(compressed));
|
||||||
|
EncodePoint(sink, P, compressed);
|
||||||
|
assert(sink.TotalPutLength() == EncodedPointSize(compressed));
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
ECPM::Point ECPM::BERDecodePoint(BufferedTransformation &bt) const
|
||||||
|
{
|
||||||
|
SecByteBlock str;
|
||||||
|
BERDecodeOctetString(bt, str);
|
||||||
|
Point P;
|
||||||
|
if (!DecodePoint(P, str, str.size()))
|
||||||
|
BERDecodeError();
|
||||||
|
return P;
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
void ECPM::DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const
|
||||||
|
{
|
||||||
|
SecByteBlock str(EncodedPointSize(compressed));
|
||||||
|
EncodePoint(str, P, compressed);
|
||||||
|
DEREncodeOctetString(bt, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
bool ECPM::ValidateParameters(RandomNumberGenerator &rng, unsigned int level) const
|
||||||
|
{
|
||||||
|
Integer p = FieldSize();
|
||||||
|
|
||||||
|
bool pass = p.IsOdd();
|
||||||
|
pass = pass && !m_A.IsNegative() && m_A<p && !m_B.IsNegative() && m_B<p;
|
||||||
|
|
||||||
|
if (level >= 1)
|
||||||
|
pass = pass && ((m_B * (m_A * m_A - 4)) % p).IsPositive();
|
||||||
|
|
||||||
|
if (level >= 2)
|
||||||
|
pass = pass && VerifyPrime(rng, p);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
bool ECPM::VerifyPoint(const Point &P) const
|
||||||
|
{
|
||||||
|
const FieldElement &x = P.x, &y = P.y;
|
||||||
|
Integer p = FieldSize();
|
||||||
|
|
||||||
|
// use the field arithmetic here, in case our data is in Montgomery form
|
||||||
|
// ecp.cpp does this with plain integer arithmetic -> will fail if montgomery representation is on, but was never called when montgomery representation was on
|
||||||
|
const FieldElement IsOnCurve = m_fieldPtr->Subtract(m_fieldPtr->Multiply(x,(m_fieldPtr->Add(1,m_fieldPtr->Multiply(x,(m_fieldPtr->Add(m_A,x)))))),m_fieldPtr->Multiply(m_B,m_fieldPtr->Square(y)));
|
||||||
|
|
||||||
|
return P.identity ||
|
||||||
|
(!x.IsNegative() && x<p && !y.IsNegative() && y<p
|
||||||
|
&& !(IsOnCurve));
|
||||||
|
// By^2=x^3+Ax^2+x <=> 0 == x(1+x(A+x))-By^2
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
bool ECPM::Equal(const Point &P, const Point &Q) const
|
||||||
|
{
|
||||||
|
if (P.identity && Q.identity)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (P.identity && !Q.identity)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!P.identity && Q.identity)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (GetField().Equal(P.x, Q.x) && GetField().Equal(P.y, Q.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
const ECPM::Point& ECPM::Identity() const
|
||||||
|
{
|
||||||
|
return Singleton<Point>().Ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
const ECPM::Point& ECPM::Inverse(const Point &P) const
|
||||||
|
{
|
||||||
|
if (P.identity)
|
||||||
|
return P;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_R.identity = false;
|
||||||
|
m_R.x = P.x;
|
||||||
|
m_R.y = GetField().Inverse(P.y);
|
||||||
|
return m_R;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
const ECPM::Point& ECPM::Add(const Point &P, const Point &Q) const
|
||||||
|
{
|
||||||
|
if (P.identity) return Q;
|
||||||
|
if (Q.identity) return P;
|
||||||
|
if (GetField().Equal(P.x, Q.x))
|
||||||
|
return GetField().Equal(P.y, Q.y) ? Double(P) : Identity();
|
||||||
|
|
||||||
|
FieldElement t = GetField().Subtract(Q.y, P.y); // t = y_Q - y_P
|
||||||
|
t = GetField().Divide(t, GetField().Subtract(Q.x, P.x)); // t = (y_Q - y_P) / (x_Q - x_P)
|
||||||
|
FieldElement x = GetField().Subtract(GetField().Subtract(GetField().Subtract(GetField().Multiply(m_B,GetField().Square(t)), P.x), Q.x),m_A); // x = B*t^2-x_P-x_Q-A
|
||||||
|
m_R.y = GetField().Subtract(GetField().Multiply(t, GetField().Subtract(P.x, x)), P.y); // y = t * (x_P - x) - y_P
|
||||||
|
|
||||||
|
m_R.x.swap(x);
|
||||||
|
m_R.identity = false;
|
||||||
|
return m_R;
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
const ECPM::Point& ECPM::Double(const Point &P) const
|
||||||
|
{
|
||||||
|
if (P.identity || P.y == GetField().Identity()) return Identity();
|
||||||
|
|
||||||
|
FieldElement t = GetField().Add(GetField().Double(P.x), P.x);// t = 2x_P + x_P = 3x_P
|
||||||
|
t = GetField().Add(GetField().Multiply(P.x,GetField().Add(t,GetField().Double(m_A))), GetField().ConvertIn(1)); // x_P * ( t + 2 * A)+1
|
||||||
|
FieldElement h1= GetField().Multiply(t, m_BInv), h2= GetField().Double(P.y); // put this in two steps or it fails somehow otherwise
|
||||||
|
t = GetField().Divide(h1, h2); // t = (x_P(3x_P + 2A)+1)/(2B*y_P)
|
||||||
|
FieldElement& x = m_R.x;
|
||||||
|
x = GetField().Multiply(m_B, GetField().Square(t)); // put this in two steps or it fails somehow otherwise
|
||||||
|
x = GetField().Subtract(GetField().Subtract(x, GetField().Double(P.x)), m_A); // x = B * t^2 - A - x_1 - x_2
|
||||||
|
m_R.y = GetField().Subtract(GetField().Multiply(t, GetField().Subtract(P.x, x)), P.y); // t (x_P - x) -y_P
|
||||||
|
|
||||||
|
m_R.identity = false;
|
||||||
|
return m_R;
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
ECPM::Point ECPM::ScalarMultiply(const Point &P, const Integer &k) const
|
||||||
|
{
|
||||||
|
Element result;
|
||||||
|
if (k.BitCount() <= 5)
|
||||||
|
AbstractGroup<ECPPoint>::SimultaneousMultiply(&result, P, &k, 1);
|
||||||
|
else
|
||||||
|
ECPM::SimultaneousMultiply(&result, P, &k, 1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is probably the cause of the issue
|
||||||
|
void ECPM::SimultaneousMultiply(ECPM::Point *results, const ECPM::Point &P, const Integer *expBegin, unsigned int expCount) const
|
||||||
|
{
|
||||||
|
Point ConvertedBase = MontgomeryToWeierstrass(P);
|
||||||
|
// let the compute engine do its optimized work
|
||||||
|
m_ComputeEngine->SimultaneousMultiply(results, ConvertedBase, expBegin, expCount);
|
||||||
|
|
||||||
|
// fetch the results and convert them back to our preferred form
|
||||||
|
for (unsigned int i = 0; i < expCount; ++i)
|
||||||
|
results[i] = WeierstrassToMontgomery(results[i]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
// implement Montgomery ladder below
|
||||||
|
}
|
||||||
|
|
||||||
|
// straight adaption from ecp.cpp
|
||||||
|
ECPM::Point ECPM::CascadeScalarMultiply(const Point &P, const Integer &k1, const Point &Q, const Integer &k2) const
|
||||||
|
{
|
||||||
|
if (!GetField().IsMontgomeryRepresentation())
|
||||||
|
{
|
||||||
|
ECPM ecpmr(*this, true);
|
||||||
|
const ModularArithmetic &mr = ecpmr.GetField();
|
||||||
|
return FromMontgomery(mr, ecpmr.CascadeScalarMultiply(ToMontgomery(mr, P), k1, ToMontgomery(mr, Q), k2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return AbstractGroup<Point>::CascadeScalarMultiply(P, k1, Q, k2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// added as ECP doesn't offer a Clone() function which is required for assignment
|
||||||
|
void ECPM::operator=(const ECPM& rhs)
|
||||||
|
{
|
||||||
|
m_A = rhs.m_A;
|
||||||
|
m_AThirds = rhs.m_AThirds;
|
||||||
|
m_B = rhs.m_B;
|
||||||
|
m_BInv = rhs.m_BInv;
|
||||||
|
m_fieldPtr = rhs.m_fieldPtr->Clone();
|
||||||
|
m_ComputeEngine.reset(new ECP(*rhs.m_ComputeEngine,rhs.m_ComputeEngine->GetField().IsMontgomeryRepresentation()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// converts weierstrass points to montgomery points
|
||||||
|
// it can be checked at https://crypto.stackexchange.com/q/27842 and http://safecurves.cr.yp.to/equation.html
|
||||||
|
inline ECPM::Point ECPM::WeierstrassToMontgomery(const Point& In) const
|
||||||
|
{
|
||||||
|
// (x,y) -> (Bx-A/3,By)
|
||||||
|
ECPPoint Out;
|
||||||
|
Out.identity = In.identity;
|
||||||
|
Out.x = GetField().Subtract(m_fieldPtr->Multiply(m_B,In.x),m_AThirds);
|
||||||
|
Out.y = GetField().Multiply(In.y,m_B);
|
||||||
|
return Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// converts weierstrass points to montgomery points, the math *should* be right
|
||||||
|
inline ECPM::Point ECPM::MontgomeryToWeierstrass(const Point& In) const
|
||||||
|
{
|
||||||
|
// (x,y) -> ((x+A/3)/B,y/B)
|
||||||
|
ECPPoint Out;
|
||||||
|
Out.identity = In.identity;
|
||||||
|
Out.x = GetField().Multiply(m_fieldPtr->Add(In.x,m_AThirds),m_BInv);
|
||||||
|
Out.y = GetField().Multiply(In.y, m_BInv);
|
||||||
|
return Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
// ecpm.h - written and placed in public domain by Jean-Pierre Muench. Copyright assigned to Crypto++ project.
|
||||||
|
|
||||||
|
//! \file ecpm.h
|
||||||
|
//! \brief Classes for montgomery curves over prime fields
|
||||||
|
|
||||||
|
#ifndef CRYPTOPP_ECPM_H
|
||||||
|
#define CRYPTOPP_ECPM_H
|
||||||
|
|
||||||
|
#include "cryptlib.h"
|
||||||
|
#include "integer.h"
|
||||||
|
#include "modarith.h"
|
||||||
|
#include "eprecomp.h"
|
||||||
|
#include "smartptr.h"
|
||||||
|
#include "pubkey.h"
|
||||||
|
#include "ecp.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
|
// strategy:
|
||||||
|
// first do it the conservative way: each SimultaneousMultiply is followed and preceeded by a transformation
|
||||||
|
// later replace this algorithm using an optimized algorithm using the Montgomery Ladder
|
||||||
|
class CRYPTOPP_DLL ECPM : public AbstractGroup<ECPPoint>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef ModularArithmetic Field;
|
||||||
|
typedef Integer FieldElement;
|
||||||
|
typedef ECPPoint Point;
|
||||||
|
|
||||||
|
ECPM() {}
|
||||||
|
ECPM(const ECPM &ecp, bool convertToMontgomeryRepresentation = false);
|
||||||
|
ECPM(const Integer &modulus, const FieldElement &A, const FieldElement &B);
|
||||||
|
// construct from BER encoded parameters
|
||||||
|
// this constructor will decode and extract the the fields fieldID and curve of the sequence ECParameters
|
||||||
|
ECPM(BufferedTransformation &bt);
|
||||||
|
|
||||||
|
// encode the fields fieldID and curve of the sequence ECParameters
|
||||||
|
void DEREncode(BufferedTransformation &bt) const;
|
||||||
|
|
||||||
|
bool Equal(const Point &P, const Point &Q) const;
|
||||||
|
const Point& Identity() const;
|
||||||
|
const Point& Inverse(const Point &P) const;
|
||||||
|
bool InversionIsFast() const { return true; }
|
||||||
|
const Point& Add(const Point &P, const Point &Q) const;
|
||||||
|
const Point& Double(const Point &P) const;
|
||||||
|
Point ScalarMultiply(const Point &P, const Integer &k) const;
|
||||||
|
Point CascadeScalarMultiply(const Point &P, const Integer &k1, const Point &Q, const Integer &k2) const;
|
||||||
|
void SimultaneousMultiply(Point *results, const Point &base, const Integer *exponents, unsigned int exponentsCount) const;
|
||||||
|
|
||||||
|
Point Multiply(const Integer &k, const Point &P) const
|
||||||
|
{
|
||||||
|
return ScalarMultiply(P, k);
|
||||||
|
}
|
||||||
|
Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const
|
||||||
|
{
|
||||||
|
return CascadeScalarMultiply(P, k1, Q, k2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level = 3) const;
|
||||||
|
bool VerifyPoint(const Point &P) const;
|
||||||
|
|
||||||
|
unsigned int EncodedPointSize(bool compressed = false) const
|
||||||
|
{
|
||||||
|
return 1 + (compressed ? 1 : 2)*GetField().MaxElementByteLength();
|
||||||
|
}
|
||||||
|
// returns false if point is compressed and not valid (doesn't check if uncompressed)
|
||||||
|
bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const;
|
||||||
|
bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const;
|
||||||
|
void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const;
|
||||||
|
void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const;
|
||||||
|
|
||||||
|
Point BERDecodePoint(BufferedTransformation &bt) const;
|
||||||
|
void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const;
|
||||||
|
|
||||||
|
Integer FieldSize() const { return GetField().GetModulus(); }
|
||||||
|
const Field & GetField() const { return *m_fieldPtr; }
|
||||||
|
const FieldElement & GetA() const { return m_A; }
|
||||||
|
const FieldElement & GetB() const { return m_B; }
|
||||||
|
|
||||||
|
bool operator==(const ECPM &rhs) const
|
||||||
|
{
|
||||||
|
return GetField() == rhs.GetField() && m_A == rhs.m_A && m_B == rhs.m_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const ECPM &rhs);
|
||||||
|
|
||||||
|
#ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
|
||||||
|
virtual ~ECPM() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline Point WeierstrassToMontgomery(const Point& In) const;
|
||||||
|
inline Point MontgomeryToWeierstrass(const Point& In) const;
|
||||||
|
|
||||||
|
clonable_ptr<Field> m_fieldPtr;
|
||||||
|
clonable_ptr<ECP> m_ComputeEngine; // does the heavy lifting on the scalar multiplication
|
||||||
|
FieldElement m_A, m_B; // M_B * y^2 = x^3 + m_A * x^2 + x (mod p)
|
||||||
|
FieldElement m_AThirds, m_BInv; // for faster conversion, A/3 and 1/B
|
||||||
|
mutable Point m_R;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> class EcPrecomputation;
|
||||||
|
|
||||||
|
//! ECPM precomputation
|
||||||
|
template<> class EcPrecomputation<ECPM> : public DL_GroupPrecomputation<ECPM::Point>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef ECPM EllipticCurve;
|
||||||
|
|
||||||
|
// DL_GroupPrecomputation
|
||||||
|
bool NeedConversions() const { return true; }
|
||||||
|
Element ConvertIn(const Element &P) const
|
||||||
|
{
|
||||||
|
return P.identity ? P : ECPM::Point(m_ec->GetField().ConvertIn(P.x), m_ec->GetField().ConvertIn(P.y));
|
||||||
|
};
|
||||||
|
Element ConvertOut(const Element &P) const
|
||||||
|
{
|
||||||
|
return P.identity ? P : ECPM::Point(m_ec->GetField().ConvertOut(P.x), m_ec->GetField().ConvertOut(P.y));
|
||||||
|
}
|
||||||
|
const AbstractGroup<Element> & GetGroup() const { return *m_ec; }
|
||||||
|
Element BERDecodeElement(BufferedTransformation &bt) const { return m_ec->BERDecodePoint(bt); }
|
||||||
|
void DEREncodeElement(BufferedTransformation &bt, const Element &v) const { m_ec->DEREncodePoint(bt, v, false); }
|
||||||
|
|
||||||
|
// non-inherited
|
||||||
|
void SetCurve(const ECPM &ec)
|
||||||
|
{
|
||||||
|
m_ec.reset(new ECPM(ec, true));
|
||||||
|
m_ecOriginal = ec;
|
||||||
|
}
|
||||||
|
const ECPM & GetCurve() const { return *m_ecOriginal; }
|
||||||
|
|
||||||
|
#ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
|
||||||
|
virtual ~EcPrecomputation() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
value_ptr<ECPM> m_ec, m_ecOriginal;
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
||||||
26
oids.h
26
oids.h
|
|
@ -48,6 +48,32 @@ DEFINE_OID(1, iso)
|
||||||
DEFINE_OID(oiw()+3, oiw_secsig);
|
DEFINE_OID(oiw()+3, oiw_secsig);
|
||||||
DEFINE_OID(oiw_secsig()+2, oiw_secsig_algorithms);
|
DEFINE_OID(oiw_secsig()+2, oiw_secsig_algorithms);
|
||||||
DEFINE_OID(oiw_secsig_algorithms()+26, id_sha1);
|
DEFINE_OID(oiw_secsig_algorithms()+26, id_sha1);
|
||||||
|
DEFINE_OID(identified_organization() + 6, dod);
|
||||||
|
DEFINE_OID(dod() + 1, dod_internet);
|
||||||
|
DEFINE_OID(dod_internet() + 4, dod_internet_private);
|
||||||
|
DEFINE_OID(dod_internet_private() + 1, dod_internet_private_enterprise);
|
||||||
|
DEFINE_OID(dod_internet_private_enterprise() + 9509, denis_bider);
|
||||||
|
DEFINE_OID(denis_bider() + 5, cryptopp); // denis bider provided us with this OID root, see https://github.com/weidai11/cryptopp/issues/67#issuecomment-160915245
|
||||||
|
DEFINE_OID(cryptopp() + 1, cryptopp_montgomery_curves);
|
||||||
|
// see http://safecurves.cr.yp.to/equation.html for the curves
|
||||||
|
DEFINE_OID(cryptopp_montgomery_curves() + 1, cryptoppM221);
|
||||||
|
DEFINE_OID(cryptopp_montgomery_curves() + 2, cryptoppM383);
|
||||||
|
DEFINE_OID(cryptopp_montgomery_curves() + 3, cryptoppM511);
|
||||||
|
DEFINE_OID(cryptopp_montgomery_curves() + 4, cryptoppCurve383187);
|
||||||
|
DEFINE_OID(cryptopp() + 2, cryptopp_edwards_curves);
|
||||||
|
DEFINE_OID(cryptopp_edwards_curves() + 1, cryptoppE222);
|
||||||
|
DEFINE_OID(cryptopp_edwards_curves() + 2, cryptoppE382);
|
||||||
|
DEFINE_OID(cryptopp_edwards_curves() + 3, cryptoppEd448);
|
||||||
|
DEFINE_OID(cryptopp_edwards_curves() + 4, cryptoppE521);
|
||||||
|
DEFINE_OID(cryptopp_edwards_curves() + 5, cryptoppCurve1174);
|
||||||
|
DEFINE_OID(cryptopp_edwards_curves() + 6, cryptoppCurve41417);
|
||||||
|
DEFINE_OID(dod_internet_private_enterprise() + 11591, gnu);
|
||||||
|
DEFINE_OID(gnu() + 15, gnu_elliptic_curve);
|
||||||
|
// as per https://tools.ietf.org/html/draft-josefsson-pkix-newcurves
|
||||||
|
DEFINE_OID(gnu_elliptic_curve() + 1, ietfCurve25519);
|
||||||
|
DEFINE_OID(gnu_elliptic_curve() + 2, ietfCurve448);
|
||||||
|
DEFINE_OID(gnu_elliptic_curve() + 3, ietfCurve25519ph);
|
||||||
|
DEFINE_OID(gnu_elliptic_curve() + 4, ietfCurve448ph);
|
||||||
|
|
||||||
DEFINE_OID(identified_organization()+36, teletrust);
|
DEFINE_OID(identified_organization()+36, teletrust);
|
||||||
DEFINE_OID(teletrust()+3, teletrust_algorithm)
|
DEFINE_OID(teletrust()+3, teletrust_algorithm)
|
||||||
|
|
|
||||||
1
test.cpp
1
test.cpp
|
|
@ -937,6 +937,7 @@ bool Validate(int alg, bool thorough, const char *seedInput)
|
||||||
case 68: result = ValidateGCM(); break;
|
case 68: result = ValidateGCM(); break;
|
||||||
case 69: result = ValidateCMAC(); break;
|
case 69: result = ValidateCMAC(); break;
|
||||||
case 70: result = ValidateHKDF(); break;
|
case 70: result = ValidateHKDF(); break;
|
||||||
|
case 71: result = ValidateECPM(); break;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,7 @@ bool ValidateAll(bool thorough)
|
||||||
pass=ValidateRW() && pass;
|
pass=ValidateRW() && pass;
|
||||||
// pass=ValidateBlumGoldwasser() && pass;
|
// pass=ValidateBlumGoldwasser() && pass;
|
||||||
pass=ValidateECP() && pass;
|
pass=ValidateECP() && pass;
|
||||||
|
pass = ValidateECPM() && pass;
|
||||||
pass=ValidateEC2N() && pass;
|
pass=ValidateEC2N() && pass;
|
||||||
pass=ValidateECDSA() && pass;
|
pass=ValidateECDSA() && pass;
|
||||||
pass=ValidateESIGN() && pass;
|
pass=ValidateESIGN() && pass;
|
||||||
|
|
|
||||||
107
validat2.cpp
107
validat2.cpp
|
|
@ -26,6 +26,7 @@
|
||||||
#include "integer.h"
|
#include "integer.h"
|
||||||
#include "gf2n.h"
|
#include "gf2n.h"
|
||||||
#include "ecp.h"
|
#include "ecp.h"
|
||||||
|
#include "ecpm.h"
|
||||||
#include "ec2n.h"
|
#include "ec2n.h"
|
||||||
#include "asn.h"
|
#include "asn.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
|
|
@ -715,6 +716,112 @@ bool ValidateECP()
|
||||||
return pass;
|
return pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ValidateECPM()
|
||||||
|
{
|
||||||
|
cout << "\nECPM validation suite running...\n\n";
|
||||||
|
|
||||||
|
ECIES<ECPM> ::Decryptor cpriv(GlobalRNG(), ASN1::ietfCurve25519());
|
||||||
|
ECIES<ECPM>::Encryptor cpub(cpriv);
|
||||||
|
ByteQueue bq;
|
||||||
|
cpriv.GetKey().DEREncode(bq);
|
||||||
|
cpub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
|
||||||
|
cpub.GetKey().DEREncode(bq);
|
||||||
|
ECDSA<ECPM, SHA>::Signer spriv(bq);
|
||||||
|
ECDSA<ECPM, SHA>::Verifier spub(bq);
|
||||||
|
ECDH<ECPM>::Domain ecdhc(ASN1::ietfCurve25519());
|
||||||
|
ECMQV<ECPM>::Domain ecmqvc(ASN1::ietfCurve25519());
|
||||||
|
|
||||||
|
spriv.AccessKey().Precompute();
|
||||||
|
ByteQueue queue;
|
||||||
|
spriv.AccessKey().SavePrecomputation(queue);
|
||||||
|
spriv.AccessKey().LoadPrecomputation(queue);
|
||||||
|
|
||||||
|
bool pass = SignatureValidate(spriv, spub);
|
||||||
|
cpub.AccessKey().Precompute();
|
||||||
|
cpriv.AccessKey().Precompute();
|
||||||
|
pass = CryptoSystemValidate(cpriv, cpub) && pass;
|
||||||
|
pass = SimpleKeyAgreementValidate(ecdhc) && pass;
|
||||||
|
pass = AuthenticatedKeyAgreementValidate(ecmqvc) && pass;
|
||||||
|
|
||||||
|
cout << "Turning on point compression..." << endl;
|
||||||
|
cpriv.AccessKey().AccessGroupParameters().SetPointCompression(true);
|
||||||
|
cpub.AccessKey().AccessGroupParameters().SetPointCompression(true);
|
||||||
|
ecdhc.AccessGroupParameters().SetPointCompression(true);
|
||||||
|
ecmqvc.AccessGroupParameters().SetPointCompression(true);
|
||||||
|
pass = CryptoSystemValidate(cpriv, cpub) && pass;
|
||||||
|
pass = SimpleKeyAgreementValidate(ecdhc) && pass;
|
||||||
|
pass = AuthenticatedKeyAgreementValidate(ecmqvc) && pass;
|
||||||
|
|
||||||
|
cout << "Testing recommended montgomery curves..." << endl;
|
||||||
|
OID oid;
|
||||||
|
while (!(oid = DL_GroupParameters_EC<ECPM>::GetNextRecommendedParametersOID(oid)).m_values.empty())
|
||||||
|
{
|
||||||
|
DL_GroupParameters_EC<ECPM> params(oid);
|
||||||
|
bool fail = !params.Validate(GlobalRNG(), 2);
|
||||||
|
cout << (fail ? "FAILED" : "passed") << " " << dec << params.GetCurve().GetField().MaxElementBitLength() << " bits" << endl;
|
||||||
|
pass = pass && !fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*cout << "Performing the IRTF KATs..." << endl;
|
||||||
|
|
||||||
|
// tests from page 10 of IRTF curves draft 11
|
||||||
|
// calculate the y coordinates for the test
|
||||||
|
DL_GroupParameters_EC<ECPM> Curve25519(ASN1::ietfCurve25519());
|
||||||
|
const char* KAT_Base_25519_1 = "0231029842492115040904895560451863089656472772604678260265531221036453811406496";
|
||||||
|
const char* KAT_Base_25519_2 = "02e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493";
|
||||||
|
StringSource SS25519KAT_1(KAT_Base_25519_1,true,new HexDecoder);
|
||||||
|
StringSource SS25519KAT_2(KAT_Base_25519_2, true, new HexDecoder);
|
||||||
|
Integer()
|
||||||
|
ECPPoint P_KAT_Base_25519_1, P_KAT_Base_25519_2;
|
||||||
|
Curve25519.GetCurve().DecodePoint(P_KAT_Base_25519_1, SS25519KAT_1, 67);
|
||||||
|
Curve25519.GetCurve().DecodePoint(P_KAT_Base_25519_2, SS25519KAT_2, 67);
|
||||||
|
Integer x125519("0xe6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c");
|
||||||
|
Integer x225519("0xe5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493");
|
||||||
|
Integer BInv25519 = Curve25519.GetCurve().GetField().MultiplicativeInverse(Curve25519.GetCurve().GetB());
|
||||||
|
Integer y125519 = (x125519*BInv25519*(x125519*(x125519 + Curve25519.GetCurve().GetA()) + 1)) % Curve25519.GetCurve().GetField().GetModulus();
|
||||||
|
y125519 = ModularSquareRoot(y125519, Curve25519.GetCurve().GetField().GetModulus());
|
||||||
|
Integer y225519 = (x225519*BInv25519*(x225519*(x225519 + Curve25519.GetCurve().GetA()) + 1)) % Curve25519.GetCurve().GetField().GetModulus();
|
||||||
|
y225519 = ModularSquareRoot(y225519, Curve25519.GetCurve().GetField().GetModulus());
|
||||||
|
|
||||||
|
cout <<hex<< "x1: " << x125519 << endl;
|
||||||
|
|
||||||
|
ECPPoint Test125519 = Curve25519.ExponentiateElement(P_KAT_Base_25519_1, Integer("0xa546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4"));
|
||||||
|
ECPPoint Test225519 = Curve25519.ExponentiateElement(P_KAT_Base_25519_2, Integer("0x4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d"));
|
||||||
|
|
||||||
|
Integer Result125519("0xe6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c");
|
||||||
|
Integer Result225519("0xe5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493");
|
||||||
|
|
||||||
|
bool failedKATs = false;
|
||||||
|
pass = pass && (Result125519 == Test125519.x);
|
||||||
|
pass = pass && (Result225519 == Test225519.x);
|
||||||
|
failedKATs = failedKATs || (Result125519 != Test125519.x);
|
||||||
|
failedKATs = failedKATs || (Result225519 != Test225519.x);
|
||||||
|
|
||||||
|
DL_GroupParameters_EC<ECPM> Curve448(ASN1::ietfCurve448());
|
||||||
|
Integer x1448("0x06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086");
|
||||||
|
Integer x2448("0x0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db");
|
||||||
|
Integer BInv448 = Curve448.GetCurve().GetField().MultiplicativeInverse(Curve448.GetCurve().GetB());
|
||||||
|
Integer y1448 = (x1448*BInv448*(x1448*(x1448 + Curve448.GetCurve().GetA()) + 1)) % Curve448.GetCurve().GetField().GetModulus();
|
||||||
|
y1448 = ModularSquareRoot(y1448, Curve448.GetCurve().GetField().GetModulus());
|
||||||
|
Integer y2448 = (x2448*BInv448*(x2448*(x2448 + Curve448.GetCurve().GetA()) + 1)) % Curve448.GetCurve().GetField().GetModulus();
|
||||||
|
y2448 = ModularSquareRoot(y2448, Curve448.GetCurve().GetField().GetModulus());
|
||||||
|
|
||||||
|
ECPPoint Test1448 = Curve448.ExponentiateElement(ECPPoint(x1448, y1448), Integer("0x3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3"));
|
||||||
|
ECPPoint Test2448 = Curve448.ExponentiateElement(ECPPoint(x2448, y2448), Integer("0x203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f"));
|
||||||
|
|
||||||
|
Integer Result1448("0xce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f");
|
||||||
|
Integer Result2448("0x884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d");
|
||||||
|
|
||||||
|
pass = pass && (Result1448 == Test1448.x);
|
||||||
|
pass = pass && (Result2448 == Test2448.x);
|
||||||
|
failedKATs = failedKATs || (Result1448 != Test1448.x);
|
||||||
|
failedKATs = failedKATs || (Result2448 != Test2448.x);
|
||||||
|
|
||||||
|
cout << (failedKATs ? "FAILED" : "passed") << " " << "known anser tests" << endl;*/
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
bool ValidateEC2N()
|
bool ValidateEC2N()
|
||||||
{
|
{
|
||||||
cout << "\nEC2N validation suite running...\n\n";
|
cout << "\nEC2N validation suite running...\n\n";
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ bool ValidateRabin();
|
||||||
bool ValidateRW();
|
bool ValidateRW();
|
||||||
//bool ValidateBlumGoldwasser();
|
//bool ValidateBlumGoldwasser();
|
||||||
bool ValidateECP();
|
bool ValidateECP();
|
||||||
|
bool ValidateECPM();
|
||||||
bool ValidateEC2N();
|
bool ValidateEC2N();
|
||||||
bool ValidateECDSA();
|
bool ValidateECDSA();
|
||||||
bool ValidateESIGN();
|
bool ValidateESIGN();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue