diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a2547409d..50358ee7d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -65,7 +65,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check branch - if: github.head_ref != 'dev' + if: github.head_ref != 'dev' && !startsWith(github.ref, 'release/') && !startsWith(github.ref, 'hotfix/') run: | - echo "ERROR: You can only merge to main from dev." + echo "ERROR: You can only merge to main from dev, release/*, or hotfix/*." exit 1 diff --git a/Cargo.lock b/Cargo.lock index adfcf808b..e1703793e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3042,7 +3042,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "p3-air" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "p3-field", "p3-matrix", @@ -3051,7 +3051,7 @@ dependencies = [ [[package]] name = "p3-baby-bear" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "num-bigint 0.4.5", "p3-field", @@ -3065,7 +3065,7 @@ dependencies = [ [[package]] name = "p3-blake3" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "blake3", "p3-symmetric", @@ -3074,7 +3074,7 @@ dependencies = [ [[package]] name = "p3-bn254-fr" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "ff 0.13.0", "num-bigint 0.4.5", @@ -3088,7 +3088,7 @@ dependencies = [ [[package]] name = "p3-challenger" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "p3-field", "p3-maybe-rayon", @@ -3100,7 +3100,7 @@ dependencies = [ [[package]] name = "p3-commit" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "itertools 0.12.1", "p3-challenger", @@ -3113,7 +3113,7 @@ dependencies = [ [[package]] name = "p3-dft" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "p3-field", "p3-matrix", @@ -3125,7 +3125,7 @@ dependencies = [ [[package]] name = "p3-field" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "itertools 0.12.1", "num-bigint 0.4.5", @@ -3138,7 +3138,7 @@ dependencies = [ [[package]] name = "p3-fri" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "itertools 0.12.1", "p3-challenger", @@ -3156,7 +3156,7 @@ dependencies = [ [[package]] name = "p3-interpolation" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "p3-field", "p3-matrix", @@ -3166,7 +3166,7 @@ dependencies = [ [[package]] name = "p3-keccak" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "p3-symmetric", "tiny-keccak", @@ -3175,7 +3175,7 @@ dependencies = [ [[package]] name = "p3-keccak-air" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "p3-air", "p3-field", @@ -3188,7 +3188,7 @@ dependencies = [ [[package]] name = "p3-matrix" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "itertools 0.12.1", "p3-field", @@ -3202,7 +3202,7 @@ dependencies = [ [[package]] name = "p3-maybe-rayon" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "rayon", ] @@ -3210,7 +3210,7 @@ dependencies = [ [[package]] name = "p3-mds" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "itertools 0.12.1", "p3-dft", @@ -3224,7 +3224,7 @@ dependencies = [ [[package]] name = "p3-merkle-tree" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "itertools 0.12.1", "p3-commit", @@ -3240,7 +3240,7 @@ dependencies = [ [[package]] name = "p3-poseidon2" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "gcd", "p3-field", @@ -3252,7 +3252,7 @@ dependencies = [ [[package]] name = "p3-symmetric" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "itertools 0.12.1", "p3-field", @@ -3262,7 +3262,7 @@ dependencies = [ [[package]] name = "p3-uni-stark" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "itertools 0.12.1", "p3-air", @@ -3280,7 +3280,7 @@ dependencies = [ [[package]] name = "p3-util" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=3b5265f9d5af36534a46caebf0617595cfb42c5a#3b5265f9d5af36534a46caebf0617595cfb42c5a" +source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "serde", ] diff --git a/Cargo.toml b/Cargo.toml index d88f8b7a6..063a57c60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,26 +30,26 @@ debug = true debug-assertions = true [workspace.dependencies] -p3-air = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-commit = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } +p3-air = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-commit = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", features = [ "nightly-features", -], rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-util = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-dft = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-fri = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-keccak = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-keccak-air = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-blake3 = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-merkle-tree = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-poseidon2 = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-uni-stark = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-maybe-rayon = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } -p3-bn254-fr = { git = "https://github.com/Plonky3/Plonky3.git", rev = "3b5265f9d5af36534a46caebf0617595cfb42c5a" } +], rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-util = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-dft = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-fri = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-keccak = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-keccak-air = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-blake3 = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-merkle-tree = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-poseidon2 = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-uni-stark = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-maybe-rayon = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-bn254-fr = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } # For local development. diff --git a/core/src/lib.rs b/core/src/lib.rs index 8a862fcc2..ac8524027 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -39,4 +39,4 @@ use stark::StarkGenericConfig; /// This string should be updated whenever any step in verifying an SP1 proof changes, including /// core, recursion, and plonk-bn254. This string is used to download SP1 artifacts and the gnark /// docker image. -pub const SP1_CIRCUIT_VERSION: &str = "v1.0.7-testnet"; +pub const SP1_CIRCUIT_VERSION: &str = "v1.0.8-testnet"; diff --git a/core/src/runtime/mod.rs b/core/src/runtime/mod.rs index 1692181d9..b223e1503 100644 --- a/core/src/runtime/mod.rs +++ b/core/src/runtime/mod.rs @@ -264,16 +264,9 @@ impl<'a> Runtime<'a> { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => { // If addr has a specific value to be initialized with, use that, otherwise 0. - let value = self.state.uninitialized_memory.remove(&addr).unwrap_or(0); - - // Do not emit memory initialize events for address 0 as that is done in initialize. - if addr != 0 { - self.record - .memory_initialize_events - .push(MemoryInitializeFinalizeEvent::initialize(addr, value, true)); - } + let value = self.state.uninitialized_memory.get(&addr).unwrap_or(&0); entry.insert(MemoryRecord { - value, + value: *value, shard: 0, timestamp: 0, }) @@ -312,16 +305,10 @@ impl<'a> Runtime<'a> { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => { // If addr has a specific value to be initialized with, use that, otherwise 0. - let value = self.state.uninitialized_memory.remove(&addr).unwrap_or(0); + let value = self.state.uninitialized_memory.get(&addr).unwrap_or(&0); - // Do not emit memory initialize events for address 0 as that is done in initialize. - if addr != 0 { - self.record - .memory_initialize_events - .push(MemoryInitializeFinalizeEvent::initialize(addr, value, true)); - } entry.insert(MemoryRecord { - value, + value: *value, shard: 0, timestamp: 0, }) @@ -1026,11 +1013,6 @@ impl<'a> Runtime<'a> { }, ); } - - // Create init event for register 0 because it needs to be the first row in MemoryInit. - self.record - .memory_initialize_events - .push(MemoryInitializeFinalizeEvent::initialize(0, 0, true)); } pub fn run_untraced(&mut self) -> Result<(), ExecutionError> { @@ -1134,13 +1116,29 @@ impl<'a> Runtime<'a> { addr_0_final_record, )); + let memory_initialize_events = &mut self.record.memory_initialize_events; + let addr_0_initialize_event = + MemoryInitializeFinalizeEvent::initialize(0, 0, addr_0_record.is_some()); + memory_initialize_events.push(addr_0_initialize_event); + for addr in self.state.memory.keys() { if addr == &0 { - continue; // We handle addr = 0 separately above. + // Handled above. + continue; } - let record = *self.state.memory.get(addr).unwrap(); + // Program memory is initialized in the MemoryProgram chip and doesn't require any events, + // so we only send init events for other memory addresses. + if !self.record.program.memory_image.contains_key(addr) { + let initial_value = self.state.uninitialized_memory.get(addr).unwrap_or(&0); + memory_initialize_events.push(MemoryInitializeFinalizeEvent::initialize( + *addr, + *initial_value, + true, + )); + } + let record = *self.state.memory.get(addr).unwrap(); memory_finalize_events.push(MemoryInitializeFinalizeEvent::finalize_from_record( *addr, &record, )); diff --git a/core/src/runtime/record.rs b/core/src/runtime/record.rs index 7742c2aa6..0e80a4084 100644 --- a/core/src/runtime/record.rs +++ b/core/src/runtime/record.rs @@ -572,11 +572,11 @@ impl MachineRecord for ExecutionRecord { self.nonce_lookup.insert(event.lookup_id, i as u32); } - first - .memory_initialize_events + // Put MemoryInit / MemoryFinalize events in the last shard. + let last = shards.last_mut().unwrap(); + last.memory_initialize_events .extend_from_slice(&self.memory_initialize_events); - first - .memory_finalize_events + last.memory_finalize_events .extend_from_slice(&self.memory_finalize_events); // Copy the nonce lookup to all shards. diff --git a/core/src/stark/machine.rs b/core/src/stark/machine.rs index 8891fdc14..3c8083234 100644 --- a/core/src/stark/machine.rs +++ b/core/src/stark/machine.rs @@ -682,6 +682,18 @@ pub mod tests { run_test(program).unwrap(); } + #[test] + fn test_fibonacci_prove_checkpoints() { + setup_logger(); + + let program = fibonacci_program(); + let stdin = SP1Stdin::new(); + let mut opts = SP1CoreOpts::default(); + opts.shard_size = 1024; + opts.shard_batch_size = 2; + prove(program, &stdin, BabyBearPoseidon2::new(), opts).unwrap(); + } + #[test] fn test_fibonacci_prove_batch() { setup_logger(); diff --git a/core/src/stark/types.rs b/core/src/stark/types.rs index 67f07cc03..e3eede287 100644 --- a/core/src/stark/types.rs +++ b/core/src/stark/types.rs @@ -124,7 +124,7 @@ pub struct ShardOpenedValues { /// The maximum number of elements that can be stored in the public values vec. Both SP1 and recursive /// proofs need to pad their public_values vec to this length. This is required since the recursion /// verification program expects the public values vec to be fixed length. -pub const PROOF_MAX_NUM_PVS: usize = 240; +pub const PROOF_MAX_NUM_PVS: usize = 241; #[derive(Serialize, Deserialize, Clone)] #[serde(bound = "")] diff --git a/examples/Cargo.lock b/examples/Cargo.lock index bc5ac9e3e..cb3302af4 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -4907,6 +4907,7 @@ dependencies = [ "bindgen", "cc", "cfg-if", + "hex", "log", "num-bigint 0.4.5", "p3-baby-bear", @@ -4915,6 +4916,7 @@ dependencies = [ "rand", "serde", "serde_json", + "sha2 0.10.8", "sp1-core", "sp1-recursion-compiler", "tempfile", @@ -4977,6 +4979,7 @@ dependencies = [ "strum", "strum_macros", "tempfile", + "thiserror", "tokio", "tracing", "twirp", diff --git a/examples/aggregation/program/Cargo.lock b/examples/aggregation/program/Cargo.lock index de974399f..71a2d8afc 100644 --- a/examples/aggregation/program/Cargo.lock +++ b/examples/aggregation/program/Cargo.lock @@ -725,7 +725,7 @@ dependencies = [ [[package]] name = "sha2" version = "0.10.8" -source = "git+https://github.com/sp1-patches/RustCrypto-hashes.git?branch=patch-v0.10.8#3d692aa90b91513886d757d01f8fc2d51c0ec0d7" +source = "git+https://github.com/sp1-patches/RustCrypto-hashes.git?branch=patch-v0.10.8#1f224388fdede7cef649bce0d63876d1a9e3f515" dependencies = [ "cfg-if", "cpufeatures", diff --git a/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf b/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf index 2d2682e46..cd36cd92d 100755 Binary files a/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf and b/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/ssz-withdrawals/program/Cargo.lock b/examples/ssz-withdrawals/program/Cargo.lock index 81a8dedbc..3d8ed9019 100644 --- a/examples/ssz-withdrawals/program/Cargo.lock +++ b/examples/ssz-withdrawals/program/Cargo.lock @@ -1365,7 +1365,7 @@ dependencies = [ [[package]] name = "sha2" version = "0.10.8" -source = "git+https://github.com/sp1-patches/RustCrypto-hashes.git?branch=patch-v0.10.8#3d692aa90b91513886d757d01f8fc2d51c0ec0d7" +source = "git+https://github.com/sp1-patches/RustCrypto-hashes.git?branch=patch-v0.10.8#1f224388fdede7cef649bce0d63876d1a9e3f515" dependencies = [ "cfg-if", "cpufeatures", diff --git a/examples/tendermint/program/Cargo.lock b/examples/tendermint/program/Cargo.lock index ed1af56c2..bf2d905af 100644 --- a/examples/tendermint/program/Cargo.lock +++ b/examples/tendermint/program/Cargo.lock @@ -138,7 +138,7 @@ dependencies = [ [[package]] name = "curve25519-dalek-ng" version = "4.1.1" -source = "git+https://github.com/sp1-patches/curve25519-dalek-ng.git#01f43665631d2c33385708d41d0c26dbb1baa0ea" +source = "git+https://github.com/sp1-patches/curve25519-dalek-ng.git?branch=patch-v4.1.1#f5607edd61ad8e9d80c9be933cd119f4008044d9" dependencies = [ "byteorder", "digest 0.9.0", @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "ed25519-consensus" version = "2.1.0" -source = "git+https://github.com/sp1-patches/ed25519-consensus?branch=patch-v2.1.0#59f16610526726fa5c96dd77ca792f821021b66e" +source = "git+https://github.com/sp1-patches/ed25519-consensus?branch=patch-v2.1.0#4fba9b0acc9fcf7a87d00da84c340d5988e3d7cb" dependencies = [ "curve25519-dalek-ng", "hex", diff --git a/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf b/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf index a9159cc25..f7ddcd1de 100755 Binary files a/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf and b/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 8df7eed31..5df8e7058 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -288,6 +288,7 @@ impl SP1Prover { leaf_challenger, initial_reconstruct_challenger: reconstruct_challenger.clone(), is_complete, + total_core_shards: shard_proofs.len(), }); for proof in batch.iter() { @@ -320,6 +321,7 @@ impl SP1Prover { last_proof_pv: &PublicValues, BabyBear>, deferred_proofs: &[ShardProof], batch_size: usize, + total_core_shards: usize, ) -> Vec>> { // Prepare the inputs for the deferred proofs recursive verification. let mut deferred_digest = [Val::::zero(); DIGEST_SIZE]; @@ -337,10 +339,11 @@ impl SP1Prover { sp1_vk: vk, sp1_machine: &self.core_machine, end_pc: Val::::zero(), - end_shard: last_proof_pv.shard, + end_shard: last_proof_pv.shard + BabyBear::one(), leaf_challenger: leaf_challenger.clone(), committed_value_digest: last_proof_pv.committed_value_digest.to_vec(), deferred_proofs_digest: last_proof_pv.deferred_proofs_digest.to_vec(), + total_core_shards, }); deferred_digest = Self::hash_deferred_proofs(deferred_digest, batch); @@ -377,6 +380,7 @@ impl SP1Prover { &last_proof_pv, deferred_proofs, batch_size, + shard_proofs.len(), ); (core_inputs, deferred_inputs) } @@ -393,6 +397,7 @@ impl SP1Prover { let batch_size = 2; let shard_proofs = &proof.proof.0; + let total_core_shards = shard_proofs.len(); // Get the leaf challenger. let mut leaf_challenger = self.core_machine.config().challenger(); vk.vk.observe_into(&mut leaf_challenger); @@ -465,6 +470,7 @@ impl SP1Prover { shard_proofs, kinds, is_complete, + total_core_shards, }; let proof = self.compress_machine_proof( diff --git a/prover/src/verify.rs b/prover/src/verify.rs index 95865e255..3e7ef1c64 100644 --- a/prover/src/verify.rs +++ b/prover/src/verify.rs @@ -47,6 +47,8 @@ impl SP1Prover { self.core_machine .verify(&vk.vk, &machine_proof, &mut challenger)?; + let num_shards = proof.0.len(); + // Verify shard transitions. for (i, shard_proof) in proof.0.iter().enumerate() { let public_values = PublicValues::from_vec(shard_proof.public_values.clone()); @@ -124,15 +126,15 @@ impl SP1Prover { .count(); // Assert that the `MemoryInit` and `MemoryFinalize` chips only exist in the last shard. - if i != 0 && (memory_final_count > 0 || memory_init_count > 0) { + if i != num_shards - 1 && (memory_final_count > 0 || memory_init_count > 0) { return Err(MachineVerificationError::InvalidChipOccurence( - "memory init and finalize should not eixst anywhere but the last chip" + "memory init and finalize should not exist anywhere but the last chip" .to_string(), )); } - if i == 0 && (memory_init_count != 1 || memory_final_count != 1) { + if i == num_shards - 1 && (memory_init_count != 1 || memory_final_count != 1) { return Err(MachineVerificationError::InvalidChipOccurence( - "memory init and finalize should exist the last chip".to_string(), + "memory init and finalize should exist in the last chip".to_string(), )); } } diff --git a/recursion/core/src/air/public_values.rs b/recursion/core/src/air/public_values.rs index 484342f17..4f2939376 100644 --- a/recursion/core/src/air/public_values.rs +++ b/recursion/core/src/air/public_values.rs @@ -80,7 +80,7 @@ pub struct RecursionPublicValues { /// First shard being proven. pub start_shard: T, - /// Next shard that should be proven, or 0 if the program halted. + /// Next shard that should be proven, if there are more. pub next_shard: T, /// Start state of reconstruct_challenger. @@ -110,6 +110,9 @@ pub struct RecursionPublicValues { /// Whether the proof completely proves the program execution. pub is_complete: T, + /// Total number of core shards in the program execution. + pub total_core_shards: T, + /// The digest of all the previous public values elements. pub digest: [T; DIGEST_SIZE], diff --git a/recursion/program/src/hints.rs b/recursion/program/src/hints.rs index 353f760b9..e5d889e19 100644 --- a/recursion/program/src/hints.rs +++ b/recursion/program/src/hints.rs @@ -517,6 +517,7 @@ impl<'a, A: MachineAir> Hintable let initial_reconstruct_challenger = DuplexChallenger::::read(builder); let is_complete = builder.hint_var(); + let total_core_shards = builder.hint_var(); SP1RecursionMemoryLayoutVariable { vk, @@ -524,6 +525,7 @@ impl<'a, A: MachineAir> Hintable leaf_challenger, initial_reconstruct_challenger, is_complete, + total_core_shards, } } @@ -543,6 +545,7 @@ impl<'a, A: MachineAir> Hintable stream.extend(self.leaf_challenger.write()); stream.extend(self.initial_reconstruct_challenger.write()); stream.extend((self.is_complete as usize).write()); + stream.extend(self.total_core_shards.write()); stream } @@ -556,12 +559,14 @@ impl<'a, A: MachineAir> Hintable for SP1ReduceMemoryLayout<'a, Baby let shard_proofs = Vec::>::read(builder); let kinds = Vec::::read(builder); let is_complete = builder.hint_var(); + let total_core_shards = builder.hint_var(); SP1ReduceMemoryLayoutVariable { compress_vk, shard_proofs, kinds, is_complete, + total_core_shards, } } @@ -585,6 +590,7 @@ impl<'a, A: MachineAir> Hintable for SP1ReduceMemoryLayout<'a, Baby stream.extend(proof_hints.write()); stream.extend(kinds.write()); stream.extend((self.is_complete as usize).write()); + stream.extend(self.total_core_shards.write()); stream } @@ -629,6 +635,7 @@ impl<'a, A: MachineAir> Hintable let leaf_challenger = DuplexChallenger::::read(builder); let end_pc = InnerVal::read(builder); let end_shard = InnerVal::read(builder); + let total_core_shards = builder.hint_var(); SP1DeferredMemoryLayoutVariable { compress_vk, @@ -641,6 +648,7 @@ impl<'a, A: MachineAir> Hintable leaf_challenger, end_pc, end_shard, + total_core_shards, } } @@ -676,6 +684,7 @@ impl<'a, A: MachineAir> Hintable stream.extend(self.leaf_challenger.write()); stream.extend(self.end_pc.write()); stream.extend(self.end_shard.write()); + stream.extend(self.total_core_shards.write()); stream } diff --git a/recursion/program/src/machine/compress.rs b/recursion/program/src/machine/compress.rs index f8fbc857b..60a3a6458 100644 --- a/recursion/program/src/machine/compress.rs +++ b/recursion/program/src/machine/compress.rs @@ -30,7 +30,7 @@ use crate::types::ShardProofVariable; use crate::types::VerifyingKeyVariable; use crate::utils::{ assert_challenger_eq_pv, assign_challenger_from_pv, const_fri_config, - get_challenger_public_values, hash_vkey, + get_challenger_public_values, hash_vkey, var2felt, }; use super::utils::{commit_public_values, proof_data_from_vk, verify_public_values_hash}; @@ -59,6 +59,7 @@ pub struct SP1ReduceMemoryLayout<'a, SC: StarkGenericConfig, A: MachineAir>, pub is_complete: bool, pub kinds: Vec, + pub total_core_shards: usize, } #[derive(DslVariable, Clone)] @@ -67,6 +68,7 @@ pub struct SP1ReduceMemoryLayoutVariable { pub shard_proofs: Array>, pub kinds: Array>, pub is_complete: Var, + pub total_core_shards: Var, } impl SP1CompressVerifier @@ -138,7 +140,9 @@ where shard_proofs, kinds, is_complete, + total_core_shards, } = input; + let total_core_shards_felt = var2felt(builder, total_core_shards); // Initialize the values for the aggregated public output. @@ -236,6 +240,7 @@ where challenger.observe(builder, element); } // verify proof. + let one_var = builder.constant(C::N::one()); StarkVerifier::::verify_shard( builder, &vk, @@ -243,6 +248,7 @@ where machine, &mut challenger, &proof, + one_var, ); // Load the public values from the proof. @@ -370,7 +376,7 @@ where // Assert that the start pc is equal to the current pc. builder.assert_felt_eq(pc, current_public_values.start_pc); // Verfiy that the shard is equal to the current shard. - // builder.assert_felt_eq(shard, current_public_values.start_shard); + builder.assert_felt_eq(shard, current_public_values.start_shard); // Assert that the leaf challenger is always the same. assert_challenger_eq_pv( @@ -403,9 +409,15 @@ where builder.assert_felt_eq(*digest, *current_digest); } + // Assert that total_core_shards is the same. + builder.assert_felt_eq( + total_core_shards_felt, + current_public_values.total_core_shards, + ); + // Update the accumulated values. - // Update the deffered proof digest. + // Update the deferred proof digest. for (digest, current_digest) in reconstruct_deferred_digest .iter() .zip_eq(current_public_values.end_reconstruct_deferred_digest.iter()) @@ -459,6 +471,8 @@ where reduce_public_values.committed_value_digest = committed_value_digest; // Assign the cumulative sum. reduce_public_values.cumulative_sum = cumulative_sum; + // Assign the total number of shards. + reduce_public_values.total_core_shards = total_core_shards_felt; // If the proof is complete, make completeness assertions and set the flag. Otherwise, check // the flag is zero and set the public value to zero. diff --git a/recursion/program/src/machine/core.rs b/recursion/program/src/machine/core.rs index e8a547cc0..c5d0b6ee9 100644 --- a/recursion/program/src/machine/core.rs +++ b/recursion/program/src/machine/core.rs @@ -42,6 +42,7 @@ pub struct SP1RecursionMemoryLayout<'a, SC: StarkGenericConfig, A: MachineAir { pub initial_reconstruct_challenger: DuplexChallengerVariable, pub is_complete: Var, + + pub total_core_shards: Var, } impl SP1RecursiveVerifier { @@ -131,6 +134,7 @@ where leaf_challenger, initial_reconstruct_challenger, is_complete, + total_core_shards, } = input; // Initialize values we will commit to public outputs. @@ -179,6 +183,7 @@ where machine, &mut challenger, &proof, + total_core_shards, ); // Extract public values. @@ -223,10 +228,10 @@ where builder.assign(exit_code, public_values.exit_code); }); - // If the shard is zero, verify the global initial conditions hold on challenger and pc. + // If it's first shard, verify the global initial conditions hold on challenger and pc. let shard = felt2var(builder, public_values.shard); builder.if_eq(shard, C::N::one()).then(|builder| { - // This should be the first proof as well + // This should be the 0th proof in this batch. builder.assert_var_eq(i, C::N::zero()); // Start pc should be vk.pc_start @@ -333,6 +338,7 @@ where let end_deferred_digest = [zero; POSEIDON_NUM_WORDS]; let is_complete_felt = var2felt(builder, is_complete); + let total_core_shards_felt = var2felt(builder, total_core_shards); recursion_public_values.committed_value_digest = committed_value_digest; recursion_public_values.deferred_proofs_digest = deferred_proofs_digest; @@ -348,6 +354,7 @@ where recursion_public_values.start_reconstruct_deferred_digest = start_deferred_digest; recursion_public_values.end_reconstruct_deferred_digest = end_deferred_digest; recursion_public_values.is_complete = is_complete_felt; + recursion_public_values.total_core_shards = total_core_shards_felt; // If the proof represents a complete proof, make completeness assertions. // diff --git a/recursion/program/src/machine/deferred.rs b/recursion/program/src/machine/deferred.rs index a370a5b3e..1c6ac7e1b 100644 --- a/recursion/program/src/machine/deferred.rs +++ b/recursion/program/src/machine/deferred.rs @@ -54,6 +54,7 @@ where pub leaf_challenger: SC::Challenger, pub end_pc: SC::Val, pub end_shard: SC::Val, + pub total_core_shards: usize, } /// A variable version of the [SP1DeferredMemoryLayout] struct. @@ -73,6 +74,7 @@ pub struct SP1DeferredMemoryLayoutVariable { pub leaf_challenger: DuplexChallengerVariable, pub end_pc: Felt, pub end_shard: Felt, + pub total_core_shards: Var, } impl SP1DeferredVerifier @@ -129,7 +131,7 @@ where proofs, start_reconstruct_deferred_digest, is_complete, - + total_core_shards, sp1_vk, committed_value_digest, deferred_proofs_digest, @@ -189,6 +191,7 @@ where } // Verify the proof. + let one_var = builder.constant(C::N::one()); StarkVerifier::::verify_shard( builder, &compress_vk, @@ -196,6 +199,7 @@ where machine, &mut challenger, &proof, + one_var, ); // Load the public values from the proof. @@ -290,6 +294,7 @@ where // Set the is_complete flag. deferred_public_values.is_complete = var2felt(builder, is_complete); + deferred_public_values.total_core_shards = var2felt(builder, total_core_shards); commit_public_values(builder, deferred_public_values); } diff --git a/recursion/program/src/machine/mod.rs b/recursion/program/src/machine/mod.rs index 645e46b91..23235b260 100644 --- a/recursion/program/src/machine/mod.rs +++ b/recursion/program/src/machine/mod.rs @@ -91,6 +91,7 @@ mod tests { ) .unwrap(); machine.verify(&vk, &proof, &mut challenger).unwrap(); + let total_core_shards = proof.shard_proofs.len(); tracing::info!("Proof generated successfully"); let elapsed = time.elapsed(); tracing::info!("Execution proof time: {:?}", elapsed); @@ -121,6 +122,7 @@ mod tests { leaf_challenger: &leaf_challenger, initial_reconstruct_challenger: reconstruct_challenger.clone(), is_complete, + total_core_shards, }); for proof in batch.iter() { @@ -226,6 +228,7 @@ mod tests { shard_proofs: batch.to_vec(), kinds, is_complete, + total_core_shards, }; let mut runtime = Runtime::::new( diff --git a/recursion/program/src/machine/root.rs b/recursion/program/src/machine/root.rs index 8e8eb72c6..e5a9613d0 100644 --- a/recursion/program/src/machine/root.rs +++ b/recursion/program/src/machine/root.rs @@ -107,7 +107,16 @@ where challenger.observe(builder, element); } // verify proof. - StarkVerifier::::verify_shard(builder, &vk, pcs, machine, &mut challenger, proof); + let one = builder.constant(C::N::one()); + StarkVerifier::::verify_shard( + builder, + &vk, + pcs, + machine, + &mut challenger, + proof, + one, + ); // Get the public inputs from the proof. let public_values_elements = (0..RECURSIVE_PROOF_NUM_PV_ELTS) diff --git a/recursion/program/src/machine/utils.rs b/recursion/program/src/machine/utils.rs index c721dae72..514fe0833 100644 --- a/recursion/program/src/machine/utils.rs +++ b/recursion/program/src/machine/utils.rs @@ -33,10 +33,12 @@ pub(crate) fn assert_complete( deferred_proofs_digest, next_pc, start_shard, + next_shard, cumulative_sum, start_reconstruct_deferred_digest, end_reconstruct_deferred_digest, leaf_challenger, + total_core_shards, .. } = public_values; @@ -46,6 +48,9 @@ pub(crate) fn assert_complete( // Assert that the start shard is equal to 1. builder.assert_felt_eq(*start_shard, C::F::one()); + // Assert that total_core_shards is correct by ensuring it equals next_shard - 1. + builder.assert_felt_eq(*total_core_shards, *next_shard - C::F::one()); + // The challenger has been fully verified. // The start_reconstruct_challenger should be the same as an empty challenger observing the diff --git a/recursion/program/src/stark.rs b/recursion/program/src/stark.rs index c9c8e4000..4daa1f256 100644 --- a/recursion/program/src/stark.rs +++ b/recursion/program/src/stark.rs @@ -120,6 +120,7 @@ where machine: &StarkMachine, challenger: &mut DuplexChallengerVariable, proof: &ShardProofVariable, + total_shards: Var, ) where A: MachineAir + for<'a> Air>, C::F: TwoAdicField, @@ -327,7 +328,7 @@ where } if chip.name() == "MemoryInit" { - builder.if_eq(shard, C::N::one()).then_or_else( + builder.if_eq(shard, total_shards).then_or_else( |builder| { builder.assert_var_ne(index, C::N::from_canonical_usize(EMPTY)); }, @@ -338,7 +339,7 @@ where } if chip.name() == "MemoryFinalize" { - builder.if_eq(shard, C::N::one()).then_or_else( + builder.if_eq(shard, total_shards).then_or_else( |builder| { builder.assert_var_ne(index, C::N::from_canonical_usize(EMPTY)); }, diff --git a/tests/tendermint-benchmark/Cargo.lock b/tests/tendermint-benchmark/Cargo.lock index 1ebe15982..a7fff84f0 100644 --- a/tests/tendermint-benchmark/Cargo.lock +++ b/tests/tendermint-benchmark/Cargo.lock @@ -138,7 +138,7 @@ dependencies = [ [[package]] name = "curve25519-dalek-ng" version = "4.1.1" -source = "git+https://github.com/sp1-patches/curve25519-dalek-ng.git#01f43665631d2c33385708d41d0c26dbb1baa0ea" +source = "git+https://github.com/sp1-patches/curve25519-dalek-ng.git?branch=patch-v4.1.1#f5607edd61ad8e9d80c9be933cd119f4008044d9" dependencies = [ "byteorder", "digest 0.9.0", @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "ed25519-consensus" version = "2.1.0" -source = "git+https://github.com/sp1-patches/ed25519-consensus?branch=patch-v2.1.0#59f16610526726fa5c96dd77ca792f821021b66e" +source = "git+https://github.com/sp1-patches/ed25519-consensus?branch=patch-v2.1.0#4fba9b0acc9fcf7a87d00da84c340d5988e3d7cb" dependencies = [ "curve25519-dalek-ng", "hex", @@ -457,6 +457,12 @@ dependencies = [ "signature", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.153" @@ -919,6 +925,7 @@ dependencies = [ "cfg-if", "getrandom", "k256", + "lazy_static", "libm", "once_cell", "rand",