This commit is contained in:
2026-07-23 16:37:12 +02:00
parent 99c345f2f2
commit 0da75c1311
2159 changed files with 230833 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
# file: kb_decoder_spl_elgamal_registry/Cargo.toml
# version: 2
[package]
name = "kb_decoder_spl_elgamal_registry"
version.workspace = true
edition.workspace = true
license.workspace = true
publish.workspace = true
[dependencies]
base64.workspace = true
bs58.workspace = true
kb_core = { path = "../kb_core" }
kb_decoder_api = { path = "../kb_decoder_api" }
kb_model = { path = "../kb_model" }
kb_program_ids = { path = "../kb_program_ids" }
kb_store_core = { path = "../kb_store_core" }
serde_json.workspace = true
sha2.workspace = true
spl-elgamal-registry-interface.workspace = true
tracing.workspace = true
[lints]
workspace = true

View File

@@ -0,0 +1,13 @@
<!-- file: kb_decoder_spl_elgamal_registry/README.md -->
<!-- version: 1 -->
# Décodeur SPL ElGamal Registry
Décodeur strict du programme `regVYJW7tcT8zipN5YiBvHsvR5jXW1uLFxaHSbugABg`.
Il couvre les deux instructions publiées par `spl-elgamal-registry-interface 0.2.1` :
- `CreateRegistry` (`00 <offset:i8>`) ;
- `UpdateRegistry` (`01 <offset:i8>`).
Un offset nul désigne un compte de contexte de preuve prévalidé. Un offset non nul désigne une instruction relative du programme natif ZK ElGamal Proof. Le décodeur ne prétend pas décoder la preuve elle-même et ne mélange jamais ce programme avec Token-2022.

View File

@@ -0,0 +1,11 @@
// file: kb_decoder_spl_elgamal_registry/src/constants.rs
// version: 2
//! Constants for the SPL ElGamal registry decoder.
pub(crate) const SURFACE_CODE: &str = "spl_elgamal_registry";
pub(crate) const EVENT_VERSION: u32 = 1;
pub(crate) const MAX_INSTRUCTION_BYTES: usize = 16;
/// Canonical tracing target for this crate.
pub(crate) const TRACING_TARGET: &str = "kb_decoder_spl_elgamal_registry";

View File

@@ -0,0 +1,256 @@
// file: kb_decoder_spl_elgamal_registry/src/decoder.rs
// version: 6
//! Exact dispatch for the SPL ElGamal registry program.
const SURFACES: &[kb_decoder_api::DecoderSurface] = &[kb_decoder_api::DecoderSurface {
program_id: kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
surface_code: crate::SURFACE_CODE,
priority: 100,
}];
const PROGRAM_IDS: &[&str] = &[kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID];
/// Decoder for the dedicated Token-2022 ElGamal public-key registry program.
#[derive(Clone, Debug, Default)]
pub struct SplElgamalRegistryDecoder;
impl kb_decoder_api::ProtocolDecoder for crate::SplElgamalRegistryDecoder {
fn decoder_name(&self) -> &'static str {
return "kb_decoder_spl_elgamal_registry";
}
fn decoder_version(&self) -> &'static str {
return env!("CARGO_PKG_VERSION");
}
fn program_ids(&self) -> &'static [&'static str] {
return PROGRAM_IDS;
}
fn supports_observation(
&self,
observation: &kb_model::ProgramObservation,
) -> kb_decoder_api::DecoderSupport {
return if kb_decoder_api::ProtocolDecoder::handles_program_id(self, &observation.program_id)
{
kb_decoder_api::DecoderSupport::Yes
} else {
kb_decoder_api::DecoderSupport::No
};
}
fn decode_observation(
&self,
_observation: &kb_model::ProgramObservation,
) -> kb_core::Result<std::vec::Vec<kb_model::DecodedProtocolEvent>> {
return std::result::Result::Ok(std::vec::Vec::new());
}
}
impl kb_decoder_api::InstructionDecoder for crate::SplElgamalRegistryDecoder {
fn identity(&self) -> kb_decoder_api::DecoderIdentity {
return kb_decoder_api::DecoderIdentity {
name: "spl_elgamal_registry".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
}
fn surfaces(&self) -> &'static [kb_decoder_api::DecoderSurface] {
return SURFACES;
}
fn coverage(&self) -> std::vec::Vec<kb_decoder_api::DecoderCoverageDeclaration> {
return [(0_u8, "create_registry"), (1_u8, "update_registry")]
.into_iter()
.map(|(tag, code)| {
return kb_decoder_api::DecoderCoverageDeclaration {
program_id: kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID
.to_string(),
surface_code: std::option::Option::Some(crate::SURFACE_CODE.to_string()),
entry_kind: kb_decoder_api::DecoderCoverageEntryKind::Instruction,
entry_code: code.to_string(),
discriminator_hex: std::option::Option::Some(format!("{tag:02x}")),
historical: false,
};
})
.collect();
}
fn recognize(
&self,
input: &kb_store_core::CoreInstructionReplayInput,
) -> kb_decoder_api::DecoderRecognition {
if input.program_id != kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID {
return kb_decoder_api::DecoderRecognition::incompatible();
}
let entry = input
.instruction_payload_json
.as_ref()
.and_then(|payload| return payload.get("dataBase64"))
.and_then(serde_json::Value::as_str)
.and_then(|encoded| {
use base64::Engine; // rust-rules: trait-import
return base64::engine::general_purpose::STANDARD.decode(encoded.as_bytes()).ok();
})
.and_then(|bytes| return bytes.first().copied())
.and_then(|tag| {
return match tag {
0 => std::option::Option::Some("create_registry".to_string()),
1 => std::option::Option::Some("update_registry".to_string()),
_ => std::option::Option::None,
};
});
return kb_decoder_api::DecoderRecognition::compatible(
entry.is_some(),
100,
std::option::Option::Some(crate::SURFACE_CODE.to_string()),
entry,
std::option::Option::None,
);
}
fn decode(
&self,
input: &kb_store_core::CoreInstructionReplayInput,
) -> kb_decoder_api::DecoderExecutionResult {
if input.program_id != kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID {
return kb_decoder_api::DecoderExecutionResult::unsupported(std::option::Option::None);
}
let result = crate::decode(input);
if matches!(
result.status,
kb_decoder_api::DecoderOutcomeStatus::Failed
| kb_decoder_api::DecoderOutcomeStatus::Unsupported
) {
tracing::error!(
target: crate::TRACING_TARGET,
action = "decode_failure",
signature = %input.signature,
slot = input.slot,
instruction_path = %input.instruction_path,
program_id = %input.program_id,
processor_name = "spl_elgamal_registry",
processor_version = env!("CARGO_PKG_VERSION"),
input_key = %input.replay_input_key,
payload_hash = ?input.instruction_payload_hash,
transaction_failed = input.transaction_failed,
result_status = ?result.status,
diagnostics = ?result.diagnostics,
"SPL ElGamal registry instruction was not decoded successfully"
);
}
tracing::debug!(
target: crate::TRACING_TARGET,
action = "decode",
signature = %input.signature,
instruction_path = %input.instruction_path,
program_id = %input.program_id,
transaction_failed = input.transaction_failed,
result_status = ?result.status,
observation_count = result.observations.len(),
"SPL ElGamal registry instruction decode completed"
);
return result;
}
}
#[cfg(test)]
mod tests {
use base64::Engine; // rust-rules: trait-import
fn input(
program_id: &str,
payload: &[u8],
failed: bool,
path: &str,
) -> kb_store_core::CoreInstructionReplayInput {
let result = kb_store_core::CoreInstructionReplayInput::new(
format!("signature:{path}"),
"signature",
42,
path,
program_id,
failed,
if failed {
std::option::Option::Some(serde_json::json!({"InstructionError":[0,"Custom"]}))
} else {
std::option::Option::None
},
serde_json::json!([]),
serde_json::json!([]),
std::option::Option::Some(serde_json::json!({
"dataBase64": base64::engine::general_purpose::STANDARD.encode(payload)
})),
std::option::Option::None,
serde_json::json!([]),
serde_json::json!([]),
serde_json::json!([]),
serde_json::json!([]),
);
return match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("registry replay input failed: {error}"),
};
}
#[test]
fn exact_program_boundary_and_interface_id_are_preserved() {
assert_eq!(
spl_elgamal_registry_interface::id().to_string(),
kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID
);
let decoder = crate::SplElgamalRegistryDecoder;
assert_eq!(kb_decoder_api::InstructionDecoder::coverage(&decoder).len(), 2);
let foreign = input(kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID, &[0, 1], false, "0");
assert_eq!(
kb_decoder_api::InstructionDecoder::decode(&decoder, &foreign).status,
kb_decoder_api::DecoderOutcomeStatus::Unsupported
);
}
#[test]
fn create_and_update_decode_exact_offsets_and_commit_state() {
for (tag, code, offset, failed, path) in [
(0_u8, "create_registry", 1_i8, false, "0"),
(1_u8, "update_registry", -1_i8, true, "1/0"),
(1_u8, "update_registry", 0_i8, false, "2"),
] {
let input = input(
kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
&[tag, offset as u8],
failed,
path,
);
let result = kb_decoder_api::InstructionDecoder::decode(
&crate::SplElgamalRegistryDecoder,
&input,
);
assert_eq!(result.status, kb_decoder_api::DecoderOutcomeStatus::Decoded);
assert_eq!(result.recognized_entry_code.as_deref(), std::option::Option::Some(code));
assert_eq!(
result.observations[0].payload_json["proofInstructionOffset"],
serde_json::json!(offset)
);
assert_eq!(result.observations[0].observation_committed, !failed);
}
}
#[test]
fn malformed_unknown_and_suffixed_wire_fail_closed() {
for payload in [std::vec::Vec::new(), vec![0], vec![2, 0], vec![0, 1, 2]] {
let input = input(
kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
payload.as_slice(),
false,
"0",
);
let result = kb_decoder_api::InstructionDecoder::decode(
&crate::SplElgamalRegistryDecoder,
&input,
);
assert_eq!(result.status, kb_decoder_api::DecoderOutcomeStatus::Failed);
assert!(result.observations.is_empty());
}
}
}

View File

@@ -0,0 +1,38 @@
// file: kb_decoder_spl_elgamal_registry/src/lib.rs
// version: 5
//! Decoder for the SPL Token-2022 ElGamal public-key registry program.
#![warn(missing_docs)]
#![deny(unreachable_pub)]
#![forbid(unsafe_code)]
mod constants;
mod decoder;
mod registry;
pub mod state;
/// Crate-root access to `EVENT_VERSION` from `constants`.
pub(crate) use crate::constants::EVENT_VERSION;
/// Crate-root access to `MAX_INSTRUCTION_BYTES` from `constants`.
pub(crate) use crate::constants::MAX_INSTRUCTION_BYTES;
/// Crate-root access to `SURFACE_CODE` from `constants`.
pub(crate) use crate::constants::SURFACE_CODE;
/// Canonical tracing target for this crate.
pub(crate) use crate::constants::TRACING_TARGET;
/// Crate-root access to `ParsedRegistryInstruction` from `registry`.
pub(crate) use crate::registry::ParsedRegistryInstruction;
/// Crate-root access to `decode` from `registry`.
pub(crate) use crate::registry::decode;
/// Crate-root access to `decode_payload` from `registry`.
pub(crate) use crate::registry::decode_payload;
/// Crate-root access to `parse` from `registry`.
pub(crate) use crate::registry::parse;
/// Exact decoder for the SPL ElGamal registry program.
pub use crate::decoder::SplElgamalRegistryDecoder;
/// Exact byte length of one SPL ElGamal registry account.
pub use crate::state::ELGAMAL_REGISTRY_ACCOUNT_LEN;
/// Crate-root access to `ElGamalRegistryState` from `state`.
pub use crate::state::ElGamalRegistryState;
/// Parse one exact SPL ElGamal registry account.
pub use crate::state::parse_elgamal_registry_state;

View File

@@ -0,0 +1,191 @@
// file: kb_decoder_spl_elgamal_registry/src/registry.rs
// version: 3
//! Exact two-byte SPL ElGamal registry instruction decoding.
use base64::Engine; // rust-rules: trait-import
use sha2::Digest; // rust-rules: trait-import
#[derive(Clone, Debug)]
pub(crate) struct ParsedRegistryInstruction {
pub(crate) code: &'static str,
pub(crate) tag: u8,
pub(crate) proof_instruction_offset: i8,
}
pub(crate) fn decode_payload(
input: &kb_store_core::CoreInstructionReplayInput,
) -> std::result::Result<std::vec::Vec<u8>, std::string::String> {
let payload = match input.instruction_payload_json.as_ref() {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(
"ElGamal registry instruction payload is not retained".to_string(),
);
},
};
let encoded = match payload.get("dataBase64").and_then(serde_json::Value::as_str) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(
"ElGamal registry payload does not contain dataBase64".to_string(),
);
},
};
if encoded.len() > 32 {
return std::result::Result::Err(
"ElGamal registry base64 payload is too large".to_string(),
);
}
let bytes = match base64::engine::general_purpose::STANDARD.decode(encoded.as_bytes()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(format!(
"ElGamal registry payload is not valid base64: {error}"
));
},
};
if bytes.len() > crate::MAX_INSTRUCTION_BYTES {
return std::result::Result::Err(format!(
"ElGamal registry payload exceeds {} bytes",
crate::MAX_INSTRUCTION_BYTES
));
}
return std::result::Result::Ok(bytes);
}
pub(crate) fn parse(
bytes: &[u8],
) -> std::result::Result<crate::ParsedRegistryInstruction, std::string::String> {
if bytes.len() != 2 {
return std::result::Result::Err(format!(
"ElGamal registry instruction requires exactly 2 bytes; received {}",
bytes.len()
));
}
let code = match bytes[0] {
0 => "create_registry",
1 => "update_registry",
tag => return std::result::Result::Err(format!("unknown ElGamal registry tag {tag}")),
};
return std::result::Result::Ok(crate::ParsedRegistryInstruction {
code,
tag: bytes[0],
proof_instruction_offset: bytes[1] as i8,
});
}
pub(crate) fn decode(
input: &kb_store_core::CoreInstructionReplayInput,
) -> kb_decoder_api::DecoderExecutionResult {
let bytes = match crate::decode_payload(input) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(message) => {
return kb_decoder_api::DecoderExecutionResult {
status: kb_decoder_api::DecoderOutcomeStatus::Failed,
recognized_entry_code: std::option::Option::None,
observations: std::vec::Vec::new(),
diagnostics: std::vec![kb_decoder_api::DecoderDiagnostic {
code: "elgamal_registry_payload_invalid".to_string(),
message,
retriable: false,
}],
};
},
};
let parsed = match crate::parse(bytes.as_slice()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(message) => {
return kb_decoder_api::DecoderExecutionResult {
status: kb_decoder_api::DecoderOutcomeStatus::Failed,
recognized_entry_code: bytes.first().and_then(|tag| {
return match tag {
0 => std::option::Option::Some("create_registry".to_string()),
1 => std::option::Option::Some("update_registry".to_string()),
_ => std::option::Option::None,
};
}),
observations: std::vec::Vec::new(),
diagnostics: std::vec![kb_decoder_api::DecoderDiagnostic {
code: "elgamal_registry_wire_invalid".to_string(),
message,
retriable: false,
}],
};
},
};
let committed = !input.transaction_failed;
let wire_hash = hash(bytes.as_slice());
let event = kb_model::DecodedProtocolEvent {
signature: kb_model::Signature(input.signature.clone()),
slot: kb_model::Slot(input.slot),
instruction_path: kb_model::InstructionPath(input.instruction_path.clone()),
program_id: kb_model::ProgramId(input.program_id.clone()),
protocol_code: kb_model::ProtocolCode(crate::SURFACE_CODE.to_string()),
surface_code: kb_model::SurfaceCode(crate::SURFACE_CODE.to_string()),
event_code: kb_model::EventCode(format!("{}.{}", crate::SURFACE_CODE, parsed.code)),
event_name: kb_model::EventName(parsed.code.to_string()),
event_family: kb_model::EventFamily::Admin,
source_kind: if input.instruction_path.contains('/') {
kb_model::EventSourceKind::InnerInstruction
} else {
kb_model::EventSourceKind::Instruction
},
confidence: kb_model::DecoderConfidence::ManualExact,
};
let observation = kb_decoder_api::DecodedObservation {
event_key: format!("elgamal_registry:{}:0", parsed.code),
event,
payload_json: serde_json::json!({
"eventVersion": crate::EVENT_VERSION,
"instruction": parsed.code,
"wireTag": parsed.tag,
"proofInstructionOffset": parsed.proof_instruction_offset,
"proofLocationKind": if parsed.proof_instruction_offset == 0 { "context_state_account" } else { "relative_instruction_offset" },
"instructionPath": input.instruction_path,
"instructionLocation": if input.instruction_path.contains('/') { "inner" } else { "outer" },
"transactionSucceeded": !input.transaction_failed,
"committed": committed,
"accounts": input.instruction_accounts_json,
"wire": {
"lengthBytes": bytes.len(),
"sha256": wire_hash,
"prefixHex": hex(bytes.as_slice()),
"complete": true,
},
"programBoundary": {
"registryProgramId": kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
"token2022ProgramId": kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID,
"zkProofProgramId": kb_program_ids::ZK_ELGAMAL_PROOF_PROGRAM_ID,
"proofDecodedHere": false,
}
}),
transaction_failed: input.transaction_failed,
transaction_error: input.transaction_err_json.clone(),
observation_committed: committed,
proof: kb_decoder_api::DecoderProof {
kind: kb_decoder_api::DecoderProofKind::Manual,
confidence: kb_model::DecoderConfidence::ManualExact,
evidence: std::vec![
"spl_elgamal_registry_interface_0_2_1_registry_instruction_unpack".to_string(),
format!("wire_tag:{}", parsed.tag),
format!("wire_sha256:{wire_hash}"),
],
},
};
return kb_decoder_api::DecoderExecutionResult {
status: kb_decoder_api::DecoderOutcomeStatus::Decoded,
recognized_entry_code: std::option::Option::Some(parsed.code.to_string()),
observations: std::vec![observation],
diagnostics: std::vec::Vec::new(),
};
}
fn hash(bytes: &[u8]) -> std::string::String {
let digest = sha2::Sha256::digest(bytes);
return digest.iter().map(|byte| return format!("{byte:02x}")).collect();
}
fn hex(bytes: &[u8]) -> std::string::String {
return bytes.iter().map(|byte| return format!("{byte:02x}")).collect();
}

View File

@@ -0,0 +1,76 @@
// file: kb_decoder_spl_elgamal_registry/src/state.rs
// version: 2
//! Strict SPL ElGamal registry account-state parsing.
use base64::Engine; // rust-rules: trait-import
/// Exact byte length of one SPL ElGamal registry account.
pub const ELGAMAL_REGISTRY_ACCOUNT_LEN: usize = 64;
/// Public state retained by one SPL ElGamal registry account.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ElGamalRegistryState {
/// Wallet address associated with this registry.
pub owner: String,
/// Exact 32-byte ElGamal public key encoded as standard base64.
pub elgamal_pubkey_base64: String,
/// Exact account bytes encoded as lowercase hexadecimal.
pub wire_hex: String,
}
/// Parse one exact SPL ElGamal registry account.
pub fn parse_elgamal_registry_state(
data: &[u8],
) -> std::result::Result<ElGamalRegistryState, std::string::String> {
if data.len() != ELGAMAL_REGISTRY_ACCOUNT_LEN {
return std::result::Result::Err(format!(
"SPL ElGamal registry account requires exactly {ELGAMAL_REGISTRY_ACCOUNT_LEN} bytes; received {}",
data.len()
));
}
return std::result::Result::Ok(ElGamalRegistryState {
owner: bs58::encode(&data[..32]).into_string(),
elgamal_pubkey_base64: base64::engine::general_purpose::STANDARD.encode(&data[32..64]),
wire_hex: lower_hex(data),
});
}
fn lower_hex(bytes: &[u8]) -> String {
let mut output = String::with_capacity(bytes.len() * 2);
for byte in bytes {
output.push_str(&format!("{byte:02x}"));
}
return output;
}
#[cfg(test)]
mod tests {
use base64::Engine; // rust-rules: trait-import
#[test]
fn exact_registry_state_preserves_owner_key_and_wire() {
let mut data = [0u8; crate::ELGAMAL_REGISTRY_ACCOUNT_LEN];
data[..32].fill(7);
data[32..].fill(9);
let parsed = crate::parse_elgamal_registry_state(&data);
assert_eq!(
parsed.as_ref().map(|state| return state.owner.clone()),
std::result::Result::Ok(bs58::encode([7u8; 32]).into_string())
);
assert_eq!(
parsed.as_ref().map(|state| return state.elgamal_pubkey_base64.clone()),
std::result::Result::Ok(base64::engine::general_purpose::STANDARD.encode([9u8; 32]))
);
assert_eq!(
parsed.as_ref().map(|state| return state.wire_hex.len()),
std::result::Result::Ok(128)
);
}
#[test]
fn registry_state_rejects_every_non_exact_length() {
assert!(crate::parse_elgamal_registry_state(&[0; 63]).is_err());
assert!(crate::parse_elgamal_registry_state(&[0; 65]).is_err());
}
}