diff --git a/sys/include/ape/libsec.h b/sys/include/ape/libsec.h index 37a59c078..b4fde5256 100644 --- a/sys/include/ape/libsec.h +++ b/sys/include/ape/libsec.h @@ -497,6 +497,7 @@ typedef struct ECpoint{ int inf; mpint *x; mpint *y; + mpint *z; /* nil when using affine coordinates */ } ECpoint; typedef ECpoint ECpub; diff --git a/sys/include/libsec.h b/sys/include/libsec.h index 6cd04cdfa..ab8f579aa 100644 --- a/sys/include/libsec.h +++ b/sys/include/libsec.h @@ -489,6 +489,7 @@ typedef struct ECpoint{ int inf; mpint *x; mpint *y; + mpint *z; /* nil when using affine coordinates */ } ECpoint; typedef ECpoint ECpub; diff --git a/sys/src/ape/lib/sec/port/mkfile b/sys/src/ape/lib/sec/port/mkfile index ef8cc3942..7b19cec9b 100644 --- a/sys/src/ape/lib/sec/port/mkfile +++ b/sys/src/ape/lib/sec/port/mkfile @@ -26,6 +26,7 @@ CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\ thumb.c readcert.c \ aes_xts.c \ ecc.c\ + jacobian.c\ ripemd.c\ dh.c\ curve25519.c\ @@ -37,7 +38,7 @@ CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\ secp256r1.c\ secp256k1.c\ -CLEANFILES=secp256r1.c secp256k1.c +CLEANFILES=secp256r1.c secp256k1.c jacobian.c ALLOFILES=${CFILES:%.c=%.$O} diff --git a/sys/src/libsec/port/ecc.c b/sys/src/libsec/port/ecc.c index e4e4df0fd..33038fa24 100644 --- a/sys/src/libsec/port/ecc.c +++ b/sys/src/libsec/port/ecc.c @@ -3,12 +3,33 @@ #include #include +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 @@ ecadd(ECdomain *dom, ECpoint *a, ECpoint *b, ECpoint *s) 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 @@ ecmul(ECdomain *dom, ECpoint *a, mpint *k, ECpoint *s) 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,15 +153,17 @@ ecmul(ECdomain *dom, ECpoint *a, mpint *k, ECpoint *s) 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); } 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 @@ ecverify(ECdomain *dom, ECpoint *a) 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 @@ ecpubverify(ECdomain *dom, ECpub *a) 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 @@ mpsqrt(mpint *n, mpint *p, mpint *r) 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 @@ strtoec(ECdomain *dom, char *s, char **rptr, ECpoint *ret) 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 @@ strtoec(ECdomain *dom, char *s, char **rptr, ECpoint *ret) 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 @@ strtoec(ECdomain *dom, char *s, char **rptr, ECpoint *ret) 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 @@ ecgen(ECdomain *dom, ECpriv *p) 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 @@ ecdsasign(ECdomain *dom, ECpriv *priv, uchar *dig, int len, mpint *r, mpint *s) 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 @@ ecdsasign(ECdomain *dom, ECpriv *priv, uchar *dig, int len, mpint *r, mpint *s) 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 @@ ecdsaverify(ECdomain *dom, ECpub *pub, uchar *dig, int len, mpint *r, mpint *s) 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 @@ ecdsaverify(ECdomain *dom, ECpub *pub, uchar *dig, int len, mpint *r, mpint *s) mpfree(u2); mpfree(R.x); mpfree(R.y); + mpfree(R.z); mpfree(S.x); mpfree(S.y); + mpfree(S.z); return ret; } diff --git a/sys/src/libsec/port/jacobian.mp b/sys/src/libsec/port/jacobian.mp new file mode 100644 index 000000000..a26b65944 --- /dev/null +++ b/sys/src/libsec/port/jacobian.mp @@ -0,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; + } +} diff --git a/sys/src/libsec/port/mkfile b/sys/src/libsec/port/mkfile index 49d8c7282..53e9b9514 100644 --- a/sys/src/libsec/port/mkfile +++ b/sys/src/libsec/port/mkfile @@ -22,6 +22,7 @@ CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\ tlshand.c thumb.c readcert.c \ aes_xts.c \ ecc.c\ + jacobian.c\ ripemd.c\ dh.c\ curve25519.c\ @@ -33,7 +34,7 @@ CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\ secp256r1.c\ secp256k1.c\ -CLEANFILES=secp256r1.c secp256k1.c +CLEANFILES=secp256r1.c secp256k1.c jacobian.c ALLOFILES=${CFILES:%.c=%.$O}