Skip to content

Commit de6cfd3

Browse files
committed
Removed modSqrt. All credit to Joric!
Derp. Well that sure simplifies things, doesn't it... :)
1 parent 9b2f94a commit de6cfd3

File tree

1 file changed

+8
-113
lines changed

1 file changed

+8
-113
lines changed

src/ecdsa.js

+8-113
Original file line numberDiff line numberDiff line change
@@ -10,118 +10,6 @@ function integerToBytes(i, len) {
1010
return bytes;
1111
};
1212

13-
/**
14-
* Find a quadratic residue (mod p) of this number. p must be an odd prime.
15-
*
16-
* For a given number a, this function solves the congruence of the form
17-
*
18-
* x^2 = a (mod p)
19-
*
20-
* And returns x. Note that p - x is also a root.
21-
*
22-
* 0 is returned if no square root exists for these a and p.
23-
*
24-
* The Tonelli-Shanks algorithm is used (except for some simple cases
25-
* in which the solution is known from an identity). This algorithm
26-
* runs in polynomial time (unless the generalized Riemann hypothesis
27-
* is false).
28-
*
29-
* Originally implemented in Python by Eli Bendersky:
30-
* http://eli.thegreenplace.net/2009/03/07/computing-modular-square-roots-in-python/
31-
*
32-
* Ported to JavaScript by Stefan Thomas.
33-
*/
34-
BigInteger.prototype.modSqrt = function (p) {
35-
var ONE = BigInteger.ONE,
36-
TWO = BigInteger.valueOf(2);
37-
38-
// Simple cases
39-
if (this.legendre(p) != 1) {
40-
return BigInteger.ZERO;
41-
} else if (this.equals(BigInteger.ZERO)) {
42-
return BigInteger.ZERO;
43-
} else if (p.equals(TWO)) {
44-
return p;
45-
} else if (p.mod(BigInteger.valueOf(4)).equals(BigInteger.valueOf(3))) {
46-
return this.modPow(p.add(ONE).divide(BigInteger.valueOf(4)), p);
47-
}
48-
49-
// Partition p-1 to s * 2^e for an odd s (i.e. reduce all the powers
50-
// of 2 from p-1)
51-
var s = p.subtract(ONE);
52-
var e = 0;
53-
while (s.isEven()) {
54-
s = s.divide(TWO);
55-
++e;
56-
}
57-
58-
// Find some 'n' with a legendre symbol n|p = -1.
59-
// Shouldn't take long.
60-
var n = TWO;
61-
while (n.legendre(p) != -1) {
62-
n = n.add(ONE);
63-
}
64-
65-
// Here be dragons!
66-
// Read the paper "Square roots from 1; 24, 51, 10 to Dan Shanks" by
67-
// Ezra Brown for more information
68-
69-
// x is a guess of the square root that gets better with each
70-
// iteration.
71-
//
72-
// b is the "fudge factor" - by how much we're off with the guess.
73-
// The invariant x^2 = ab (mod p) is maintained throughout the loop.
74-
//
75-
// g is used for successive powers of n to update both a and b
76-
//
77-
// r is the exponent - decreases with each update
78-
79-
var x = this.modPow(s.add(ONE).divide(TWO), p);
80-
var b = this.modPow(s, p);
81-
var g = n.modPow(s, p);
82-
var r = e;
83-
84-
for (;;) {
85-
var t = b;
86-
87-
var m;
88-
for (m = 0; m < r; m++) {
89-
if (t.equals(ONE)) break;
90-
91-
t = t.modPowInt(2, p);
92-
}
93-
94-
if (m == 0) {
95-
return x;
96-
}
97-
98-
var gs = g.modPow(TWO.pow(BigInteger.valueOf(r - m - 1)), p);
99-
g = gs.multiply(gs).mod(p);
100-
x = x.multiply(gs).mod(p);
101-
b = b.multiply(g).mod(p);
102-
r = m;
103-
}
104-
};
105-
106-
/**
107-
* Compute the Legendre symbol a|p using Euler's criterion.
108-
*
109-
* p is a prime, a is relatively prime to p
110-
* (if p divides a, then a | p = 0)
111-
*
112-
* Returns 1 if a has a square root modulo p, -1 otherwise.
113-
*/
114-
BigInteger.prototype.legendre = function (p) {
115-
var ls = this.modPow(p.subtract(BigInteger.ONE).shiftRight(1), p);
116-
if (ls.equals(p.subtract(BigInteger.ONE))) {
117-
return -1;
118-
} else if (ls.equals(BigInteger.ZERO)) {
119-
return 0;
120-
} else {
121-
return 1;
122-
}
123-
};
124-
12513
ECFieldElementFp.prototype.getByteLength = function () {
12614
return Math.floor((this.toBigInteger().bitLength() + 7) / 8);
12715
};
@@ -304,6 +192,8 @@ Bitcoin.ECDSA = (function () {
304192
var ecparams = getSECCurveByName("secp256k1");
305193
var rng = new SecureRandom();
306194

195+
var P_OVER_FOUR = null;
196+
307197
function implShamirsTrick(P, k, Q, l)
308198
{
309199
var m = Math.max(k.bitLength(), l.bitLength());
@@ -515,12 +405,17 @@ Bitcoin.ECDSA = (function () {
515405
var a = curve.getA().toBigInteger();
516406
var b = curve.getB().toBigInteger();
517407

408+
// We precalculate (p + 1) / 4 where p is if the field order
409+
if (!P_OVER_FOUR) {
410+
P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4));
411+
}
412+
518413
// 1.1 Compute x
519414
var x = isSecondKey ? r.add(n) : r;
520415

521416
// 1.3 Convert x to point
522417
var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
523-
var beta = alpha.modSqrt(p);
418+
var beta = alpha.modPow(P_OVER_FOUR, p);
524419

525420
var xorOdd = beta.isEven() ? (i % 2) : ((i+1) % 2);
526421
// If beta is even, but y isn't or vice versa, then convert it,

0 commit comments

Comments
 (0)