lib/icp_agent/vet_kd.ex

defmodule ICPAgent.VetKD do
  @moduledoc """
  This module provides functions for working with Dfinity vetKeys.

  https://internetcomputer.org/docs/references/vetkeys-overview
  """
  alias ExEcc.BLS.Ciphersuites.G2Basic
  alias ExEcc.BLS.PointCompression
  alias ExEcc.OptimizedBLS12381.OptimizedCurve, as: Curve

  def new_transport_private_key do
    rem(:binary.decode_unsigned(:crypto.strong_rand_bytes(64)), Curve.curve_order())
  end

  def transport_private_key_to_public_key(transport_private_key) do
    G2Basic.sk_to_pk(transport_private_key)
  end

  def decrypt_key(encrypted_key, transport_privkey) when is_integer(transport_privkey) do
    # Reference: https://github.com/dfinity/vetkeys/blob/dd255c8fa1ec0356f9448f1728ed4d6a5b736308/frontend/ic_vetkeys/src/utils/utils.ts#L584
    <<c1::unsigned-size(384), c2x::unsigned-size(384), c2y::unsigned-size(384),
      c3::unsigned-size(384)>> = encrypted_key

    c1 = PointCompression.decompress_g1(c1)
    _c2 = PointCompression.decompress_g2({c2x, c2y})
    c3 = PointCompression.decompress_g1(c3)

    c1_tsk = Curve.multiply(c1, transport_privkey)
    Curve.add(c3, Curve.neg(c1_tsk)) |> Curve.normalize()
  end
end