From a8b7777e396e3c78b7a5f01249ed17cb835ec2ce Mon Sep 17 00:00:00 2001 From: Bhargav Annem Date: Sun, 11 Aug 2024 04:44:41 -0700 Subject: [PATCH] feat: uint256 add/mul --- core/src/runtime/record.rs | 15 +- core/src/runtime/syscall.rs | 42 ++++- core/src/stark/air.rs | 8 +- core/src/syscall/precompiles/uint256/air.rs | 157 +++++++++++------- tests/uint256-mul/Cargo.lock | 8 +- .../elf/riscv32im-succinct-zkvm-elf | Bin 235124 -> 238292 bytes tests/uint256-mul/src/main.rs | 126 ++++++++++---- zkvm/entrypoint/src/syscalls/bigint.rs | 9 +- zkvm/entrypoint/src/syscalls/mod.rs | 6 + zkvm/entrypoint/src/syscalls/uint256_mul.rs | 50 ++++++ 10 files changed, 309 insertions(+), 112 deletions(-) diff --git a/core/src/runtime/record.rs b/core/src/runtime/record.rs index e4d0391597..e410800fbd 100644 --- a/core/src/runtime/record.rs +++ b/core/src/runtime/record.rs @@ -21,7 +21,7 @@ use crate::syscall::precompiles::edwards::EdDecompressEvent; use crate::syscall::precompiles::fptower::{Fp2AddSubEvent, Fp2MulEvent, FpOpEvent}; use crate::syscall::precompiles::keccak256::KeccakPermuteEvent; use crate::syscall::precompiles::sha256::{ShaCompressEvent, ShaExtendEvent}; -use crate::syscall::precompiles::uint256::Uint256MulEvent; +use crate::syscall::precompiles::uint256::Uint256OpEvent; use crate::syscall::precompiles::ECDecompressEvent; use crate::syscall::precompiles::{ECAddEvent, ECDoubleEvent}; use crate::utils::SP1CoreOpts; @@ -91,7 +91,7 @@ pub struct ExecutionRecord { pub bls12381_double_events: Vec, - pub uint256_mul_events: Vec, + pub uint256_op_events: Vec, pub memory_initialize_events: Vec, @@ -201,8 +201,8 @@ impl MachineRecord for ExecutionRecord { self.bls12381_double_events.len(), ); stats.insert( - "uint256_mul_events".to_string(), - self.uint256_mul_events.len(), + "uint256_op_events".to_string(), + self.uint256_op_events.len(), ); stats.insert( "bls12381_fp_event".to_string(), @@ -281,8 +281,7 @@ impl MachineRecord for ExecutionRecord { .append(&mut other.bls12381_add_events); self.bls12381_double_events .append(&mut other.bls12381_double_events); - self.uint256_mul_events - .append(&mut other.uint256_mul_events); + self.uint256_op_events.append(&mut other.uint256_op_events); self.bls12381_fp_events .append(&mut other.bls12381_fp_events); self.bls12381_fp2_addsub_events @@ -426,7 +425,7 @@ impl ExecutionRecord { ed_add_events: std::mem::take(&mut self.ed_add_events), ed_decompress_events: std::mem::take(&mut self.ed_decompress_events), k256_decompress_events: std::mem::take(&mut self.k256_decompress_events), - uint256_mul_events: std::mem::take(&mut self.uint256_mul_events), + uint256_op_events: std::mem::take(&mut self.uint256_op_events), bls12381_fp_events: std::mem::take(&mut self.bls12381_fp_events), bls12381_fp2_mul_events: std::mem::take(&mut self.bls12381_fp2_mul_events), bls12381_decompress_events: std::mem::take(&mut self.bls12381_decompress_events), @@ -554,7 +553,7 @@ impl ExecutionRecord { ); split_events!( self, - uint256_mul_events, + uint256_op_events, shards, opts.deferred_shift_threshold, last diff --git a/core/src/runtime/syscall.rs b/core/src/runtime/syscall.rs index ac3d592319..05a9a7e770 100644 --- a/core/src/runtime/syscall.rs +++ b/core/src/runtime/syscall.rs @@ -12,7 +12,7 @@ use crate::syscall::precompiles::edwards::EdDecompressChip; use crate::syscall::precompiles::fptower::{Fp2AddSubSyscall, Fp2MulAssignChip, FpOpSyscall}; use crate::syscall::precompiles::keccak256::KeccakPermuteChip; use crate::syscall::precompiles::sha256::{ShaCompressChip, ShaExtendChip}; -use crate::syscall::precompiles::uint256::Uint256MulChip; +use crate::syscall::precompiles::uint256::Uint256OpSyscall; use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; use crate::syscall::precompiles::weierstrass::WeierstrassDecompressChip; use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; @@ -97,6 +97,12 @@ pub enum SyscallCode { /// Executes the `HINT_READ` precompile. HINT_READ = 0x00_00_00_F1, + /// Executes the `UINT256_ADD` precompile. + UINT256_ADD = 0x00_01_01_1B, + + /// Executes the `UINT256_SUB` precompile. + UINT256_SUB = 0x00_01_01_1C, + /// Executes the `UINT256_MUL` precompile. UINT256_MUL = 0x00_01_01_1D, @@ -168,6 +174,8 @@ impl SyscallCode { 0x00_00_00_1B => SyscallCode::VERIFY_SP1_PROOF, 0x00_00_00_F0 => SyscallCode::HINT_LEN, 0x00_00_00_F1 => SyscallCode::HINT_READ, + 0x00_01_01_1B => SyscallCode::UINT256_ADD, + 0x00_01_01_1C => SyscallCode::UINT256_SUB, 0x00_01_01_1D => SyscallCode::UINT256_MUL, 0x00_01_01_20 => SyscallCode::BLS12381_FP_ADD, 0x00_01_01_21 => SyscallCode::BLS12381_FP_SUB, @@ -376,7 +384,18 @@ pub fn default_syscall_map() -> HashMap> { SyscallCode::BLS12381_DOUBLE, Arc::new(WeierstrassDoubleAssignChip::::new()), ); - syscall_map.insert(SyscallCode::UINT256_MUL, Arc::new(Uint256MulChip::new())); + syscall_map.insert( + SyscallCode::UINT256_ADD, + Arc::new(Uint256OpSyscall::new(FieldOperation::Add)), + ); + syscall_map.insert( + SyscallCode::UINT256_SUB, + Arc::new(Uint256OpSyscall::new(FieldOperation::Sub)), + ); + syscall_map.insert( + SyscallCode::UINT256_MUL, + Arc::new(Uint256OpSyscall::new(FieldOperation::Mul)), + ); syscall_map.insert( SyscallCode::BLS12381_FP_ADD, Arc::new(FpOpSyscall::::new(FieldOperation::Add)), @@ -453,7 +472,18 @@ pub fn default_syscall_map() -> HashMap> { SyscallCode::BLS12381_DECOMPRESS, Arc::new(WeierstrassDecompressChip::::with_lexicographic_rule()), ); - syscall_map.insert(SyscallCode::UINT256_MUL, Arc::new(Uint256MulChip::new())); + syscall_map.insert( + SyscallCode::UINT256_ADD, + Arc::new(Uint256OpSyscall::new(FieldOperation::Add)), + ); + syscall_map.insert( + SyscallCode::UINT256_SUB, + Arc::new(Uint256OpSyscall::new(FieldOperation::Sub)), + ); + syscall_map.insert( + SyscallCode::UINT256_MUL, + Arc::new(Uint256OpSyscall::new(FieldOperation::Mul)), + ); syscall_map } @@ -529,6 +559,12 @@ mod tests { SyscallCode::BN254_DOUBLE => { assert_eq!(code as u32, sp1_zkvm::syscalls::BN254_DOUBLE) } + SyscallCode::UINT256_ADD => { + assert_eq!(code as u32, sp1_zkvm::syscalls::UINT256_ADD) + } + SyscallCode::UINT256_SUB => { + assert_eq!(code as u32, sp1_zkvm::syscalls::UINT256_SUB) + } SyscallCode::UINT256_MUL => { assert_eq!(code as u32, sp1_zkvm::syscalls::UINT256_MUL) } diff --git a/core/src/stark/air.rs b/core/src/stark/air.rs index c534c15ad2..e5cbdda322 100644 --- a/core/src/stark/air.rs +++ b/core/src/stark/air.rs @@ -31,7 +31,7 @@ pub(crate) mod riscv_chips { pub use crate::syscall::precompiles::keccak256::KeccakPermuteChip; pub use crate::syscall::precompiles::sha256::ShaCompressChip; pub use crate::syscall::precompiles::sha256::ShaExtendChip; - pub use crate::syscall::precompiles::uint256::Uint256MulChip; + pub use crate::syscall::precompiles::uint256::Uint256OpChip; pub use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; pub use crate::syscall::precompiles::weierstrass::WeierstrassDecompressChip; pub use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; @@ -101,7 +101,7 @@ pub enum RiscvAir { /// A precompile for doubling a point on the Elliptic curve bls12_381. Bls12381Double(WeierstrassDoubleAssignChip>), /// A precompile for uint256 mul. - Uint256Mul(Uint256MulChip), + Uint256Op(Uint256OpChip), /// A precompile for decompressing a point on the BLS12-381 curve. Bls12381Decompress(WeierstrassDecompressChip>), /// A precompile for BLS12-381 fp operation. @@ -163,8 +163,8 @@ impl RiscvAir { chips.push(RiscvAir::Bls12381Add(bls12381_add)); let bls12381_double = WeierstrassDoubleAssignChip::>::new(); chips.push(RiscvAir::Bls12381Double(bls12381_double)); - let uint256_mul = Uint256MulChip::default(); - chips.push(RiscvAir::Uint256Mul(uint256_mul)); + let uint256_mul = Uint256OpChip::default(); + chips.push(RiscvAir::Uint256Op(uint256_mul)); let bls12381_fp = FpOpChip::::new(); chips.push(RiscvAir::Bls12381Fp(bls12381_fp)); let bls12381_fp2_addsub = Fp2AddSubAssignChip::::new(); diff --git a/core/src/syscall/precompiles/uint256/air.rs b/core/src/syscall/precompiles/uint256/air.rs index 25477692c8..86c94eae76 100644 --- a/core/src/syscall/precompiles/uint256/air.rs +++ b/core/src/syscall/precompiles/uint256/air.rs @@ -12,8 +12,7 @@ use crate::stark::MachineRecord; use crate::syscall::precompiles::SyscallContext; use crate::utils::ec::uint256::U256Field; use crate::utils::{ - bytes_to_words_le, limbs_from_access, limbs_from_prev_access, pad_rows, words_to_bytes_le, - words_to_bytes_le_vec, + limbs_from_access, limbs_from_prev_access, pad_rows, words_to_bytes_le, words_to_bytes_le_vec, }; use generic_array::GenericArray; use num::{BigUint, One, Zero}; @@ -29,12 +28,14 @@ use std::borrow::{Borrow, BorrowMut}; use std::mem::size_of; use typenum::Unsigned; -/// The number of columns in the Uint256MulCols. -const NUM_COLS: usize = size_of::>(); +/// The number of columns in the Uint256OpCols. +pub const fn num_uint256_cols() -> usize { + size_of::>() +} #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Uint256MulEvent { - pub lookup_id: u128, +pub struct Uint256OpEvent { + pub lookup_id: usize, pub shard: u32, pub channel: u8, pub clk: u32, @@ -43,27 +44,34 @@ pub struct Uint256MulEvent { pub y_ptr: u32, pub y: Vec, pub modulus: Vec, + pub op: FieldOperation, pub x_memory_records: Vec, pub y_memory_records: Vec, pub modulus_memory_records: Vec, } #[derive(Default)] -pub struct Uint256MulChip; +pub struct Uint256OpChip; + +pub struct Uint256OpSyscall { + op: FieldOperation, +} -impl Uint256MulChip { - pub const fn new() -> Self { - Self +impl Uint256OpSyscall { + pub fn new(op: FieldOperation) -> Self { + Self { op } } } type WordsFieldElement = ::WordsFieldElement; const WORDS_FIELD_ELEMENT: usize = WordsFieldElement::USIZE; -/// A set of columns for the Uint256Mul operation. +/// A set of columns for the Uint256Op operation. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct Uint256MulCols { +pub struct Uint256OpCols { + pub is_real: T, + /// The shard number of the syscall. pub shard: T, @@ -99,15 +107,17 @@ pub struct Uint256MulCols { pub output_range_check: FieldLtCols, - pub is_real: T, + pub is_add: T, + pub is_sub: T, + pub is_mul: T, } -impl MachineAir for Uint256MulChip { +impl MachineAir for Uint256OpChip { type Record = ExecutionRecord; type Program = Program; fn name(&self) -> String { - "Uint256MulMod".to_string() + "Uint256OpMod".to_string() } fn generate_trace( @@ -115,9 +125,10 @@ impl MachineAir for Uint256MulChip { input: &ExecutionRecord, output: &mut ExecutionRecord, ) -> RowMajorMatrix { + const NUM_COLS: usize = num_uint256_cols(); // Generate the trace rows & corresponding records for each chunk of events concurrently. let rows_and_records = input - .uint256_mul_events + .uint256_op_events .chunks(1) .map(|events| { let mut records = ExecutionRecord::default(); @@ -127,7 +138,10 @@ impl MachineAir for Uint256MulChip { .iter() .map(|event| { let mut row: [F; NUM_COLS] = [F::zero(); NUM_COLS]; - let cols: &mut Uint256MulCols = row.as_mut_slice().borrow_mut(); + let cols: &mut Uint256OpCols = row.as_mut_slice().borrow_mut(); + + println!("x len: {}", event.x.len()); + println!("y len: {}", event.y.len()); // Decode uint256 points let x = BigUint::from_bytes_le(&words_to_bytes_le::<32>(&event.x)); @@ -136,12 +150,15 @@ impl MachineAir for Uint256MulChip { BigUint::from_bytes_le(&words_to_bytes_le::<32>(&event.modulus)); // Assign basic values to the columns. - cols.is_real = F::one(); cols.shard = F::from_canonical_u32(event.shard); cols.channel = F::from_canonical_u8(event.channel); cols.clk = F::from_canonical_u32(event.clk); cols.x_ptr = F::from_canonical_u32(event.x_ptr); cols.y_ptr = F::from_canonical_u32(event.y_ptr); + cols.is_add = F::from_canonical_u8((event.op == FieldOperation::Add) as u8); + cols.is_sub = F::from_canonical_u8((event.op == FieldOperation::Sub) as u8); + cols.is_mul = F::from_canonical_u8((event.op == FieldOperation::Mul) as u8); + cols.is_real = F::one(); // Populate memory columns. for i in 0..WORDS_FIELD_ELEMENT { @@ -180,7 +197,7 @@ impl MachineAir for Uint256MulChip { &y, &effective_modulus, // &modulus, - FieldOperation::Mul, + event.op, ); cols.modulus_is_not_zero = F::one() - cols.modulus_is_zero.result; @@ -211,12 +228,12 @@ impl MachineAir for Uint256MulChip { pad_rows(&mut rows, || { let mut row: [F; NUM_COLS] = [F::zero(); NUM_COLS]; - let cols: &mut Uint256MulCols = row.as_mut_slice().borrow_mut(); + let cols: &mut Uint256OpCols = row.as_mut_slice().borrow_mut(); let x = BigUint::zero(); let y = BigUint::zero(); cols.output - .populate(&mut vec![], 0, 0, &x, &y, FieldOperation::Mul); + .populate(&mut vec![], 0, 0, &x, &y, FieldOperation::Add); row }); @@ -227,7 +244,7 @@ impl MachineAir for Uint256MulChip { // Write the nonces to the trace. for i in 0..trace.height() { - let cols: &mut Uint256MulCols = + let cols: &mut Uint256OpCols = trace.values[i * NUM_COLS..(i + 1) * NUM_COLS].borrow_mut(); cols.nonce = F::from_canonical_usize(i); } @@ -236,18 +253,19 @@ impl MachineAir for Uint256MulChip { } fn included(&self, shard: &Self::Record) -> bool { - !shard.uint256_mul_events.is_empty() + !shard.uint256_op_events.is_empty() } } -impl Syscall for Uint256MulChip { - fn num_extra_cycles(&self) -> u32 { - 1 +impl BaseAir for Uint256OpChip { + fn width(&self) -> usize { + num_uint256_cols() } +} +impl Syscall for Uint256OpSyscall { fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { let clk = rt.clk; - let x_ptr = arg1; if x_ptr % 4 != 0 { panic!(); @@ -269,42 +287,42 @@ impl Syscall for Uint256MulChip { let (modulus_memory_records, modulus) = rt.mr_slice(modulus_ptr, WORDS_FIELD_ELEMENT); // Get the BigUint values for x, y, and the modulus. - let uint256_x = BigUint::from_bytes_le(&words_to_bytes_le_vec(&x)); - let uint256_y = BigUint::from_bytes_le(&words_to_bytes_le_vec(&y)); - let uint256_modulus = BigUint::from_bytes_le(&words_to_bytes_le_vec(&modulus)); - - // Perform the multiplication and take the result modulo the modulus. - let result: BigUint = if uint256_modulus.is_zero() { - let modulus = BigUint::one() << 256; - (uint256_x * uint256_y) % modulus - } else { - (uint256_x * uint256_y) % uint256_modulus + let modulus = &BigUint::from_bytes_le(&words_to_bytes_le_vec(&modulus)); + let modulus = &modulus + .is_zero() + .then(|| BigUint::one() << 256) + .unwrap_or(modulus.clone()); + + let x = &(BigUint::from_bytes_le(&words_to_bytes_le_vec(&x)) % modulus); + let y = &(BigUint::from_bytes_le(&words_to_bytes_le_vec(&y)) % modulus); + + let result = match self.op { + FieldOperation::Add => (x + y) % modulus, + FieldOperation::Sub => (x + modulus - y) % modulus, + FieldOperation::Mul => (x * y) % modulus, + _ => panic!(), }; - let mut result_bytes = result.to_bytes_le(); - result_bytes.resize(32, 0u8); // Pad the result to 32 bytes. + let mut result_limbs = result.to_u32_digits(); + result_limbs.resize(32, 0u32); // Pad the result to 32 bytes. - // Convert the result to little endian u32 words. - let result = bytes_to_words_le::<8>(&result_bytes); - - // Increment clk so that the write is not at the same cycle as the read. rt.clk += 1; - // Write the result to x and keep track of the memory records. - let x_memory_records = rt.mw_slice(x_ptr, &result); + let x_memory_records = rt.mw_slice(x_ptr, &result_limbs); - let lookup_id = rt.syscall_lookup_id; + let lookup_id = rt.syscall_lookup_id as usize; let shard = rt.current_shard(); let channel = rt.current_channel(); - rt.record_mut().uint256_mul_events.push(Uint256MulEvent { + rt.record_mut().uint256_op_events.push(Uint256OpEvent { lookup_id, shard, channel, clk, x_ptr, - x, + x: x.to_u32_digits(), y_ptr, - y, - modulus, + y: y.to_u32_digits(), + modulus: modulus.to_u32_digits(), + op: self.op, x_memory_records, y_memory_records, modulus_memory_records, @@ -312,15 +330,13 @@ impl Syscall for Uint256MulChip { None } -} -impl BaseAir for Uint256MulChip { - fn width(&self) -> usize { - NUM_COLS + fn num_extra_cycles(&self) -> u32 { + 1 } } -impl Air for Uint256MulChip +impl Air for Uint256OpChip where AB: SP1AirBuilder, Limbs::Limbs>: Copy, @@ -328,9 +344,16 @@ where fn eval(&self, builder: &mut AB) { let main = builder.main(); let local = main.row_slice(0); - let local: &Uint256MulCols = (*local).borrow(); + let local: &Uint256OpCols = (*local).borrow(); let next = main.row_slice(1); - let next: &Uint256MulCols = (*next).borrow(); + let next: &Uint256OpCols = (*next).borrow(); + + // Check that operations flags are boolean. + builder.assert_bool(local.is_add); + builder.assert_bool(local.is_sub); + builder.assert_bool(local.is_mul); + // Check that only one of them is set. + builder.assert_eq(local.is_add + local.is_sub + local.is_mul, AB::Expr::one()); // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); @@ -370,12 +393,15 @@ where + Polynomial::from_coefficients(&coeff_2_256) * modulus_is_zero.into(); // Evaluate the uint256 multiplication - local.output.eval_with_modulus( + local.output.eval_variable( builder, &x_limbs, &y_limbs, &p_modulus, - FieldOperation::Mul, + local.is_add, + local.is_sub, + local.is_mul, + AB::F::zero(), local.shard, local.channel, local.is_real, @@ -422,13 +448,24 @@ where local.is_real, ); + // Select the correct syscall id based on the operation flags. + // + // *Remark*: If support for division is added, we will need to add the division syscall id. + let add_syscall_id = AB::F::from_canonical_u32(SyscallCode::UINT256_ADD.syscall_id()); + let sub_syscall_id = AB::F::from_canonical_u32(SyscallCode::UINT256_SUB.syscall_id()); + let mul_syscall_id = AB::F::from_canonical_u32(SyscallCode::UINT256_MUL.syscall_id()); + + let syscall_id_felt = local.is_add * add_syscall_id + + local.is_sub * sub_syscall_id + + local.is_mul * mul_syscall_id; + // Receive the arguments. builder.receive_syscall( local.shard, local.channel, local.clk, local.nonce, - AB::F::from_canonical_u32(SyscallCode::UINT256_MUL.syscall_id()), + syscall_id_felt, local.x_ptr, local.y_ptr, local.is_real, diff --git a/tests/uint256-mul/Cargo.lock b/tests/uint256-mul/Cargo.lock index d202f1b3ec..119635d9e2 100644 --- a/tests/uint256-mul/Cargo.lock +++ b/tests/uint256-mul/Cargo.lock @@ -16,7 +16,7 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "biguint-mul-test" -version = "1.0.1" +version = "1.1.0" dependencies = [ "bytemuck", "num", @@ -289,7 +289,7 @@ dependencies = [ [[package]] name = "sp1-derive" -version = "1.0.1" +version = "1.1.1" dependencies = [ "proc-macro2", "quote", @@ -298,7 +298,7 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "1.0.1" +version = "1.1.1" dependencies = [ "anyhow", "bincode", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "sp1-zkvm" -version = "1.0.1" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", diff --git a/tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf b/tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf index 2bac42edfc71268accd05f17a1fd4b56df4589a8..7ccf39153fcf211b629f30b417461fd0efa0c259 100755 GIT binary patch delta 58766 zcmcG%4R}<=^*=syv%7gQ;KC*WLJ~IFB!mz`AV7E%Z-8Jx)Sy98BLorzls9=3mAV^~ z4X9M37a3Hrcn0%0TVD6&Y{k>fe7Reh&&#zUNiX@rmj|5B8DYceeB0yX zT(nWS>_cN+kC&o#Dl1fDOzk;M{bq)-t*2Rsev5Iq=X6Ea@7hz~xg|BUB<*9GS9Y{Suelt(rqkW%|tofLctW3fh{XR6|1 zBa9WjuZ~kZ9^;PljJx}!8>f1kMX+wh*ghp@aWTfaJ`2p>+&I-|vibY8QJNf7zXLxS zhm%baL*ErI_@^E%Xf1Ecvz@js2`V zkIOuLy;h#hMyc0K3vDt2UMtUiM!VN+E4#?mGB1CoR&gE_vqVY(zh+T3V8$>G_0e;t{FASFx-R@$ZdKc?;1!MDAZJp8T8{Fdy z!=x&i0s+IFnHncYDf`(Ij1}h};$HEF!Fvp`THwqbw)R zU-E?{#I+puoTozv%`t`(GPZYgAj1LRI2(QyINpX|@i>d44A49-rWvjP6S8juLGZaj zkLgNhb+C5_=x&dzI7-%06bLnfxx0acFfkB#)GVO8VA3J{CaUBecWp_tJ8IIW?%GKw z+{UiKeS5@2mGtOQTf%!pO-k=kJ84J{L(iAgX`mK^IvdoRdKjUczC6Zg%Q{kN78@6q z%S}pR3p~ym^p8!hK#1A^v1-s~rmTSgPcU2agVOO2%|46Nbvh|x!ae6J6mohY)$Fd#;yo~gx<_T9vYg%BYqM&4L}fSkzz_nB_w?oMM*e2di+lRK zTisFFHGW4_f6jdwyWLS)H9hwX53xNX+Ss0--etbbt?sIaoN)Kt1p!^Y?Ag&vSST8m zIBK(NSXEDoq|V(_+Fm3yNDg0b2sP)_zcCeNpmM=N#PqX05u5LX-INl>Vv=+Hl%WCVKN~!(6l^QQjI25 z3roR_5nCM9Nz*Sf3+QfI^z5^a*#EB#DTLm#3_L6rwZXJ+i>BvAh&Ab~V*TF?DIMb( z#srs$u^(Ybdd*o4NliYT#$>wh$;yz1oPUNPRno8s+=gM&#gJemrZF{3L-OS{D`Uzh z11s){bTTGC45&GZ49S;C1r$eNEMxH3M1jEp195-`!{H7X3C8$VhZ^VaxT;n?4@0Vv z=}|HrhLnSHU=N)>tl6=I1;E!FRV&Ms<=goDma~Jw?21w3#BuE=H3G zY&V(&V7t+H&S5m~fiG+{Hk&zY*^J)V%D@RQM;cALS%76U7>EBq&OV{voW*FU4UtCk zZiHChpH-~?o6*e1xV_0Vn)^Cq2szI6+;bR>7sKTYqxr#?U4z-@Cevsz3t6*|GMY>> z8eg`YW#G$;;md1!)Y8n8vlX)yW*r!fFaI5BIF`{w4dVW&r~x$^tjBE`PF44AnrHgQ z{ByUn)aWyaeSRo*QdNDd7S)oHZ8#CkAn5Yc$1Iz4RX}ENoz=B^Em|YdJA%!J^M2betxzIzgv01mNeiJVvWb?6zl;=7hQsk^i97psiwuQR5C{)6zR#zabDC|cjI{dD z>u0rk48J(UobjG$8sq3Wxzf=aeA%;M_107wY4z+C7*m(2@_&mtn_>0+YaIV2=8Qqi z8RN@Nk5w^eaTHCRRXvNMXiELhG3N*h{TyeFIooMw^oNSUV2?Rb*=|(U9An0uF+ws1 z($Pm`j9Bx8`)wjqlMkkLRwtHBX?=x zAoSDFbM{l29Cf$jp<^~M)@MzP$FvJ|GMyK|t3|EbL@_8<)McsNg* z7hr0|>2$&aY=z{s546>-B()^+bGb1jiP1rdM9wptBIn|>XX=uNFJXF&$`kzg+!fjL zI6L4MooH;F&ku7iD#6fnI)4r6$dWOn;5_p{r;R#i$-h*gUMW4&V~`GAZnX(savF5> zi5%W&DW)8`C&bEW15Y&2NMg^c4L+S2LBxBKroZS96A=uWjK7h)ezNkGufyGAIz%{E zrNZcvZ%7!l-lYU>`SyQneaUyo7l&zxcD(&)VN3gesN@8g5fVhUEHt@O$l%HUtzzd- zC<|K~n1T==DlH|^1jb6Ju&692>$QjWHD7(#h>z*hYY(U2&-60r8MRwIYhN_R#tiT` zN|iqB%c)VDg^nQlvj($0=bm~@GrK4~fY>F0x($ttObbo-I5W?Y#>zd;VdqHGFZVbn zGUI4Wk84#OWgchwIe0^tdYskgNMo0HoGZ?ereAE7#U`5NPxd%BoP#ffos(_nNMn;c z&b{YI(26= z;2dfC2%|Av{xInO9DJdn(EmBo*bwOd9BKMs!+oA5KemQ8oP&>cxVD`mjpaiB=Sb7> zn&-U4d20M*L;vUC3uQw8=SX8dkK-iL5GR~5wspjLh=gSMp^?Vv^9J-KZ&DvboCiB_ zH6ylgS?QY$J-&~b9(`td-~rLNhff=I_~2 z7UxWA-rVaQ&OE#(FDf0ixh3N^OU9{VWlv4c)B5TaH`V3q_G=gaV|rq2e50ARg!Jg|I|^H1oZ%8iZ0!= z>Rsk(N@9D0@9LiDzjy3e*~AKs0kd-_XHzz0|Jjr}mqwQyb=eqY*cl181`{Fel1Pm^ zOY%K%25M-8`pXurzh>a%0lr^5b9_6UIaNJf)+=#yP?q%T9F%&tY$OJZ5eyE%O&t#( zz@pVAK3j7CwHq~drLpPS{)s;$EgIV>cnya>ldtXc%Z?0Klx|IlmQHk^WJozZhG80q;sGSV{|1<7<2{0`m@tVKoid>s|j)5W6tPhz$G>seIJYpgcsHC~%h z&!c>kcvLnCk;r{{(^2MJl;487oPK2d3I6j7Y|p*Rs_LD1W$tEG_q5>YWmOwnpuJ`@ z+75jR4LHzRCv`(7T|Wms^s${^b#rjM8i~PDH4@RcaLzl8O|!@F{>I_i8JeDCoSJ=E zYPQEwz>GThBRI*bx_Z2pYn?>{2TpQ`Q9Wlc@4simoF%Eq`y$;*DGA)>PAnV+XQzoQ}bc;HuTNqfKVW!_+L43;q|aBwL_WO`2LSgbWu;QZ3C zjguy6u98Cej1CsVxuzPBTn@u%CHit>Y0W@hV{ESJ%bP{zK|abjQ8PU)aKuv&ui)CX zpOzRN99lrLEw}ffQGLhd$${79OmnA`HM!a@gwrsS*B>J6|NSQaug}5%+oCI{PxrV+T-|i#7u1aDCjZlt-w#cCg6E+fm?xJ~ zSL^#a3+e_s9ASeTvODM;g;W>bFj#L742sd@B*ktv?xwQLG<1Pcf1a79ucS8;oxJ)A ztGkR-bx9g~%y0+MA+{!{QdG_CQ9}=AYk{YX`N6d0z(Ymbzt8u$T;3+vmlqiIugy|& zvnP$lV49yj;i<>V4Hv4GVzZ58P6kE>wna^v{s6@l#$6B>%`+e}g_;KPnN7W);tbgw zdQl=nQK%@~95y?wA~V0rr{C+j*oAh|+ZS26eorSO3V@!?3f5zh-8qt_{zBK%ur;7PV7aBHCRe*MAW3J-4EMU5dR5X02&|@Q(Lg>k&jMr9 zx*D_kAy!MxQ53tU;LaP0HT`$S=0A)Ys>{O&v)}=tYF&;JA!+)|s4NGo>aDs$Z7PTM z`Mgf!*}Hlh{oWXpQF4uRFZC@m>FHVPtTvpL4v%X$e6(~;R~c*G@bL_z@r}N*8DwaSje)V;1m7C<1R{iBONOrzOWVgxNrLb$a(g?p z&F6gpK6#=!uF-N#$*>V8o!#&tpW@RWGZr2ip~2g1JM>I6`DF*f&lztHOw5M!#wZIU zQqxTVh8mmR#Bk0sLT?76m1c5`sc%j5d_lWL!6xi|SP|AdW7k`087+$t?r`Cjop4xA z*0M=~M6>#5jrO;)udHqA^`qSE_=9>z9X8{*4r47&mmr3d&ez$pGF*eJWwE5il-z6} zb~9WE8!_+8#hj|{Lu29F*J~xKjl*v*Fa>-8MVWzI%dJLPYp$lRHP*C_830Y|c1?HS zeYocH2J!9@{f=^FPXyz2P#3kmh2Q^nuf#h|=^r(v|CO0=wV4q0 zh)S5S-E7v+I7Eghp@xxTlFe{A{VFOhGdqwimcwg2#4wd=ID={%E;{Hprv7obzXZMI zEU7EP(-R%6q5K|Khz{pO8xLf$qDi2;UfWsddVw|Jw^3ieYftb6d0+<-1|o{xh%A~B zVL-jItYDyPS*=iOvDtg<8sEsIwnJTrT;#L_fI3b2e0vE?ADs7 z{9sGasQ%OF?j_fCl1kPZJO7k^ks7np5QAulS)ydj643+_IkFiRzp4MJBJ?&-Fmev} z)Iu*AV-NS^FA485p0lU!aCfeSnv4za-l~OOHr(&sJ}&T1?SMMO0JFZ6?Qxa7?4bp( z6rDxOSeEqaEZIx4d+JMGGMojPGTgw`LVuX|HkKZaF^<3Y{Fv#I@y#=qppxG5CXHVo zR=7pLhO^~OS{;}LO*D?YzsR(tbw=3-NlBqz(n{cJ47{6Fb{7a5Yd-i#^ipy~I8(dk z&-Z98tBm*$Q=`qAg}#v|rJ*J|zDui|a7`2sN?(&=RDZbWzwp21k@2H6)*eRuM=MIqWO_8hPdMNeM&*${1J&2rz(ja4vI9DT(3y_1_WtFfNNOnAi2o!*V`)agCq-5wYF4Eu7^^=S zV^PBeoo^iYrouAmUHKCjg&72n7{WKQ@?oE0%C^u>ttiqS4GiYnZC@}`xPo(ZhY_+f|?~p%GZ-sO5l29;n!6* zIV6AJI-~9D3}>j)my>RM^i^LYoua@%UV` z(y>PTx9@48p~lf~r$zfn<+TI$jQwsrPYOMHW`XPp>Z}xF*Z0ke`BkT}y8ZX6tk5Z= z^u*QX?;ngECkB|mzc)TO@rYU97si?&YSeG`vElgf!Sj?_{)9!;A4J0&aE75D3kP%> zg-q7pAdi7pa;CSyAPY%vP+_E;9IDZB<>UghhGrvlGBH{uml;P+UZ?2#Zw&n>oK&DD zzWSWX9vZu6*H5WYCd0ZthfmFn()4l0u+zWq=ceA$FQ5&xsuU;QPtf4TLPr&RXiv(& zPdElErsD=Nk)v?4>l7na61${j+(t?ik}vR8(^!p9(T0W+s@B6tJ&@ZO2&#f!CGTM* z4p4L_%tq2f&0?Q}7e_0mmo_?iqWT^9ZBvSqJGJOCsw*^9RL1a8Dk-#4G{*1?#goze zIhCyUvnA`bO-TMXk7jaER>?BuZ+&)CD2`vi`zdsZ;XIEN?~v`HktN#|I3iNwc^{QM zFu7@LJTK(d*hPphGY1Mqpc`MM1%`-I-FUiU)&~l2cQi)E2_>(K`Q7=QVQ{KDe@96h zxIna?&mRn@EOqnGG}a)>dmyiDu0Bj`?!ix(EjZe=p(h{2!~6$5{5L8obU>_2;FC@8 zJMlpRpKXfr8=)uiOSM2x(U8cqwGbEk68Q)%5HH#jd9D`tmqUztZ9-ZPGp$G0G$xSN%}ndoHBEm&1Wy zX1OeGm4p0CN^6qQP4HMJJ@f_9{Z@r0!v`|_k!GaJJ>RbBC9Ssf5w?Oq?krfBzRoP~ zFP-$zU!;&KT6(*Qp7l=uXSM=|5QAtWshK93Rc!XUS=iA|-avjh-4*;qZFFE{%NCmz zQC?TDO=$xrFVon^wtSy@oPKj>L8(f5ZrNg2@CzBLkeREDf1-@0Ab;&_Rp1?>8?muw z022J1q6J&}+mud1n0e7)tIW`w%lpejcrP%RE&qqgKpqV(lG+IUT}GlJkj!iPwf{`# z(dNo{CXM1Fb7GgA`f=gy%YPp&nF5!J_P#t>3w$i%Q+OYhGcd)7Lu7=5mWD&8*z5;Y zN8nF*8I>Srr0{2=b=d`%iTG3);8mkUMJfzUKh)Ha%CEH?2|SOGwS@YL(`jUoX(Fc| z|FciY*Nxtk77fj(GxY+dn`s1QKoxh}Xz&;auGx(i;DV6?bl1jcSOK=`nnnPzaNIRJ? z^$wF)9Um6!U8yS^N`$KjMM^fmTw_m(rP=Vus*|>gec8NZOc#SPtyxwUGS6*L#euAF^DvfG^Fq1ueWWPw z&o42HykG3-&)+nMT2QzT@qXgr9R7)>zbBB^ue zOY(>2i#1are#uWp!G}p{!EeH=9mtNwFerM_~-*koW50b$dnIEA5cn}N^lSZ z3uq}*;9pob6o}1v{5wsr7wZS{%c#R>&4KAzwJ=W{AH;tZT|l~K6U63x{!0ZyqeQ`A z?wb~^oE9^O5WAyOCZ{E{t5at77Nv^@DlfE!eyar)DwH&~t!dj}{u{31u289{9>TA{ z`!TOc7v<0g2vu$GOaNaj7Qs=v? z(wy;OwFIabeS+9EoG15WhdkJgmAk9bFazVn5s07#){4_ezb4Swr8-naquCT!;7mft zo?Ex!1x=jm^FPF`v9zVM8}9QbaJ0~+v>R-hsejC+rz8h9 zlkY++%xD)jBufbmk{up-Xx>YqV`z)WEJDl#S5Q&J$7_LqipC;-V-IvCIb_QmLU)Rk zk^GiuRZp$hJQCrVTdHV`s2GK)wUsP6u)JyWC<@~gsuZoGd6o&T6Q@V>)M&5lo?C@? z48K5uz$#Hah7UJWmWjqOa7mI)Uo4J|;e*TqE*2?cd3HuI={;3D{t9^a6yt z`ZuCtT)0I(v3VTdtxCg*i}DNkb&5UIL+raSEL``d;}`O|X2aPjF{2m(CQB4+ilNky zTZD@FXpMCfr-740F|}F68dgkgawnN4b}2#VOEF_Sze8gk;>dV}yh@87io6LN2Q$7E zrzh|iHT_euZz9yCWPVwkoX96!5=)Vufm>OnzDimpxhPjj48|GW4_h8Jup*r1bXw*Z zC(Tj0g2ke)gcpS^^}Nm`eSv5#;RCO;a>d({=2EF*DfKRsVP9C&lBSQLbY)%e4T^8H zqM0+lq=iPRNo2(&KA=!GQI{t!;CVDzB6%Lk85k;a)676#Tk$rE)=7L>Y-sZy$Aj1| z-XP9@g6FEv3%w%NT*P12LNAE1rThw;O(`|kh{jU%S*T7NDCI+w^q8=4G{dPXyII?P zZZT{!zt}8;R2!1Rf0<~Q%*SbgM?~vn{*sDMoDZsbyG1}-Tr|k>-?5VdC@@{+tGXMRR4etOBli>QtVb6nbCgvgSoqeF@Erm#DqH;C6E_@S*VRsKTIU zdTmrFS_*MYl)691I@@C_^7&u*L zvxYaJPV=?GTcW(2e-x>iP^!?UQ=FOJR56`DgLy{kOB3#^c-5eY`UC%v^~X6g&a7Ym zw`jbI52mR``6midP3`|Ej$Xy>dp@c)--(ek5HzyyMcoX31zu-ZPE#d+j`Lb>vG8(o z=YJLPSM!?&%Xlle9q}W^oIIdQAJk}OTuBPmu(>KR!j0WcJFn)~nN7kdb6<-Esw(?H z)9Pz^R208kteMIG9leVh9lA{fX7NFO3G~$zI(oY6tky>!;gj#wUbENF$Mm$nRl-`q#+030C~pN%>04}vz2^(Du+ct zE@UDy@9WIW$;FCPDy4i?@f8aDF8rU#es9$X776g!vlyR=XhJyV4D z3EoF6x{1%$^lL=xO%xMfEJDjTHZ?D3+O(Vto`}=dAuQxzbh*1V3Z5XpPfT3NFY9&! zd;6SZF@isx5REH&A?Q>!a9MA1E*el@QbSMt z5sW%9bv5rhU=?fugoq<3hc6SAP{pQ0MBf}2F}L!q{Zu6f!<9HOzo<%HU(){QKSbN@ ze4y=pt730P_=@`bg#Ek90=JQJ8y|3?WD30;^#opXCpaB+Xe_EEA(HvGs*p%};5VXu z4I(Gfva{tw5xR{pKSO|L&LO}~QL%#PNp!!RCyu)BKMN7~<=KT`>(3BkfM~v*Pl*(Q1k^cZQ2QI$i4;ubMX=3snd?@cP*4)AS@@%o`4&HCn z83w72YjATNs&K8Ggzk_FVZ}HO6W<_(x3U4j;)=NZrEuWQM;>*F> zCAXOS;%nIB@k4mkc%0pICBZefO!PQ|CE{=`pFL1EFEqG|=_pOgP0h~gOS*~5I^K&P z7pv=_i4w7?4l3v^TI+cKtdiQS7VK09S=9CtPG=*&WG?BxYO{hRv77j8|2qt#UGe@ueUf{j~dfO{8~N`kCAJ6NngeL zudw(*YoM@yicM=d-kDb2;f$lr80F1Nd?IBX$5}!#V;x#iAXcw~TkS6nuj9W|h2dS3 z<*O)2R{Hr!thtjH!Qr9@eA)L|y)em|+QQSF&Ebl+JJH;JBH=FXgE@`7i{F|7&zVV{ zmXjlM6v2DqteLL`R#P94U&MmbC){^qE?2F7(XOE;vHxzw zeXV3X`qNFJ_0W-juI~d&M{R^DDH_B|bpN9UmAYsyFc0G_2M09^gj$0*}*+U1~2J60H5SH;wg(WOj1=yT zyjP!*a?e$2Dx_Ayq!DLu3@w#<4H(gNrQ{qdS4xsyZw_~i%c+aNM(D3Z?B59eO(gx5 z^p(vek7G@#81s^buPmU&Jh4=uSu93u7JRN!j{ak0+$S@z@0t+zc{H9W${ylX{&RUF zZvL^8*TbSYOQxwY)iNC(OH=8AE&WVFj3NK7o7}1-ZP;wZaGt=C9x?P` zejTm1m`-62)+=bgoDG`9wukvuv6EDtC1t{~nGejmT7Hb76nh<+rX0duqt8jAd^5k0 zKPB4Ma&JYE$Y8Y>HD&v>6LRP9ap&6Xs{5n68+W?!rygA41I1QUW=3x@wb@g&$D@aE z59E{{_X%ma`JEowIa9bF;YEGA26Aam8AU$sbY_dnNBBjfvauEOFKIPSOG7pPlZHea zO6RlWN?Su^1zP~;hGAd}zk**c4sXE_oGBcSB5|G=`zRdH{HCRk@}4|4a0~RxaC%96 zaz9TMI~wtpG%&Mi{Z{@3AG4IS%*J*ZQj!)LjR5MD64=>Seca8|>#i%Q3n$$uc0SJg zrY@vI#@63K>*b?^brXC=lI67p;^^aWTB?pgWTn|!ZLVn8#*;L?NbK0guhCe4Y1B;= zqx1ffHE{l!;^^JGh*P;8uY^L0V%K&osr3ZWx}7Iw=sm0Ma5$ZCh|41 zT%C)UCuxf;N=$r`cDeq(aR=N=;5)H?2Z~{T7dv;r4+OpvM|SX6W0$Eh7hEBB{0cKh zra1U3K5)=EECt6b3*@3#y`X!5oOVm5@IFO5I37eX(k&=W{6VaFiuX;=soh?ZL-Vqy z2w#`f|CJTadyiFV(GFi@OOEfccXPzPr_i@+MEuiy$Y2>z2Jbq%zec=n`D^eYUcXx` zd>VF=jhLuAj^1I50U>$@=G!l5_+sv*qlvP}l6%Ddr!iX358tD!;!sN2+`(yeck?_p`A_H1BxJq0i z<{3EN98vjU0*91?$h%RA!0 zZhoyTe3nfKU3y0NEb00sqVzeAb4=mTRIy(q8lU6+=!~0=h9kOF^;*@e*ih;`3nYfX+dEZ^Fn=MP6J zjm4ZjZ@`5*dyA>hL22*2z%yt*3)z$%;4-~+FV@`=Itl!I_GYkui>Xcg!ZRc|bq)#s zh8kkT`sZo8V-JrNA2#tN;kK0RJ4;(WJ4Z=v|D`P-ox3d`oTDx8pS>-AJck6W5p5a$ zqOC2vUgSa5Fz0&$qby(C@LN8iE9J8@DA(+dkLBmBq^+2ib)c*h z6)jYGnpoe0Gebzge&bs4K?`1T1Xng~dW~NZ%Wo6M-{#|zf~#nsr&p9bTmL&LW^j1# zCcTxnM5&z4J4O6qG^vls!I#&(chl6v{7oKC^S;L~HZ|P} zWy}wXOXW;P9Te^KZu~P}o0{QqmC;FkPRjw+We9cWgCpi(n%MSdKGZMgSBI>P7JHo% zI1Id@$CerXN)PC=+k=B?zMy#n+l<*&r~ih0#T06q`BYi7vZg=%M+-)?6`kdxELm>k+W6gklt}p$ zRxnCz`V}$B7+eF1TlDPgGUdwM0?&Db8-X^9VN2euO_C5a|d0N}in146LpWu_DE>u$8)kM$w zmV4zJt#&#E5s)VxO?rb7jKQH!S}_DROBX}@u9gO|;Uq8a1z-f9_#IVfxV9gV&*+Ws ziQ^}Es!D9RPbE$gDzX0YCht#tMuu?bXemzmEAD;7i4j`W#$j5#R+lGk=&j+E*C4T_ zx0db98S`RuW92eAJx;^Af~wgo7A#q87BSkpdbBssd&_9=I^^k(JkR1u z@>=Z;;y2#kcFG^l%h+M?+I6!`@%p85Y_%{}kipKk6*|i-^pdm5gtQ#++m$%g(bT+BoM?lsr=0cd?c)=JnNz(=Hp5 z!N#Gq2XGI?eXOdphD|q$*ZOLcwBHU9-BYv?vA+fH2=I&+e1MiH-b&TddoEal@ilg6 zhWx(`Nay3kf(wqhJ7A#(Y63d3E5=ru&vNrL3 zsurtl8Ycdks*Uc+7I_)8A$8`h_A<~XrD?0Qyy4>IH0{ds^$)#BRsa3M(Pz`evpTA{ zw4au&ogOZ3=m(oE8zHvz)2{EgW(59Y25^?*?tyy+a#AnQJ@G@Yc(hQPDCT*!;o52B z@MGIE?Ks02@R?;@L9E;I^tz$ z{oG}XXD^&pwWNA(M0zH8tLHB7RkduvQW}FYv!#R&j))u5wdCZokr|Bq$@IlHE?#o; zVy~j38`#t=Q9*rS@yLz;^ zAyd1*=e#lCMFnGUC*z(sMs&~8Zr4tZ5%*+iTkt+dL?Q`p32+j>lWh2> z2)r!<&j%)Zu=4)~<&z7r@O~3l&0o3rMz8p5e=W(mZ(IiJD`IoB+nl2=>@tN^TqypT zquuKN0OT7`3O2i#7q^8A@tgY7!ZWq5>D9pG;jQ#+EE7n*7XAY1DK`8ia8Dcl1Q@ON zgfqMgLYib~a^-4Q#%RY&#mu4FrP|oZ;@3m9m$kPii^YXnu5;=XdqcV{1*CCt74BH+ zhy2W<{gG(6Eu07yb+_T92EaAV zU6zBp4{i%j!EYb#<4e-R7PxiTLXX z?N)8?B{bHji>4y2L@T&d{9L5n;NQ1AJv?1kuS#bzH>b1A)#>aI?mXPv8q!&{k50K982LFTL!M*z7bk^UyboSx}RX5J9_Re169UVubVF#Rj44$hm z%aDq!#}oa=)?Jn%z8tAdpScr+OF=kvX@>0nIYWmd&EPdv=MPsHeD5E;=@teXsxkKB#qWaXh+J#rK7cR-4do{u;ECDP>hRd zqY)MD9=eGZwUrO?$^D4`orFuAd6JkKU{>lIRH z&0Q`QU!W!XMwWL9auk(W6|aWyo6&*mcchDf!?Z!p>6m)GX6rA|a33YI zru7+HyN(_^Zmmb}J)X`gz~e?<(%6h(Ix7Rc4H~utw`<)_w>78>KSo8gIV?nmu3fL4 zx>DSwYiZ6ISHVWarzzSX@u99IX-lsXKj_*VcgnM!_J z`g*5AMd(NHBvY4krT?-?SVOSu#LP+BcxT>q8LUuQ$xD;8!P@-m#CMalr~HRd&e&@* z*d@3r?-AUy@Ov5VI^6f+eiZj!+#%d=;BLeH6K=<~2xD<);l3DmE$+>@_u&2=?t{4F z!S_czzrw9SMmO$M+>LNCLn<iS3 zo+(z9YLmLhv~=n>zD4|@6k1w8OMG3bmrxt~m;z^B+^LiJ~y?zDhgIPQ&7?RY$r6$j%^Tc~) zT5eJ$>OD(mBu&#sB!2*2Qu^0;lFCn;^?i-{r)jxydDuv#MvtE_9-5|Q45|dCP8)`s zlvlCxHfGW008?m?kM&F=_%yYw>UFu6)$@JeETmE15xC!<-*oBa+IHvVjmQ7pK{F;@ zBs^*In4_bEdW9{|Lpp}Dm5Hy;3=%VL*+^r6Adxe%HDrRUgTB%cvtI(1~V20+< z8eC!~rEI1Y{CT?VGccJ3qQxI(XxT|CVmiWNcu@?tSJ?a*;ksJOm~<3rq(8byoJyn} zvGG%gwF0zO&~}jA6T1ia)Ed4{yE7^iumNcm-NfRnwQQ~8e6jIrSo9jVc!8b=dx-bw zncxwB!!vnULPtj#@}LaPNcw=#_Kg$W}68Z5&~6U7ufojVgdIu?qp75HmJ+mL)Z zQQUEjmXYu6)6ua;W!EV?iQ9(sI?$~qkfu(8wx*BNR4(BJguf@jL(N9j1?5Wm`?0ad zydVuj`srlR^I9!q=<$?}4*Z=8;;S@UDeGAQp0?DkJ+cn8W2ve~)?BN_I4jdSIzr;x zd0Kz5>soY5yH~t$t(JDfuJn!$8dG$U(DBe?D`+GfT}1PO_5o<5V!DVn4B()RF9Ebt zGw(=ZGWAI1RD#}~P9q{s8|kCLkf!bMk#K36H&blENYQ3wiWe&|E)ufDUkESE691%U zLzYOoj>b!WG5R|2>p9|@>(CENb2>T>h?)wmmuR?7bBs(z zU2Fi)()^AN`fcfg^tKc9g`iu5g3?2vRp*N>Gqt24Cy_Rc^5CMh<48*w+|kiS1e;DB z(Xa*3M~Y&M#W)f#6Qq*`LYt*!kJ~o1YZq1`ZD#~+1!#M1H0r8#pzR-Oj+RxVzKp>M2&oi`2_ah2$|y+tCwQcKD` zUDQ>eHSj%-k)67xzG?vNWRX~0sU;8Hj5PZ=B3&Fn`hL($@f*7ElA)12M?gP5QoLBH zrHvmu+SFgAl9zOz0LMK8bW7(%%K@znG%tSBMfHybtzxuDo~AEWzSGRVj_BG9>TEx!gab%eih>&{ zVPf|N4vi802o-b|`bp3OQ#(2~NASm^ryZAcrIV1EpsxcRK22WK*&{()eThh_*3y#N zF6$iVWR(k%cI+}SrCQ65?|pekM*%!DmVxK|cce8bz1WB=MJnuFndOE{pDG3#lL^%usWloR%p=9q4V9U0o~DH&X?m z&sQ2=YMIJj(DSN0Ix1Af(u7F(L!d7OeHhVkd2zRa)&SZuE?&7_OY@gskCCM659dq4 zBLB!dvwq~EvILkg*#M#+0ev;-^A*3Padr~)gP>O{;h?~HF5|*@ z)SPgm_3omd8 zX~S+3TjpyS{te4u4a9>BWOfSw>;la`nBuX;y$`fVQ8Pi0S$-ycEa)>L=u}=g=sQ4P zNIs3cLK)lz#fkSrxm5WIFq~Y8P9+9hq^EU6yBQ-hqO%%7FTcgq6Zk0qUeLDP+R;&o z-*ge}AZYEN#Yl?srAI(J3fc!w@$v#KX?$ZKJkQB~qkL{G3__r9rh!ZtcP411b)98V zqeg-@woWA7fPq?ZH{u~;#zp)Kkruzcqhr6MC|Urty`WLdOc#~00knjBpcu^QEUHfH z?w-1i->KbCRZ}^8kzV;gN5?_@ri*9?DbL0(-oej~fanIX-7K6K+d(@ny7saITW2ww zIvYZKy+Jz-K1)$V%LA<)G|B&{ZLnJ z6F*)1-}TDp$={{RXGODmE)1#XQS-SlBp$j^``UjPjno)tpMrZ0-m#M49F+4wZwDqB z2oDFQ*P&#=#9t5m0Weu0;i(vHd;54DL1vwWZ$&9B&g~KX8Jr{4at1r8b71u$(d*!v(FfHt`FkT}q{61jor7_|C z!16`AS-_XTtI=Yb$SJ)iLeNdXFjk2#0JdJ9Q~G>h>)kkEBi4^Wh8Aa-8D0j1^`@H` zz5=%1ViQh4jA^~iCVU~V^~Rd;4ZzlmX~GWxTQ8momoA1?^z}-ArD>c^_k++o#WX7r zs)19011N_WmIH4Ft}wB8iP8Wd;~MrLmSeU-`sP%{A0h$F%fU``90R7e*oekZJ!b`o z5$P>=fr3G?oX@1V024N}~EER8yD1gc;zt(FO z$=UM}>F-A1&m-^&;L6I*{Qm}?Z(%=F9E)(Y0GoF3Cvwz|0=CW!P#4?++&HAuaXb#Z z3m82k`QHMrzTe94WU1Yu(V?A=rxf@ou-oKc4!jBctAWve7kd_jleP*z1a=@pj+wy; zAD?F{fI`HjHhe9xb&!EZc|EXoeu40AV0n1KERW_4^WXxtUt?=;!{h^%#F%~bTi_gM z#Ol+31JfxBx@gpoTLZI&zynR}2X3$$fb?&HkJ!dU{x4uvNVm#c0$exS%c?clKMkTU zK{#I3IS5m4XN(Rvj6?;LUIV^eC@|No@D*Tr?8C%S0miIjA0*&>_adJ5aMkN&A=%({0;CX6iDwi zNh65}g7T0)&%_r3TNepj5rJ=sz#And{o|qxdmv%oqI{m4NMd?JYUpM2jdgGVy6 zef3>^`IT$2oIwW5ZXX0bVk_VXFr7Cd&q?`@uEX?-3X4qvvhRcyfj`~E3xKUtMH8$^oVV8iDB~6KRCf-v*{rO;Q8E^v0S_ zJPk9`hXBvFmA3(SC(4r=MG5|wK{x{?Hz}7J zf=B{A2~5YSs64`szHrqacjDQ=*3m1Z``Km?+EIZM8K}b7fKS;fYzLl*6H)PIdfyai z2-s3_3GkuOcvEYp?*fh)(}`14fx(YSQkH)aa1OAVJ^dQH34~#`0v`sh0Jc>08t@7m zJ^^f<^&){&(lGrZ9g~`>0GN(&^*8Y{U^@1dZQ@6O=?EBEFWRrMgCNj(u%RZykHB;` zY>AfH+rPD>}#lY2L zWqvjPF9g9l-9`*JMZr!Y!(uZ-Gq81$07roXUwPS440{@60%cc!=Vkk%6z&H}QhxBV zObjYYe-BvyyO(V<)9=hg1O5psbNCelzF%V}f5!BxDO?S_ZYYjQaE1Q{oH781Ot564 z0>_{;y@S&kZO{?^J@5*&h%RctkH8@uyR*hnDh9(rU`u1Az^idG&5inHhUFlvBZ7&y z08@bwT&5qSbXx&G06T0rB?o3`!xsS`v*BgHrMB`P0X~Ivzg6Ku5Mpc$KLYo*;j{r* z2iWjr;Q2PZ0(hhiKMI^J6K5WAu0v`pAL5Wo00Jyvjw)Aq~Ive%_Z?oa2fcN@sgm*zWV8djf^30+saV~HL zT5zL@y#g^HR7w}kX2*crfZ@R1ml^*eVzWa2pwVE)%Z zXs`%qK}C5wql27Oz(G`)H`(kGRM_Jo6bRf0{3JjD@ETkCO~A)X)#+90g)5N`bxwF14liECSjVjPM#wE;VcM(*Ct^_1Iz^2GLtR9M}X;~LDgnrw~0Tz4+UEJk=_IW zGnb~blSn54KYsuL4g?rx;)4*_I^N3t$Pl-gG3(qbRq!kXvMy5TuTa40n>wwe&qiQW zCH^WRfophLNK2J4V6 z75O#N>6~l|a!?=AMOa-5AGYBl=$f!}L?*vIo$}H7TU9?8o<;^D%tu*P1&V=K%?egh z2D&&qZ#XId#!v|J6IPevrxVB)UI2c=+d#0&m+8v?s0?&m*~-v{41`mVWM#0Y6CWLI zw)kg{P?!d-#cxml0_k)Fy3v+S*z|u&06HhFF3u{85LN@n+cMbG-$y!~nYLFb&rr(( zI6HqN@?%WUMPq`lHe30lknXt*^FLJ}9R&#eE>lO-2;U2w1Ds=~zX-hU7wIeqWl;;` zM`+OBv{VuewxzJDv!B ze*!Y}1_!BR2?%)+1<>JOdjXM{4i($e?f4;-H#VZYv1_~V`sayMU#NnPwT`t0ms`g308MkmkPV!&0{eBry_%NjnKgBD1g2Ku#bAe>f)^bST(B2 z5s}8G0b5@J5MBdpeGx$TNnm*h-{k)zu=RlerT^OxLIqkxlNJ$jE`X~ACJ#*b3g9Ea z6u1z+9oRbEPxx2B6=(paeVIP^5x7PD5muMN+x`PyI1VeP%R9%I0CoeLX0QCuq4k{wz5<3}woNDJ zg-|)t6HL3OitYS_+wSSiABitU{!`EpA~LC=RlpyFyWFp_tsoo=6O^ZFzqf0Fc6!0PZW(HFk-PALd0}L_g`P33X95nD74sUZBI#nOz{){~JIk1HrO_ z-vO@!w#@8n;09ZIVll<>o%{?JeOIF{B|s#mPg|^X9r?{qLe%>IMi8uTMMz~Efg4eQ zHR_vzt#3pqz3Nx0g&`Uf(BNiZs;~_;5WXH7i@CxabkJb8-AY4p5F@=2m;{jXKSe-G zo!7f?+-+v@TM4 zT?B57z{G18nD83W*?_a*RuM73w?<^3FT>Quo_>2o)Gy5CMPP=WQ;6Pek| zz}DALgueoAg+P{BCX~RJLm(Ohlz#gbB|sZ6^|=PKEJwPGFJMIjF-Ay(E6nuDrx1UV z%5;-(FBqsr($}Ma1J9^FEH~5Vzo7cqvSZ!^fzV}bX8KjY)Bw83Y##(JwNws#1lamq zi_-tT5B5ic#wzeaw8*+FJKq+eviXm6RbeEaxTR})B=$bqnf|^X(=Qcp1htaNGND4s zVBt1+DiYwp|10g<JQkj&Z$%9oH})?x@NkD(XT6^peXPb(8sOdF;wB%Qr8xANEITc{3FpzVt$E8 zlO920;R2!+(xYpUso+8{DB-gAft!J;kPC++FSx)FhGzjE1onay^ouZr)mO38Z{RzD zrvWp%BTacylE{L-kU$<-{;c1Dx2r{iTb_dgXuuVC4)~ye{{dVP2$aS=?^{^Mb_{A-Ffd~SJum+2Pn}J6%yc3wennxbk7aEce zfXSoee4g4x4-dNp9sqqP(P{moLKS}T@!}rvJC7Fgi+B|}ILSQ(6?RaESM!*Ndfl|G z^V?(m{SJ8r;Uj3!0fzNpB@4!1irfz@?urR>g?E9TMF(PHqV}BrG3YIzSEGXR#NY|o zU-;Nx|A~>_b@fX`x)cnDVL=rtsKI<-{)Qvr-j5@7uC4K2qoJ6&>In=9I;0K=*CHln zBZ$dX+H$pR#r^^EsL+sIyUoY+{Ufj9d+2}{KJP_^h(_;n`X%E1M=z#+8m1RzMS2+H zy-;@k02`@z72aPF=~*bW5iaslr)LL_R;dA_zX$sM5S`wV<@8f0LScb!0@J&kUZP|D z5r+L#dp)V|ra!q=#|Ck84=}OaW9BHJGs>z!%dl8AG6fgU0x$ z*d>#NRA@{OW6wt&42}5oY3=YJhTtH>_W_d!X_`~}I&Aq4U5)2|FDfCR9TjB3a>g(e zI~W>ciwU>}m|V;S)NI7+28F8`eaL34erP{}wSNGZV&)x&cLCE7^Y%Z*kZ}JaS@`>S z(c)LZaPBq1XFz`go&YRPv$iK|AcYFnj?1v=#8UqjBHVN@p z@ztQ>aWK>gm>M2dlPQV+0XMn#C z<9Ggq3VKhQ3QeQLW7wksdqD>LJEY3RJgAUL)$RTeApdv@{ICNU3egadLTBy3G((5H zgX@9Y1qIrGz4yZX{v7FDRLnz%7yA{`&=+u$i3UR$z5%!a`11_^2$;VjP6{uA$9UmE zCk_G8s)Zq04gRHtm~nb}Z8d>`Dq4S5&F3)yJm_+8vcfGC6(rII zL1Dt1L%4opV2}=Zgk#{t{wG5GUWNAu@O@y|czvyRT1`)zKQSk&lK<~JXL&!_*eJ2fG|F=qgdfE zUj9Nrue}0`5n_r8d3-W3-EH9TE!NGbpoF3y!{Day4r!uKldxh7l?YUa6NFPg9`4#+fhOH zKX@AwxabLB+ymjC`vJcWOjkm10Vjd!YKZR)nDO0V60BZ1!AN#3SWBAwxKXE`0kKX?&f12_RI@&SMx8rUX zM*jt#9Vt)LF$H>K-%qoK)4u{t(~#q5w`2ZMq8P&(e6|A{1cBi-q~gKQxDp-EVpFxN zxC0wl0-bh9L|+Fy1Nh4fJMa)MJavoH6859)4CblF9Kx*vZg0aFVqVV!BYEu4z|@{w z^l+%dZNSvtdm8oz&c|ql67lefSg?H&s{bI4ALPPRLhWQX>!Ou&D`y=p!Wsc+XXWh681|(8r_I378K&MhU!NMbixxtxQ%04|MC!U z1q6%&BUx}i@FKy&Ex_vqOaeQ(0JQi3^kty)M05IAiNh~6WEX_+WC1%oDn)_Rbl$GO z!cw?$cQHMTH-zY6OxL@hQ2a-v_#Qm(!vg&0joFR(;~=*fW7zLy>}Y^7OFjBiz|R4n z&G1aYB5n}tz>|Lu=#$amQkv%Ij|ySGe^k5$hV~{uXo%%K;HAEXV2Vf|0n?2(eu+rO zfY%H7Brx5S!|4^*B8Uat7kH0=tAXi~8-M;WjSlP$1dyOGJ{qD=c%_(M#Ggk8t(~}l z3Uau`g#8ln{v+(=AF_~2_3On9VLbFeF+Gg65WOLU*N3q5M(Fupd!x7m5ocl1YCD+s z_W>^zFd0z)W^wy4o)MxCemivjKltrp0d)d?4juA~hiIA}MG#Vud3gh=_`p6W0EGrZ z5lTG2*$;k`J)8oc^9nW`pwklv(bZS6wm9g3G8yIa+fhLsk^sVo&>=58s>cZmMXo~- zLLlD{5O0$}9|igz(8W#ZMuC1c=nlU!i7dLS6G4Xt+=7>Y`87(Uai7d=fR6)v1_D1a4e_s`A_hsM@m?_0Wda5M7q|g*o|N(eY8SV(+*-wiD8GaaiR1oB<73S1BD zrE2eA?6BSo_-CO%lE=1qj`TG&;Du`}HXz!{_X7c?@cIz_fPg>5v?FDDW`^EQ0_qNTZm?zeEfOcp>l_;JdvJ@QDd6XJ{@?150?&l-FG4u15MjEY%P-gyf}bu56E`&c;xGzxDl-_rLlv`{FfH)Y zEmSCoRx-?|A=R%JIv{*hz}uRT$#DCZ$lrK4Q0PO@@`AuW2ly!m6<%(K0#Bjh8G&Ksukl(fFt=zYJi-fQN_#Inh7%H=h}HowgU7f+ z?*lL5LkRgz$b`!U+zj~+zj=>b_)e&Ue*iy*27Iv?p2hP!FclgiDyxN^)7BCkB&Krv)*PLW`j<6 z3GmE0__`j$yBt&uhDMF(m>53$CQdwnUu1YPur;ezdVw{tp#U%Bk!2ygDTIkvG=Ol! z-)rbU6g>Y|-0d?o0g}t#4GB0kPmF${4y_O-iYRcyT|Va1G*g0qTA+ZR|Fno7RHRYs zTR5`;!@*v@Lfz05Ve24M0?H;|N9Db3IdKo05NP~0)8J7P&I?P^b2`pbO_%N!o(@cCp@m7 zr!b9w1mDB<8CswVX}lsNU~32;4&gIql1RUhLi88w0Dt)g?x_kqMD+IlguVESNUy-< z)PU{|A_XoA37i?ifdKl;@1S)+&_NYu6?L!&RFbzc)P6h1)IZl)6tMd)JikLA<#rPA z2i}13pE(PEu)^Cf6%-&+>!3iPQg}V+p8aIODVPN$;3yk{vA`rCftIAem{5naLwHpP z?+D=|Av|C%UOX!Cov>M=d|#heGXN3gM$6eD)mfe+b|n5Idj_M+^=+?28VG&J)We5Wov>FY>=U z*Kf~L^G)C%H#X)Od^%$8<~bPu*4Z&B1}RkWO)zxKibICDS+!JmXjJ2&22eF#`vSjQ$?*%HcR#Wq1^(+2(Wc1xAJ! z0I&aTOlpbx1`J<_4bQtV>4;Bvq~D@qb*@G_%q-k_Glm4`{}Wh;_uqms{U8|Aqrh|? zP|fI5VG12yw=w)QFdbfVTzM-Lz`}`x8qaOj@@>Z-Mu=aMi7%r!2OzkfLZW4xQF5#vas94rP$930I-9!GY!u#J9 zQU@f{<2AQ<-5prJe-ra=JR*VjejOdaf(8g6+yP7vqemG&4MDtYB@-y&$De_ZBPIq{ z`26+2m8)XXhKqgtt2>c+*cTG;`7bUEx(iW@FA6m=ff-<&&3b1v)L|!ZCY)Gd7AJ~D{dYSw+!1Vor3cP>mS@a1i=Ktp`82!>n7%h;G5UsYqC+7@s=fsScKfH{WY7X&`aoh0 ztv^)p1}ek`*0*tVikO(e1l|tZgec}i^b9cl$j~81uUdv7`mdOG=Qqil4NQmEdQO(Jd<^Y4OY&=_C{Q2{0WTa+ja?0H)!E_&tFBzJjxW=>rG4 z1ePrR2{4@ragPms5Kl%o;Wq}DLVsS3Af4}jJ&*YR@{o7l;1n7xei%`Y^Z9|SLFXDI zqE>tfwZiY9;(M5uh;kb9DnxnpBXIFg@tXiFDAzp!`ZsC{neY4`Kp}i$(#Q;I0H&AM z7Bl&80(ahn^Z#a6F?~HwLhr>iWEMRPOedX(SqI~P=)X+1i1F70(-=?3; z@Rb`t$D2_j_^f#nLxAIVK8@=)VsUd26!RFv!>FK#&n&~g+X@dn>c1{eE?cwB{~&QG z>)_t)2rA_AM#g`22Z9jux)118$SZ$*p*ZNK?kt`K8-X1$=w`o!PqCmOxA6U4#nWu; zZb-)QdNosEAuv7fS2Gv4?8?$zcEyZ&) z+>5qGoBCU7GGXOXmT4H-WGbPZpSfXSJmG$6f;`Z@;!yN+?uzZv?_ZWQ^SMkak+yX; zujCW9rRU9LE^Xy9ilVD}BCbmD$@bhE=f->DbZ_g3j;+jTrlp#RjFva8Ov=*T{Trn+Nwy4adjy5sH2 zTDD)}W;a5euFmdO*Dn1l<*TZ6qpDM4v=zM@WxMLCbZ1vrR<)#EPRV#nmal&$xU`anm9$IiVwcnHoYRc1+IFXG3B$T$4aI@;DYHIV{@^CdcbA$F?Q%Xn z@035dYRIrpu}jqg4V<1bU-_e;{tNCZDB$#zdIep3P_=wbg~95{ex+!%K6S8^@}p2G zSmpGzqQsT*?MjxfY?3MK^t`6UlLc*iR5tl9DC?ySr<_$au9ojwwM&ZWHp8fh1E;)o zJ+77STCMy^t7%SQCiFNF%Aa0(Lc*`UF2oO?PR9@VPH)LAXo;8H2`Q4Bo+}%bYRc5q zjB2N|MlzGj=G>;avQ?=iY&&Dv$$U1MPFeZ9Uu$GiX5KcmtZCY2R?WHJ-WH8JYQo6p zEWI~YMbBkz-PSBkPrG;QieB4KwP2?L zGc$0Nm2~5~qluhOEZDqRNi$<8S)*XRkxSUAlxpWQs;-#nWHOu75;;3>YM z?d*|Lacf?Ve$h$fGg*v?mQ83@&agA%0|)jjqWs>l3!HxK6pK4UBab8#_4on9-O)20 zGi@ZbjAmraOeSG#x$^A|_F+A1TSz-$R;P;_gDqQ_w<~L59`(#xNIS)>PKkjG(sVIz zDb~XJ(<3V~Iv)Zd9vwd*y@#2?q);&P@)W!*9K+S>zoP5w07E?_BUeWNUUlZKRNo^o(WcHpJ<9!?aUb&B)=wDqe_}9ytpJ zcI9+JLJP}DSJn_`Vd?9Uvk-wLI8((o6?SzcSc^F=x9ZjC*_%4|NAEv-)3*;tBNvaR z6(Fe_)9q{)zu+n@xOG9sZf>5=tFbnes$Q@#jcRwvaJk7HI{|~`Jt&`ZfgE?AnTTZ} znbVPd>})QhX0sSScYhpD)0fxDeMTl!Ba<|(ypc}kQ@S=j-rS5ts;H)tFcONTCsKxC z>ZYP-?t}~Er6Y5RbW%yD6+NHGWQ;75nb#nt8%Z^#8X6wI6-!H^jr;ctS~{07l7`zpS*~@*C~}=UpicgR`__5#bwkvYuIB8tme1ufMovRu;m6h& z32uU6!2;bd)g%-$btREf+*yijx?AdG%Y8jA zpH-Pp7?y6q-+2QQPD^ZBqsUgIH%Xr}&pUG1^!TN6bHp8?$|K!bPzeVG8AG=X#CpcS z$w1P*zcV_l5=#b5&gC^Lo3c}B#cdlUSGz0f&}vm@v}S;ACeyi;Zd$3Fma;QgYmurA z-Tk;;KFhseiaf~e_$Yd26_zeM1lZYRR!`-0GdF(Ihr{Ki5%=nm@+SAoqu`szN6G!% z&IY;PsFae>6jjkv*{p)8R~WfcW*M0ry#WGaIGE+)QDOUmsa1fmTwgmk@Rl$r8^yf!c72H2) zvg-8c2IW6hfsayG4G>fA{uVh_sihNnC9T`ZTr!U{vAnximoIT2=!_2SmrP}pw2@JA zX4ce{wEK!7Usq-1EgSm-#Y&{JSsS6`Zao7bIn|Ws$+@{%x5Jdr@24WOXEYVvnrY+% z_oOLXJ)4{OPtE<*sJRH|dp&yG=vD>So-3Px%g_u%#eZdr;O_bNC0x&k=-(H?r&S3F?$b-37bwEEiXA`6IRBjBD7piaVJcaXSubLHAzlP zbhoUOt4B7`Q93L5+`}uM!M`}V#-}X!{GbkZ$q$Z7)>!w%O8K1LtLN6@SL@t!9+Yc) z(@p(#^W976Z~FXk+I)8|{Y^jhfxlNhDC4(d=eyhRf3M^7qf(7)H{*xcPd+GDo;r8| qF2kSd{~m9fJ7|@BcCTeG;TwZK%j8vZ<-jArpLyHU$oq#>qVoU43*)i? delta 56118 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 diff --git a/tests/uint256-mul/src/main.rs b/tests/uint256-mul/src/main.rs index d7201115af..f963657b22 100644 --- a/tests/uint256-mul/src/main.rs +++ b/tests/uint256-mul/src/main.rs @@ -19,6 +19,34 @@ fn uint256_mul(x: &[u8; 32], y: &[u8; 32], modulus: &[u8; 32]) -> [u8; 32] { bytemuck::cast::<[u32; 8], [u8; 32]>(result) } +fn uint256_add(x: &[u8; 32], y: &[u8; 32], modulus: &[u8; 32]) -> [u8; 32] { + println!("cycle-tracker-start: uint256_add"); + let mut result = [0u32; 8]; + sys_bigint( + result.as_mut_ptr() as *mut [u32; 8], + 1, + x.as_ptr() as *const [u32; 8], + y.as_ptr() as *const [u32; 8], + modulus.as_ptr() as *const [u32; 8], + ); + println!("cycle-tracker-end: uint256_add"); + bytemuck::cast::<[u32; 8], [u8; 32]>(result) +} + +fn uint256_sub(x: &[u8; 32], y: &[u8; 32], modulus: &[u8; 32]) -> [u8; 32] { + println!("cycle-tracker-start: uint256_sub"); + let mut result = [0u32; 8]; + sys_bigint( + result.as_mut_ptr() as *mut [u32; 8], + 2, + x.as_ptr() as *const [u32; 8], + y.as_ptr() as *const [u32; 8], + modulus.as_ptr() as *const [u32; 8], + ); + println!("cycle-tracker-end: uint256_sub"); + bytemuck::cast::<[u32; 8], [u8; 32]>(result) +} + fn biguint_to_bytes_le(x: BigUint) -> [u8; 32] { let mut bytes = x.to_bytes_le(); bytes.resize(32, 0); @@ -27,71 +55,107 @@ fn biguint_to_bytes_le(x: BigUint) -> [u8; 32] { #[sp1_derive::cycle_tracker] fn main() { + let mut rng = rand::thread_rng(); + + // Test multiplication for _ in 0..50 { - // Test with random numbers. - let mut rng = rand::thread_rng(); let mut x: [u8; 32] = rng.gen(); let mut y: [u8; 32] = rng.gen(); let modulus: [u8; 32] = rng.gen(); - // Convert byte arrays to BigUint let modulus_big = BigUint::from_bytes_le(&modulus); - let x_big = BigUint::from_bytes_le(&x); + let x_big = BigUint::from_bytes_le(&x) % &modulus_big; x = biguint_to_bytes_le(&x_big % &modulus_big); - let y_big = BigUint::from_bytes_le(&y); + let y_big = BigUint::from_bytes_le(&y) % &modulus_big; y = biguint_to_bytes_le(&y_big % &modulus_big); let result_bytes = uint256_mul(&x, &y, &modulus); + let result = (x_big * y_big) % &modulus_big; + let result_syscall = BigUint::from_bytes_le(&result_bytes); - let result = (x_big * y_big) % modulus_big; + assert_eq!(result, result_syscall, "Multiplication failed"); + } + + // Test addition + for _ in 0..50 { + let mut x: [u8; 32] = rng.gen(); + let mut y: [u8; 32] = rng.gen(); + let modulus: [u8; 32] = rng.gen(); + + let modulus_big = BigUint::from_bytes_le(&modulus); + let x_big = BigUint::from_bytes_le(&x) % &modulus_big; + x = biguint_to_bytes_le(&x_big % &modulus_big); + let y_big = BigUint::from_bytes_le(&y) % &modulus_big; + y = biguint_to_bytes_le(&y_big % &modulus_big); + + let result_bytes = uint256_add(&x, &y, &modulus); + let result = (x_big + y_big) % &modulus_big; let result_syscall = BigUint::from_bytes_le(&result_bytes); - assert_eq!(result, result_syscall); + assert_eq!(result, result_syscall, "Addition failed"); } - // Modulus zero tests + // Test subtraction + for _ in 0..50 { + let mut x: [u8; 32] = rng.gen(); + let mut y: [u8; 32] = rng.gen(); + let modulus: [u8; 32] = rng.gen(); + + let modulus_big = BigUint::from_bytes_le(&modulus); + let x_big = BigUint::from_bytes_le(&x) % &modulus_big; + x = biguint_to_bytes_le(&x_big % &modulus_big); + let y_big = BigUint::from_bytes_le(&y) % &modulus_big; + y = biguint_to_bytes_le(&y_big % &modulus_big); + + let result_bytes = uint256_sub(&x, &y, &modulus); + let result = (modulus_big.clone() + x_big - y_big) % &modulus_big; + let result_syscall = BigUint::from_bytes_le(&result_bytes); + + assert_eq!(result, result_syscall, "Subtraction failed"); + } + + // Modulus zero tests for multiplication (unchanged) let modulus = [0u8; 32]; let modulus_big: BigUint = BigUint::one() << 256; for _ in 0..50 { - // Test with random numbers. - let mut rng = rand::thread_rng(); let mut x: [u8; 32] = rng.gen(); let mut y: [u8; 32] = rng.gen(); - // Convert byte arrays to BigUint - let x_big = BigUint::from_bytes_le(&x); + let x_big = BigUint::from_bytes_le(&x) % &modulus_big; x = biguint_to_bytes_le(&x_big % &modulus_big); - let y_big = BigUint::from_bytes_le(&y); + let y_big = BigUint::from_bytes_le(&y) % &modulus_big; y = biguint_to_bytes_le(&y_big % &modulus_big); let result_bytes = uint256_mul(&x, &y, &modulus); - let result = (x_big * y_big) % &modulus_big; let result_syscall = BigUint::from_bytes_le(&result_bytes); - assert_eq!(result, result_syscall, "x: {:?}, y: {:?}", x, y); + assert_eq!( + result, result_syscall, + "Modulus zero multiplication failed: x: {:?}, y: {:?}", + x, y + ); } - // Test with random numbers. - let mut rng = rand::thread_rng(); + // Special cases for addition and subtraction + let zero: [u8; 32] = [0; 32]; + let mut one: [u8; 32] = [0; 32]; + one[0] = 1; let x: [u8; 32] = rng.gen(); - // Hardcoded edge case: Multiplying by 1 - let modulus = [0u8; 32]; + // Addition special cases + let result_zero_add = uint256_add(&x, &zero, &modulus); + assert_eq!(result_zero_add, x, "Adding zero failed"); - let mut one: [u8; 32] = [0; 32]; - one[0] = 1; // Least significant byte set to 1, represents the number 1 - let original_x = x; // Copy original x value before multiplication by 1 - let result_one = uint256_mul(&x, &one, &modulus); - assert_eq!( - result_one, original_x, - "Multiplying by 1 should yield the same number." - ); + let result_modulus_add = uint256_add(&x, &modulus, &modulus); + assert_eq!(result_modulus_add, x, "Adding modulus failed"); + + // Subtraction special cases + let result_zero_sub = uint256_sub(&x, &zero, &modulus); + assert_eq!(result_zero_sub, x, "Subtracting zero failed"); - // Hardcoded edge case: Multiplying by 0 - let zero: [u8; 32] = [0; 32]; // Represents the number 0 - let result_zero = uint256_mul(&x, &zero, &modulus); - assert_eq!(result_zero, zero, "Multiplying by 0 should yield 0."); + let result_same_sub = uint256_sub(&x, &x, &modulus); + assert_eq!(result_same_sub, zero, "Subtracting the same number failed"); println!("All tests passed successfully!"); } diff --git a/zkvm/entrypoint/src/syscalls/bigint.rs b/zkvm/entrypoint/src/syscalls/bigint.rs index b7d1e7018d..e3d95176f9 100644 --- a/zkvm/entrypoint/src/syscalls/bigint.rs +++ b/zkvm/entrypoint/src/syscalls/bigint.rs @@ -1,4 +1,4 @@ -use super::syscall_uint256_mulmod; +use super::{syscall_uint256_addmod, syscall_uint256_mulmod, syscall_uint256_submod}; /// The number of limbs in a "uint256". const N: usize = 8; @@ -43,6 +43,11 @@ pub extern "C" fn sys_bigint( // This syscall writes the result in-place, so it will mutate the result ptr appropriately. let result_ptr = result_ptr as *mut [u32; N]; let concat_ptr = concat_ptr as *mut [u32; N]; - syscall_uint256_mulmod(result_ptr, concat_ptr); + match op { + 0 => syscall_uint256_mulmod(result_ptr, concat_ptr), + 1 => syscall_uint256_addmod(result_ptr, concat_ptr), + 2 => syscall_uint256_submod(result_ptr, concat_ptr), + _ => unreachable!(), + } } } diff --git a/zkvm/entrypoint/src/syscalls/mod.rs b/zkvm/entrypoint/src/syscalls/mod.rs index e40728d7ed..38271b8a5f 100644 --- a/zkvm/entrypoint/src/syscalls/mod.rs +++ b/zkvm/entrypoint/src/syscalls/mod.rs @@ -97,6 +97,12 @@ pub const HINT_READ: u32 = 0x00_00_00_F1; /// Executes `BLS12381_DECOMPRESS`. pub const BLS12381_DECOMPRESS: u32 = 0x00_00_01_1C; +/// Executes the `UINT256_ADD` precompile. +pub const UINT256_ADD: u32 = 0x00_01_01_1B; + +/// Executes the `UINT256_SUB` precompile. +pub const UINT256_SUB: u32 = 0x00_01_01_1C; + /// Executes the `UINT256_MUL` precompile. pub const UINT256_MUL: u32 = 0x00_01_01_1D; diff --git a/zkvm/entrypoint/src/syscalls/uint256_mul.rs b/zkvm/entrypoint/src/syscalls/uint256_mul.rs index c5ce19951a..3e0240254f 100644 --- a/zkvm/entrypoint/src/syscalls/uint256_mul.rs +++ b/zkvm/entrypoint/src/syscalls/uint256_mul.rs @@ -1,6 +1,56 @@ #[cfg(target_os = "zkvm")] use core::arch::asm; +/// Uint256 addition operation. +/// +/// The result is written over the first input. +/// +/// ### Safety +/// +/// The caller must ensure that `x` and `y` are valid pointers to data that is aligned along a four +/// byte boundary. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_uint256_addmod(x: *mut [u32; 8], y: *const [u32; 8]) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::UINT256_ADD, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// Uint256 subtraction operation. +/// +/// The result is written over the first input. +/// +/// ### Safety +/// +/// The caller must ensure that `x` and `y` are valid pointers to data that is aligned along a four +/// byte boundary. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_uint256_submod(x: *mut [u32; 8], y: *const [u32; 8]) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::UINT256_SUB, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + /// Uint256 multiplication operation. /// /// The result is written over the first input.