syntax = "proto3";

package quilibrium.node.ceremony.pb;

option go_package = "source.quilibrium.com/quilibrium/monorepo/node/protobufs";

import "channel.proto";
import "clock.proto";
import "keys.proto";

// Describes the transcript of KZG ceremony execution
message CeremonyTranscript {
  // The active collection of powers over G1
  repeated quilibrium.node.keys.pb.BLS48581G1PublicKey g1_powers = 1;
  // The active collection of powers over G2
  repeated quilibrium.node.keys.pb.BLS48581G2PublicKey g2_powers = 2;
  // The running s^256 G1 witnesses – the choice of the 256th power is to ensure
  // combinatorial birthday paradox-based attacks are not possible. In common
  // KZG ceremonies, the collection of witnesses to PoT pubkeys produce the
  // relationship of e(w*G1, s*G2) == (s'*G1, G2), where w*s == s'. The problem
  // with this is that there are n powers under G2 (excl. the case where PoT
  // ceremonies _only_ have the first G2 power), and so the chance of collision
  // by combination to a target value for s' is feasible such that a sum of a
  // permutation of valid G2 powers could forge witness values to reach a
  // a desired outcome, as there are matching pairs of the G1 and G2 powers to
  // permute. When the number of G2 powers is low, or one, this reduces to the
  // discrete log assumption and so the only viable attack is of
  // O(sqrt(<bit size>)) per Pollard's Rho (barring any advancements), but in
  // many cases the number of G2 powers is high enough such that n! naive
  // combinations of additions are greater (and cheap, since the additions are
  // first tested in G1) than the required time of testing the discrete log,
  // and combined with many generated target values, significantly reduces the
  // amount of time required to complete the attack. This means that in
  // traditional KZG ceremonies, the last contributor to a ceremony can
  // potentially control the secret. Or, we can just track the witnesses to the
  // highest power in the ceremony and avoid the whole problem. :)
  repeated quilibrium.node.keys.pb.BLS48581G1PublicKey running_g1_256_witnesses = 3;
  // The running s^256 G2 powers – see notes on running_g1_256_witnesses for why
  // we do this.
  repeated quilibrium.node.keys.pb.BLS48581G2PublicKey running_g2_256_powers = 4;
}

message CeremonyLobbyState {
  int32 lobby_state = 1;
  oneof ceremony_state {
    CeremonyOpenState ceremony_open_state = 2;
    CeremonyInProgressState ceremony_in_progress_state = 3;
    CeremonyFinalizingState ceremony_finalizing_state = 4;
    CeremonyValidatingState ceremony_validating_state = 5;
  }
  CeremonyTranscript latest_transcript = 6;
  bytes reward_trie = 7;
}

message CeremonySeenProverAttestation {
  quilibrium.node.keys.pb.Ed448PublicKey seen_prover_key = 1;
  uint64 last_seen_frame = 2;
  quilibrium.node.keys.pb.Ed448Signature prover_signature = 3;
}

message CeremonyDroppedProverAttestation {
  quilibrium.node.keys.pb.Ed448PublicKey dropped_prover_key = 1;
  uint64 last_seen_frame = 2;
  quilibrium.node.keys.pb.Ed448Signature prover_signature = 3;
}

message CeremonyTranscriptShare {
  repeated quilibrium.node.keys.pb.BLS48581G1PublicKey additive_g1_powers = 1;
  repeated quilibrium.node.keys.pb.BLS48581G2PublicKey additive_g2_powers = 2;
  quilibrium.node.keys.pb.BLS48581G1PublicKey additive_g1_256_witness = 3;
  quilibrium.node.keys.pb.BLS48581G2PublicKey additive_g2_256_witness = 4;
  quilibrium.node.keys.pb.Ed448Signature prover_signature = 5;
}

// Describes the required proof to commit to a transcript to advance a round,
// and as a proof to move to the verification state
message CeremonyTranscriptCommit {
  // Prover key signature over the G1 point of the additive share of the first
  // power.
  quilibrium.node.keys.pb.Ed448Signature prover_signature = 1;
  // BLS short signature over the Ed448 prover public key, using the additive
  // share of the first power.
  quilibrium.node.keys.pb.BLS48581Signature contribution_signature = 2;
}

message CeremonyAdvanceRound {
  repeated CeremonyTranscriptCommit commits = 1;
}

message CeremonyLobbyJoin {
  uint64 frame_number = 1;
  quilibrium.node.keys.pb.X448PublicKey identity_key = 2;
  quilibrium.node.keys.pb.X448PublicKey signed_pre_key = 3;
  quilibrium.node.keys.pb.Ed448Signature public_key_signature_ed448 = 4;
  bytes peer_id = 5;
}

message CeremonyLobbyStateTransition {
  repeated string type_urls = 1;
  repeated bytes transition_inputs = 2;
}

message CeremonyOpenState { 
  repeated CeremonyLobbyJoin joined_participants = 1;
  repeated quilibrium.node.keys.pb.Ed448PublicKey preferred_participants = 2;
}

message CeremonyInProgressState { 
  repeated CeremonyLobbyJoin active_participants = 1;
  repeated CeremonySeenProverAttestation latest_seen_prover_attestations = 2;
  repeated CeremonyDroppedProverAttestation dropped_participant_attestations = 3;
  repeated CeremonyAdvanceRound transcript_round_advance_commits = 4;
  repeated quilibrium.node.keys.pb.Ed448PublicKey next_round_participants = 5;
}

message CeremonyFinalizingState {
  repeated CeremonyLobbyJoin active_participants = 1;
  repeated CeremonySeenProverAttestation latest_seen_prover_attestations = 2;
  repeated CeremonyDroppedProverAttestation dropped_participant_attestations = 3;
  repeated CeremonyTranscriptCommit commits = 4;
  repeated CeremonyTranscriptShare shares = 5;
  repeated quilibrium.node.keys.pb.Ed448PublicKey next_round_participants = 6;
}

message CeremonyValidatingState {
  repeated CeremonyTranscriptCommit commits = 1;
  CeremonyTranscript updated_transcript = 2;
  repeated quilibrium.node.keys.pb.Ed448PublicKey next_round_participants = 3;
}

message CeremonyPeerListAnnounce {
  repeated CeremonyPeer peer_list = 1;
}

message CeremonyPeer {
  bytes peer_id = 1;
  string multiaddr = 2;
  uint64 max_frame = 3;
  int64 timestamp = 4;
  bytes version = 5;
  bytes signature = 6;
  bytes public_key = 7;
  bytes total_distance = 8;
}

message CeremonyCompressedSync {
  uint64 from_frame_number = 1;
  uint64 to_frame_number = 2;
  repeated quilibrium.node.clock.pb.ClockFrame truncated_clock_frames = 3;
  repeated InclusionProofsMap proofs = 4;
  repeated InclusionSegmentsMap segments = 5;
}

message SyncRequestAuthentication {
  bytes peer_id = 1;
  bytes challenge = 2;
  quilibrium.node.keys.pb.Ed448Signature response = 3;
}

message CeremonyCompressedSyncRequestMessage {
  oneof sync_message {
    quilibrium.node.clock.pb.ClockFramesPreflight preflight = 1;
    quilibrium.node.clock.pb.ClockFramesRequest request = 2;
    SyncRequestAuthentication authentication = 3; 
  }
}

message CeremonyCompressedSyncResponseMessage {
  oneof sync_message {
    quilibrium.node.clock.pb.ClockFramesPreflight preflight = 1;
    CeremonyCompressedSync response = 2;
  }
}

message InclusionProofsMap {
  bytes frame_commit = 1;
  bytes proof = 2;
  repeated InclusionCommitmentsMap commitments = 3;
}

message InclusionSegmentsMap {
  bytes hash = 1;
  bytes data = 2;
}

message InclusionCommitmentsMap {
  bytes commitment = 1;
  string type_url = 2;
  repeated bytes segment_hashes = 3;
}

message GetDataFrameRequest {
  uint64 frame_number = 1;
}

message DataFrameResponse {
  quilibrium.node.clock.pb.ClockFrame clock_frame = 1;
  bytes proof = 2;
}

service CeremonyService {
  rpc GetCompressedSyncFrames (quilibrium.node.clock.pb.ClockFramesRequest) returns (stream CeremonyCompressedSync);
  rpc NegotiateCompressedSyncFrames (stream CeremonyCompressedSyncRequestMessage) returns (stream CeremonyCompressedSyncResponseMessage);
  rpc GetPublicChannel (stream quilibrium.node.channel.pb.P2PChannelEnvelope) returns (stream quilibrium.node.channel.pb.P2PChannelEnvelope);
  rpc GetDataFrame (GetDataFrameRequest) returns (DataFrameResponse);
}