Packages
signet
1.0.0-beta3
1.6.1
1.6.0
1.5.0
1.4.2
1.4.1
1.4.0
1.3.12
1.3.11
1.3.10
1.3.9
1.3.8
1.3.7
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.0-echo8
1.0.0-echo7
1.0.0-echo6
1.0.0-echo5
1.0.0-echo4
1.0.0-echo3
1.0.0-echo2
1.0.0-echo1
1.0.0-delta8
1.0.0-delta7
1.0.0-delta6
1.0.0-delta5
1.0.0-delta4
1.0.0-delta3
1.0.0-delta2
1.0.0-delta1
1.0.0-charlie9
1.0.0-charlie8
1.0.0-charlie7
1.0.0-charlie6
1.0.0-charlie5
1.0.0-charlie4
1.0.0-charlie3
1.0.0-charlie2
1.0.0-charlie1
1.0.0-beta9
1.0.0-beta8
1.0.0-beta7
1.0.0-beta6
1.0.0-beta5
1.0.0-beta4
1.0.0-beta3
1.0.0-beta2
1.0.0-beta1
1.0.0-alpha9
1.0.0-alpha8
1.0.0-alpha7
1.0.0-alpha6
1.0.0-alpha5
1.0.0-alpha4
1.0.0-alpha3
1.0.0-alpha2
1.0.0-alpha10
1.0.0-alpha1
0.2.0-alpha6
0.2.0-alpha5
0.2.0-alpha4
0.2.0-alpha1
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
0.1.0-rc7
0.1.0-rc6
0.1.0-rc5
0.1.0-rc4
0.1.0-rc3
0.1.0-rc2
0.1.0-rc1
0.1.0-rc0
Lightweight Ethereum and Solana RPC client for Elixir
Current section
Files
Jump to
Current section
Files
lib/signet/signer/cloud_kms.ex
if Code.ensure_loaded?(GoogleApi.CloudKMS.V1.Api.Projects) do
defmodule Signet.Signer.CloudKMS do
@moduledoc """
Signer to sign messages from a Google Cloud KMS key.
"""
import Signet.Hash, only: [keccak: 1]
alias GoogleApi.CloudKMS.V1.Api.Projects, as: CloudKMSApi
@doc ~S"""
Get the Ethereum address associated with the given KMS key version.
## Examples
iex> {:ok, address} = Signet.Signer.CloudKMS.get_address("token", "project", "location", "keychain", "key", "version")
iex> Base.encode16(address)
"DDA641B2A76A4A7C3617815BB13281DD207B74D5"
"""
@spec get_address(term(), String.t(), String.t(), String.t(), String.t(), String.t()) ::
{:ok, binary()} | {:error, String.t()}
def get_address(cred, project, location, keychain, key, version) do
with {:ok, %GoogleApi.CloudKMS.V1.Model.PublicKey{algorithm: algorithm, pem: pem}} <-
CloudKMSApi.cloudkms_projects_locations_key_rings_crypto_keys_crypto_key_versions_get_public_key(
client(cred),
project,
location,
keychain,
key,
version
) do
case algorithm do
"EC_SIGN_SECP256K1_SHA256" ->
[certs] = :public_key.pem_decode(pem)
{{:ECPoint, public_key}, _} = :public_key.pem_entry_decode(certs)
{:ok, Signet.Util.get_eth_address(public_key)}
_ ->
{:error, "Invalid algorithm: #{algorithm}"}
end
end
end
@doc ~S"""
Signs a message with the given KMS key version, after digesting the message with keccak.
## Examples
iex> {:ok, sig} = Signet.Signer.CloudKMS.sign("test", "token", "project", "location", "keychain", "key", "version")
iex> {:ok, recid} = Signet.Recover.find_recid("test", sig, Base.decode16!("DDA641B2A76A4A7C3617815BB13281DD207B74D5"))
iex> Signet.Recover.recover_eth("test", %{sig|recid: recid}) |> Base.encode16()
"DDA641B2A76A4A7C3617815BB13281DD207B74D5"
"""
@spec sign(String.t(), term(), String.t(), String.t(), String.t(), String.t(), String.t()) ::
{:ok, Curvy.Signature.t()} | {:error, String.t()}
def sign(message, cred, project, location, keychain, key, version) when is_binary(message) do
message_hash_enc =
message
|> keccak()
|> Base.encode64()
with {:ok, response} <-
CloudKMSApi.cloudkms_projects_locations_key_rings_crypto_keys_crypto_key_versions_asymmetric_sign(
client(cred),
project,
location,
keychain,
key,
version,
body: %{
digest: %{
sha256: message_hash_enc
}
}
),
{:ok, decoded_sig} <- Base.decode64(response.signature) do
{:ok, Curvy.Signature.parse(decoded_sig)}
end
end
defp client(token) when is_binary(token), do: GoogleApi.CloudKMS.V1.Connection.new(token)
defp client(cred) do
%{token: token, type: "Bearer"} = Goth.fetch!(cred)
GoogleApi.CloudKMS.V1.Connection.new(token)
end
end
end