1use crate::{Address, ProgramError};
4
5pub type Sha256Hash = [u8; 32];
6pub type Keccak256Hash = [u8; 32];
7pub type Blake3Hash = [u8; 32];
8pub type Secp256k1Pubkey = [u8; 64];
9pub type EthereumAddress = [u8; 20];
10pub type CurvePoint = [u8; 32];
11pub type CurveScalar = [u8; 32];
12pub type PoseidonHash = [u8; 32];
13pub type AltBn128G1 = [u8; 64];
14pub type AltBn128G1Compressed = [u8; 32];
15pub type AltBn128G2 = [u8; 128];
16pub type AltBn128G2Compressed = [u8; 64];
17pub type AltBn128PairingResult = [u8; 32];
18
19pub const MAX_HASH_SEGMENTS: usize = 16;
20pub const CURVE25519_EDWARDS: u64 = 0;
21pub const CURVE25519_RISTRETTO: u64 = 1;
22pub const CURVE_GROUP_ADD: u64 = 0;
23pub const CURVE_GROUP_SUB: u64 = 1;
24pub const CURVE_GROUP_MUL: u64 = 2;
25pub const POSEIDON_BN254_X5: u64 = 0;
26pub const POSEIDON_BIG_ENDIAN: u64 = 0;
27pub const POSEIDON_LITTLE_ENDIAN: u64 = 1;
28pub const MAX_POSEIDON_INPUTS: usize = 12;
29pub const POSEIDON_INPUT_LEN: usize = 32;
30pub const ALT_BN128_LE_FLAG: u64 = 0x80;
31pub const ALT_BN128_FIELD_SIZE: usize = 32;
32pub const ALT_BN128_G1_POINT_SIZE: usize = 64;
33pub const ALT_BN128_G2_POINT_SIZE: usize = 128;
34pub const ALT_BN128_G1_ADDITION_INPUT_SIZE: usize = 128;
35pub const ALT_BN128_G2_ADDITION_INPUT_SIZE: usize = 256;
36pub const ALT_BN128_G1_MULTIPLICATION_INPUT_SIZE: usize = 96;
37pub const ALT_BN128_G2_MULTIPLICATION_INPUT_SIZE: usize = 160;
38pub const ALT_BN128_PAIRING_ELEMENT_SIZE: usize = 192;
39pub const ALT_BN128_G1_ADD_BE: u64 = 0;
40pub const ALT_BN128_G1_SUB_BE: u64 = 1;
41pub const ALT_BN128_G1_MUL_BE: u64 = 2;
42pub const ALT_BN128_PAIRING_BE: u64 = 3;
43pub const ALT_BN128_G2_ADD_BE: u64 = 4;
44pub const ALT_BN128_G2_SUB_BE: u64 = 5;
45pub const ALT_BN128_G2_MUL_BE: u64 = 6;
46pub const ALT_BN128_G1_ADD_LE: u64 = ALT_BN128_G1_ADD_BE | ALT_BN128_LE_FLAG;
47pub const ALT_BN128_G1_SUB_LE: u64 = ALT_BN128_G1_SUB_BE | ALT_BN128_LE_FLAG;
48pub const ALT_BN128_G1_MUL_LE: u64 = ALT_BN128_G1_MUL_BE | ALT_BN128_LE_FLAG;
49pub const ALT_BN128_PAIRING_LE: u64 = ALT_BN128_PAIRING_BE | ALT_BN128_LE_FLAG;
50pub const ALT_BN128_G2_ADD_LE: u64 = ALT_BN128_G2_ADD_BE | ALT_BN128_LE_FLAG;
51pub const ALT_BN128_G2_SUB_LE: u64 = ALT_BN128_G2_SUB_BE | ALT_BN128_LE_FLAG;
52pub const ALT_BN128_G2_MUL_LE: u64 = ALT_BN128_G2_MUL_BE | ALT_BN128_LE_FLAG;
53pub const ALT_BN128_G1_COMPRESS_BE: u64 = 0;
54pub const ALT_BN128_G1_DECOMPRESS_BE: u64 = 1;
55pub const ALT_BN128_G2_COMPRESS_BE: u64 = 2;
56pub const ALT_BN128_G2_DECOMPRESS_BE: u64 = 3;
57pub const ALT_BN128_G1_COMPRESS_LE: u64 = ALT_BN128_G1_COMPRESS_BE | ALT_BN128_LE_FLAG;
58pub const ALT_BN128_G1_DECOMPRESS_LE: u64 = ALT_BN128_G1_DECOMPRESS_BE | ALT_BN128_LE_FLAG;
59pub const ALT_BN128_G2_COMPRESS_LE: u64 = ALT_BN128_G2_COMPRESS_BE | ALT_BN128_LE_FLAG;
60pub const ALT_BN128_G2_DECOMPRESS_LE: u64 = ALT_BN128_G2_DECOMPRESS_BE | ALT_BN128_LE_FLAG;
61pub const MAX_INSTRUCTION_DATA_LEN: usize = 1232;
62pub const MAX_INSTRUCTION_ACCOUNTS_BYTES: usize = 2176;
63
64pub const ED25519_PROGRAM_ID: Address = Address::new_from_array(crate::__decode_base58_32(
65 "Ed25519SigVerify111111111111111111111111111",
66));
67
68pub const SECP256K1_PROGRAM_ID: Address = Address::new_from_array(crate::__decode_base58_32(
69 "KeccakSecp256k11111111111111111111111111111",
70));
71
72pub const SECP256R1_PROGRAM_ID: Address = Address::new_from_array(crate::__decode_base58_32(
75 "Secp256r1SigVerify1111111111111111111111111",
76));
77
78#[derive(Clone, Debug)]
79pub struct ProcessedInstruction {
80 pub program_id: Address,
81 pub data: [u8; MAX_INSTRUCTION_DATA_LEN],
82 pub data_len: usize,
83 pub accounts_len: usize,
84}
85
86#[derive(Clone, Debug)]
87pub struct ProcessedInstructionData<const MAX_DATA: usize> {
88 pub program_id: Address,
89 pub data: [u8; MAX_DATA],
90 pub data_len: usize,
91}
92
93#[repr(C)]
94struct ProcessedInstructionMeta {
95 data_len: u64,
96 accounts_len: u64,
97}
98
99#[cfg(feature = "crypto-big-mod-exp")]
100#[repr(C)]
101struct BigModExpParams {
102 base: *const u8,
103 base_len: u64,
104 exponent: *const u8,
105 exponent_len: u64,
106 modulus: *const u8,
107 modulus_len: u64,
108}
109
110#[cfg(any(
111 feature = "crypto-curve",
112 feature = "crypto-poseidon",
113 feature = "crypto-bn254",
114 feature = "crypto-big-mod-exp"
115))]
116#[inline]
117fn syscall_error(status: u64) -> ProgramError {
118 if status <= u32::MAX as u64 {
119 ProgramError::Custom(status as u32)
120 } else {
121 ProgramError::InvalidArgument
122 }
123}
124
125#[inline]
126pub fn sha256(inputs: &[&[u8]]) -> Result<Sha256Hash, ProgramError> {
127 if inputs.len() > MAX_HASH_SEGMENTS {
128 return Err(ProgramError::InvalidArgument);
129 }
130
131 let mut result = [0u8; 32];
132 unsafe {
135 crate::syscalls::sol_sha256(
136 inputs as *const _ as *const u8,
137 inputs.len() as u64,
138 result.as_mut_ptr(),
139 );
140 }
141 Ok(result)
142}
143
144#[inline]
145pub fn sha256_single(input: &[u8]) -> Result<Sha256Hash, ProgramError> {
146 sha256(&[input])
147}
148
149#[inline]
150pub fn keccak256(inputs: &[&[u8]]) -> Result<Keccak256Hash, ProgramError> {
151 if inputs.len() > MAX_HASH_SEGMENTS {
152 return Err(ProgramError::InvalidArgument);
153 }
154
155 let mut result = [0u8; 32];
156 unsafe {
159 crate::syscalls::sol_keccak256(
160 inputs as *const _ as *const u8,
161 inputs.len() as u64,
162 result.as_mut_ptr(),
163 );
164 }
165 Ok(result)
166}
167
168#[inline]
169pub fn keccak256_single(input: &[u8]) -> Result<Keccak256Hash, ProgramError> {
170 keccak256(&[input])
171}
172
173#[inline]
174pub fn blake3(inputs: &[&[u8]]) -> Result<Blake3Hash, ProgramError> {
175 if inputs.len() > MAX_HASH_SEGMENTS {
176 return Err(ProgramError::InvalidArgument);
177 }
178
179 let mut result = [0u8; 32];
180 let rc = unsafe {
183 crate::syscalls::sol_blake3(
184 inputs as *const _ as *const u8,
185 inputs.len() as u64,
186 result.as_mut_ptr(),
187 )
188 };
189 if rc != 0 {
190 return Err(ProgramError::InvalidArgument);
191 }
192 Ok(result)
193}
194
195#[inline]
196pub fn blake3_single(input: &[u8]) -> Result<Blake3Hash, ProgramError> {
197 blake3(&[input])
198}
199
200#[inline]
201pub fn secp256k1_recover(
202 message_hash: &[u8; 32],
203 recovery_id: u8,
204 signature: &[u8; 64],
205) -> Result<Secp256k1Pubkey, ProgramError> {
206 let mut result = [0u8; 64];
207 let rc = unsafe {
210 crate::syscalls::sol_secp256k1_recover(
211 message_hash.as_ptr(),
212 recovery_id as u64,
213 signature.as_ptr(),
214 result.as_mut_ptr(),
215 )
216 };
217 if rc != 0 {
218 return Err(ProgramError::InvalidArgument);
219 }
220 Ok(result)
221}
222
223#[inline]
224pub fn recover_ethereum_address(
225 message_hash: &[u8; 32],
226 recovery_id: u8,
227 signature: &[u8; 64],
228) -> Result<EthereumAddress, ProgramError> {
229 let pubkey = secp256k1_recover(message_hash, recovery_id, signature)?;
230 let digest = keccak256(&[&pubkey])?;
231 let mut address = [0u8; 20];
232 address.copy_from_slice(&digest[12..32]);
233 Ok(address)
234}
235
236#[inline]
237pub fn curve_validate_point(curve_id: u64, point: &[u8; 32]) -> Result<bool, ProgramError> {
238 let rc = unsafe {
241 crate::syscalls::sol_curve_validate_point(curve_id, point.as_ptr(), core::ptr::null_mut())
242 };
243 Ok(rc == 0)
244}
245
246#[inline]
247pub fn curve25519_edwards_validate_point(point: &[u8; 32]) -> Result<bool, ProgramError> {
248 curve_validate_point(CURVE25519_EDWARDS, point)
249}
250
251#[cfg(feature = "crypto-curve")]
252#[inline]
253fn curve_group_op(
254 curve_id: u64,
255 group_op: u64,
256 left: &CurvePoint,
257 right: &CurvePoint,
258) -> Result<CurvePoint, ProgramError> {
259 let mut result = [0u8; 32];
260 let rc = unsafe {
262 crate::syscalls::sol_curve_group_op(
263 curve_id,
264 group_op,
265 left.as_ptr(),
266 right.as_ptr(),
267 result.as_mut_ptr(),
268 )
269 };
270 if rc != 0 {
271 return Err(syscall_error(rc));
272 }
273 Ok(result)
274}
275
276#[cfg(feature = "crypto-curve")]
277#[inline]
278pub fn curve_group_add(
279 curve_id: u64,
280 left: &CurvePoint,
281 right: &CurvePoint,
282) -> Result<CurvePoint, ProgramError> {
283 curve_group_op(curve_id, CURVE_GROUP_ADD, left, right)
284}
285
286#[cfg(feature = "crypto-curve")]
287#[inline]
288pub fn curve_group_sub(
289 curve_id: u64,
290 left: &CurvePoint,
291 right: &CurvePoint,
292) -> Result<CurvePoint, ProgramError> {
293 curve_group_op(curve_id, CURVE_GROUP_SUB, left, right)
294}
295
296#[cfg(feature = "crypto-curve")]
297#[inline]
298pub fn curve_group_mul(
299 curve_id: u64,
300 scalar: &CurveScalar,
301 point: &CurvePoint,
302) -> Result<CurvePoint, ProgramError> {
303 let mut result = [0u8; 32];
304 let rc = unsafe {
307 crate::syscalls::sol_curve_group_op(
308 curve_id,
309 CURVE_GROUP_MUL,
310 scalar.as_ptr(),
311 point.as_ptr(),
312 result.as_mut_ptr(),
313 )
314 };
315 if rc != 0 {
316 return Err(syscall_error(rc));
317 }
318 Ok(result)
319}
320
321#[cfg(feature = "crypto-curve")]
322#[inline]
323pub fn curve_multiscalar_mul(
324 curve_id: u64,
325 scalars: &[CurveScalar],
326 points: &[CurvePoint],
327) -> Result<CurvePoint, ProgramError> {
328 if scalars.len() != points.len() || points.is_empty() {
329 return Err(ProgramError::InvalidArgument);
330 }
331
332 let mut result = [0u8; 32];
333 let rc = unsafe {
336 crate::syscalls::sol_curve_multiscalar_mul(
337 curve_id,
338 scalars.as_ptr() as *const u8,
339 points.as_ptr() as *const u8,
340 points.len() as u64,
341 result.as_mut_ptr(),
342 )
343 };
344 if rc != 0 {
345 return Err(syscall_error(rc));
346 }
347 Ok(result)
348}
349
350#[cfg(feature = "crypto-poseidon")]
351#[inline]
352pub fn poseidon_hashv(
353 parameters: u64,
354 endianness: u64,
355 inputs: &[&[u8]],
356) -> Result<PoseidonHash, ProgramError> {
357 if inputs.is_empty() || inputs.len() > MAX_POSEIDON_INPUTS {
358 return Err(ProgramError::InvalidArgument);
359 }
360 if inputs.iter().any(|input| input.len() != POSEIDON_INPUT_LEN) {
361 return Err(ProgramError::InvalidArgument);
362 }
363
364 let mut result = [0u8; 32];
365 let rc = unsafe {
368 crate::syscalls::sol_poseidon(
369 parameters,
370 endianness,
371 inputs as *const _ as *const u8,
372 inputs.len() as u64,
373 result.as_mut_ptr(),
374 )
375 };
376 if rc != 0 {
377 return Err(syscall_error(rc));
378 }
379 Ok(result)
380}
381
382#[cfg(feature = "crypto-poseidon")]
383#[inline]
384pub fn poseidon_hash(
385 parameters: u64,
386 endianness: u64,
387 input: &[u8; 32],
388) -> Result<PoseidonHash, ProgramError> {
389 poseidon_hashv(parameters, endianness, &[input])
390}
391
392#[cfg(feature = "crypto-poseidon")]
393#[inline]
394pub fn poseidon_bn254_x5(inputs: &[&[u8]]) -> Result<PoseidonHash, ProgramError> {
395 poseidon_hashv(POSEIDON_BN254_X5, POSEIDON_BIG_ENDIAN, inputs)
396}
397
398#[cfg(feature = "crypto-bn254")]
399#[inline]
400fn alt_bn128_group_op<const OUT: usize>(
401 group_op: u64,
402 input: &[u8],
403) -> Result<[u8; OUT], ProgramError> {
404 let mut result = [0u8; OUT];
405 let rc = unsafe {
407 crate::syscalls::sol_alt_bn128_group_op(
408 group_op,
409 input.as_ptr(),
410 input.len() as u64,
411 result.as_mut_ptr(),
412 )
413 };
414 if rc != 0 {
415 return Err(syscall_error(rc));
416 }
417 Ok(result)
418}
419
420#[cfg(feature = "crypto-bn254")]
421#[inline]
422fn alt_bn128_compression_op<const OUT: usize>(
423 op: u64,
424 input: &[u8],
425) -> Result<[u8; OUT], ProgramError> {
426 let mut result = [0u8; OUT];
427 let rc = unsafe {
429 crate::syscalls::sol_alt_bn128_compression(
430 op,
431 input.as_ptr(),
432 input.len() as u64,
433 result.as_mut_ptr(),
434 )
435 };
436 if rc != 0 {
437 return Err(syscall_error(rc));
438 }
439 Ok(result)
440}
441
442#[cfg(feature = "crypto-bn254")]
443#[inline]
444pub fn alt_bn128_g1_addition_be(input: &[u8]) -> Result<AltBn128G1, ProgramError> {
445 if input.len() > ALT_BN128_G1_ADDITION_INPUT_SIZE {
446 return Err(ProgramError::InvalidArgument);
447 }
448 alt_bn128_group_op::<ALT_BN128_G1_POINT_SIZE>(ALT_BN128_G1_ADD_BE, input)
449}
450
451#[cfg(feature = "crypto-bn254")]
452#[inline]
453pub fn alt_bn128_g1_multiplication_be(input: &[u8]) -> Result<AltBn128G1, ProgramError> {
454 if input.len() > ALT_BN128_G1_MULTIPLICATION_INPUT_SIZE {
455 return Err(ProgramError::InvalidArgument);
456 }
457 alt_bn128_group_op::<ALT_BN128_G1_POINT_SIZE>(ALT_BN128_G1_MUL_BE, input)
458}
459
460#[cfg(feature = "crypto-bn254")]
461#[inline]
462pub fn alt_bn128_pairing_be(input: &[u8]) -> Result<AltBn128PairingResult, ProgramError> {
463 if !input.len().is_multiple_of(ALT_BN128_PAIRING_ELEMENT_SIZE) {
464 return Err(ProgramError::InvalidArgument);
465 }
466 alt_bn128_group_op::<ALT_BN128_FIELD_SIZE>(ALT_BN128_PAIRING_BE, input)
467}
468
469#[cfg(feature = "crypto-bn254")]
470#[inline]
471pub fn alt_bn128_add(input: &[u8]) -> Result<AltBn128G1, ProgramError> {
472 alt_bn128_g1_addition_be(input)
473}
474
475#[cfg(feature = "crypto-bn254")]
476#[inline]
477pub fn alt_bn128_mul(input: &[u8]) -> Result<AltBn128G1, ProgramError> {
478 alt_bn128_g1_multiplication_be(input)
479}
480
481#[cfg(feature = "crypto-bn254")]
482#[inline]
483pub fn alt_bn128_pairing(input: &[u8]) -> Result<AltBn128PairingResult, ProgramError> {
484 alt_bn128_pairing_be(input)
485}
486
487#[cfg(feature = "crypto-bn254")]
488#[inline]
489pub fn alt_bn128_g1_compress_be(input: &AltBn128G1) -> Result<AltBn128G1Compressed, ProgramError> {
490 alt_bn128_compression_op::<ALT_BN128_FIELD_SIZE>(ALT_BN128_G1_COMPRESS_BE, input)
491}
492
493#[cfg(feature = "crypto-bn254")]
494#[inline]
495pub fn alt_bn128_g1_decompress_be(
496 input: &AltBn128G1Compressed,
497) -> Result<AltBn128G1, ProgramError> {
498 alt_bn128_compression_op::<ALT_BN128_G1_POINT_SIZE>(ALT_BN128_G1_DECOMPRESS_BE, input)
499}
500
501#[cfg(feature = "crypto-bn254")]
502#[inline]
503pub fn alt_bn128_g2_compress_be(input: &AltBn128G2) -> Result<AltBn128G2Compressed, ProgramError> {
504 alt_bn128_compression_op::<ALT_BN128_G1_POINT_SIZE>(ALT_BN128_G2_COMPRESS_BE, input)
505}
506
507#[cfg(feature = "crypto-bn254")]
508#[inline]
509pub fn alt_bn128_g2_decompress_be(
510 input: &AltBn128G2Compressed,
511) -> Result<AltBn128G2, ProgramError> {
512 alt_bn128_compression_op::<ALT_BN128_G2_POINT_SIZE>(ALT_BN128_G2_DECOMPRESS_BE, input)
513}
514
515#[cfg(feature = "crypto-big-mod-exp")]
516#[inline]
517pub fn big_mod_exp(
518 base: &[u8],
519 exponent: &[u8],
520 modulus: &[u8],
521 output: &mut [u8],
522) -> Result<(), ProgramError> {
523 if modulus.is_empty() || output.len() != modulus.len() {
524 return Err(ProgramError::InvalidArgument);
525 }
526
527 let params = BigModExpParams {
528 base: base.as_ptr(),
529 base_len: base.len() as u64,
530 exponent: exponent.as_ptr(),
531 exponent_len: exponent.len() as u64,
532 modulus: modulus.as_ptr(),
533 modulus_len: modulus.len() as u64,
534 };
535 let rc = unsafe {
538 crate::syscalls::sol_big_mod_exp(
539 ¶ms as *const BigModExpParams as *const u8,
540 output.as_mut_ptr(),
541 )
542 };
543 if rc != 0 {
544 return Err(syscall_error(rc));
545 }
546 Ok(())
547}
548
549#[inline(always)]
550pub fn get_stack_height() -> u64 {
551 crate::syscalls::sol_get_stack_height()
552}
553
554#[inline(always)]
555pub fn is_top_level() -> bool {
556 get_stack_height() <= 1
557}
558
559#[inline(always)]
560pub fn is_cpi() -> bool {
561 get_stack_height() > 1
562}
563
564#[inline(always)]
565pub fn require_top_level() -> Result<(), ProgramError> {
566 if is_top_level() {
567 Ok(())
568 } else {
569 Err(ProgramError::InvalidArgument)
570 }
571}
572
573#[inline]
574pub fn get_processed_instruction(index: u64) -> Option<ProcessedInstruction> {
575 let mut meta = ProcessedInstructionMeta {
576 data_len: MAX_INSTRUCTION_DATA_LEN as u64,
577 accounts_len: (MAX_INSTRUCTION_ACCOUNTS_BYTES / 34) as u64,
578 };
579 let mut program_id = Address::default();
580 let mut data = [0u8; MAX_INSTRUCTION_DATA_LEN];
581 let mut accounts = [0u8; MAX_INSTRUCTION_ACCOUNTS_BYTES];
582
583 let rc = unsafe {
586 crate::syscalls::sol_get_processed_sibling_instruction(
587 index,
588 &mut meta as *mut ProcessedInstructionMeta as *mut u8,
589 program_id.as_mut().as_mut_ptr(),
590 data.as_mut_ptr(),
591 accounts.as_mut_ptr(),
592 )
593 };
594 if rc != 0 {
595 return None;
596 }
597
598 Some(ProcessedInstruction {
599 program_id,
600 data,
601 data_len: meta.data_len as usize,
602 accounts_len: meta.accounts_len as usize,
603 })
604}
605
606#[inline]
607pub fn get_processed_instruction_data<const MAX_DATA: usize>(
608 index: u64,
609) -> Option<ProcessedInstructionData<MAX_DATA>> {
610 let mut meta = ProcessedInstructionMeta {
611 data_len: MAX_DATA as u64,
612 accounts_len: 0,
613 };
614 let mut program_id = Address::default();
615 let mut data = [0u8; MAX_DATA];
616 let mut accounts = [0u8; 0];
617
618 let rc = unsafe {
622 crate::syscalls::sol_get_processed_sibling_instruction(
623 index,
624 &mut meta as *mut ProcessedInstructionMeta as *mut u8,
625 program_id.as_mut().as_mut_ptr(),
626 data.as_mut_ptr(),
627 accounts.as_mut_ptr(),
628 )
629 };
630 if rc != 0 {
631 return None;
632 }
633
634 Some(ProcessedInstructionData {
635 program_id,
636 data,
637 data_len: meta.data_len as usize,
638 })
639}
640
641#[inline]
642pub fn require_ed25519_instruction(
643 sibling_index: u64,
644) -> Result<ProcessedInstruction, ProgramError> {
645 let instruction =
646 get_processed_instruction(sibling_index).ok_or(ProgramError::InvalidArgument)?;
647 if instruction.program_id != ED25519_PROGRAM_ID {
648 return Err(ProgramError::IncorrectProgramId);
649 }
650 Ok(instruction)
651}
652
653#[inline]
654pub fn require_ed25519_instruction_data<const MAX_DATA: usize>(
655 sibling_index: u64,
656) -> Result<ProcessedInstructionData<MAX_DATA>, ProgramError> {
657 let instruction =
658 get_processed_instruction_data(sibling_index).ok_or(ProgramError::InvalidArgument)?;
659 if instruction.program_id != ED25519_PROGRAM_ID {
660 return Err(ProgramError::IncorrectProgramId);
661 }
662 Ok(instruction)
663}
664
665#[inline]
666pub fn require_secp256k1_instruction(
667 sibling_index: u64,
668) -> Result<ProcessedInstruction, ProgramError> {
669 let instruction =
670 get_processed_instruction(sibling_index).ok_or(ProgramError::InvalidArgument)?;
671 if instruction.program_id != SECP256K1_PROGRAM_ID {
672 return Err(ProgramError::IncorrectProgramId);
673 }
674 Ok(instruction)
675}
676
677#[inline]
682pub fn require_secp256r1_instruction(
683 sibling_index: u64,
684) -> Result<ProcessedInstruction, ProgramError> {
685 let instruction =
686 get_processed_instruction(sibling_index).ok_or(ProgramError::InvalidArgument)?;
687 if instruction.program_id != SECP256R1_PROGRAM_ID {
688 return Err(ProgramError::IncorrectProgramId);
689 }
690 Ok(instruction)
691}
692
693#[inline]
696pub fn require_secp256r1_instruction_data<const MAX_DATA: usize>(
697 sibling_index: u64,
698) -> Result<ProcessedInstructionData<MAX_DATA>, ProgramError> {
699 let instruction =
700 get_processed_instruction_data(sibling_index).ok_or(ProgramError::InvalidArgument)?;
701 if instruction.program_id != SECP256R1_PROGRAM_ID {
702 return Err(ProgramError::IncorrectProgramId);
703 }
704 Ok(instruction)
705}
706
707#[cfg(test)]
708mod tests {
709 use super::*;
710
711 const EMPTY: &[u8] = b"";
712
713 #[test]
714 fn hash_helpers_accept_sixteen_segments() {
715 let inputs = [EMPTY; MAX_HASH_SEGMENTS];
716
717 assert!(sha256(&inputs).is_ok());
718 assert!(keccak256(&inputs).is_ok());
719 assert!(blake3(&inputs).is_ok());
720 }
721
722 #[test]
723 fn hash_helpers_reject_more_than_sixteen_segments() {
724 let inputs = [EMPTY; MAX_HASH_SEGMENTS + 1];
725
726 assert_eq!(sha256(&inputs), Err(ProgramError::InvalidArgument));
727 assert_eq!(keccak256(&inputs), Err(ProgramError::InvalidArgument));
728 assert_eq!(blake3(&inputs), Err(ProgramError::InvalidArgument));
729 }
730
731 #[cfg(feature = "crypto-curve")]
732 #[test]
733 fn curve_msm_requires_matching_nonempty_inputs() {
734 let scalars = [[0u8; 32]; 2];
735 let points = [[0u8; 32]; 1];
736
737 assert_eq!(
738 curve_multiscalar_mul(CURVE25519_EDWARDS, &scalars, &points),
739 Err(ProgramError::InvalidArgument)
740 );
741 assert_eq!(
742 curve_multiscalar_mul(CURVE25519_EDWARDS, &[], &[]),
743 Err(ProgramError::InvalidArgument)
744 );
745 }
746
747 #[cfg(feature = "crypto-poseidon")]
748 #[test]
749 fn poseidon_rejects_bad_input_shape() {
750 let short = [0u8; 31];
751 let input = [0u8; 32];
752 let too_many = [&input[..]; MAX_POSEIDON_INPUTS + 1];
753
754 assert_eq!(
755 poseidon_hashv(POSEIDON_BN254_X5, POSEIDON_BIG_ENDIAN, &[]),
756 Err(ProgramError::InvalidArgument)
757 );
758 assert_eq!(
759 poseidon_hashv(POSEIDON_BN254_X5, POSEIDON_BIG_ENDIAN, &[&short]),
760 Err(ProgramError::InvalidArgument)
761 );
762 assert_eq!(
763 poseidon_hashv(POSEIDON_BN254_X5, POSEIDON_BIG_ENDIAN, &too_many),
764 Err(ProgramError::InvalidArgument)
765 );
766 }
767
768 #[cfg(feature = "crypto-bn254")]
769 #[test]
770 fn bn254_rejects_bad_input_lengths() {
771 let oversized_add = [0u8; ALT_BN128_G1_ADDITION_INPUT_SIZE + 1];
772 let bad_pairing = [0u8; ALT_BN128_PAIRING_ELEMENT_SIZE + 1];
773
774 assert_eq!(
775 alt_bn128_g1_addition_be(&oversized_add),
776 Err(ProgramError::InvalidArgument)
777 );
778 assert_eq!(
779 alt_bn128_pairing_be(&bad_pairing),
780 Err(ProgramError::InvalidArgument)
781 );
782 }
783
784 #[cfg(feature = "crypto-big-mod-exp")]
785 #[test]
786 fn big_mod_exp_requires_output_matching_modulus() {
787 let mut output = [0u8; 1];
788 let mut empty_output = [];
789
790 assert_eq!(
791 big_mod_exp(&[1], &[1], &[1, 2], &mut output),
792 Err(ProgramError::InvalidArgument)
793 );
794 assert_eq!(
795 big_mod_exp(&[1], &[1], &[], &mut empty_output),
796 Err(ProgramError::InvalidArgument)
797 );
798 }
799}