sp1_zkvm/syscalls/secp256r1.rs
1#[cfg(target_os = "zkvm")]
2use core::arch::asm;
3
4/// Adds two Secp256k1 points.
5///
6/// The result is stored in the first point.
7///
8/// ### Safety
9///
10/// The caller must ensure that `p` and `q` are valid pointers to data that is aligned along a four
11/// byte boundary. Additionally, the caller must ensure that `p` and `q` are valid points on the
12/// secp256k1 curve, and that `p` and `q` are not equal to each other.
13#[allow(unused_variables)]
14#[no_mangle]
15pub extern "C" fn syscall_secp256r1_add(p: *mut [u32; 16], q: *mut [u32; 16]) {
16 #[cfg(target_os = "zkvm")]
17 unsafe {
18 asm!(
19 "ecall",
20 in("t0") crate::syscalls::SECP256R1_ADD,
21 in("a0") p,
22 in("a1") q
23 );
24 }
25
26 #[cfg(not(target_os = "zkvm"))]
27 unreachable!()
28}
29
30/// Double a Secp256k1 point.
31///
32/// The result is stored in-place in the supplied buffer.
33///
34/// ### Safety
35///
36/// The caller must ensure that `p` is valid pointer to data that is aligned along a four byte
37/// boundary.
38#[allow(unused_variables)]
39#[no_mangle]
40pub extern "C" fn syscall_secp256r1_double(p: *mut [u32; 16]) {
41 #[cfg(target_os = "zkvm")]
42 unsafe {
43 asm!(
44 "ecall",
45 in("t0") crate::syscalls::SECP256R1_DOUBLE,
46 in("a0") p,
47 in("a1") 0
48 );
49 }
50
51 #[cfg(not(target_os = "zkvm"))]
52 unreachable!()
53}
54
55/// Decompresses a compressed Secp256k1 point.
56///
57/// The input array should be 64 bytes long, with the first 32 bytes containing the X coordinate in
58/// big-endian format. The second half of the input will be overwritten with the Y coordinate of the
59/// decompressed point in big-endian format using the point's parity (is_odd).
60///
61/// ### Safety
62///
63/// The caller must ensure that `point` is valid pointer to data that is aligned along a four byte
64/// boundary.
65#[allow(unused_variables)]
66#[no_mangle]
67pub extern "C" fn syscall_secp256r1_decompress(point: &mut [u8; 64], is_odd: bool) {
68 #[cfg(target_os = "zkvm")]
69 {
70 // Memory system/FpOps are little endian so we'll just flip the whole array before/after
71 point.reverse();
72 let p = point.as_mut_ptr();
73 unsafe {
74 asm!(
75 "ecall",
76 in("t0") crate::syscalls::SECP256R1_DECOMPRESS,
77 in("a0") p,
78 in("a1") is_odd as u8
79 );
80 }
81 point.reverse();
82 }
83
84 #[cfg(not(target_os = "zkvm"))]
85 unreachable!()
86}