Author

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

hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Bom, acho que para já, a chave pública e a privada estão correctas, a versão compressed e a versão uncompressed.

O resultado é este:
Code:
$ bin/./btctest
PrivKey = 0x832e693326d86f401e7a007c0b7b4309956ba7663bc2b31f86cb1e98b55ab72a
PubKey Q[x, y] = privKey * [G.x, G.y]
PubKey ==> Q.x = 0xe336cc45635afd8b2b3c1ae6b4a0f578f3d3b88c5cef2869b7a39c8a07efd961
PubKey ==> Q.y = 0xafa74f4d4d08842460c02671533033c4ac33a6c456b0be444924dfa3bcc5d3b5
Compressed Public Key: 0x03e336cc45635afd8b2b3c1ae6b4a0f578f3d3b88c5cef2869b7a39c8a07efd961
Uncompressed Public Key: 0x04e336cc45635afd8b2b3c1ae6b4a0f578f3d3b88c5cef2869b7a39c8a07efd961afa74f4d4d08842460c02671533033c4ac33a6c456b0be444924dfa3bcc5d3b5

O código continua no mesmo local para quem tiver curiosidade:
https://gitlab.com/PsySc0rpi0n/bitcoinexp
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Edited;
Aina falta uma pequena parte que quero cumprir que é formatar a Public Key da forma correcta como é feito em Bitcoin. Por isso, pelo menos mais esse passo quero concretizar. Depois posso continuar a adicionar "cenas" ou ar por concluída esta pequena aventura!

Só deves dar por concluída, quando gerares um endereço Bitcoin de forma viável. Se depois será segura ou não, será outra conversa.  Cheesy

Parabéns pelo projeto e progresso.

Estou a tratar disso mesmo agora. Só que ao juntar o código, deparo-me agora com erros na compilação que não consigo perceber! Estou a pedir ajuda noutros locais para ver se me conseguem ajudar!
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Edited;
Aina falta uma pequena parte que quero cumprir que é formatar a Public Key da forma correcta como é feito em Bitcoin. Por isso, pelo menos mais esse passo quero concretizar. Depois posso continuar a adicionar "cenas" ou ar por concluída esta pequena aventura!

Só deves dar por concluída, quando gerares um endereço Bitcoin de forma viável. Se depois será segura ou não, será outra conversa.  Cheesy

Parabéns pelo projeto e progresso.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Quero deixar aqui mais um update.

Finalmente conseguir juntar tudo e gerar a Private Key e a Public Key mas ainda numa forma que não é utilizável em Bitcoin. Isto porque a Pub Key não é mais que a Private Key multiplicada, normalmente, por um starting point chamado o ponto G (não transpôr isto para o campo sexual, seus malvados heheh).

Ou seja, sendoeste starting point, um ponto de coordenadas X e Y, denominado por G.x e G.y, a Public Key é um ponto Q de coordenadas X' e Y' tal que Q = G*privKey. Ou um pouco mais extenso: Q[x, y] = G[x, y] * privKey. Foi a este ponto que cheguei, embora ainda não tenha comparado os resultados para ter a certeza absoluta que obtenho os mesmos resultados, mas ter chegado aqui já foi bom.

Fica aqui o repositório onde tenho estado a guardar os meus avanços (e recuos):

https://gitlab.com/PsySc0rpi0n/bitcoinexp

Não tenho lá instrucções de como usar, mas basicamente é instalar a biblioteca libgmp10-dev no linux, claro, clonar o repositório e correr o típico make. Depois o binário estará na pasta bin.

Atenção que a private key gerada não tem a complexidade nem em termos de captação de dados aleatórios nem de entropia suficientes para competir com a que é gerada pela wallet do Bitcoin core. Portanto, não usem nada disto, até porque eu nunca testei se mesmo que as coisas fossem feitas de forma segura, se funcionariam no contexto de Bitcoin. Isso ainda estará para ser testado.

Edited;
Aina falta uma pequena parte que quero cumprir que é formatar a Public Key da forma correcta como é feito em Bitcoin. Por isso, pelo menos mais esse passo quero concretizar. Depois posso continuar a adicionar "cenas" ou ar por concluída esta pequena aventura!
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Bom, já consegui uma parte!
Os meus printfs é que estavam a estragar a coisa. Após ter pedido ajuda a alguém mais experiente, consegui resolver o problema e até já consigo ter o número aleatório no formato da biblioteca GMP. Agora preciso de fazer com que este número aleatório cumpra um requisito ou dois e já o poderei usar no resto do programa!

Para já está assim:
Code:
#include 
#include
#include
#include
#include
#include

int main(void) {
    uint8_t bytes = ceil(log2(pow(2, 256) - 1) + 1) / 8;
    // uint8_t bytes = 2;
    FILE* fpointer = NULL;
    unsigned char* data = NULL;
    mpz_t imp_val;

    mpz_init(imp_val);

    if( (data = (unsigned char*) malloc(bytes)) == NULL) {
        printf("Memory error!\n");
        exit(-1);
    }

    printf("bytes: %d\n", bytes);

    if( (fpointer = fopen("/dev/urandom", "rb")) == NULL )
        return -1;

    fread(data, bytes, 1, fpointer);

    printf("0x");
    for(uint8_t i = 0; i < bytes; i++){
        printf("%02hhx", data[i]);
    }
    printf("\n");
    mpz_import(imp_val, 1, 1, 32, 1, 0, data);
    gmp_printf("0x%Zx\n", imp_val);
    mpz_clear(imp_val);
    free(data);
    fclose(fpointer);
    return 0;
}

hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Bom, depois de pesquisar mais um pouco, gerar números aleatórios também parece ter muito que se lhe diga. E acho que vou continuar com um número aleatório básico sem grandes mecanismos para o tornar num número aleatório extremamente bom, nem que não seja só para conseguir continuar este pequeno projecto que não vai servir para nada!

Se calhar estas a diminuir esse teu projeto e a ter uma visão muito limitadora do que podes fazer com ele.
É verdade que começas-te o projeto, para gerar endereços Bitcoin, mas podes vir a usar para outras coisas.

Eu não sei se gostas de geradores automáticos de passwords. Mas, podes evoluir esse teu projeto, para teres uma ferramenta própria e construída por ti, para gerar as tuas passwords.


EDIT:
Se alguém souber ajudar, era fixe, para eu conseguir continuar! É que quando imprimo cada byte, no loop for, de vez em quando aparecem-me os quantos "fffff" que não percebo de onde vêm!

Já pensas-te que isso podem ser números em formato hexidecimal?
https://www.numberplanet.com/number/fffffffe/index.html
https://www.numberplanet.com/number/ffffffd6/index.html
etc...

Sim, claro, posso usar para outras coisas, mas só depois de ter a certeza que está a funcionar como é suposto.
Aqueles fffff não são supostos ali estarem de certeza. Sei que há aqui malta que de certeza percebe porque é que aquilo está a acontecer, mas se calhar não lhes apetece estarem a meter-se nisto. lol

Tenho pedido também ajuda noutros locais, mas está complicado!

O resultado devia ser 32 conjuntos de 2 caractéres alfanuméricos, tipo:
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Bom, depois de pesquisar mais um pouco, gerar números aleatórios também parece ter muito que se lhe diga. E acho que vou continuar com um número aleatório básico sem grandes mecanismos para o tornar num número aleatório extremamente bom, nem que não seja só para conseguir continuar este pequeno projecto que não vai servir para nada!

Se calhar estas a diminuir esse teu projeto e a ter uma visão muito limitadora do que podes fazer com ele.
É verdade que começas-te o projeto, para gerar endereços Bitcoin, mas podes vir a usar para outras coisas.

Eu não sei se gostas de geradores automáticos de passwords. Mas, podes evoluir esse teu projeto, para teres uma ferramenta própria e construída por ti, para gerar as tuas passwords.


EDIT:
Se alguém souber ajudar, era fixe, para eu conseguir continuar! É que quando imprimo cada byte, no loop for, de vez em quando aparecem-me os quantos "fffff" que não percebo de onde vêm!

Já pensas-te que isso podem ser números em formato hexidecimal?
https://www.numberplanet.com/number/fffffffe/index.html
https://www.numberplanet.com/number/ffffffd6/index.html
etc...
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Bom, depois de pesquisar mais um pouco, gerar números aleatórios também parece ter muito que se lhe diga. E acho que vou continuar com um número aleatório básico sem grandes mecanismos para o tornar num número aleatório extremamente bom, nem que não seja só para conseguir continuar este pequeno projecto que não vai servir para nada!

Para gerar um número aleatório para Bitcoin, sabemos que ele tem que ter 32 bytes. E com 32 bytes, conseguimos gerar 2^256 - 1 número aleatórios, certo?

O que fiz em código foi usar o device "/dev/urandom" como fonte para o meu número aleatório e depois usar uma função da GMP library para transformar este array de 32 bytes de dados num número no seu formato binário, mas acho que não está a funcionar!

O código que tenho é este:
Code:
#include 
#include
#include
#include
#include
#include

int main(void) {
    uint8_t bytes = ceil(log2(pow(2, 256) - 1) + 1) / 8;
    FILE* fpointer = NULL;
    char* data = NULL;
    mpz_t imp_val;

    mpz_init(imp_val);

    if( (data = (char*) malloc(bytes)) == NULL) {
        printf("Memory error!\n");
        exit(-1);
    }

    printf("bytes: %d\n", bytes);

    if( (fpointer = fopen("/dev/urandom", "rb")) == NULL )
        return -1;
    // rewind(fpointer);

    for(uint8_t i = 0; i < bytes; i++){
        fread(&data[i], 1, 1, fpointer);
        printf("%x", data[i]);
    }
    printf("\n");
    printf("Len: %ld\n", strlen(data));
    printf("Sizeof: %lu\n", sizeof(data[0]));
    mpz_import(imp_val, 32, 1, sizeof(data[0]), 0, 0, data);
    gmp_printf("Data: %Zb\n", imp_val);
    mpz_clear(imp_val);
    free(data);
    fclose(fpointer);
    return 0;
}

Se alguém souber ajudar, era fixe, para eu conseguir continuar! É que quando imprimo cada byte, no loop for, de vez em quando aparecem-me os quantos "fffff" que não percebo de onde vêm!
Code:
$ ./randoma
bytes: 32
07 4b fffffffe ffffffd6 60 03 ffffffa0 ffffff85 ffffffdb ffffffed 24 fffffff3 58 10 48 03 60 ffffff81 33 6d fffffff1 66 59 ffffff80 ffffffb0 ffffffdc fffffff6 ffffffee 5d 3f 07 ffffffad
Len: 32
Sizeof: 1
Data: 11111111111110011101000100000111001010101110000
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Voltando ao subject do tópico, já nem sei porque coloquei "python" quando estou a usar C e a GMP library!
Por falar nisto, ontem consegui "descobrir" um bug que tinha no código e agora acho que consigo avançar mais um pouco. No entanto, é algo que deve ter explicação e não um bug propriamente dito. Eu é que não sei explicar! Mas logo vou fazer mais uns testes a ver se chego a alguma conclusão!

Isso normalmente acontece, quando seguimos um caminho que depois descobrimos que não era preciso seguir. As vezes isso deixa portas abertas para outras situações.
Mas, depois partilha a conclusão. A investigação também faz parte da aprendizagem.


Estou desvastado! Duplamente! lol... Hoje, foram precisos olhos alheios para descobrir o que estava de errado no meu código até agora.
Resumindo, eu tinha 4 funções para implementar: mod_inv() (que eu pensava que já estava implementada na GMP library por defeito, só que não!!!), add(), double() e multiply() (que é uma junção da add() e da double()).

Primeiro tive um problema com a mod_inv() e percebi que a que vem por defeito na GMP library, não fazia exactamente o que era necessário, portanto, pedi ajuda a um amigo para construírmos uma. Depois disso, para alguns casos, continuei a ter resultados errados com a função multiply(). Andei vários dias sem conseguir perceber porquê.
Ontem ao fazer alguns testes, reparei que estava a cometer um erro ao assumir que tinha convertido correctamente o seguinte valor em decimal para hexadecimal:
Code:
2 ** 256 - 2 ** 32 - 2 ** 9 - 2 ** 8 - 2 ** 7 - 2 ** 6 - 2 ** 4 - 1
=
115792089237316195423570985008687907853269984665640564039457584007908834671663
=
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f

Não sei como, copiei aquele número em hexadecimal mal para o código:
Code:
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc2f

e por isso estava a obter valores errados. Depois de descobrir isto e de resolver, agora venho a perceber que esta library não tem condições suficientemente "boas" para gerar números aleatórios suficientemente bons para private keys de Bitcoin.

Nem sei o que faça... Se continue mesmo só por gozo mas sem perspectivas de alguma vez poder usar o código para gerar uma PK e respectiva address com ele, ou se simplesmente abandone este pequeno projecto e pense noutra coisita para fazer!
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Voltando ao subject do tópico, já nem sei porque coloquei "python" quando estou a usar C e a GMP library!
Por falar nisto, ontem consegui "descobrir" um bug que tinha no código e agora acho que consigo avançar mais um pouco. No entanto, é algo que deve ter explicação e não um bug propriamente dito. Eu é que não sei explicar! Mas logo vou fazer mais uns testes a ver se chego a alguma conclusão!

Isso normalmente acontece, quando seguimos um caminho que depois descobrimos que não era preciso seguir. As vezes isso deixa portas abertas para outras situações.
Mas, depois partilha a conclusão. A investigação também faz parte da aprendizagem.





Mais um pouco de offtopic:  Roll Eyes
Isso dá para jogar em conjunto? Isso é que era fixe. Juntarmos aqui meia dúzia de gatos pingados e criarmos uma jogatana em conjunto. Mas duvido que dê, principalmente entre plataformas diferentes! Mas gostava de aprender rápido esse jogo, em vez de aprender jogando, durante meses. Não tenho pachorra para andar meses a ver vídeos e ler artigos e a testar e a experimentar!

A partida, o próprio jogo dá para jogar online, independentemente da plataforma.
Quando ao aprender, bem eu não sou de ver videos e coisas assim, faço isso muito raramente e para coisas muito especificas. Então o que eu recomendo sempre, é fazer um jogo em modo sandbox, onde a pessoa pode explorar todas as funcionalidades sem grandes preocupações. Depois, neste caso, acho que quanto mais vezes jogar mais se sabe.


Eu adoro civilization. Eu jogo desde criança, quando joguei o Civilization 1. Sempre adorei esse jogo, e acredito que joguei quase todos.

Também gosto do jogo, apenas não sou adepto de jogos por turnos. Mas, a qualidade deste jogo, justifica perder algum tempo a joga-lo. Por isso não sou nenhum pro, já tu serás um adversário bem difícil.  Wink
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Edited;
Estás a falar do Sid Meyers: Civilization, certo?
https://civilization.com/

Correto. Mas, não foi só um jogo, foi toda a serie de jogo e mais uns jogos do Sid Meyers. Ao todo deve ter sido uns 10 ou 15 jogos, nem sei.  Tongue

É um estilo de jogo muito especifico, e com uma jogabilidade muito própria. No inicio não é fácil, mas depois de perceber como tudo funciona fica mais fácil. Mesmo assim, não é dos jogos de estratégia mais fácil, antes pelo contrario.

Eu adoro civilization. Eu jogo desde criança, quando joguei o Civilization 1. Sempre adorei esse jogo, e acredito que joguei quase todos.

Uns meses atrás eu consegui gratuitamente na Epic Games o ultimo civilization e joguei até zerar. Bem bacana, foi bom lembrar os velhos tempos.



Sobre aprender python, eu recomendo que voce utilize os sites gratuitos:

https://kaggle.com
https://www.codecademy.com/
https://hackerrank.com

Quando voce aprender o básico, dai voce vai atrás de um pago. Minha sugestão.

Isso dá para jogar em conjunto? Isso é que era fixe. Juntarmos aqui meia dúzia de gatos pingados e criarmos uma jogatana em conjunto. Mas duvido que dê, principalmente entre plataformas diferentes! Mas gostava de aprender rápido esse jogo, em vez de aprender jogando, durante meses. Não tenho pachorra para andar meses a ver vídeos e ler artigos e a testar e a experimentar!

Voltando ao subject do tópico, já nem sei porque coloquei "python" quando estou a usar C e a GMP library!
Por falar nisto, ontem consegui "descobrir" um bug que tinha no código e agora acho que consigo avançar mais um pouco. No entanto, é algo que deve ter explicação e não um bug propriamente dito. Eu é que não sei explicar! Mas logo vou fazer mais uns testes a ver se chego a alguma conclusão!
legendary
Activity: 2212
Merit: 5622
Non-custodial BTC Wallet
Edited;
Estás a falar do Sid Meyers: Civilization, certo?
https://civilization.com/

Correto. Mas, não foi só um jogo, foi toda a serie de jogo e mais uns jogos do Sid Meyers. Ao todo deve ter sido uns 10 ou 15 jogos, nem sei.  Tongue

É um estilo de jogo muito especifico, e com uma jogabilidade muito própria. No inicio não é fácil, mas depois de perceber como tudo funciona fica mais fácil. Mesmo assim, não é dos jogos de estratégia mais fácil, antes pelo contrario.

Eu adoro civilization. Eu jogo desde criança, quando joguei o Civilization 1. Sempre adorei esse jogo, e acredito que joguei quase todos.

Uns meses atrás eu consegui gratuitamente na Epic Games o ultimo civilization e joguei até zerar. Bem bacana, foi bom lembrar os velhos tempos.



Sobre aprender python, eu recomendo que voce utilize os sites gratuitos:

https://kaggle.com
https://www.codecademy.com/
https://hackerrank.com

Quando voce aprender o básico, dai voce vai atrás de um pago. Minha sugestão.
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Edited;
Estás a falar do Sid Meyers: Civilization, certo?
https://civilization.com/

Correto. Mas, não foi só um jogo, foi toda a serie de jogo e mais uns jogos do Sid Meyers. Ao todo deve ter sido uns 10 ou 15 jogos, nem sei.  Tongue

É um estilo de jogo muito especifico, e com uma jogabilidade muito própria. No inicio não é fácil, mas depois de perceber como tudo funciona fica mais fácil. Mesmo assim, não é dos jogos de estratégia mais fácil, antes pelo contrario.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Ahh, o site é uma espécia de hub de promoções de formações online, é isso? Ok, apesar de nem precisar de guardar já que já aqui fica no forum para consulta futura! Ainda assim, se ficar nos meus bookmarks, também não perco nada! Obrigado pelos links! Vou ficar atento!

Sim, tem sempre promos de jogos, ebooks, cursos e software.
As vezes apanha-se mesmo coisas porreiras. Já comprei coisas lá por preços bem em conta.

Por exemplo, há uns tempos atras comprei toda a serie do jogo Civilization por menos de 20€.  Cool

Quando comprei a minha Nintendo Switch, comprei esse jogo em promoção por 6€ senão me engano. Mas como nunca tinha jogado o jogo, aquilo não é muito fácil começar a jogar logo bem e então acabei por jogar apenas uma semana ou duas. Nunca mais joguei o jogo!

Edited;
Estás a falar do Sid Meyers: Civilization, certo?
https://civilization.com/
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Ahh, o site é uma espécia de hub de promoções de formações online, é isso? Ok, apesar de nem precisar de guardar já que já aqui fica no forum para consulta futura! Ainda assim, se ficar nos meus bookmarks, também não perco nada! Obrigado pelos links! Vou ficar atento!

Sim, tem sempre promos de jogos, ebooks, cursos e software.
As vezes apanha-se mesmo coisas porreiras. Já comprei coisas lá por preços bem em conta.

Por exemplo, há uns tempos atras comprei toda a serie do jogo Civilization por menos de 20€.  Cool
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Era fixe era poder ver o conteúdo sem ter que estar a criar mais uma conta. Por acaso tenho interesse em alguns temas mas pelo menos na Udemy não há nada sobre o tema que me agrade! Mas não poder ver nesse site sem criar conta, é um revés!

Por acaso também reparei nisso. Achei um pouco chato.
Apesar da pagina inicial do curso, fazer uma explicação bem cuidada do que cada curso fala, não é bem a mesma coisa.

O preço é bom, e só por isso pode valer a pena, para quem esta a explorar essa linguagem.


Qualquer das formas, eu recomendei guardar os site da promoção e não da escola. Porque o site da promo, apresenta sempre boas promoções com regularidade: https://www.humblebundle.com/bundles

Ahh, o site é uma espécia de hub de promoções de formações online, é isso? Ok, apesar de nem precisar de guardar já que já aqui fica no forum para consulta futura! Ainda assim, se ficar nos meus bookmarks, também não perco nada! Obrigado pelos links! Vou ficar atento!
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Era fixe era poder ver o conteúdo sem ter que estar a criar mais uma conta. Por acaso tenho interesse em alguns temas mas pelo menos na Udemy não há nada sobre o tema que me agrade! Mas não poder ver nesse site sem criar conta, é um revés!

Por acaso também reparei nisso. Achei um pouco chato.
Apesar da pagina inicial do curso, fazer uma explicação bem cuidada do que cada curso fala, não é bem a mesma coisa.

O preço é bom, e só por isso pode valer a pena, para quem esta a explorar essa linguagem.


Qualquer das formas, eu recomendei guardar os site da promoção e não da escola. Porque o site da promo, apresenta sempre boas promoções com regularidade: https://www.humblebundle.com/bundles
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Ok, neste momento não. Não estou a fazer nada específico com Python. É só mais C em casa e Arduino no trabalho. De resto, quando preciso de outras linguagens, são coisas pontuais e simples que é fácil encontrar pela net através de exemplos e depois adaptar para o que preciso!

OK. Mas, fica atento ao site que indiquei, eles tem regularmente promoções de software e cursos, muito interessantes. Wink

Era fixe era poder ver o conteúdo sem ter que estar a criar mais uma conta. Por acaso tenho interesse em alguns temas mas pelo menos na Udemy não há nada sobre o tema que me agrade! Mas não poder ver nesse site sem criar conta, é um revés!
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Ok, neste momento não. Não estou a fazer nada específico com Python. É só mais C em casa e Arduino no trabalho. De resto, quando preciso de outras linguagens, são coisas pontuais e simples que é fácil encontrar pela net através de exemplos e depois adaptar para o que preciso!

OK. Mas, fica atento ao site que indiquei, eles tem regularmente promoções de software e cursos, muito interessantes. Wink
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
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.

Ok, neste momento não. Não estou a fazer nada específico com Python. É só mais C em casa e Arduino no trabalho. De resto, quando preciso de outras linguagens, são coisas pontuais e simples que é fácil encontrar pela net através de exemplos e depois adaptar para o que preciso!
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.
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.


Pois, mas depende sempre da complexidade do código para onde estás a olhar! Eu já fiz algumas formações em Python mas não considero que tenha qualquer apetência sequer para participar no mais simples projecto. Também é certo que nunca acabei por aplicar com frequência o que fui aprendendo, e as coisas vão esquecendo, mas eu sempre tive esta noção. É que é preciso anos e anos de experiência para se conseguir participar em projectos no Gitlab / Github!
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
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.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Pois, a curva eu sei que é a secp256k1 (koblitz curve). Só que no vídeo não é explícito se esse detalhe já está incluído na biblioteca que ele usa. Era só essa a minha dúvida.
Eu não uso Java. Nunca me identifiquei com essa linguagem de programação, por isso nem cheguei a ir ver a documentação.

No caso, essa linguagem é javascript  Grin

Nesses cálculos sobre as curvas elípticas eu realmente teria que estudar, nunca olhei. Como a biblioteca que ele utiliza é de código aberto, talvez se achar interessante você poderia observar o código dela e tentar entender por ele como as coisas são feitas.

Javascript e python são linguagens bastante parecidas. Java que é bem diferente..

Essas scripting languages são todas muito semelhantes. Aprendeu uma, as outras vem quase de graça.

Scripting:
Php, javascript, python, Ruby.

Programming:
Java,  c, c++..

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.
legendary
Activity: 2212
Merit: 5622
Non-custodial BTC Wallet
Pois, a curva eu sei que é a secp256k1 (koblitz curve). Só que no vídeo não é explícito se esse detalhe já está incluído na biblioteca que ele usa. Era só essa a minha dúvida.
Eu não uso Java. Nunca me identifiquei com essa linguagem de programação, por isso nem cheguei a ir ver a documentação.

No caso, essa linguagem é javascript  Grin

Nesses cálculos sobre as curvas elípticas eu realmente teria que estudar, nunca olhei. Como a biblioteca que ele utiliza é de código aberto, talvez se achar interessante você poderia observar o código dela e tentar entender por ele como as coisas são feitas.

Javascript e python são linguagens bastante parecidas. Java que é bem diferente..

Essas scripting languages são todas muito semelhantes. Aprendeu uma, as outras vem quase de graça.

Scripting:
Php, javascript, python, Ruby.

Programming:
Java,  c, c++..
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Pois, a curva eu sei que é a secp256k1 (koblitz curve). Só que no vídeo não é explícito se esse detalhe já está incluído na biblioteca que ele usa. Era só essa a minha dúvida.
Eu não uso Java. Nunca me identifiquei com essa linguagem de programação, por isso nem cheguei a ir ver a documentação.

Neste momento até estou a tentar perceber a transposição da teoria da matemática, nos cáculos sobre curvas elípticas, para programação. São 3 + 1 operações, módulo inverso , duplicar (ou seja multiplicar por 2 ou somar duas vezes) soma e multiplicação que é a combinação de duplicar e somar, que são as operações efectuadas para obter a Pub Key e assinar transacções em Bitcoin.

No caso, essa linguagem é javascript  Grin

Nesses cálculos sobre as curvas elípticas eu realmente teria que estudar, nunca olhei. Como a biblioteca que ele utiliza é de código aberto, talvez se achar interessante você poderia observar o código dela e tentar entender por ele como as coisas são feitas.

Sim, uma olhadela dou sempre. O que queria dizer é que não faço com Java ou Jaavascript o que estou a fazer com C e Python, que é pesquisar exemplos, criar os meus source files, compilar e ver os resultados. No caso de C ainda é melhor, que executo o programa com um debugger (gdb neste caso) e vou executando o código linha a linha e vou percebendo o que vai acontecendo. Eu tenho alguma dificuldade em interiorizar a recursividade em funcções! xD

Este  é um exemplo apenas do algortimo de Euclides estendido, escrito em C e a correr no GDB, linha a linha e imprimindo os valores das variáveis para perceber como vão alterando a cada iteração para conseguir depois entender como acontece a operação do módulo inverso:
hero member
Activity: 1764
Merit: 881
Pois, a curva eu sei que é a secp256k1 (koblitz curve). Só que no vídeo não é explícito se esse detalhe já está incluído na biblioteca que ele usa. Era só essa a minha dúvida.
Eu não uso Java. Nunca me identifiquei com essa linguagem de programação, por isso nem cheguei a ir ver a documentação.

Neste momento até estou a tentar perceber a transposição da teoria da matemática, nos cáculos sobre curvas elípticas, para programação. São 3 + 1 operações, módulo inverso , duplicar (ou seja multiplicar por 2 ou somar duas vezes) soma e multiplicação que é a combinação de duplicar e somar, que são as operações efectuadas para obter a Pub Key e assinar transacções em Bitcoin.

No caso, essa linguagem é javascript  Grin

Nesses cálculos sobre as curvas elípticas eu realmente teria que estudar, nunca olhei. Como a biblioteca que ele utiliza é de código aberto, talvez se achar interessante você poderia observar o código dela e tentar entender por ele como as coisas são feitas.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Bem vista a questão do número aleatório. Realmente nem pensei nisso.
Quanto à outra questão, pelo menos no link do learnmeabitcoin, os cálculos sobre curvas elípticas em Bitcoin são feitos num campo finito que eles denominam de 'p'. Não sei se nos vídeos, as bibliotecas que ele usa já o fazem intrinsecamente ou não.

Ah, entendi. É que no caso, a curva eliptica do Bitcoin é uma curva específica, é a curva Secp256k1 e os parâmetros dela já são bem definidos. Pode ver aqui:

https://en.bitcoin.it/wiki/Secp256k1

No caso, a biblioteca eccrypto que ele usa pra gerar a chave pública é feita utilizando especificamente essa curva eliptica que o Bitcoin utiliza. Pode ver a documentação da biblioteca aqui: https://www.npmjs.com/package/eccrypto

Por isso no vídeo ele já sai usando direto a biblioteca.


Pois, a curva eu sei que é a secp256k1 (koblitz curve). Só que no vídeo não é explícito se esse detalhe já está incluído na biblioteca que ele usa. Era só essa a minha dúvida.
Eu não uso Java. Nunca me identifiquei com essa linguagem de programação, por isso nem cheguei a ir ver a documentação.

Neste momento até estou a tentar perceber a transposição da teoria da matemática, nos cáculos sobre curvas elípticas, para programação. São 3 + 1 operações, módulo inverso , duplicar (ou seja multiplicar por 2 ou somar duas vezes) soma e multiplicação que é a combinação de duplicar e somar, que são as operações efectuadas para obter a Pub Key e assinar transacções em Bitcoin.
hero member
Activity: 1764
Merit: 881
Bem vista a questão do número aleatório. Realmente nem pensei nisso.
Quanto à outra questão, pelo menos no link do learnmeabitcoin, os cálculos sobre curvas elípticas em Bitcoin são feitos num campo finito que eles denominam de 'p'. Não sei se nos vídeos, as bibliotecas que ele usa já o fazem intrinsecamente ou não.

Ah, entendi. É que no caso, a curva eliptica do Bitcoin é uma curva específica, é a curva Secp256k1 e os parâmetros dela já são bem definidos. Pode ver aqui:

https://en.bitcoin.it/wiki/Secp256k1

No caso, a biblioteca eccrypto que ele usa pra gerar a chave pública é feita utilizando especificamente essa curva eliptica que o Bitcoin utiliza. Pode ver a documentação da biblioteca aqui: https://www.npmjs.com/package/eccrypto

Por isso no vídeo ele já sai usando direto a biblioteca.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Então, estava a ver os vídeos do tal Tiago Salem e vi que ele gera uma private key de forma diferente ao que eu estava a pensar e não sei se tem que ser como ele faz ou se pode ser como eu estava a pensar.

Ele gera 32 números de 1 byte. Eu gero 1 número de 32 bytes. Há diferença nestas duas abordagens em termos de resultado final no contexto da private key em Bitcoin?

No caso não vai fazer diferença porque você quer gerar um número aleatório de 32 bytes, então não faz diferença se você concatenar 32 números aleatórios de 1 byte, 8 números de 4 bytes ou como você está fazendo que é gerar de uma vez só um número inteiro de 32 bytes. O que importa é somente o resultado final.

Para além disso, ele não limita o valor máximo para a private key. Isto é normal? Ou será que as bibliotecas que ele usa jáo fazem por defeito para Bitcoin? Ou é apenas as operações sobre a private key que têm que se manter dentro dos imites especificados na curva secp256k1 ?

Não entendi a questão do valor máximo. Não me lembro de nenhuma biblioteca que ele tenha usado que seja específica pro Bitcoin.

Bem vista a questão do número aleatório. Realmente nem pensei nisso.
Quanto à outra questão, pelo menos no link do learnmeabitcoin, os cálculos sobre curvas elípticas em Bitcoin são feitos num campo finito que eles denominam de 'p'. Não sei se nos vídeos, as bibliotecas que ele usa já o fazem intrinsecamente ou não.


Eu estou a tentar fazer em Python, mas tenho muitos poucos conhecimentos.
Não quero que ninguém faça código nenhum porque quero tentar fazer por mim, sem ter ajuda de ninguém, a não ser para corrigir coisas erradas no código que eu tenho. Só assim aprendo alguma coisa. Portanto, por favor, não metam aqui as vossas soluções porque assim não aprendo nada! Queria apenas ajuda nos pormenores que eu tenho errados no meu código.

O meu código é o seguinte:
Code:
#!/usr/bin/python

import random

priv_key = random.randint(1, 0xffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141)
print("Private Key is:", hex(priv_key))

G = {
        'x': 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
        'y': 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
    }
print("G point is:", G)

pub_key = {
            'x_pub': G['x'] * priv_key,
            'y_pub': G['y'] * priv_key
          }
print("Public Key is:", pub_key)
print("x Public Key in Hex:", hex(pub_key['x_pub']))
print("y Public Key in Hex:", hex(pub_key['y_pub']))

O que obtenho é o seguinte:
Code:
x Public Key in Hex: 0x1baff1c9a2089c156990e9f9100ec834a93bf278b8ca785300df6237c66821ab6888da774227b2751e11559c8a9b2c4b650088109126808657567050c716900
y Public Key in Hex: 0x106d3d04bf6f5d7a1792e381ca4c1b65b038b89e838ab8cbd97e04e20546c754df1e549d6b149b3f06c4aec0ecfd2d922d0a40163c5dac589e414938eab1500

Mas no site que estou a seguir, pelo que percebo, esta pub key devia ter 64 chars (ou 32 bytes). Mas não me parece que esteja a ser o caso.
Então onde estou a errar?

Você já tentou usar o chatgpt?

O chatgpt é uma ferramenta incrível para escrever códigos.

Muitas vezes no meu trabalho e nos meus hobbies eu explico pro chatgpt como quero o código, e ele faz.

Ele erra muitas vezes, mas ele faz o trabalho pesado e também detecta erros muito Bem.

Além disso, ele monta uma estrutura muito organizada nos códigos

Eu recomendo que você faça essa pergunta pra ele, q ele irá te ajudar muito

Estou longe do computador agora, em viagem, e não posso rodar o código pra testar e te ajudar

Tenho usado ocasionalmente mas neste caso, não eu sei me seria útil, pois é uma questão sobre um vídeo.
legendary
Activity: 2212
Merit: 5622
Non-custodial BTC Wallet

Eu estou a tentar fazer em Python, mas tenho muitos poucos conhecimentos.
Não quero que ninguém faça código nenhum porque quero tentar fazer por mim, sem ter ajuda de ninguém, a não ser para corrigir coisas erradas no código que eu tenho. Só assim aprendo alguma coisa. Portanto, por favor, não metam aqui as vossas soluções porque assim não aprendo nada! Queria apenas ajuda nos pormenores que eu tenho errados no meu código.

O meu código é o seguinte:
Code:
#!/usr/bin/python

import random

priv_key = random.randint(1, 0xffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141)
print("Private Key is:", hex(priv_key))

G = {
        'x': 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
        'y': 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
    }
print("G point is:", G)

pub_key = {
            'x_pub': G['x'] * priv_key,
            'y_pub': G['y'] * priv_key
          }
print("Public Key is:", pub_key)
print("x Public Key in Hex:", hex(pub_key['x_pub']))
print("y Public Key in Hex:", hex(pub_key['y_pub']))

O que obtenho é o seguinte:
Code:
x Public Key in Hex: 0x1baff1c9a2089c156990e9f9100ec834a93bf278b8ca785300df6237c66821ab6888da774227b2751e11559c8a9b2c4b650088109126808657567050c716900
y Public Key in Hex: 0x106d3d04bf6f5d7a1792e381ca4c1b65b038b89e838ab8cbd97e04e20546c754df1e549d6b149b3f06c4aec0ecfd2d922d0a40163c5dac589e414938eab1500

Mas no site que estou a seguir, pelo que percebo, esta pub key devia ter 64 chars (ou 32 bytes). Mas não me parece que esteja a ser o caso.
Então onde estou a errar?

Você já tentou usar o chatgpt?

O chatgpt é uma ferramenta incrível para escrever códigos.

Muitas vezes no meu trabalho e nos meus hobbies eu explico pro chatgpt como quero o código, e ele faz.

Ele erra muitas vezes, mas ele faz o trabalho pesado e também detecta erros muito Bem.

Além disso, ele monta uma estrutura muito organizada nos códigos

Eu recomendo que você faça essa pergunta pra ele, q ele irá te ajudar muito

Estou longe do computador agora, em viagem, e não posso rodar o código pra testar e te ajudar
hero member
Activity: 1764
Merit: 881
Então, estava a ver os vídeos do tal Tiago Salem e vi que ele gera uma private key de forma diferente ao que eu estava a pensar e não sei se tem que ser como ele faz ou se pode ser como eu estava a pensar.

Ele gera 32 números de 1 byte. Eu gero 1 número de 32 bytes. Há diferença nestas duas abordagens em termos de resultado final no contexto da private key em Bitcoin?

No caso não vai fazer diferença porque você quer gerar um número aleatório de 32 bytes, então não faz diferença se você concatenar 32 números aleatórios de 1 byte, 8 números de 4 bytes ou como você está fazendo que é gerar de uma vez só um número inteiro de 32 bytes. O que importa é somente o resultado final.

Para além disso, ele não limita o valor máximo para a private key. Isto é normal? Ou será que as bibliotecas que ele usa jáo fazem por defeito para Bitcoin? Ou é apenas as operações sobre a private key que têm que se manter dentro dos imites especificados na curva secp256k1 ?

Não entendi a questão do valor máximo. Não me lembro de nenhuma biblioteca que ele tenha usado que seja específica pro Bitcoin.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Então, estava a ver os vídeos do tal Tiago Salem e vi que ele gera uma private key de forma diferente ao que eu estava a pensar e não sei se tem que ser como ele faz ou se pode ser como eu estava a pensar.

Ele gera 32 números de 1 byte. Eu gero 1 número de 32 bytes. Há diferença nestas duas abordagens em termos de resultado final no contexto da private key em Bitcoin?

Para além disso, ele não limita o valor máximo para a private key. Isto é normal? Ou será que as bibliotecas que ele usa jáo fazem por defeito para Bitcoin? Ou é apenas as operações sobre a private key que têm que se manter dentro dos imites especificados na curva secp256k1 ?
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Obrigado. Vou dar uma vista de olhos, embora o link que estou a usar seja bastante explícito. Eles explicam tudo como deve ser e o problema é mais entender os processos matemáticos e transportá-los para programação. Estou a tentar em Python embora me sentisse mais à vontade em C, mas em C acho que o nível de complexidade sobe ainda mais. Logo vejo.
Para já, estou a tentar perceber a multiplicação inversa num campo finito. Eles usam até um método de Euclides e a seguir um método de Euclides extendido e são estas coisas que é preciso interiorizar para depois passar para programação!

Bem, nesse caso acho que você deveria estudar primeiro sobre criptografia de chave pública e privada antes de ir direto para a criação da chave pública do Bitcoin, que é mais complexa. Talvez começar entendendo como funciona o RSA, fazer com uns números pequenos só pra entender a lógica e então desbravar os mares da criptografia de curvas elípticas.

Sobre o algoritmo de Euclides, acho que não tem necessidade de você implementá-lo para fazer o seu exercício. Já que é algo que já vem pronto em alguma biblioteca de criptografia que tem por aí. Mas se precisar de ajuda, pode contar comigo, já calculei vários mdc na mão no semestre passado usando o algoritmo de Euclides.  Cheesy

E pelo menos aqui no Brasil, a gente chama de inverso modular o que você chamou de multiplicação inversa num campo finito. Talvez procurando por inverso modular fique mais fácil de achar conteúdo. Geralmente ele fica dentro dos cursos de Matemática Discreta em graduação de cursos de computação.

Eu entendo os processos matemáticos. Esses não são assim muito difíceis, até porque com as explicações visuais (aqueles gifs que o site tem), ajudam muito para perceber o que está a acontecer.

Sim, não pretendo implementar o algortimo de Euclides. Esse usarei o que houver diponível, mas a parte da multiplicação inversa (ou inverso modular) gostava de conseguir implementar. Este, o duplicar e o adicionar. Já ficava muito contente de conseguir estes três!
hero member
Activity: 1764
Merit: 881
Obrigado. Vou dar uma vista de olhos, embora o link que estou a usar seja bastante explícito. Eles explicam tudo como deve ser e o problema é mais entender os processos matemáticos e transportá-los para programação. Estou a tentar em Python embora me sentisse mais à vontade em C, mas em C acho que o nível de complexidade sobe ainda mais. Logo vejo.
Para já, estou a tentar perceber a multiplicação inversa num campo finito. Eles usam até um método de Euclides e a seguir um método de Euclides extendido e são estas coisas que é preciso interiorizar para depois passar para programação!

Bem, nesse caso acho que você deveria estudar primeiro sobre criptografia de chave pública e privada antes de ir direto para a criação da chave pública do Bitcoin, que é mais complexa. Talvez começar entendendo como funciona o RSA, fazer com uns números pequenos só pra entender a lógica e então desbravar os mares da criptografia de curvas elípticas.

Sobre o algoritmo de Euclides, acho que não tem necessidade de você implementá-lo para fazer o seu exercício. Já que é algo que já vem pronto em alguma biblioteca de criptografia que tem por aí. Mas se precisar de ajuda, pode contar comigo, já calculei vários mdc na mão no semestre passado usando o algoritmo de Euclides.  Cheesy

E pelo menos aqui no Brasil, a gente chama de inverso modular o que você chamou de multiplicação inversa num campo finito. Talvez procurando por inverso modular fique mais fácil de achar conteúdo. Geralmente ele fica dentro dos cursos de Matemática Discreta em graduação de cursos de computação.
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Muito legal o exercício que está fazendo @darkv0rt3x.

Tem um brasileiro chamado Tiago Salem (que inclusive tem uma conta aqui no fórum sob o user @tiagosalem) que tem um canal no Youtube onde ele faz vídeos mais técnicos sobre o Bitcoin. Ele tem uma série de vídeos criando uma chave privada na raça, o exemplo dele é a partir de Javascript mas acho que pode te ajudar de alguma forma. A forma como ele explica é bem didática e os vídeos são bem sucintos:

Série [1/4] - Gerando chaves privadas do Bitcoin "na raça"!
Série [2/4] - Gerando um WIF (Wallet Import Format)!
Série [3/4] - Curvas elípticas no Bitcoin - Gerando chaves públicas
Série [4/4] - Finalmente! O nascimento do nosso endereço Bitcoin!




Obrigado. Vou dar uma vista de olhos, embora o link que estou a usar seja bastante explícito. Eles explicam tudo como deve ser e o problema é mais entender os processos matemáticos e transportá-los para programação. Estou a tentar em Python embora me sentisse mais à vontade em C, mas em C acho que o nível de complexidade sobe ainda mais. Logo vejo.
Para já, estou a tentar perceber a multiplicação inversa num campo finito. Eles usam até um método de Euclides e a seguir um método de Euclides extendido e são estas coisas que é preciso interiorizar para depois passar para programação!
hero member
Activity: 1764
Merit: 881
Muito legal o exercício que está fazendo @darkv0rt3x.

Tem um brasileiro chamado Tiago Salem (que inclusive tem uma conta aqui no fórum sob o user @tiagosalem) que tem um canal no Youtube onde ele faz vídeos mais técnicos sobre o Bitcoin. Ele tem uma série de vídeos criando uma chave privada na raça, o exemplo dele é a partir de Javascript mas acho que pode te ajudar de alguma forma. A forma como ele explica é bem didática e os vídeos são bem sucintos:

Série [1/4] - Gerando chaves privadas do Bitcoin "na raça"!
Série [2/4] - Gerando um WIF (Wallet Import Format)!
Série [3/4] - Curvas elípticas no Bitcoin - Gerando chaves públicas
Série [4/4] - Finalmente! O nascimento do nosso endereço Bitcoin!


hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Edited;
Esqueçam o meu post inicial... Não tem nada a ver o que eu estou ali a fazer com o que tem que ser feito. Primeiro tenho que escrever funcções para realizar as operações do módulo inverso, double e add em curvas elípticas!
Logo vi que aquilo estava a parecer simples demais!

Mas, função a função, vou tentar escrever as 3 em python. Sei que já há imensos exemplos pela net e já vi alguns, e vou tentar seguir esses exemplos e tentar entendê-los!

As vezes basta ler as coisas de uma perspectiva diferente, para se perceber o que pode estar a faltar.
Ao colocares aqui o código, acabas-te por ver o mesmo de outra perspectiva, e perceber que faltavam algumas coisas.

Já sabes que estamos sempre prontos ajudar. Como foi o caso...  Cool

Por acaso até nem foi por aqui. Foi mesmo ao falar com outra pessoa mais experiente, que ao tentar tirar uma dúvida com ele, ele acabou por me abrir a pestana para o que estava a falhar! E está a falhar por tanto... lol. Nem sei bem por onde começar!
Operações em curvas elípticas tem muito que se lhe diga. Nem sei se estarei sequer à altura para entender a primeira operação que é o módulo inverso, já que não se podem fazer divisões directas nestas curvas. Temos é que multiplicar pelo inverso de um número. Ou seja, em vez de dividirmos 3 por 4, temos que multiplicar 3 por 4^-1 que é o mesmo que 1/4... lol
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Edited;
Esqueçam o meu post inicial... Não tem nada a ver o que eu estou ali a fazer com o que tem que ser feito. Primeiro tenho que escrever funcções para realizar as operações do módulo inverso, double e add em curvas elípticas!
Logo vi que aquilo estava a parecer simples demais!

Mas, função a função, vou tentar escrever as 3 em python. Sei que já há imensos exemplos pela net e já vi alguns, e vou tentar seguir esses exemplos e tentar entendê-los!

As vezes basta ler as coisas de uma perspectiva diferente, para se perceber o que pode estar a faltar.
Ao colocares aqui o código, acabas-te por ver o mesmo de outra perspectiva, e perceber que faltavam algumas coisas.

Já sabes que estamos sempre prontos ajudar. Como foi o caso...  Cool
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Os scripts Rust que estão no site acho que devem ser antigos e não correm neste compilador online:
https://www.programiz.com/rust/online-compiler/

Se tentar compilar e correr, aquilo dá erros de sintaxe, acho eu.

Eu estou a tentar fazer em Python, mas tenho muitos poucos conhecimentos.
Não quero que ninguém faça código nenhum porque quero tentar fazer por mim, sem ter ajuda de ninguém, a não ser para corrigir coisas erradas no código que eu tenho. Só assim aprendo alguma coisa. Portanto, por favor, não metam aqui as vossas soluções porque assim não aprendo nada! Queria apenas ajuda nos pormenores que eu tenho errados no meu código.

Parabens pelo esforço em querer aprender no duro. Mas, as vezes aprende-se mais assim, do que andar apenas a seguir o que outros dizem.

Agora, estas a tentar compilar o script online?
Porque, não instalas um compilador e fazes tudo offline?

Se calhar fiz-me entender mal. O que quis dizer é que o site tem exemplos de código em Rust que não consigo fazer correr online - afinal era em Ruby. Tentei alguns dos exemplos num compilador de Rust online e aquilo dá erros por todo o lado e eu não percebo nada de Rust, nem sequer para tentar corrigir/alterar os exemplos para eles compilarem.

O que eu estou a fazer em Python, sim isso é tudo no meu PC.


Edited;
Esqueçam o meu post inicial... Não tem nada a ver o que eu estou ali a fazer com o que tem que ser feito. Primeiro tenho que escrever funcções para realizar as operações do módulo inverso, double e add em curvas elípticas!
Logo vi que aquilo estava a parecer simples demais!

Mas, função a função, vou tentar escrever as 3 em python. Sei que já há imensos exemplos pela net e já vi alguns, e vou tentar seguir esses exemplos e tentar entendê-los!
legendary
Activity: 1638
Merit: 4508
**In BTC since 2013**
Os scripts Rust que estão no site acho que devem ser antigos e não correm neste compilador online:
https://www.programiz.com/rust/online-compiler/

Se tentar compilar e correr, aquilo dá erros de sintaxe, acho eu.

Eu estou a tentar fazer em Python, mas tenho muitos poucos conhecimentos.
Não quero que ninguém faça código nenhum porque quero tentar fazer por mim, sem ter ajuda de ninguém, a não ser para corrigir coisas erradas no código que eu tenho. Só assim aprendo alguma coisa. Portanto, por favor, não metam aqui as vossas soluções porque assim não aprendo nada! Queria apenas ajuda nos pormenores que eu tenho errados no meu código.

Parabens pelo esforço em querer aprender no duro. Mas, as vezes aprende-se mais assim, do que andar apenas a seguir o que outros dizem.

Agora, estas a tentar compilar o script online?
Porque, não instalas um compilador e fazes tudo offline?
hero member
Activity: 1176
Merit: 647
I rather die on my feet than to live on my knees
Estou a tentar seguir este tutorial para tentar gerar uma private key e a respectiva address, só mesmo para perceber o processo mas devo estar a fazer algo de errado porque era suposto ter uma Pub Key com 64 caractéres e o que estou a obter, tem muitos mais.

Os scripts Rust que estão no site acho que devem ser antigos e não correm neste compilador online:
https://www.programiz.com/rust/online-compiler/

Se tentar compilar e correr, aquilo dá erros de sintaxe, acho eu.

Eu estou a tentar fazer em Python, mas tenho muitos poucos conhecimentos.
Não quero que ninguém faça código nenhum porque quero tentar fazer por mim, sem ter ajuda de ninguém, a não ser para corrigir coisas erradas no código que eu tenho. Só assim aprendo alguma coisa. Portanto, por favor, não metam aqui as vossas soluções porque assim não aprendo nada! Queria apenas ajuda nos pormenores que eu tenho errados no meu código.

O meu código é o seguinte:
Code:
#!/usr/bin/python

import random

priv_key = random.randint(1, 0xffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141)
print("Private Key is:", hex(priv_key))

G = {
        'x': 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
        'y': 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
    }
print("G point is:", G)

pub_key = {
            'x_pub': G['x'] * priv_key,
            'y_pub': G['y'] * priv_key
          }
print("Public Key is:", pub_key)
print("x Public Key in Hex:", hex(pub_key['x_pub']))
print("y Public Key in Hex:", hex(pub_key['y_pub']))

O que obtenho é o seguinte:
Code:
x Public Key in Hex: 0x1baff1c9a2089c156990e9f9100ec834a93bf278b8ca785300df6237c66821ab6888da774227b2751e11559c8a9b2c4b650088109126808657567050c716900
y Public Key in Hex: 0x106d3d04bf6f5d7a1792e381ca4c1b65b038b89e838ab8cbd97e04e20546c754df1e549d6b149b3f06c4aec0ecfd2d922d0a40163c5dac589e414938eab1500

Mas no site que estou a seguir, pelo que percebo, esta pub key devia ter 64 chars (ou 32 bytes). Mas não me parece que esteja a ser o caso.
Então onde estou a errar?
Jump to: