Попередньо скомпільовані програми

Підсумок

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

Попередньо скомпільовані програми

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

Перевірка підпису ed25519

Програма ed25519 перевіряє один або кілька підписів ed25519 в межах однієї інструкції.

ПрограмаID програмиОписІнструкціїДжерело
Програма Ed25519Ed25519SigVerify111111111111111111111111111Перевіряє підписи 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 програмиОписІнструкціїДжерело
Програма Secp256k1KeccakSecp256k11111111111111111111111111111Перевіряє операції відновлення публічного ключа 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 на одну інструкцію.

ПрограмаID програмиОписІнструкціїДжерело
Програма Secp256r1Secp256r1SigVerify1111111111111111111111111Перевіряє до 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.
Всі права захищені.
Залишайтеся на зв'язку