Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Security estimate #151

Merged
merged 2 commits into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 57 additions & 5 deletions air/src/proof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,16 @@ impl StarkProof {
get_conjectured_security(
self.context.options(),
self.context.num_modulus_bits(),
self.lde_domain_size() as u64,
self.trace_length() as u64,
H::COLLISION_RESISTANCE,
)
} else {
// TODO: implement provable security estimation
unimplemented!("proven security estimation has not been implement yet")
get_proven_security(
self.context.options(),
self.context.num_modulus_bits(),
self.lde_domain_size() as u64,
H::COLLISION_RESISTANCE,
)
}
}

Expand Down Expand Up @@ -177,12 +181,12 @@ impl StarkProof {
fn get_conjectured_security(
options: &ProofOptions,
base_field_bits: u32,
lde_domain_size: u64,
trace_domain_size: u64,
collision_resistance: u32,
) -> u32 {
// compute max security we can get for a given field size
let field_size = base_field_bits * options.field_extension().degree();
let field_security = field_size - lde_domain_size.trailing_zeros();
let field_security = field_size - trace_domain_size.trailing_zeros();

irakliyk marked this conversation as resolved.
Show resolved Hide resolved
// compute security we get by executing multiple query rounds
let security_per_query = log2(options.blowup_factor());
Expand All @@ -198,3 +202,51 @@ fn get_conjectured_security(
collision_resistance,
)
}

/// Estimates proven security level for the specified proof parameters.
fn get_proven_security(
options: &ProofOptions,
base_field_bits: u32,
lde_domain_size: u64,
collision_resistance: u32,
) -> u32 {
let extension_field_bits = (base_field_bits * options.field_extension().degree()) as f64;
let blowup_bits = log2(options.blowup_factor()) as f64;
let num_fri_queries = options.num_queries() as f64;
let lde_size_bits = lde_domain_size.trailing_zeros() as f64;

// m is a parameter greater or equal to 3.
// A larger m gives a worse field security bound but a better query security bound.
// An optimal value of m is then a value that would balance field and query security
// but there is no simple closed form solution.
// This sets m so that field security is equal to the best query security for any value
// of m, unless the calculated value is less than 3 in which case it gets rounded up to 3.
let mut m = extension_field_bits + 1.0;
m -= options.grinding_factor() as f64;
m -= (num_fri_queries + 3.0) / 2.0 * blowup_bits;
m -= 2.0 * lde_size_bits;
m /= 7.0;
m = 2.0_f64.powf(m);
m -= 0.5;
m = m.max(3.0);

// compute pre-FRI query security
// this considers only the third component given in the corresponding part of eq. 20
// in https://eprint.iacr.org/2021/582, i.e. (m+1/2)^7.n^2 / (2\rho^1.5.q) as all
// other terms are negligible in comparison.
let pre_query_security = (extension_field_bits + 1.0
- 3.0 / 2.0 * blowup_bits
irakliyk marked this conversation as resolved.
Show resolved Hide resolved
- 2.0 * lde_size_bits
- 7.0 * (m + 0.5).log2()) as u32;

// compute security we get by executing multiple query rounds
let security_per_query = 0.5 * blowup_bits - (1.0 + 1.0 / (2.0 * m)).log2();
let mut query_security = (security_per_query * num_fri_queries) as u32;

query_security += options.grinding_factor();

cmp::min(
cmp::min(pre_query_security, query_security) - 1,
collision_resistance,
)
}
14 changes: 7 additions & 7 deletions examples/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ impl ExampleOptions {
}

/// Returns security level of the input proof in bits.
pub fn get_proof_security_level(&self, proof: &StarkProof) -> usize {
pub fn get_proof_security_level(&self, proof: &StarkProof, conjectured: bool) -> usize {
let security_level = match self.hash_fn.as_str() {
"blake3_192" => proof.security_level::<Blake3_192>(true),
"blake3_256" => proof.security_level::<Blake3_256>(true),
"sha3_256" => proof.security_level::<Sha3_256>(true),
"rp64_256" => proof.security_level::<Rp64_256>(true),
"rp_jive64_256" => proof.security_level::<RpJive64_256>(true),
"griffin_jive64_256" => proof.security_level::<GriffinJive64_256>(true),
"blake3_192" => proof.security_level::<Blake3_192>(conjectured),
"blake3_256" => proof.security_level::<Blake3_256>(conjectured),
"sha3_256" => proof.security_level::<Sha3_256>(conjectured),
"rp64_256" => proof.security_level::<Rp64_256>(conjectured),
"rp_jive64_256" => proof.security_level::<RpJive64_256>(conjectured),
"griffin_jive64_256" => proof.security_level::<GriffinJive64_256>(conjectured),
val => panic!("'{val}' is not a valid hash function option"),
};
Nashtare marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
8 changes: 6 additions & 2 deletions examples/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,12 @@ fn main() {

let proof_bytes = proof.to_bytes();
debug!("Proof size: {:.1} KB", proof_bytes.len() as f64 / 1024f64);
let security_level = options.get_proof_security_level(&proof);
debug!("Proof security: {} bits", security_level);
let conjectured_security_level = options.get_proof_security_level(&proof, true);
let proven_security_level = options.get_proof_security_level(&proof, false);
debug!(
"Proof security: {} bits ({} proven)",
conjectured_security_level, proven_security_level,
);
#[cfg(feature = "std")]
debug!(
"Proof hash: {}",
Expand Down