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

Default ProofParams on sandstorm and Starkware Verifier expected ProofParams #6

Open
tiagorvmartins opened this issue Aug 25, 2023 · 3 comments

Comments

@tiagorvmartins
Copy link

The proof generation on sandstorm uses the following parameters listed below as default:

#[structopt(long, default_value = "65")]
num_queries: u8,
#[structopt(long, default_value = "2")]
lde_blowup_factor: u8,
#[structopt(long, default_value = "16")]
proof_of_work_bits: u8,
#[structopt(long, default_value = "8")]
fri_folding_factor: u8,
#[structopt(long, default_value = "16")]
fri_max_remainder_coeffs: u8,

While checking starkex smart contracts, the proofParams expected on the smart contract method verifyProofAndRegister of Starkware GpsStatementVerifier seems to be the related with the following:

PROOF_PARAMS_N_QUERIES_OFFSET
PROOF_PARAMS_LOG_BLOWUP_FACTOR_OFFSET
PROOF_PARAMS_PROOF_OF_WORK_BITS_OFFSET
PROOF_PARAMS_FRI_LAST_LAYER_LOG_DEG_BOUND_OFFSET
PROOF_PARAMS_N_FRI_STEPS_OFFSET
PROOF_PARAMS_FRI_STEPS_OFFSET

I can see a relation between the first three to the default ones used by sandstorm, but even looking at sandstorm and comparing with starkex smart contracts, couldn't figure yet how I can get the other parameters (PROOF_PARAMS_FRI_LAST_LAYER_LOG_DEG_BOUND_OFFSET, PROOF_PARAMS_N_FRI_STEPS_OFFSET, PROOF_PARAMS_FRI_STEPS_OFFSET), taking into account on sandstorm there is the fri_folding_factor and fri_max_remainder_coeffs.

I believe there might be a way, maybe not trivial, can some insight be given on this matter? @andrewmilson
Thank you!

@andrewmilson
Copy link
Owner

andrewmilson commented Aug 26, 2023

Yeah, not all the proof params can be derived directly from the Sandstorm params. Here's how you can calculate each of them:

let lde_blowup_factor = proof.options.lde_blowup_factor as usize;
let lde_domain_size = proof.trace_len * lde_blowup_factor;
let fri_options = proof.options.into_fri_options();
let remainder_codeword_size = fri_options.remainder_size(lde_domain_size);
let max_remainder_coeffs = remainder_codeword_size / lde_blowup_factor;

let fri_last_layer_log_deg_bound = max_remainder_coeffs.ilog2();

let fri_steps = [
    vec![0u32],
    vec![proof.options.fri_folding_factor.ilog2(); fri_options.num_layers(lde_domain_size)],
]
.concat();

let n_fri_steps = fri_steps.len();

@tiagorvmartins
Copy link
Author

Hi @andrewmilson thank you! That really helped understanding and putting it together on my side.
I am currently trying to test an example following the required params for the starkex expected params.

Another fields which I couldn't find a matching anywhere was the cairoAuxInput and cairoVerifierId.
However, did some digging/comparing the source code and I have the following at the moment:

println!("n_steps: {}", air_public_input.n_steps);
println!("rc_min: {}", air_public_input.rc_min);
println!("rc_max: {}", air_public_input.rc_max);
println!("layout_code: {}", air_public_input.layout.sharp_code()); // the code returned doesnt match any layout code in starkex contracts, also what layout from the specs should we use? Does the layout used is related with the cairoVerifierId field?
println!("program_begin_addr: {}", air_public_input.memory_segments.program.begin_addr);
println!("program_stop_ptr: {}", air_public_input.memory_segments.program.stop_ptr);
println!("execution_begin_addr: {}", air_public_input.memory_segments.execution.begin_addr);
println!("execution_stop_ptr: {}", air_public_input.memory_segments.execution.stop_ptr);            
match air_public_input.memory_segments.output {
    Some(p) => {
        println!("output_begin_addr: {}", p.begin_addr);
        println!("output_stop_ptr: {}", p.stop_ptr);
    },
    None => println!("memory_segment output has no value"),
}
match air_public_input.memory_segments.pedersen {
    Some(p) => {
        println!("pedersen_begin_addr: {}", p.begin_addr);
        println!("pedersen_stop_ptr: {}", p.stop_ptr);
    },
    None => println!("memory_segment pedersen has no value"),
}
match air_public_input.memory_segments.range_check {
    Some(p) => {
        println!("range_check_begin_addr: {}", p.begin_addr);
        println!("range_check_stop_ptr: {}", p.stop_ptr);
    },
    None => println!("memory_segment range_check has no value"),
}
match air_public_input.memory_segments.ecdsa {
    Some(p) => {
        println!("ecdsa_begin_addr: {}", p.begin_addr);
        println!("ecdsa_stop_ptr: {}", p.stop_ptr);
    },
    None => println!("memory_segment ecdsa has no value"),
}
match air_public_input.memory_segments.bitwise {
    Some(p) => {
        println!("bitwise_begin_addr: {}", p.begin_addr);
        println!("bitwise_stop_ptr: {}", p.stop_ptr);
    },
    None => println!("memory_segment bitwise has no value"),
}
match air_public_input.memory_segments.ec_op {
    Some(p) => {
        println!("ec_op_begin_addr: {}", p.begin_addr);
        println!("ec_op_stop_ptr: {}", p.stop_ptr);
    },
    None => println!("memory_segment ec_op has no value"),
}
println!("public_memory_padding_addr: {}", air_public_input.public_memory_padding().address);
println!("public_memory_padding_value: {}", air_public_input.public_memory_padding().value);
println!("n_public_memory_pages: {}", air_public_input.public_memory.len() - 1); // Minus 1, because there is the padding element inside, I guess?



let addr = air_public_input.public_memory_padding().address;            
let mut public_memory_pages: Vec<String> = Vec::new();
            
for i in air_public_input.public_memory.iter() {                 
    if i.address != addr {                     
        public_memory_pages.push(i.value.to_string());
    }
}

println!("public_memory_pages: {}", public_memory_pages.join(""));

Note: I am not fluent in rust, so sorry if there is something that doesn't make sense.

However I have a few questions which can also be seen as comments on the code above.

  1. What layout code should we use? In starkex contracts, I notice there are at least 6 different layouts, and there is a LAYOUT_CODE there, but none matched the code returned from this sharp_code function, maybe its in a different type data (not sure).

  2. Does the layout code should match the cairoVerifierId? Which layout of starkex contracts does sandstorm uses? Let's say it matches the Layout6 of Starkex, then I should use cairoVerifierId 6?

  3. Not sure about how to send the public memory pages from the air_public_input, is something along the logic I followed the correct way of doing it?

Thank you again your help!

@tiagorvmartins
Copy link
Author

Hello @andrewmilson, quick update:

Found the utility function public_input_elements on the type CairoAuxInput inside sandstorm which helps with my previous comment, however I did notice the following:

 // Only 1 memory page currently for the main memory page
// TODO: support more memory pages
vals[OFFSET_N_PUBLIC_MEMORY_PAGES] = Some(uint!(1_U256));
vals.map(Option::unwrap).to_vec()

Also looked into the contract source code:
https://github.com/starkware-libs/starkex-contracts/blob/aecf37f2278b2df233edd13b686d0aa9462ada02/evm-verifier/solidity/contracts/gps/GpsStatementVerifier.sol#L107

Trying to submit a transaction to a starkex verifier on chain and I am getting:
execution reverted: Invalid publicMemoryPages length.

Can you give some insights on what I might be missing?

Here is the current cairoAuxInput:
[14 32764 32770 2110234636557836973669 1 5 45 76 76 76 76 76 460 460 2508 2508 1 290341444919459839 1 44 2438915998226227605472886518537430927592922043182741168578657691006379362735]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants