1solana_pubkey::declare_id!("Secp256r1SigVerify1111111111111111111111111");
13
14use bytemuck::{Pod, Zeroable};
15
16#[derive(Default, Debug, Copy, Clone, Zeroable, Pod, Eq, PartialEq)]
17#[repr(C)]
18pub struct Secp256r1SignatureOffsets {
19 pub signature_offset: u16,
21
22 pub signature_instruction_index: u16,
24
25 pub public_key_offset: u16,
27
28 pub public_key_instruction_index: u16,
30
31 pub message_data_offset: u16,
33
34 pub message_data_size: u16,
36
37 pub message_instruction_index: u16,
39}
40
41#[cfg(all(not(target_arch = "wasm32"), not(target_os = "solana")))]
42mod target_arch {
43 use {
44 crate::Secp256r1SignatureOffsets,
45 bytemuck::bytes_of,
46 openssl::{
47 bn::{BigNum, BigNumContext},
48 ec::{EcGroup, EcKey, EcPoint},
49 ecdsa::EcdsaSig,
50 nid::Nid,
51 pkey::{PKey, Private},
52 sign::{Signer, Verifier},
53 },
54 solana_feature_set::FeatureSet,
55 solana_instruction::Instruction,
56 solana_precompile_error::PrecompileError,
57 };
58
59 pub const COMPRESSED_PUBKEY_SERIALIZED_SIZE: usize = 33;
60 pub const SIGNATURE_SERIALIZED_SIZE: usize = 64;
61 pub const SIGNATURE_OFFSETS_SERIALIZED_SIZE: usize = 14;
62 pub const SIGNATURE_OFFSETS_START: usize = 2;
63 pub const DATA_START: usize = SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START;
64
65 pub const SECP256R1_ORDER: [u8; FIELD_SIZE] = [
67 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
68 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63,
69 0x25, 0x51,
70 ];
71
72 pub const SECP256R1_ORDER_MINUS_ONE: [u8; FIELD_SIZE] = [
74 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
75 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63,
76 0x25, 0x50,
77 ];
78
79 const SECP256R1_HALF_ORDER: [u8; FIELD_SIZE] = [
81 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
82 0xFF, 0xDE, 0x73, 0x7D, 0x56, 0xD3, 0x8B, 0xCF, 0x42, 0x79, 0xDC, 0xE5, 0x61, 0x7E, 0x31,
83 0x92, 0xA8,
84 ];
85 const FIELD_SIZE: usize = 32;
87
88 pub fn new_secp256r1_instruction(
89 message: &[u8],
90 signing_key: EcKey<Private>,
91 ) -> Result<Instruction, Box<dyn std::error::Error>> {
92 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)?;
93 if signing_key.group().curve_name() != Some(Nid::X9_62_PRIME256V1) {
94 return Err(("Signing key must be on the secp256r1 curve".to_string()).into());
95 }
96
97 let mut ctx = BigNumContext::new()?;
98 let pubkey = signing_key.public_key().to_bytes(
99 &group,
100 openssl::ec::PointConversionForm::COMPRESSED,
101 &mut ctx,
102 )?;
103
104 let signing_key_pkey = PKey::from_ec_key(signing_key)?;
105
106 let mut signer = Signer::new(openssl::hash::MessageDigest::sha256(), &signing_key_pkey)?;
107 signer.update(message)?;
108 let signature = signer.sign_to_vec()?;
109
110 let ecdsa_sig = EcdsaSig::from_der(&signature)?;
111 let r = ecdsa_sig.r().to_vec();
112 let s = ecdsa_sig.s().to_vec();
113 let mut signature = vec![0u8; SIGNATURE_SERIALIZED_SIZE];
114
115 let mut padded_r = vec![0u8; FIELD_SIZE];
117 let mut padded_s = vec![0u8; FIELD_SIZE];
118 padded_r[FIELD_SIZE.saturating_sub(r.len())..].copy_from_slice(&r);
119 padded_s[FIELD_SIZE.saturating_sub(s.len())..].copy_from_slice(&s);
120
121 signature[..FIELD_SIZE].copy_from_slice(&padded_r);
122 signature[FIELD_SIZE..].copy_from_slice(&padded_s);
123
124 let s_bignum = BigNum::from_slice(&s)?;
126 let half_order = BigNum::from_slice(&SECP256R1_HALF_ORDER)?;
127 let order = BigNum::from_slice(&SECP256R1_ORDER)?;
128 if s_bignum > half_order {
129 let mut new_s = BigNum::new()?;
130 new_s.checked_sub(&order, &s_bignum)?;
131 let new_s_bytes = new_s.to_vec();
132
133 let mut new_padded_s = vec![0u8; FIELD_SIZE];
135 new_padded_s[FIELD_SIZE.saturating_sub(new_s_bytes.len())..]
136 .copy_from_slice(&new_s_bytes);
137
138 signature[FIELD_SIZE..].copy_from_slice(&new_padded_s);
139 }
140
141 assert_eq!(pubkey.len(), COMPRESSED_PUBKEY_SERIALIZED_SIZE);
142 assert_eq!(signature.len(), SIGNATURE_SERIALIZED_SIZE);
143
144 let mut instruction_data = Vec::with_capacity(
145 DATA_START
146 .saturating_add(SIGNATURE_SERIALIZED_SIZE)
147 .saturating_add(COMPRESSED_PUBKEY_SERIALIZED_SIZE)
148 .saturating_add(message.len()),
149 );
150
151 let num_signatures: u8 = 1;
152 let public_key_offset = DATA_START;
153 let signature_offset = public_key_offset.saturating_add(COMPRESSED_PUBKEY_SERIALIZED_SIZE);
154 let message_data_offset = signature_offset.saturating_add(SIGNATURE_SERIALIZED_SIZE);
155
156 instruction_data.extend_from_slice(bytes_of(&[num_signatures, 0]));
157
158 let offsets = Secp256r1SignatureOffsets {
159 signature_offset: signature_offset as u16,
160 signature_instruction_index: u16::MAX,
161 public_key_offset: public_key_offset as u16,
162 public_key_instruction_index: u16::MAX,
163 message_data_offset: message_data_offset as u16,
164 message_data_size: message.len() as u16,
165 message_instruction_index: u16::MAX,
166 };
167
168 instruction_data.extend_from_slice(bytes_of(&offsets));
169 instruction_data.extend_from_slice(&pubkey);
170 instruction_data.extend_from_slice(&signature);
171 instruction_data.extend_from_slice(message);
172
173 Ok(Instruction {
174 program_id: crate::id(),
175 accounts: vec![],
176 data: instruction_data,
177 })
178 }
179
180 pub fn verify(
181 data: &[u8],
182 instruction_datas: &[&[u8]],
183 _feature_set: &FeatureSet,
184 ) -> Result<(), PrecompileError> {
185 if data.len() < SIGNATURE_OFFSETS_START {
186 return Err(PrecompileError::InvalidInstructionDataSize);
187 }
188 let num_signatures = data[0] as usize;
189 if num_signatures == 0 {
190 return Err(PrecompileError::InvalidInstructionDataSize);
191 }
192 if num_signatures > 8 {
193 return Err(PrecompileError::InvalidInstructionDataSize);
194 }
195
196 let expected_data_size = num_signatures
197 .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE)
198 .saturating_add(SIGNATURE_OFFSETS_START);
199
200 if data.len() < expected_data_size {
202 return Err(PrecompileError::InvalidInstructionDataSize);
203 }
204
205 let half_order: BigNum = BigNum::from_slice(&SECP256R1_HALF_ORDER)
207 .map_err(|_| PrecompileError::InvalidSignature)?;
208
209 let order_minus_one: BigNum = BigNum::from_slice(&SECP256R1_ORDER_MINUS_ONE)
211 .map_err(|_| PrecompileError::InvalidSignature)?;
212
213 let one = BigNum::from_u32(1).map_err(|_| PrecompileError::InvalidSignature)?;
215
216 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)
218 .map_err(|_| PrecompileError::InvalidSignature)?;
219 let mut ctx = BigNumContext::new().map_err(|_| PrecompileError::InvalidSignature)?;
220
221 for i in 0..num_signatures {
222 let start = i
223 .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE)
224 .saturating_add(SIGNATURE_OFFSETS_START);
225 let end = start.saturating_add(SIGNATURE_OFFSETS_SERIALIZED_SIZE);
226
227 let offsets: &Secp256r1SignatureOffsets =
229 bytemuck::try_from_bytes(&data[start..end])
230 .map_err(|_| PrecompileError::InvalidDataOffsets)?;
231
232 let signature = get_data_slice(
234 data,
235 instruction_datas,
236 offsets.signature_instruction_index,
237 offsets.signature_offset,
238 SIGNATURE_SERIALIZED_SIZE,
239 )?;
240
241 let pubkey = get_data_slice(
243 data,
244 instruction_datas,
245 offsets.public_key_instruction_index,
246 offsets.public_key_offset,
247 COMPRESSED_PUBKEY_SERIALIZED_SIZE,
248 )?;
249
250 let message = get_data_slice(
252 data,
253 instruction_datas,
254 offsets.message_instruction_index,
255 offsets.message_data_offset,
256 offsets.message_data_size as usize,
257 )?;
258
259 let r_bignum = BigNum::from_slice(&signature[..FIELD_SIZE])
260 .map_err(|_| PrecompileError::InvalidSignature)?;
261 let s_bignum = BigNum::from_slice(&signature[FIELD_SIZE..])
262 .map_err(|_| PrecompileError::InvalidSignature)?;
263
264 let within_range = r_bignum >= one
266 && r_bignum <= order_minus_one
267 && s_bignum >= one
268 && s_bignum <= half_order;
269
270 if !within_range {
271 return Err(PrecompileError::InvalidSignature);
272 }
273
274 let ecdsa_sig = openssl::ecdsa::EcdsaSig::from_private_components(r_bignum, s_bignum)
276 .and_then(|sig| sig.to_der())
277 .map_err(|_| PrecompileError::InvalidSignature)?;
278
279 let public_key_point = EcPoint::from_bytes(&group, pubkey, &mut ctx)
280 .map_err(|_| PrecompileError::InvalidPublicKey)?;
281 let public_key = EcKey::from_public_key(&group, &public_key_point)
282 .map_err(|_| PrecompileError::InvalidPublicKey)?;
283 let public_key_as_pkey =
284 PKey::from_ec_key(public_key).map_err(|_| PrecompileError::InvalidPublicKey)?;
285
286 let mut verifier =
287 Verifier::new(openssl::hash::MessageDigest::sha256(), &public_key_as_pkey)
288 .map_err(|_| PrecompileError::InvalidSignature)?;
289 verifier
290 .update(message)
291 .map_err(|_| PrecompileError::InvalidSignature)?;
292
293 if !verifier
294 .verify(&ecdsa_sig)
295 .map_err(|_| PrecompileError::InvalidSignature)?
296 {
297 return Err(PrecompileError::InvalidSignature);
298 }
299 }
300 Ok(())
301 }
302
303 fn get_data_slice<'a>(
304 data: &'a [u8],
305 instruction_datas: &'a [&[u8]],
306 instruction_index: u16,
307 offset_start: u16,
308 size: usize,
309 ) -> Result<&'a [u8], PrecompileError> {
310 let instruction = if instruction_index == u16::MAX {
311 data
312 } else {
313 let signature_index = instruction_index as usize;
314 if signature_index >= instruction_datas.len() {
315 return Err(PrecompileError::InvalidDataOffsets);
316 }
317 instruction_datas[signature_index]
318 };
319
320 let start = offset_start as usize;
321 let end = start.saturating_add(size);
322 if end > instruction.len() {
323 return Err(PrecompileError::InvalidDataOffsets);
324 }
325
326 Ok(&instruction[start..end])
327 }
328
329 #[cfg(test)]
330 mod test {
331 use {
332 super::*,
333 solana_feature_set::FeatureSet,
334 solana_sdk::{
335 hash::Hash,
336 signature::{Keypair, Signer},
337 transaction::Transaction,
338 },
339 };
340
341 fn test_case(
342 num_signatures: u16,
343 offsets: &Secp256r1SignatureOffsets,
344 ) -> Result<(), PrecompileError> {
345 assert_eq!(
346 bytemuck::bytes_of(offsets).len(),
347 SIGNATURE_OFFSETS_SERIALIZED_SIZE
348 );
349
350 let mut instruction_data = vec![0u8; DATA_START];
351 instruction_data[0..SIGNATURE_OFFSETS_START].copy_from_slice(bytes_of(&num_signatures));
352 instruction_data[SIGNATURE_OFFSETS_START..DATA_START]
353 .copy_from_slice(bytes_of(offsets));
354 verify(
355 &instruction_data,
356 &[&[0u8; 100]],
357 &FeatureSet::all_enabled(),
358 )
359 }
360
361 #[test]
362 fn test_invalid_offsets() {
363 solana_logger::setup();
364
365 let mut instruction_data = vec![0u8; DATA_START];
366 let offsets = Secp256r1SignatureOffsets::default();
367 instruction_data[0..SIGNATURE_OFFSETS_START].copy_from_slice(bytes_of(&1u16));
368 instruction_data[SIGNATURE_OFFSETS_START..DATA_START]
369 .copy_from_slice(bytes_of(&offsets));
370 instruction_data.truncate(instruction_data.len() - 1);
371
372 assert_eq!(
373 verify(
374 &instruction_data,
375 &[&[0u8; 100]],
376 &FeatureSet::all_enabled()
377 ),
378 Err(PrecompileError::InvalidInstructionDataSize)
379 );
380
381 let offsets = Secp256r1SignatureOffsets {
382 signature_instruction_index: 1,
383 ..Secp256r1SignatureOffsets::default()
384 };
385 assert_eq!(
386 test_case(1, &offsets),
387 Err(PrecompileError::InvalidDataOffsets)
388 );
389
390 let offsets = Secp256r1SignatureOffsets {
391 message_instruction_index: 1,
392 ..Secp256r1SignatureOffsets::default()
393 };
394 assert_eq!(
395 test_case(1, &offsets),
396 Err(PrecompileError::InvalidDataOffsets)
397 );
398
399 let offsets = Secp256r1SignatureOffsets {
400 public_key_instruction_index: 1,
401 ..Secp256r1SignatureOffsets::default()
402 };
403 assert_eq!(
404 test_case(1, &offsets),
405 Err(PrecompileError::InvalidDataOffsets)
406 );
407 }
408
409 #[test]
410 fn test_invalid_signature_data_size() {
411 solana_logger::setup();
412
413 let small_data = vec![0u8; SIGNATURE_OFFSETS_START - 1];
415 assert_eq!(
416 verify(&small_data, &[&[]], &FeatureSet::all_enabled()),
417 Err(PrecompileError::InvalidInstructionDataSize)
418 );
419
420 let mut zero_sigs_data = vec![0u8; DATA_START];
422 zero_sigs_data[0] = 0; assert_eq!(
424 verify(&zero_sigs_data, &[&[]], &FeatureSet::all_enabled()),
425 Err(PrecompileError::InvalidInstructionDataSize)
426 );
427
428 let mut too_many_sigs = vec![0u8; DATA_START];
430 too_many_sigs[0] = 9; assert_eq!(
432 verify(&too_many_sigs, &[&[]], &FeatureSet::all_enabled()),
433 Err(PrecompileError::InvalidInstructionDataSize)
434 );
435 }
436 #[test]
437 fn test_message_data_offsets() {
438 let offsets = Secp256r1SignatureOffsets {
439 message_data_offset: 99,
440 message_data_size: 1,
441 ..Secp256r1SignatureOffsets::default()
442 };
443 assert_eq!(
444 test_case(1, &offsets),
445 Err(PrecompileError::InvalidSignature)
446 );
447
448 let offsets = Secp256r1SignatureOffsets {
449 message_data_offset: 100,
450 message_data_size: 1,
451 ..Secp256r1SignatureOffsets::default()
452 };
453 assert_eq!(
454 test_case(1, &offsets),
455 Err(PrecompileError::InvalidDataOffsets)
456 );
457
458 let offsets = Secp256r1SignatureOffsets {
459 message_data_offset: 100,
460 message_data_size: 1000,
461 ..Secp256r1SignatureOffsets::default()
462 };
463 assert_eq!(
464 test_case(1, &offsets),
465 Err(PrecompileError::InvalidDataOffsets)
466 );
467
468 let offsets = Secp256r1SignatureOffsets {
469 message_data_offset: u16::MAX,
470 message_data_size: u16::MAX,
471 ..Secp256r1SignatureOffsets::default()
472 };
473 assert_eq!(
474 test_case(1, &offsets),
475 Err(PrecompileError::InvalidDataOffsets)
476 );
477 }
478
479 #[test]
480 fn test_pubkey_offset() {
481 let offsets = Secp256r1SignatureOffsets {
482 public_key_offset: u16::MAX,
483 ..Secp256r1SignatureOffsets::default()
484 };
485 assert_eq!(
486 test_case(1, &offsets),
487 Err(PrecompileError::InvalidDataOffsets)
488 );
489
490 let offsets = Secp256r1SignatureOffsets {
491 public_key_offset: 100 - (COMPRESSED_PUBKEY_SERIALIZED_SIZE as u16) + 1,
492 ..Secp256r1SignatureOffsets::default()
493 };
494 assert_eq!(
495 test_case(1, &offsets),
496 Err(PrecompileError::InvalidDataOffsets)
497 );
498 }
499
500 #[test]
501 fn test_signature_offset() {
502 let offsets = Secp256r1SignatureOffsets {
503 signature_offset: u16::MAX,
504 ..Secp256r1SignatureOffsets::default()
505 };
506 assert_eq!(
507 test_case(1, &offsets),
508 Err(PrecompileError::InvalidDataOffsets)
509 );
510
511 let offsets = Secp256r1SignatureOffsets {
512 signature_offset: 100 - (SIGNATURE_SERIALIZED_SIZE as u16) + 1,
513 ..Secp256r1SignatureOffsets::default()
514 };
515 assert_eq!(
516 test_case(1, &offsets),
517 Err(PrecompileError::InvalidDataOffsets)
518 );
519 }
520
521 #[test]
522 fn test_secp256r1() {
523 solana_logger::setup();
524 let message_arr = b"hello";
525 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
526 let signing_key = EcKey::generate(&group).unwrap();
527 let mut instruction = new_secp256r1_instruction(message_arr, signing_key).unwrap();
528 let mint_keypair = Keypair::new();
529 let feature_set = FeatureSet::all_enabled();
530
531 let tx = Transaction::new_signed_with_payer(
532 &[instruction.clone()],
533 Some(&mint_keypair.pubkey()),
534 &[&mint_keypair],
535 Hash::default(),
536 );
537
538 assert!(tx.verify_precompiles(&feature_set).is_ok());
539
540 let message_byte_index = instruction.data.len() - 1;
543 instruction.data[message_byte_index] =
544 instruction.data[message_byte_index].wrapping_add(12);
545 let tx = Transaction::new_signed_with_payer(
546 &[instruction.clone()],
547 Some(&mint_keypair.pubkey()),
548 &[&mint_keypair],
549 Hash::default(),
550 );
551
552 assert!(tx.verify_precompiles(&feature_set).is_err());
553 }
554
555 #[test]
556 fn test_secp256r1_high_s() {
557 solana_logger::setup();
558 let message_arr = b"hello";
559 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
560 let signing_key = EcKey::generate(&group).unwrap();
561 let mut instruction = new_secp256r1_instruction(message_arr, signing_key).unwrap();
562
563 let feature_set = FeatureSet::all_enabled();
565 let tx_pass = verify(
566 instruction.data.as_slice(),
567 &[instruction.data.as_slice()],
568 &feature_set,
569 );
570 assert!(tx_pass.is_ok());
571
572 let public_key_offset = DATA_START;
574 let signature_offset = public_key_offset + COMPRESSED_PUBKEY_SERIALIZED_SIZE;
575 let s_offset = signature_offset + FIELD_SIZE;
576
577 let order = BigNum::from_slice(&SECP256R1_ORDER).unwrap();
579 let current_s =
580 BigNum::from_slice(&instruction.data[s_offset..s_offset + FIELD_SIZE]).unwrap();
581 let mut high_s = BigNum::new().unwrap();
582 high_s.checked_sub(&order, ¤t_s).unwrap();
583
584 instruction.data[s_offset..s_offset + FIELD_SIZE].copy_from_slice(&high_s.to_vec());
586
587 let tx_fail = verify(
592 instruction.data.as_slice(),
593 &[instruction.data.as_slice()],
594 &feature_set,
595 );
596 assert!(tx_fail.unwrap_err() == PrecompileError::InvalidSignature);
597 }
598 #[test]
599 fn test_new_secp256r1_instruction_31byte_components() {
600 solana_logger::setup();
601 let message_arr = b"hello";
602 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
603 let signing_key = EcKey::generate(&group).unwrap();
604
605 loop {
607 let instruction =
608 new_secp256r1_instruction(message_arr, signing_key.clone()).unwrap();
609
610 let signature_offset = DATA_START + COMPRESSED_PUBKEY_SERIALIZED_SIZE;
612 let r = &instruction.data[signature_offset..signature_offset + FIELD_SIZE];
613 let s = &instruction.data
614 [signature_offset + FIELD_SIZE..signature_offset + 2 * FIELD_SIZE];
615
616 let r_bn = BigNum::from_slice(r).unwrap();
618 let s_bn = BigNum::from_slice(s).unwrap();
619 let r_bytes = r_bn.to_vec();
620 let s_bytes = s_bn.to_vec();
621
622 if r_bytes.len() == 31 || s_bytes.len() == 31 {
623 let mint_keypair = Keypair::new();
625 let tx = Transaction::new_signed_with_payer(
626 &[instruction],
627 Some(&mint_keypair.pubkey()),
628 &[&mint_keypair],
629 Hash::default(),
630 );
631
632 let feature_set = FeatureSet::all_enabled();
633 assert!(tx.verify_precompiles(&feature_set).is_ok());
634 break;
635 }
636 }
637 }
638
639 #[test]
640 fn test_new_secp256r1_instruction_signing_key() {
641 solana_logger::setup();
642 let message_arr = b"hello";
643 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
644 let signing_key = EcKey::generate(&group).unwrap();
645 assert!(new_secp256r1_instruction(message_arr, signing_key).is_ok());
646
647 let incorrect_group = EcGroup::from_curve_name(Nid::X9_62_PRIME192V1).unwrap();
648 let incorrect_key = EcKey::generate(&incorrect_group).unwrap();
649 assert!(new_secp256r1_instruction(message_arr, incorrect_key).is_err());
650 }
651 #[test]
652 fn test_secp256r1_order() {
653 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
654 let mut ctx = BigNumContext::new().unwrap();
655 let mut openssl_order = BigNum::new().unwrap();
656 group.order(&mut openssl_order, &mut ctx).unwrap();
657
658 let our_order = BigNum::from_slice(&SECP256R1_ORDER).unwrap();
659 assert_eq!(our_order, openssl_order);
660 }
661
662 #[test]
663 fn test_secp256r1_order_minus_one() {
664 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
665 let mut ctx = BigNumContext::new().unwrap();
666 let mut openssl_order = BigNum::new().unwrap();
667 group.order(&mut openssl_order, &mut ctx).unwrap();
668
669 let mut expected_order_minus_one = BigNum::new().unwrap();
670 expected_order_minus_one
671 .checked_sub(&openssl_order, &BigNum::from_u32(1).unwrap())
672 .unwrap();
673
674 let our_order_minus_one = BigNum::from_slice(&SECP256R1_ORDER_MINUS_ONE).unwrap();
675 assert_eq!(our_order_minus_one, expected_order_minus_one);
676 }
677
678 #[test]
679 fn test_secp256r1_half_order() {
680 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
682
683 let mut ctx = BigNumContext::new().unwrap();
685 let mut openssl_order = BigNum::new().unwrap();
686 group.order(&mut openssl_order, &mut ctx).unwrap();
687
688 let mut calculated_half_order = BigNum::new().unwrap();
690 let two = BigNum::from_u32(2).unwrap();
691 calculated_half_order
692 .checked_div(&openssl_order, &two, &mut ctx)
693 .unwrap();
694
695 let our_half_order = BigNum::from_slice(&SECP256R1_HALF_ORDER).unwrap();
697
698 assert_eq!(calculated_half_order, our_half_order);
700 }
701
702 #[test]
703 fn test_secp256r1_order_relationships() {
704 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
705 let mut ctx = BigNumContext::new().unwrap();
706 let mut openssl_order = BigNum::new().unwrap();
707 group.order(&mut openssl_order, &mut ctx).unwrap();
708
709 let our_order = BigNum::from_slice(&SECP256R1_ORDER).unwrap();
710 let our_order_minus_one = BigNum::from_slice(&SECP256R1_ORDER_MINUS_ONE).unwrap();
711 let our_half_order = BigNum::from_slice(&SECP256R1_HALF_ORDER).unwrap();
712
713 assert_eq!(our_order, openssl_order);
715
716 let mut expected_order_minus_one = BigNum::new().unwrap();
718 expected_order_minus_one
719 .checked_sub(&openssl_order, &BigNum::from_u32(1).unwrap())
720 .unwrap();
721 assert_eq!(our_order_minus_one, expected_order_minus_one);
722
723 let mut expected_half_order = BigNum::new().unwrap();
725 expected_half_order
726 .checked_div(&openssl_order, &BigNum::from_u32(2).unwrap(), &mut ctx)
727 .unwrap();
728 assert_eq!(our_half_order, expected_half_order);
729
730 let mut double_half_order = BigNum::new().unwrap();
732 double_half_order
733 .checked_mul(&our_half_order, &BigNum::from_u32(2).unwrap(), &mut ctx)
734 .unwrap();
735 assert_eq!(double_half_order, expected_order_minus_one);
736 }
737 }
738}
739
740#[cfg(any(target_arch = "wasm32", target_os = "solana"))]
741mod target_arch {
742 use {solana_feature_set::FeatureSet, solana_precompile_error::PrecompileError};
743
744 pub fn verify(
745 _data: &[u8],
746 _instruction_datas: &[&[u8]],
747 _feature_set: &FeatureSet,
748 ) -> Result<(), PrecompileError> {
749 Err(PrecompileError::InvalidSignature)
750 }
751}
752
753pub use self::target_arch::*;