Aravinth Manivannan
35bc3ceee0
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
161 lines
4.7 KiB
Rust
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
|
|
));
|
|
}
|
|
}
|