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.
Há muitas funções diferentes disponíveis na linguagem de programação Script. A função CHECKSIG foi feita para travar uma saída a um endereço específico, mas você pode usar outras (e em várias combinações) para criar travas muito mais complexas.
Por exemplo, você poderia criar uma trava que só pode ser destravada após uma data específica, ou uma trava que só pode ser destravada pelos donos de dois (ou mais) endereços diferentes.
É por isso que o bitcoin às vezes é chamado de "dinheiro programável".