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