Travas
O que impede que os bitcoins sejam roubados?
Toda saída em uma transação tem uma trava. Essa trava é um conjunto de requisitos que precisam ser cumpridos para gastar a saída em uma transação futura.
Em outras palavras, essas travas impedem que os bitcoins sejam roubados (ou seja, que outra pessoa gaste seus bitcoins), já que cada saída que recebemos é onerada por uma trava.
Por exemplo, uma trava típica diz algo como isto:
Quando as travas são colocadas nas saídas?
Como sabemos, uma transação pega saídas existentes e cria novas a partir delas:
E é durante a criação dessas saídas que damos a cada uma a sua própria "trava":
Então, quando queremos enviar bitcoins para um amigo, criamos uma nova saída e adicionamos uma trava que diz "somente o dono do endereço 1amigo1234567890... pode usar esta saída":
Como resultado, essa nova saída efetivamente "pertencerá" ao nosso amigo, porque ele é a única pessoa que tem a chave privada necessária para destravar os bitcoins travados nesse endereço, então ninguém mais conseguirá gastá-la.
Como é uma trava?
As travas são escritas em uma linguagem de programação básica chamada Script.
É um pouco complicado explicar o funcionamento de uma linguagem de programação inteira em um diagrama, mas lá vai:

Este é um exemplo simplificado de um script de travamento; não é exatamente como o Script se parece.
Agora, a parte mais interessante desse script de travamento é a parte CHECKPRIVATEKEY, que é uma função que usamos para ajudar a definir os requisitos da trava.
Então, para esta saída específica, definimos uma trava que quer comparar o endereço 1EUXSxuUVy2PC5enGXR1a3yxbEjNWMHuem com uma chave privada.
Se conseguirmos fornecer a essa trava a chave privada correta (que o dono do endereço mantém em segredo), podemos destravá-la e gastá-la em uma transação.
Como você destrava uma trava?
Quando você constrói os dados da transação, você inclui um "script de destravamento" junto a cada saída que quer gastar:
Então, por exemplo, para destravar um script de travamento típico (ex.: [endereço] CHECKPRIVATEKEY), precisamos provar que somos donos do endereço dentro da trava. Para isso, fornecemos a chave privada conectada ao endereço.
Então, quando um nó recebe esses dados da transação, ele roda os scripts de "travamento"+"destravamento" juntos para ver se sua chave privada está matematicamente conectada ao endereço.
Se estiver tudo certo, o nó aceita a transação e a repassa para outros nós, que, por sua vez, vão rodar o script de "travamento"+"destravamento" antes de aceitar a transação.
E é assim que você destrava uma trava em uma saída.
Não estamos entregando nossa chave privada?
Observação astuta.
Confissão: na verdade não colocamos nossa chave privada no script de destravamento.
Veja bem, para não termos que entregar nossa chave privada dentro dos dados da transação, usamos a chave privada para criar algo chamado assinatura digital:
Obviamente eu menti sobre aquela função CHECKPRIVATEKEY também.
Porém, existe uma função que compara um endereço com uma assinatura digital, e ela se chama CHECKSIG:
E graças à matemática das assinaturas digitais e à função CHECKSIG, ainda podemos travar saídas para endereços e destravá-las sem ter que entregar a chave privada.
Maravilha.