Pages:
Author

Topic: Exercício pessoal: Private Keys e Addresses Bitcoin em Python - page 2. (Read 578 times)

legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Isso são cursos? Ou é apenas software?

São cursos: https://academy.zenva.com/

Acredito que vais gostar, pelo o preço pode ser útil, se estas a explorar o Python.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Para quem esta interessado em programação Python, pode ser interessante aproveitar um pack de cursos da Zenva, avaliado em 1500€, por apenas uns 30€:
https://www.humblebundle.com/software/black-friday-python-generative-ai-bundle-software

Infelizmente não é possível pagar com BTC, só PayPal ou cartão de credito.

Isso são cursos? Ou é apenas software?

Por falar nesta thread, tenho andado ainda a trabalhar nisto mas tenho tido alguns problemas... Coisas que pensava que estavam a funcionar, agora parece não estaarem a funcionar para todos os casos. Por isso, não sei como vou continuar, mas até ver ainda não desisti de todo!
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Para quem esta interessado em programação Python, pode ser interessante aproveitar um pack de cursos da Zenva, avaliado em 1500€, por apenas uns 30€:
https://www.humblebundle.com/software/black-friday-python-generative-ai-bundle-software

Infelizmente não é possível pagar com BTC, só PayPal ou cartão de credito.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
No entanto, números muito grandes vão usar mais bytes e a minha questão vem aqui:
Na imagem diz que se começa da esquerda para a direita, ignorando o primeiro número. Mas e se houver mais que uma word, é para ignorar o primeiro número de cada word ou apenas o primeiro número da primeira word? Alguém me consegue dar o vosso juízo? Se fossem vocês, como interpretavam?

Bem, eu não sou nenhum especialista em C, nem em binário. Mas, eu interpretaria como ignorando o primeiro numero referente a sintaxe, isto porque o espaço é contacto como um caractere.
Como disse, não sou especialista, então posso estar 1000% errado.

Bom, ontem em conversa com um amigo, cheguei à conclusão que é apenas o primeiro número da primeira word.
Acabámos por fazer o código em conjunto (maior parte foi ele que fez) e de uma maneira muito mais sucinta e fácil. Nem precisámos daquela função manhosa mpz_export(). Fizémos com uma outra mais simples (que eu até já tinha experimentado) e aquilo ficou muito mais intuitivo e legível que o que eu tenho. Mais daqui a bocado já posto aqui como ficou.
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
No entanto, números muito grandes vão usar mais bytes e a minha questão vem aqui:
Na imagem diz que se começa da esquerda para a direita, ignorando o primeiro número. Mas e se houver mais que uma word, é para ignorar o primeiro número de cada word ou apenas o primeiro número da primeira word? Alguém me consegue dar o vosso juízo? Se fossem vocês, como interpretavam?

Bem, eu não sou nenhum especialista em C, nem em binário. Mas, eu interpretaria como ignorando o primeiro numero referente a sintaxe, isto porque o espaço é contacto como um caractere.
Como disse, não sou especialista, então posso estar 1000% errado.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Bom, depois de uma carrada de dias a tentar perceber umas coisas sobre bits, bytes, words e etc, lá consegui dar mais um passo aqui na minha jornada.

O milestone for conseguir escrever parte da função para o algoritmo doube and add. Mas ainda só consegui fazer a conversão de um número em um conjunto de bits (0s e 1s) organizado por words.
O difícil foi mesmo perceber como raio uma word de tamanho diferente, influenciava a representação de um número na sua forma decimal. Tive também que ter em conta a endianness dos bits dentro de cada word e a ordem de cada word. Não foi fácil para mim, conseguir perceber como estes 2 parâmetros estavam a influenciar a representação binária de um número. Não vou estar com os pormenores das minhas dúvidas porque iria ser muito confuso para mim explicar, e para vocês, perceberem.

Só para que vá ficando o registo, esta é a função que ainda não está completa:
Code:
void ecdsa_doubleAdd(gmp_coord GPoint, gmp_coord* pointDouble, gmp_coord* pointAdd,
                    gmp_coord* pointDoubleAdd, mpz_t pKey, mpz_t opA, mpz_t opP){
    gmp_coord tmpGPoint;
    unsigned char* binary_array;
    size_t number_of_words = 0, number_of_bits = 0;
    int order = 1, endianness = 1;
    size_t nails = 0, word_size = 8, numb = 8 * word_size - nails;
   
    mpz_inits(tmpGPoint.x, tmpGPoint.y, NULL);
    mpz_set(tmpGPoint.x, GPoint.x);
    mpz_set(tmpGPoint.y, GPoint.y);

    number_of_bits = mpz_sizeinbase(pKey, 2);
    number_of_words = (number_of_bits + numb - 1) / numb;
    if(!(binary_array = (unsigned char*) malloc(word_size + number_of_words)))
        exit(-1);
    mpz_export(binary_array, &number_of_words, order, word_size, endianness,
                                                                nails, pKey);
    for(size_t i = 0; i < number_of_words * word_size; i++){
        for(int j = 8; j > 0; j--){
            printf("%d", (binary_array[i] >> (j - 1) & 1));
            if( ((binary_array[i] >> (j - 1)) & 1) ){ // bit == 1, double and add algo
                ecdsa_double(tmpGPoint, pointDouble, opA, opP);
                mpz_inits(tmpGPoint.x, tmpGPoint.y, NULL);
                ecdsa_add(*pointAdd, tmpGPoint, pointDoubleAdd, opA, opP);
            }else{ // If bit == 0, double algo
                ecdsa_double(tmpGPoint, pointDouble, opA, opP);
            }
        }
    }
    printf("\n");
    mpz_clears(tmpGPoint.x, tmpGPoint.y, NULL);
}

Neste momento faltam 3 coisas. Uma delas, quero a vossa ajuda, se estiverem com paciência para lerem um pouco.
No site que estou a seguir, diz o seguinte:


Na imagem, é mostrado o número 21 em representação binária e depois diz:
Começar da esquerda para a direita e ignorando o primeiro número.

Ora, para contextualizar, estando a fazer isto em C, usando a biblioteca GMP, a representação binária de um número é feita à custa de words, bytes e bits e o exemplo que é usado no site, o número 21, é só o pior dos casos porque não abrange rigorosamente nada de outros possíveis casos. Mas com números grandes, é necessário levar outras coisas em conta, como o número de words necessárias para representar um número em binário. Ora o númeor 21, seja qual for o tamanho da word que eu escolher, apenas usa uma word (99% das máquinas onde este código pode correr é 1 byte = 8 bits). Conseguimos escrever pelo menos at 256. Portanto, 1 word é sempre suficiente.

Só para terem noção do que eu tive que fazer para perceber isto, cheguei a fazer isto no Calc (equivalente do Excel no Linux) para perceber a diferença de uma word de 1 byte e uma word de 8 bytes e como os bits lá ficam armazenados dentro:


No entanto, números muito grandes vão usar mais bytes e a minha questão vem aqui:
Na imagem diz que se começa da esquerda para a direita, ignorando o primeiro número. Mas e se houver mais que uma word, é para ignorar o primeiro número de cada word ou apenas o primeiro número da primeira word? Alguém me consegue dar o vosso juízo? Se fossem vocês, como interpretavam?
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
O que não falta lá são comentários. Repara bem que quase todas as linhas de código têm comentários, ou antes ou no final da linha de códig. Os comments em C podem ser feitos com /* comment */ ou com // Comment.

Tens razão, estão lá... Desculpa, não reparei.  Lips sealed

Sem duvida, é bom usar comentários quando se escreve algum código, por mais simples que seja.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Só uma sugestão: Cria comentários no código, a indicar o que cada passo/função esta a realizar.

Isso agora é tudo bonito porque esta a mexer nisso todos os dias. Se por acaso, ficares umas semanas sem mexeres nisso, quando voltas a olhar para o código, já não tem lembras o que cada coisa faz e tens de rever novamente.

Eu já cometi esse "erro", não documentar e depois é tudo mais trabalhoso.

O que não falta lá são comentários. Repara bem que quase todas as linhas de código têm comentários, ou antes ou no final da linha de códig. Os comments em C podem ser feitos com /* comment */ ou com // Comment.

E sim, eu sei perfeitamente o que isso é. Voltar a um code e nao ter coentátrios. Obriga basicamente a rever o código todo!
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Só uma sugestão: Cria comentários no código, a indicar o que cada passo/função esta a realizar.

Isso agora é tudo bonito porque esta a mexer nisso todos os dias. Se por acaso, ficares umas semanas sem mexeres nisso, quando voltas a olhar para o código, já não tem lembras o que cada coisa faz e tens de rever novamente.

Eu já cometi esse "erro", não documentar e depois é tudo mais trabalhoso.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
E mais um passo concluído...

Já tenho a função para a operação Add() a funcionar. Mais uma vez deixo aqui o código para me ir servindo quase como que um snapshot do que vou fazendo. Amanhã talvez não pegue nisto porque vou ter uma brincadeira de amigos e sou capaz de não chegar a casa direito. heheh

O próximo passo é uma função Multiply() que vai usar estas duas Double() e Add().

Code:
#include
#include
#include

typedef struct{
    mpz_t x;
    mpz_t y;
}gmp_coord;

void ecdsa_double(gmp_coord point, gmp_coord* newPoint,
                                    mpz_t opa, mpz_t opP){
    mpz_t opPow, opSum, opMult, opInv, opSlope, opSub;
    mpz_t tmp, tmp1, tmp2, tmp3;
    mpz_inits(opPow, opSum, opMult, opInv, opSlope, opSub, NULL);
    mpz_inits(tmp, tmp1, tmp2, tmp3, NULL);

    // Compute the operations needed in the numerator of (3X² + a) / (2Y)
    mpz_pow_ui(opPow, point.x, 2); // X²
    mpz_set_ui(tmp, 3);
    mpz_mul(opMult, opPow, tmp); // 3X²
    mpz_add(opSum, opMult, opa); // 3X² + a
    // Compute the operations needed in the denominator of (3X² + a) / (2Y)
    mpz_set_ui(tmp1, 2);
    mpz_mul(tmp2, point.y, tmp1); // 2Y
    mpz_invert(opInv, tmp2, opP); // 1/(2Y)
    // Compute the operation needed in the equation (3X² + a) / (2Y)
    mpz_mul(tmp3, opSum, opInv); // (3X² + a) / (2Y)
    // Compute the operation ((3X² + a) / (2Y)) % p
    mpz_mod(opSlope, tmp3, opP);

    // Compute the new X coord of the doubled point
    mpz_inits(opPow, opMult, NULL);
    mpz_pow_ui(opPow, opSlope, 2); // opSlope²   
    mpz_mul(opMult, point.x, tmp1); // 2X
    mpz_sub(opSub, opPow, opMult); // opSlope² - 2x
    mpz_mod(newPoint->x, opSub, opP); // (opSlope² - 2x) % p
       
    // Compute the new Y coord of the doubled point
    mpz_inits(opSub, opMult, tmp, NULL);
    mpz_sub(opSub, point.x, newPoint->x); // (x - X)
    mpz_mul(opMult, opSlope, opSub); // opSlope(x - X)
    mpz_sub(tmp, opMult, point.y); // opSlope(x - X) - y
    mpz_mod(newPoint->y, tmp, opP); // (opSlope(x - X) - y) % p

    mpz_clears(opPow, opSum, opMult, opInv, opSlope, opSub, NULL);
    mpz_clears(tmp, tmp1, tmp2, tmp3, NULL);
}

int ecdsa_add(gmp_coord pointa, gmp_coord pointb, gmp_coord* newPoint,
                                                            mpz_t opA, mpz_t opP){
    mpz_t opSlope, opSub, opSub1, opInv, opPow, opMult;
    mpz_inits(opSlope, opSub, opSub1, opInv, opPow, opMult, NULL);

    if(!(mpz_cmp(pointa.x, pointb.x) && mpz_cmp(pointa.y,  pointb.y))){
        ecdsa_double(pointa, newPoint, opA, opP);
    }else{
        // Computation of opSlope = (y - Y) / (x - X)
        mpz_sub(opSub, pointa.y, pointb.y); // (y - Y)
        mpz_sub(opSub1, pointa.x, pointb.x); // (x - X)
        mpz_invert(opInv, opSub1, opP); // 1 / (x - X)
        mpz_mul(opMult, opSub, opInv); // (y - Y) * (1 / (x - X))
        mpz_mod(opSlope, opMult, opP); // (y - Y) * (1 / (x - X)) % p

        // Computation of nX = opSlope² - x - X
        mpz_inits(opPow, opSub, opSub1, NULL);
        mpz_pow_ui(opPow, opSlope, 2); // opSlope²
        mpz_sub(opSub, opPow, pointa.x); // opSlope² - x
        mpz_sub(opSub1, opSub, pointb.x); // (opSlope² - x) - X
        mpz_mod(newPoint->x, opSub1, opP);// ((opSlope² - x) - X) % p
   
        // Computation of nY = opSlope(x - nX) - Y
        mpz_inits(opSub, opMult, opSub1, NULL);
        mpz_sub(opSub, pointa.x, newPoint->x); // (x - nX)
        mpz_mul(opMult, opSlope, opSub); // opSlope(x - nX)
        mpz_sub(opSub1, opMult, pointa.y); // opSlope(x - nX) - Y
        mpz_mod(newPoint->y, opSub1, opP);// (opSlope(x - nX) - Y) % p
    }
    mpz_clears(opSlope, opSub, opSub1, opInv, opPow, opMult, NULL);
    return 0;
}

int main(void){
    mpz_t a, b, n, P;
    gmp_coord G, pointP, doubleP, pointQ;
    gmp_coord pointAdd;

    mpz_inits(a, b, n, P, G.x, G.y, NULL);
    mpz_inits(pointP.x, pointP.y, doubleP.x, doubleP.y, pointQ.x, pointQ.y, pointAdd.x, pointAdd.y, NULL);
   
    mpz_set_str(a, "0000000000000000000000000000000000000000000000000000000000000000", 16);
    mpz_set_str(b, "0000000000000000000000000000000000000000000000000000000000000007", 16);
    mpz_set_str(n, "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16);
    // mpz_set_str(P, "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc2f", 16);
    mpz_set_str(P, "61", 16);
    mpz_set_str(G.x, "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16);
    mpz_set_str(G.y, "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16);
    mpz_set_str(pointP.x, "3d", 16); // 61
    mpz_set_str(pointP.y, "45", 16); // 69
    mpz_set_str(pointQ.x, "15", 16); // 15
    mpz_set_str(pointQ.y, "1b", 16); // 27

    ecdsa_double(pointP, &doubleP, a, P);
    gmp_printf("2P.x: 0x%Zx =-= 2P.y: 0x%Zx\n", doubleP.x, doubleP.y);
    gmp_printf("2P.x: %Zd =-= 2P.y: %Zd\n", doubleP.x, doubleP.y);

    ecdsa_add(pointP, pointQ, &pointAdd, a, P);
    gmp_printf("(P + Q).x: %Zd =-= (P + Q).y: %Zd\n", pointAdd.x, pointAdd.y);
    mpz_clears(a, b, n, P, G.x, G.y, pointP.x, pointP.y, doubleP.x, doubleP.y, pointQ.x, pointQ.y, pointAdd.x, pointAdd.y, NULL);
    return 0;
}
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Ora, mais um passo concluído com sucesso.

Hoje, como precisava de começar a pensar em criar funções em vez de ter o código todoe esparrachado na função main(), porque ia precisar para a função doubleAdd(), comecei a reescrever o código mas para usar funções e enviar parâmetros para essas funções, e então já escrevi a função double() e fiz algumas alterações aos nomes das funções para serem mais genéricos e mais intuitivos.

Fiquei surpreendido comigo próprio porque só tive que perseguir 2 bugs e os resultados apareceram correctos.

Aqui fica o code para referência e para partilhar a minha jornada!

Code:
#include
#include

typedef struct{
    mpz_t x;
    mpz_t y;
}gmp_coord;

void ecdsa_double(gmp_coord point, mpz_t opa, mpz_t opP, gmp_coord* newPoint){
    mpz_t opPow, opSum, opMult, opInv, opSlope, opSub;
    mpz_t tmp, tmp1, tmp2, tmp3;
    mpz_inits(opPow, opSum, opMult, opInv, opSlope, opSub, NULL);
    mpz_inits(tmp, tmp1, tmp2, tmp3, NULL);

    // Compute the operations needed in the numerator of (3X² + a) / (2Y)
    mpz_pow_ui(opPow, point.x, 2); // X²
    mpz_set_ui(tmp, 3);
    mpz_mul(opMult, opPow, tmp); // 3X²
    mpz_add(opSum, opMult, opa); // 3X² + a
    // Compute the operations needed in the denominator of (3X² + a) / (2Y)
    mpz_set_ui(tmp1, 2);
    mpz_mul(tmp2, point.y, tmp1); // 2Y
    mpz_invert(opInv, tmp2, opP); // 1/(2Y)
    // Compute the operation needed in the equation (3X² + a) / (2Y)
    mpz_mul(tmp3, opSum, opInv); // (3X² + a) / (2Y)
    // Compute the operation ((3X² + a) / (2Y)) % p
    mpz_mod(opSlope, tmp3, opP);

    // Compute the new X coord of the doubled point
    mpz_inits(opPow, opMult, NULL);
    mpz_pow_ui(opPow, opSlope, 2); // opSlope²   
    mpz_mul(opMult, point.x, tmp1); // 2X
    mpz_sub(opSub, opPow, opMult); // opSlope² - 2x
    mpz_mod(newPoint->x, opSub, opP); // (opSlope² - 2x) % p
       
    // Compute the new Y coord of the doubled point
    mpz_inits(opSub, opMult, tmp, NULL);
    mpz_sub(opSub, point.x, newPoint->x); // (x - X)
    mpz_mul(opMult, opSlope, opSub); // opSlope(x - X)
    mpz_sub(tmp, opMult, point.y); // opSlope(x - X) - y
    mpz_mod(newPoint->y, tmp, opP); // (opSlope(x - X) - y) % p

    mpz_clears(opPow, opSum, opMult, opInv, opSlope, opSub, NULL);
    mpz_clears(tmp, tmp1, tmp2, tmp3, NULL);
}

int main(void){
    mpz_t a, b, n, P;
    gmp_coord G, pointP, doubleP;

    mpz_inits(a, b, n, P, G.x, G.y, pointP.x, pointP.y, doubleP.x, doubleP.y, NULL);

    // mpz_set_str(a, "0000000000000000000000000000000000000000000000000000000000000000", 16);
    mpz_set_str(a, "0000000000000000000000000000000000000000000000000000000000000000", 16);
    mpz_set_str(b, "0000000000000000000000000000000000000000000000000000000000000007", 16);
    mpz_set_str(n, "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16);
    // mpz_set_str(P, "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc2f", 16);
    mpz_set_str(P, "61", 16);
    mpz_set_str(G.x, "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16);
    mpz_set_str(G.y, "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16);
    mpz_set_str(pointP.x, "3d", 16);
    mpz_set_str(pointP.y, "45", 16);
    ecdsa_double(pointP, a, P, &doubleP);
    // gmp_printf("2P.x: 0x%Zx =-= 2P.y: 0x%Zx\n", doubleP.x, doubleP.y);
    gmp_printf("2P.x: %Zd =-= 2P.y: %Zd\n", doubleP.x, doubleP.y);
    mpz_clears(a, b, n, P, G.x, G.y, pointP.x, pointP.y, doubleP.x, doubleP.y, NULL);
    return 0;
}

Para já ainda não estou a usar os valores dos parâmetros da curva secp256k1, mas mesmo com valores pequenos, os resultados coincidem com os do script Ruby do site learnmeabitcoin.com
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Bom, parece que estou no bom caminho.

Já consigo obter os mesmos resultados para as operações de Mod_Inv() e Double() que oo script Ruby do site do learnmeabitcoin.

Aqui fica o script Ruby:
Code:
$a = 0
$b = 7

# prime field
$p = 97

def inverse(a, m = $p)
  m_orig = m         # store original modulus
  a = a % m if a < 0 # make sure a is positive
  prevy, y = 0, 1
  while a > 1
    q = m / a
    y, prevy = prevy - q * y, y
    a, m = m % a, a
  end
  return y % m_orig
end

def double(point)
  # slope = (3x₁² + a) / 2y₁
  slope = ((3 * point[:x] ** 2 + $a) * inverse((2 * point[:y]), $p)) % $p # using inverse to help with division

  # x = slope² - 2x₁
  x = (slope ** 2 - (2 * point[:x])) % $p

  # y = slope * (x₁ - x) - y₁
  y = (slope * (point[:x] - x) - point[:y]) % $p

  # Return the new point
  return { x: x, y: y }
end

point = {
x: 61,
  y: 69
}

puts double(point)

e o meu super code em C a devolver as mesmas coordenadas:
(não se assustem)
(há algumas linhas que são comments e outras tantas com printfs para ajudar ao debugging)
Code:
#include
#include

int main(void){
    mpz_t a, b, p, Px, Py, /*Qx, Qy,*/ Rx, Ry;
    mpz_t mult0, pow, tri, add;
    mpz_t slope, inv, mod, mult1, doub;
    mpz_t tmp, tmp1, tmp2, tmp3;
    mpz_t sub, sub1;

    mpz_inits(a, b, p, Px, Py, /*Qx, Qy,*/ Rx, Ry, NULL);
    mpz_inits(pow, tri, mult0, add, NULL);
    mpz_inits(slope, inv, mod, mult1, doub, NULL);
    mpz_inits(tmp, tmp1, tmp2, tmp3, NULL);
    mpz_inits(sub, sub1, NULL);

    mpz_set_ui(a, 0);
    mpz_set_ui(b, 7);
    mpz_set_ui(p, 97);
    mpz_set_ui(Px, 61);
    mpz_set_ui(Py, 69);
    // mpz_set_ui(Qx, 53);
    // mpz_set_ui(Qy, 38);
    mpz_set_ui(doub, 2);
    mpz_set_ui(tri, 3);
   
    // Operations to compute s = (3x^2 + a) / 2*y
    // Compute each of the 3 operations of the left term
    // X²
    mpz_pow_ui(pow, Px, 2);
    gmp_printf("X²: %Zd\n", pow);
    // 3*X²
    mpz_mul(mult0, pow, tri);
    gmp_printf("3X²: %Zd\n", mult0);
    // 3X²+a
    mpz_add(add, mult0, a);
    gmp_printf("3X² + a: %Zd\n", add);

    /*=========================================*/
    // Compute the 2 operations of the right term
    // 2*Y
    mpz_mul(mult1, Py, doub);
    gmp_printf("2Y: %Zd\n", mult1);
    // 1/(2*Y) or (2*Y)-¹
    mpz_invert(inv, mult1, p);
    gmp_printf("1/(2Y): %Zd\n", inv);

    // Compute the multiplication of the top term
    // and the inverse of the bottom term
    // (3*X² + a) * (1 / 2*Y)
    mpz_mul(tmp, add, inv);
    gmp_printf("(3X² + a) * (1/(2Y)): %Zd\n", tmp);
   
    // Compute the above MOD p
    // ((3*X² + a) * (2*Y)-¹) % p , finite field
    mpz_mod(slope, tmp, p);
    gmp_printf("(3X² + a) * (1/(2Y)) %% p: %Zd\n", slope);

    // Compute new x coord
    mpz_inits(tmp, tmp1, tmp2, NULL);
    mpz_mul(tmp, Px, doub);
    mpz_init(pow);
    mpz_pow_ui(pow, slope, 2);
    mpz_sub(tmp1, pow, tmp);
    mpz_mod(Rx, tmp1, p);

    // Compute new y coord
    mpz_inits(tmp, tmp1, tmp2, NULL);
    mpz_sub(tmp, Px, Rx);
    mpz_mul(tmp1, slope, tmp);
    mpz_sub(tmp2, tmp1, Py);
    mpz_mod(Ry, tmp2, p);
   
    gmp_printf("X coord: %Zd -=- Y coord: %Zd\n", Rx, Ry);

    mpz_clears(a, b, p, Px, Py, /*Qx, Qy,*/ Rx, Ry, NULL);
    mpz_clears(pow, mult0, tri, add, NULL);
    mpz_clears(slope, inv, mod, mult1, doub, NULL);
    mpz_clears(tmp, tmp1, tmp2, tmp3, NULL);
    mpz_clears(sub, sub1, NULL);
    return 0;
}
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Há alguém entendido em Ruby que me possa ajudar a executar a seguinte função, para eu ver que resultados ela cuta fora e comparar com o meu código?

Code:
def double(point)
  # slope = (3x₁² + a) / 2y₁
  slope = ((3 * point[:x] ** 2 + $a) * inverse((2 * point[:y]), $p)) % $p # using inverse to help with division

  # x = slope² - 2x₁
  x = (slope ** 2 - (2 * point[:x])) % $p

  # y = slope * (x₁ - x) - y₁
  y = (slope * (point[:x] - x) - point[:y]) % $p

  # Return the new point
  return { x: x, y: y }
end

Não sei como usar esta função e mostrar os valores de X e Y.

Queria comparar com o código que tenho em C que é o seguinte:
Code:
#include
#include

int main(void){
    mpz_t a, b, p, Px, Py, /*Qx, Qy,*/ Rx, Ry;
    mpz_t mult0, pow, tri, add;
    mpz_t slope, inv, mod, mult1, doub;
    mpz_t tmp, tmp1, tmp2, tmp3;
    mpz_t sub, sub1;

    mpz_inits(a, b, p, Px, Py, /*Qx, Qy,*/ Rx, Ry, NULL);
    mpz_inits(pow, tri, mult0, add, NULL);
    mpz_inits(slope, inv, mod, mult1, doub, NULL);
    mpz_inits(tmp, tmp1, tmp2, tmp3, NULL);
    mpz_inits(sub, sub1, NULL);

    mpz_set_ui(a, 0);
    mpz_set_ui(b, 7);
    mpz_set_ui(p, 97);
    mpz_set_ui(Px, 61);
    mpz_set_ui(Py, 69);
    // mpz_set_ui(Qx, 53);
    // mpz_set_ui(Qy, 38);
    mpz_set_ui(doub, 2);
    mpz_set_ui(tri, 3);
   
    // Operations to compute s = (3x^2 + a) / 2*y
    // Compute each of the 3 operations of the upper term
    mpz_pow_ui(pow, Px, 2);
    mpz_mul(mult0, pow, tri);
    mpz_add(add, mult0, a);

    // Compute the 2 operation of the below term
    mpz_mul(mult1, Py, doub);
    mpz_invert(inv, mult1, p);

    // Compute the multiplication of the 2 above terms
    mpz_mul(tmp, add, inv);

    // Compute the integer division (remainder) of the above result
    mpz_tdiv_r(slope, add, inv);

    // Compute new x coord
    mpz_init(tmp);
    mpz_mul(tmp, Px, doub);
    mpz_init(pow);
    mpz_pow_ui(pow, slope, 2);
    mpz_sub(tmp1, pow, tmp);
    mpz_tdiv_r(Rx, tmp1, p);

    // Compute new y coord
    mpz_inits(tmp, tmp1, NULL);
    mpz_sub(tmp, Px, Rx);
    mpz_mul(tmp1, slope, tmp);
    mpz_sub(tmp2, tmp1, Py);
    mpz_tdiv_r(Ry, tmp2, p);
   
    gmp_printf("X coord: %Zd -=- Y coord: %Zd\n", Rx, Ry);

    mpz_clears(a, b, p, Px, Py, /*Qx, Qy,*/ Rx, Ry, NULL);
    mpz_clears(pow, mult0, tri, add, NULL);
    mpz_clears(slope, inv, mod, mult1, doub, NULL);
    mpz_clears(tmp, tmp1, tmp2, tmp3, NULL);
    mpz_clears(sub, sub1, NULL);
    return 0;
}

Isto parece ridículo mas não sei se haverá forma mais simples de usar esta biblioteca!
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Mais um pequeno garnde avanço.
Enquanto vagueava pela documentação desta livraria que me foi aconselhada para trabalhar com números muito grande, vejo que já tem algumas operações matemáticas que necessito implementadas de raíz, como o móulo inverso. Acabei de testar um pequeno código e obtive o resultado esperado:

Code:
#include
#include

int main(void){
    mpz_t a, b, res;
    mpz_inits(a, b, res, NULL);

    mpz_set_ui(a, 13);
    mpz_set_ui(b, 47);

    mpz_invert(res, a, b);

    gmp_printf("The Inverse of %Zd of %Zd is %Zd\n", a, b, res);
    mpz_clears(a, b, res, NULL);
    return 0;
}

O resultado esperado é 29 e foi o que obtive!  Smiley

Agora vou testar se uma outra função executa a operação doubleAdd() necessária nas curvas elípticas, mas esta já não estou tão confiante porque esta já envolve coordenadas de dois pontos! Vamos ver!

A função em questão é:
Quote

Function: void mpz_addmul (mpz_t rop, const mpz_t op1, const mpz_t op2)
Function: void mpz_addmul_ui (mpz_t rop, const mpz_t op1, unsigned long int op2)

    Set rop to rop + op1 times op2.

Acham que dá para adaptar e usar esta built-in function para calcular o doubleAdd em curvas elípticas que está definido assim em Ruby:
Code:
def double(point)
  # slope = (3x₁² + a) / 2y₁
  slope = ((3 * point[:x] ** 2 + $a) * inverse((2 * point[:y]), $p)) % $p # using inverse to help with division

  # x = slope² - 2x₁
  x = (slope ** 2 - (2 * point[:x])) % $p

  # y = slope * (x₁ - x) - y₁
  y = (slope * (point[:x] - x) - point[:y]) % $p

  # Return the new point
  return { x: x, y: y }
end

em que o inverse() é a função que acabei de conseguir usar da livraria GMP.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Alguém aqui programa em C ou nem por isso? Preciso de ajuda.

Tenho este código para lidar com números muito grandes onde uso a livraria GMP para executar as operações necessárias. No entanto, o output do programa é zero  e ainda não descobri porquê!

Ainda ando pelo site a tentar encontrar como executar operações depois de usar a funcção mpz_set_str() mas ainda não econtrei nada que me respondesse à minha questão!

Code:
#include
#include

int main (void){
    mpz_t a, b, P, G, res;

    mpz_init(a);
    mpz_init(b);
    mpz_init(P);
    mpz_init(G);
    mpz_init(res);

    mpz_set_ui(a, 0x0000000000000000000000000000000000000000000000000000000000000000);
    mpz_set_ui(b, 0x0000000000000000000000000000000000000000000000000000000000000007);
    mpz_set_str(P, "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc2f", 16);
    mpz_set_str(G, "0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16);
    mpz_add(res, P, G);

    printf("GMP version: %d\n", __GNU_MP_RELEASE);
    gmp_printf("P + G = %Zd\n", res);
    return 0;
}



Edited;
ok, já percebi.

Nas variáveis que usei a função mpz_set_str() não posso incluir o 0x porque são caractéres inválidos neste contexto, fazendo que só seja considerado o zero de cada variável e portanto, 0 + 0, dá 0...

Edited 2;
Ou aliás, posso usar o 0x, mas tenho que usar base 0 na função. Sendo assim, a função usa o prefixo para identificar o formato do número.

Portanto, assim também funciona:
Code:
#include
#include

int main (void){
    mpz_t a, b, P, G, res;

    mpz_init(a);
    mpz_init(b);
    mpz_init(P);
    mpz_init(G);
    mpz_init(res);

    mpz_set_ui(a, 0x0000000000000000000000000000000000000000000000000000000000000000);
    mpz_set_ui(b, 0x0000000000000000000000000000000000000000000000000000000000000007);
    mpz_set_str(P, "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc2f", 0);
    mpz_set_str(G, "0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 0);
    mpz_add(res, P, G);

    printf("GMP version: %d\n", __GNU_MP_RELEASE);
    gmp_printf("P + G = %Zd\n", res);
    return 0;
}
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Bom, acho que acabei de chegar a um dos meus milestones para esta thread.

A primeira operação necessária é a Modular Inverse. Através de exemplos que vi pela net, acabei por fazer duas versões, uma em Python com a ajuda do chatGPT e outra em C com a ajuda do site GeeksforGeeks e fiz umas ligeiras alterações. É possível que depois, quando tiver as 3 operações prontas, possa ainda alterar para remover printfs que não são necessários!

Por curiosidade, aqui ficam os codes:

Python3
Code:
def extended_gcd(a, b):
    if a == 0:
        return (b, 0, 1)
    else:
        gcd, x, y = extended_gcd(b % a, a)
        return (gcd, y - (b // a) * x, x)

def mod_inverse(a, m):
    # Find the modular inverse of a modulo m using extended Euclidean algorithm
    gcd, x, y = extended_gcd(a, m)
    if gcd != 1:
        raise ValueError("Modular inverse does not exist")
    else:
        return x % m

# Example usage
a = 13
m = 47

# Calculate the modular inverse of 'a' modulo 'm'
inverse = mod_inverse(a, m)

print(f"The modular inverse of {a} modulo {m} is {inverse}")

e uma versão C que para além dos printfs que mencionei em cima, pode ainda ser necessário alterar alguns tipos de dados, quando trabalhar com números da magnitude dos de Bitcoin:
Code:
#include
#include
#include

int32_t ext_gcd(int32_t a, int32_t b,
                 int32_t* x, int32_t* y){
    int32_t gcd = 0;
    if(!a){
        *x = 0, *y = 1;
        return b;
    }
    int32_t x1 = 0, y1 = 0;
    gcd = ext_gcd(b % a, a, &x1, &y1);
    *x = y1 - (b / a) * x1;
    *y = x1;
    return gcd;
}

int32_t modInverse(int32_t a, int32_t m){
    int32_t x = 0, y = 0, gcd = 0, res = 0;
    
    gcd = ext_gcd(a, m, &x, &y);

    if(gcd != 1)
        return 0;
    else
        res = (x % m + m) % m;
    return res;
}


int main(int argc, char** argv){
    int32_t a = 0, b = 0;
    int32_t res = 0;

    if(argc < 3)
        return -1;

    a = atoi(argv[1]), b = atoi(argv[2]);
    res = modInverse(a, b);
    if(!res)
        printf("Modular Inverse not possible!\n");
    else
        printf("Modular Inverse of %d mod %d is %d\n", a, b, res);
    return 0;
}
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Ohh, sim. Mas isso é bonito para os primeiros 0.2% do que há para aprender sobre cada uma delas. Primeiro que consigas chegar a um ponto onde já tenhas conhecimentos e experiência para fazer coisas mais interessantes, como participar em projectos no github ou gitlab, já não é assim tão fácil.


Eu diria o oposto.

A diferença está mais no começo , basicamente na sintaxes.

Todo o mindset é o mesmo, que é a parte mais importante.

Por exemplo, se você já sabe python e for fazer um código em javascript,  você terá mais dificuldade no  comeco.
Vai ver diferenças nos ident (aqueles espaços obrigatórios no python) que não tem em javascript.  Vai ver diferenças na forma de definir uma variável.

Por exemplo

Python
Code:
x = 5

Javascript
Code:
var x = 5;

Ou então if e else e loops

Python


Javascript



Aqui tem um guia de similaridades e diferenca
https://www.freecodecamp.org/news/python-vs-javascript-what-are-the-key-differences-between-the-two-popular-programming-languages/


Na verdade  o que muda são mais detalhes na sintaxes.  Acostumando c isso, ficam bem próximas.

Eu não consigo achar isso assim, porque, tanto a indentação como os parêntesis ou os ":" são comuns a praticamente qualquer linguagem de programação. Então, quando tu mudas de uma para outra, já sabes que vais encontrar esses detalhes, portanto já não é uma novidade.
Agora, quanto às variáveis, sim, tive alguma dificuldade em assimilar qu python não precisava de especificar o tipo de dados e que também TUDO é um objecto. Em C, temos que ter controlo sobre tudo, mas mesmo tudo!
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Mas ainda assim, que uma pessoa conheça 60% de uma linguagem de programação e que consiga participar em alguns projectos ou mesmo iniciar um projecto, já tem que ter bastante experiência nessa área. Eu pelo menos tenho essa percepção. Pode estar errada, mas é a que tenho!

Bem, mas isso é valido para quase todo o tipo de trabalho. A teoria é muito bonito, mas é a pratica que vai permitir a pessoa ganhar experiencia e crescer em conhecimento.
Uma coisa que tive sempre a noção é que a pessoa aprende mais no "terreno" do que na "sala de aula".

Então, para a pessoa ganhar experiencia tem de ir para o terreno. Procura começar a participar em projetos novos e pequenos. Começa por coisas simples, como por exemplo a tradução, o layout e outras coisas que podem ser uteis para o projeto, mas não requerem muita experiencia. Depois, se realmente investires tempo nisso, vais começar a ir mais além.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Ohh, sim. Mas isso é bonito para os primeiros 0.2% do que há para aprender sobre cada uma delas. Primeiro que consigas chegar a um ponto onde já tenhas conhecimentos e experiência para fazer coisas mais interessantes, como participar em projectos no github ou gitlab, já não é assim tão fácil.

Mas a maioria não conhece essas linguagens todas de forma 100%.

Eu não sou nenhum especialista em programações, tenho só umas ideias muito básicas. Mas, uma coisa que percebi ao longo destes anos, é que um programador que tenha um bom conhecimento numa determinada linguagem, e tenha um bom conhecimento de "Logica de Programação", facilmente entra noutras linguagens e consegue fazer coisas interessantes.

Depois ter um conhecimento mais profundo ou não, vai depender do interesse e no envolvimento que se tiver com esse código.

Ou seja, o que o Bitmover quis dizer é que se tiveres conhecimento de como funciona um determinada linguagem de programação, mas facilmente vais entender o que outra semelhante quer dizer/funciona. Não significa que viras especialistas, mas quando olhas para o código, não fiques sem perceber nada.


Sim, eu não digo a 100%. Claro que não deve haver ninguém assim, até porque as linguagens cobrem toda uma vasta panóplia de temas que me parece impossível que uma única pessoa conseguisse absorver tanto conhecimento. Para além disso as pessoas acabam por se especializar em apenas uma ou duas temáticas de cada vez, dependendo do que estão a fazer naquele momento.

Mas ainda assim, que uma pessoa conheça 60% de uma linguagem de programação e que consiga participar em alguns projectos ou mesmo iniciar um projecto, já tem que ter bastante experiência nessa área. Eu pelo menos tenho essa percepção. Pode estar errada, mas é a que tenho!
legendary
Activity: 2212
Merit: 5622
Non-custodial BTC Wallet
Ohh, sim. Mas isso é bonito para os primeiros 0.2% do que há para aprender sobre cada uma delas. Primeiro que consigas chegar a um ponto onde já tenhas conhecimentos e experiência para fazer coisas mais interessantes, como participar em projectos no github ou gitlab, já não é assim tão fácil.


Eu diria o oposto.

A diferença está mais no começo , basicamente na sintaxes.

Todo o mindset é o mesmo, que é a parte mais importante.

Por exemplo, se você já sabe python e for fazer um código em javascript,  você terá mais dificuldade no  comeco.
Vai ver diferenças nos ident (aqueles espaços obrigatórios no python) que não tem em javascript.  Vai ver diferenças na forma de definir uma variável.

Por exemplo

Python
Code:
x = 5

Javascript
Code:
var x = 5;

Ou então if e else e loops

Python


Javascript



Aqui tem um guia de similaridades e diferenca
https://www.freecodecamp.org/news/python-vs-javascript-what-are-the-key-differences-between-the-two-popular-programming-languages/


Na verdade  o que muda são mais detalhes na sintaxes.  Acostumando c isso, ficam bem próximas.
Pages:
Jump to: