use fri::FriOptions;
use math::StarkField;
use utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum HashFunction {
Blake3_192 = 1,
Blake3_256 = 2,
Sha3_256 = 3,
}
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum FieldExtension {
None = 1,
Quadratic = 2,
Cubic = 3,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ProofOptions {
num_queries: u8,
blowup_factor: u8,
grinding_factor: u8,
hash_fn: HashFunction,
field_extension: FieldExtension,
fri_folding_factor: u8,
fri_max_remainder_size: u8, }
impl ProofOptions {
pub const MIN_BLOWUP_FACTOR: usize = 2;
#[rustfmt::skip]
pub fn new(
num_queries: usize,
blowup_factor: usize,
grinding_factor: u32,
hash_fn: HashFunction,
field_extension: FieldExtension,
fri_folding_factor: usize,
fri_max_remainder_size: usize,
) -> ProofOptions {
assert!(num_queries > 0, "number of queries must be greater than 0");
assert!(num_queries <= 128, "number of queries cannot be greater than 128");
assert!(blowup_factor.is_power_of_two(), "blowup factor must be a power of 2");
assert!(blowup_factor >= Self::MIN_BLOWUP_FACTOR,
"blowup factor cannot be smaller than {}", Self::MIN_BLOWUP_FACTOR);
assert!(blowup_factor <= 128, "blowup factor cannot be greater than 128");
assert!(grinding_factor <= 32, "grinding factor cannot be greater than 32");
assert!(fri_folding_factor.is_power_of_two(), "FRI folding factor must be a power of 2");
assert!(fri_folding_factor >= 4, "FRI folding factor cannot be smaller than 4");
assert!(fri_folding_factor <= 16, "FRI folding factor cannot be greater than 16");
assert!(fri_max_remainder_size.is_power_of_two(), "FRI max remainder size must be a power of 2");
assert!(fri_max_remainder_size >= 32, "FRI max remainder size cannot be smaller than 32");
assert!(fri_max_remainder_size <= 1024, "FRI max remainder size cannot be greater than 1024");
ProofOptions {
num_queries: num_queries as u8,
blowup_factor: blowup_factor as u8,
grinding_factor: grinding_factor as u8,
hash_fn,
field_extension,
fri_folding_factor: fri_folding_factor as u8,
fri_max_remainder_size: fri_max_remainder_size.trailing_zeros() as u8,
}
}
pub fn num_queries(&self) -> usize {
self.num_queries as usize
}
pub fn blowup_factor(&self) -> usize {
self.blowup_factor as usize
}
pub fn grinding_factor(&self) -> u32 {
self.grinding_factor as u32
}
pub fn hash_fn(&self) -> HashFunction {
self.hash_fn
}
pub fn field_extension(&self) -> FieldExtension {
self.field_extension
}
pub fn domain_offset<B: StarkField>(&self) -> B {
B::GENERATOR
}
pub fn to_fri_options(&self) -> FriOptions {
let folding_factor = self.fri_folding_factor as usize;
let max_remainder_size = 2usize.pow(self.fri_max_remainder_size as u32);
FriOptions::new(self.blowup_factor(), folding_factor, max_remainder_size)
}
}
impl Serializable for ProofOptions {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write_u8(self.num_queries);
target.write_u8(self.blowup_factor);
target.write_u8(self.grinding_factor);
target.write(self.hash_fn);
target.write(self.field_extension);
target.write_u8(self.fri_folding_factor);
target.write_u8(self.fri_max_remainder_size);
}
}
impl Deserializable for ProofOptions {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
Ok(ProofOptions::new(
source.read_u8()? as usize,
source.read_u8()? as usize,
source.read_u8()? as u32,
HashFunction::read_from(source)?,
FieldExtension::read_from(source)?,
source.read_u8()? as usize,
2usize.pow(source.read_u8()? as u32),
))
}
}
impl FieldExtension {
pub fn is_none(&self) -> bool {
matches!(self, Self::None)
}
pub fn degree(&self) -> u32 {
match self {
Self::None => 1,
Self::Quadratic => 2,
Self::Cubic => 3,
}
}
}
impl Serializable for FieldExtension {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write_u8(*self as u8);
}
}
impl Deserializable for FieldExtension {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
match source.read_u8()? {
1 => Ok(FieldExtension::None),
2 => Ok(FieldExtension::Quadratic),
3 => Ok(FieldExtension::Cubic),
value => Err(DeserializationError::InvalidValue(format!(
"value {} cannot be deserialized as FieldExtension enum",
value
))),
}
}
}
impl HashFunction {
pub fn collision_resistance(&self) -> u32 {
match self {
Self::Blake3_192 => 96,
Self::Blake3_256 => 128,
Self::Sha3_256 => 128,
}
}
}
impl Serializable for HashFunction {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write_u8(*self as u8);
}
}
impl Deserializable for HashFunction {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
match source.read_u8()? {
1 => Ok(HashFunction::Blake3_192),
2 => Ok(HashFunction::Blake3_256),
3 => Ok(HashFunction::Sha3_256),
value => Err(DeserializationError::InvalidValue(format!(
"value {} cannot be deserialized as HashFunction enum",
value
))),
}
}
}