Предкомпилированные программы

Кратко

Предкомпилированные программы (Ed25519, Secp256k1, Secp256r1) проверяют подписи как нативный код, обходя виртуальную машину sBPF. Они выполняют криптографические операции, которые слишком медленны для sBPF. Предкомпилированные программы нельзя вызывать через CPI.

Предкомпилированные программы

Предкомпилированные программы обходят виртуальную машину sBPF и выполняются как нативный код внутри validator. Они обрабатывают криптографические операции, которые слишком медленны для выполнения в sBPF.

Проверка подписи ed25519

Программа ed25519 проверяет одну или несколько подписей ed25519 в одной инструкции.

ПрограммаID программыОписаниеИнструкцииИсходный код
Ed25519 ProgramEd25519SigVerify111111111111111111111111111Проверяет подписи ed25519. Если хотя бы одна подпись не проходит проверку, возвращается ошибка.ИнструкцииИсходный код

Первый u8 инструкции содержит количество подписей для проверки, за которым следует один байт заполнения. Затем для каждой подписи сериализуется следующая структура:

Ed25519SignatureOffsets
struct Ed25519SignatureOffsets {
signature_offset: u16, // offset to ed25519 signature of 64 bytes
signature_instruction_index: u16, // instruction index to find signature
public_key_offset: u16, // offset to public key of 32 bytes
public_key_instruction_index: u16, // instruction index to find public key
message_data_offset: u16, // offset to start of message data
message_data_size: u16, // size of message data
message_instruction_index: u16, // index of instruction data to get message data
}
Signature verification pseudocode
process_instruction() {
for i in 0..count {
// i'th index values referenced:
instructions = &transaction.message().instructions
instruction_index = ed25519_signature_instruction_index != u16::MAX ? ed25519_signature_instruction_index : current_instruction;
signature = instructions[instruction_index].data[ed25519_signature_offset..ed25519_signature_offset + 64]
instruction_index = ed25519_pubkey_instruction_index != u16::MAX ? ed25519_pubkey_instruction_index : current_instruction;
pubkey = instructions[instruction_index].data[ed25519_pubkey_offset..ed25519_pubkey_offset + 32]
instruction_index = ed25519_message_instruction_index != u16::MAX ? ed25519_message_instruction_index : current_instruction;
message = instructions[instruction_index].data[ed25519_message_data_offset..ed25519_message_data_offset + ed25519_message_data_size]
if pubkey.verify(signature, message) != Success {
return Error
}
}
return Success
}

Проверка восстановления secp256k1

Программа secp256k1 проверяет операции восстановления публичного ключа secp256k1 (ecrecover).

ПрограммаID программыОписаниеИнструкцииИсходный код
Secp256k1 ProgramKeccakSecp256k11111111111111111111111111111Проверяет операции восстановления публичного ключа secp256k1 (ecrecover).ИнструкцииИсходный код

Первый байт инструкции содержит количество публичных ключей для проверки. Затем для каждого ключа сериализуется следующая структура:

SecpSignatureOffsets
struct SecpSignatureOffsets {
signature_offset: u16, // offset to [signature,recovery_id] of 64+1 bytes
signature_instruction_index: u8, // instruction index to find signature
eth_address_offset: u16, // offset to ethereum_address of 20 bytes
eth_address_instruction_index: u8, // instruction index to find ethereum address
message_data_offset: u16, // offset to start of message data
message_data_size: u16, // size of message data
message_instruction_index: u8, // instruction index to find message data
}
Recovery verification pseudocode
process_instruction() {
for i in 0..count {
// i'th index values referenced:
instructions = &transaction.message().instructions
signature = instructions[signature_instruction_index].data[signature_offset..signature_offset + 64]
recovery_id = instructions[signature_instruction_index].data[signature_offset + 64]
ref_eth_pubkey = instructions[eth_address_instruction_index].data[eth_address_offset..eth_address_offset + 20]
message_hash = keccak256(instructions[message_instruction_index].data[message_data_offset..message_data_offset + message_data_size])
pubkey = ecrecover(signature, recovery_id, message_hash)
eth_pubkey = keccak256(pubkey[1..])[12..]
if eth_pubkey != ref_eth_pubkey {
return Error
}
}
return Success
}

Подпись и данные сообщения могут ссылаться на любые instruction data в транзакции. Указав специальную инструкцию sysvar, программы также могут читать данные самой транзакции.

Стоимость транзакции равна количеству подписей для проверки, умноженному на стоимость проверки одной подписи.

Проверка подписи secp256r1

Программа secp256r1 проверяет до 8 подписей secp256r1 за одну инструкцию.

ПрограммаProgram IDОписаниеИнструкцииИсходный код
Secp256r1 ProgramSecp256r1SigVerify1111111111111111111111111Проверяет до 8 подписей secp256r1. Принимает подпись, публичный ключ и сообщение. Возвращает ошибку при неудаче.ИнструкцииИсходный код

Первое поле инструкции u8 — это количество подписей для проверки, за которым следует один байт выравнивания. Затем для каждой подписи сериализуется следующая структура:

Secp256r1SignatureOffsets
struct Secp256r1SignatureOffsets {
signature_offset: u16, // offset to compact secp256r1 signature of 64 bytes
signature_instruction_index: u16, // instruction index to find signature
public_key_offset: u16, // offset to compressed public key of 33 bytes
public_key_instruction_index: u16, // instruction index to find public key
message_data_offset: u16, // offset to start of message data
message_data_size: u16, // size of message data
message_instruction_index: u16, // index of instruction data to get message data
}

Для всех подписей применяется требование низких значений S, чтобы избежать случайной изменяемости подписи.

Signature verification pseudocode
process_instruction() {
if data.len() < SIGNATURE_OFFSETS_START {
return Error
}
num_signatures = data[0] as usize
if num_signatures == 0 || num_signatures > 8 {
return Error
}
expected_data_size = num_signatures * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START
if data.len() < expected_data_size {
return Error
}
for i in 0..num_signatures {
offsets = parse_signature_offsets(data, i)
signature = get_data_slice(data, instruction_datas, offsets.signature_instruction_index, offsets.signature_offset, SIGNATURE_SERIALIZED_SIZE)
if s > half_curve_order {
return Error
}
pubkey = get_data_slice(data, instruction_datas, offsets.public_key_instruction_index, offsets.public_key_offset, COMPRESSED_PUBKEY_SERIALIZED_SIZE)
message = get_data_slice(data, instruction_datas, offsets.message_instruction_index, offsets.message_data_offset, offsets.message_data_size)
if !verify_signature(signature, pubkey, message) {
return Error
}
}
return Success
}

Is this page helpful?

Содержание

Редактировать страницу

Управляется

© 2026 Solana Foundation.
Все права защищены.
Связаться с нами