Загрузка данных


// task5.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; }
	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;
	while (res>0){
		A->lm[i]=res%Osn;
		res/=Osn;
		i++;
	}
	A->len=i;
	if(i==0){ A->len=1; A->lm[0]=0; }
	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){
		for(i=0;i<A->len;i++){
			C->lm[i+1] = (C->lm[i]+A->lm[i]*(K>0?K:-K))/Osn;
			C->lm[i] = (C->lm[i]+A->lm[i]*(K>0?K:-K))%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(More_Shift(A,B,sp)==1) sp--;
	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;
}

// ============ ФУНКЦИИ ИЗ EllipLong.c ============

char ps[] = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f";
int a = 0;
int b = 7;
char xGs[] = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
char yGs[] = "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8";

LDig P, xG, yG, n;

void InitPar(){
	InitLong(&P);
	InitLong(&n);
	InitLong(&xG);
	InitLong(&yG);
	Read16Long(&P, ps);
	Read16Long(&n, ns);
	Read16Long(&xG, xGs);
	Read16Long(&yG, yGs);
}

// Расширенный алгоритм Евклида
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;
	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, &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);
	printf("b = %d\n\n", b);
	
	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;
}