Skip to content

Commit f5bc5ff

Browse files
fix: report data and attestation
1 parent a5d73c3 commit f5bc5ff

2 files changed

Lines changed: 63 additions & 17 deletions

File tree

kms/src/near_kms_client.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//! which verifies attestation and requests keys from the MPC network.
99
1010
use anyhow::{Context, Result};
11+
use byte_slice_cast::AsByteSlice;
1112
use fs_err as fs;
1213
use hex;
1314
use near_api::{
@@ -16,6 +17,7 @@ use near_api::{
1617
};
1718
use near_crypto::InMemorySigner;
1819
use serde::{Deserialize, Serialize};
20+
use sha3::{Digest, Sha3_384};
1921
use std::str::FromStr;
2022
use std::sync::Arc;
2123

@@ -267,3 +269,48 @@ pub fn load_or_generate_near_signer(config: &KmsConfig) -> Result<Option<InMemor
267269
Ok(Some(signer))
268270
}
269271
}
272+
273+
/// Converts a NEAR public key to the report_data format required by the NEAR KMS contract.
274+
///
275+
/// The format matches `ReportData::new()` in the contract:
276+
/// `[version(2 bytes big endian) || SHA3-384(public_key_bytes[1..]) || zero padding]`
277+
///
278+
/// # Arguments
279+
/// * `public_key` - The NEAR account public key (must be ED25519)
280+
///
281+
/// # Returns
282+
/// A 64-byte array containing the report_data in the format expected by the KMS contract
283+
///
284+
/// # Errors
285+
/// Returns an error if the public key is not ED25519 (only ED25519 keys are supported for NEAR implicit accounts)
286+
pub fn near_public_key_to_report_data(
287+
public_key: &near_crypto::PublicKey,
288+
) -> Result<[u8; 64]> {
289+
const REPORT_DATA_SIZE: usize = 64;
290+
const BINARY_VERSION_SIZE: usize = 2;
291+
const PUBLIC_KEYS_HASH_SIZE: usize = 48;
292+
const PUBLIC_KEYS_OFFSET: usize = BINARY_VERSION_SIZE;
293+
294+
let mut report_data = [0u8; REPORT_DATA_SIZE];
295+
296+
// Version: 1 (2 bytes, big endian)
297+
report_data[0..BINARY_VERSION_SIZE].copy_from_slice(&1u16.to_be_bytes());
298+
299+
// Get public key bytes (skip first byte which is curve type identifier)
300+
let public_key_bytes = match public_key {
301+
near_crypto::PublicKey::ED25519(pk) => pk.as_byte_slice(),
302+
_ => anyhow::bail!("Only ED25519 keys are supported for NEAR implicit accounts"),
303+
};
304+
305+
// Hash public key bytes (skip first byte) with SHA3-384
306+
let mut hasher = Sha3_384::new();
307+
hasher.update(&public_key_bytes[1..]); // Skip first byte (curve type)
308+
let hash: [u8; PUBLIC_KEYS_HASH_SIZE] = hasher.finalize().into();
309+
310+
// Copy hash to report_data (offset 2, length 48)
311+
report_data[PUBLIC_KEYS_OFFSET..PUBLIC_KEYS_OFFSET + PUBLIC_KEYS_HASH_SIZE]
312+
.copy_from_slice(&hash);
313+
// Remaining bytes (50..64) are already zero-padded
314+
315+
Ok(report_data)
316+
}

kms/src/onboard_service.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::ckd::{
2626
derive_root_key_from_mpc, g1_to_near_format, generate_ephemeral_keypair, MpcConfig,
2727
};
2828
use crate::config::{AuthApi, KmsConfig};
29-
use crate::near_kms_client::{load_or_generate_near_signer, NearKmsClient};
29+
use crate::near_kms_client::{load_or_generate_near_signer, near_public_key_to_report_data, NearKmsClient};
3030
use dcap_qvl::collateral;
3131
use near_api::NetworkConfig;
3232
use ra_tls::kdf;
@@ -446,6 +446,10 @@ async fn try_derive_keys_from_mpc(
446446
tracing::info!(" Domain ID: {}", mpc_domain_id);
447447
tracing::info!(" Signer Account ID: {}", signer.account_id);
448448

449+
// Get the NEAR account public key for report_data (clone before moving signer)
450+
// The signer's public_key field contains the NEAR account public key
451+
let near_account_public_key = signer.public_key.clone();
452+
449453
let kms_client = NearKmsClient::new(
450454
network_config,
451455
mpc_contract_id.clone(),
@@ -479,28 +483,20 @@ async fn try_derive_keys_from_mpc(
479483
// Get TDX attestation (quote, collateral, tcb_info) for KMS contract
480484
// The KMS contract's request_kms_root_key() requires attestation verification
481485
let (quote_hex, collateral_json, tcb_info_json) = if quote_enabled {
482-
// Generate a quote with the worker public key as report_data
483-
let worker_pubkey_bytes = ephemeral_public_key.to_compressed();
484-
let mut report_data = vec![0u8; 64];
485-
// Put worker public key in report_data (first 48 bytes for BLS12-381 G1)
486-
if worker_pubkey_bytes.len() <= 48 {
487-
report_data[..worker_pubkey_bytes.len()].copy_from_slice(&worker_pubkey_bytes);
488-
} else {
489-
// Hash if too long
490-
use sha2::{Digest, Sha256};
491-
let hash = Sha256::digest(&worker_pubkey_bytes);
492-
report_data[..32].copy_from_slice(&hash);
493-
}
486+
// Generate report_data from NEAR account public key using helper function
487+
let report_data = near_public_key_to_report_data(&near_account_public_key)
488+
.context("Failed to convert NEAR public key to report_data format")?;
494489

495-
let attest_response = app_attest(report_data)
490+
let attest_response = app_attest(report_data.to_vec())
496491
.await
497492
.context("Failed to get TDX quote for MPC request")?;
498493

499494
let attestation = VersionedAttestation::from_scale(&attest_response.attestation)
500495
.context("Failed to parse attestation")?;
501496

502-
// Get quote bytes
497+
// Get quote bytes - need to call into_inner() first to get Attestation
503498
let quote_bytes = attestation
499+
.into_inner()
504500
.tdx_quote()
505501
.and_then(|q| Some(q.quote.clone()))
506502
.context("Failed to get TDX quote bytes")?;
@@ -512,8 +508,11 @@ async fn try_derive_keys_from_mpc(
512508
.await
513509
.context("Failed to get collateral and verify quote")?;
514510

515-
let collateral_json = serde_json::to_string(&verified_report.collateral)
516-
.context("Failed to serialize collateral")?;
511+
// Extract collateral from verified_report
512+
// The verified_report contains the quote verification result
513+
// We need to serialize the entire verified_report or extract the needed fields
514+
let collateral_json = serde_json::to_string(&verified_report)
515+
.context("Failed to serialize verified report as collateral")?;
517516

518517
// Get TCB info from verified report
519518
let td_report = verified_report

0 commit comments

Comments
 (0)