seq_runtime/crypto/
ed25519.rs1use crate::seqstring::global_string;
4use crate::stack::{Stack, pop, push};
5use crate::value::Value;
6
7use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
8use aes_gcm::aead::OsRng;
13
14#[unsafe(no_mangle)]
29pub unsafe extern "C" fn patch_seq_crypto_ed25519_keypair(stack: Stack) -> Stack {
30 assert!(!stack.is_null(), "crypto.ed25519-keypair: stack is null");
31
32 let signing_key = SigningKey::generate(&mut OsRng);
33 let verifying_key = signing_key.verifying_key();
34
35 let private_hex = hex::encode(signing_key.to_bytes());
36 let public_hex = hex::encode(verifying_key.to_bytes());
37
38 let stack = unsafe { push(stack, Value::String(global_string(public_hex))) };
39 unsafe { push(stack, Value::String(global_string(private_hex))) }
40}
41
42#[unsafe(no_mangle)]
57pub unsafe extern "C" fn patch_seq_crypto_ed25519_sign(stack: Stack) -> Stack {
58 assert!(!stack.is_null(), "crypto.ed25519-sign: stack is null");
59
60 let (stack, key_val) = unsafe { pop(stack) };
61 let (stack, msg_val) = unsafe { pop(stack) };
62
63 match (msg_val, key_val) {
64 (Value::String(message), Value::String(private_key_hex)) => {
65 match ed25519_sign(message.as_bytes(), private_key_hex.as_str_or_empty()) {
67 Some(signature) => {
68 let stack = unsafe { push(stack, Value::String(global_string(signature))) };
69 unsafe { push(stack, Value::Bool(true)) }
70 }
71 None => {
72 let stack = unsafe { push(stack, Value::String(global_string(String::new()))) };
73 unsafe { push(stack, Value::Bool(false)) }
74 }
75 }
76 }
77 _ => panic!("crypto.ed25519-sign: expected String, String on stack"),
78 }
79}
80
81#[unsafe(no_mangle)]
96pub unsafe extern "C" fn patch_seq_crypto_ed25519_verify(stack: Stack) -> Stack {
97 assert!(!stack.is_null(), "crypto.ed25519-verify: stack is null");
98
99 let (stack, pubkey_val) = unsafe { pop(stack) };
100 let (stack, sig_val) = unsafe { pop(stack) };
101 let (stack, msg_val) = unsafe { pop(stack) };
102
103 match (msg_val, sig_val, pubkey_val) {
104 (Value::String(message), Value::String(signature_hex), Value::String(public_key_hex)) => {
105 let valid = ed25519_verify(
107 message.as_bytes(),
108 signature_hex.as_str_or_empty(),
109 public_key_hex.as_str_or_empty(),
110 );
111 unsafe { push(stack, Value::Bool(valid)) }
112 }
113 _ => panic!("crypto.ed25519-verify: expected String, String, String on stack"),
114 }
115}
116
117pub(super) fn ed25519_sign(message: &[u8], private_key_hex: &str) -> Option<String> {
122 let key_bytes = hex::decode(private_key_hex).ok()?;
123 if key_bytes.len() != 32 {
124 return None;
125 }
126
127 let key_array: [u8; 32] = key_bytes.try_into().ok()?;
128 let signing_key = SigningKey::from_bytes(&key_array);
129 let signature = signing_key.sign(message);
130
131 Some(hex::encode(signature.to_bytes()))
132}
133
134pub(super) fn ed25519_verify(message: &[u8], signature_hex: &str, public_key_hex: &str) -> bool {
136 let verify_inner = || -> Option<bool> {
137 let sig_bytes = hex::decode(signature_hex).ok()?;
138 if sig_bytes.len() != 64 {
139 return Some(false);
140 }
141
142 let pubkey_bytes = hex::decode(public_key_hex).ok()?;
143 if pubkey_bytes.len() != 32 {
144 return Some(false);
145 }
146
147 let sig_array: [u8; 64] = sig_bytes.try_into().ok()?;
148 let pubkey_array: [u8; 32] = pubkey_bytes.try_into().ok()?;
149
150 let signature = Signature::from_bytes(&sig_array);
151 let verifying_key = VerifyingKey::from_bytes(&pubkey_array).ok()?;
152
153 Some(verifying_key.verify(message, &signature).is_ok())
154 };
155
156 verify_inner().unwrap_or(false)
157}