Загрузка данных
// task5_fixed.c - Сложение точек G + P на эллиптической кривой secp256k1
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define MaxDig 1000
#define Osn 0x100
#define mm 8
typedef struct{
int lm[MaxDig];
int len;
int sign;
} LDig;
// ============ ФУНКЦИИ ИЗ larif16-2.c ============
void InitLong(LDig *A){
int i;
for (i=0; i<MaxDig; i++) A->lm[i]=0;
A->len=1;
A->sign=1;
}
void Read16Long(LDig *A, char *S){
char chs[3];
int i,len, b[100],ch,k=0;
if (S[0]=='-'){
A->sign = -1;
k=1;
} else {
A->sign = 1;
}
strcpy(chs,"");
len = strlen(S);
A->len = len/2;
for (i=k;i<len;i+=2){
chs[0]=S[i];
chs[1]=S[i+1];
chs[2]='\0';
sscanf(chs,"%02x",&ch);
b[i/2]=ch;
}
for(i=0; i<A->len;i++)
A->lm[A->len-1-i]=b[i];
}
void Write16Long(LDig *A, char *S){
char s[10];
int i;
if (A->sign<0) strcpy(S,"-");
else strcpy(S,"");
for (i=A->len-1;i>=0;i--){
sprintf(s,"%02x", A->lm[i]);
strcat(S,s);
}
}
void ShowLongS(LDig *A){
char S[256];
Write16Long(A, S);
printf("%s\n",S);
}
int IsNulLong(LDig *A){
return ((A->len==1) && (A->lm[0]==0));
}
void DigToArray(int k, LDig *A){
int res, i=0, sign=1;
if (k<0) sign=-1;
res = (k<0) ? -k : k;
if (res == 0) {
A->len=1;
A->lm[0]=0;
A->sign=1;
return;
}
while (res>0){
A->lm[i]=res%Osn;
res/=Osn;
i++;
}
A->len=i;
A->sign=sign;
}
int Eq(LDig *A, LDig *B){
int i;
if((A->len!=B->len)||(A->sign!=B->sign)) return 0;
for(i=0;i<A->len;i++)
if(A->lm[i]!=B->lm[i]) return 0;
return 1;
}
int More(LDig *A, LDig *B){
int i;
if(A->len > B->len) return 1;
if(A->len < B->len) return 0;
for(i=A->len-1;i>=0;i--){
if(A->lm[i] > B->lm[i]) return 1;
if(A->lm[i] < B->lm[i]) return 0;
}
return 0;
}
int More_Shift(LDig *A, LDig *B, int sp){
int i;
if(A->len > B->len+sp) return 0;
if(A->len < B->len+sp) return 1;
for(i=A->len-1;i>=sp;i--){
if(A->lm[i] > B->lm[i-sp]) return 0;
if(A->lm[i] < B->lm[i-sp]) return 1;
}
for(i=0;i<sp;i++)
if(A->lm[i]>0) return 0;
return 2;
}
void Sum_Shift(LDig *A, LDig *B, int sp){
int i,k;
if(A->len > B->len+sp) k=A->len;
else k=B->len+sp;
for(i=0;i<k;i++){
A->lm[i+sp+1] += (A->lm[i+sp]+B->lm[i])/Osn;
A->lm[i+sp] = (A->lm[i+sp]+B->lm[i])%Osn;
}
if(A->lm[k]==0) A->len=k;
else A->len=k+1;
}
void Sub_Shift(LDig *A, LDig *B, int sp){
int i,j;
for(i=0;i<B->len;i++){
A->lm[i+sp] -= B->lm[i];
j=i;
while((A->lm[j+sp]<0) && (j<A->len-1)){
A->lm[j+sp] += Osn;
A->lm[j+sp+1]--;
j++;
}
}
i=A->len-1;
while((i>0) && (A->lm[i]==0)) i--;
A->len=i+1;
}
void SumTwo(LDig *A, LDig *B, LDig *C){
*C = *A;
Sum_Shift(C, B, 0);
}
void SubTwo(LDig *A, LDig *B, LDig *C){
*C = *A;
Sub_Shift(C, B, 0);
}
void SumLong(LDig *A, LDig *B, LDig *C){
if(A->sign == B->sign){
SumTwo(A, B, C);
C->sign = A->sign;
} else {
if(More(A, B)){
SubTwo(A, B, C);
C->sign = A->sign;
} else {
SubTwo(B, A, C);
C->sign = B->sign;
}
}
}
void SumLongA(LDig *A, LDig *B){
LDig C;
InitLong(&C);
SumLong(A, B, &C);
*A = C;
}
void SubLong(LDig *A, LDig *B, LDig *C){
if(A->sign != B->sign){
SumTwo(A, B, C);
C->sign = A->sign;
} else {
if(More(A, B)){
SubTwo(A, B, C);
C->sign = A->sign;
} else {
SubTwo(B, A, C);
C->sign = -B->sign;
}
}
}
void Mul(LDig *A, int K, LDig *C){
int i;
InitLong(C);
if(K != 0){
int absK = (K>0) ? K : -K;
for(i=0;i<A->len;i++){
C->lm[i+1] = (C->lm[i] + A->lm[i]*absK) / Osn;
C->lm[i] = (C->lm[i] + A->lm[i]*absK) % Osn;
}
if(C->lm[A->len] > 0) C->len = A->len+1;
else C->len = A->len;
}
C->sign = A->sign * ((K>0) ? 1 : -1);
}
void MulA(LDig *A, int K){
LDig C;
InitLong(&C);
Mul(A, K, &C);
*A = C;
}
void MulTwoLong(LDig *A, LDig *B, LDig *C){
int i;
LDig C1;
InitLong(C);
for(i=0;i<B->len;i++){
Mul(A, B->lm[i], &C1);
Sum_Shift(C, &C1, i);
}
C->sign = A->sign * B->sign;
}
void LongDivLong(LDig *A, LDig *B, LDig *Res, LDig *Ost){
int sp, Down, Up, k;
LDig C;
*Ost = *A;
sp = A->len - B->len;
if(sp < 0) sp = 0;
if(More_Shift(A, B, sp) == 1) sp--;
if(sp < 0) sp = 0;
Res->len = sp+1;
while(sp >= 0){
Down = 0;
Up = Osn;
while(Up - 1 > Down){
InitLong(&C);
Mul(B, (Up+Down)/2, &C);
k = More_Shift(Ost, &C, sp);
if(k == 0) Down = (Down+Up)/2;
else if(k == 1) Up = (Up+Down)/2;
else { Up = (Up+Down)/2; Down = Up; }
}
InitLong(&C);
Mul(B, (Up+Down)/2, &C);
if(More_Shift(Ost, &C, 0) == 0)
Sub_Shift(Ost, &C, sp);
else {
Sub_Shift(&C, Ost, sp);
*Ost = C;
}
Res->lm[sp] = (Up+Down)/2;
sp--;
}
Res->sign = A->sign * B->sign;
Ost->sign = A->sign;
}
void OstLong(LDig *A, LDig *Ost, LDig *P){
LDig Res;
InitLong(&Res);
LongDivLong(A, P, &Res, Ost);
if((Ost->sign < 0) && !IsNulLong(Ost))
SumLongA(Ost, P);
}
void OstLongA(LDig *A, LDig *P){
LDig Ost;
InitLong(&Ost);
OstLong(A, &Ost, P);
*A = Ost;
}
// ============ ФУНКЦИИ ДЛЯ ЭЛЛИПТИЧЕСКОЙ КРИВОЙ ============
char ps[] = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f";
int a_coef = 0;
int b_coef = 7;
char xGs[] = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
char yGs[] = "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8";
// Расширенный алгоритм Евклида
void LongEnhEvklid(LDig *A, LDig *B, LDig *t, LDig *nod){
LDig r1, r2, t1, t2, r, q, tt, C;
InitLong(&r1); InitLong(&r2);
InitLong(&t1); InitLong(&t2);
InitLong(&q); InitLong(&r);
InitLong(&tt); InitLong(&C);
r1 = *A;
r2 = *B;
DigToArray(0, &t1);
DigToArray(1, &t2);
while(!IsNulLong(&r2)){
LongDivLong(&r1, &r2, &q, &r);
r1 = r2;
r2 = r;
MulTwoLong(&q, &t2, &C);
SubLong(&t1, &C, &tt);
t1 = t2;
t2 = tt;
}
*nod = r1;
*t = t1;
}
void invA(LDig *A, LDig *T, LDig *P){
LDig t, nod, Ed;
InitLong(&t);
InitLong(&nod);
InitLong(&Ed);
Ed.lm[0] = 1;
Ed.len = 1;
LongEnhEvklid(P, A, &t, &nod);
if(!Eq(&nod, &Ed))
printf("Ошибка: нет обратного элемента\n");
*T = t;
}
// Сложение двух точек
void AddPoint(LDig *xP, LDig *yP, LDig *xQ, LDig *yQ, LDig *xR, LDig *yR, LDig *p){
LDig m, s1, s2, C1, C2, C3;
InitLong(&m); InitLong(&s1); InitLong(&s2);
InitLong(&C1); InitLong(&C2); InitLong(&C3);
SubLong(xP, xQ, &C1);
OstLongA(&C1, p);
SubLong(yP, yQ, &C2);
OstLongA(&C2, p);
// Проверка на особые точки
if(IsNulLong(xP) && IsNulLong(yP)){
*xR = *xQ;
*yR = *yQ;
return;
}
if(IsNulLong(xQ) && IsNulLong(yQ)){
*xR = *xP;
*yR = *yP;
return;
}
if(IsNulLong(&C1) && IsNulLong(&C2)){
// Удвоение
MulTwoLong(xP, xP, &C1);
OstLongA(&C1, p);
MulA(&C1, 3);
DigToArray(a_coef, &C2);
SumLongA(&C1, &C2);
OstLong(&C1, &s1, p);
Mul(yP, 2, &C1);
OstLong(&C1, &C2, p);
invA(&C2, &s2, p);
OstLongA(&s2, p);
} else {
// Обычное сложение
OstLong(&C2, &s1, p);
OstLong(&C1, &C3, p);
invA(&C3, &s2, p);
OstLongA(&s2, p);
}
MulTwoLong(&s1, &s2, &m);
OstLongA(&m, p);
MulTwoLong(&m, &m, &C1);
OstLongA(&C1, p);
SumLong(xP, xQ, &C2);
OstLongA(&C2, p);
SubLong(&C1, &C2, xR);
OstLongA(xR, p);
SubLong(xR, xP, &C1);
OstLongA(&C1, p);
MulTwoLong(&C1, &m, &C2);
OstLongA(&C2, p);
SumLong(yP, &C2, yR);
OstLongA(yR, p);
yR->sign = -yR->sign;
OstLongA(yR, p);
}
// ============ MAIN ============
int main() {
LDig xG, yG, xP, yP, xR, yR;
LDig p_mod;
printf("=== Задание №5: Сложение точек G + P ===\n\n");
// Инициализация модуля p
InitLong(&p_mod);
Read16Long(&p_mod, ps);
// Инициализация точки G
InitLong(&xG);
InitLong(&yG);
Read16Long(&xG, xGs);
Read16Long(&yG, yGs);
// Инициализация точки P (из задания)
InitLong(&xP);
InitLong(&yP);
Read16Long(&xP, "f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9");
Read16Long(&yP, "388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672");
printf("Параметры кривой:\n");
printf("p = %s\n", ps);
printf("a = %d\n", a_coef);
printf("b = %d\n\n", b_coef);
printf("Точка G:\n");
printf("xG = "); ShowLongS(&xG);
printf("yG = "); ShowLongS(&yG);
printf("\n");
printf("Точка P:\n");
printf("xP = "); ShowLongS(&xP);
printf("yP = "); ShowLongS(&yP);
printf("\n");
// Вычисляем G + P
InitLong(&xR);
InitLong(&yR);
AddPoint(&xG, &yG, &xP, &yP, &xR, &yR, &p_mod);
printf("Результат G + P:\n");
printf("xR = "); ShowLongS(&xR);
printf("yR = "); ShowLongS(&yR);
return 0;
}