arnaucube
arnaucube/sonobe-light-btcPublic Self-hosted repository
sonobe-light-btc/src/main.rs
src/main.rsRaw
  1use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
  2use ark_crypto_primitives::snark::SNARK;
  3use ark_ff::PrimeField;
  4use ark_groth16::Groth16;
  5use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
  6use ark_light_bitcoin_client::{
  7    gadgets::BTCBlockCheckerGadget,
  8    get_block_hash, get_target, read_blocks,
  9    utils::{Block, BlockVar},
 10};
 11use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar};
 12use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
 13use ark_std::rand;
 14use folding_schemes::Decider as DeciderTrait;
 15use folding_schemes::{
 16    commitment::{kzg::KZG, pedersen::Pedersen},
 17    folding::nova::{decider_eth::Decider, Nova},
 18    frontend::FCircuit,
 19};
 20use folding_schemes::{folding::nova::decider_eth_circuit::DeciderEthCircuit, FoldingScheme};
 21use num_bigint::BigUint;
 22use num_traits::Num;
 23use std::{marker::PhantomData, time::Instant};
 24use utils::setup;
 25mod utils;
 26
 27#[derive(Clone, Debug)]
 28pub struct BTCBlockCheckerFCircuit<F: PrimeField> {
 29    _f: PhantomData<F>,
 30    block: Vec<Block>,
 31}
 32
 33impl<F: PrimeField> FCircuit<F> for BTCBlockCheckerFCircuit<F> {
 34    type Params = Vec<Block>;
 35
 36    fn new(params: Self::Params) -> Self {
 37        Self {
 38            _f: PhantomData,
 39            block: params,
 40        }
 41    }
 42
 43    fn state_len(&self) -> usize {
 44        1
 45    }
 46
 47    fn step_native(&self, i: usize, z_i: Vec<F>) -> Result<Vec<F>, folding_schemes::Error> {
 48        let new_z_i = vec![z_i[0] + F::one()];
 49
 50        // Check block hash
 51        let computed_block_hash = get_block_hash(&self.block[i].block_header);
 52        assert_eq!(computed_block_hash, self.block[i].block_hash);
 53
 54        // Check prev_block_hash
 55        assert_eq!(
 56            self.block[i].prev_block_hash,
 57            hex::encode(&self.block[i].block_header[4..36].to_vec())
 58        );
 59
 60        // Check pow
 61        let target = get_target(&self.block[i].block_header);
 62        let bigint_block_hash = BigUint::from_str_radix(&self.block[i].block_hash, 16).unwrap();
 63        assert!(BigUint::from_bytes_be(&bigint_block_hash.to_bytes_le()) < target);
 64
 65        Ok(new_z_i)
 66    }
 67
 68    fn generate_step_constraints(
 69        &self,
 70        cs: ConstraintSystemRef<F>,
 71        i: usize,
 72        z_i: Vec<ark_r1cs_std::fields::fp::FpVar<F>>,
 73    ) -> Result<Vec<ark_r1cs_std::fields::fp::FpVar<F>>, SynthesisError> {
 74        let new_z_i = vec![z_i[0].clone() + FpVar::new_constant(cs.clone(), F::one())?];
 75        let block_var = BlockVar::new_witness(cs.clone(), || Ok(self.block[i].clone()))?;
 76        let _ = BTCBlockCheckerGadget::check_block(cs.clone(), block_var.clone())?;
 77        Ok(new_z_i)
 78    }
 79}
 80
 81fn main() {
 82    let file = include_str!("./data/btc-blocks.json");
 83    let (mut prev_block_hash, blocks) = read_blocks(100, 1, file);
 84
 85    let mut blocks_prepared = vec![];
 86    for batch in blocks.iter() {
 87        let block_hashes =
 88            serde_json::from_value::<Vec<String>>(batch.get("blockHashes").unwrap().clone())
 89                .unwrap();
 90        let block_headers =
 91            serde_json::from_value::<Vec<Vec<u8>>>(batch.get("blockHeaders").unwrap().clone())
 92                .unwrap();
 93        for (block_hash, block_header) in block_hashes.iter().zip(block_headers) {
 94            let block = Block {
 95                block_header,
 96                block_hash: block_hash.to_string(),
 97                prev_block_hash,
 98            };
 99            blocks_prepared.push(block.clone());
100            prev_block_hash = block_hash.to_string();
101        }
102    }
103
104    type NOVA = Nova<
105        Projective,
106        GVar,
107        Projective2,
108        GVar2,
109        BTCBlockCheckerFCircuit<Fr>,
110        KZG<'static, Bn254>,
111        Pedersen<Projective2>,
112    >;
113
114    type DECIDER = Decider<
115        Projective,
116        GVar,
117        Projective2,
118        GVar2,
119        BTCBlockCheckerFCircuit<Fr>,
120        KZG<'static, Bn254>,
121        Pedersen<Projective2>,
122        Groth16<Bn254>,
123        NOVA,
124    >;
125
126    let n_blocks_checked = blocks_prepared.len();
127    let circuit = BTCBlockCheckerFCircuit::<Fr>::new(blocks_prepared.clone());
128    let (prover_params, poseidon_config, kzg_vk) = setup(circuit.clone());
129    let z_0 = vec![Fr::from(0)];
130    let mut nova = NOVA::init(&prover_params, circuit, z_0.clone()).unwrap();
131
132    println!("Computing folds...");
133    let now = Instant::now();
134    for i in 0..n_blocks_checked {
135        let current_state = nova.z_i[0].into_bigint();
136        if i % 10 == 0 {
137            println!("--- At block: {}/{} ---", current_state, n_blocks_checked);
138        }
139        nova.prove_step().unwrap();
140    }
141    let elapsed = now.elapsed();
142    println!(
143        "Done folding. Checked {} blocks in: {:.2?}",
144        n_blocks_checked, elapsed
145    );
146
147    let circuit = DeciderEthCircuit::<
148        Projective,
149        GVar,
150        Projective2,
151        GVar2,
152        KZG<Bn254>,
153        Pedersen<Projective2>,
154    >::from_nova::<BTCBlockCheckerFCircuit<Fr>>(nova.clone())
155    .unwrap();
156    let mut rng = rand::rngs::OsRng;
157
158    // decider setup
159    println!("Starting setup...");
160    let now = Instant::now();
161    let (g16_pk, g16_vk) =
162        Groth16::<Bn254>::circuit_specific_setup(circuit.clone(), &mut rng).unwrap();
163    let elapsed = now.elapsed();
164    println!("Setup done in: {:.2?}", elapsed);
165
166    // decider proof generation
167    println!("Generating proof...");
168    let now = Instant::now();
169    let decider_pp = (poseidon_config.clone(), g16_pk, prover_params.cs_params);
170    let proof = DECIDER::prove(decider_pp, rng, nova.clone()).unwrap();
171    let elapsed = now.elapsed();
172    println!("Proof generated in: {:.2?}", elapsed);
173
174    // decider proof verification
175    println!("Verifying proof...");
176    let verified = DECIDER::verify(
177        (g16_vk.clone(), kzg_vk.clone()),
178        nova.i,
179        nova.z_0,
180        nova.z_i,
181        &nova.U_i,
182        &nova.u_i,
183        &proof,
184    )
185    .unwrap();
186    assert!(verified);
187}