blockchain v0.1.7 Blockchain.Transaction.Signature
Defines helper functions for signing and getting the signature of a transaction, as defined in Appendix F of the Yellow Paper.
For any of the following functions, if chain_id is specified, it’s assumed that we’re post-fork and we should follow the specification EIP-155 from:
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
Link to this section Summary
Functions
Given a private key, this will return an associated ethereum address, as defined in Eq.(213)
Given a public key, this will return an associated ethereum address, as defined (in part) in Eq.(213)
Given a private key, returns a public key
Verifies a given signature is valid, as defined in Eq.(209), Eq.(210), Eq.(211)
Recovers a public key from a signed hash
Given a transaction, we will determine the sender of the message
Returns a ECDSA signature (v,r,s) for a given hashed value
Takes a given transaction and returns a version signed with the given private key. This is defined in Eq.(216) and Eq.(217) of the Yellow Paper
Returns a hash of a given transaction according to the formula defined in Eq.(214) and Eq.(215) of the Yellow Paper
Link to this section Types
Link to this section Functions
address_from_private(private_key) :: EVM.address
Given a private key, this will return an associated ethereum address, as defined in Eq.(213).
This returns the rightmost 160-bits of the Keecak-256 of the public key.
Examples
iex> Blockchain.Transaction.Signature.address_from_private(<<1::256>>)
<<125, 110, 153, 187, 138, 191, 140, 192, 19, 187, 14, 145, 45, 11, 23, 101, 150, 254, 123, 136>>
address_from_public(public_key) :: EVM.address
Given a public key, this will return an associated ethereum address, as defined (in part) in Eq.(213).
This returns the rightmost 160-bits of the Keecak-256 of the public key.
Examples
iex> Blockchain.Transaction.Signature.address_from_public(<<1::256>>)
<<113, 126, 106, 50, 12, 244, 75, 74, 250, 194, 176, 115, 45, 159, 203, 226, 183, 250, 12, 246>>
get_public_key(private_key) :: {:ok, public_key} | {:error, String.t}
Given a private key, returns a public key.
This covers Eq.(206) of the Yellow Paper.
Examples
iex> Blockchain.Transaction.Signature.get_public_key(<<1::256>>)
{:ok, <<4, 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149,
206, 135, 11, 7, 2, 155, 252, 219, 45, 206, 40, 217, 89,
242, 129, 91, 22, 248, 23, 152, 72, 58, 218, 119, 38, 163,
196, 101, 93, 164, 251, 252, 14, 17, 8, 168, 253, 23, 180,
72, 166, 133, 84, 25, 156, 71, 208, 143, 251, 16, 212, 184>>}
iex> Blockchain.Transaction.Signature.get_public_key(<<1>>)
{:error, "Private key size not 32 bytes"}
is_signature_valid?(boolean, integer, integer, integer) :: boolean
Verifies a given signature is valid, as defined in Eq.(209), Eq.(210), Eq.(211)
Examples
iex> Blockchain.Transaction.Signature.is_signature_valid?(true, 1, 1, 27) true
iex> Blockchain.Transaction.Signature.is_signature_valid?(true, 1, 1, 20) # invalid v false
iex> secp256k1n = 115792089237316195423570985008687907852837564279074904382605163141518161494337 iex> Blockchain.Transaction.Signature.is_signature_valid?(false, secp256k1n - 1, 1, 28) # r okay true
iex> secp256k1n = 115792089237316195423570985008687907852837564279074904382605163141518161494337 iex> Blockchain.Transaction.Signature.is_signature_valid?(false, secp256k1n + 1, 1, 28) # r too high false
iex> secp256k1n = 115792089237316195423570985008687907852837564279074904382605163141518161494337 iex> Blockchain.Transaction.Signature.is_signature_valid?(false, 1, secp256k1n + 1, 28) # s too high for non-homestead false
iex> secp256k1n = 115792089237316195423570985008687907852837564279074904382605163141518161494337 iex> Blockchain.Transaction.Signature.is_signature_valid?(false, 1, secp256k1n - 1, 28) # s okay for non-homestead true
iex> secp256k1n = 115792089237316195423570985008687907852837564279074904382605163141518161494337 iex> Blockchain.Transaction.Signature.is_signature_valid?(true, 1, secp256k1n - 1, 28) # s too high for homestead false
iex> secp256k1n = 115792089237316195423570985008687907852837564279074904382605163141518161494337 iex> secp256k1n_2 = round(:math.floor(secp256k1n / 2)) iex> Blockchain.Transaction.Signature.is_signature_valid?(true, secp256k1n_2 - 1, 1, 28) # s okay for homestead true
recover_public(BitHelper.keccak_hash, hash_v, hash_r, hash_s, integer | nil) :: {:ok, public_key} | {:error, String.t}
Recovers a public key from a signed hash.
This implements Eq.(208) of the Yellow Paper, adapted from https://stackoverflow.com/a/20000007
Examples
iex> Blockchain.Transaction.Signature.recover_public(<<2::256>>, 28, 38938543279057362855969661240129897219713373336787331739561340553100525404231, 23772455091703794797226342343520955590158385983376086035257995824653222457926) {:ok, <<121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11, 7, 2,
155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23, 152, 72, 58,
218, 119, 38, 163, 196, 101, 93, 164, 251, 252, 14, 17, 8, 168, 253, 23, 180,
72, 166, 133, 84, 25, 156, 71, 208, 143, 251, 16, 212, 184>>}
iex> Blockchain.Transaction.Signature.recover_public(<<2::256>>, 55, 38938543279057362855969661240129897219713373336787331739561340553100525404231, 23772455091703794797226342343520955590158385983376086035257995824653222457926)
iex> data = “ec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080” |> BitHelper.from_hex iex> hash = data |> BitHelper.kec iex> v = 27 iex> r = 18515461264373351373200002665853028612451056578545711640558177340181847433846 iex> s = 46948507304638947509940763649030358759909902576025900602547168820602576006531 iex> Blockchain.Transaction.Signature.recover_public(hash, v, r, s) {:ok,
<<75, 194, 163, 18, 101, 21, 63, 7, 231, 14, 11, 171, 8, 114, 78, 107, 133,
226, 23, 248, 205, 98, 140, 235, 98, 151, 66, 71, 187, 73, 51, 130, 206, 40,
202, 183, 154, 215, 17, 158, 225, 173, 62, 188, 219, 152, 161, 104, 5, 33,
21, 48, 236, 198, 207, 239, 161, 184, 142, 109, 255, 153, 35, 42>>}
iex> { v, r, s } = { 37, 18515461264373351373200002665853028612451056578545711640558177340181847433846, 46948507304638947509940763649030358759909902576025900602547168820602576006531 } iex> data = “ec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080” |> BitHelper.from_hex iex> hash = data |> BitHelper.kec iex> Blockchain.Transaction.Signature.recover_public(hash, v, r, s, 1) {:ok, <<75, 194, 163, 18, 101, 21, 63, 7, 231, 14, 11, 171, 8, 114, 78, 107, 133,
226, 23, 248, 205, 98, 140, 235, 98, 151, 66, 71, 187, 73, 51, 130, 206, 40,
202, 183, 154, 215, 17, 158, 225, 173, 62, 188, 219, 152, 161, 104, 5, 33,
21, 48, 236, 198, 207, 239, 161, 184, 142, 109, 255, 153, 35, 42>>}
sender(Blockchain.Transaction.t, integer | nil) :: {:ok, EVM.address} | {:error, String.t}
Given a transaction, we will determine the sender of the message.
This is defined in Eq.(218) of the Yellow Paper, verified by Eq.(219).
Examples
iex> Blockchain.Transaction.Signature.sender(%Blockchain.Transaction{data: nil, gas_limit: 7, gas_price: 6, init: <<1>>, nonce: 5, r: 38889131630470350300468726261158724183878062819625353581392042110782473464074, s: 56013001490976921811414879795854011730332692343890561111314022658085426919315, to: "", v: 27, value: 5})
{:ok, <<97, 159, 86, 232, 190, 208, 127, 225, 150, 192, 219, 196, 27, 82, 226, 188, 100, 129, 123, 58>>}
iex> Blockchain.Transaction.Signature.sender(%Blockchain.Transaction{data: nil, gas_limit: 7, gas_price: 6, init: <<1>>, nonce: 5, r: 38889131630470350300468726261158724183878062819625353581392042110782473464074, s: 56013001490976921811414879795854011730332692343890561111314022658085426919315, to: "", v: 37, value: 5}, 1)
{:ok, <<193, 199, 91, 238, 113, 76, 188, 186, 97, 187, 114, 56, 173, 211, 129, 121, 109, 144, 30, 253>>}
iex> Blockchain.Transaction.Signature.sender(%Blockchain.Transaction{data: nil, gas_limit: 7, gas_price: 6, init: <<1>>, nonce: 5, r: 0, s: 0, to: "", v: 0, value: 5})
{:error, "Recovery id invalid 0-3"}
sign_hash(BitHelper.keccak_hash, private_key, integer | nil) :: {hash_v, hash_r, hash_s}
Returns a ECDSA signature (v,r,s) for a given hashed value.
This implementes Eq.(207) of the Yellow Paper.
Examples
iex> Blockchain.Transaction.Signature.sign_hash(<<2::256>>, <<1::256>>) {28, 38938543279057362855969661240129897219713373336787331739561340553100525404231, 23772455091703794797226342343520955590158385983376086035257995824653222457926}
iex> Blockchain.Transaction.Signature.sign_hash(<<5::256>>, <<1::256>>) {27, 74927840775756275467012999236208995857356645681540064312847180029125478834483, 56037731387691402801139111075060162264934372456622294904359821823785637523849}
iex> data = “ec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080018080” |> BitHelper.from_hex iex> hash = data |> BitHelper.kec iex> private_key = “4646464646464646464646464646464646464646464646464646464646464646” |> BitHelper.from_hex iex> Blockchain.Transaction.Signature.sign_hash(hash, private_key, 1) { 37, 18515461264373351373200002665853028612451056578545711640558177340181847433846, 46948507304638947509940763649030358759909902576025900602547168820602576006531 }
sign_transaction(Blockchain.Transaction.t, private_key, integer | nil) :: Blockchain.Transaction.t
Takes a given transaction and returns a version signed with the given private key. This is defined in Eq.(216) and Eq.(217) of the Yellow Paper.
Examples
iex> Blockchain.Transaction.Signature.sign_transaction(%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<>>, value: 5, init: <<1>>}, <<1::256>>)
%Blockchain.Transaction{data: <<>>, gas_limit: 7, gas_price: 6, init: <<1>>, nonce: 5, r: 97037709922803580267279977200525583527127616719646548867384185721164615918250, s: 31446571475787755537574189222065166628755695553801403547291726929250860527755, to: "", v: 27, value: 5}
iex> Blockchain.Transaction.Signature.sign_transaction(%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<>>, value: 5, init: <<1>>}, <<1::256>>, 1)
%Blockchain.Transaction{data: <<>>, gas_limit: 7, gas_price: 6, init: <<1>>, nonce: 5, r: 25739987953128435966549144317523422635562973654702886626580606913510283002553, s: 41423569377768420285000144846773344478964141018753766296386430811329935846420, to: "", v: 38, value: 5}
transaction_hash(Blockchain.Transaction.t, integer | nil) :: BitHelper.keccak_hash
Returns a hash of a given transaction according to the formula defined in Eq.(214) and Eq.(215) of the Yellow Paper.
Note: As per EIP-155 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md),
we will append the chain-id and nil elements to the serialized transaction.
Examples
iex> Blockchain.Transaction.Signature.transaction_hash(%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<>>, value: 5, init: <<1>>})
<<127, 113, 209, 76, 19, 196, 2, 206, 19, 198, 240, 99, 184, 62, 8, 95, 9, 122, 135, 142, 51, 22, 61, 97, 70, 206, 206, 39, 121, 54, 83, 27>>
iex> Blockchain.Transaction.Signature.transaction_hash(%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1>>, value: 5, data: <<1>>})
<<225, 195, 128, 181, 3, 211, 32, 231, 34, 10, 166, 198, 153, 71, 210, 118, 51, 117, 22, 242, 87, 212, 229, 37, 71, 226, 150, 160, 50, 203, 127, 180>>
iex> Blockchain.Transaction.Signature.transaction_hash(%Blockchain.Transaction{nonce: 5, gas_price: 6, gas_limit: 7, to: <<1>>, value: 5, data: <<1>>}, 1)
<<132, 79, 28, 4, 212, 58, 235, 38, 66, 211, 167, 102, 36, 58, 229, 88, 238, 251, 153, 23, 121, 163, 212, 64, 83, 111, 200, 206, 54, 43, 112, 53>>