pub struct IronShieldChallenge {
pub random_nonce: String,
pub created_time: i64,
pub expiration_time: i64,
pub website_id: String,
pub challenge_param: [u8; 32],
pub recommended_attempts: u64,
pub public_key: [u8; 32],
pub challenge_signature: [u8; 64],
}Expand description
IronShield Challenge structure for the proof-of-work algorithm
random_nonce: The SHA-256 hash of a random number (hex string).created_time: Unix milli timestamp for the challenge.expiration_time: Unix milli timestamp for the challenge expiration time.challenge_param: Target threshold - hash must be less than this value.recommended_attempts: Expected number of attempts for user guidance (3x difficulty).website_id: The identifier of the website.public_key: Ed25519 public key for signature verification.challenge_signature: Ed25519 signature over the challenge data.
Fields§
§random_nonce: String§created_time: i64§expiration_time: i64§website_id: String§challenge_param: [u8; 32]§recommended_attempts: u64§public_key: [u8; 32]§challenge_signature: [u8; 64]Implementations§
Source§impl IronShieldChallenge
impl IronShieldChallenge
Sourcepub fn new(
website_id: String,
difficulty: u64,
private_key: SigningKey,
public_key: [u8; 32],
) -> Self
pub fn new( website_id: String, difficulty: u64, private_key: SigningKey, public_key: [u8; 32], ) -> Self
Constructor for creating a new IronShieldChallenge instance.
This function creates a new challenge and automatically generates a cryptographic signature using the provided private key. The signature covers all challenge data to prevent tampering.
§Arguments
website_id: The identifier of the website.difficulty: The target difficulty (expected number of attempts).private_key: Ed25519 private key for signing the challenge.public_key: Ed25519 public key corresponding to the private key.
§Returns
Self: A new, properly signed IronShieldChallenge.
Sourcepub fn difficulty_to_challenge_param(difficulty: u64) -> [u8; 32]
pub fn difficulty_to_challenge_param(difficulty: u64) -> [u8; 32]
Converts a difficulty value (expected number of attempts) to a challenge_param.
The difficulty represents the expected number of hash attempts needed to find a valid nonce where SHA256(random_nonce_bytes + nonce_bytes) < challenge_param.
Since hash outputs are uniformly distributed over the 256-bit space, the relationship is: challenge_param = 2^256 / difficulty.
This function accurately calculates this for difficulties ranging from 1 to u64::MAX.
§Arguments
difficulty: Expected number of attempts (must be > 0).
§Returns
[u8; 32]: The challenge_param bytes in big-endian format.
§Panics
- Panics if difficulty is 0
§Examples
- difficulty = 1 -> challenge_param = [0xFF; 32] (very easy, ~100% chance).
- difficulty = 2 -> challenge_param = [0x80, 0x00, …] (MSB set, ~50% chance).
- difficulty = 10,000 -> challenge_param ≈ 2^242.7 (realistic difficulty).
- difficulty = 1,000,000 -> challenge_param ≈ 2^236.4 (higher difficulty).
Sourcepub fn is_expired(&self) -> bool
pub fn is_expired(&self) -> bool
§Returns
bool:trueif the challenge is expired,falseotherwise.
Sourcepub fn time_until_expiration(&self) -> i64
pub fn time_until_expiration(&self) -> i64
§Returns
i64:created_timeplus 30 seconds.
Sourcepub fn generate_created_time() -> i64
pub fn generate_created_time() -> i64
§Returns
i64: The current time in millis.
Sourcepub fn generate_random_nonce() -> String
pub fn generate_random_nonce() -> String
§Returns
String: A random hex-encoded value.
Sourcepub fn recommended_attempts(difficulty: u64) -> u64
pub fn recommended_attempts(difficulty: u64) -> u64
Returns the recommended number of attempts to expect for a given difficulty.
This provides users with a realistic expectation of how many attempts they might need. Since the expected value is equal to the difficulty, we return 2x the difficulty to give users a reasonable upper bound for planning purposes.
§Arguments
difficulty: The target difficulty (expected number of attempts)
§Returns
u64: Recommended number of attempts (2x the difficulty)
§Examples
- difficulty = 1,000 → recommended_attempts = 2,000
- difficulty = 50,000 → recommended_attempts = 100,000
Sourcepub fn concat_struct(&self) -> String
pub fn concat_struct(&self) -> String
Concatenates the challenge data into a string.
Concatenates:
random_nonceas a string.created_timeasi64.expiration_timeasi64.website_idas a string.public_keyas a lowercase hex string.challenge_paramsas a lowercase hex string.
Sourcepub fn from_concat_struct(concat_str: &str) -> Result<Self, String>
pub fn from_concat_struct(concat_str: &str) -> Result<Self, String>
Creates an IronShieldChallenge from a concatenated string.
This function reverses the operation of
IronShieldChallenge::concat_struct.
Expects a string in the format:
“random_nonce|created_time|expiration_time|website_id|challenge_params|public_key|challenge_signature”
§Arguments
concat_str: The concatenated string to parse, typically generated byconcat_struct().
§Returns
Result<Self, String>: A result containing the parsedIronShieldChallengeor an error message if parsing fails.
Sourcepub fn to_base64url_header(&self) -> String
pub fn to_base64url_header(&self) -> String
Encodes the challenge as a base64url string for HTTP header transport.
This method concatenates all challenge fields using the established | delimiter
format, and then base64url-encodes the result for safe transport in HTTP headers.
§Returns
String: Base64url-encoded string ready for HTTP header use.
§Example
use ironshield_types::IronShieldChallenge;
use ed25519_dalek::SigningKey;
let dummy_key = SigningKey::from_bytes(&[0u8; 32]);
let challenge = IronShieldChallenge::new(
"test_website".to_string(),
100_000,
dummy_key,
[0x34; 32],
);
let header_value = challenge.to_base64url_header();
// Use header_value in HTTP header: "X-IronShield-Challenge-Data: {header_value}"Sourcepub fn from_base64url_header(encoded_header: &str) -> Result<Self, String>
pub fn from_base64url_header(encoded_header: &str) -> Result<Self, String>
Decodes a base64url-encoded challenge from an HTTP header.
This method reverses the to_base64url_header() operation by first base64url-decoding
the input string and then parsing it using the established | delimiter format.
§Arguments
encoded_header: The base64url-encoded string from the HTTP header.
§Returns
Result<Self, String>: Decoded challenge or detailed error message.
§Example
use ironshield_types::IronShieldChallenge;
use ed25519_dalek::SigningKey;
// Create a challenge and encode it
let dummy_key = SigningKey::from_bytes(&[0u8; 32]);
let original = IronShieldChallenge::new(
"test_website".to_string(),
100_000,
dummy_key,
[0x34; 32],
);
let header_value = original.to_base64url_header();
// Decode it back
let decoded = IronShieldChallenge::from_base64url_header(&header_value).unwrap();
assert_eq!(original.random_nonce, decoded.random_nonce);Trait Implementations§
Source§impl Clone for IronShieldChallenge
impl Clone for IronShieldChallenge
Source§fn clone(&self) -> IronShieldChallenge
fn clone(&self) -> IronShieldChallenge
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more