gomcaptcha/mcaptcha-pow-ffi/src/lib.rs
Aravinth Manivannan 35bc3ceee0
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
feat: reuse init
2024-01-08 05:05:31 +05:30

161 lines
4.7 KiB
Rust

// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use mcaptcha_pow_sha256::ConfigBuilder;
use std::ffi::CStr;
use std::ffi::CString;
#[repr(C)]
pub struct ProofOfWork {
pub nonce: u64,
pub result: *const libc::c_char,
}
impl From<mcaptcha_pow_sha256::PoW<String>> for ProofOfWork {
fn from(value: mcaptcha_pow_sha256::PoW<String>) -> Self {
Self {
nonce: value.nonce,
result: CString::new(value.result).unwrap().into_raw(),
}
}
}
#[no_mangle]
pub extern "C" fn prove_work(
salt: *const libc::c_char,
phrase: *const libc::c_char,
difficulty: u32,
) -> ProofOfWork {
let (salt, phrase) = unsafe { (CStr::from_ptr(salt), CStr::from_ptr(phrase)) };
let salt = salt.to_str().unwrap();
let phrase = phrase.to_str().unwrap().to_string();
let config = ConfigBuilder::default()
.salt(salt.to_string())
.build()
.unwrap();
config.prove_work(&phrase, difficulty).unwrap().into()
}
#[no_mangle]
pub extern "C" fn is_valid_proof(
nonce: u64,
result: *const libc::c_char,
phrase: *const libc::c_char,
salt: *const libc::c_char,
) -> bool {
let (result, phrase, salt) = unsafe {
(
CStr::from_ptr(result),
CStr::from_ptr(phrase),
CStr::from_ptr(salt),
)
};
let result = result.to_str().unwrap().to_string();
let pow: mcaptcha_pow_sha256::PoW<String> = mcaptcha_pow_sha256::PoWBuilder::default()
.nonce(nonce)
.result(result)
.build()
.unwrap();
let config = ConfigBuilder::default()
.salt(salt.to_str().unwrap().to_string())
.build()
.unwrap();
config.is_valid_proof(&pow, &phrase.to_str().unwrap().to_string())
}
#[no_mangle]
pub extern "C" fn is_sufficient_difficulty(
nonce: u64,
result: *const libc::c_char,
salt: *const libc::c_char,
difficulty: u32,
) -> bool {
let (result, salt) = unsafe { (CStr::from_ptr(result), CStr::from_ptr(salt)) };
let result = result.to_str().unwrap().to_string();
let pow: mcaptcha_pow_sha256::PoW<String> = mcaptcha_pow_sha256::PoWBuilder::default()
.nonce(nonce)
.result(result)
.build()
.unwrap();
let config = ConfigBuilder::default()
.salt(salt.to_str().unwrap().to_string())
.build()
.unwrap();
config.is_sufficient_difficulty(&pow, difficulty)
}
#[cfg(test)]
pub mod test {
use super::*;
use std::ffi::CString;
#[test]
fn test_pow() {
let salt: String =
"27b7eb6be3437b7da0d9329dea9a7c76f1640cd16d39fd94b5d0dd42c763c63c".into();
let phrase: String =
"b641c711c01079805a2a0888bf716b66c83419ab0c65455a49cb4d8b3e36c4ec".into();
let difficulty = 50_000;
let c = mcaptcha_pow_sha256::ConfigBuilder::default()
.salt(salt.clone())
.build()
.unwrap();
// calculate pow
let mcaptcha_work = c.prove_work(&phrase, difficulty).unwrap();
let ffi_work = super::prove_work(
CString::new(salt.clone()).unwrap().into_raw(),
CString::new(phrase.clone()).unwrap().into_raw(),
difficulty,
);
assert_eq!(ffi_work.nonce, mcaptcha_work.nonce);
let res = unsafe { CStr::from_ptr(ffi_work.result) };
let res = res.to_str().unwrap();
assert_eq!(res, mcaptcha_work.result);
// verify pow
assert!(super::is_valid_proof(
mcaptcha_work.nonce,
CString::new(mcaptcha_work.result.clone())
.unwrap()
.into_raw(),
CString::new(phrase.clone()).unwrap().into_raw(),
CString::new(salt.clone()).unwrap().into_raw(),
));
assert!(!super::is_valid_proof(
mcaptcha_work.nonce,
CString::new(phrase.clone()).unwrap().into_raw(),
CString::new(phrase.clone()).unwrap().into_raw(),
CString::new(salt.clone()).unwrap().into_raw(),
));
// is sufficient difficulty
assert!(super::is_sufficient_difficulty(
mcaptcha_work.nonce,
CString::new(mcaptcha_work.result.clone())
.unwrap()
.into_raw(),
CString::new(salt.clone()).unwrap().into_raw(),
difficulty
));
// is sufficient difficulty
assert!(super::is_sufficient_difficulty(
mcaptcha_work.nonce,
CString::new(mcaptcha_work.result.clone())
.unwrap()
.into_raw(),
CString::new(salt.clone()).unwrap().into_raw(),
difficulty
));
}
}