fluentbase_runtime/syscall_handler/edwards/
edwards_decompress.rs1use crate::{syscall_handler::syscall_process_exit_code, RuntimeContext};
7use fluentbase_types::{ExitCode, ED25519_POINT_COMPRESSED_SIZE, ED25519_POINT_DECOMPRESSED_SIZE};
8use rwasm::{StoreTr, TrapCode, Value};
9use sp1_curves::{curve25519_dalek::CompressedEdwardsY, edwards::ed25519::decompress};
10
11pub fn syscall_ed25519_decompress_handler(
12 ctx: &mut impl StoreTr<RuntimeContext>,
13 params: &[Value],
14 _result: &mut [Value],
15) -> Result<(), TrapCode> {
16 let slice_ptr = params[0].i32().unwrap() as usize;
17 let sign = params[1].i32().unwrap() as u32;
18 let mut compressed_edwards_y = [0u8; ED25519_POINT_COMPRESSED_SIZE];
19 ctx.memory_read(
20 slice_ptr + ED25519_POINT_COMPRESSED_SIZE,
21 &mut compressed_edwards_y,
22 )?;
23 let decompressed_x_bytes = syscall_ed25519_decompress_impl(compressed_edwards_y, sign)
24 .map_err(|exit_code| syscall_process_exit_code(ctx, exit_code))?;
25 ctx.memory_write(slice_ptr, &decompressed_x_bytes)?;
26 Ok(())
27}
28
29pub fn syscall_ed25519_decompress_impl(
30 mut compressed_edwards_y: [u8; ED25519_POINT_COMPRESSED_SIZE],
31 sign: u32,
32) -> Result<[u8; ED25519_POINT_DECOMPRESSED_SIZE], ExitCode> {
33 if sign > 1 {
35 return Err(ExitCode::MalformedBuiltinParams);
36 }
37 let mut result = [0u8; ED25519_POINT_DECOMPRESSED_SIZE];
38 result[32..64].copy_from_slice(&compressed_edwards_y);
39 compressed_edwards_y[ED25519_POINT_COMPRESSED_SIZE - 1] &= 0b0111_1111;
41 compressed_edwards_y[ED25519_POINT_COMPRESSED_SIZE - 1] |= (sign as u8) << 7;
42 let compressed_y = CompressedEdwardsY(compressed_edwards_y);
44 let decompressed = match decompress(&compressed_y) {
45 Some(decompressed) => decompressed,
46 None => return Err(ExitCode::MalformedBuiltinParams),
47 };
48 let mut decompressed_x_bytes = decompressed.x.to_bytes_le();
49 decompressed_x_bytes.resize(32, 0u8);
50 result[0..32].copy_from_slice(decompressed_x_bytes.as_slice());
51 Ok(result)
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use fluentbase_types::hex;
58
59 #[test]
61 fn test_ed25519_decompress_sp1() {
62 let mut pub_bytes: [u8; 32] =
63 hex!("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf");
64 let sign = pub_bytes[31] >> 7;
65 pub_bytes[31] &= 0b0111_1111;
66 let decompressed = syscall_ed25519_decompress_impl(pub_bytes, sign as u32).unwrap();
67 let expected: [u8; 64] = [
68 47, 252, 114, 91, 153, 234, 110, 201, 201, 153, 152, 14, 68, 231, 90, 221, 137, 110,
69 250, 67, 10, 64, 37, 70, 163, 101, 111, 223, 185, 1, 180, 88, 236, 23, 43, 147, 173,
70 94, 86, 59, 244, 147, 44, 112, 225, 36, 80, 52, 195, 84, 103, 239, 46, 253, 77, 100,
71 235, 248, 25, 104, 52, 103, 226, 63,
72 ];
73 assert_eq!(hex::encode(decompressed), hex::encode(expected));
74 }
75
76 #[test]
82 fn test_ed25519_decompress_invalid_input_returns_error() {
83 let sign = 0;
84 let invalid_y: [u8; 32] =
86 hex!("0200000000000000000000000000000000000000000000000000000000000000");
87
88 let result = syscall_ed25519_decompress_impl(invalid_y, sign);
89
90 assert!(
91 result.is_err(),
92 "Expected error for invalid point, got: {:?}",
93 result
94 );
95 assert_eq!(result.unwrap_err(), ExitCode::MalformedBuiltinParams);
96 }
97}