Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ jobs:
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}

# We must install foundry in order to be able to test anvil
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

Expand Down Expand Up @@ -840,34 +839,45 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
cache-dependency-path: pnpm-lock.yaml

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}

- name: Install node dependencies
run: pnpm install --frozen-lockfile

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Download enclave binary
uses: actions/download-artifact@v4
with:
name: enclave-binary
path: ~/.cargo/bin/

- name: Download support scripts artifacts
uses: actions/download-artifact@v4
with:
name: support-scripts-artifacts
path: templates/default/target/

- name: Download SDK artifacts
uses: actions/download-artifact@v4
with:
name: sdk-artifacts
path: ./

- name: Make binaries executable
run: |
chmod +x ~/.cargo/bin/enclave
chmod +x templates/default/target/debug/e3-support-scripts-dev

- name: Setup ZK prover
run: |
enclave noir setup

- name: Verify downloaded artifacts
run: |
echo "Checking downloaded artifacts:"
Expand All @@ -877,6 +887,7 @@ jobs:
ls -la crates/wasm/dist || echo "WASM dist not found"
echo "Support scripts permissions:"
ls -la templates/default/target/debug/e3-support-scripts-dev

- name: Test Template
run: |
cd templates/default
Expand Down
1 change: 1 addition & 0 deletions crates/events/src/enclave_event/compute_request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl ToString for ComputeRequest {
ZkRequest::PkBfv(_) => "ZkPkBfv",
ZkRequest::PkGeneration(_) => "ZkPkGeneration",
ZkRequest::ShareComputation(_) => "ZkShareComputation",
ZkRequest::ShareEncryption(_) => "ZkShareEncryption",
},
}
.to_string()
Expand Down
53 changes: 50 additions & 3 deletions crates/events/src/enclave_event/compute_request/zk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub enum ZkRequest {
PkGeneration(PkGenerationProofRequest),
/// Generate proof for share and esm computation (C2a and C2b).
ShareComputation(ShareComputationProofRequest),
/// Generate proof for share encryption (C3a/C3b).
ShareEncryption(ShareEncryptionProofRequest),
}

/// Request to generate a proof for share computation (C2a or C2b).
Expand All @@ -39,6 +41,38 @@ pub struct ShareComputationProofRequest {
pub committee_size: CiphernodesCommitteeSize,
}

/// Request to generate a proof for share encryption (C3a or C3b).
#[derive(Derivative, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derivative(Debug)]
pub struct ShareEncryptionProofRequest {
/// Bincode-serialized Vec<u64> share row coefficients (witness — encrypted at rest).
pub share_row_raw: SensitiveBytes,
/// Serialized BFV Ciphertext bytes (via fhe_traits::Serialize).
#[derivative(Debug(format_with = "e3_utils::formatters::hexf"))]
pub ciphertext_raw: ArcBytes,
/// Serialized recipient BFV PublicKey bytes.
#[derivative(Debug(format_with = "e3_utils::formatters::hexf"))]
pub recipient_pk_raw: ArcBytes,
/// Serialized u_rns Poly bytes (witness — encrypted at rest).
pub u_rns_raw: SensitiveBytes,
/// Serialized e0_rns Poly bytes (witness — encrypted at rest).
pub e0_rns_raw: SensitiveBytes,
/// Serialized e1_rns Poly bytes (witness — encrypted at rest).
pub e1_rns_raw: SensitiveBytes,
/// SecretKey or SmudgingNoise.
pub dkg_input_type: DkgInputType,
/// Threshold BFV preset (handler derives DKG params via build_pair_for_preset).
pub params_preset: BfvPreset,
/// Committee size.
pub committee_size: CiphernodesCommitteeSize,
/// Recipient index (for correlation tracking).
pub recipient_party_id: usize,
/// Modulus row index (for correlation tracking).
pub row_index: usize,
/// ESI index (for C3b only; 0 for C3a). Disambiguates proofs across multiple ESI entries.
pub esi_index: usize,
}

/// Request to generate a proof for BFV public key generation (C0).
#[derive(Derivative, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derivative(Debug)]
Expand Down Expand Up @@ -100,12 +134,14 @@ impl PkGenerationProofRequest {
/// ZK proof generation response variants.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ZkResponse {
/// Proof for BFV public key (T0).
/// Proof for BFV public key (C0).
PkBfv(PkBfvProofResponse),
/// Proof for PK generation (T1a).
/// Proof for PK generation (C1).
PkGeneration(PkGenerationProofResponse),
/// Proof for share and esm computation (T2a and T2b).
/// Proof for share and esm computation (C2a and C2b).
ShareComputation(ShareComputationProofResponse),
/// Proof for share encryption (C3a/C3b).
ShareEncryption(ShareEncryptionProofResponse),
}

/// Response containing a generated share computation proof.
Expand All @@ -115,6 +151,17 @@ pub struct ShareComputationProofResponse {
pub dkg_input_type: DkgInputType,
}

/// Response containing a generated share encryption proof.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ShareEncryptionProofResponse {
pub proof: Proof,
pub dkg_input_type: DkgInputType,
pub recipient_party_id: usize,
pub row_index: usize,
/// ESI index (for C3b only; 0 for C3a).
pub esi_index: usize,
}

/// Response containing a generated BFV public key proof.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct PkBfvProofResponse {
Expand Down
6 changes: 3 additions & 3 deletions crates/events/src/enclave_event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ pub enum EnclaveEventData {
TicketSubmitted(TicketSubmitted),
PlaintextOutputPublished(PlaintextOutputPublished),
PkGenerationProofSigned(PkGenerationProofSigned),
ShareComputationProofSigned(ShareComputationProofSigned),
DkgProofSigned(DkgProofSigned),
EnclaveError(EnclaveError),
E3RequestComplete(E3RequestComplete),
E3Failed(E3Failed),
Expand Down Expand Up @@ -471,7 +471,7 @@ impl EnclaveEventData {
EnclaveEventData::DecryptionshareCreated(ref data) => Some(data.e3_id.clone()),
EnclaveEventData::PlaintextAggregated(ref data) => Some(data.e3_id.clone()),
EnclaveEventData::PkGenerationProofSigned(ref data) => Some(data.e3_id.clone()),
EnclaveEventData::ShareComputationProofSigned(ref data) => Some(data.e3_id.clone()),
EnclaveEventData::DkgProofSigned(ref data) => Some(data.e3_id.clone()),
EnclaveEventData::CiphernodeSelected(ref data) => Some(data.e3_id.clone()),
EnclaveEventData::ThresholdShareCreated(ref data) => Some(data.e3_id.clone()),
EnclaveEventData::ThresholdSharePending(ref data) => Some(data.e3_id.clone()),
Expand Down Expand Up @@ -523,7 +523,7 @@ impl_event_types!(
PlaintextAggregated,
PublishDocumentRequested,
PkGenerationProofSigned,
ShareComputationProofSigned,
DkgProofSigned,
E3RequestComplete,
E3Failed,
E3StageChanged,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ use std::fmt::{self, Display};

#[derive(Message, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[rtype(result = "()")]
pub struct ShareComputationProofSigned {
pub struct DkgProofSigned {
pub e3_id: E3id,
pub party_id: u64,
pub signed_proof: SignedProofPayload,
}

impl Display for ShareComputationProofSigned {
impl Display for DkgProofSigned {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
Expand Down
64 changes: 36 additions & 28 deletions crates/events/src/enclave_event/signed_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,35 @@ use std::fmt::{self, Display};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ProofType {
/// T0 — BFV public key proof (Proof 0).
T0PkBfv = 0,
/// T1 — TrBFV public key generation proof (Proof 1).
T1PkGeneration = 1,
/// T1 — Secret key share computation proof (Proof 2a).
T1SkShareComputation = 2,
/// T1 — Smudging noise share computation proof (Proof 2b).
T1ESmShareComputation = 3,
/// T1 — Share encryption proof (Proof 3).
T1ShareEncryption = 4,
C0PkBfv = 0,
/// C1 — TrBFV public key generation proof (Proof 1).
C1PkGeneration = 1,
/// C2a — Secret key share computation proof (Proof 2a).
C2aSkShareComputation = 2,
/// C2b — Smudging noise share computation proof (Proof 2b).
C2bESmShareComputation = 3,
/// C3a — Share encryption proof (Proof 3a).
C3aSkShareEncryption = 4,
/// C3b — Smudging noise share encryption proof (Proof 3b).
C3bESmShareEncryption = 5,
/// T2 — DKG share decryption proof (Proof 4).
T2DkgShareDecryption = 5,
T2DkgShareDecryption = 6,
/// T5 — Threshold share decryption proof (Proof 6).
T5ShareDecryption = 6,
T5ShareDecryption = 7,
/// T6 — Decrypted shares aggregation proof (Proof 7).
T6DecryptedSharesAggregation = 7,
T6DecryptedSharesAggregation = 8,
}

impl ProofType {
/// Map this proof type to its corresponding circuit names.
pub fn circuit_names(&self) -> Vec<CircuitName> {
match self {
ProofType::T0PkBfv => vec![CircuitName::PkBfv],
ProofType::T1PkGeneration => vec![CircuitName::PkGeneration],
ProofType::T1SkShareComputation => vec![CircuitName::SkShareComputation],
ProofType::T1ESmShareComputation => vec![CircuitName::ESmShareComputation],
ProofType::T1ShareEncryption => vec![CircuitName::ShareEncryption],
ProofType::C0PkBfv => vec![CircuitName::PkBfv],
ProofType::C1PkGeneration => vec![CircuitName::PkGeneration],
ProofType::C2aSkShareComputation => vec![CircuitName::SkShareComputation],
ProofType::C2bESmShareComputation => vec![CircuitName::ESmShareComputation],
ProofType::C3aSkShareEncryption => vec![CircuitName::ShareEncryption],
ProofType::C3bESmShareEncryption => vec![CircuitName::ShareEncryption],
ProofType::T2DkgShareDecryption => vec![CircuitName::DkgShareDecryption],
ProofType::T5ShareDecryption => vec![CircuitName::ThresholdShareDecryption],
ProofType::T6DecryptedSharesAggregation => vec![
Expand All @@ -68,11 +71,12 @@ impl ProofType {
/// Slash reason identifier for on-chain policies.
pub fn slash_reason(&self) -> &'static str {
match self {
ProofType::T0PkBfv
| ProofType::T1PkGeneration
| ProofType::T1SkShareComputation
| ProofType::T1ESmShareComputation
| ProofType::T1ShareEncryption
ProofType::C0PkBfv
| ProofType::C1PkGeneration
| ProofType::C2aSkShareComputation
| ProofType::C2bESmShareComputation
| ProofType::C3aSkShareEncryption
| ProofType::C3bESmShareEncryption
| ProofType::T2DkgShareDecryption => "E3_BAD_DKG_PROOF",
ProofType::T5ShareDecryption => "E3_BAD_DECRYPTION_PROOF",
ProofType::T6DecryptedSharesAggregation => "E3_BAD_AGGREGATION_PROOF",
Expand Down Expand Up @@ -220,7 +224,7 @@ mod tests {
fn test_payload() -> ProofPayload {
ProofPayload {
e3_id: E3id::new("1", 42),
proof_type: ProofType::T0PkBfv,
proof_type: ProofType::C0PkBfv,
proof: Proof::new(
CircuitName::PkBfv,
ArcBytes::from_bytes(&[10, 20, 30]),
Expand Down Expand Up @@ -271,7 +275,7 @@ mod tests {
fn different_payloads_produce_different_digests() {
let p1 = test_payload();
let mut p2 = test_payload();
p2.proof_type = ProofType::T1PkGeneration;
p2.proof_type = ProofType::C1PkGeneration;

assert_ne!(
p1.digest().expect("digest should succeed"),
Expand All @@ -287,7 +291,7 @@ mod tests {
let mut signed =
SignedProofPayload::sign(payload, &signer).expect("signing should succeed");
// Tamper with the payload after signing
signed.payload.proof_type = ProofType::T1PkGeneration;
signed.payload.proof_type = ProofType::C1PkGeneration;

let recovered = signed.recover_address().expect("recovery should succeed");
// Recovered address won't match the signer because payload was tampered
Expand All @@ -296,13 +300,17 @@ mod tests {

#[test]
fn proof_type_circuit_names_mapping() {
assert_eq!(ProofType::T0PkBfv.circuit_names(), vec![CircuitName::PkBfv]);
assert_eq!(ProofType::C0PkBfv.circuit_names(), vec![CircuitName::PkBfv]);
assert_eq!(
ProofType::T1PkGeneration.circuit_names(),
ProofType::C1PkGeneration.circuit_names(),
vec![CircuitName::PkGeneration]
);
assert_eq!(
ProofType::T1ShareEncryption.circuit_names(),
ProofType::C3aSkShareEncryption.circuit_names(),
vec![CircuitName::ShareEncryption]
);
assert_eq!(
ProofType::C3bESmShareEncryption.circuit_names(),
vec![CircuitName::ShareEncryption]
);
assert_eq!(
Expand Down
2 changes: 1 addition & 1 deletion crates/events/src/enclave_event/test_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl TestEvent {
#[cfg(test)]
use std::fmt::{self, Display};

use crate::{AggregateId, E3id};
use crate::E3id;

#[cfg(test)]
impl Display for TestEvent {
Expand Down
9 changes: 8 additions & 1 deletion crates/events/src/enclave_event/threshold_share_pending.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.

use crate::{E3id, PkGenerationProofRequest, ShareComputationProofRequest, ThresholdShare};
use crate::{
E3id, PkGenerationProofRequest, ShareComputationProofRequest, ShareEncryptionProofRequest,
ThresholdShare,
};
use actix::Message;
use serde::{Deserialize, Serialize};
use std::fmt::{self, Display};
Expand All @@ -22,6 +25,10 @@ pub struct ThresholdSharePending {
pub sk_share_computation_request: ShareComputationProofRequest,
/// The proof request for C2b (ESmShareComputation)
pub e_sm_share_computation_request: ShareComputationProofRequest,
/// C3a: SK share encryption proof requests (one per recipient per modulus row)
pub sk_share_encryption_requests: Vec<ShareEncryptionProofRequest>,
/// C3b: E_SM share encryption proof requests (per ESI, per recipient, per modulus row)
pub e_sm_share_encryption_requests: Vec<ShareEncryptionProofRequest>,
}

impl Display for ThresholdSharePending {
Expand Down
Loading
Loading