Below is the next patch planned for Rabin-Williams. It improves efficiency
of the signature scheme while maintaining compatibility with P1363 and
preserving existing behavior.
The class members used in precomputation are mutable so Precompute can be
called from const member functions. The precomputation does not modify the
RW proper parameters, like n, p, q and u.
The OMP gear is guarded by an OMP if clause dependent upon
CRYPTOPP_RW_USE_OMP. We were not able to improve performance for the class
by utilizing OMP.
Optional blinding was removed in favor of a "better" planned cut-in.
Blinding applies to many (all?) integer factorization based problems, so it
should be more than a one-off cut-in.
The fix for CVE-2015-2141 was already committed.
Comments are welcomed.
**********
$ cat rw.diff
diff --git a/rw.cpp b/rw.cpp
index 0b9318b..00fc00d 100644
--- a/rw.cpp
+++ b/rw.cpp
@@ -5,8 +5,14 @@
#include "nbtheory.h"
#include "asn.h"
+#ifndef NDEBUG
+# include <cassert>
+#endif
+
#ifndef CRYPTOPP_IMPORTS
+static const bool CRYPTOPP_RW_USE_OMP = true;
+
NAMESPACE_BEGIN(CryptoPP)
void RWFunction::BERDecode(BufferedTransformation &bt)
@@ -99,6 +105,55 @@ void
InvertibleRWFunction::GenerateRandom(RandomNumberGenerator &rng, const Name
m_n = m_p * m_q;
m_u = m_q.InverseMod(m_p);
+
+ Precompute();
+}
+
+void InvertibleRWFunction::Initialize(const Integer &n, const Integer &p,
const Integer &q, const Integer &u)
+{
+ m_n = n; m_p = p; m_q = q; m_u = u;
+
+ Precompute();
+}
+
+void InvertibleRWFunction::PrecomputeTweakedRoots() const
+{
+ ModularArithmetic modp(m_p), modq(m_q);
+
+ #pragma omp parallel sections if(CRYPTOPP_RW_USE_OMP)
+ {
+ #pragma omp section
+ m_pre_2_9p = modp.Exponentiate(2, (9 * m_p - 11)/8);
+ #pragma omp section
+ m_pre_2_3q = modq.Exponentiate(2, (3 * m_q - 5)/8);
+ #pragma omp section
+ m_pre_q_p = modp.Exponentiate(m_q, m_p - 2);
+ }
+
+ m_precompute = true;
+}
+
+void InvertibleRWFunction::LoadPrecomputation(BufferedTransformation &bt)
+{
+ BERSequenceDecoder seq(bt);
+ m_pre_2_9p.BERDecode(seq);
+ m_pre_2_3q.BERDecode(seq);
+ m_pre_q_p.BERDecode(seq);
+ seq.MessageEnd();
+
+ m_precompute = true;
+}
+
+void InvertibleRWFunction::SavePrecomputation(BufferedTransformation &bt)
const
+{
+ if(!m_precompute)
+ Precompute();
+
+ DERSequenceEncoder seq(bt);
+ m_pre_2_9p.DEREncode(seq);
+ m_pre_2_3q.DEREncode(seq);
+ m_pre_q_p.DEREncode(seq);
+ seq.MessageEnd();
}
void InvertibleRWFunction::BERDecode(BufferedTransformation &bt)
@@ -109,6 +164,8 @@ void
InvertibleRWFunction::BERDecode(BufferedTransformation &bt)
m_q.BERDecode(seq);
m_u.BERDecode(seq);
seq.MessageEnd();
+
+ m_precompute = false;
}
void InvertibleRWFunction::DEREncode(BufferedTransformation &bt) const
@@ -121,46 +178,70 @@ void
InvertibleRWFunction::DEREncode(BufferedTransformation &bt) const
seq.MessageEnd();
}
+// DJB's "RSA signatures and Rabin-Williams signatures..."
(http://cr.yp.to/sigs/rwsota-20080131.pdf).
Integer InvertibleRWFunction::CalculateInverse(RandomNumberGenerator &rng,
const Integer &x) const
{
DoQuickSanityCheck();
- ModularArithmetic modn(m_n);
+
+ if(!m_precompute)
+ Precompute();
+
+ ModularArithmetic modn(m_n), modp(m_p), modq(m_q);
Integer r, rInv;
- // do this in a loop for people using small numbers for testing
- do {
+ do
+ {
+ // Do this in a loop for people using small numbers for
testing
r.Randomize(rng, Integer::One(), m_n - Integer::One());
// Fix for CVE-2015-2141. Thanks to Evgeny Sidorov for
reporting.
- // Squaring to satisfy Jacobi requirements suggested by JPM.
+ // Squaring to satisfy Jacobi requirements suggested by
Jean-Pierre Munch.
r = modn.Square(r);
rInv = modn.MultiplicativeInverse(r);
- } while (rInv.IsZero());
+ } while(rInv.IsZero());
Integer re = modn.Square(r);
- re = modn.Multiply(re, x); // blind
+ re = modn.Multiply(re, x); // blind
- Integer cp=re%m_p, cq=re%m_q;
- if (Jacobi(cp, m_p) * Jacobi(cq, m_q) != 1)
- {
- cp = cp.IsOdd() ? (cp+m_p) >> 1 : cp >> 1;
- cq = cq.IsOdd() ? (cq+m_q) >> 1 : cq >> 1;
- }
+ const Integer &h = re, &p = m_p, &q = m_q, &n = m_n;
+ Integer e, f;
+
+ const Integer U = modq.Exponentiate(h, (q+1)/8);
+ if(((modq.Exponentiate(U, 4) - h) % q).IsZero())
+ e = Integer::One();
+ else
+ e = -1;
+
+ const Integer eh = e*h, V = modp.Exponentiate(eh, (p-3)/8);
+ if(((modp.Multiply(modp.Exponentiate(V, 4), modp.Exponentiate(eh,
2)) - eh) % p).IsZero())
+ f = Integer::One();
+ else
+ f = 2;
- #pragma omp parallel
- #pragma omp sections
+ Integer W, X;
+ #pragma omp parallel sections if(CRYPTOPP_RW_USE_OMP)
+ {
+ #pragma omp section
+ {
+ W = (f.IsUnit() ? U : modq.Multiply(m_pre_2_3q, U));
+ }
+ #pragma omp section
{
- #pragma omp section
- cp = ModularSquareRoot(cp, m_p);
- #pragma omp section
- cq = ModularSquareRoot(cq, m_q);
+ const Integer t =
modp.Multiply(modp.Exponentiate(V, 3), eh);
+ X = (f.IsUnit() ? t : modp.Multiply(m_pre_2_9p, t));
}
+ }
+ const Integer Y = W + q * modp.Multiply(m_pre_q_p, (X - W));
+
+ // Signature
+ Integer s = modn.Multiply(modn.Square(Y), rInv);
+ assert((e * f * s.Squared()) % m_n == x);
- Integer y = CRT(cq, m_q, cp, m_p, m_u);
- y = modn.Multiply(y, rInv); // unblind
- y = STDMIN(y, m_n-y);
- if (ApplyFunction(y) != x) // check
+ // IEEE P1363, Section 8.2.8 IFSP-RW, p.44
+ s = STDMIN(s, m_n - s);
+ if (ApplyFunction(s) != x) // check
throw Exception(Exception::OTHER_ERROR,
"InvertibleRWFunction: computational error during private key operation");
- return y;
+
+ return s;
}
bool InvertibleRWFunction::Validate(RandomNumberGenerator &rng, unsigned
int level) const
@@ -195,6 +276,8 @@ void InvertibleRWFunction::AssignFrom(const
NameValuePairs &source)
CRYPTOPP_SET_FUNCTION_ENTRY(Prime2)
CRYPTOPP_SET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1)
;
+
+ m_precompute = false;
}
NAMESPACE_END
diff --git a/rw.h b/rw.h
index 6820251..45b3946 100644
--- a/rw.h
+++ b/rw.h
@@ -48,8 +48,9 @@ class CRYPTOPP_DLL InvertibleRWFunction : public
RWFunction, public TrapdoorFunc
typedef InvertibleRWFunction ThisClass;
public:
- void Initialize(const Integer &n, const Integer &p, const Integer
&q, const Integer &u)
- {m_n = n; m_p = p; m_q = q; m_u = u;}
+ InvertibleRWFunction() : m_precompute(false) {}
+
+ void Initialize(const Integer &n, const Integer &p, const Integer
&q, const Integer &u);
// generate a random private key
void Initialize(RandomNumberGenerator &rng, unsigned int
modulusBits)
{GenerateRandomWithKeySize(rng, modulusBits);}
@@ -79,8 +80,21 @@ public:
void SetPrime2(const Integer &q) {m_q = q;}
void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u)
{m_u = u;}
+ virtual bool SupportsPrecomputation() const {return true;}
+ virtual void Precompute(unsigned int unused = 0)
{PrecomputeTweakedRoots();}
+ virtual void Precompute(unsigned int unused = 0) const
{PrecomputeTweakedRoots();}
+
+ virtual void LoadPrecomputation(BufferedTransformation
&storedPrecomputation);
+ virtual void SavePrecomputation(BufferedTransformation
&storedPrecomputation) const;
+
+protected:
+ void PrecomputeTweakedRoots() const;
+
protected:
Integer m_p, m_q, m_u;
+
+ mutable Integer m_pre_2_9p, m_pre_2_3q, m_pre_q_p;
+ mutable bool m_precompute;
};
//! RW
--
--
You received this message because you are subscribed to the "Crypto++ Users"
Google Group.
To unsubscribe, send an email to [email protected].
More information about Crypto++ and this group is available at
http://www.cryptopp.com.
---
You received this message because you are subscribed to the Google Groups
"Crypto++ Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.