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