View Source Hash(x) Signature
Context
You can add the hash of any value as the signer to an account. Then, the value itself can be used as a signature. Of course, once it's used, it is revealed to the world, so it can be used by anyone.
Guide
This guide will show you how to create a hash signature and use it to sign a transaction.
A payment transaction will be used as an example, but the same process can be applied to any transaction!
1. Prerequisites
You need to have two funded accounts.
- For the first one: you will need to know the public and secret key. This account will send the payment.
- For the second one: you will need to know the public key. This account will receive the payment.
# payer's keypair
payer_pk = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"
payer_sk = "SECRET_SEED"
# destination public key
destination_pk = "GDC3W2X5KUTZRTQIKXM5D2I5WG5JYSEJQWEELVPQ5YMWZR6CA2JJ35RW"
2. Generate x
and hash(x)
You need to create a random 32-byte (256-bit) value, which we call x
or preimage
; and the SHA256 hash of x
, which we call hash(x)
.
Those values can be generated using the following code:
raw_preimage = :crypto.strong_rand_bytes(32)
preimage = Base.encode16(raw_preimage, case: :lower)
hash_x = :sha256 |> :crypto.hash(raw_preimage) |> Base.encode16(case: :lower)
For instance, the values of preimage
and hash_x
can be:
raw_preimage = <<37, 115, 193, 39, 204, 224, 190, 248, 12, 251, 213, 33, 46, 170, 236, 55, 88, 33, 172, 109, 176, 93, 53, 67, 186, 198, 71, 19, 14, 107, 216, 223>>
preimage = "2573c127cce0bef80cfbd5212eaaec375821ac6db05d3543bac647130e6bd8df"
hash_x = "819a87db1e47ae26b9b7716a6a4eb01bb3c16aeb82b83548dec81948b76e4f34"
Notice that preimage
and hash_x
are both hexadecimal encoded.
3. Add hash(x)
as a signer to the account
In this step, the SHA256 hash is added as a signer to the account.
Remember that it is stored in the hash_x
variable.
Setting the signer is done via the Stellar.TxBuild.SetOptions
operation, see the code below:
# 1. set the source account
source_account = Stellar.TxBuild.Account.new(payer_pk)
# 2. set the next sequence number for the source account
server = Stellar.Horizon.Server.testnet()
{:ok, seq_num} = Stellar.Horizon.Accounts.fetch_next_sequence_number(server, payer_pk)
sequence_number = Stellar.TxBuild.SequenceNumber.new(seq_num)
# 3. build the set_options operation setting the hash(x) as a signer with weight 1
set_options_op = Stellar.TxBuild.SetOptions.new(signer: [hash_x: hash_x, weight: 1])
# 4. build the tx signature
signature = Stellar.TxBuild.Signature.new(ed25519: payer_sk)
# 5. submit the transaction to Horizon
{:ok, envelope} =
source_account
|> Stellar.TxBuild.new(sequence_number: sequence_number)
|> Stellar.TxBuild.add_operation(set_options_op)
|> Stellar.TxBuild.sign(signature)
|> Stellar.TxBuild.envelope()
{:ok, submitted_tx} = Stellar.Horizon.Transactions.create(server, envelope)
The transaction is submitted! Now, the hash(x)
is a signer of the account.
4. Send the payment using preimage
as a signature
Since the hash(x)
is a signer of the account, then you can submit a transaction using the preimage
as a signature.
Let's send a payment to the destination account!
# 1. set the founder account
source_account = Stellar.TxBuild.Account.new(payer_pk)
# 2. set the next sequence number for the founder account
server = Stellar.Horizon.Server.testnet()
{:ok, seq_num} = Stellar.Horizon.Accounts.fetch_next_sequence_number(server, payer_pk)
sequence_number = Stellar.TxBuild.SequenceNumber.new(seq_num)
# 3. build the payment operation
payment_op =
Stellar.TxBuild.Payment.new(
destination: destination_pk,
asset: :native,
amount: 25
)
# 4. build the tx signature by providing the hex-encoded preimage
signature = Stellar.TxBuild.Signature.new(hash_x: preimage)
# 5. submit the transaction to Horizon
{:ok, envelope} =
source_account
|> Stellar.TxBuild.new(sequence_number: sequence_number)
|> Stellar.TxBuild.add_operation(payment_op)
|> Stellar.TxBuild.sign(signature)
|> Stellar.TxBuild.envelope()
{:ok, submitted_tx} = Stellar.Horizon.Transactions.create(server, envelope)
👍 That's it!
The payment was sent using the
preimage
as a signature!