Skip to content

Commit

Permalink
Added compact signature support.
Browse files Browse the repository at this point in the history
  • Loading branch information
Hajto committed Jun 15, 2023
1 parent 349f929 commit 0b6cf94
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 1 deletion.
37 changes: 37 additions & 0 deletions lib/ex_web3_ec_recover/compact_signature.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
defmodule ExWeb3EcRecover.CompactSignature do
@moduledoc false
@enforce_keys [:r, :y_parity_and_s]
defstruct @enforce_keys

@type t :: %__MODULE__{
r: binary(),
y_parity_and_s: binary()
}

@spec from_hexstring(binary()) :: ExWeb3EcRecover.CompactSignature.t()
def from_hexstring("0x" <> signature) when byte_size(signature) == 64 do
<<r::binary-size(256), y_parity_and_s::binary-size(256)>> = Base.decode16!(signature)

%__MODULE__{
r: r,
y_parity_and_s: y_parity_and_s
}
end

@spec from_canonical(ExWeb3EcRecover.Signature.t()) :: ExWeb3EcRecover.CompactSignature.t()
def from_canonical(%ExWeb3EcRecover.Signature{} = sig) do
y_parity = sig.v_num
<<s::size(256)>> = sig.s
y_parity_and_s = Bitwise.bor(Bitwise.bsl(y_parity, 255), s)

%__MODULE__{
r: sig.r,
y_parity_and_s: <<y_parity_and_s::size(256)>>
}
end

@spec serialize(__MODULE__.t()) :: binary()
def serialize(%__MODULE__{} = cs) do
cs.r <> cs.y_parity_and_s
end
end
6 changes: 6 additions & 0 deletions lib/ex_web3_ec_recover/signature.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ defmodule ExWeb3EcRecover.Signature do
@enforce_keys [:r, :s, :v_num]
defstruct @enforce_keys

@type t :: %__MODULE__{
r: binary(),
s: binary(),
v_num: 0 | 1
}

def from_hexstring("0x" <> signature) when byte_size(signature) == 130 do
# 65 bytes of data, each byte takes two bytes in hexstring
sig_binary = Base.decode16!(signature, case: :lower)
Expand Down
33 changes: 33 additions & 0 deletions test/compact_signature_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
defmodule ExWeb3EcRecover.CompactSignatureTest do
@moduledoc false
# Test data provided by https://eips.ethereum.org/EIPS/eip-2098#example-implementation-in-python
use ExUnit.Case, async: true

test "parity 0" do
sig =
"0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b907e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea520641b"

canon = ExWeb3EcRecover.Signature.from_hexstring(sig)
result = ExWeb3EcRecover.CompactSignature.from_canonical(canon)

assert Base.encode16(result.r, case: :lower) ==
"68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90"

assert Base.encode16(result.y_parity_and_s, case: :lower) ==
"7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064"
end

test "parity 1" do
sig =
"0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76139c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f5507931c"

canon = ExWeb3EcRecover.Signature.from_hexstring(sig)
result = ExWeb3EcRecover.CompactSignature.from_canonical(canon)

assert Base.encode16(result.r, case: :lower) ==
"9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76"

assert Base.encode16(result.y_parity_and_s, case: :lower) ==
"939c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793"
end
end
2 changes: 1 addition & 1 deletion test/signed_type_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ defmodule ExWeb3EcRecover.SignedTypeTest do
types = %{
"Message" => [
%{"name" => "data1", "type" => "int256"},
%{"name" => "data2", "type" => "uint256"},
%{"name" => "data2", "type" => "uint256"}
]
}

Expand Down

0 comments on commit 0b6cf94

Please sign in to comment.