From 712f7650384894b24286612eb44783b4862f8efc Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 10:37:15 -0700 Subject: [PATCH 01/28] prover type --- Cargo.lock | 2 ++ sdk/Cargo.toml | 2 ++ sdk/src/lib.rs | 29 ++++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index bba9a1a133..b0a73531af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4921,6 +4921,8 @@ dependencies = [ "sha2", "sp1-core", "sp1-prover", + "strum", + "strum_macros", "tempfile", "tokio", "tracing", diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 3b7a122ff6..24b55d5d1e 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -37,6 +37,8 @@ tempfile = "3.10.1" num-bigint = "0.4.5" cfg-if = "1.0" ethers = { version = "2", default-features = false } +strum_macros = "0.26.2" +strum = "0.26.2" [features] neon = ["sp1-core/neon"] diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 38ae6183c5..dfb3e2e37c 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -19,7 +19,13 @@ pub mod utils { pub use sp1_core::utils::setup_logger; } -use std::{env, fmt::Debug, fs::File, path::Path}; +use std::{ + any::{Any, TypeId}, + env, + fmt::Debug, + fs::File, + path::Path, +}; use anyhow::{Ok, Result}; pub use provers::{LocalProver, MockProver, NetworkProver, Prover}; @@ -29,6 +35,7 @@ pub use sp1_prover::{ CoreSC, HashableKey, InnerSC, OuterSC, PlonkBn254Proof, SP1Prover, SP1ProvingKey, SP1PublicValues, SP1Stdin, SP1VerifyingKey, }; +use strum_macros::EnumString; /// A client for interacting with SP1. pub struct ProverClient { @@ -36,6 +43,13 @@ pub struct ProverClient { pub prover: Box, } +#[derive(Debug, PartialEq, EnumString)] +pub enum ProverType { + Local, + Mock, + Network, +} + /// A proof generated with SP1. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound(serialize = "P: Serialize + Debug + Clone"))] @@ -147,6 +161,19 @@ impl ProverClient { } } + pub fn prover_type(&self) -> ProverType { + let prover_type_id = (*self.prover).type_id(); + if prover_type_id == TypeId::of::() { + ProverType::Local + } else if prover_type_id == TypeId::of::() { + ProverType::Mock + } else if prover_type_id == TypeId::of::() { + ProverType::Network + } else { + panic!("invalid prover type") + } + } + /// Executes the given program on the given input (without generating a proof). /// /// Returns the public values of the program after it has been executed. From b954a47303e3f1a0ee15cd3b49936928045218c6 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 10:39:19 -0700 Subject: [PATCH 02/28] update comments --- sdk/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index dfb3e2e37c..b2c2bea571 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -43,6 +43,7 @@ pub struct ProverClient { pub prover: Box, } +/// The type of prover used by the [ProverClient]. #[derive(Debug, PartialEq, EnumString)] pub enum ProverType { Local, @@ -161,6 +162,17 @@ impl ProverClient { } } + /// Returns the type of prover used by the [ProverClient]. + /// + /// ### Examples + /// + /// ```no_run + /// use sp1_sdk::ProverClient; + /// + /// let client = ProverClient::local(); + /// let prover_type = client.prover_type(); + /// assert_eq!(prover_type, ProverType::Local); + /// ``` pub fn prover_type(&self) -> ProverType { let prover_type_id = (*self.prover).type_id(); if prover_type_id == TypeId::of::() { From 52c9c9471545c8948b59afb0ccade77b221c1571 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 10:57:00 -0700 Subject: [PATCH 03/28] prover type --- sdk/src/lib.rs | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index b2c2bea571..14c9be89c2 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -41,6 +41,7 @@ use strum_macros::EnumString; pub struct ProverClient { /// The underlying prover implementation. pub prover: Box, + pub prover_type: ProverType, } /// The type of prover used by the [ProverClient]. @@ -96,12 +97,15 @@ impl ProverClient { { "mock" => Self { prover: Box::new(MockProver::new()), + prover_type: ProverType::Mock, }, "local" => Self { prover: Box::new(LocalProver::new()), + prover_type: ProverType::Local, }, "network" => Self { prover: Box::new(NetworkProver::new()), + prover_type: ProverType::Network, }, _ => panic!( "invalid value for SP1_PROVER enviroment variable: expected 'local', 'mock', or 'remote'" @@ -124,6 +128,7 @@ impl ProverClient { pub fn mock() -> Self { Self { prover: Box::new(MockProver::new()), + prover_type: ProverType::Mock, } } @@ -142,6 +147,7 @@ impl ProverClient { pub fn local() -> Self { Self { prover: Box::new(LocalProver::new()), + prover_type: ProverType::Local, } } @@ -159,30 +165,7 @@ impl ProverClient { pub fn remote() -> Self { Self { prover: Box::new(NetworkProver::new()), - } - } - - /// Returns the type of prover used by the [ProverClient]. - /// - /// ### Examples - /// - /// ```no_run - /// use sp1_sdk::ProverClient; - /// - /// let client = ProverClient::local(); - /// let prover_type = client.prover_type(); - /// assert_eq!(prover_type, ProverType::Local); - /// ``` - pub fn prover_type(&self) -> ProverType { - let prover_type_id = (*self.prover).type_id(); - if prover_type_id == TypeId::of::() { - ProverType::Local - } else if prover_type_id == TypeId::of::() { - ProverType::Mock - } else if prover_type_id == TypeId::of::() { - ProverType::Network - } else { - panic!("invalid prover type") + prover_type: ProverType::Network, } } From 74fe3defa8f319bbd34a88017ebc57743419ac16 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 10:59:12 -0700 Subject: [PATCH 04/28] lint --- sdk/src/lib.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 14c9be89c2..a7ae542fdc 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -19,13 +19,7 @@ pub mod utils { pub use sp1_core::utils::setup_logger; } -use std::{ - any::{Any, TypeId}, - env, - fmt::Debug, - fs::File, - path::Path, -}; +use std::{env, fmt::Debug, fs::File, path::Path}; use anyhow::{Ok, Result}; pub use provers::{LocalProver, MockProver, NetworkProver, Prover}; From be2ce85ff10da55b2bdf2d07de1a6e0dd7f341ee Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 11:00:33 -0700 Subject: [PATCH 05/28] change to network --- sdk/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index a7ae542fdc..65e0cfe38c 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -154,9 +154,9 @@ impl ProverClient { /// ```no_run /// use sp1_sdk::ProverClient; /// - /// let client = ProverClient::remote(); + /// let client = ProverClient::network(); /// ``` - pub fn remote() -> Self { + pub fn network() -> Self { Self { prover: Box::new(NetworkProver::new()), prover_type: ProverType::Network, From 573a7641c8b6563013de6e1c046079968123baf2 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 11:01:18 -0700 Subject: [PATCH 06/28] fix --- sdk/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 65e0cfe38c..a7ae542fdc 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -154,9 +154,9 @@ impl ProverClient { /// ```no_run /// use sp1_sdk::ProverClient; /// - /// let client = ProverClient::network(); + /// let client = ProverClient::remote(); /// ``` - pub fn network() -> Self { + pub fn remote() -> Self { Self { prover: Box::new(NetworkProver::new()), prover_type: ProverType::Network, From 2325a9ce6df68d9e45074601403a81996d62a21b Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Thu, 30 May 2024 11:16:32 -0700 Subject: [PATCH 07/28] fix: gnark-ffi linking on mac --- recursion/gnark-ffi/build.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/recursion/gnark-ffi/build.rs b/recursion/gnark-ffi/build.rs index 35c3f63f10..586e7f8425 100644 --- a/recursion/gnark-ffi/build.rs +++ b/recursion/gnark-ffi/build.rs @@ -58,6 +58,12 @@ fn main() { // Link the Go library println!("cargo:rustc-link-search=native={}", dest_path.display()); println!("cargo:rustc-link-lib=static={}", lib_name); + + // Static linking doesn't really work on macos, so we need to link some system libs + if cfg!(target_os = "macos") { + println!("cargo:rustc-link-lib=framework=CoreFoundation"); + println!("cargo:rustc-link-lib=framework=Security"); + } } } } From d1ca91fd7ae735db878476a4075538561e18056c Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 11:29:29 -0700 Subject: [PATCH 08/28] clean --- sdk/src/lib.rs | 16 ---------------- sdk/src/provers/local.rs | 6 ++++-- sdk/src/provers/mock.rs | 6 ++++-- sdk/src/provers/mod.rs | 11 ++++++++++- sdk/src/provers/network.rs | 6 +++--- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index a7ae542fdc..38ae6183c5 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -29,21 +29,11 @@ pub use sp1_prover::{ CoreSC, HashableKey, InnerSC, OuterSC, PlonkBn254Proof, SP1Prover, SP1ProvingKey, SP1PublicValues, SP1Stdin, SP1VerifyingKey, }; -use strum_macros::EnumString; /// A client for interacting with SP1. pub struct ProverClient { /// The underlying prover implementation. pub prover: Box, - pub prover_type: ProverType, -} - -/// The type of prover used by the [ProverClient]. -#[derive(Debug, PartialEq, EnumString)] -pub enum ProverType { - Local, - Mock, - Network, } /// A proof generated with SP1. @@ -91,15 +81,12 @@ impl ProverClient { { "mock" => Self { prover: Box::new(MockProver::new()), - prover_type: ProverType::Mock, }, "local" => Self { prover: Box::new(LocalProver::new()), - prover_type: ProverType::Local, }, "network" => Self { prover: Box::new(NetworkProver::new()), - prover_type: ProverType::Network, }, _ => panic!( "invalid value for SP1_PROVER enviroment variable: expected 'local', 'mock', or 'remote'" @@ -122,7 +109,6 @@ impl ProverClient { pub fn mock() -> Self { Self { prover: Box::new(MockProver::new()), - prover_type: ProverType::Mock, } } @@ -141,7 +127,6 @@ impl ProverClient { pub fn local() -> Self { Self { prover: Box::new(LocalProver::new()), - prover_type: ProverType::Local, } } @@ -159,7 +144,6 @@ impl ProverClient { pub fn remote() -> Self { Self { prover: Box::new(NetworkProver::new()), - prover_type: ProverType::Network, } } diff --git a/sdk/src/provers/local.rs b/sdk/src/provers/local.rs index 41c9f56cf0..3fb469ab4b 100644 --- a/sdk/src/provers/local.rs +++ b/sdk/src/provers/local.rs @@ -7,6 +7,8 @@ use crate::{ SP1ProvingKey, SP1VerifyingKey, }; +use super::ProverType; + /// An implementation of [crate::ProverClient] that can generate end-to-end proofs locally. pub struct LocalProver { prover: SP1Prover, @@ -21,8 +23,8 @@ impl LocalProver { } impl Prover for LocalProver { - fn id(&self) -> String { - "local".to_string() + fn id(&self) -> ProverType { + ProverType::Local } fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { diff --git a/sdk/src/provers/mock.rs b/sdk/src/provers/mock.rs index 66b0dda205..8ec44ca479 100644 --- a/sdk/src/provers/mock.rs +++ b/sdk/src/provers/mock.rs @@ -9,6 +9,8 @@ use sp1_prover::{ verify::verify_plonk_bn254_public_inputs, HashableKey, PlonkBn254Proof, SP1Prover, SP1Stdin, }; +use super::ProverType; + /// An implementation of [crate::ProverClient] that can generate mock proofs. pub struct MockProver { pub(crate) prover: SP1Prover, @@ -23,8 +25,8 @@ impl MockProver { } impl Prover for MockProver { - fn id(&self) -> String { - "mock".to_string() + fn id(&self) -> ProverType { + ProverType::Mock } fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { diff --git a/sdk/src/provers/mod.rs b/sdk/src/provers/mod.rs index c18770333c..53c9e32fa9 100644 --- a/sdk/src/provers/mod.rs +++ b/sdk/src/provers/mod.rs @@ -13,10 +13,19 @@ use sp1_prover::SP1CoreProofData; use sp1_prover::SP1Prover; use sp1_prover::SP1ReduceProof; use sp1_prover::{SP1ProvingKey, SP1Stdin, SP1VerifyingKey}; +use strum_macros::EnumString; + +/// The type of prover. +#[derive(Debug, PartialEq, EnumString)] +pub enum ProverType { + Local, + Mock, + Network, +} /// An implementation of [crate::ProverClient]. pub trait Prover: Send + Sync { - fn id(&self) -> String; + fn id(&self) -> ProverType; fn sp1_prover(&self) -> &SP1Prover; diff --git a/sdk/src/provers/network.rs b/sdk/src/provers/network.rs index f86900e266..4e1b70920d 100644 --- a/sdk/src/provers/network.rs +++ b/sdk/src/provers/network.rs @@ -15,7 +15,7 @@ use sp1_prover::utils::block_on; use sp1_prover::{SP1Prover, SP1Stdin}; use tokio::{runtime, time::sleep}; -use super::LocalProver; +use super::{LocalProver, ProverType}; /// An implementation of [crate::ProverClient] that can generate proofs on a remote RPC server. pub struct NetworkProver { @@ -151,8 +151,8 @@ impl NetworkProver { } impl Prover for NetworkProver { - fn id(&self) -> String { - "remote".to_string() + fn id(&self) -> ProverType { + ProverType::Network } fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { From 1b9a0ae8ee7b180c636315c04d8348d5d463b5e4 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 12:24:22 -0700 Subject: [PATCH 09/28] feat: enforce only `dev` can merge into `main` (#844) --- .github/workflows/main.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e57346e040..cfc5854ae2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,4 +38,13 @@ jobs: args: --release -p sp1-sdk --features plonk -- test_e2e_prove_plonk --nocapture env: RUSTFLAGS: -Copt-level=3 -Cdebug-assertions -Coverflow-checks=y -Cdebuginfo=0 -C target-cpu=native - RUST_BACKTRACE: 1 \ No newline at end of file + RUST_BACKTRACE: 1 + check-branch: + name: Check branch + runs-on: ubuntu-latest + steps: + - name: Check branch + if: github.head_ref != 'dev' + run: | + echo "ERROR: You can only merge to main from dev." + exit 1 \ No newline at end of file From 1d8aa1b3dc438d6aa18433a2b6f8bdc51458942e Mon Sep 17 00:00:00 2001 From: Tej Qu Nair Date: Thu, 30 May 2024 13:38:34 -0700 Subject: [PATCH 10/28] feat: runtime instruction/syscall report (#839) Co-authored-by: Ratan Kaliani --- core/src/runtime/mod.rs | 98 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 4 deletions(-) diff --git a/core/src/runtime/mod.rs b/core/src/runtime/mod.rs index 2a73cf5dac..9fcc75f045 100644 --- a/core/src/runtime/mod.rs +++ b/core/src/runtime/mod.rs @@ -81,6 +81,24 @@ pub struct Runtime { pub max_syscall_cycles: u32, pub emit_events: bool, + + /// Report of instruction calls. + pub report: InstructionReport, + + /// Whether we should write to the report. + pub should_report: bool, +} + +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct InstructionReport { + pub instruction_counts: HashMap, + pub syscall_counts: HashMap, +} + +impl InstructionReport { + pub fn total_instruction_count(&self) -> u32 { + self.instruction_counts.values().sum() + } } #[derive(Error, Debug)] @@ -140,6 +158,8 @@ impl Runtime { syscall_map, emit_events: true, max_syscall_cycles, + report: Default::default(), + should_report: false, } } @@ -535,6 +555,14 @@ impl Runtime { let mut memory_store_value: Option = None; self.memory_accesses = MemoryAccessRecord::default(); + if self.should_report { + self.report + .instruction_counts + .entry(instruction.opcode) + .and_modify(|c| *c += 1) + .or_insert(1); + } + match instruction.opcode { // Arithmetic instructions. Opcode::ADD => { @@ -749,6 +777,14 @@ impl Runtime { b = self.rr(Register::X10, MemoryAccessPosition::B); let syscall = SyscallCode::from_u32(syscall_id); + if self.should_report { + self.report + .syscall_counts + .entry(syscall) + .and_modify(|c| *c += 1) + .or_insert(1); + } + let syscall_impl = self.get_syscall(syscall).cloned(); let mut precompile_rt = SyscallContext::new(self); let (precompile_next_pc, precompile_cycles, returned_exit_code) = @@ -954,16 +990,18 @@ impl Runtime { tracing::info!("starting execution"); } - pub fn run_untraced(&mut self) -> Result<(), ExecutionError> { + pub fn run_untraced(&mut self) -> Result<&InstructionReport, ExecutionError> { self.emit_events = false; + self.should_report = true; while !self.execute()? {} - Ok(()) + Ok(&self.report) } - pub fn run(&mut self) -> Result<(), ExecutionError> { + pub fn run(&mut self) -> Result<&InstructionReport, ExecutionError> { self.emit_events = true; + self.should_report = true; while !self.execute()? {} - Ok(()) + Ok(&self.report) } pub fn dry_run(&mut self) { @@ -1110,6 +1148,58 @@ pub mod tests { assert_eq!(runtime.register(Register::X31), 42); } + #[test] + fn test_ssz_withdrawals_program_run_report() { + let program = ssz_withdrawals_program(); + let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + runtime.run().unwrap(); + assert_eq!(runtime.report, { + use super::Opcode::*; + use super::SyscallCode::*; + super::InstructionReport { + instruction_counts: [ + (LB, 10723), + (DIVU, 6), + (LW, 237094), + (JALR, 38749), + (XOR, 242242), + (BEQ, 26917), + (AND, 151701), + (SB, 58448), + (MUL, 4036), + (SLTU, 16766), + (ADD, 583439), + (JAL, 5372), + (LBU, 57950), + (SRL, 293010), + (SW, 312781), + (ECALL, 2264), + (BLTU, 43457), + (BGEU, 5917), + (BLT, 1141), + (SUB, 12382), + (BGE, 237), + (MULHU, 1152), + (BNE, 51442), + (AUIPC, 19488), + (OR, 301944), + (SLL, 278698), + ] + .into(), + syscall_counts: [ + (COMMIT_DEFERRED_PROOFS, 8), + (SHA_EXTEND, 1091), + (COMMIT, 8), + (WRITE, 65), + (SHA_COMPRESS, 1091), + (HALT, 1), + ] + .into(), + } + }); + assert_eq!(runtime.report.total_instruction_count(), 2757356); + } + #[test] #[should_panic] fn test_panic() { From 507b67c16f306cb6d47daca9862f48afe9b21030 Mon Sep 17 00:00:00 2001 From: Chris T Date: Thu, 30 May 2024 13:51:06 -0700 Subject: [PATCH 11/28] chore: add network requester to requested proof (#845) --- sdk/src/lib.rs | 1 + sdk/src/proto/network.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 4f0a4b1c4a..c89eed47e2 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -8,6 +8,7 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs)] +#[rustfmt::skip] pub mod proto { pub mod network; } diff --git a/sdk/src/proto/network.rs b/sdk/src/proto/network.rs index 3c8919d7e6..173c032f1e 100644 --- a/sdk/src/proto/network.rs +++ b/sdk/src/proto/network.rs @@ -241,6 +241,9 @@ pub struct RequestedProof { /// The mode for proof generation. #[prost(enumeration = "ProofMode", tag = "2")] pub mode: i32, + /// Proof requester's address. + #[prost(bytes = "vec", tag = "3")] + pub requester: ::prost::alloc::vec::Vec, } /// The response for getting proof requests by a given status. #[derive(serde::Serialize, serde::Deserialize)] From dffe9e638ae9762b3e6327a1040273a920f5dcd4 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Thu, 30 May 2024 13:56:26 -0700 Subject: [PATCH 12/28] chore: default reconstruct commitments = true --- core/src/utils/options.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/utils/options.rs b/core/src/utils/options.rs index 432029baec..d823859d1b 100644 --- a/core/src/utils/options.rs +++ b/core/src/utils/options.rs @@ -12,7 +12,7 @@ impl Default for SP1CoreOpts { shard_size: 1 << 22, shard_batch_size: 16, shard_chunking_multiplier: 1, - reconstruct_commitments: false, + reconstruct_commitments: true, } } } From 99effb189cdcd952b809bd12df69d16bd6dd4726 Mon Sep 17 00:00:00 2001 From: Matt Stam Date: Thu, 30 May 2024 16:45:55 -0700 Subject: [PATCH 13/28] feat: execute() exposes ExecutionReport (#847) --- core/src/runtime/mod.rs | 59 ++++++++++++++++++------ core/src/runtime/syscall.rs | 9 +++- examples/fibonacci/script/bin/execute.rs | 2 +- prover/src/lib.rs | 12 +++-- sdk/src/lib.rs | 15 ++++-- sdk/src/provers/mock.rs | 4 +- sdk/src/provers/network.rs | 26 +++++------ 7 files changed, 89 insertions(+), 38 deletions(-) diff --git a/core/src/runtime/mod.rs b/core/src/runtime/mod.rs index 9fcc75f045..003d35e8c5 100644 --- a/core/src/runtime/mod.rs +++ b/core/src/runtime/mod.rs @@ -22,6 +22,7 @@ pub use utils::*; use std::collections::hash_map::Entry; use std::collections::HashMap; +use std::fmt::{Display, Formatter, Result as FmtResult}; use std::fs::File; use std::io::BufWriter; use std::io::Write; @@ -82,23 +83,53 @@ pub struct Runtime { pub emit_events: bool, - /// Report of instruction calls. - pub report: InstructionReport, + /// Report of the program execution. + pub report: ExecutionReport, /// Whether we should write to the report. pub should_report: bool, } #[derive(Default, Debug, Clone, PartialEq, Eq)] -pub struct InstructionReport { - pub instruction_counts: HashMap, - pub syscall_counts: HashMap, +pub struct ExecutionReport { + pub instruction_counts: HashMap, + pub syscall_counts: HashMap, } -impl InstructionReport { - pub fn total_instruction_count(&self) -> u32 { +impl ExecutionReport { + pub fn total_instruction_count(&self) -> u64 { self.instruction_counts.values().sum() } + + pub fn total_syscall_count(&self) -> u64 { + self.syscall_counts.values().sum() + } +} + +impl Display for ExecutionReport { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + writeln!(f, "Instruction Counts:")?; + let mut sorted_instructions = self.instruction_counts.iter().collect::>(); + + // Sort instructions by opcode name + sorted_instructions.sort_by_key(|&(opcode, _)| opcode.to_string()); + for (opcode, count) in sorted_instructions { + writeln!(f, " {}: {}", opcode, count)?; + } + writeln!(f, "Total Instructions: {}", self.total_instruction_count())?; + + writeln!(f, "Syscall Counts:")?; + let mut sorted_syscalls = self.syscall_counts.iter().collect::>(); + + // Sort syscalls by syscall name + sorted_syscalls.sort_by_key(|&(syscall, _)| format!("{:?}", syscall)); + for (syscall, count) in sorted_syscalls { + writeln!(f, " {}: {}", syscall, count)?; + } + writeln!(f, "Total Syscall Count: {}", self.total_syscall_count())?; + + Ok(()) + } } #[derive(Error, Debug)] @@ -555,7 +586,7 @@ impl Runtime { let mut memory_store_value: Option = None; self.memory_accesses = MemoryAccessRecord::default(); - if self.should_report { + if self.should_report && !self.unconstrained { self.report .instruction_counts .entry(instruction.opcode) @@ -777,7 +808,7 @@ impl Runtime { b = self.rr(Register::X10, MemoryAccessPosition::B); let syscall = SyscallCode::from_u32(syscall_id); - if self.should_report { + if self.should_report && !self.unconstrained { self.report .syscall_counts .entry(syscall) @@ -990,18 +1021,18 @@ impl Runtime { tracing::info!("starting execution"); } - pub fn run_untraced(&mut self) -> Result<&InstructionReport, ExecutionError> { + pub fn run_untraced(&mut self) -> Result<(), ExecutionError> { self.emit_events = false; self.should_report = true; while !self.execute()? {} - Ok(&self.report) + Ok(()) } - pub fn run(&mut self) -> Result<&InstructionReport, ExecutionError> { + pub fn run(&mut self) -> Result<(), ExecutionError> { self.emit_events = true; self.should_report = true; while !self.execute()? {} - Ok(&self.report) + Ok(()) } pub fn dry_run(&mut self) { @@ -1156,7 +1187,7 @@ pub mod tests { assert_eq!(runtime.report, { use super::Opcode::*; use super::SyscallCode::*; - super::InstructionReport { + super::ExecutionReport { instruction_counts: [ (LB, 10723), (DIVU, 6), diff --git a/core/src/runtime/syscall.rs b/core/src/runtime/syscall.rs index 4915f2640f..c320c7e28e 100644 --- a/core/src/runtime/syscall.rs +++ b/core/src/runtime/syscall.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::fmt; use std::sync::Arc; use strum_macros::EnumIter; @@ -28,7 +29,7 @@ use crate::{runtime::ExecutionRecord, runtime::MemoryReadRecord, runtime::Memory /// - The second byte is 0/1 depending on whether the syscall has a separate table. This is used /// in the CPU table to determine whether to lookup the syscall using the syscall interaction. /// - The third byte is the number of additional cycles the syscall uses. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, EnumIter)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, EnumIter, Ord, PartialOrd)] #[allow(non_camel_case_types)] pub enum SyscallCode { /// Halts the program. @@ -149,6 +150,12 @@ impl SyscallCode { } } +impl fmt::Display for SyscallCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + pub trait Syscall: Send + Sync { /// Execute the syscall and return the resulting value of register a0. `arg1` and `arg2` are the /// values in registers X10 and X11, respectively. While not a hard requirement, the convention diff --git a/examples/fibonacci/script/bin/execute.rs b/examples/fibonacci/script/bin/execute.rs index be8776b414..180da9ceea 100644 --- a/examples/fibonacci/script/bin/execute.rs +++ b/examples/fibonacci/script/bin/execute.rs @@ -15,7 +15,7 @@ fn main() { // Only execute the program and get a `SP1PublicValues` object. let client = ProverClient::new(); - let mut public_values = client.execute(ELF, stdin).unwrap(); + let (mut public_values, _) = client.execute(ELF, stdin).unwrap(); println!("generated proof"); diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 22111fbbd6..cd88882a2a 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -28,7 +28,7 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::prelude::*; use sp1_core::air::{PublicValues, Word}; pub use sp1_core::io::{SP1PublicValues, SP1Stdin}; -use sp1_core::runtime::{ExecutionError, Runtime}; +use sp1_core::runtime::{ExecutionError, ExecutionReport, Runtime}; use sp1_core::stark::{Challenge, StarkProvingKey}; use sp1_core::stark::{Challenger, MachineVerificationError}; use sp1_core::utils::{SP1CoreOpts, DIGEST_SIZE}; @@ -213,7 +213,10 @@ impl SP1Prover { /// Generate a proof of an SP1 program with the specified inputs. #[instrument(name = "execute", level = "info", skip_all)] - pub fn execute(elf: &[u8], stdin: &SP1Stdin) -> Result { + pub fn execute( + elf: &[u8], + stdin: &SP1Stdin, + ) -> Result<(SP1PublicValues, ExecutionReport), ExecutionError> { let program = Program::from(elf); let opts = SP1CoreOpts::default(); let mut runtime = Runtime::new(program, opts); @@ -222,7 +225,10 @@ impl SP1Prover { runtime.write_proof(proof.clone(), vkey.clone()); } runtime.run_untraced()?; - Ok(SP1PublicValues::from(&runtime.state.public_values_stream)) + Ok(( + SP1PublicValues::from(&runtime.state.public_values_stream), + runtime.report, + )) } /// Generate shard proofs which split up and prove the valid execution of a RISC-V program with diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index c89eed47e2..70114f21c2 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -25,7 +25,10 @@ use std::{env, fmt::Debug, fs::File, path::Path}; use anyhow::{Ok, Result}; pub use provers::{LocalProver, MockProver, NetworkProver, Prover}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use sp1_core::stark::{MachineVerificationError, ShardProof}; +use sp1_core::{ + runtime::ExecutionReport, + stark::{MachineVerificationError, ShardProof}, +}; pub use sp1_prover::{ CoreSC, HashableKey, InnerSC, OuterSC, PlonkBn254Proof, SP1Prover, SP1ProvingKey, SP1PublicValues, SP1Stdin, SP1VerifyingKey, @@ -151,7 +154,7 @@ impl ProverClient { /// Executes the given program on the given input (without generating a proof). /// - /// Returns the public values of the program after it has been executed. + /// Returns the public values and execution report of the program after it has been executed. /// /// /// ### Examples @@ -169,9 +172,13 @@ impl ProverClient { /// stdin.write(&10usize); /// /// // Execute the program on the inputs. - /// let public_values = client.execute(elf, stdin).unwrap(); + /// let (public_values, report) = client.execute(elf, stdin).unwrap(); /// ``` - pub fn execute(&self, elf: &[u8], stdin: SP1Stdin) -> Result { + pub fn execute( + &self, + elf: &[u8], + stdin: SP1Stdin, + ) -> Result<(SP1PublicValues, ExecutionReport)> { Ok(SP1Prover::execute(elf, &stdin)?) } diff --git a/sdk/src/provers/mock.rs b/sdk/src/provers/mock.rs index 8ec44ca479..f0d75b3101 100644 --- a/sdk/src/provers/mock.rs +++ b/sdk/src/provers/mock.rs @@ -38,7 +38,7 @@ impl Prover for MockProver { } fn prove(&self, pk: &SP1ProvingKey, stdin: SP1Stdin) -> Result { - let public_values = SP1Prover::execute(&pk.elf, &stdin)?; + let (public_values, _) = SP1Prover::execute(&pk.elf, &stdin)?; Ok(SP1ProofWithPublicValues { proof: vec![], stdin, @@ -55,7 +55,7 @@ impl Prover for MockProver { } fn prove_plonk(&self, pk: &SP1ProvingKey, stdin: SP1Stdin) -> Result { - let public_values = SP1Prover::execute(&pk.elf, &stdin)?; + let (public_values, _) = SP1Prover::execute(&pk.elf, &stdin)?; Ok(SP1PlonkBn254Proof { proof: PlonkBn254Proof { public_inputs: [ diff --git a/sdk/src/provers/network.rs b/sdk/src/provers/network.rs index 4e1b70920d..34e5e6008e 100644 --- a/sdk/src/provers/network.rs +++ b/sdk/src/provers/network.rs @@ -9,8 +9,6 @@ use crate::{ use crate::{SP1CompressedProof, SP1PlonkBn254Proof, SP1Proof, SP1ProvingKey, SP1VerifyingKey}; use anyhow::{Context, Result}; use serde::de::DeserializeOwned; -use sp1_core::runtime::{Program, Runtime}; -use sp1_core::utils::SP1CoreOpts; use sp1_prover::utils::block_on; use sp1_prover::{SP1Prover, SP1Stdin}; use tokio::{runtime, time::sleep}; @@ -42,18 +40,20 @@ impl NetworkProver { mode: ProofMode, ) -> Result

{ let client = &self.client; - // Execute the runtime before creating the proof request. - let program = Program::from(elf); - let opts = SP1CoreOpts::default(); - let mut runtime = Runtime::new(program, opts); - runtime.write_vecs(&stdin.buffer); - for (proof, vkey) in stdin.proofs.iter() { - runtime.write_proof(proof.clone(), vkey.clone()); + + let skip_simulation = env::var("SKIP_SIMULATION") + .map(|val| val == "true") + .unwrap_or(false); + + if !skip_simulation { + let (_, report) = SP1Prover::execute(elf, &stdin)?; + log::info!( + "Simulation complete, cycles: {}", + report.total_instruction_count() + ); + } else { + log::info!("Skipping simulation"); } - runtime - .run_untraced() - .context("Failed to execute program")?; - log::info!("Simulation complete, cycles: {}", runtime.state.global_clk); let proof_id = client.create_proof(elf, &stdin, mode).await?; log::info!("Created {}", proof_id); From 0c8d1bded6dc022f7057feb58e0cb83474feaf29 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 17:48:51 -0700 Subject: [PATCH 14/28] fix: remove aggregation programs (#849) --- examples/Cargo.lock | 2 + .../aggregation/programs/fibonacci/Cargo.lock | 760 ------------------ .../aggregation/programs/fibonacci/Cargo.toml | 8 - .../fibonacci/elf/riscv32im-succinct-zkvm-elf | Bin 127540 -> 0 bytes 4 files changed, 2 insertions(+), 768 deletions(-) delete mode 100644 examples/aggregation/programs/fibonacci/Cargo.lock delete mode 100644 examples/aggregation/programs/fibonacci/Cargo.toml delete mode 100755 examples/aggregation/programs/fibonacci/elf/riscv32im-succinct-zkvm-elf diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 47160c32a8..76c62068b2 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -4956,6 +4956,8 @@ dependencies = [ "sha2 0.10.8", "sp1-core", "sp1-prover", + "strum", + "strum_macros", "tempfile", "tokio", "tracing", diff --git a/examples/aggregation/programs/fibonacci/Cargo.lock b/examples/aggregation/programs/fibonacci/Cargo.lock deleted file mode 100644 index 08f43eb04d..0000000000 --- a/examples/aggregation/programs/fibonacci/Cargo.lock +++ /dev/null @@ -1,760 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "autocfg" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", -] - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core", - "sec1", - "subtle", - "tap", - "zeroize", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "bitvec", - "rand_core", - "subtle", -] - -[[package]] -name = "fibonacci-program" -version = "0.1.0" -dependencies = [ - "sp1-zkvm", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "k256" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "sha2", - "signature", -] - -[[package]] -name = "libc" -version = "0.2.154" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "parity-scale-codec" -version = "3.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" -dependencies = [ - "arrayvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" -dependencies = [ - "proc-macro-crate 2.0.2", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" -dependencies = [ - "toml_datetime", - "toml_edit 0.20.2", -] - -[[package]] -name = "proc-macro2" -version = "1.0.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "scale-info" -version = "2.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" -dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "serde" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "snowbridge-amcl" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" -dependencies = [ - "parity-scale-codec", - "scale-info", -] - -[[package]] -name = "sp1-precompiles" -version = "0.1.0" -dependencies = [ - "anyhow", - "bincode", - "cfg-if", - "getrandom", - "hex", - "k256", - "num", - "rand", - "serde", - "snowbridge-amcl", -] - -[[package]] -name = "sp1-zkvm" -version = "0.1.0" -dependencies = [ - "bincode", - "cfg-if", - "getrandom", - "k256", - "libm", - "once_cell", - "rand", - "serde", - "sha2", - "sp1-precompiles", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/examples/aggregation/programs/fibonacci/Cargo.toml b/examples/aggregation/programs/fibonacci/Cargo.toml deleted file mode 100644 index 6f08cf227b..0000000000 --- a/examples/aggregation/programs/fibonacci/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[workspace] -[package] -version = "0.1.0" -name = "fibonacci-program" -edition = "2021" - -[dependencies] -sp1-zkvm = { path = "../../../../zkvm/entrypoint" } diff --git a/examples/aggregation/programs/fibonacci/elf/riscv32im-succinct-zkvm-elf b/examples/aggregation/programs/fibonacci/elf/riscv32im-succinct-zkvm-elf deleted file mode 100755 index 0170fd08b9b60db07c2de5ec503ef821307fdff2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127540 zcmeFa349gR+4z6v&YgRc7#5i4LfEv{YDb7&ewv6kLECBt6Tn(PB8yAikj16&|2}8thJ;1iw|(FL=kxoO z&nL`1Gv_?#InR0abLPy=3IH3#q+IO6$88sk6C$>s|lZ*{VoI)c}>Na#V!- z^6YGC%HMW=%U?M7I|5C987hy9{K<3GS?=&JOa6-VU%w4X$)6?ngXd?ytkjur6zRX! zj#Bd1w*BS~hT433AN@CgW_$P(yrlg%cV2&m{5<-fe$Gu(scY}=sIkyh`tZN}3H&2> z^`rm%_a6%UhXVhhz<((49}4_mNden1{vIniITY(x8H)A2I}|JGW5x!bWyA)R8L@%i zG-3n3XT(Z=WboW@XGWBr9Z~LVOW9%ma!Qq((^=Ukof&dZI#b!XMd}(%s5f(YsgwPn zO3VsJY|Bt?DqGo+Y~@yk)dKAE?uxqao8^W|bT2o|;xd&8TalLi%RjkBmF6T~en=&` zmrSQr;?_yVHLAi)bRT0T%THE``IF3+$ zz%s);%`lRu)hlyQrGif8lnSM4rEOLEaW}BCK>o|QU^hhYtJ)#QN2|md?e7usg{HuA7 zjNdGdD6^!Bd8VC3n=0yiQh(h_fmP`0-%o!!>~**KFxSlwU_T)BkB^5rJE$|)zYhDk z#+|;B<5w2Yo+D-@q=7`faVJ?8pO0wM|~^KU+~JJkTEQ zx^MW;hSb}U?;h38yr_Mj^PUd+Tt{7>mo*>NP0hd*nnTY|;M-7a5c*{x`egw6rQ|F# z*00Qr_5G%aelUEUP;rJ?jE=F+REhUjbT^BUz4Clzju5#jR%ZDS<<3hfZ)aM$^CO0x zpE8_DP0E?H23{*tiOFlS+z|blO1Z=qw*2AnyZqTvt`@uy?JRmA?9D1LoY?~m@AKUZ z?}^RI$%-0IR#(HzKF4rV)Vn1L9Q52Q<~S>=+-MkH3Ihv0R-KJrvqH|yamxAp2g)%g zD=!=~TB@G;$ob7PqK7_m!}OU=pZwY3&gjT9(LS|_eD z%PUo)SGlF@Y8~7M9elTn4M6|2Yo`pqO~rEECa>It<|cZ~OhQ-mn28<>p~ph#u@G|* z_T{1;ey>!qflGn;7%(%mFO3OqabGV!ta+d+y;81rb?TR{RcZ*nzOJg$||q=)Sr?2|Ue9k;rpy1o_J74(1Zw(IMa? zt^eR7@E4juo078(dp2`46Mcg{^82%%%jlkfuGwxjI$2qv#1;JvJIownk3@gl5p=ju z`%C2>G&G>00SygkXh1{ZU#$-dlY+~zuL~{#K3Y$>)fPIyAFFGv`J=`mn*Ng=>CF5x zZ>eZTzn%;HRvjN7(g%H6zTHJfB?`cuvTa#!dDEMeU0a~MR8y%PJ#g5YR;!%U3gtx7 zs@77uZYp0TZdj{osUKUG-Y&QVywFR}OJFCCrc;bD*5Q=`1_Y_Yi~B|2t@ zo$xcI-t4qLo}5&R8_qGE6m-wNHNaDqo5i<=lEu%3;2UKR&1bA>X!uYlR`S~rbb}85 z{P?_t9EtxhE&Pdl{RgH!_6p_9T%i&<5si}@0oPSkq2#KDke#YRmK&85-=m!B-72;` zV#ZeP3I+P*<6sQCT+5edpKj_)az7TH_r~$&9~o-pfee2MKigHQzqr<;p+F|i722bJ zI%(RbLYhb1P-k6k%P+RJjl$zanR$Z_oddr}&GKa{;4u;+(zehP-dnfB??1iW?^Av8 z)8;$b4|{xSihhiM|LTepx!EDR+o`^sgv(!dXAg(&ck4Q?#W+PC>O>c*zu4K&9(HGD ztCn8bpJ*8Re%*V=qftgixPGQDnS97H61U`Zbdg!{A%KB-hcOQ>u;?`C=acJvbWvI9Dn{yq`1IwtPD`XqA|x>{hN zUqzoJM;0n`6ncC?weogH4Rcg~l^hkvE{sI~K6lvenq{~PXBp0(EW?{}P{khD56|Ue z^GB$bA3yg=tOy^n@7egkkAJ4W2o1EK81TvtpI6emUF)tuf2tlbZwv0yeqW3H4(9cF zsq0pyUes->Q_aF(cI3T`{`je$Z^rD(n00%#OYR{H9b;;Z@**o4)0wK~&b5aU-`&-* zhI=uCKgxFWT2(WL`&aDBt>K;lBX~ zh8->J?4@>wVh^lErW#aiaP6VQ#Qj;ZWowZy{sz__0v7QC_b2a<#8z@|HGdEB_b`8b zYY)Zx@mE5<10$5XyV`If`%AIU_yV-~LB#Z`_JjAkhV;=2_h>ketYtnUhw#HfEk9`d zMC8KVk590+K-qEh<*r>Saet(vTa8Z1V$Ns5U;K6>UGe$5VsG{{rnvHkJgS^?>XdiT zGTiDyXo;=I&bKVg`o!HgR3&b)a^0v3C8qB0>q5&!)xIun6#wFueci=>NZhlpZ?b<> z#VX*DrfOAF0bZM<_zgoK3)SC2UCZmKriuCr8fS=C{0xA4|J<&K+W z*b8q_$<+;qHNP#}2aH<`_a5r4iYRAK$cQbs414n|__CUEmJwSCzA5fSB8Q=Y(K4~| zBfEO&VPvJ7wwc%=!N27m>jQY-Nc>=J$hF=jUWh7lz(|!GP_2@E8#QmomPLSH0L-z_ z9b7Xo-$;MrPODOhInb{-O52gtmpNgqRaMljR_?SBLZbqCF3&_pM2^5CU;1)W1)4UR z-kJ_Y89FHFU>rpU1s#l|=%Ap3aTFaCbkOp7d^!|Bhl;Gsyx5z;GgYE$Dr7!(1@qB4 zz=OF$-rM7m#e9U0!Xw0dP_Ny5h@Oak3LYiQ4f8OKnCTuXOVe_p)mhUFpD}4c(Epx0- zq>eln`N-5iUVlmYGqc9&{*u-d6}x4>s<|a%B%?D_EV-7p)jVIIYLeg>U8Q0(!FMLl zty&dJ$-PFNZ&EcWsk>Xnkl`BmG8sLfV%375$V9}bsm|b6rCM&c-u_o`()^dI(m45J zMnBKD-oWSn+k!si87hqz3tvR<8}*l(l;2UpKAnRcMl)N-VU}~@u-VtYyxuqx*aJB;(cOi9X}__PZ&RY+D}*z#M#UItNF0z zh2nCRxLsm&cx7I(wvB~*4ijL5!BXsH*E9%pUJWvPnKpn^fbs!Ja zfjm$Lo_DAf-*siGCH9E5BlfVhBhdw4%#R)3(6+0}dhdvDq#o9G3tLYt+rl3<+n|3H z4d}j{SPy@&EaZkOL+1IF5qs=3!<|1*IlCK_TR2bIT|bWwL{H`CtJ*B)c~;iD&a`|( zbgOsOKIKe9zvri@`y0b~V-@4eSI$13H&+?n)x?O?3iWflpvrK*zY>4CpZFSCcH~`C z>}DeOS!Iv-kXRIZ(K-+6Ht(u07)QMvb{N*KW!-V){B;)r6Mj#zJRxu*dMs;Mo|S=_}6^&s3idLK|1Z)3K_- zJVaxC&%zfMnzik>;=*Jx_nK2GF3&9MU1$1AUwM#h%R>^a0Nxk?{hO>LO zlDhV|S<0CK3~ZV+<$&^Ltk!;3asa*q`d;jt)O9z_Ql7xTril;c99+%3V(Pb*jEX(^Q)m{#UMi}3z!4);a!7%wqcWsV*M(Mut`Pe!amrf-q@tx*reXrq~6%1-aPNk^WL$drM+W= zA3Mc713NbuoMQAfAgz*vEyEm8ZY2AspuY!q{}J}!d}OsE%M(no*w&oYu10R&V;AHjhye&ta$$R z2FCIf@U!CcRyA=y5BOQ}NzY+N^M?RGD?a4ZJnqj2KJ{z+L#x%m&x#lKz$Z%Cz|V?L z8}xPX*#>;-oHH7jF9JUjpO!O;u@3=$B%XgYc&_;c@FVf2rz@e=J;0B|hy0ki7_%Pu zk@&u+meKF6z>mZybqD`7R{%c}pZC?Lv7fcTkHp9Ppb_}pfgg_VyXQsxwMyWJE+#^^U1&u$EU@6fqxzF`8|qprLPA*bsjyN zwtoPAD4yRF{u%NI;D_RCHeU#xmjfR^@qYZoeanF#iccGSC3VO(@;i0s^^9vU@I&!Q zD{i39P~dZa{Y-GH1b!%PHQr9YMZm`|c={J@$-sgd@;wwIU5}JP*_$r?I z5pz_0C-7xGsb_59i``;_UhNheT;DC$??*kcfjwdajZ8%f5X?pkMJh0Bxmr=Jd-wN`6Rz>!!+dW#qK_wF#((r zLHj0bAaSnvYLkgQ2h|7l@COqD>w8^%SSj5uIh;EE?(QOOe0-V(j^X3fpqwkne+;bb zA~^Z&@C(7s@7uy(B&ShSX50Ch_G1n4m;Cl44Cikv=yU1GN7~P8(;i>zb=sHoDLm4? zxlQ{9!+DeTgT9x4qhxU{>p&+tTSKz(<+X)5#l2tL>f@+eO#d;VpHH;Eim`5MZL4SW7g zDpU5-QN!EUWO(U)%Cr1@IQ@2ZtTp6&$0&Qu8OqIn$A>j$8~pd>Be2F?126sR2&`#u z8&1PI!IHs&F@|0$fl4-+a%@AUKQmkeCe^pz}czc*yG^u!Xdu@OnrOYB*QIS zp?zfCekAzK*r~koTIHqI@|RX#)^z-Q@R}ds)eK$>e7wy5$koVIO7L-;7aHyY@Y{u7 zUWlJRWdZ#E8uM4#MV@;jHZ$hUN^ll@9r8Iou7<|d16R8lTo>#__8Rg1!F7R;t1|*z zH-YN{A6F?mBdK=)TxW0{c|egn43EGw@w+nN*YXh+W zG_Z%_=i~b~jHNu;aP5^UQ}&)-L7XsFd3(7&{bS`-@teGbcgt>K$%(`S%ZN?(DtF_r zmA&L*!%N&uzcVzR$qVDq3_UljzhQ5?$FS%ASUK0cW_XRXb%`-rHX6~%K$#C&DlAniLjS$mWhJxKfmzV0q!7}Ib!qN|pGFa0>9ZlK@EhP?!QgR(blEx1ls z&dprcwP;vQ)s90cJFfx z@56kwi-3KjhV6`)tYcztcQtZ;Sm>SSg}}8D zS)K7A*BQ`T^L0m`ujvmtbnii~c0H}!4dCq#(J`$v0>0h=-Yz^maWwtI!(Xus@BK00 z&h=?x+{jq|;OnYQ(3rmOSqWdiPrJ3i8SBT!&`Q(zqBwc@_iX+9EB!kr=xev4m}3<;u2`HOZQ=qZr1YXv?QoI z5qeM7@|Y<*>!AI0leIiL!>&UP!Tq-Pl`|`9xZ~iHF7S!qeKCAu!zYYa=2&nwN6rYv z2ESU6?2Al3JuzgDUI=XXMEYvQdk6Hs1pEDJcg^2Vml)oU$Ae2>!<#i8IAtBZS;!^4 z?v6i={@&F21^42=(BBvR{??DD|L>Di_=TpoN7?%d^7!LR!JRAP5?EgHAXnrh;BQ|p zpMZYg%@{IrnY^f$eGu;ja=9wxZdk}%-r&z=`IvxD4nS}CyWgwbo$UUGH*#~p-<#m? z55e2eeBz`;_G9z`uj={T$ox93baFQ&fL-I`Ewb^IKadN7XRhNacvo}pwpG~FHQ+so zzE=eLWDPLKw8PuH=m2}fUJdZx4c_yBJ?$vGcN^aJzr%Nb#y2>*v)0`QkbBYH=vnl3 z2W=BmE3sA3dja&`B|HkfUFbap-P5q2GW2$#cTn~k6NY!-W997SD!K_+-t3jwt~7X0 z#&=lBUXYc@%vxZM)iUaolVcJ8bmUMoHt^Lv{d+`->289*-RT;(%n5#`awhK*Ug+su z-H1PtBYLxk(~xgC`x}t20>g={=XqrZ-@egL)2a0HdO)i!tYLf}+z;wGb~jzcTEc_C z_sd@6Pno+9m2;3QbPzr0SZU>)gsva^eRRq%0-f?Z@?n?ya7F|=W#kO@%Dmb&DR!rE zifNC(4?g^t@&>7pl5Zg0(J@(8a zKQ~uBhCG_PfU&#PU{0sJ1d+H^O&&>Z=`(gyDW$qO=uJ>&qO^EF|^vz}7ksK1cU z!*;HR*HihxF*>mBsQn+ixj%jEhED6r3*y_jacqwd%iTN$*zj;r_C^f>=R(7|j_dj> z(StI7(B!shhT8OR_!c{#Qf~MAu`M^D=dM=CGb+2d zOP0ufl`i&{>y`J;8RQf3t-CEUk^|~(_ht0qRTCIn{mJen{SCM0-<0>pw}rM{+;8{C zmwj7&L?b!4%ywTHY`BYGQ{LN)4RcUs5BJ-H4EN{g#i;a+~O z*lVum;R7Bp+-+xr^Iop!DDU}0hSTvvY-gH%pn1w6%Wn>@?C#82Z#d>U!yH`S1Kjd; zdCv2O+v~7$FV8c)w+|U^?`_Kc*4c*l&JqpBz5G|~W@8Vx7O*qg4xPks=;q87gx ze_-(he5tpg%TCJJ{>9k-pzPfC1H-Mz#SYzVJLm)F!0XU$2DEt-UaHJ>qR5sdaNw84 zyEGhoE4Fhk{POlQJ`P(a8}3~AB`7-=?pMyC2E)6a>xGMf1zyow?B@!6HTXOqy&|#I z82G#wd_L((KeieJPxnF>1!XUZubRHm@TUEa>on%g1E;cFkF{nmC9se^8`&dQ?vCCB zEMzZn6R@UHo&qdnFDQHK8b}Z_u0vectwYyML)WdrHtxgkOQ17r0>95=oTJf0hlG#N z_vnYk=!c-}-F6c;4|||}QTnU?SY$5O*Fm+uPuFXw9+Q1plXCOWW6;G*r2-|c6;#>jUUAiI6*^X#q6;qFFc ztE|B8h5QaM3fylY`%@Q_m#wtjm)L)`=pE%zfO5Wxw$#YdHr;Qd-?8n zs55tmvTqF$Gd?bG3*5i^9Fis1o{_w#r}YEPcMpp5Iv;a+dD$1UeE=4Ggt0Q=Yiu^jib=S zed!V8<;8sG>x-3h$140mUp_T`MLzRHKACf&FY+l@@p;{Gr@)i+A@gwAxzzh>n|i-g z&hylp(?EP$K-|4w$I9-wq10=Jh9CI;$2k0xtO$CizPtD%P8dBFc?q9|7(irR`z*g< zjwj$F1#OUdckYd?Fr1TqXt*6aV3(H`W_$qc=SPK?D>dKf__cW;aG=vJ;J@^;vKM{9 zka_YN=2N~JnmnXwB4zKH70UbIUgdnq^_hOqmU~s;ciV3A2=KD_61#UpgWn+&@G`hb zT<(s$kMY6FLD@^sJmN;Nqs%!wOp@tmc*!{hcabv z-EVb_>V3d6~&k$J%Zze{A^B_7R`y_1eB^8rq)d_9!68$Glf8-X6` zhF*Y9PWe2_=%H@tp`h$NGZxue0G+r(C&!vc4n<@h-61{zGVjNq&}ptuCtnXir@20z zr0iu6J)X?xwCbUz0kq!(tjC$F&CDIPNaijLPA?G?FCr!m%HHrz%-ure+{jhtE(K1a zhi)Cmx1o9BC^~1K86>8gFRN39#axJ#~^Rh>^ z&|S0$8LsbPUxE+t`uWIzSx@_t0fv1)@_YyKeD&AJeHw-Kw~LYcca&{)QqEgvL|5o8~Ypfgduti_Lei1bI}=; z&-P=gYUV&}ey2N$<=!{kPRRHKWV{zbxe92vA3P=~cfwHGHS2cX)1RZ=N^)BD1df7*6h;hI?^0;_VNK zM=n?P<-qQ?MLF*X-a8EYa{Tc>?Z6+oLV0&QPTii={UoT1PmuQtbzckWJ`8=tR#*1$ zo}o?kCd0XX0sMM3G0{UhCUQ6Ymb}F!#95a^k8#A+_d-MTa!__ox(eCPCVuPF!+RQj zdjAsW!@Pzr71_`6ZV3SwKV}0qV+l4xaNdT^ScJ{U;Jgi+u?U+Hl${sQ!-uK+A=it( zOxz7_w-8s}wh2Gemwm05kbS#1JU!)bpv$mhy}=jm@AMiA=n)@RAz}~eH z+1~(upY!uz4bv%4WSq-%e#)clt;^TBF6S^;@>5)jKAoiO<$U`n+5brFeYP+AtF%6{ zdjosYui!W6hCb3bl<$P!roexze4HpdFN`Ipv>Tkb3QiXHBJ?r47JFQ8yJN0LchA*2 z2^-l}>^ib|vVA#vdiQR0KxJ3ExA^&$C)+Qhhp)K^U!cCL-Thu{zR}aYZtg4C{%*tqS1r=MzSmet z%-6~AMh#>vXS2Q?MyJWRkbCl-_BP~x)E>&`>HMDfi5`0?oviirTh`s1wVHMD4$Kv{ zc+ua%_jSYGa;{S*1u<(J6vW8LJpcgG%biGggATeL6#5_ln-v?uRL zJSTlVteofe;9HDhf8;6b9RWTutGgNaOa7{JkY4pF9kaTdvG*6@d(7F5|InSd^CNif zpt8q*0lK{G$GWK|<~d6I`w($MSr2c0)Nt<1*Z#e>^*d|fSN!{h*m~Ofc484Uyivn) zZu=oLV=jX@zm1I#c!l<3N{GAR$w^Ppce5V{UYSihi+(3FM))@UQ(xfp#0A5vfPi>~AscZ{ab@jAcgN`5gYdtcdw4jY4S&lNr9WR2$!THFHP zH%~;)mjyo2uYq$hI&!bCdp6xeZXCTQWwG!0QodjRKKRA8oF@ku(5X=LEP4!kYGY4# zp?gMehECYi1aubNGx|#Cv>M&xm%Vjq@WIFZkn6hG5#1xc&?eu;`??1@Nt_Q3+84sF zcU|OMaLPs&MgKHTZ0FY#pJw?u39R^6OSt88DHlkY=P4MxOHHnSP)gt&y@u4(uLp1TN60B;G|(~0v0$0`6_$k6kx4t&0jgg&?$Qvqv#gNG3oUU z?DZn_o!}t(v$nap&PSFPZ3EZY=&Q2szy^nE?jz4!y)5!( zn|d*ZLw*iz>v^=@%2=L3c3ObnNFL-7#?VL}Zym6^8n%0ox-HBl@;rAl{B;F!_I%)p zd?L>&k0?(U$p27Z-9(s+s5qUn) z0?cu&&A%@49Cf0F=w@IvmjGiI@Yc~Ec3J#N_)FI7Y*~vHzcMI0=yqrCWMqdcG$WIcQ0XpO(DXWKURCMbJPM_A9or`*f+X=E|V7{%AUr53#q*k$d% zAkSi#1qXZ;7rShWU6%4~KlA;Uk>Geh?D7n3z{eub0Zzao2WXQ6^d>=b$pMPqgD(CW z>J<2DRT~}COdgy0x{)h%5*_2rL5^;VqK}bh$-j&L66D`S-)R43^L^m-Q@ys~nb(6y z6#oT%bnqnf#_GU-sgH>NBEE+^ZZJ5#t;b}K-iqIFo{?Gmvqw*5Ef8L7NdO02hBboI zRAid#u`M+#{Ues_iH_fFWc1~J&p0s^JN>GXNz54 zge;@y-7VPVd;g}`Khw>()8x$a-Xd227B;(>SbHb(`yInYmhJoYDChgX!v})LMlA%7 z(S|qtDr9#Ex~l})`;zweB)0Zt8k;P6f~qRUyISN~{O0bQt)T2JJ&Acf@nh;O#IN_h zLfroa@x6P>a~)f6d02U3cV?e$xZlcSjy}-22x4_)|0ON^jyX){N9+l-`6GR0B@O%b zYn^$7C(!j>eL2>4;~d&;*6qBiW^E@# zj$M)CK_~a{hNIVK&WGL!y?&(W&H9m+W8s5_2=D?qrtIADAp14X>LK@?^~mu-?%|(0 zSsl<@l>sj>hpZ228#s9*xWk_r8>sEX6!2f=^Cx9z*xP{(`U@ z-v*9e%e;^E^?}&H(et6Lz-p^o zG@M547H~e~D!L`>O6_CIn!3%t6m6Hao@`^6wT?W>E_2Tr29E9Ra>TcRE$FEMjA;)# zQ)~cq>wXS=JTTDxSHc(YSx|PK-H!|te|*ICeEgGWfBujg3*EhO660B+X=86$gP%Ia zhXd~RmU-~wG!4f~606F1o_*T4@#jBFZXhQ9t>qW*#!2eG^M zgel;}+y!Ole0WQIs-JKLCxPY6P9PiPF9#Cuk{fsJd$q6cj=q`kEit?n?#))pefe5! z@?E?Sa;dC$VUurC?tR$sH@|PVmtuR#hua-+x@?~P;QHK38zV*6cT)F@3`RIAZIIAn; z-zYJAH*fZ{Mr`oX?)K&R_xwQMMpHG@K3*1_OMST2R zi{afiin#j}bS8E8*oHg$TyjQ#_47R9i?2uLjs7L$x&d8YNGzRT?YIUyA7tNz2hB&b zZvtA7H*m+hz(L1ScB=j)v3(D@@2wxho*?S1M}Aq8MSd-RZFWDp{8Zq*9>CiIJoHv8 zysLnRz6r|SsHoxH(9Q6!;|e~$-E0JAGd|vA;H)Hmgty191PD25B%?HkOA5Q2y z!7GE490m<0@3cfMyg@HP+=Zz7J2AK6>B0p65#=N+Tb z-(%TZ@j5Z`IBX2p*1cr~_sjJ@6IoYx$1fpn$A9Hr6)*KW z^h#H7LMPqO8=TOWtc7EXExAfAK<^)0xXXvNxf%S19)Y!aGVjRXAILj00%v`H*1{Rv z`&@^E{iCSG;c>vFP0$Wbpeh+#@=Mpxfug>v(7Id|{;Y#eoYTsv}>^;37I)TexuHv%*!!f~W zb}@2E+}m^$wqdc4*XEmnyF|k!M(*lvAVzlYB7Pn%?+x{IH~tt~d=D~yqjI+(oA=^_ zvaY0U@ylmmbCF@>-Tq4^MxM&=zR1iDNJtM=n0zvd-t*bCBw`1@nxU5RJENR0Xy9nU7usO0%x4cp!N z3;g<%@DqO2P2f4V*N|(f@8OQ_#rpRl)>6<#mz_u4yj8a~i;1ntg-f6AWsmrMvra2{ zYq!@Y@Z4q8{}T0I(e<6Ih0t;Xb+P$eg{JNX8@%@Vb+KwupYnxyYJ%Zi23dxf1Vl<^_LgWO+Y20a@;aEbl%9 zPQdLw)`!!$37qBwXS$Emo%F>$??UA6re?uOc^$WbQ(4$!e}Pv``>n-(o_*>zbY7Ek zmoV?|yrc2ACC|Qucr++G7ooQ#&wex4iw={wz{i}!9NoGJeQ-6ou7`qLSFi>^4%^?e z6s!SIcA|UqJ#SZ$`B#DAblQX*7qE^wh1df*-UWW+YSA;}v>w$sjYE#R&LC%UP_L`# z{9EI5><>BsoJPHu3|nk!9a<&r&!9bY(RzIwH2*TXrFWp$uYu;jLbv#3Z~c?LjylYB z{XytlNX`hHX0rzdKh+&O4ZP+Bc#+@kN`715ZpOcM@7McolBXLz?TzHb7Ll)Nfd?lP zV+(g`duEf%wtKvWoPHIV9YkFD7O|wrFFyBue^X+&#h2D=RO{E{HzimH9s=DPxSlQJ zBi{THxUJ`UE`G>5@uih_`vUCn6Zp#Y-5s-rF?VIX_#m`C#Cq{L#N(TTn6(Djz_@I+ za-L}n+mTaryFHrx7FXwvp7>OSz++y4XK#&TtD)uF&-(s9xZ7KK2fOckJ@q(dO{VQt z?8SHxAB_4Uv)%B~s4vfLk=btKXQUi?MvvXO5dD4=00@9{{phSO}=$gI7X918u~TYszE#g_o*dG<5F zCtL4DNB#sjl%wzz_nZq)V|>qX9n8H(=wz5ql(`_MVh4LXoGEYndps7SN2IOJZA=0d zdL$@27w!d48a>JN!mS#X(-E1=-33lRVDHewK_27x;Ph?u0PzTPus7WgoS(6$kMisR z;0bLSuV$Y;{LemaCrS>Zq(0P&6LGNH>uufMy=*IMe~f=Bb2D-idJ=i*jUEZg-t*{> zo4`f%i0JO?#ZXe_ht3ddRx8 z+igh@3zuM5!9Nx8<@e=&$SLys##aqj?C;OXQNQ_LhAX~x!8`1`Sj*Ukg6Bx&Y=+^D z*dlo;XaJloXEWCReqJlhb;6gC>k{~OKDxCK-M7<^g{xNTypR(ahab@iSpk3cf4E)# z4*ev5axOj}ek?wk`F`|G;ogn!@_aHPHH3!8-6$%AR|3I*hD}4K>|{Kb zqf_!6_8NX5`7hQb&?$NNCPCS|c{KT#4eTQ!&+#GG);$|d#6S($-Kn&H1pD?9`%j(( zr^}A)+xgaFaJtFg`yu;whBJ59F9zOg_+|^)+flEtnzv*fZthNe+%S8fnxNGXe_snZ zBKM_9%-IS*_d?kl4o)A;W3A=`+8^W(o}JSSE ze?W{@0L}N~Q{<7O8Vb#teVVObh`m6z8`fh>(Ywty>%4n8mtZ~qgF}vKqi!R6iQUcE z0j~bLOUUU$_w;!s_06?=>e(7m*AkY-l^N8AN`m=IRhVK0D5_k z_V4V=(I6a59<>6z9e2Z`Q!X)+z>@l1VxCXGi>KWv8N6Y>Ta9S4NL@sFV z#XcO36S<(wJ4u4i3&_%84J0UXA||CDKn=Fh@!2 zyQ|pbo{mKvS+cZevVVO~H)Vy1Nl$T7%ZM|V_B8t&r%unCK?42A~*4sSI=$$;R zzLzKq3aK;SpF`vvB z!G*JUVnuxnd)hwENiEf9I3^~p4C(VfJFXF2*c;=YmjEuUXC|1Z4o826d5<_7Un9&} z0T#c{_xmiFt?w;(RG+EySJ$co2Vir4#PQ(yxFugc-Z>0*L}g{ps7oA5b3V;X#xz_d z?p>kbEhy4wzg*_u55pI0IA?4gb!PHBpE1fg#1$RvrpKYRp%PuJkll2JvL{)&vB*+o z@8c{(%gUwu9xoVH2j8EWbnw5@7`ZW8H zaeU^PikyLA*n-!sksP6&J=@Y}&${;wWgUGwc#J?sEdO1Ss{MyKAAs}jB8SX@v!VI< z(7c>8K8ILxmZBa{RR)i`bES@do_4m>W4tFZw>g>dW;r>Ra4z^v_~Lvcar^bAz)Lq^FOFgEz)NNiALg!618GJl+%Vk9Ey zP0m0@u0spX6dhCdL?X*7mHCr%cR1%*`S&Z{s! z-)!xtq0bBS)2RC?`N|fzs$^`te!5FPqLa|uD>&PoGv(v{`82tr)3I;7L-|;6CatyA zMIQw;>66Gse+n(37iaz!X}VRRkBh+nIjbnfSsR?~Z6s6#TN6=fIL}ui3|X<96sH5m@{TLCx2lLlCwQHlP6g|Z#!ot z^WI*4m~(S@x3)f}xco53MA=x%V&;8F2WBFE|~bcz+tW1aRf!8c?=cRkhzR&Y+R{I0Zo8kbI! zGp*q(ll#!Fj`u4K&Pw6@ph%jtP|Cutbyje;TSZShto*v{L6JTLuUHXy-AW(DWtKZ6 zpZD5QDsh(;Zufj4^JtX?eX6O<3FS)D$3b1+wr$Hy&OI!ukD_Cv$$n)~WGhQ#&97Tm zm4uHH_hV0s&@bR%2mH|Tvb9yt8Ir%ip8rgE=LGca)Y3UDXAQm?=&&1G@~k&xo@$sU z?Az7Uu-O*6Rn955VnyGxY|flAWp2gx z%#?XPA76PkHi7eK=D`{>;f z6}=`Ryr1a2CRbp(a*mz_eerGJ-;>N=fbT=u;Eip=p8G!KR|B8&Hhpiw1L9NG#an$! z?6rTdVrbhwTe_|}h(5`xmGik8Qrk7nXRg@Jw-X}1PO&%}ov{l&0-b|B=IlAj17*yH z!P)5OCh=`$eCSmC5wQmv_W*A<0>5ZmTDK7zp!@4-Q>qegtl-MnBWps)goR94$b@B{ zYFN-IjNcK)pAVa-8S;&ah{(x5VY_qn8E05%=F3&;6U3=M3kv;2Q_(XWB-V*JtdNKJPm?>+HWvzuXhh?(V#>_h_xpA~j6mYfWo)>Az0v(rw45b=_Y-T`yE% zAKL1LidQ~^ew$A~zfJ#(^!q}4UR5L8&`;+~lEwH)_gI;8c5}p*@C|}q`kY;D?<TXx{gI<#KHIaPc$3W{LP6=vZubti-@(XZ+$6=NMN8 zF^Req{|}vEm}Uw3PIO-pHf?Y{XTp>3SoVz8)#i$s`0vDmE5qWm6Qh8a#tHa+m-CzZ z^r!t+eQso38@o{Yl=$+RF2obDe&mEoDrv`eFc>@eu0FA%rgr){qnmyEQkU`n_6Fl_ zjS(eBWrxe4-+Hc$ zw=d%@;;d)E%d+~|7I8~ay@Bm*{hkuIwaa~p-*5ISZ!`9aHe;{&75ao2V_s&gePex7 z0<$$I20Z@^QEf{rg0ZTd!B{`lXN#ZHhyA@-ue!6N(1E{O$!n0?5I@dNabEs_)!P$K zXN7hCOZ-wT)1`kVht<)ydnfWe;k8ojJ6RShecm4Y1{ke}#ErQ1IBfKd5EWD}hSP48w9Oj1c8FTOE>_hQkQ!em0 z+uI0uwe-wnd8Nc!S&2F1=lE^*t2YB*DJ$@mvIJlGlkY&@7J_V_2h!Z%aoJ6{9R!~@owNpe}(UB;EIeM#_zza9f_Ht|tq=4@AqYflzj61&LX z;j^_YUa|il_r=tm$J&azJ2K-4Xn&edKan?|er@JN%eST{vZ-kp=6v)cG!#EOBkw(- zA?IXUp_bd{y#)>7!+OoHE$^;)i`eIbV1DD$AA9~<=SqBGsoV1IE}fmGGL19N{(VjL#l# zC3A21W9uyK>vklI>rLSc|GZi?KSM)1@M(jXbCvL}=mhcAeO^tSjsKU4UmP8$2(OC& z*H7~*=gA2F`t*m^jP)^ivohlk{zdB)eEi_N-#MASg+DVnBZ(zAH~p`6MC4Oq8_t4{ z$yx8obB_CMw9)$6*wN2xZ=P2HnyvrIbCBA$7&mt3clypaE@Q^tdL(%708?=)A`%QzCt(Vy)*i?)L5X$ zUGYtFdfi=~`SND{lJM(x4PxUqQO&1w&qI+|WwmqVsBjsNt&q7T6jZ92(og0}M*fPc^ zb)xBWq>hX+=qJk`KRE4|=M7)L zWlsFI6{q{xx^iOQh|HZEO=&%*>szUFMXw4hbQ{-iD8a=IHGD~5BUS#~WHp?l%ULDo z+L7;qD{_Uc(Q?Fhnta)=xXPa=ZMTmb?}-e%%%g7$E2fH^!tWomo<%;TGR%C1krj*c zsm<7+GICv#=`36W%SlfNyI)ru~P+?UAk-`&xUFDspf8_^_MWf7shM z&5&;o*$aj;-Vw@N9VO?N#rU`vtv>8lSF4tS=pn&B@!HD1&g_+?iAZ*yoj-&l(?O5JE7-2>qgFa^~Y|m%vFiEpJlz`*-}034tE@OZ@*o& zb?=%T$d2x_!vW$rAJezO1a-cvVB8bu;t*xDtA_bkBZU z=Mh`+A&2AR^Q!=#cac?K87fwx^;;MpE}ZOF7DgY1$)A|yPt4@NGL!s?nLMpNWb$3Z zt-yQ;iY<|2@jvLiMuJ+s?)KpFGuC0!EQ}o5yL@*Pi+4-@{V6+KbaFvCf$#HOI1ktMMwft@U>P2IJ`P0iy> z^);$C&00mOobRjhdzyW~O$~W7)|cPKtXrgt$BKU_^Bs@$0oO>9d@N&y2dgshhRu@a z$G5xd-q*Ym*jzg+s@&=bI?j)iYVpPFD(e=PdDh<&j52?|&YW_>`TMMOYo-13AOAnG zZmn&tI`7lgijmilo&)$!D|{$f%=Z~o1#yW&Pl&$E=zxlMVtr)~g6OB^?fRB}+sYGm7h8axyd8N2 zMn*0J{qp9~Fxs>~CKt<^2X?&7|7NYgtdj3!Dpi|}?VkN%V7rI>Gq$^nHxt`^OE@=U zyXAZa_ujL?75eb~7JRrI^VBrul=%OLTe7mDi};h!L-q>zzT{SIKT~I8KZE`w7ogWz z+nl-uySJrOY^Zzdt%rraEpu~x8@hdYU_*b)o|fh0=d*L=yWK5|!~4~iGKENSLySj`;Od)FSHL__eX6*MQ2*+*?z2s4VAppU~Hzo zpPDKDKkF_5@0H)Gb39t7R{XuSeWZMj#F#;UjVIK#@IgCU*%~`zD~q(A9dKM*>En3M zzt2{d&S{m$R$Hm=_-Ab8F>*Q+Uc`>MjM0}r=o<8E5{@}3Nw9k+niR4gO+hi>CCpl4a0J453{=U?2d1KxuZW!Gbv}x&T zp>NQe6iU+?8OKLdATLRpOSwRy@*V)7Kl&Uk9f`S z_sJy5Tl#fXO~A|T_7utYZxUCoZ9ldf=KphJlQ=_Z+b2Yllpsimj*WCggQPR@547^S8b1l-ot({hgS9W#68iDu6%1+ zbTsoQxl+kjVT&{SGP05-7ldk}lFxjPxmc?FweQpl@#B5{Q@&XAk;IZ(53xolz8(7o zbk0cDwMFkpZfkc1`nzM08>f$Udpdft4nW^A%i4Y-9m?E?Wt@JFtYWJ0EquK{DF3jf zv-OF<5Sgg4)@*u(pOb64eV2TPHq3f|*sou{SoAR8 zNDP}Rsf%A@mW<$Cz;c}vjtxM*S61uXmdTkHN#2!~F}YT1m9|Zqrlm>g|419-1Z~oM z)2Kd}2UVeQ&j0=2(Op;SSY{vlyHe%*bu81gtlmvwCnc6ivDYh=|NBfVlNmeo$s&)5 zo?F59v55)MXN)DsZbJX){j8Jx{j6bldfz^OKdbyE$3)J6{j657pB383epY!lk3CeG zy{T>5#Vl#3_r0;7b#;V=SR)}@_L5JIuy?nf@9gd~-IVOzm3qNgn`Nw0 zkFieXd(70c=QGx^E7_+Iq3)4(v8c2Q#yX#|j%}7Y?A?_%jI~XhwlHGRBQR<-j8gpO zlrkU8 z;+1gXnK0jN!}hUeEA~U@XLLLDnoB#a8@Mla%+Ie?=x?6OUSDJ?|7?^)@>`u zd(GAUntZeHX#ONN;Eaz-a*JiHF>;W*>lD}anS!U`E;LF)^_%2bYu;c zHII79_a9k*V=dV4*J|{AfTGrz5BThF0vK zo-8*^iQ5vh=0(V35~G%}X2{yt_F!)vc}%hCazC?no498MIpX2yV{}e2c_e7=?;||w z-4uVWy|y~ampS!oXc{)#u@nG3t1v({@UcQ z@MqK=nc*9;!+M^J(>sL!6MtO6{zVJlnBSe(bhg7Xn!v!x#YYx9qq8Ty;;Hd z{wU+KBijSHSC5#*^*X*ZWluUWlpA3VvzjA%O|W}&$X_2+W+Jbdxkf+8TA4pTi)`}M zK796F`n~{H)f!6#dUC#Ptz5A~POD`uZvz+M3BAnWBH`Mf>pPqi}FRjC(=v4S=Eiv2Pl zwfoG+-PD+w+P@p~?i}*dgS3CQZ%98kRoqGYcWd6`ewrB3&sDdXqYE?h+}1Y#kGzwm z=~|a;%lFW#Radp<4Yh3^R$160v6>kJzvISfqEEF>7oE!9a`RN-Vff=`zY*Dt9JAN- zT8T~6PmbABrteqW0E`0mY_!{J+6wdP-yqY-F>+#C`hA!#)Xx#UlIZwg$3(B}HacCg zZc(Zh`2Af69~X!%)qCsvf~WMsUf5dM3!84U7uK(Tt;X+|`xR5^@0h)uv7%xl5eg%7 zqH|bR88MT7BsOC2|Bwgt)#DuiXL?%f?g?m8cjfVEQaVNK(eY>^<8CQY~64Sw{qA`i#p_?S~2oBF)X9@?W~V%w_p_mt_JNG0=H$=Y*fk3?N# z61g_Z@$a>NTKZB(H%T56TmqY0I#=%h_xPvIIsyNTJwB}}zQz1>JszzzPfiZ_XQ7qH zzAm3{vX17PI&jbMO~pk5?;q!zimx4?Z`4=WE7|dAyfokBhFMeh`9|{$zLDk|_=Pz= z0k5bLCm8>5@I7X)w#bj>m7W=1DYb-W%o5%aD<&2p_T@bQd<@|m&VLwMpxm|j`kN=Q zeh;GiBcWs8Lm`)?=e>^a0MGuP;IE}e@z*2m`KvC&cbPo^{|)_gLjF4Q1oR#JZ|1L4 z|4IHTIRSqa|C{;i*mnVZ{oL#S2mUJgxAWI_KR}dGbyWy0taO>+8~V(?6_BH7@G9R$SiIxx1TNc|G&qX}f+aV*j3gE56^pUv+Kjg~ZZ!Kbr^R7|7!lv*8Q&k({9lT# zC0@^2&i&z9Psdo>KqiC-v=4=y)3F}@A-SYd>S$lI^;zL{;!mx6lX~s?!v+}0u=o!~ zOyNsq{9xU0-JXB0--;9TJM1<3ZMWtiv61A_b>0+T&fgnJ%%sSV;;Sc%D-DzPRg?Jc z|H?b767zdQDwMO2n4+hp-&=Lh&XfMIx2^p#{z~jpJ@HW4zx3{^_+9diBKo2a@@7hC zG938O_I_VxiSgR4&xjok{KZ27FX}ns-Pgd@RlL=PUv%!rmv?LH@ndc4FR^y9c8WFP zvP>L*hQN}Xg}`tlDRLT*60b_WhdnE{j^p0V@JZWzhmT|33)0>d9*Z!h*H$t<{I1A! z_Se*v$~QAz*7p-vH-|iHt#a0~Uq7NMIQOO0TT6K|d5fMA<#Aquen&O(K&iJcoyoK5 zarHGNBmoi)4TKkEcb*;rZ2>C;m<)rqNCU&g| z);rR>Tzp$MQp8xZGWP#kWG@RkWeY7ej#cSB(l*E&wfqm@XZ{oTP5uo0wzR_!{ydg` z%BSC$a?b7f6xzL=q21;GAnnkHpGrIR=YKP9(Cr_^t?uGa$E~zMaFaP_?vKgCx{+)3 zID#X$$?pdnR>OV*c`Qe3HJGhHrbtr|IA9 zeXTep_`Q=gm7ek&|J<8EQfY_LAV`T(*bdj^qD!%3|m)*^njc^3I|w1zc^nlQe| zJnR$oGSBV#Vb(et3|UJyN3cdZf4Jc`Hz0H5BpbkG!A!of*=RV`JIRGaS-V`yx+DI7 z_V-HeV#f&CZqtIv6vm+0% zHq4*Zs?(ce)?CIadl*VX!F)}N6+!pB@c&2JnE*yrUH|{R*|R_b!x9kXA&Y`8 zL9{^=gq9)-hzm+4GZRP+Nz9_4sDZGlsMtY8MGF;CtF_voVC%2N1w?Drwr*|xRTQfJ z`tzr_fK<`>f6iNymj?vu|LJ4$z2~myo_p@O>w~Yny**MF+R(n6q(9f^kJ^S!?6Q|p z*NMK0deLioz3TPYdXLDWoS|TyoB1uNQ+O?V58a~2+eAhWn^Qf~9%b1lJXFrF`V_|A z&rpsKYktqT+D3a+Sp$@LTm4)E=e**rnZ4bk%hh-wGp}uwM_&U8dcQ``&O#<;v1g<& z_qR+@f&(vN-%+L-%*xfz_N20QOm%P0V9td7UL#b_p3=YH|6;mr^G z&Q_5>k-aYS&#bu|w%-|fGWItgWnOM5bK8{Msf{Z0_uQ+) z9#_tsS$ipDj)OfxoJW6AO)Wk_*_zplIXL#IXFld?XU})Ag>(1;%FMh@{Ln-4tHfI~ zeAYcRZ7Znj&Avmao&Au9H;~%{?49e&J|5q9l#6}Z#GBoR_+E2KTzdw2zYb;!pO8b= zu<=8jtc@*aZOmv>KX1>z4LO3&9JG7v6ea%oBko|!jdGVpw!0!jpO@ zMNV6*lHT4U#+B!NKbR#lwFEu+5IlPdd*j{rg2-{?x9bTv_&w_GFk3;^Y`6M*vCcqy zko|Voqras+CJI21AOj}kZU!qsrxYr{xk9H>ey%@j61O7qWJJrX1%8TTYa~vy{u@9!dqL(YM zuLrhuj_hZnji^C)Klvj`o;} zLPva_9du8UJx~7*x<}wIj{9>`7YBoG3HKa#(qAj|ui}|+2HJe=xB8pUlR9u9C+Jst z#`k{U;WsC~`vZ^r?0&4>kp7ilxl><##kn%V-~J}{4faI;7r4iJ9{0_Ds06P#;Fh%< z8RKmAp~rf%t|a}{zU8jSiY`lW7x}-}>uUFuO$=t)+O3jwyB+aa?Ur&P ztC>oqsJz=f1s&y}J#fwt9#p^sV{bis?U{#Q47t*zGrK{VlTB z&Hcb~Y#ZV@1^Mt0ZaMX8+GZar*uNW=DMOcTQtn%->u-IYrft|n;ia{Qy~}*bP;ChP zDSJHV4>((fevZ+f(!a_XbK-9s#(AWZ$@i#z=mO>kS(H81k87Z?4{-Y5JIArMu!>?z@_( zudzzq#qXjYAFkrILrv|kP~vOl{Jz1sbJj`fi9Xnx z*JF1+1b;FZ=df;L&aX+`SZkC=8~cgQ)a&9Dv&;`j-NSSCjmn;!4_m2&CkBuPy!UJ* z4V5(53#RiQ-oj&ZympVl$0g_xFL%S~df(Spfoz#;dy=2j6O2KU>`&v)NcWEC)nE%e z?*q^8U#4;nPwnLS@VM|(;*qu_dxsDAQ>6P5x|BiMO{9={A@l=0=&tYR!f%m%8H==y zC|BJNphJjD#x5!EEF%xJo#T;zS(}&oiDz?OOCO6?ycqPAnd6$XZZl-5g?$^-O*i*i zWT4x759r4@pLscZK$fsS;#SUQZggXly4_<|P`*j3dnk4b`A=m@Th&}rcG{WVUJSb} zS9sCwol3|f@o`3wGobFVw8^ph9KC+elGq6BTOTd^pdvTj4PR6x)q}B8wh{rS>^z# zJAYfn0LIi`(+=5}>D$*Me#QA-_oPwKOO@1ZNxiSq$JIXR<6iQ(C(*|HzQH`%6J6-- z|GJ-i(wD9H#h_s36yn~__XLTjZ<4#AWvvkVt?v%Lb9O(nGEvp{jIHQl-Er`VyJ8~e z$3IiulitIg@gCIYW3d6qSB}j8Su(t*pZD|lziNiGFTafW=q$!CcPnn{pMLUC{Cruz zZXFySc=t)zm#+AsJC(@t(^R)t==;8jPm*)5ttZCsx^s}&XOR^(6Q%A%mWg+-KF%Dz zg!$x&V(YShi2XDz2Xcm@TjITM^9Oq<0pT^jj3*~@r-bTa%!@z9!^Gnrs;Z(h*)zR6 z*z#@8p6uJcb^mCi%U!`(c;Um$51b(L8Tj2mz8~&Qd#2u!lsil8i$iVr6F?b_7pY|&}m3oo%MMvp;9q4_< zY9qp*@7*rotLTTIZ+U}0x53!R+%x!RncL85{vDpq@eX~I>|<1<4{8nD{21eu23Pnka7ZR|@$Ud%qYzutF0HyxePZ9nVYj4t0)fo|}r!i$u*!O#mQn|gsUqV#=~ z|ET?x)i=pHe9%i@<;%?tX0U%jUvpEQc2_Ks^VxxTUXeeTxq<%LkVk%z$7d8|(U^Z3 zA$_&T<3wF2asS{!+Bouv-BvzCbytKLBX0@>m(!1BY*gakm1oI*)3zOwt}UETWaZs2 z+kR+-5x%FEp-cA8qKq5(?!-*wa#p8YEOb6 zgBhHKV;m^|@&q>@D0n)-d$C zbw}X4zBZ3+VY}?m=aGziJ1QR0^}vW{I`w{Ga@KgqrmW6s~}^$lh2NS_CjeG2SF zabwRJ^K28vFY{E-Kxf~eUXR;fq+EQZQT3Sifw3=u^;2UWia19830_S^&s+N!$p`7m zzO|upkH`)Udd0(?dD!8{9XCy%6BB)u((jjJZc4vb1byrETkS`Cw z40=PPuZ)NvIzTvh>xe5wd!vu%-bypx(YAPrOOH1nI(Kv$@p?0jc*~?*TBLZN64|zu zJybsKH}J8>wO=2{1q1X;<>&-CubuxHdJ$XY^R2$%inr43Ph$6R&vNA8PJa6<@qIr1 zTqJThK-Q1+vy8etw@wpzj`+N4yAK|%*jd)@hd0vakyhI(Y)6^TTKQFa&#t$>lW&a3 zTw(mGCq3=Ra~t!#DL=aV^|w4SuI3I^OLnuFzh*8M+0b?1_9i_YFJXM>u>A*e;?Mf% z=N{MRvM6Wfo>tCnQ3k`m@{ag#I~&{NzWk2jQ>~**5l6!b`xl!d_O;eV< zYm7QazNF6IkhZmajL45JUvfXI(cT`By4U64IeZE3&tRvpcK`o#zcu$68~k;Y zh5Jd{hD+L0?B#>+3VG4TM@JnKP``%lZ`v6t=755;D`>a5rvzCmj3>Uzl;5C#qibvb zt$#|byrU&Ll6V7w%eUq+f3s@a*(n!$H{Iww_jCWVb?^C`~hbnKW+z+1K^RMUr9rTBM@oOLO z1p9kg$2&#c+Mm3w+^gUe(3%eaQC{0Di4T$cgx+^5?_?~ z$kYEsybrLBXvCMozkDa=zSa+wp{)-u%x zWzJXci-V+@>WfYb*+y6K}zEzKv8_)?PJ3*|Y5ZL%{=|=fnpdAbr9Gc9rd^^nHu2 z)iHCJu6Xqe*{S{`(8H3pS8HE+fH69A5pT>=<9Q#z*L~D;!&tHX-4C3Ne9qSU8R>h1 z{YFT?gzQt^e$02C|D=-I$ymkr7H!|>fyZNoAMw3g;Vpmr6(!=`Q6}@c#+k55Bjc-{ zbVUMBD(=aYaV7o5{Qc;2S)dfeqT6>9(HEAaW zy}8nNxy=4eKLaFn05A2uB=$KPBOg0w4douXj=#|t=pO7YnSWuOW6(x^vB@9P_ldtK zX;FXH-aE6;p)V1eQ2a|+Y(hOh-W{_d^D())e`%`Ya<2??uP9DLeA7 z?>mAIy8Xzw8C#b4MqtPC-Ik#v-;=pNUFKQWG3}?}7fau6rggEEmdKlwfjL1Rb{e*v zl~3$D`UKr}le@r;KKWtkH}t%pjBQ5WZu0FC!g+$a&DWY~^2|)5L6>PsV^6F1Yxn(U zW2^gR-H|$boId6S=qp+OJe&1T@?y>d3`GYF&DZVnBjgDiL-KS#{hGI8vE)h5XNTQ^ ztxn$be3~|F%S&D!XWUeQJRrl%%XNEQ zzcb3a<3*9@RF4fxba`uQkh?NP=SIA=*$TNMESZ*ho1x0Xgl9g7KG@BCip&F~vUy%YDf^d+rIym5ys?z*#==&mF`{%^kstP%k>|n)i|I(C25x9@6WS^K)ii zR5xoBZRUQKwo%WBo_Fc`d3nN=tA`Z#eX`!kd=oY;eZi5#FfTyZZtdlv<{YogVY@5H zCu_hmCx#vA8tO`@_qm$&bV%c56H3PZ(fxWrW^4VUg|&^4&Le%UuAlb+cDueu z=Dw^LI%|sR-h4gtl;~ResFasEVaC*L_h+c?ovhDqrVbw9{KNy-b2s3N(w6nUX=pZj zYz%V}`R_5F`b_37Igh`@7zgM!KJ6Y|C~nrdUb8RR#yrv|M!siN30>@XgQjd{{`6z_ z2pLx_Q4QN3*&O8k7j2g{rf0~HRj&Ifm!_8s{qHy8^H#M{7Nh(-iFZV2xd(bbu=B>s zlgN(Fmx12BcKTM~>vHmErlI>`-Cgpgj~SL5v0hGeg0eN6Mm?=N8BK54f?!LO71N|?%IZDGG9+z>`ii?!d+6Q+<T``lwV77iKC1qs4y^r4UDmCJYD4t3 zJFy|#D%cCc{z$zJXzvog$aFjFVc5v5t*j*v#u+;~^J}eP=<9G5v}J1@&Rk3HY$L`x zoWv_~PP_ZsT5s?4)42|3lx>qP-b&2ewFmzW^=fgai+hz=i z?GW!Wj{J*$H&GJ#blCLI7&=_Hi<#%rZF*JaLTz)^74vnQ&a3G*Ho9Nze(YM>b;mq0 zHodXlps$B~&va^zKb_W*M;@abPkENt9)CK@$!0qGIRNy10Q)#Vd(JS{qIaml173aY zhHrVfg8RKL^s3K&KRTBB3W^=&V|~Hk%?H@2*|c^2TQVs>_LomJ&k`t|d*OYKz3@G~ z9yv$AoUnTjd*OrnIfA+0>S-Kr9OhXBTO3{YtpDr&e!5KiY-bT9?_To$ntmp19{Q)Z zA@@5jr{49l4Lx}X_5dspdWyefM+SR;j3 zdBQ7nobU=hp@+E7eMta46mXAH_45zLTH0BE*8LrCd5_97(mLKaj>WUx_Z#CzJI^}# zHB;XMLf>?xGD$m@b{kw_p6SrX-L3lGe>wM(@-xo(>VV!n_j35ZYj>Tmmsxag z@PLe6o@Jh%zRld%+P?BFY#+v9GHzJw{cbCLD)T3~QD2%mIgqoJI+QVo%(2lwx%GJ? z*9A&sW&eq(FG`fiwa@WAZ@#D9^c?d>jjUtGZ%ZdJY?8^70`9nbV<2Uju2|JjV0KH`q;fYNrKO9{U6MLKxtwR}%FuCzUR zrqUk2R%!pDoo@rjmDF?JrBi=tQrwR&RZ{<`;~UF=QH7S8hWkIRRf3n+DUnZJQQIDU zmi+yW?+Q!4nmWP-^)SyFVV1gd+Me6rmpc)-hXmeoAD*2@viH}{BYk{<9HkEK%1Nyo z$@nf$O>OgMw+C`3wtvNZ1U{DW}mDIBb)2Tl<^6laId^5VY+J11G%v+`- zD?j2c2LGY>01@-%IW)j%W8&+NMdo%!T&+F1=^nwK9fey*Hrj`RR^BabF&3OTuZ$svKM?K5uW!U7`mev=@0eRax9{u4I#+LVK6g)Q7T@BO zF#5QoVv*?2lyB#?Mi}3XtiKSZEISy`2AT84yHlKfi1s5r-xV|TZ__^^=Tq3Hv7&ml ztna0stmX_0zvuT=qVv$b{;#&nH!)?7A{u2chyTOA5&u7#ulP{^c69p(Pbypc5`Ovq ziS1s>=sWO?exA;Y-<88JHT<4(sq8t8eszfOv;SbY&1Mhk3&uXw4-S#OZ-=BG{gAaH zzyFQ)CqLl(=h)S9P6$0?@htnMtzo3D@P2-vx#ZL-dhpUIRJ79@XEQPakRchBfZj3 zG^LDGE~cOEC8>EdW#lMD*-KqndSZ*M-i|{CtXzHHYEoV$Pf|~8%~yKzQlZJlx>&8I z3-Nf3dQLVXkS%qM$yj`TtO_k6GHivbAdK+tKasVMC}TEZq|DoUX&reO4wgJjjV-Eg zY1T#hiey}?X`(jjwc1$YyyPepS+Y)Rg0pB6tuoexGSroBWo@#$S!;~d%}bK$ghu;H zF4U$c8yD0xHPMvHlXW%8#Kc6R5hXD33RJXSmd2WS^P4M8l|5byg$p8uMa9vQ(pXhI zk*rp-2W#ZWXcxKseJq9_O^285GjzC=G0N-Istt4oag@S5M8)Fean%2r^$RB?7S(C! zwlgLmnz04R#2M2oJNbL4N>et(HRb7q^i!JhJiimJ)|5lnXv$Rl$s=t(utHNRmugA_ ze%4*7DX;T)pEl%kxu(FdN%bvtiJ3LTeojlXHnM6_bFxV*PsS3p_3_J^=OY^l?UYkA zqZEistXUhMnMu4eKhu-|zjOGNy8Q{iE`DqIm2~Uso0H?U#+Ewm%9`f+TIG4OX3U&> z=ESppH1oWPXH}dYuB0-rsA;UPTYw~@_vmLu1oh_G)KD8+gi@@Ek%z`uJV}CUh<6(C zu7cmv$1NkVllZmsq!yldVwy7fI<1R)AMj*&BKZ~B+W|eElsewuD)(8Jp{6Tlwits!i^X8L;&Ke{FWOL(hpLTfd}=%RH+)g|sNOSHqM8NHt1^P^=3_h z;R~eSYBZ`%d7Ush#56ALmS~FaE{griRHr8L3tealbkepa6dSOw;!kVV$rrGr^wTUxDL`46V z*I?^5(-Ti=>ioOI5g!$F!i&x$_&Ig8izbOlyr_wux%027_4N%ikZCJvp-hg|C2EtV zT{xw#p{3dUyBz7CEq3rl^yD*07craEQd>(xGm^>6M5T1bd~Qp9bF5-vJef=+6XHCx zzJ987KG;$9EsgQynJrBeDj9ESwgQUFS&j8{Mos0(E9mu`2=n7u-J+>Ab(b}nnUJVN zK~HR)*CN_%Dr}Lc>+9xCkzTg3r2+QN>J*q+b;*Sduqm0SsINxvo>To}-Fi6(scf88 z7pJ|>t8c`NO`yN2>s;Pmyi)h__BOG|jP%h$&*BxGBywy03SGj9f04<4yy7N)C0+?D zf6FUl2BFC-{)H}K1WTGhUdykfA%D|M^z;hR&7Xd%Df^I5l`}56yn}heyl3)G<4r@K z&2JTNE$<@UHr_S7>v@04`+MF$^6ugNly?I0e$B7@0DTPa0NxPq1m4NKQ=wnP?|j~7 z-ZtLbc{lPt!uu5O^Sm$eCg=k!9W{L|VZc&0aT~UTepLDhUT2%P>zBy~zn^|-CYFI$M`c=gMd__g$lQ;!V#cc&iNMcFMr9J(3X0Npc&U&GA8T+`~SwJNa^n#POP z6rCxSTRc`*SC3srYiVq%xguFhhaJDXh32m1g~qd3rQGDoUhjoE}^^ ztk)C1nDBjgMOOEMxs-!e4pMR%gn&zekj7crIa6VQR((o;5M2UMhzbEp$o(dD)W{f2@ z#=Yc5uLIfu<3+KJjifS_sfRSBFMebEN*#0|gDrY1bcxfMe?4*vx&e9~^eT)ck@2o} z^6`$^oUt2*CTvu`GvnV++@jZyXy=(+(wX0B>mz%K#`=a#W#qS-5;L_^L~`^gmgAWgQ4Vg@2yMvYp^csL*qNWE zMRk%H{FHrX=>2-?r~n*VXyv|RN}zf{^SHW}1&04R{GWio8s7fmKNJdw3PO=kVW=on z9EyfYLZ#tQI2g2IBLg5rW`K}kVrBoqlp3L=q6 zVWcQh9EnCsBBh0)!f;_hVWhCIu&A)OFj`nrSXvY+3Kta=MT!cGii(PhqD3V|rNyD* zaB)F#q`0uSsJOT|T3k|G8VyCm(Sm3sS{N;g7DuDel4xm3s3crcP!cIAEGa4}E{T?u zl$4f|#Zr#K+cD7wbN`QVem<9X-cM;`e_3_54~Kqj%iHc zG#dRhbGoN#HS`fpcxsZFu2Is5S1QW?l9t$Q2lySqZ~13NUp7b`qA=ClkrxTtrRR5q zpNfC6C9S+4)*4X!)~IYTex)sBz_c;^b_|a7nS@R~&`~!iZkdN-fTjP=O<>~FthN!4 zjC-c@%CCjz@VDeeadXDdqbav~E0s%v8WEnmHsotjBxNhkM3K$K`D-4GoG-{^F#KQ_Bit)A#*k|9ir#GIbyc(O4{L{u6%HM{}RCd2N>(TdPvp?QDrP@)I5*M7C6;=s(V6Ube^h33E&BMRJT9V zb)q_6f_nmZ$#e}=U9M8qMnsuK==57%eBs}_E7zjpxd>x zOi`a>;r}MJQd4|2F2$o}YOd)ng)({60WPn4hihQ(9_om|fUJCXh_bm{r>JMad6z4j za&eY~SY7PpRMpY0fclBBO;uDSH#e6itG=(^#*!ta^o(?S)cc8FaZPtm$_jg~R*Q2+ zQO-1-TT181n&uELB=k4v5F7FNO(^&ZX{_SHG7s{PcSez*6zfE1>`aFx0e zf2!+$$(xVg6I`GhcBtl(7dLC8F9O=_*%I9+D!*In9L)7#7 zkriUO%0~k59BGrJRE63t^s=l@*?c*Q_cXtv{=joC?n=I^zXA_D-ax?RKgqL}?K_@= zfZ9{-=T&ovwU-{FH=%AI%;_FD;9uZZDqHs{%G=Lt(!yXD{q65r2U*x4^R&%|sX!ZM zZBcaF9De0tIf{vP#tOzD0&POO{kNv@qpZe{*deE%KIC*JH{$cLsk+S7W@-#Es+-4a znT9(G_El3?{+6)PpZ=L&v6VW!^0(zDXP=>0zcl?=ezmK$G1_=dyE=1B<~7tND zls7+LQS$sozw{sUF^8#iOD#8GCv-S?@{5x@fDM%{BYViiR7Fox1KP_ zAIQw=)4#ZM{DTj@{nw1>np+?AXP$OObb$9-_Q%26Z zXT!$(Ha+m*FMsp&^S-R?z9)|VLB+Y7A9(qX8~g(Xo;>`FAAI=nr|BI#J=)OWBSuC_ z#!vp?)af&3oqxeab1tonC#x@OT6oQMH*EUFuO8d}+M~a!tN&f<(vz?Dx;pe^c8~WC^n0@X)2BouJtF@6K<1JW=l$r^!03JhM-1xI zKVupRl=m3m&-6_WoRZO!b>{sqsJ6~X6u1TnJ2o>o)UHU3}pIB{h3RO2l!8O4?17X zDd^F5cXdlv>+?5EjrUj<%I$Z{FP5IY@u{Vy{?VQ}z7d&|GDmuYOCP&9`6ExMzgL-v z#2p6%%ibKF@$(OtL~_&(@UVdgy-(}MW`+Ti$oa#Meh}tmLJ<#J?QZ~5Pc(1zTwb4sIX#Hx`R1a#p ztylTf(_5dN;8Q)byeAa8mh>FsNo1d&+4^Y7i9N=6GW@QdzSg_i-uCoz_i$h7nd{5; zs5#l55(+mmaPqVzGqX=5FU5hLc+K#){$Y3~+vw%a37^m9_XYeJy)p-74agqYBe!RE zjwjdMo4u+1)c&44b%1-I{{(fAYj8i!eX4tGR=yf?hg}8g1FnZ$zwkU9_}cZ2_gmL@ z?sUd47cRQ-rk{sqUvT5nNesd^)+z;klGWY#uH{E>ePak^xH^1Gn^Tn6` zvG<>8#iI*!bo^0-+asCPj3DFGdo{+t5?7N7tcBH)pzOE1(*Nh z-JXN%>Ia=T_nK=T{nd59eY#)&lLk*Zd)hf7|JPpk#E#eBcxT^d`x~2XX>PfFMEZ7Os;LM6Ox6YW?vg^gy z{`B@=Km0DOXmd|q`mSebdEf+(uh)`CdbU379h|Y`1owb|>KW%L^!VMX-{GNT@VVLo z&rgQ8?(!~u%stSz^jr6Z{(c#G86t2$@n!l3`Y!aJ>YbE1#)E9Q!&zfI1ASTU)<+Nx+yTho#US1FA1FLU7GHd7Z}%Ttb0h#ket@lo~3sT$m+Xlt#=$9va4raM(giR zZq9Cfb6~c&HSKMEH~aH@+|i6BbNaMy3$*^ho0)f-JJVMZm=wtNHD{gVzQ}W7Mr&K% zpv-<5Q$4LW_#WPr-QN@5=vnf&5&mqiw{>&wlKp;F8|{O7lc)7}?i1WOJ!EVlk9yU4 zin>@;Psn!Z;|-Z>IHac2GQTU2_!GN4Fe9Dzhy#zfmGK@tudCZk+&;oh#^3VD?|j~U zxUCb1@}9ZVm#C{;*SmizaS44D?|kB(FUCW8Pt8ex5a-8crqgTq75Ypoe9Eia3%hXE zW~I}cO!@_#^tCc(8OHlD?*{w~GSUbo?0#5+2V&s+$wQ9WQ$Aq+Kk&i+#Zy|m-lQ{ry3cNJg$MZ_~LYWqzn+t zdsbFD^N6$XYn%AHB%Lnf7k_0=e!Y$R`b*R4+N019;{MUxqto+9zc6;>_+_581p3UX zbb2~}lYVab5>=m{!q!$+<9^U^FEfj#(`up3kEheE22GnRW#ez*iTv?0v|59fYlYLm zo1hI!q|=iby9rO`bmfUY@4E{>W%JVM#YXrt$&c`VH}0Eox7W#+xUI)c_$ZI~3lO*X z8>71zZi8@p8aJsXdBk4`w?`ad%W>Oc^C$6MV8(YOd6#$=LLW3go!0nU9tpD=w~@Ft zlRsyjO1>U}zW68U^mcotFx+zMy7H?8w>;eJyqO9J*!+o{RGMM+G)y^>vM$6ugx{mJ z_jS-0)*rdOOP;nt{|LIIA&S|77sobo4WPsY#7jYsCS#6KVU>ZWvhDu3J4maxm9Jq_)7lV)$r5_S{x%I0+X z9fKaS=X*Oet>ti<@aP?AyP;8R{Smi)xV?tkFw;%rm+Lomf1;~I?wqQOXx~%ANRKk6Qw_ z-G*OX#|Xc+;67#%a%<%GFu8tR;<~DQU-r8*Ynnvt-7S35ol4Xv3~C+qGFA;{Gx2<+xAgZ;SVmjwe8$gnNUL-|0?1 z41@mswPxK^8hns^O~8FO?izo~BW}}i`xrN?&c!W(+g_VL$^Sy!_Tg4;^2lm$;(sl) zJieb-$lvma+k?23;AX`u`F;OSaE=*%yV#i5I2p#;e{^a;@)hAUnTCY3v`0Guf|=wvBSn%qryCK-z4!I z!To96L#xy2^%75c&kp~uw(=bO?YcFc7Mp?ml^v_UUM>FDc9f@!jVtLs0=@jUbUN3FPdk!r zDCK+|e`D6+kH6)S-;Zz`iJK-4JR&cLa4W=ZrZ`YPmJS&ybQ)SMG*ich<{w_hb+A+K zcgyj+@J{-2GakGC5FRI>Z-*W*+q%8YNj{cAfAB8&X@@xSlhbXwAqN8>$++n2a)G24SvM@zUtOsp;2(3OuN+*)z7;u85R zH~lTeXi&CkL8Bm6FOxHscId1Kf9QsP;SdpYj&jrwhncqAX2a9_KrlLs1Z+i=^0 z+eb$Jk7yIWgP(<)X-{Sut@ysgU3t(eRIoehzL4-0XUy0k@epH;Ho@ZsoX@@i+X_^^CZ$$GsMJQ~z}6(k-~J$K8~d z4)>RFe+PF{4m;{$FYaT0kxnNJKInXvavs8c;lmwm|Csjl7&bV)_R9|abXfbG3Vr&c zonyBn=>?ISX7Tq}I=z;^rQKONTm!CwwhP*7Bd^n)aw+X;3w}bsPN#SAw}iL1Hw~xP zp}!4%*-_$a{+37FviWBwZn|CsOC4yq&B4vd(-PbtIfDCi+z&b2CBFH% zPkn;%ouM<=sJ2W)QdaTLx~<5h(0TOw7q_QqKSnt^WNi!X2Y+MMr{P`ycf&oJ{u}t2 z@tb$A@w>+S)$yz<_Q1Ai@mh9@%LX3V8?J>5^F#T?V^2MmrS*bPF>eve>ETnW3rgal zP;soNq_k*k_*xb;!q-|}!qG@UxF|nd6jkKJOuRF){Af{rXl$MAEN8pZ$b!99vwV?7?_v-D^I0Zo|(D2d^d!ni&SFg` zUqasr4*g4mDvwKf4Lkw5@u&)>$~gi^0};H^H01 z*10voy{4gidTP2I!^*O95_l7sYF7l01wROGHSueNw;pM4^7qIb&2&o<3{^!BgIVVZ))|uGBq<5;&T`uJ>;5;inFrTzi=G*XWu<+ONe+F}r|0(HPkML_c^zD>qwdwy?;HkYeMRdG`FG68ylxF~R2|p9O*eW0R zi;Fl12`)3~Ia&N+J`(>p2R_|_e+1r@rT6s!@&x@~51Dl366|HLRliG# z&w7NvKXc%x9r&*fe87Q&J+0V~bK(;E=f&LFE1C;Dt84 z7i^s!6Z(kCuJOO%$j>JZ+*cAZAK~u=2aY@N4G#Q}1HbIRpE_`FQEayKiX8X?2fo^Y z?{(m39C)t-`=#Tvr8nAv&vxL1121vldmZ?<4*a$Q?|0zd((&8!GtPmhI`BLPUh2U2 zIq>ft`0oz-N*qqXP9fq&${^BlO%fq&+}zjffZ9QX?d&gpCA#%OP+IxttEch$ zzZ#FKe2agJS+JOOmVZ0l#ims`Q@g=N7i>HRf8^Y)g|ETC zV7m2=`0VsAq01RudwPPc@MEYb>pZFS@A53P(a(qe>OLcWp)Udd9gG=CZMc+2zWK-FS@h*zrvKH{f4uzu zTr0liG2(OLRSPtoYSEqe%et;~C$4PhN_XN7mv^Pxan?!n=kUj}w~E0Zk^fwBWaVGZ z>KKoae>;xh{~-Pmd)@zPaPH?_!^=4zdw3_7^FemH9d9K*%@N=04*z!iKK?^C|2+mX zezxHf@HVhjKXGuw7oGTK@ID(|@-^s6&B&fve|G#7{zHVf__Y@-=gIBzF4%ZfrJO&l zv)aO6saor-xZpd%)|qj^&x5VA$bvDYI?j9x9ymnlIA<-m0&Ja~7Tf@~&O{5o8*H6% z7Q9o!lmBswQGZ(#=u_miOr?EbKfebSd6az>g0qs0pUJd^i@+jpmjBO)&w8YP>2WgS z+p$ATetUG%CL2En&Sww2)qY&u?Fkk-%~VfsI^nHH;*-DSEVc2FDIPf|Z9GTDa=zM5 zmvh+NVL5kfr^}h_?(i-LUG5vO`?up-%JbNlo%-qyum^0(&$HkOU`sy#4_t1e=MANP zZCKJdbd6>tXUeA&%UN^dG5BN0XA$4q2aNtimk03TuR8J6Vdw+oV*n8d{Yr2j(m%z- zKL^hQk2Uch!E3=%f8zfjSkAxpGV##ixbHX4Sqgm`SkA@fnDj+pIV0QK#GAl!Ue*f# zDp=0WO8b)VUxVcwt)=gWk5KgUv{@#7I#|xu%CKDgUk#RXwlYi;ycsNKZY}zsz;gc9 zq8|dwSzIfMj=l&d@5MZ2wV9*A1r5u zt^6(l%ei4I{3BpFLu}R0TVOd)95mB&jaKxt#a4dCg5{jCg)achnPZEeZD2WnY|$SD z%UNWv8Q)*QaxU5Of9~bvpZ2ufW$1$&z#`wf@h|%5N6pwP$d}&#FkbvCSoFgflRmA* z&<`FHd#*qpp8z?SGx=KY1ndVPMU~Z-5ul9^{en=}#9LnC$8J&*0XN zjrfG#dlBsk|9bldp9fxLqo=^DZS>c{>%o3AzP?wX4{h}G!CSyOzliS+@Y6Q>+u&uk z_y=4~`?k?90>2FQnepEZ{p)^>^YTy=40t^xp%~P41FZ$%Pp+oKXkCuo)C9Aqi#IZH*`6puGb$eOdi3;W8h`o z;B|!8h`&SMg5`|6-Ch@Lk8ju#&48qLGJ+*|4K9{_EZBIA^tagXvp=Ceh|l8RlZ~`L zuqA&Vf`uQ2L?HYd)@qd3lE8&F8<|F)G@4(v}SiIWvD|puuO@4Tc z^2j|o#&cvWcjwsYPAvE8SoGIPKlk6A`b8FC6Sn#oJr?-~2M8ega~61$jou30Yr_(+ zJ$}I>muvFFW8~L~11mJ0YSHcZVdA&$Barmp1UHi&YFf{anh(FgIO})}_)Dr6bS&B!lMkN;lq7>mE8_a1l<*lMqbmURt3oBUgk)jnrB_>;F%Grbu6bmA`^bSIX( z0E|af<|Y+I!oP!qlI?*mw+n9y|uV;D)aL?f6mRSHA9SFMkDB+OVXPcVpM^cI*iupU@w~ zpXBcnu-w&CU<=pk5NBg9s|q0Aa?(D{3p`eM)~vbAmx!~vd#ZD&^OrV!wb-d z(AVM5k{7|oW8_Ef!{`osZs|%Nb_~45L3iR^YdYf_+ho*VAsLYRcnU1}mq++rxfuDk z>KhzGe@Xglpo{-Ez`{@2XC*j*y&(J${V8~HEBX%qvX@lwF!Ys_cce*Q2bTKTZQ?(G zh2K{A4e-x;q<)_U@3ZuS-b&Gbw(^MIk+*7Q5QD#V{A{&Bx8gs!4tvoyUd@e|LHV)d zsoW9YWCxaeK8(jm&yL3s-_&n9?PKv*Zu37IdLHR}aF_X}R`6=*vOmd^7s1A(Do;ai zIMmr*KLoF_;oel_HXD|3hf!T%$SF&|6b?EDv! z+~Z_CM*YmOVQ&%gY?B}Hx7bD(y!|#!et1;nZ2X68{#U{;iBE$n<^R()M*UkjvcyO~ z+ob>dCfXbP=n0nmpLR3t)rt>&y$bv$^pPh0C2-!io%NZ0OXpoJ5}waLbv#!2?fDhr zm$v-to^RLmA4^`>9RqK0(08xv8s3S^?(Rx=Vr!q4mA)PSobt?}yt@1#|MFP-xGeup zZ0+x|=uT|y2ear--1@W5{Qi;jt$S>w{kcXD|-D>-@;F;K4&aoJZ$Bc`nV0O zz%RYOLLQo$4EYf;mGIwyg&$UYtD9-B_h|b50--;JeI@x@X!`fje@l5SJpOw86MvbR zpBunZUW@)~Xq z{5`f&lOG=JbLhLR`lSTdgFgc6`W4&`w(cAfc{z0r;i2oH;eV}(2T5$;|8}JJHTdAh zuJ*EE<589KO3;sB32*UFu<@wM6VMNmUKS3LzC3w9*YsbDpCt~w#)jV|y!*S(^^VL^ z^cUDFUlDkY4NJt^ZQ(1STlXGG`Zt2DNBI4q1MhHP@oSGyaOHiP{O}m^;Ka%%O{ZFP zCtmNMJF(pVV?3(zOX_Dm<=cgW)Xyj2)mC}IH{Z(qC|Ecv^!%T4cO3Wx6Tg3i^4Q}~ zL!Ur;a=yT-Kf%VMDl^8@UegwKDRaOJZS(|K?mM#lF95Hz;TEvmqh!&q0n1%V7G4hC zX2UmuObE4bB`|5p4zNPJ=sN&F9kw}7qki2wP|X!66ue#pCw_$+(q%_F2|_b;IW&uQ|* zW9Sbj9^{};w&9PFSBY-}K}Eh>NMG&*(_=%PzBoeqb8O+o-^usWN&e+|$L9Zi{9E@iN&RJ)8Q79%@jqyXCOt){DVcm2)!7* z1?)F*46Jb9k!E6k6uINicvStziRJ!3JKc#NbI_gm?U%cTcjDSVcBMP^VCziVnjmIdz9j}I8CGgAQr}$fA^S>4PGU)dDI%uQ64}GnJUioLuNRArn zaVFzk8@&W<-2*1|R|U52`VzbvY~9}_cq`btn@jNfVC&8;D9R~dx0!w|c({%JD0s9D?*nT# z{{{DA&)ewD;BjE9JfDIKZTKnpV?Cmec4Hq5-q$(*a5DVzaG#fzp9J_z!t3$@f8yxd z0CWq7e}?{nKG4knn~wOu01v{y@L%fV#B%yeusnk0*=3U_!G&*V^1~ygI2=!YOVizj zem3!0_nJw3FJVted~yy=>icr&)+6P;*@1;-kMChKe^&qgCb-!uFY&7tv=49Jt+q|KY$HQ@X}q z=)iLw_yz}l!hv@?aMlmI#$W8fF$Z4lz*`;oeFyIGqptCnIB?v7Z+76P9C)t-=S=My z|9A&ZI`A3?{;dOl;K03p+%^6Q4m{6+e+sV5W6u5#oy<_g<5BM znr0Z|yM<=>&ESRbNA#Pd-)|=NW*_)x=I2E4^Fd8HXwrv)<-A_N#FN1a^Y0X&J#1d3 z0j%2a((?`bSDLY2zhJSS%S^l*ydD4YUcX(qk!V){4aQ=VMt zr-9!tvhwFqehilR6}dw~!v8neUO#1X2xzO14PblyTyP2f^G=O1u@Qc);Kw`D-*PGK z;{nR!GU$H?i@j*c;~ka8{6-$hNc!)BWxhtLL2zD-^1amA-e!Tto?dIxQ(zgt_c8HK zu*^S&%<`ncGTyM#8()RI(%)P7YOstKt@ij2u)Vxz#JiUFUa-Brd;_+Z_kslSmt?w7?>485`BIC2_ur1kr!?j~ zjPSeeFvgoQ-z)Kj)=~e+vlZXkJB|4!x#L6VPu@#%^HG#$CBLy=E;Lv2lk?|R zH}cUSCBMmVXsTjKDPRAGkA=#2gzzkP2ITVzsKy$uR8B%~TC{-Mcln*q9qYzl#;;Oc zQ&nHbcRFh3^1-orM4ew<6$)1u6<0-ylEu|kiO|^iyq5fsGWVis5x)6ZP*Y!|e>$mD z|2WlLK70_4&M%5q6&6;7N<&rQ(qwT}NrjR>HOAM-@~exg3!Ei5f4t|~35 z4i%TiL#2^qVO2>YKYH9gOC<}11#^c@ojGjSd6S0C9M)108WwBPf8?Iy{CqyAke^?k ztZJDz?ChDtB0%yMjwi`ebz!_D5{o3_vE$EMxafN(S&)bpR~5%g;-&GD;z&Wk@h4eO za@_nVC_H|zMaS>8`1rj>zbAVNi>l%!d_^KuS`sd-u7*9|uV#@Sk+#CpXso&_T13r$ z&v>d!qt&H}a8+qls3cnbz2iw16_qASt7D;1K}oWpBw^%7L{mgD!iPSJ4Dqd5&`^71 zu@#Z#j&Pl*e+k7V$R*)etU6wh2p1J4tHUuGnG{!#zM;9Xpjf`TGPkB~E}ub+C#98i zL_jNuL}+q+vZJu5x;PrCD(xCL8a^zr{za4g{Hpqe$wYoWAC{CDt7_zJc1ggD#3kV^xLG z(t_%6I9W{s`BQ&5b4oZgH^g6Op2;8K;}+tuggHJ{6_!}_=nIZN%zxlDVnr{19A}n9 z2k2Qkeq|7r7OsameytEbel;By4W>tb{F)?OYK1xebP75u`#(^b9W^Kk9v_Pfj=u&A zj=$pmgX%i&oF0F59>2^-M8|}qhgk`QlPe}pr?JPA(PSi6TwI-uN2{uflK(+ZciiPV zemN>p3NEjz4;R;7w(znm8>$iu<|}+neXe{>JwK7CF0AGQk|ps-qM)iO)@jyssL)8{ zFfAyC#;~c=F*tY){YK9fDvHv<<2@QJ=qz#p9|#VI64g~zqW_AEA`vuT0qiNMDo#eK zs<|7=D)X_u77OD`tlXDaAJi^3J~9@L;vlwHeVl)5=G7$=B~l}Er=K%}TH(ejZm5bT zV$}sz;bduPg<-$_C((sV^-u21jn~&E=2~CwAZq&Bl2VjzG+Z1nsxIxcrjA*p&W3bs zuN}?f*j_tS{jt49jv)=& zUFxw=M6q9e!5f?14Uy_QI{Pr!x*>MQ zp>TH`3U|jLG(6w=NzCQ5YW$yH#rN}~NxqK9a3>iGC(J%aw7TuX@c9L$Rf%|{5RZki zNL4|p?yW=IBGKw-X(CY-PlOVMC5$n+f-n>=3B{{RY>YDWu5PbmzwTu5Nw-AM32fvaAkAqH@Wo zDfvywcsM^n?+~ksSEEGujAy9Wiub6rkaF~JD1xJgqZmh}6>?QgV}87${(fs-=^TXllSiF?!)>tBnwR$|%u+m-Ff^MmiZmEUc zQt1er6Zt3w+DwFraJn{Z0)ra`U1#!24l~td7|P7OIRd5QXBfs@dT|KDAQtXAmse1F zc<`~&ON)xShA%8QEW9~VAP0P^J3oJh{%d9?nkdC&O%|5Mt4bMN z8`FIq!;X@}Cl-yV`o{m)+`05fk|cG!1`r@2V8xBwE?OZZL@M0leL_7wJxptRyGQ+4 zmQxZBkLl7>R~DI7+td3A_y$}!z&GK@nG@o)XTAdxKXdnpd_|^vRqZVFZckNLd0Ke* z!`$p|e=|3myDQLock8mn^v6y<;qYP`EDU)z5a?{!u$g5q5@u08s z$f6Bo*!M_WG()b#75}*$bl;l6_ohhKkx9Vjn1%cDN9@XL-HtUH|n9%tS6JNA1qGTk=$VEQ~yYn6lL zf4`5;hpW5Idq%yfvExjVV~})BIb?f}wd+Zp7%8LrI#arod%y<*1|BhOa6$%Ea; z^78pp*IPpZg0W4V7D<_qNT=9+BTXQ?0~+<5Kq`~Sn7mCg_}+Q zQ?O|oKUnEKq{feHYJ;?eJ5cO70&=`qSV(-qzvYyDbBjIcVvatXZX3$4tb&jea?&TJ z?u)E$6$VV!4P6nxHR1<&8*T~?unjlaNKUwE`~d6tY1>BZgB?iY_hTBb8PoVRo>pg! zP#fwQk7K(sRQBrK+ppifT|RyC_1kx^pOwocX8YxBzFhv~+25gY%A~A|v?3B>wAQ(R z*C%b<3DPeKvG)dpo`Wze^QukSyup41?P>a64U6rFhMP|F6mB~0nQ+s4^i>9b^YM}! z$rtW^YgBsSqWse)ItrH0Tcd}>l^XM~!12-m!s(#V=T}z*vhq4F7;B{9-**zp4NVfTO-IZ(e0rvWLI`8h*Yl!X3 z+xKe-T+6%b%YV2tOE|CU=SMDysk269Cdo`{@}UCYJKYz@D4z(lkAvNTbPxHr^5li3 zQ3(VEm(~!!UOHaYdx9TVMAH^uuGSx#TL-Cs-F&)QHI_^(-c{2MeGhG24-lnWV0ym> zP1o^$_yGyzpE7Mal@wJ1MW^WsVgePB#Q3I`<9+~^)iXT}VrHt#>#`~a1sqs_@mip< zt}T)sH4<-bo7>Bdkr;>J$W5|Cw^)4LTwiu$Be01SuT=1_fnfpJ1-t9=zQ7xe9j~op z9vs>&pc8I79azDpTlg*9^vr>^r8DJqOTaESnS!CHGstBLqmoudEla6Yi%FpcTUrL& zbh1^)yTnfJ1Qsn84s^G<7*G1<=GLqwyfYuDVD@(6I&IG>TXvAn(wzQ+EuGxFppeJl zsd9U(TXCnSDqp;M`s9T}N0(1uy?gogNLc{xR$0>zFiy&b*!#KXO_NCgFBv#hQd60P zNKVQ%p1Dz`tBFPu-dKQY`>y5orL(VIz4{63Q$kjR_c@MCfq^ixGG*_%hB_NTYWumR z#SJWA&8J~rv{|9x0jVTyvMud2*q?OL^5LeF=@@Q0ok-!PlR64Foz`Wz>2%PBo1VeF zh^CJV3H|vkQEBppJ|Dj;&2`gWnZA7X^2z5fo_!%|*_09y7wBr>d+o`!GL0$`TCU__ zt*#4qTGby=`I}qhr9XWRllpy&O;@ml2wD#ql%0J1^eUf*qt8)qWE7#|xP5j2eoahM zlyz5hT}IN?BA*61+!O-HDf>1$s8-2^Q$RyYvQL-hg)$YKf|2)d=9dr#glA1&+{`Co1f2fmGF8f=-L>zd1K8%>}5nE39Z^zP*rSIwu@9l`n+_Nz_$ zu~Bm-wja{0FUYVnAiX=p&t}+biU8#?`63GA?{UOX@*bY)_$x~ZQzEK@Sz&b z)yw1^Re7H@rLKxD(F7tV-!j~C8rE>r$q)`UwJ9nVItw->1Ln*^Dj@Dar0G{>D`NeU37tH}G5 zE;UsT%QZ~~nH@>S8gsFha&D3iw6w8a`9@A7`6_E(zRJ+cR~c9N>P~iNaIhe1XCPxm zD1C$VZ)u9_=1OU2XFyaPF2AEETBk{#5m+xVL+gHfKyul3owC_--N0;Y>1s7VYbPjP z@|iS+MZ}}+JcXN1&_=MSJ~#B~xnE9t1M;vW%BD@D3s^R)#@rC_p&gQxblYSb;0?Ci zI=kVf(+UqZrF{K3a-puK)ArRbTZk(O{cRX z-1Ht3yItp@iOtR~bm1JHR9#coOVcNk14A%yFj>duth!vcSk_5Xkms`4LM7p*)wxHO z=YDzill7TT;&`2Y&0U2CXffkK+0Qzpzyk)Txqm-xZ$gtw$5|p}Cy5XkN-V8R~iARO{x)V7HHk~wS zumd|Wo{-c@j|GKJdNkN_i*ALR#=n$~UxGVPzR>&cMEQbEeizj7O0$lhSYY1RDFFG5ZyG&YDv4g&Dv5tB>+eLV42Aa- zxd@fDTq32$j{x;ThvxG7Vksem_3g#B%E!mmy5HD;6YMnC zzp&q0q~3mKu`v0r14g6-1<~>=bG`oq37$_saUWRUkq+pBy?56ispG_x?awS2IsT(J zd;dg^VBR}O?_v76&E0zAI`g;dONjvPV7(H1ur2JbEVr0zA1EZOQr3U-~h>&7dr=;wqb`fXgq506aSo>K<024TT?$L#Nv~%R$ zv-S4blGZM4BLX5O>9oslo5V;Vv6S4fTOM3gFfvHED%UzzVti*K?nZ_+X|J;g}KciJC^Kqa(yH#Z^iNm)=9 zp-QtvDN+EP_{38U_7>ajpd1tiq-csH#0^SUtsW9ruFZ3)rZu|D-QHcqXXI8)eU}j; zY*MHw62;zK1k>ytIX>AbBPszGSpns?pYSnXx=B#H0zHz{L>7Ooim@cb~s_{&e}XCokSTd$auN$(yg9y+#1sgB})64pk>1#h$Go^B~nb z3i%JL0VSp!J9i`hVDFIrZW>cpEm3_)XZ8cfb=I=?&DE{alYJ)tB6eD-Vdzj~)>vKD%rScPe=0 zvs+#4?Ua`uw~8xnEsTZV`*Q-Oy}uv+PMpnnb-9tnW2nnUG@Hjmxa-jS=E}_wM7j}w5_O!n7Y&3okZoj`M6|06$HSWrn|iTv|Mps4_B*? zJTt2_VQhh&U?o(&YAPODyz!xWsJGxO_xGm;_g zfx5g|+1T8V_sqO4Z6SrVzzcK<6(x!!F)cK)OnZav{<{_wxuYIf1}zwyqV2tE4bA6d zb{>*DBs%L0XV00Pt{|ZI8WgULp7x0 zw+EG~o6QFE)7yEtt=CXm*vEOMsh&>MyQ-R^J}|Sl%gFng?w~7c>IEvPebSdy@7XyS z(?{3~4dpp>(-a-$Pg2718+nW5`s-oIy-mpfy`dz^Xp3iD(8JG5DA1vkOtp%tsZOH?>+k9ObYHDb4ofH=Ey0_! zbK@1+2X9i(NtkxIEUpK01>s=zSyM@tKne4}oL^qP(m!YIv17v~pw7QnSDe>gJq;PP z1F1?t=?>~&)UL43v{bfRNs568gUz8Y>_L2=0zMUWs1#L<%>mXk9feBSv+#{&U*rxj zg4S)|spM^$QYs5x*6v>1JxBLGygd-fDC0T=(v+&9rugUXqv@XVNS8g$MtrLw<%5*@ z28%?&20wVV~qVsv6KEY2sua7`OH7=Ht(dEw(H!hrRbe z2^3`3zW{_@t(P~hZWCp@>$U;j%gF<4G{jo8aD*_@=BzBO`qgrjD>Z4IdCbUDE}CMq z)NU#{Ezw)ka30?6;wINLRGGuIg@;`KKsKsrWE-69blnfn)PbA!2RJ8;PWCgHCIJ99b<2x)bjNzD;S zr%5`Dbblh{s=^Q=AV+NztQ}nuA7=2SvmTqM3BoL=bP*1cPgj!WFjSZjBwSH58*{F4 z4y$}@H!(yhpT{T^Kc(J&_4?V9FP6_=e);MsKPguwtalkS?m1D0R1;ePgq*Gd#0ys_ zSI~iRK;aPh4yIrX1sDYxC`$VW0S-1-)oQb}-zfbP^U1lqa&)@fxv~ID&9nk*Nnr-M zh=cT8)&yTJSE}AG2D5zk#-_v6T&iR8BqisLvU04Z(KV)=xkAx{Zsa(}lstrz;5)e$ zdZNM%V_DQ~SyZ~F6e>AujHP?`6H?vAuz91Zc(UH#U#=jcEF3X@8fKNtieY!7r?5OPZ&gZ0#nmN+ z`y+5H~NSpy(L^ z4Qz?LD+FTD-lUsdFL5Hg8~g|fqjmfk5gu@w6~U4^gv`=CPm7_=`?e@jwlx+LRsy=z zzI`xnOl5w;42fe-zzCRR8fpfal&78;4+bNi8h0evQy*@P5BNSX z%l-(2ww}*%dUY4DBn={>FOZ4{I?o$;ZS~w~F4GhQE+kCRt&KgYYssA?e(X z^{=6*Ckgb@pzfbRJ7%2)z_sM@dve5#n$iE3CGdxiyk{;ETnR z>rWE-DQ`cK;CLy3J)U99dB8qT3CoXDbYCghm@R`OocgXyCAcoT4fN!VF*# zr5LYW$idnTXB{d*PrPuEtdIo)T`K7Y9)KW=~Qe*B?X ze``aR9FlWCre@9*hd)WF!Il7PU! z)S5lL3?p~qx&DqvkzI<_nV6v^e(dg@X@LDIUYnaW^d2I*-^xXzuleWBOG!#UFVvel zZKw=^Wf#|Z?-I?-f86JNxa7f~Kdr^$p0B)SesBjy?$E;pc%Sg$0@9NUC~^$EmG$r* z_^{c-1$dwI;Q}7L4j#LZ)#;VYX>@=WE62lFezUev7=Sj_@Tiu7eM?;g3KH3a4elXU zFAI66 zLve{!k8g##Jw@UmUH5s>L7gO$4dcVwTIWBz4aD`WYH|o?nh=6E3Gs-yRh)W4&CD8N z0)FGApv45aKdFR5Vele4Gr(X{T#w;K?*4LWJauyR310zMQl-So8L6w|5r6jNeQQma zBiGy-YW9Qj`-8}q;Xe7k;)cqMJ1BOq#pYAaJvgXx*%|IVg3kc9&uw~YCz>f|?TkkO zBf_w_D@`PdTdl{19kh1S(`tU#R)lhRSUb?0plm9vIQtyf4QXFd2JocX-4i)aX2EQh z0Tlc2@DiaovBy;oEl0-Y79f?*JAM$%IWGF_MM-)a-aqrS7mk7JmOl&QE#6bV ztqJV1VYpl@2obSB7K>M#H`6+S>O{zxfhz$in`VUgf)C4&jeJ=t_O&K#kBj9;MD@+5 z5AEv8zacvl-h2UPkAhER!vvPm^oCpocDRuyd-SZ@v8`B$^EYF#V|>R*SRiNw0TK=# z1gx;Ra-2AX_aUF#GqgaER~8qVWrd(l#kN z#3*Ijl3TFG6+Jg+qQ@N;+OF6V^M~Ov+SydVsV%|Vw9N6Rwjka-=AID^{x+jXrqrf{ zkyXKYBWyj8U1LUSW65C$`5IDPSrPdJH}dr6aO~0B=Cd(7yEDQfylFctV(0J(gu9Qx zqBl8`0lw%z=NXWpS zTqg#&aJe3K8=R4SLP1(+3JvV>GkB+_#e#-d4*M}3BelWs`*gg{b<%E`u!u39^l%Y= z)6FjLxK4~m{3H4>>hwp57(M-mi_qs@M2=2D%Vo|dQtACNZ7&b9R6Fz}8YbGnxko#uZ9zMZPZ#|_pC3n~g0J7ttjIVL#3G>9#gLi;P#zXLrv8yTd#5>qEQyTI( zT5@stpBaE{8u+awIl;K<6Nso=1`&x%aM2P%AY=;>2c=krSE`;7m%aJw)w>s8j8}!B z*h!!33o<&St}m6bQP88QJ0mQvJL$+{dANkpR(`mIarwJ>vvu_G0xm-zQQ!RT;%1Ya+AT+0lusQnJYceCCwdn9gR z8nE&~R-n_5)t}N&R})`MI&P8ia~tg6WI8^ofAe}{w|`t7Q1^=B${FQ-jigh=jo)M+p6TDb5#e@? z#rnqdL!smJ<23>t=Au{%JSfv}n+tGr4l~*t5jk8WkY}zxMSp=nRpX4qPUR;`((hq$ z3u~dF=z~$*JP6}5liPcoh^*j>WVyWp`ZjtFK9<}T&YB5I7>(jbNbu7-CxK;`@7C0| zBlKkb&D{q;p-r?h!TB}R#cs&^1UB-Vcc%(gH=Am>yY56y6<=Npf3>!yWE`LMJ!nog zw7_=U{i_Kr`!Of`wBr9@#yM%EB}tZkz=GA0$Ftz%qy=j`reo~oR3E|;#@NY&C1hg| z?cox(B*PQ6QjpyW+5r<@D);1*Ls?hwJLO`68paE74aGO*7`T6M zr0Na+R6|*!oK&1K%j_X!Re*+$EGp8O^M(r=+`D;aDWpT^ou&EE3fHh?RX%{5b3i5J zN64H1dY*F-ks{N zEXeI^fM=UJ+{ukchGP2(-_KibzK@bWX%%WMH4E+9#}v z6K!+pmTRFM=cMF-%vBVffKW#+rOZs}H;GN@Mx!qlYi`#dz5BI%kz9o5{dX3VoL>Zo zj1%TVf;MC__5DDB3x_M*m%BEQ-&m3~j^}_;*i61hQZ(cs4*ig4AeK}!$e}`aji#_s z$sHk!(axUPfA&m<4NS2B7;U5zLJ+J#ZaNBMNa|djR&ooL*K3%DWmY9w0`AJYh$Y}= zIxJzb3yvj>voyw#0^ulC;vl_#yL|QKmv5fEUA}(z@(t4nLA3{K8i+3rU?L;zI@jZS zKCg5Sl82xuO70B6hahROn6ilG9uhgQp0sdMLio%&bMlTaDnJu8WDbEQdjvQ`kn1LN z0+E=>rofV<9ywy(se>@sttpoOa0!n-&PN~j;ReB|Tpl68TW1fKkd3T}2ajZSrVrB+ z;q;y;A(d5MZ_Kt%iK)0!fUqT1SSZn>IaKWW4laYtYv+@%AGBshLdz*@Mh@vwacqOn z`Iv1@1%sTM|EToAtwDsQMh}NfLaS{3FGup}D-<9^i|3m&>T>SVyd*Wy`SJt*?H}`1+WnUN><@o*@q_=lxcK++m;7v$_ou$yZ}as(|LR8< z|M`cXUHk>#kAKE?Kja5==|b9FEPixx@kgIsWb(cLBfpbBf6m{rUFF;Tqy3Hh&)DuS z`KR Date: Thu, 30 May 2024 20:01:55 -0700 Subject: [PATCH 15/28] fix: plonk feature off by default (#852) --- .../program/elf/riscv32im-succinct-zkvm-elf | Bin 127496 -> 127568 bytes prover/Cargo.toml | 2 -- recursion/gnark-ffi/Cargo.toml | 2 -- sdk/Cargo.toml | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf b/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf index 6665fa85dcb0c309b5507d1a358273096496dbb5..e67522c9f4a5b50a19553a7f9618fe5e13c0bb07 100755 GIT binary patch delta 18377 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 delta 18232 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 diff --git a/prover/Cargo.toml b/prover/Cargo.toml index fb10228f5d..3bb4890ee5 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -53,7 +53,5 @@ name = "e2e" path = "scripts/e2e.rs" [features] -default = ["plonk"] - neon = ["sp1-core/neon"] plonk = ["sp1-recursion-gnark-ffi/plonk"] diff --git a/recursion/gnark-ffi/Cargo.toml b/recursion/gnark-ffi/Cargo.toml index a5270d58da..d10ed2fd31 100644 --- a/recursion/gnark-ffi/Cargo.toml +++ b/recursion/gnark-ffi/Cargo.toml @@ -21,6 +21,4 @@ cc = "1.0" cfg-if = "1.0" [features] -default = ["plonk"] - plonk = [] diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 24b55d5d1e..95e2d69435 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -16,7 +16,7 @@ reqwest = { version = "0.12.4", features = [ "stream", ] } anyhow = "1.0.83" -sp1-prover = { path = "../prover", default-features = false } +sp1-prover = { path = "../prover" } sp1-core = { path = "../core" } futures = "0.3.30" bincode = "1.3.3" From 27c1741047163f5c97984e9abf1adf3155a93650 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 21:40:18 -0700 Subject: [PATCH 16/28] feat: generic const expr (#854) Co-authored-by: Chris Tian --- core/benches/main.rs | 3 --- core/src/lib.rs | 1 - .../syscall/precompiles/weierstrass/weierstrass_add.rs | 9 +++------ .../precompiles/weierstrass/weierstrass_decompress.rs | 9 +++------ .../precompiles/weierstrass/weierstrass_double.rs | 10 ++++------ core/src/utils/mod.rs | 2 +- eval/src/main.rs | 3 --- prover/scripts/build_plonk_bn254.rs | 3 --- prover/scripts/e2e.rs | 3 --- prover/scripts/fibonacci_groth16.rs | 3 --- prover/scripts/fibonacci_sweep.rs | 3 --- prover/scripts/tendermint_sweep.rs | 3 --- prover/src/lib.rs | 2 -- recursion/core/src/poseidon2_wide/external.rs | 3 +-- recursion/program/src/lib.rs | 2 -- sdk/src/lib.rs | 3 --- 16 files changed, 12 insertions(+), 50 deletions(-) diff --git a/core/benches/main.rs b/core/benches/main.rs index f40f3db01a..88c2db0874 100644 --- a/core/benches/main.rs +++ b/core/benches/main.rs @@ -1,6 +1,3 @@ -#![allow(incomplete_features)] -#![feature(generic_const_exprs)] - use criterion::{black_box, criterion_group, criterion_main, Criterion}; use sp1_core::io::SP1Stdin; use sp1_core::runtime::{Program, Runtime}; diff --git a/core/src/lib.rs b/core/src/lib.rs index 3fb0786a03..da90db9cf4 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -11,7 +11,6 @@ deprecated, incomplete_features )] -#![feature(generic_const_exprs)] #![warn(unused_extern_crates)] extern crate alloc; diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index ac049a5be4..adbab629f0 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -36,8 +36,7 @@ use crate::utils::ec::weierstrass::WeierstrassParameters; use crate::utils::ec::AffinePoint; use crate::utils::ec::CurveType; use crate::utils::ec::EllipticCurve; -use crate::utils::limbs_from_prev_access; -use crate::utils::pad_rows; +use crate::utils::{limbs_from_prev_access, pad_rows}; pub const fn num_weierstrass_add_cols() -> usize { size_of::>() @@ -202,8 +201,6 @@ impl WeierstrassAddAssignChip { impl MachineAir for WeierstrassAddAssignChip -where - [(); num_weierstrass_add_cols::()]:, { type Record = ExecutionRecord; type Program = Program; @@ -235,7 +232,7 @@ where for i in 0..events.len() { let event = &events[i]; - let mut row = [F::zero(); num_weierstrass_add_cols::()]; + let mut row = vec![F::zero(); num_weierstrass_add_cols::()]; let cols: &mut WeierstrassAddAssignCols = row.as_mut_slice().borrow_mut(); @@ -287,7 +284,7 @@ where output.add_byte_lookup_events(new_byte_lookup_events); pad_rows(&mut rows, || { - let mut row = [F::zero(); num_weierstrass_add_cols::()]; + let mut row = vec![F::zero(); num_weierstrass_add_cols::()]; let cols: &mut WeierstrassAddAssignCols = row.as_mut_slice().borrow_mut(); let zero = BigUint::zero(); diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs index ef610267f6..bd38edea8e 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs @@ -32,7 +32,6 @@ use crate::runtime::Syscall; use crate::runtime::SyscallCode; use crate::syscall::precompiles::create_ec_decompress_event; use crate::syscall::precompiles::SyscallContext; -use crate::utils::bytes_to_words_le_vec; use crate::utils::ec::weierstrass::bls12_381::bls12381_sqrt; use crate::utils::ec::weierstrass::secp256k1::secp256k1_sqrt; use crate::utils::ec::weierstrass::WeierstrassParameters; @@ -40,7 +39,7 @@ use crate::utils::ec::CurveType; use crate::utils::ec::EllipticCurve; use crate::utils::limbs_from_access; use crate::utils::limbs_from_prev_access; -use crate::utils::pad_rows; +use crate::utils::{bytes_to_words_le_vec, pad_rows}; pub const fn num_weierstrass_decompress_cols() -> usize { size_of::>() @@ -137,8 +136,6 @@ impl WeierstrassDecompressChip { impl MachineAir for WeierstrassDecompressChip -where - [(); num_weierstrass_decompress_cols::()]:, { type Record = ExecutionRecord; type Program = Program; @@ -168,7 +165,7 @@ where for i in 0..events.len() { let event = events[i].clone(); - let mut row = [F::zero(); num_weierstrass_decompress_cols::()]; + let mut row = vec![F::zero(); num_weierstrass_decompress_cols::()]; let cols: &mut WeierstrassDecompressCols = row.as_mut_slice().borrow_mut(); @@ -209,7 +206,7 @@ where output.add_byte_lookup_events(new_byte_lookup_events); pad_rows(&mut rows, || { - let mut row = [F::zero(); num_weierstrass_decompress_cols::()]; + let mut row = vec![F::zero(); num_weierstrass_decompress_cols::()]; let cols: &mut WeierstrassDecompressCols = row.as_mut_slice().borrow_mut(); diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index 241a9b6143..50bb0a4332 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -37,8 +37,7 @@ use crate::utils::ec::weierstrass::WeierstrassParameters; use crate::utils::ec::AffinePoint; use crate::utils::ec::CurveType; use crate::utils::ec::EllipticCurve; -use crate::utils::limbs_from_prev_access; -use crate::utils::pad_rows; +use crate::utils::{limbs_from_prev_access, pad_rows}; pub const fn num_weierstrass_double_cols() -> usize { size_of::>() @@ -221,8 +220,6 @@ impl WeierstrassDoubleAssignChip { impl MachineAir for WeierstrassDoubleAssignChip -where - [(); num_weierstrass_double_cols::()]:, { type Record = ExecutionRecord; type Program = Program; @@ -261,7 +258,8 @@ where let rows = events .iter() .map(|event| { - let mut row = [F::zero(); num_weierstrass_double_cols::()]; + let mut row = + vec![F::zero(); num_weierstrass_double_cols::()]; let cols: &mut WeierstrassDoubleAssignCols = row.as_mut_slice().borrow_mut(); @@ -310,7 +308,7 @@ where } pad_rows(&mut rows, || { - let mut row = [F::zero(); num_weierstrass_double_cols::()]; + let mut row = vec![F::zero(); num_weierstrass_double_cols::()]; let cols: &mut WeierstrassDoubleAssignCols = row.as_mut_slice().borrow_mut(); let zero = BigUint::zero(); diff --git a/core/src/utils/mod.rs b/core/src/utils/mod.rs index 3632cde1b8..664674bee8 100644 --- a/core/src/utils/mod.rs +++ b/core/src/utils/mod.rs @@ -65,7 +65,7 @@ pub fn limbs_from_access>(cols: &[M]) Limbs(sized) } -pub fn pad_rows(rows: &mut Vec<[T; N]>, row_fn: impl Fn() -> [T; N]) { +pub fn pad_rows(rows: &mut Vec, row_fn: impl Fn() -> T) { let nb_rows = rows.len(); let mut padded_nb_rows = nb_rows.next_power_of_two(); if padded_nb_rows < 16 { diff --git a/eval/src/main.rs b/eval/src/main.rs index dbf67c51b5..3ed7a9d3af 100644 --- a/eval/src/main.rs +++ b/eval/src/main.rs @@ -1,6 +1,3 @@ -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - use clap::{command, Parser}; use csv::WriterBuilder; use serde::Serialize; diff --git a/prover/scripts/build_plonk_bn254.rs b/prover/scripts/build_plonk_bn254.rs index 66ccb229d3..e81d621479 100644 --- a/prover/scripts/build_plonk_bn254.rs +++ b/prover/scripts/build_plonk_bn254.rs @@ -1,6 +1,3 @@ -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - use std::path::PathBuf; use clap::Parser; diff --git a/prover/scripts/e2e.rs b/prover/scripts/e2e.rs index c4833f2202..ac2f08170c 100644 --- a/prover/scripts/e2e.rs +++ b/prover/scripts/e2e.rs @@ -1,6 +1,3 @@ -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - use std::borrow::Borrow; use std::path::PathBuf; diff --git a/prover/scripts/fibonacci_groth16.rs b/prover/scripts/fibonacci_groth16.rs index a17b37bb8f..a1fcf2d640 100644 --- a/prover/scripts/fibonacci_groth16.rs +++ b/prover/scripts/fibonacci_groth16.rs @@ -1,8 +1,5 @@ //! Tests end-to-end performance of wrapping a recursion proof to PLONK. -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - use std::time::Instant; use itertools::iproduct; diff --git a/prover/scripts/fibonacci_sweep.rs b/prover/scripts/fibonacci_sweep.rs index 14f3536628..d509ffb59e 100644 --- a/prover/scripts/fibonacci_sweep.rs +++ b/prover/scripts/fibonacci_sweep.rs @@ -1,8 +1,5 @@ //! Sweeps end-to-end prover performance across a wide range of parameters for Fibonacci. -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - use std::{fs::File, io::BufWriter, io::Write, time::Instant}; use itertools::iproduct; diff --git a/prover/scripts/tendermint_sweep.rs b/prover/scripts/tendermint_sweep.rs index 37209895f4..595970e6ad 100644 --- a/prover/scripts/tendermint_sweep.rs +++ b/prover/scripts/tendermint_sweep.rs @@ -1,8 +1,5 @@ //! Sweeps end-to-end prover performance across a wide range of parameters for Tendermint. -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - use std::{fs::File, io::BufWriter, io::Write, time::Instant}; use itertools::iproduct; diff --git a/prover/src/lib.rs b/prover/src/lib.rs index cd88882a2a..73e3f27c0b 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -7,8 +7,6 @@ //! 3. Wrap the shard proof into a SNARK-friendly field. //! 4. Wrap the last shard proof, proven over the SNARK-friendly field, into a PLONK proof. -#![allow(incomplete_features)] -#![feature(generic_const_exprs)] #![allow(clippy::too_many_arguments)] #![allow(clippy::new_without_default)] diff --git a/recursion/core/src/poseidon2_wide/external.rs b/recursion/core/src/poseidon2_wide/external.rs index 6fb3bc870e..9181d3a1fa 100644 --- a/recursion/core/src/poseidon2_wide/external.rs +++ b/recursion/core/src/poseidon2_wide/external.rs @@ -61,8 +61,7 @@ impl MachineAir for Poseidon2WideChip>::width(self); for event in &input.poseidon2_events { - let mut row = Vec::new(); - row.resize(num_columns, F::zero()); + let mut row = vec![F::zero(); num_columns]; let mut cols = if use_sbox_3 { let cols: &mut Poseidon2SBoxCols = row.as_mut_slice().borrow_mut(); diff --git a/recursion/program/src/lib.rs b/recursion/program/src/lib.rs index aa71142ee9..dacc8c88c3 100644 --- a/recursion/program/src/lib.rs +++ b/recursion/program/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] #![allow(type_alias_bounds)] #![allow(clippy::type_complexity)] #![allow(clippy::too_many_arguments)] diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 70114f21c2..7e4f2cb9f3 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -5,9 +5,6 @@ //! Visit the [Getting Started](https://succinctlabs.github.io/sp1/getting-started.html) section //! in the official SP1 documentation for a quick start guide. -#![allow(incomplete_features)] -#![feature(generic_const_exprs)] - #[rustfmt::skip] pub mod proto { pub mod network; From 8ef12a5b33bc59df4bc90ec3c7e3cf11123ccd66 Mon Sep 17 00:00:00 2001 From: Tamir Hemo Date: Thu, 30 May 2024 23:02:14 -0700 Subject: [PATCH 17/28] doc: recursive program docs (#855) --- recursion/program/Makefile | 8 ---- recursion/program/src/commit.rs | 2 + recursion/program/src/machine/compress.rs | 4 +- recursion/program/src/machine/core.rs | 48 +++++++++++++++++++---- recursion/program/src/machine/deferred.rs | 6 +-- recursion/program/src/machine/utils.rs | 2 + 6 files changed, 50 insertions(+), 20 deletions(-) delete mode 100644 recursion/program/Makefile diff --git a/recursion/program/Makefile b/recursion/program/Makefile deleted file mode 100644 index a1430680b5..0000000000 --- a/recursion/program/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -all: - make fri-sweep - -fri-sweep: - mkdir -p experiments/results && \ - RUSTFLAGS='-C target-cpu=native -C target_feature=+avx512ifma,+avx512vl' \ - RUST_LOG=info \ - cargo run --package sp1-recursion-program --release --bin fri_sweep \ No newline at end of file diff --git a/recursion/program/src/commit.rs b/recursion/program/src/commit.rs index 0edff4bfeb..100d74c405 100644 --- a/recursion/program/src/commit.rs +++ b/recursion/program/src/commit.rs @@ -3,6 +3,7 @@ use sp1_recursion_compiler::ir::{Array, Builder, Config, Ext, FromConstant, Usiz use crate::fri::types::{FriConfigVariable, TwoAdicPcsRoundVariable}; +/// Reference: [p3_commit::PolynomialSpace] pub trait PolynomialSpaceVariable: Sized + FromConstant { type Constant: PolynomialSpace; @@ -33,6 +34,7 @@ pub trait PolynomialSpaceVariable: Sized + FromConstant { ) -> Self; } +/// Reference: [p3_commit::Pcs] pub trait PcsVariable { type Domain: PolynomialSpaceVariable; diff --git a/recursion/program/src/machine/compress.rs b/recursion/program/src/machine/compress.rs index dcc85fed1a..f8fbc857bc 100644 --- a/recursion/program/src/machine/compress.rs +++ b/recursion/program/src/machine/compress.rs @@ -96,6 +96,8 @@ where deferred_vk, ); + builder.halt(); + builder.compile_program() } } @@ -472,7 +474,5 @@ where ); commit_public_values(builder, reduce_public_values); - - builder.halt(); } } diff --git a/recursion/program/src/machine/core.rs b/recursion/program/src/machine/core.rs index 916a25a2ac..2c1c74fc5e 100644 --- a/recursion/program/src/machine/core.rs +++ b/recursion/program/src/machine/core.rs @@ -71,6 +71,8 @@ impl SP1RecursiveVerifier { }; SP1RecursiveVerifier::verify(&mut builder, &pcs, machine, input); + builder.halt(); + builder.compile_program() } } @@ -90,13 +92,39 @@ where /// This program represents a first recursive step in the verification of an SP1 proof /// consisting of one or more shards. Each shard proof is verified and its public values are /// aggregated into a single set representing the start and end state of the program execution - /// across all shards. + /// across all shards. + /// + /// # Constraints + /// + /// ## Verifying the STARK proofs. + /// For each shard, the verifier asserts the correctness of the STARK proof which is composed + /// of verifying the FRI proof for openings and verifying the constraints. + /// + /// ## Aggregating the shard public values. + /// + /// See [SP1Prover::verify] for the verification algorithm of a complete SP1 proof. In this + /// function, we are aggregating several shard proofs and attesting to an aggregated state which + /// reprersents all the shards. The consistency conditions of the aggregated state are + /// asserted in the following way: + /// + /// - Start pc for every shardf should be what the next pc declared in the previous shard was. + /// - Public input, deferred proof digests, and exit code should be the same in all shards. + /// + /// ## The leaf challenger. + /// A key difference between the recursive tree verification and the complete one in + /// [SP1Prover::verify] is that the recursive verifier has no way of reconstructiing the + /// chanllenger only from a part of the shard proof. Therefoee, the value of the leaf challenger + /// is witnessed in the program and the verifier assertds correctness given this challenger. + /// In the course of the recursive verification, the challenger is reconstructed by observing + /// the commitments one by one, and in the final step, the challenger is asserted to be the same + /// as the one witnessed here. pub fn verify( builder: &mut Builder, pcs: &TwoAdicFriPcsVariable, machine: &StarkMachine>, input: SP1RecursionMemoryLayoutVariable, ) { + // Read input. let SP1RecursionMemoryLayoutVariable { vk, shard_proofs, @@ -212,6 +240,8 @@ where }); // Assert compatibility of the shard values. + + // Assert that the committed value digests are all the same. for (word, current_word) in committed_value_digest .iter() .zip_eq(public_values.committed_value_digest.iter()) @@ -243,16 +273,19 @@ where builder.assert_felt_eq(*digest, *current_digest); } - // Update the reconstruct challenger, cumulative sum, shard number, and program counter. + // Update the loop variables: the reconstruct challenger, cumulative sum, shard number, + // and program counter. + + // Increment the shard index by one. + builder.assign(current_shard, current_shard + C::F::one()); + + // Update the reconstruct challenger. reconstruct_challenger.observe(builder, proof.commitment.main_commit); for j in 0..machine.num_pv_elts() { let element = builder.get(&proof.public_values, j); reconstruct_challenger.observe(builder, element); } - // Increment the shard count by one. - builder.assign(current_shard, current_shard + C::F::one()); - // Update current_pc to be the end_pc of the current proof. builder.assign(current_pc, public_values.next_pc); @@ -267,6 +300,8 @@ where }); }); + // Write all values to the public values struct and commit to them. + // Compute vk digest. let vk_digest = hash_vkey(builder, &vk); let vk_digest: [Felt<_>; DIGEST_SIZE] = array::from_fn(|i| builder.get(&vk_digest, i)); @@ -281,6 +316,7 @@ where let cumulative_sum_arrray = array::from_fn(|i| builder.get(&cumulative_sum_arrray, i)); let zero: Felt<_> = builder.eval(C::F::zero()); + // Initialize the public values we will commit to. let mut recursion_public_values_stream = [zero; RECURSIVE_PROOF_NUM_PV_ELTS]; @@ -317,7 +353,5 @@ where }); commit_public_values(builder, recursion_public_values); - - builder.halt(); } } diff --git a/recursion/program/src/machine/deferred.rs b/recursion/program/src/machine/deferred.rs index 3df497d445..2ae232ab73 100644 --- a/recursion/program/src/machine/deferred.rs +++ b/recursion/program/src/machine/deferred.rs @@ -91,6 +91,8 @@ where SP1DeferredVerifier::verify(&mut builder, &pcs, machine, input); + builder.halt(); + builder.compile_program() } } @@ -114,7 +116,7 @@ where /// - Asserts that each of these proofs is valid as a `compress` proof. /// - Asserts that each of these proofs is complete by checking the `is_complete` flag in the /// proof's public values. - /// - Aggregates the proof information into an accumulated deferred digest. + /// - Aggregates the proof information into the accumulated deferred digest. pub fn verify( builder: &mut Builder, pcs: &TwoAdicFriPcsVariable, @@ -289,7 +291,5 @@ where deferred_public_values.is_complete = var2felt(builder, is_complete); commit_public_values(builder, deferred_public_values); - - builder.halt(); } } diff --git a/recursion/program/src/machine/utils.rs b/recursion/program/src/machine/utils.rs index 59540136b3..c721dae725 100644 --- a/recursion/program/src/machine/utils.rs +++ b/recursion/program/src/machine/utils.rs @@ -22,6 +22,8 @@ use crate::{ }; /// Assertions on the public values describing a complete recursive proof state. +/// +/// See [SP1Prover::verify] for the verification algorithm of a complete SP1 proof. pub(crate) fn assert_complete( builder: &mut Builder, public_values: &RecursionPublicValues>, From e48c01ecc5c4bbea491289d19637c8ca57656532 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Thu, 30 May 2024 23:53:49 -0700 Subject: [PATCH 18/28] feat: feature flag `alloy_sol_types` (#850) --- Cargo.lock | 1 - book/SUMMARY.md | 4 ++- book/developers/common-issues.md | 18 ++++++++++ sdk/Cargo.toml | 8 +++-- sdk/src/lib.rs | 34 +++++++++++++++---- sdk/src/{ => network}/auth.rs | 0 sdk/src/{ => network}/client.rs | 2 +- sdk/src/network/mod.rs | 3 ++ .../{provers/network.rs => network/prover.rs} | 4 +-- sdk/src/provers/mod.rs | 2 -- 10 files changed, 60 insertions(+), 16 deletions(-) create mode 100644 book/developers/common-issues.md rename sdk/src/{ => network}/auth.rs (100%) rename sdk/src/{ => network}/client.rs (99%) create mode 100644 sdk/src/network/mod.rs rename sdk/src/{provers/network.rs => network/prover.rs} (98%) diff --git a/Cargo.lock b/Cargo.lock index b0a73531af..b75a8e5669 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4896,7 +4896,6 @@ dependencies = [ name = "sp1-sdk" version = "0.1.0" dependencies = [ - "alloy-primitives", "alloy-sol-types", "anyhow", "async-trait", diff --git a/book/SUMMARY.md b/book/SUMMARY.md index 91624caa07..3728ed9b0e 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -40,4 +40,6 @@ - [Recommended Settings](./developers/recommended-settings.md) -- [Building Plonk Bn254 Artifacts](./developers/building-plonk-artifacts.md) \ No newline at end of file +- [Building Plonk Bn254 Artifacts](./developers/building-plonk-artifacts.md) + +- [Common Issues](./developers/common-issues.md) \ No newline at end of file diff --git a/book/developers/common-issues.md b/book/developers/common-issues.md new file mode 100644 index 0000000000..285f461a36 --- /dev/null +++ b/book/developers/common-issues.md @@ -0,0 +1,18 @@ +# Alloy Errors + +If you are using a library that depends on `alloy_sol_types`, and encounter an error like this: + +``` +perhaps two different versions of crate `alloy_sol_types` are being used? +``` + +This is likely due to two different versions of `alloy_sol_types` being used. To fix this, you can set `default-features` to `false` for the `sp1-sdk` dependency in your `Cargo.toml`. + +```toml +[dependencies] +sp1-sdk = { version = "0.1.0", default-features = false } +``` + +This will configure out the `network` feature which will remove the dependency on `alloy_sol_types` +and configure out the `NetworkProver`. + diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 95e2d69435..6f0e06ff40 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -29,8 +29,7 @@ tracing = "0.1.40" hex = "0.4.3" log = "0.4.21" axum = "=0.7.5" -alloy-primitives = "0.7.0" -alloy-sol-types = "0.7.0" +alloy-sol-types = { version = "0.7.0", optional = true } sha2 = "0.10.8" dirs = "5.0.1" tempfile = "3.10.1" @@ -41,8 +40,13 @@ strum_macros = "0.26.2" strum = "0.26.2" [features] +default = ["network"] + neon = ["sp1-core/neon"] plonk = ["sp1-prover/plonk"] +# TODO: Once alloy has a 1.* release, we can likely remove this feature flag, as there will be less +# dependency resolution issues. +network = ["dep:alloy-sol-types"] [build-dependencies] vergen = { version = "8", default-features = false, features = [ diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 7e4f2cb9f3..a48ef5e248 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -10,17 +10,23 @@ pub mod proto { pub mod network; } pub mod artifacts; -pub mod auth; -pub mod client; +#[cfg(feature = "network")] +pub mod network; +#[cfg(feature = "network")] +pub use crate::network::prover::NetworkProver; + pub mod provers; pub mod utils { pub use sp1_core::utils::setup_logger; } +use cfg_if::cfg_if; use std::{env, fmt::Debug, fs::File, path::Path}; use anyhow::{Ok, Result}; -pub use provers::{LocalProver, MockProver, NetworkProver, Prover}; + +pub use provers::{LocalProver, MockProver, Prover}; + use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp1_core::{ runtime::ExecutionReport, @@ -86,8 +92,16 @@ impl ProverClient { "local" => Self { prover: Box::new(LocalProver::new()), }, - "network" => Self { - prover: Box::new(NetworkProver::new()), + "network" => { + cfg_if! { + if #[cfg(feature = "network")] { + Self { + prover: Box::new(NetworkProver::new()), + } + } else { + panic!("network feature is not enabled") + } + } }, _ => panic!( "invalid value for SP1_PROVER enviroment variable: expected 'local', 'mock', or 'network'" @@ -144,8 +158,14 @@ impl ProverClient { /// let client = ProverClient::network(); /// ``` pub fn network() -> Self { - Self { - prover: Box::new(NetworkProver::new()), + cfg_if! { + if #[cfg(feature = "network")] { + Self { + prover: Box::new(NetworkProver::new()), + } + } else { + panic!("network feature is not enabled") + } } } diff --git a/sdk/src/auth.rs b/sdk/src/network/auth.rs similarity index 100% rename from sdk/src/auth.rs rename to sdk/src/network/auth.rs diff --git a/sdk/src/client.rs b/sdk/src/network/client.rs similarity index 99% rename from sdk/src/client.rs rename to sdk/src/network/client.rs index 87403dbde7..3a5e13ce62 100644 --- a/sdk/src/client.rs +++ b/sdk/src/network/client.rs @@ -1,7 +1,7 @@ use std::{env, time::Duration}; use crate::{ - auth::NetworkAuth, + network::auth::NetworkAuth, proto::network::{UnclaimProofRequest, UnclaimReason}, }; use anyhow::{Context, Ok, Result}; diff --git a/sdk/src/network/mod.rs b/sdk/src/network/mod.rs new file mode 100644 index 0000000000..950aa10953 --- /dev/null +++ b/sdk/src/network/mod.rs @@ -0,0 +1,3 @@ +pub mod auth; +pub mod client; +pub mod prover; diff --git a/sdk/src/provers/network.rs b/sdk/src/network/prover.rs similarity index 98% rename from sdk/src/provers/network.rs rename to sdk/src/network/prover.rs index 34e5e6008e..675c10696d 100644 --- a/sdk/src/provers/network.rs +++ b/sdk/src/network/prover.rs @@ -2,7 +2,7 @@ use std::{env, time::Duration}; use crate::proto::network::ProofMode; use crate::{ - client::NetworkClient, + network::client::NetworkClient, proto::network::{ProofStatus, TransactionStatus}, Prover, }; @@ -13,7 +13,7 @@ use sp1_prover::utils::block_on; use sp1_prover::{SP1Prover, SP1Stdin}; use tokio::{runtime, time::sleep}; -use super::{LocalProver, ProverType}; +use crate::provers::{LocalProver, ProverType}; /// An implementation of [crate::ProverClient] that can generate proofs on a remote RPC server. pub struct NetworkProver { diff --git a/sdk/src/provers/mod.rs b/sdk/src/provers/mod.rs index 53c9e32fa9..4c731c43d4 100644 --- a/sdk/src/provers/mod.rs +++ b/sdk/src/provers/mod.rs @@ -1,12 +1,10 @@ mod local; mod mock; -mod network; use crate::{SP1CompressedProof, SP1PlonkBn254Proof, SP1Proof}; use anyhow::Result; pub use local::LocalProver; pub use mock::MockProver; -pub use network::NetworkProver; use sp1_core::stark::MachineVerificationError; use sp1_prover::CoreSC; use sp1_prover::SP1CoreProofData; From 896ee505e067af91d3a6d9d075b95c9c80cfcd96 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Fri, 31 May 2024 11:26:13 -0700 Subject: [PATCH 19/28] contracts --- book/verifying-proofs/solidity-and-evm.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/book/verifying-proofs/solidity-and-evm.md b/book/verifying-proofs/solidity-and-evm.md index 294023c5b8..425e9f8862 100644 --- a/book/verifying-proofs/solidity-and-evm.md +++ b/book/verifying-proofs/solidity-and-evm.md @@ -44,4 +44,8 @@ fn main() { sp1_sdk::artifacts::export_solidity_plonk_bn254_verifier(contracts_src_dir) .expect("failed to export verifier"); } -``` \ No newline at end of file +``` + +## Installing SP1 Contracts + +To install the SP1 contracts with [Foundry](https://github.com/foundry-rs/foundry), follow the instructions in the [SP1 Contracts README](https://github.com/succinctlabs/sp1-contracts). \ No newline at end of file From 90d97e20c86b8a4f362684dcd367a55e5c4f63f6 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Fri, 31 May 2024 12:50:06 -0700 Subject: [PATCH 20/28] clean --- book/verifying-proofs/solidity-and-evm.md | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/book/verifying-proofs/solidity-and-evm.md b/book/verifying-proofs/solidity-and-evm.md index 425e9f8862..98cd3768a0 100644 --- a/book/verifying-proofs/solidity-and-evm.md +++ b/book/verifying-proofs/solidity-and-evm.md @@ -23,29 +23,6 @@ sp1-sdk = { features = ["plonk"] } You can run the above script with `RUST_LOG=info cargo run --bin plonk_bn254 --release` in `examples/fibonacci/script`. -## Exporting the Verifier Contract - -To export the verifier contract, you can use the export function in the `sp1_sdk` crate. - -### Example - -```rust,noplayground -//! Builds the proving artifacts and exports the solidity verifier. -//! -//! You can run this script using the following command: -//! ```shell -//! RUST_LOG=info cargo run --package fibonacci-script --bin artifacts --release -//! ``` - -use std::path::PathBuf; - -fn main() { - let contracts_src_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../contracts/src"); - sp1_sdk::artifacts::export_solidity_plonk_bn254_verifier(contracts_src_dir) - .expect("failed to export verifier"); -} -``` - ## Installing SP1 Contracts To install the SP1 contracts with [Foundry](https://github.com/foundry-rs/foundry), follow the instructions in the [SP1 Contracts README](https://github.com/succinctlabs/sp1-contracts). \ No newline at end of file From 8a9f0c2015d9eb611eb652d19ee44a50bf0e5c95 Mon Sep 17 00:00:00 2001 From: Chris T Date: Fri, 31 May 2024 13:54:52 -0700 Subject: [PATCH 21/28] chore: bump plonk artifacts (#864) --- prover/src/install.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prover/src/install.rs b/prover/src/install.rs index cb4d08f168..873c50f685 100644 --- a/prover/src/install.rs +++ b/prover/src/install.rs @@ -10,7 +10,7 @@ use crate::utils::block_on; pub const PLONK_BN254_ARTIFACTS_URL_BASE: &str = "https://sp1-circuits.s3-us-east-2.amazonaws.com"; /// The current version of the plonk bn254 artifacts. -pub const PLONK_BN254_ARTIFACTS_COMMIT: &str = "57ad9e7d"; +pub const PLONK_BN254_ARTIFACTS_COMMIT: &str = "e48c01ec"; /// Install the latest plonk bn254 artifacts. /// From 166e243e342d5c32db3c6d875afd2db75636b789 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Fri, 31 May 2024 14:40:09 -0700 Subject: [PATCH 22/28] fix --- book/verifying-proofs/solidity-and-evm.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/book/verifying-proofs/solidity-and-evm.md b/book/verifying-proofs/solidity-and-evm.md index 98cd3768a0..1efb9b7a89 100644 --- a/book/verifying-proofs/solidity-and-evm.md +++ b/book/verifying-proofs/solidity-and-evm.md @@ -14,7 +14,6 @@ To use PLONK proving & verification locally, enable the `plonk` feature flag in sp1-sdk = { features = ["plonk"] } ``` - ### Example ```rust,noplayground @@ -23,6 +22,6 @@ sp1-sdk = { features = ["plonk"] } You can run the above script with `RUST_LOG=info cargo run --bin plonk_bn254 --release` in `examples/fibonacci/script`. -## Installing SP1 Contracts +## Install SP1 Contracts To install the SP1 contracts with [Foundry](https://github.com/foundry-rs/foundry), follow the instructions in the [SP1 Contracts README](https://github.com/succinctlabs/sp1-contracts). \ No newline at end of file From 5e15886a20306a7f285992762b95513af806eda4 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Fri, 31 May 2024 14:50:50 -0700 Subject: [PATCH 23/28] clean --- book/verifying-proofs/solidity-and-evm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/verifying-proofs/solidity-and-evm.md b/book/verifying-proofs/solidity-and-evm.md index 1efb9b7a89..99ba2cbeb1 100644 --- a/book/verifying-proofs/solidity-and-evm.md +++ b/book/verifying-proofs/solidity-and-evm.md @@ -24,4 +24,4 @@ You can run the above script with `RUST_LOG=info cargo run --bin plonk_bn254 --r ## Install SP1 Contracts -To install the SP1 contracts with [Foundry](https://github.com/foundry-rs/foundry), follow the instructions in the [SP1 Contracts README](https://github.com/succinctlabs/sp1-contracts). \ No newline at end of file +To install the SP1 contracts with [Foundry](https://github.com/foundry-rs/foundry), follow the instructions in the [sp1-contracts repo](https://github.com/succinctlabs/sp1-contracts). \ No newline at end of file From 47b8901b32088e0e26525d7b81098433d18a0749 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Fri, 31 May 2024 15:05:00 -0700 Subject: [PATCH 24/28] try permalink --- book/verifying-proofs/solidity-and-evm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/verifying-proofs/solidity-and-evm.md b/book/verifying-proofs/solidity-and-evm.md index 99ba2cbeb1..599955e71e 100644 --- a/book/verifying-proofs/solidity-and-evm.md +++ b/book/verifying-proofs/solidity-and-evm.md @@ -24,4 +24,4 @@ You can run the above script with `RUST_LOG=info cargo run --bin plonk_bn254 --r ## Install SP1 Contracts -To install the SP1 contracts with [Foundry](https://github.com/foundry-rs/foundry), follow the instructions in the [sp1-contracts repo](https://github.com/succinctlabs/sp1-contracts). \ No newline at end of file +https://github.com/succinctlabs/sp1-contracts/blob/f74ad2963bbb09ac283af8d10152765ab8e07111/README.md?plain=1#L1-L34 \ No newline at end of file From 362e3972a2ee6b1e215f2c30fb93d3729d352bb2 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Fri, 31 May 2024 15:05:59 -0700 Subject: [PATCH 25/28] fix --- book/verifying-proofs/solidity-and-evm.md | 37 ++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/book/verifying-proofs/solidity-and-evm.md b/book/verifying-proofs/solidity-and-evm.md index 599955e71e..e75c988f14 100644 --- a/book/verifying-proofs/solidity-and-evm.md +++ b/book/verifying-proofs/solidity-and-evm.md @@ -24,4 +24,39 @@ You can run the above script with `RUST_LOG=info cargo run --bin plonk_bn254 --r ## Install SP1 Contracts -https://github.com/succinctlabs/sp1-contracts/blob/f74ad2963bbb09ac283af8d10152765ab8e07111/README.md?plain=1#L1-L34 \ No newline at end of file +# SP1 Contracts + +This repository contains the smart contracts for verifying [SP1](https://github.com/succinctlabs/sp1) EVM proofs. + +## Installation + +> [!WARNING] +> [Foundry](https://github.com/foundry-rs/foundry) installs the latest release version initially, but subsequent `forge update` commands will use the `main` branch. This branch is the development branch and should be avoided in favor of tagged releases. The release process matches a specific SP1 version. + +To install the latest release version: + +```bash +forge install succinctlabs/sp1-contracts +``` + +To install a specific version: +```bash +forge install succinctlabs/sp1-contracts@ +``` + +Add `@sp1-contracts/=lib/sp1-contracts/contracts/src/` in `remappings.txt.` + +### Usage + +Once installed, you can use the contracts in the library by importing them: + +```solidity +pragma solidity ^0.8.25; + +import {SP1Verifier} from "@sp1-contracts/SP1Verifier.sol"; + +contract MyContract is SP1Verifier { +} +``` + +For more details on the contracts, refer to the [sp1-contracts](https://github.com/succinctlabs/sp1-contracts) repo. \ No newline at end of file From 66ffc3fb1c60baae8869909d4639d3b84a725961 Mon Sep 17 00:00:00 2001 From: Tamir Hemo Date: Fri, 31 May 2024 15:07:52 -0700 Subject: [PATCH 26/28] chore: program doc and remove unnecessary clones (#857) --- core/src/stark/permutation.rs | 12 ++++++------ recursion/program/src/machine/core.rs | 2 -- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/core/src/stark/permutation.rs b/core/src/stark/permutation.rs index a76b4c8995..865397d5d4 100644 --- a/core/src/stark/permutation.rs +++ b/core/src/stark/permutation.rs @@ -65,7 +65,7 @@ pub(crate) fn generate_permutation_trace>( sends: &[Interaction], receives: &[Interaction], preprocessed: Option<&RowMajorMatrix>, - main: &mut RowMajorMatrix, + main: &RowMajorMatrix, random_elements: &[EF], batch_size: usize, ) -> RowMajorMatrix { @@ -96,13 +96,13 @@ pub(crate) fn generate_permutation_trace>( Some(prep) => { permutation_trace .par_rows_mut() - .zip_eq(prep.par_rows()) - .zip_eq(main.par_rows()) + .zip_eq(prep.par_row_slices()) + .zip_eq(main.par_row_slices()) .for_each(|((row, prep_row), main_row)| { populate_permutation_row( row, - prep_row.collect::>().as_slice(), - main_row.collect::>().as_slice(), + prep_row, + main_row, sends, receives, alpha, @@ -114,7 +114,7 @@ pub(crate) fn generate_permutation_trace>( None => { permutation_trace .par_rows_mut() - .zip_eq(main.par_rows_mut()) + .zip_eq(main.par_row_slices()) .for_each(|(row, main_row)| { populate_permutation_row( row, diff --git a/recursion/program/src/machine/core.rs b/recursion/program/src/machine/core.rs index 2c1c74fc5e..1b86351109 100644 --- a/recursion/program/src/machine/core.rs +++ b/recursion/program/src/machine/core.rs @@ -263,8 +263,6 @@ where // Assert that exit code is the same for all proofs. builder.assert_felt_eq(exit_code, public_values.exit_code); - // Assert that the committed value digests are all the same. - // Assert that the deferred proof digest is the same for all proofs. for (digest, current_digest) in deferred_proofs_digest .iter() From ce2cf6bf9afa6159327d7a5443e7faf7f4e9de65 Mon Sep 17 00:00:00 2001 From: Matt Stam Date: Fri, 31 May 2024 15:39:47 -0700 Subject: [PATCH 27/28] feat: check version for proof requests (#862) --- sdk/src/network/auth.rs | 3 +++ sdk/src/network/client.rs | 9 +++++++-- sdk/src/network/prover.rs | 6 +++++- sdk/src/proto/network.rs | 3 +++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/sdk/src/network/auth.rs b/sdk/src/network/auth.rs index 2cf1c8c861..2f34fd0f02 100644 --- a/sdk/src/network/auth.rs +++ b/sdk/src/network/auth.rs @@ -15,6 +15,7 @@ sol! { uint64 nonce; uint64 deadline; uint32 mode; + string version; } struct SubmitProof { @@ -94,11 +95,13 @@ impl NetworkAuth { nonce: u64, deadline: u64, mode: i32, + version: &str, ) -> Result> { let type_struct = CreateProof { nonce, deadline, mode: mode as u32, + version: version.to_string(), }; self.sign_message(type_struct).await } diff --git a/sdk/src/network/client.rs b/sdk/src/network/client.rs index 3a5e13ce62..c47447c602 100644 --- a/sdk/src/network/client.rs +++ b/sdk/src/network/client.rs @@ -27,6 +27,9 @@ const DEFAULT_PROVER_NETWORK_RPC: &str = "https://rpc.succinct.xyz/"; /// The default SP1 Verifier address on all chains. const DEFAULT_SP1_VERIFIER_ADDRESS: &str = "0xed2107448519345059eab9cddab42ddc78fbebe9"; +/// The timeout for a proof request to be fulfilled. +const TIMEOUT: Duration = Duration::from_secs(60 * 60); + pub struct NetworkClient { pub rpc: TwirpClient, pub http: HttpClientWithMiddleware, @@ -172,17 +175,18 @@ impl NetworkClient { elf: &[u8], stdin: &SP1Stdin, mode: ProofMode, + version: &str, ) -> Result { let start = SystemTime::now(); let since_the_epoch = start .duration_since(UNIX_EPOCH) .expect("Invalid start time"); - let deadline = since_the_epoch.as_secs() + 1000; + let deadline = since_the_epoch.as_secs() + TIMEOUT.as_secs(); let nonce = self.get_nonce().await?; let create_proof_signature = self .auth - .sign_create_proof_message(nonce, deadline, mode.into()) + .sign_create_proof_message(nonce, deadline, mode.into(), version) .await?; let res = self .rpc @@ -191,6 +195,7 @@ impl NetworkClient { nonce, deadline, mode: mode.into(), + version: version.to_string(), }) .await?; diff --git a/sdk/src/network/prover.rs b/sdk/src/network/prover.rs index 675c10696d..eb035f8e3c 100644 --- a/sdk/src/network/prover.rs +++ b/sdk/src/network/prover.rs @@ -9,6 +9,7 @@ use crate::{ use crate::{SP1CompressedProof, SP1PlonkBn254Proof, SP1Proof, SP1ProvingKey, SP1VerifyingKey}; use anyhow::{Context, Result}; use serde::de::DeserializeOwned; +use sp1_prover::install::PLONK_BN254_ARTIFACTS_COMMIT; use sp1_prover::utils::block_on; use sp1_prover::{SP1Prover, SP1Stdin}; use tokio::{runtime, time::sleep}; @@ -55,7 +56,10 @@ impl NetworkProver { log::info!("Skipping simulation"); } - let proof_id = client.create_proof(elf, &stdin, mode).await?; + let version = PLONK_BN254_ARTIFACTS_COMMIT; + log::info!("Client version {}", version); + + let proof_id = client.create_proof(elf, &stdin, mode, version).await?; log::info!("Created {}", proof_id); let mut is_claimed = false; diff --git a/sdk/src/proto/network.rs b/sdk/src/proto/network.rs index 173c032f1e..7a8497c319 100644 --- a/sdk/src/proto/network.rs +++ b/sdk/src/proto/network.rs @@ -16,6 +16,9 @@ pub struct CreateProofRequest { /// The deadline for the proof request, signifying the latest time a fulfillment would be valid. #[prost(uint64, tag = "4")] pub deadline: u64, + /// The client version used, in the form of an 8-character git commit hash. + #[prost(string, tag = "5")] + pub version: ::prost::alloc::string::String, } /// The response for creating a proof. #[derive(serde::Serialize, serde::Deserialize)] From 20e36b7a0bfaa0c0d7358a94f4506ed4b83b85b8 Mon Sep 17 00:00:00 2001 From: Chris T Date: Fri, 31 May 2024 17:05:48 -0700 Subject: [PATCH 28/28] feat(sdk): add explorer link (#858) --- prover/Makefile | 2 +- recursion/gnark-ffi/build.rs | 2 ++ recursion/gnark-ffi/src/ffi.rs | 2 ++ sdk/src/network/client.rs | 10 ++++++---- sdk/src/network/prover.rs | 14 ++++++++++---- sdk/src/proto/network.rs | 6 +++--- sdk/src/provers/local.rs | 1 + 7 files changed, 25 insertions(+), 12 deletions(-) diff --git a/prover/Makefile b/prover/Makefile index bc3ad6ef61..a63ebbbea0 100644 --- a/prover/Makefile +++ b/prover/Makefile @@ -6,7 +6,7 @@ build-plonk-bn254: rm -rf build && \ mkdir -p build && \ RUSTFLAGS='-C target-cpu=native' \ - cargo run -p sp1-prover --release --bin build_plonk_bn254 -- \ + cargo run -p sp1-prover --release --bin build_plonk_bn254 --features plonk -- \ --build-dir=./build release-plonk-bn254: diff --git a/recursion/gnark-ffi/build.rs b/recursion/gnark-ffi/build.rs index 586e7f8425..650744599c 100644 --- a/recursion/gnark-ffi/build.rs +++ b/recursion/gnark-ffi/build.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use cfg_if::cfg_if; use std::env; use std::path::PathBuf; diff --git a/recursion/gnark-ffi/src/ffi.rs b/recursion/gnark-ffi/src/ffi.rs index 3ab6914cb7..d7ecf9d612 100644 --- a/recursion/gnark-ffi/src/ffi.rs +++ b/recursion/gnark-ffi/src/ffi.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + //! FFI bindings for the Go code. The functions exported in this module are safe to call from Rust. //! All C strings and other C memory should be freed in Rust, including C Strings returned by Go. //! Although we cast to *mut c_char because the Go signatures can't be immutable, the Go functions diff --git a/sdk/src/network/client.rs b/sdk/src/network/client.rs index c47447c602..9b04ae3b00 100644 --- a/sdk/src/network/client.rs +++ b/sdk/src/network/client.rs @@ -22,7 +22,7 @@ use crate::proto::network::{ }; /// The default RPC endpoint for the Succinct prover network. -const DEFAULT_PROVER_NETWORK_RPC: &str = "https://rpc.succinct.xyz/"; +pub const DEFAULT_PROVER_NETWORK_RPC: &str = "https://rpc.succinct.xyz/"; /// The default SP1 Verifier address on all chains. const DEFAULT_SP1_VERIFIER_ADDRESS: &str = "0xed2107448519345059eab9cddab42ddc78fbebe9"; @@ -37,19 +37,21 @@ pub struct NetworkClient { } impl NetworkClient { + pub fn rpc_url() -> String { + env::var("PROVER_NETWORK_RPC").unwrap_or_else(|_| DEFAULT_PROVER_NETWORK_RPC.to_string()) + } + // Create a new NetworkClient with the given private key for authentication. pub fn new(private_key: &str) -> Self { let auth = NetworkAuth::new(private_key); - let rpc_url = env::var("PROVER_NETWORK_RPC") - .unwrap_or_else(|_| DEFAULT_PROVER_NETWORK_RPC.to_string()); - let twirp_http_client = HttpClient::builder() .pool_max_idle_per_host(0) .pool_idle_timeout(Duration::from_secs(240)) .build() .unwrap(); + let rpc_url = Self::rpc_url(); let rpc = TwirpClient::new(Url::parse(&rpc_url).unwrap(), twirp_http_client, vec![]).unwrap(); diff --git a/sdk/src/network/prover.rs b/sdk/src/network/prover.rs index eb035f8e3c..c4870fcacf 100644 --- a/sdk/src/network/prover.rs +++ b/sdk/src/network/prover.rs @@ -2,7 +2,7 @@ use std::{env, time::Duration}; use crate::proto::network::ProofMode; use crate::{ - network::client::NetworkClient, + network::client::{NetworkClient, DEFAULT_PROVER_NETWORK_RPC}, proto::network::{ProofStatus, TransactionStatus}, Prover, }; @@ -62,6 +62,13 @@ impl NetworkProver { let proof_id = client.create_proof(elf, &stdin, mode, version).await?; log::info!("Created {}", proof_id); + if NetworkClient::rpc_url() == DEFAULT_PROVER_NETWORK_RPC { + log::info!( + "View in explorer: https://explorer.succinct.xyz/{}", + proof_id.split('_').last().unwrap_or(&proof_id) + ); + } + let mut is_claimed = false; loop { let (status, maybe_proof) = client.get_proof_status::

(&proof_id).await?; @@ -82,10 +89,9 @@ impl NetworkProver { status.unclaim_description() )); } - _ => { - sleep(Duration::from_secs(1)).await; - } + _ => {} } + sleep(Duration::from_secs(2)).await; } } diff --git a/sdk/src/proto/network.rs b/sdk/src/proto/network.rs index 7a8497c319..5f36a2bd84 100644 --- a/sdk/src/proto/network.rs +++ b/sdk/src/proto/network.rs @@ -312,7 +312,7 @@ impl ProofMode { /// /// The values are not transformed in any way and thus are considered stable /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub const fn as_str_name(&self) -> &'static str { + pub fn as_str_name(&self) -> &'static str { match self { ProofMode::Unspecified => "PROOF_MODE_UNSPECIFIED", ProofMode::Core => "PROOF_MODE_CORE", @@ -365,7 +365,7 @@ impl ProofStatus { /// /// The values are not transformed in any way and thus are considered stable /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub const fn as_str_name(&self) -> &'static str { + pub fn as_str_name(&self) -> &'static str { match self { ProofStatus::ProofUnspecifiedStatus => "PROOF_UNSPECIFIED_STATUS", ProofStatus::ProofPreparing => "PROOF_PREPARING", @@ -422,7 +422,7 @@ impl TransactionStatus { /// /// The values are not transformed in any way and thus are considered stable /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub const fn as_str_name(&self) -> &'static str { + pub fn as_str_name(&self) -> &'static str { match self { TransactionStatus::TransactionUnspecifiedStatus => "TRANSACTION_UNSPECIFIED_STATUS", TransactionStatus::TransactionScheduled => "TRANSACTION_SCHEDULED", diff --git a/sdk/src/provers/local.rs b/sdk/src/provers/local.rs index 3fb469ab4b..5eadf79a34 100644 --- a/sdk/src/provers/local.rs +++ b/sdk/src/provers/local.rs @@ -56,6 +56,7 @@ impl Prover for LocalProver { }) } + #[allow(unused)] fn prove_plonk(&self, pk: &SP1ProvingKey, stdin: SP1Stdin) -> Result { cfg_if! { if #[cfg(feature = "plonk")] {