$ a="486662"; b="1"; p="57896044618658097711785492504343953926634992332820282019728792003956564819949" $ x="9"; y="43114425171068552920764898935933967039370386198203806730763910166200978582548" $ ./ec.out "$a" "$b" "$p" "$x" "$y" 1*(y^2) = x^3 + 486662*(x^2) + x (mod 57896044618658097711785492504343953926634992332820282019728792003956564819949) 25401056036235045220436215630227531782477232918721757282083167532085 * P(x, y) = (9, 43114425171068552920764898935933967039370386198203806730763910166200978582548) = Q(x, y) = (2152181765955508802144811366391548358206596269149408838626058763387933371482, 11578758651574146923540708489424215527254544219548915855368449621649032022464) $ ./ec.out "$a" "$b" "$p" "$x" "$y" 1*(y^2) = x^3 + 486662*(x^2) + x (mod 57896044618658097711785492504343953926634992332820282019728792003956564819949) 14923829837058818803507170043209691418601607100463140519943405743260 * P(x, y) = (9, 43114425171068552920764898935933967039370386198203806730763910166200978582548) = Q(x, y) = (10616717952671290844210554362351196131260739681824015303968067548318407877443, 44474405861832920486283648404346377112839096552743000067399554821542048806382) $ x="10616717952671290844210554362351196131260739681824015303968067548318407877443"; y="44474405861832920486283648404346377112839096552743000067399554821542048806382" $ ./ec.out "$a" "$b" "$p" "$x" "$y" "25401056036235045220436215630227531782477232918721757282083167532085" 1*(y^2) = x^3 + 486662*(x^2) + x (mod 57896044618658097711785492504343953926634992332820282019728792003956564819949) 25401056036235045220436215630227531782477232918721757282083167532085 * P(x, y) = (10616717952671290844210554362351196131260739681824015303968067548318407877443, 44474405861832920486283648404346377112839096552743000067399554821542048806382) = Q(x, y) = (5796465362698668629448044005371479448781495853974848652041497206752313461872, 30198337259834952114045673142150509214022566212693868468740722556827195886413) $ x="2152181765955508802144811366391548358206596269149408838626058763387933371482"; y="11578758651574146923540708489424215527254544219548915855368449621649032022464" $ ./ec.out "$a" "$b" "$p" "$x" "$y" "14923829837058818803507170043209691418601607100463140519943405743260" 1*(y^2) = x^3 + 486662*(x^2) + x (mod 57896044618658097711785492504343953926634992332820282019728792003956564819949) 14923829837058818803507170043209691418601607100463140519943405743260 * P(x, y) = (2152181765955508802144811366391548358206596269149408838626058763387933371482, 11578758651574146923540708489424215527254544219548915855368449621649032022464) = Q(x, y) = (5796465362698668629448044005371479448781495853974848652041497206752313461872, 30198337259834952114045673142150509214022566212693868468740722556827195886413) $
#include "bn.c" struct ecurve { bnum *a, *b, *p, *x, *y; }; #define ecc struct ecurve struct ectemp { bnum *i, *s, *xr, *yr; bnum *t, *u, *v; bnum *w, *h, *g; }; #define ect struct ectemp ecc *ecinit(bnum *a, bnum *b, bnum *p, bnum *x, bnum *y) { ecc *r = malloc(1 * sizeof(ecc)); r->a = a; r->b = b; r->p = p; r->x = x; r->y = y; return r; } ecc *ecdup(ecc *e) { ecc *r = malloc(1 * sizeof(ecc)); r->a = bndup(e->a); r->b = bndup(e->b); r->p = bndup(e->p); r->x = bndup(e->x); r->y = bndup(e->y); return r; } void ecfree(ecc *e) { bnfree(e->a); bnfree(e->b); bnfree(e->p); bnfree(e->x); bnfree(e->y); free(e); } void ecout(int d, char *s, ecc *e, char *t) { char *a = bnstr(e->a), *b = bnstr(e->b), *p = bnstr(e->p); char *x = bnstr(e->x), *y = bnstr(e->y); char as[2], bs[2]; as[0] = '+'; as[1] = '\0'; bs[0] = '\0'; bs[1] = '\0'; if ((e->a)->sign == 1) { as[0] = '-'; } if ((e->b)->sign == 1) { bs[0] = '-'; } if (d == 1) { printf(" %s%s*(y^2) = x^3 %s %s*(x^2) + x (mod %s)\n", bs, b, as, a, p); } printf("%s", s); printf("(x, y) = (%s, %s)", x, y); printf("%s", t); free(a); free(b); free(p); free(x); free(y); } ect *etinit(ecc *e) { ect *t = malloc(1 * sizeof(ect)); int ss = max(1, (e->b)->size); ss = max(((e->a)->size * 2) + 2, ((e->p)->size * 2) + 2); ss = max(((e->x)->size * 2) + 2, ((e->y)->size * 2) + 2); t->i = bninit(ss); t->s = bninit(ss); t->xr = bninit(ss); t->yr = bninit(ss); t->t = bninit(ss); t->u = bninit(ss); t->v = bninit(ss); int tt = ((ss * 2) + 2); t->w = bninit(tt); t->h = bninit(tt); t->g = bninit(tt + 4); return t; } void etfree(ect *t) { bnfree(t->i); bnfree(t->s); bnfree(t->xr); bnfree(t->yr); bnfree(t->t); bnfree(t->u); bnfree(t->v); bnfree(t->w); bnfree(t->h); bnfree(t->g); free(t); } // modular multiplicative inverse void egcd(bnum *a, bnum *b, bnum *g) { int size = ((a->size + b->size) * 3); // s = 0; news = 1 bnum *s = bninit(size); bnum *news = bninit(size); news->nums[0] = 1; // r = b; newr = a bnum *r = bninit(size); bncopy(b, r); bnum *newr = bninit(size); bncopy(a, newr); // init some temp vars bnum *prev = bninit(size), *quot = bninit(size), *temp = bninit(size); while ((r->leng > 1) || (r->nums[0] > 0)) { // quot = (newr / r) if ((r->leng == 1) && (r->nums[0] < 3)) { bncopy(newr, quot); if (r->nums[0] > 1) { bnrshift(quot, 1); } } else { bndiv(newr, r, quot, temp); } // prev = s bncopy(s, prev); // s = (news - (quot * prev)) bnzero(temp); bnmul(quot, prev, temp); bnsub(news, temp, s, 0); // news = prev bncopy(prev, news); // prev = r bncopy(r, prev); // r = (newr - (quot * prev)) bnzero(temp); bnmul(quot, prev, temp); bnsub(newr, temp, r, 0); // newr = prev bncopy(prev, newr); } if (news->sign == 1) { // news = news + b bnadd(news, b, news, 0); } bncopy(news, g); bnfree(s); bnfree(news); bnfree(r); bnfree(newr); bnfree(prev); bnfree(quot); bnfree(temp); } // modular square root int sqrtmod(bnum *a, bnum *p, bnum *r) { bnum *o = bninit(1); o->nums[0] = 1; o->leng = 1; o->sign = 0; // legendre symbol // define if a is a quadratic residue modulo odd prime // g = (p - 1) / 2 // p - 1 bnum *qq = bndup(p); bnsub(qq, o, qq, 1); // (p - 1) / 2 bnum *g = bndup(qq); bnrshift(g, 1); // l = pow(a, g, p) // pow(a, g, p) bnum *l = bninit(max(max(a->size, g->size), p->size) * 3); bnpowmod(a, g, p, l); if (bncmp(l, qq) == 0) { bnfree(o); bnfree(qq); bnfree(g); bnfree(l); return -1; } // factor p - 1 on the form q * (2 ^ s) (with Q odd) // q = p - 1; s = 0 bnum *q = bndup(qq); bnum *s = bninit(p->size); while ((q->nums[0] % 2) == 0) { // s += 1; q /= 2 bnadd(s, o, s, 1); bnrshift(q, 1); } // select a z which is a quadratic non resudue modulo p // z = 1 bnum *z = bninit(p->size); z->nums[0] = 1; z->leng = 1; z->sign = 0; while (1) { // while (lsym(z, p) != -1) bnpowmod(z, g, p, l); if (bncmp(l, qq) == 0) { break; } // z += 1 bnadd(z, o, z, 1); } // c = pow(z, q, p) bnum *c = bninit(max(max(z->size, q->size), p->size) * 3); bnpowmod(z, q, p, c); // search for a solution // f = ((q + 1) / 2) bnum *f = bndup(q); bnadd(f, o, f, 1); bnrshift(f, 1); // x = pow(a, f, p) bnpowmod(a, f, p, r); // t = pow(a, q, p) bnum *t = bninit(max(max(a->size, q->size), p->size) * 3); bnpowmod(a, q, p, t); // m = s bnum *m = bninit(p->size), *i = bninit(p->size), *e = bninit(p->size); bncopy(s, m); // u = 2 bnum *u = bninit(1); u->nums[0] = 2; u->leng = 1; u->sign = 0; bnum *b = bninit(p->size * 4), *v = bninit(p->size * 4), *w = bninit(p->size * 4); while ((t->leng > 1) || (t->nums[0] != 1)) { // find the lowest i such that t ^ (2 ^ i) = 1 // i = 1; e = 2 i->nums[0] = 1; i->leng = 1; i->sign = 0; e->nums[0] = 2; e->leng = 1; e->sign = 0; while (bncmp(i, m) < 0) { bnpowmod(t, e, p, l); if ((l->leng == 1) && (l->nums[0] == 1)) { break; } bnlshift(e, 1); bnadd(i, o, i, 1); } // update next value to iterate // (m - i - 1) bnsub(m, i, v, 0); bnsub(v, o, v, 0); // 2 ^ (m - i - 1) bnpowmod(u, v, p, l); // b = (c ^ (2 ^ (m - i - 1))) % p bnpowmod(c, l, p, b); // x = ((x * b) % p) bnzero(v); bnmul(r, b, v); bndiv(v, p, w, r); // b = (b * b) % p bnzero(v); bnmul(b, b, v); bndiv(v, p, w, b); // t = ((t * b) % p) bnzero(v); bnmul(t, b, v); bndiv(v, p, w, t); // c = b; m = i bncopy(b, c); bncopy(i, m); } bnfree(o); bnfree(qq); bnfree(g); bnfree(l); bnfree(q); bnfree(s); bnfree(z); bnfree(c); bnfree(f); bnfree(t); bnfree(m); bnfree(i); bnfree(e); bnfree(b); bnfree(u); bnfree(v); bnfree(w); // r = [x, p - x] return 0; } // montgomery curve arithmetic void nmod(bnum *a, bnum *b) { if (a->sign == 1) { bnadd(b, a, a, 0); } } void pdub(ecc *p, ecc *r, ect *t) { // printf("2P=\n"); // l = 3*x^2 + 2*a*x + 1 / 2*b*y // x^2 bnzero(t->w); bnmul(p->x, p->x, t->w); bndiv(t->w, p->p, t->t, t->v); // 3*x^2 bnadd(t->v, t->v, t->w, 1); bnadd(t->w, t->v, t->w, 1); // 2*a*x bnzero(t->h); bnmul(p->a, p->x, t->h); bnlshift(t->h, 1); bndiv(t->h, p->p, t->t, t->u); nmod(t->u, p->p); // 3*x^2 + 2*a*x + 1 bnadd(t->w, t->u, t->g, 1); int x, o = 1; for (x = 0; (x < (t->g)->leng) && (o == 1); ++x) { o = 0; if ((t->g)->nums[x] == 0xffffffff) { o = 1; } (t->g)->nums[x] += 1; } if (o == 1) { (t->g)->nums[x] = 1; (t->g)->leng += 1; } bndiv(t->g, p->p, t->t, t->yr); // 1 / 2*b*y bnzero(t->w); bnmul(p->b, p->y, t->w); bnlshift(t->w, 1); bndiv(t->w, p->p, t->t, t->u); nmod(t->u, p->p); egcd(t->u, p->p, t->i); // 3*x^2 + 2*a*x + 1 / 2*b*y bnzero(t->w); bnmul(t->yr, t->i, t->w); bndiv(t->w, p->p, t->t, t->s); // xr = b*l^2 - a - 2*x // l^2 bnzero(t->g); bnmul(t->s, t->s, t->g); // b*l^2 - a bnzero(t->w); bnmul(p->b, t->g, t->w); bnsub(t->w, p->a, t->w, 0); // 2*x bnzero(t->h); bncopy(p->x, t->h); bnlshift(t->h, 1); // b*l^2 - a - 2*x bnsub(t->w, t->h, t->w, 0); bndiv(t->w, p->p, t->t, t->xr); nmod(t->xr, p->p); // yr = ((3*x + a) * l) - b*l^3 - y // (3*x + a) * l bnadd(t->h, p->x, t->w, 1); bnadd(t->w, p->a, t->w, 0); bndiv(t->w, p->p, t->t, t->u); nmod(t->u, p->p); bnzero(t->w); bnmul(t->u, t->s, t->w); // l^3 bncopy(t->g, t->h); bnzero(t->g); bnmul(t->h, t->s, t->g); bndiv(t->g, p->p, t->t, t->u); // b*l^3 bnzero(t->h); bnmul(p->b, t->u, t->h); bndiv(t->h, p->p, t->t, t->u); nmod(t->u, p->p); // ((3*x + a) * l) - b*l^3 - y bnsub(t->w, t->u, t->w, 0); bnsub(t->w, p->y, t->w, 0); bndiv(t->w, p->p, t->t, t->yr); nmod(t->yr, p->p); (t->xr)->leng = (p->p)->size; bncopy(t->xr, r->x); (t->yr)->leng = (p->p)->size; bncopy(t->yr, r->y); } void padd(ecc *p, ecc *q, ecc *r, ect *t) { // printf("P+Q=\n"); // l = (Qy - Py) / (Qx - Px) // Qy - Py bnsub(q->y, p->y, t->yr, 0); // Qx - Px bnsub(q->x, p->x, t->xr, 0); bndiv(t->xr, p->p, t->t, t->u); nmod(t->u, p->p); // 1 / (Qx - Px) egcd(t->u, p->p, t->i); // (Qy - Py) / (Qx - Px) bnzero(t->w); bnmul(t->yr, t->i, t->w); bndiv(t->w, p->p, t->t, t->s); // xr = b*l^2 - a - Px - Qx // b*l^2 - a - Px - Qx bnzero(t->w); bnmul(t->s, t->s, t->w); bnzero(t->g); bnmul(p->b, t->w, t->g); bnsub(t->g, p->a, t->g, 0); bnsub(t->g, p->x, t->g, 0); bnsub(t->g, q->x, t->g, 0); bndiv(t->g, p->p, t->t, t->xr); nmod(t->xr, p->p); // yr = ((2*Px + Qx + a) * l) - b*l^3 - Py // 2*Px + Qx + a bnadd(p->x, p->x, t->t, 1); bnadd(t->t, q->x, t->t, 1); bnadd(t->t, p->a, t->t, 0); bndiv(t->t, p->p, t->u, t->v); nmod(t->v, p->p); // (2*Px + Qx + a) * l bnzero(t->w); bnmul(t->v, t->s, t->w); bndiv(t->w, p->p, t->t, t->u); // b*l^3 bnzero(t->w); bnmul(t->s, t->s, t->w); bnzero(t->g); bnmul(t->w, t->s, t->g); bndiv(t->g, p->p, t->t, t->v); bnzero(t->w); bnmul(t->v, p->b, t->w); // ((2*Px + Qx + a) * l) - b*l^3 - Py bnsub(t->u, t->w, t->v, 0); bnsub(t->v, p->y, t->v, 0); bndiv(t->v, p->p, t->t, t->yr); nmod(t->yr, p->p); (t->xr)->leng = (p->p)->size; bncopy(t->xr, r->x); (t->yr)->leng = (p->p)->size; bncopy(t->yr, r->y); } void pmul(bnum *m, ecc *p, ecc *r) { int init = 0; bnum *mul = bndup(m); ecc *b = ecdup(p); ect *t = etinit(p); while ((mul->leng > 1) || (mul->nums[0] > 0)) { if ((mul->nums[0] % 2) == 1) { if (init == 0) { bnfree(r->x); r->x = bndup(b->x); bnfree(r->y); r->y = bndup(b->y); } else { padd(r, b, r, t); } init = 1; } pdub(b, b, t); bnrshift(mul, 1); } bnfree(mul); ecfree(b); etfree(t); }