b6f7f73
ZhenYi
refactor: reorganize configuration files and update module paths for improved structure
b6f7f73
use sha2::{Digest, Sha256};
use crate::server::errors::{AuthError, AuthResult};
use crate::server::http::challenge::types::{ChallengeResponse, PowProofRequest};
use crate::server::share::crypto;
pub fn pow_hash(challenge: &ChallengeResponse, nonce: u64, payload: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(b"pow.v1\n");
hasher.update(challenge.context.as_bytes());
hasher.update([0u8]);
hasher.update(challenge.difficulty.to_be_bytes());
hasher.update([0u8]);
hasher.update(challenge.issued_at.to_be_bytes());
hasher.update([0u8]);
hasher.update(challenge.expires_at.to_be_bytes());
hasher.update([0u8]);
hasher.update((payload.len() as u64).to_be_bytes());
hasher.update(payload);
hasher.update([0u8]);
hasher.update(nonce.to_be_bytes());
hasher.finalize().into()
}
pub fn meets_difficulty(hash: &[u8], difficulty: u32) -> bool {
let hash_bits = (hash.len() * 8) as u32;
if difficulty == 0 {
return true;
}
if difficulty > hash_bits {
return false;
}
let full_bytes = (difficulty / 8) as usize;
let remaining_bits = (difficulty % 8) as u8;
if !hash[..full_bytes].iter().all(|byte| *byte == 0) {
return false;
}
if remaining_bits == 0 {
return true;
}
if hash.len() <= full_bytes {
return false;
}
let mask = 0xffu8 << (8 - remaining_bits);
(hash[full_bytes] & mask) == 0
}
pub fn verify_pow(
challenge: &ChallengeResponse,
proof: &PowProofRequest,
expected_payload: &[u8],
) -> AuthResult<()> {
if crypto::now_secs() > challenge.expires_at {
return Err(AuthError::Expired);
}
if proof.payload != expected_payload {
return Err(AuthError::InvalidPayload);
}
let hash = pow_hash(challenge, proof.nonce, &proof.payload);
if !meets_difficulty(&hash, challenge.difficulty) {
return Err(AuthError::InvalidProof);
}
Ok(())
}