rustev_core/ranking/
permute.rs1use rustev_contract::canonical::{CanonicalError, canonical_bytes, tagged_digest};
3use serde::Serialize;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum PermuteError {
7 Canonical(CanonicalError),
8 DigestEncoding,
9 Overflow,
10}
11
12#[derive(Debug, Clone, Copy, Serialize)]
14#[serde(untagged)]
15pub enum DrawKey<'a> {
16 Permutation(u64),
17 Comparison(&'a str),
18}
19
20pub fn draw(
22 seed: &str,
23 step: &str,
24 instance: &[String],
25 j: DrawKey<'_>,
26 i: u64,
27) -> Result<(u64, u64), PermuteError> {
28 let range = u128::from(i) + 1;
29 let space = 1u128 << 64;
30 let limit = (space / range) * range;
31 let mut attempt = 0u64;
32 loop {
33 let bytes = canonical_bytes(&(seed, step, instance, j, i, attempt))
37 .map_err(PermuteError::Canonical)?;
38 let digest = tagged_digest("rustev.permute/1", &bytes);
39 let prefix = digest.get(7..23).ok_or(PermuteError::DigestEncoding)?;
40 let v = u64::from_str_radix(prefix, 16).map_err(|_| PermuteError::DigestEncoding)?;
43 if u128::from(v) < limit {
44 return Ok(((u128::from(v) % range) as u64, attempt));
45 }
46 attempt = attempt.checked_add(1).ok_or(PermuteError::Overflow)?;
47 }
48}
49
50pub fn permutation(
52 size: usize,
53 seed: &str,
54 step: &str,
55 instance: &[String],
56 j: u64,
57) -> Result<Vec<usize>, PermuteError> {
58 let mut positions: Vec<_> = (0..size).collect();
59 for i in (1..size).rev() {
60 let index = u64::try_from(i).map_err(|_| PermuteError::Overflow)?;
61 let (r, _) = draw(seed, step, instance, DrawKey::Permutation(j), index)?;
62 let r = usize::try_from(r).map_err(|_| PermuteError::Overflow)?;
63 positions.swap(i, r);
65 }
66 Ok(positions)
67}
68
69pub fn presentation_bit(
71 seed: &str,
72 step: &str,
73 instance: &[String],
74 comparison: &str,
75) -> Result<bool, PermuteError> {
76 draw(seed, step, instance, DrawKey::Comparison(comparison), 1).map(|(v, _)| v == 1)
77}