Skip to content

Commit 3d37139

Browse files
committed
implement true constant-time cmov() for ref10 implementation
1 parent f460205 commit 3d37139

File tree

4 files changed

+82
-11
lines changed

4 files changed

+82
-11
lines changed

src/net/i2p/crypto/eddsa/math/FieldElement.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,7 @@ public FieldElement divide(FieldElement val) {
7070

7171
public abstract FieldElement pow22523();
7272

73+
public abstract FieldElement cmov(FieldElement g, final int b);
74+
7375
// Note: concrete subclasses must implement hashCode() and equals()
7476
}

src/net/i2p/crypto/eddsa/math/GroupElement.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -811,19 +811,10 @@ static byte[] toRadix16(final byte[] a) {
811811
*
812812
* @param u The group element to return if b == 1.
813813
* @param b in {0, 1}
814-
* @return u if b == 1; this if b == 0; null otherwise.
814+
* @return u if b == 1; this if b == 0. Results undefined if b is not in {0, 1}.
815815
*/
816816
GroupElement cmov(final GroupElement u, final int b) {
817-
GroupElement ret = null;
818-
for (int i = 0; i < b; i++) {
819-
// Only for b == 1
820-
ret = u;
821-
}
822-
for (int i = 0; i < 1-b; i++) {
823-
// Only for b == 0
824-
ret = this;
825-
}
826-
return ret;
817+
return precomp(curve, X.cmov(u.X, b), Y.cmov(u.Y, b), Z.cmov(u.Z, b));
827818
}
828819

829820
/**

src/net/i2p/crypto/eddsa/math/bigint/BigIntegerFieldElement.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ public FieldElement pow22523(){
104104
return pow(f.getQm5d8());
105105
}
106106

107+
@Override
108+
public FieldElement cmov(FieldElement g, int b) {
109+
// Not constant-time, but it doesn't really matter because none of the underlying BigInteger operations
110+
// are either, so there's not much point in trying hard here ...
111+
return b == 0 ? this : g;
112+
}
113+
107114
@Override
108115
public int hashCode() {
109116
return bi.hashCode();

src/net/i2p/crypto/eddsa/math/ed25519/Ed25519FieldElement.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,77 @@ public FieldElement pow22523() {
942942
return multiply(t0);
943943
}
944944

945+
/**
946+
* Constant-time conditional move. Well, actually it is a conditional copy.
947+
* Logic is taken from the SUPERCOP implementation at:
948+
* https://github.com/floodyberry/supercop/blob/master/crypto_sign/ed25519/ref10/fe_cmov.c
949+
*
950+
* @param g the other field element.
951+
* @param b must be 0 or 1, otherwise results are undefined.
952+
* @return a copy of this if b == 0, or a copy of g if b == 1.
953+
*/
954+
@Override
955+
public FieldElement cmov(FieldElement g, int b) {
956+
Ed25519FieldElement that = (Ed25519FieldElement) g;
957+
// f0 ... f9 are a copy of this.t
958+
int f0 = this.t[0];
959+
int f1 = this.t[1];
960+
int f2 = this.t[2];
961+
int f3 = this.t[3];
962+
int f4 = this.t[4];
963+
int f5 = this.t[5];
964+
int f6 = this.t[6];
965+
int f7 = this.t[7];
966+
int f8 = this.t[8];
967+
int f9 = this.t[9];
968+
// g0 ... g9 are a copy of that.t
969+
int g0 = that.t[0];
970+
int g1 = that.t[1];
971+
int g2 = that.t[2];
972+
int g3 = that.t[3];
973+
int g4 = that.t[4];
974+
int g5 = that.t[5];
975+
int g6 = that.t[6];
976+
int g7 = that.t[7];
977+
int g8 = that.t[8];
978+
int g9 = that.t[9];
979+
// x0 ... x9 are XORs of this.t and that.t
980+
int x0 = f0 ^ g0;
981+
int x1 = f1 ^ g1;
982+
int x2 = f2 ^ g2;
983+
int x3 = f3 ^ g3;
984+
int x4 = f4 ^ g4;
985+
int x5 = f5 ^ g5;
986+
int x6 = f6 ^ g6;
987+
int x7 = f7 ^ g7;
988+
int x8 = f8 ^ g8;
989+
int x9 = f9 ^ g9;
990+
b = -b;
991+
// turn x0 ... x9 into 0s if b is 0, otherwise keep unchanged
992+
x0 &= b;
993+
x1 &= b;
994+
x2 &= b;
995+
x3 &= b;
996+
x4 &= b;
997+
x5 &= b;
998+
x6 &= b;
999+
x7 &= b;
1000+
x8 &= b;
1001+
x9 &= b;
1002+
// turn f0 ... f9 into a copy of this.t if b is 0, or a copy of that.t if b is 1
1003+
f0 ^= x0;
1004+
f1 ^= x1;
1005+
f2 ^= x2;
1006+
f3 ^= x3;
1007+
f4 ^= x4;
1008+
f5 ^= x5;
1009+
f6 ^= x6;
1010+
f7 ^= x7;
1011+
f8 ^= x8;
1012+
f9 ^= x9;
1013+
return new Ed25519FieldElement(f, new int[]{ f0, f1, f2, f3, f4, f5, f6, f7, f8, f9});
1014+
}
1015+
9451016
@Override
9461017
public int hashCode() {
9471018
return Arrays.hashCode(t);

0 commit comments

Comments
 (0)