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}