Skip to content

Commit 1cc9654

Browse files
authored
Merge pull request #34 from dufkan/master
Release 2.1 changes
2 parents cabb25f + cd8b577 commit 1cc9654

19 files changed

+476
-145
lines changed

CITATION.cff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ authors:
88
- family-names: "Dufka"
99
given-names: "Antonin"
1010
title: "JCMathLib"
11-
version: 2.0
11+
version: 2.1
1212
url: "https://github.com/OpenCryptoProject/JCMathLib"
1313
preferred-citation:
1414
type: conference-paper

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,19 +152,19 @@ options:
152152
-h, --help show this help message and exit
153153
-d DIR, --dir DIR Directory to package
154154
-k, --keep-locks Keep locks
155-
-c {SecP256k1,SecP256r1,SecP512r1} [{SecP256k1,SecP256r1,SecP512r1} ...], --curves {SecP256k1,SecP256r1,SecP512r1} [{SecP256k1,SecP256r1,SecP512r1} ...]
155+
-c {SecP256k1,SecP256r1,SecP512r1,Wei25519} [{SecP256k1,SecP256r1,SecP512r1,Wei25519} ...], --curves {SecP256k1,SecP256r1,SecP512r1,Wei25519} [{SecP256k1,SecP256r1,SecP512r1,Wei25519} ...]
156156
Curves to include
157157
-p PACKAGE, --package PACKAGE
158158
Package name
159159
-o OUTPUT, --output OUTPUT
160160
Output file
161161
```
162162
163-
For example, to bundle JCMathLib for your applet `test` in which you use curve `SecP256k1`, use the following. The
163+
For example, to bundle JCMathLib for your applet `test` in which you use curve `SecP256r1`, use the following. The
164164
output will be stored in `jcmathlib.java` file.
165165
166166
```
167-
$ python package.py -p test -c SecP256k1 -o jcmathlib.java
167+
$ python package.py -p test -c SecP256r1 -o jcmathlib.java
168168
```
169169
170170
## Community

applet/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
group 'test-applet'
2-
version '2.0'
2+
version '2.1'
33

44
// Buildscript configuration for the javacard-gradle plugin.
55
// Do not modify this particular block. Dependencies for the project are lower.

applet/src/main/java/opencrypto/jcmathlib/BigNat.java

Lines changed: 103 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ public void divide(BigNat other) {
2828
tmp.lock();
2929
tmp.clone(this);
3030
tmp.remainderDivide(other, this);
31-
copy(tmp);
3231
tmp.unlock();
3332
}
3433

@@ -236,6 +235,12 @@ private void modSqFixed() {
236235
public void modExp(BigNat exp, BigNat mod) {
237236
if (!OperationSupport.getInstance().RSA_EXP)
238237
ISOException.throwIt(ReturnCodes.SW_OPERATION_NOT_SUPPORTED);
238+
if (OperationSupport.getInstance().RSA_CHECK_EXP_ONE && exp.isOne())
239+
return;
240+
if (!OperationSupport.getInstance().RSA_SQ && exp.isTwo()) {
241+
modMult(this, mod);
242+
return;
243+
}
239244

240245
BigNat tmpMod = rm.BN_F; // modExp is called from modSqrt => requires BN_F not being locked when modExp is called
241246
byte[] tmpBuffer = rm.ARRAY_A;
@@ -399,47 +404,47 @@ public void modSq(BigNat mod) {
399404
}
400405
}
401406

407+
/**
408+
* Checks whether this BigNat is a quadratic residue modulo p.
409+
* @param p modulo
410+
*/
411+
public boolean isQuadraticResidue(BigNat p) {
412+
BigNat tmp = rm.BN_A;
413+
BigNat exp = rm.BN_B;
414+
tmp.clone(this);
415+
exp.clone(p);
416+
exp.decrement();
417+
exp.shiftRight((short) 1);
418+
tmp.modExp(exp, p);
419+
return tmp.isOne();
420+
}
421+
402422
/**
403423
* Computes square root of provided BigNat which MUST be prime using Tonelli Shanks Algorithm. The result (one of
404424
* the two roots) is stored to this.
405425
*/
406426
public void modSqrt(BigNat p) {
407-
BigNat s = rm.BN_A;
408-
BigNat exp = rm.BN_A;
427+
BigNat exp = rm.BN_G;
409428
BigNat p1 = rm.BN_B;
410429
BigNat q = rm.BN_C;
411430
BigNat tmp = rm.BN_D;
412-
BigNat z = rm.BN_E;
431+
BigNat z = rm.BN_A;
432+
BigNat t = rm.BN_B;
433+
BigNat b = rm.BN_C;
413434

414-
// 1. By factoring out powers of 2, find Q and S such that p-1=Q2^S p-1=Q*2^S and Q is odd
435+
// 1. Find Q and S such that p - 1 = Q * 2^S and Q is odd
415436
p1.lock();
416437
p1.clone(p);
417438
p1.decrement();
418439

419-
// Compute Q
420440
q.lock();
421441
q.clone(p1);
422-
q.shiftRight((short) 1); // Q /= 2
423442

424-
// Compute S
425-
s.lock();
426-
s.setSize(p.length());
427-
s.zero();
428-
tmp.lock();
429-
tmp.setSize(p.length());
430-
tmp.zero();
431-
432-
while (!tmp.equals(q)) {
433-
s.increment();
434-
// TODO replace with modMult(s, q, p)
435-
tmp.setSizeToMax(false);
436-
tmp.clone(s);
437-
tmp.mult(q);
438-
tmp.mod(p);
439-
tmp.shrink();
443+
short s = 0;
444+
while (!q.isOdd()) {
445+
++s;
446+
q.shiftRight((short) 1);
440447
}
441-
tmp.unlock();
442-
s.unlock();
443448

444449
// 2. Find the first quadratic non-residue z by brute-force search
445450
exp.lock();
@@ -451,23 +456,92 @@ public void modSqrt(BigNat p) {
451456
z.setSize(p.length());
452457
z.setValue((byte) 1);
453458
tmp.lock();
459+
tmp.setSize(p.length());
454460
tmp.setValue((byte) 1);
455461

456462
while (!tmp.equals(p1)) {
457463
z.increment();
458464
tmp.copy(z);
459-
tmp.modExp(exp, p);
465+
tmp.modExp(exp, p); // Euler's criterion
460466
}
461467
p1.unlock();
462468
tmp.unlock();
463-
z.unlock();
464-
exp.copy(q);
465-
q.unlock();
469+
470+
// 3. Compute the first candidate
471+
exp.clone(q);
466472
exp.increment();
467473
exp.shiftRight((short) 1);
468474

475+
t.lock();
476+
t.clone(this);
477+
t.modExp(q, p);
478+
479+
if (t.isZero()) {
480+
z.unlock();
481+
t.unlock();
482+
exp.unlock();
483+
q.unlock();
484+
zero();
485+
return;
486+
}
487+
469488
mod(p);
470489
modExp(exp, p);
471490
exp.unlock();
491+
492+
if (t.isOne()) {
493+
z.unlock();
494+
t.unlock();
495+
q.unlock();
496+
return;
497+
}
498+
499+
// 4. Search for further candidates
500+
z.modExp(q, p);
501+
q.unlock();
502+
503+
while(true) {
504+
tmp.lock();
505+
tmp.clone(t);
506+
short i = 0;
507+
508+
do {
509+
tmp.modSq(p);
510+
++i;
511+
} while (!tmp.isOne());
512+
513+
tmp.unlock();
514+
515+
b.lock();
516+
b.clone(z);
517+
s -= i;
518+
--s;
519+
520+
tmp.lock();
521+
tmp.setSize((short) 1);
522+
tmp.setValue((byte) 1);
523+
while(s != 0) {
524+
tmp.shiftLeft((short) 1);
525+
--s;
526+
}
527+
b.modExp(tmp, p);
528+
tmp.unlock();
529+
s = i;
530+
z.clone(b);
531+
z.modSq(p);
532+
t.modMult(z, p);
533+
modMult(b, p);
534+
b.unlock();
535+
536+
if(t.isZero()) {
537+
zero();
538+
break;
539+
}
540+
if(t.isOne()) {
541+
break;
542+
}
543+
}
544+
z.unlock();
545+
t.unlock();
472546
}
473547
}

applet/src/main/java/opencrypto/jcmathlib/BigNatInternal.java

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,18 @@ public boolean isOne() {
250250
return value[(short) (value.length - 1)] == (byte) 0x01;
251251
}
252252

253+
/**
254+
* Test equality with two.
255+
*/
256+
public boolean isTwo() {
257+
for (short i = offset; i < (short) (value.length - 1); i++) {
258+
if (value[i] != 0) {
259+
return false; // CTO
260+
}
261+
}
262+
return value[(short) (value.length - 1)] == (byte) 0x02;
263+
}
264+
253265
/**
254266
* Check if stored BigNat is odd.
255267
*/
@@ -456,7 +468,7 @@ public void mult(BigNatInternal other) {
456468
* Right bit shift with carry
457469
*
458470
* @param bits number of bits to shift by
459-
* @param carry XORed into the highest byte
471+
* @param carry ORed into the highest byte
460472
*/
461473
protected void shiftRight(short bits, short carry) {
462474
// assumes 0 <= bits < 8
@@ -480,6 +492,39 @@ public void shiftRight(short bits) {
480492
shiftRight(bits, (short) 0);
481493
}
482494

495+
/**
496+
* Left bit shift with carry
497+
*
498+
* @param bits number of bits to shift by
499+
* @param carry ORed into the lowest byte
500+
*/
501+
protected void shiftLeft(short bits, short carry) {
502+
// assumes 0 <= bits < 8
503+
short mask = (short) ((-1 << (8 - bits)) & 0xff); // highest `bits` bits set to 1
504+
for (short i = (short) (value.length - 1); i >= offset; --i) {
505+
short current = (short) (value[i] & 0xff);
506+
short previous = current;
507+
current <<= bits;
508+
value[i] = (byte) (current | carry);
509+
carry = (short) (previous & mask);
510+
carry >>= (8 - bits);
511+
}
512+
513+
if (carry != 0) {
514+
setSize((short) (size + 1));
515+
value[offset] = (byte) carry;
516+
}
517+
}
518+
519+
/**
520+
* Right bit shift
521+
*
522+
* @param bits number of bits to shift by
523+
*/
524+
public void shiftLeft(short bits) {
525+
shiftLeft(bits, (short) 0);
526+
}
527+
483528
/**
484529
* Divide this by divisor and store the remained in this and quotient in quotient.
485530
*
@@ -490,7 +535,7 @@ public void shiftRight(short bits) {
490535
*/
491536
public void remainderDivide(BigNatInternal divisor, BigNatInternal quotient) {
492537
if (quotient != null) {
493-
quotient.zero();
538+
quotient.setSizeToMax(true);
494539
}
495540

496541
short divisorIndex = divisor.offset;
@@ -543,6 +588,10 @@ public void remainderDivide(BigNatInternal divisor, BigNatInternal quotient) {
543588
divisionRound++;
544589
divisorShift--;
545590
}
591+
592+
if (quotient != null) {
593+
quotient.shrink();
594+
}
546595
}
547596

548597
/**

0 commit comments

Comments
 (0)