shithub: riscv

Download patch

ref: 2fa4c8ef663d774467dbcf61222c44a8826311b9
parent: 2763229c0032c35dcd035eb7fa315c48d1c9e1ad
author: cinap_lenrek <[email protected]>
date: Wed Apr 20 16:09:59 EDT 2016

libsec: implement elliptic curve group operations in jacobian coordinate system

--- a/sys/include/ape/libsec.h
+++ b/sys/include/ape/libsec.h
@@ -497,6 +497,7 @@
 	int inf;
 	mpint *x;
 	mpint *y;
+	mpint *z;	/* nil when using affine coordinates */
 } ECpoint;
 
 typedef ECpoint ECpub;
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -489,6 +489,7 @@
 	int inf;
 	mpint *x;
 	mpint *y;
+	mpint *z;	/* nil when using affine coordinates */
 } ECpoint;
 
 typedef ECpoint ECpub;
--- a/sys/src/ape/lib/sec/port/mkfile
+++ b/sys/src/ape/lib/sec/port/mkfile
@@ -26,6 +26,7 @@
 	thumb.c readcert.c \
 	aes_xts.c  \
 	ecc.c\
+	jacobian.c\
 	ripemd.c\
 	dh.c\
 	curve25519.c\
@@ -37,7 +38,7 @@
 	secp256r1.c\
 	secp256k1.c\
 
-CLEANFILES=secp256r1.c secp256k1.c
+CLEANFILES=secp256r1.c secp256k1.c jacobian.c
 
 ALLOFILES=${CFILES:%.c=%.$O}
 
--- a/sys/src/libsec/port/ecc.c
+++ b/sys/src/libsec/port/ecc.c
@@ -3,12 +3,33 @@
 #include <libsec.h>
 #include <ctype.h>
 
+extern void jacobian_affine(mpint *p,
+	mpint *X, mpint *Y, mpint *Z);
+extern void jacobian_dbl(mpint *p, mpint *a,
+	mpint *X1, mpint *Y1, mpint *Z1,
+	mpint *X3, mpint *Y3, mpint *Z3);
+extern void jacobian_add(mpint *p, mpint *a,
+	mpint *X1, mpint *Y1, mpint *Z1,
+	mpint *X2, mpint *Y2, mpint *Z2,
+	mpint *X3, mpint *Y3, mpint *Z3);
+
 void
-ecassign(ECdomain *, ECpoint *a, ECpoint *b)
+ecassign(ECdomain *dom, ECpoint *a, ECpoint *b)
 {
-	b->inf = a->inf;
+	if((b->inf = a->inf) != 0)
+		return;
 	mpassign(a->x, b->x);
 	mpassign(a->y, b->y);
+	if(b->z != nil){
+		mpassign(a->z != nil ? a->z : mpone, b->z);
+		return;
+	}
+	if(a->z != nil){
+		b->z = mpcopy(a->z);
+		jacobian_affine(dom->p, b->x, b->y, b->z);
+		mpfree(b->z);
+		b->z = nil;
+	}
 }
 
 void
@@ -28,10 +49,26 @@
 		ecassign(dom, a, s);
 		return;
 	}
+
+	if(s->z != nil){
+		if(a == b)
+			jacobian_dbl(dom->p, dom->a,
+				a->x, a->y, a->z != nil ? a->z : mpone,
+				s->x, s->y, s->z);
+		else
+			jacobian_add(dom->p, dom->a,
+				a->x, a->y, a->z != nil ? a->z : mpone,
+				b->x, b->y, b->z != nil ? b->z : mpone,
+				s->x, s->y, s->z);
+		s->inf = mpcmp(s->z, mpzero) == 0;
+		return;
+	}
+
 	if(mpcmp(a->x, b->x) == 0 && (mpcmp(a->y, mpzero) == 0 || mpcmp(a->y, b->y) != 0)){
 		s->inf = 1;
 		return;
 	}
+	s->inf = 0;
 	l = mpnew(0);
 	k = mpnew(0);
 	sx = mpnew(0);
@@ -103,8 +140,10 @@
 	ns.inf = 1;
 	ns.x = mpnew(0);
 	ns.y = mpnew(0);
+	ns.z = mpnew(0);
 	na.x = mpnew(0);
 	na.y = mpnew(0);
+	na.z = mpnew(0);
 	ecassign(dom, a, &na);
 	l = mpcopy(k);
 	l->sign = 1;
@@ -114,7 +153,7 @@
 		ecadd(dom, &na, &na, &na);
 		mpright(l, 1, l);
 	}
-	if(k->sign < 0){
+	if(k->sign < 0 && !ns.inf){
 		ns.y->sign = -1;
 		mpmod(ns.y, dom->p, ns.y);
 	}
@@ -121,8 +160,10 @@
 	ecassign(dom, &ns, s);
 	mpfree(ns.x);
 	mpfree(ns.y);
+	mpfree(ns.z);
 	mpfree(na.x);
 	mpfree(na.y);
+	mpfree(na.z);
 	mpfree(l);
 }
 
@@ -132,18 +173,17 @@
 	mpint *p, *q;
 	int r;
 
+	assert(a->z == nil);	/* need affine coordinates */
 	if(a->inf)
 		return 1;
-	
+
 	p = mpnew(0);
 	q = mpnew(0);
-	mpmul(a->y, a->y, p);
-	mpmod(p, dom->p, p);
-	mpmul(a->x, a->x, q);
-	mpadd(q, dom->a, q);
-	mpmul(a->x, q, q);
-	mpadd(q, dom->b, q);
-	mpmod(q, dom->p, q);
+	mpmodmul(a->y, a->y, dom->p, p);
+	mpmodmul(a->x, a->x, dom->p, q);
+	mpmodadd(q, dom->a, dom->p, q);
+	mpmodmul(q, a->x, dom->p, q);
+	mpmodadd(q, dom->b, dom->p, q);
 	r = mpcmp(p, q);
 	mpfree(p);
 	mpfree(q);
@@ -162,10 +202,12 @@
 		return 0;
 	p.x = mpnew(0);
 	p.y = mpnew(0);
+	p.z = mpnew(0);
 	ecmul(dom, a, dom->n, &p);
 	r = p.inf;
 	mpfree(p.x);
 	mpfree(p.y);
+	mpfree(p.z);
 	return r;
 }
 
@@ -272,8 +314,8 @@
 	zq = mpnew(0);
 	for(;;){
 		for(;;){
-			mprand(mpsignif(p), genrandom, a);
-			if(mpcmp(a, mpzero) > 0 && mpcmp(a, p) < 0)
+			mpnrand(p, genrandom, a);
+			if(mpcmp(a, mpzero) > 0)
 				break;
 		}
 		mpmul(a, a, t);
@@ -345,11 +387,12 @@
 		ret->x = mpnew(0);
 		ret->y = mpnew(0);
 	}
+	ret->inf = 0;
 	o = 0;
 	switch(octet(&s)){
 	case 0:
 		ret->inf = 1;
-		return ret;
+		break;
 	case 3:
 		o = 1;
 	case 2:
@@ -370,7 +413,7 @@
 		mpfree(r);
 		if(!ecverify(dom, ret))
 			goto err;
-		return ret;
+		break;
 	case 4:
 		if(halfpt(dom, s, &s, ret->x) == nil)
 			goto err;
@@ -378,8 +421,12 @@
 			goto err;
 		if(!ecverify(dom, ret))
 			goto err;
-		return ret;
+		break;
 	}
+	if(ret->z != nil && !ret->inf)
+		mpassign(mpone, ret->z);
+	return ret;
+
 err:
 	if(rptr)
 		*rptr = s;
@@ -403,8 +450,8 @@
 		p->d = mpnew(0);
 	}
 	for(;;){
-		mprand(mpsignif(dom->n), genrandom, p->d);
-		if(mpcmp(p->d, mpzero) > 0 && mpcmp(p->d, dom->n) < 0)
+		mpnrand(dom->n, genrandom, p->d);
+		if(mpcmp(p->d, mpzero) > 0)
 			break;
 	}
 	ecmul(dom, &dom->G, p->d, p);
@@ -419,6 +466,7 @@
 
 	tmp.x = mpnew(0);
 	tmp.y = mpnew(0);
+	tmp.z = nil;
 	tmp.d = mpnew(0);
 	E = betomp(dig, len, nil);
 	t = mpnew(0);
@@ -432,8 +480,7 @@
 		mpmul(r, priv->d, s);
 		mpadd(E, s, s);
 		mpinvert(tmp.d, dom->n, t);
-		mpmul(s, t, s);
-		mpmod(s, dom->n, s);
+		mpmodmul(s, t, dom->n, s);
 		if(mpcmp(s, mpzero) != 0)
 			break;
 	}
@@ -461,18 +508,19 @@
 	u2 = mpnew(0);
 	R.x = mpnew(0);
 	R.y = mpnew(0);
+	R.z = mpnew(0);
 	S.x = mpnew(0);
 	S.y = mpnew(0);
+	S.z = mpnew(0);
 	mpinvert(s, dom->n, t);
-	mpmul(E, t, u1);
-	mpmod(u1, dom->n, u1);
-	mpmul(r, t, u2);
-	mpmod(u2, dom->n, u2);
+	mpmodmul(E, t, dom->n, u1);
+	mpmodmul(r, t, dom->n, u2);
 	ecmul(dom, &dom->G, u1, &R);
 	ecmul(dom, pub, u2, &S);
 	ecadd(dom, &R, &S, &R);
 	ret = 0;
 	if(!R.inf){
+		jacobian_affine(dom->p, R.x, R.y, R.z);
 		mpmod(R.x, dom->n, t);
 		ret = mpcmp(r, t) == 0;
 	}
@@ -482,8 +530,10 @@
 	mpfree(u2);
 	mpfree(R.x);
 	mpfree(R.y);
+	mpfree(R.z);
 	mpfree(S.x);
 	mpfree(S.y);
+	mpfree(S.z);
 	return ret;
 }
 
--- /dev/null
+++ b/sys/src/libsec/port/jacobian.mp
@@ -1,0 +1,60 @@
+# Elliptic curve group operations in jacobian coordinates:
+#	x=X/Z^2
+#	x=Y/Z^3
+
+jacobian_new(x,y,z, X,Y,Z) {
+	X = x;
+	Y = y;
+	Z = z;
+}
+jacobian_inf(X,Y,Z) {
+	X,Y,Z = jacobian_new(0,1,0);
+}
+jacobian_affine(p, X,Y,Z) mod(p) {
+	if(Z != 0) {
+		ZZ = Z^2;
+		ZZZ = ZZ*Z;
+		X = X / ZZ;
+		Y = Y / ZZZ;
+		Z = 1;
+	}
+}
+jacobian_dbl(p,a, X1,Y1,Z1, X3,Y3,Z3) mod(p) {
+	if(Y1 == 0) {
+		X3,Y3,Z3 = jacobian_inf();
+	} else {
+		XX = X1^2;
+		YY = Y1^2;
+		YYYY = YY^2;
+		ZZ = Z1^2;
+		S = 2*((X1+YY)^2-XX-YYYY);
+		M = 3*XX+a*ZZ^2;
+		Z3 = (Y1+Z1)^2-YY-ZZ;	
+		X3 = M^2-2*S;
+		Y3 = M*(S-X3)-8*YYYY;
+	}
+}
+jacobian_add(p,a, X1,Y1,Z1, X2,Y2,Z2, X3,Y3,Z3) mod(p) {
+	Z1Z1 = Z1^2;
+	Z2Z2 = Z2^2;
+	U1 = X1*Z2Z2;
+	U2 = X2*Z1Z1;
+	S1 = Y1*Z2*Z2Z2;
+	S2 = Y2*Z1*Z1Z1;
+	if(U1 == U2) {
+		if(S1 != S2) {
+			X3,Y3,Z3 = jacobian_inf();
+		} else {
+			X3,Y3,Z3 = jacobian_dbl(p,a, X1,Y1,Z1);
+		}
+	} else {
+		H = U2-U1;
+		I = (2*H)^2;
+		J = H*I;
+		r = 2*(S2-S1);
+		V = U1*I;
+		X3 = r^2-J-2*V;
+		Y3 = r*(V-X3)-2*S1*J;
+		Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H;
+	}
+}
--- a/sys/src/libsec/port/mkfile
+++ b/sys/src/libsec/port/mkfile
@@ -22,6 +22,7 @@
 	tlshand.c thumb.c readcert.c \
 	aes_xts.c  \
 	ecc.c\
+	jacobian.c\
 	ripemd.c\
 	dh.c\
 	curve25519.c\
@@ -33,7 +34,7 @@
 	secp256r1.c\
 	secp256k1.c\
 
-CLEANFILES=secp256r1.c secp256k1.c
+CLEANFILES=secp256r1.c secp256k1.c jacobian.c
 
 ALLOFILES=${CFILES:%.c=%.$O}