プリコンパイル済みプログラム

概要

プリコンパイル(Ed25519、Secp256k1、Secp256r1)は、sBPF VMをバイパスして署名をネイティブコードとして検証します。sBPF実行では遅すぎる暗号化操作を処理します。プリコンパイルはCPI経由で呼び出すことはできません。

プリコンパイル済みプログラム

プリコンパイル済みプログラムは、sBPF仮想マシンをバイパスし、validator内でネイティブコードとして実行されます。sBPF実行では遅すぎる暗号化操作を処理します。

ed25519署名の検証

ed25519プログラムは、単一のinstruction内で1つ以上のed25519署名を検証します。

プログラムプログラムID説明Instructionsソース
Ed25519プログラムEd25519SigVerify111111111111111111111111111ed25519署名を検証します。いずれかの署名が失敗した場合、エラーが返されます。Instructionsソース

instructionの最初のu8には、チェックする署名の数のカウントが含まれ、その後に1バイトのパディングが続きます。その後、以下の構造体が署名ごとに1回シリアライズされます:

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説明Instructionsソース
Secp256k1プログラムKeccakSecp256k11111111111111111111111111111secp256k1公開鍵リカバリ操作(ecrecover)を検証します。Instructionsソース

instructionの最初のバイトには、チェックする公開鍵の数のカウントが含まれます。その後、以下の構造体が公開鍵ごとに1回シリアライズされます:

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を参照できます。特別なinstructions sysvarを指定することで、プログラムはトランザクション自体からデータを読み取ることもできます。

トランザクションコストは、検証する署名の数に署名検証あたりのコストを乗じた値に等しくなります。

secp256r1署名の検証

secp256r1プログラムは、1つのinstructionあたり最大8つのsecp256r1署名を検証します。

プログラムプログラムID説明Instructionsソース
Secp256r1プログラムSecp256r1SigVerify1111111111111111111111111最大8つのsecp256r1署名を検証します。署名、公開鍵、メッセージを受け取ります。いずれかが失敗した場合はエラーを返します。Instructionsソース

instructionの最初のu8は、チェックする署名の数であり、その後に1バイトのパディングが続きます。その後、以下の構造体が署名ごとに1回シリアライズされます。

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.
無断転載を禁じます。
つながろう