Skip to content

Commit b4530d5

Browse files
authored
feat: graffiti features (succinctlabs#212)
1 parent d27860b commit b4530d5

File tree

14 files changed

+543
-41
lines changed

14 files changed

+543
-41
lines changed

Diff for: Cargo.lock

-21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: plonky2x/core/Cargo.toml

+1-6
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ num = { version = "0.4", default-features = false }
2121
sha2 = "0.10.7"
2222
curve25519-dalek = { git = "https://github.com/succinctlabs/curve25519-dalek.git", branch = "feature/edwards-point-getters" }
2323
ff = { package = "ff", version = "0.13", features = ["derive"] }
24-
2524
ethers = { version = "2.0" }
26-
2725
hex = "0.4.3"
2826
log = { version = "0.4.14", default-features = false }
2927
rand = { version = "0.8.4", package = "rand" }
@@ -47,14 +45,11 @@ serde_with = "3.3.0"
4745
bincode = "1.3.3"
4846
uuid = { version = "1.4.1", features = ["serde"] }
4947
serde_plain = "1.0.2"
50-
jemallocator = "0.5.0"
5148
ed25519-consensus = "2.1.0"
5249
async-trait = "0.1.73"
5350
digest = "0.10.7"
5451
sha256 = "1.4.0"
5552

5653
[dev-dependencies]
57-
plonky2 = { git = "https://github.com/mir-protocol/plonky2.git", features = [
58-
"gate_testing",
59-
] }
54+
plonky2 = { git = "https://github.com/mir-protocol/plonky2.git", features = ["gate_testing"] }
6055
env_logger = "0.10.0"

Diff for: plonky2x/core/src/backend/circuit/serialization/hints.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,16 @@ use crate::frontend::curta::hash::sha::sha256::hint::Sha256ProofHint;
4949
use crate::frontend::ecc::ed25519::field::ed25519_base::Ed25519Base;
5050
use crate::frontend::eth::beacon::generators::{
5151
BeaconAllWithdrawalsHint, BeaconBalanceBatchWitnessHint, BeaconBalanceGenerator,
52-
BeaconBalanceWitnessHint, BeaconBalancesGenerator, BeaconExecutionPayloadHint,
53-
BeaconHeaderHint, BeaconHistoricalBlockGenerator, BeaconPartialBalancesHint,
52+
BeaconBalanceWitnessHint, BeaconBalancesGenerator, BeaconBlockRootsHint,
53+
BeaconExecutionPayloadHint, BeaconGraffitiHint, BeaconHeaderHint,
54+
BeaconHeadersFromOffsetRangeHint, BeaconHistoricalBlockGenerator, BeaconPartialBalancesHint,
5455
BeaconPartialValidatorsHint, BeaconValidatorBatchHint, BeaconValidatorGenerator,
5556
BeaconValidatorsGenerator, BeaconValidatorsHint, BeaconWithdrawalGenerator,
5657
BeaconWithdrawalsGenerator, CompressedBeaconValidatorBatchHint, Eth1BlockToSlotHint,
5758
};
5859
use crate::frontend::eth::beacon::vars::{
59-
BeaconBalancesVariable, BeaconValidatorVariable, BeaconValidatorsVariable,
60-
BeaconWithdrawalVariable, BeaconWithdrawalsVariable,
60+
BeaconBalancesVariable, BeaconHeaderVariable, BeaconValidatorVariable,
61+
BeaconValidatorsVariable, BeaconWithdrawalVariable, BeaconWithdrawalsVariable,
6162
};
6263
use crate::frontend::eth::mpt::generators::LteGenerator;
6364
use crate::frontend::eth::storage::generators::{
@@ -84,7 +85,7 @@ use crate::frontend::num::u32::gates::range_check_u32::U32RangeCheckGenerator;
8485
use crate::frontend::num::u32::gates::subtraction_u32::U32SubtractionGenerator;
8586
use crate::frontend::uint::uint64::U64Variable;
8687
use crate::frontend::vars::{Bytes32Variable, SubArrayExtractorHint, U256Variable};
87-
use crate::prelude::{BoolVariable, U32Variable, Variable};
88+
use crate::prelude::{ArrayVariable, BoolVariable, U32Variable, Variable};
8889

8990
pub trait HintSerializer<L: PlonkParameters<D>, const D: usize>:
9091
WitnessGeneratorSerializer<L::Field, D>
@@ -463,6 +464,12 @@ where
463464

464465
r.register_hint::<SubArrayExtractorHint>();
465466

467+
r.register_hint::<BeaconBlockRootsHint>();
468+
469+
r.register_hint::<BeaconGraffitiHint>();
470+
471+
register_powers_of_two!(r, BeaconHeadersFromOffsetRangeHint);
472+
466473
register_watch_generator!(
467474
r,
468475
L,
@@ -477,7 +484,9 @@ where
477484
BeaconBalancesVariable,
478485
BeaconWithdrawalsVariable,
479486
BeaconWithdrawalVariable,
480-
BeaconValidatorVariable
487+
BeaconValidatorVariable,
488+
BeaconHeaderVariable,
489+
ArrayVariable<Bytes32Variable, 8192>
481490
);
482491

483492
r

Diff for: plonky2x/core/src/frontend/builder/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod boolean;
22
pub mod io;
3+
pub mod permutation;
34
mod proof;
45
pub mod watch;
56

Diff for: plonky2x/core/src/frontend/builder/permutation.rs

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
2+
use serde::{Deserialize, Serialize};
3+
4+
use super::CircuitBuilder;
5+
use crate::frontend::hint::simple::hint::Hint;
6+
use crate::frontend::uint::uint32::U32Variable;
7+
use crate::frontend::vars::{EvmVariable, ValueStream, VariableStream};
8+
use crate::prelude::{ArrayVariable, PlonkParameters, Variable};
9+
use crate::utils::hash::sha256;
10+
11+
#[derive(Debug, Clone, Serialize, Deserialize)]
12+
struct RandomPermutationHint<const B: usize>;
13+
14+
impl<L: PlonkParameters<D>, const D: usize, const B: usize> Hint<L, D>
15+
for RandomPermutationHint<B>
16+
{
17+
fn hint(&self, input_stream: &mut ValueStream<L, D>, output_stream: &mut ValueStream<L, D>) {
18+
let inputs = input_stream.read_value::<ArrayVariable<U32Variable, B>>();
19+
let dummy = input_stream.read_value::<U32Variable>();
20+
let nonce = input_stream.read_value::<U32Variable>();
21+
22+
let mut filtered_inputs = Vec::new();
23+
for i in 0..inputs.len() {
24+
if inputs[i] != dummy {
25+
filtered_inputs.push(inputs[i]);
26+
}
27+
}
28+
29+
filtered_inputs.sort_by_key(|x| {
30+
let mut bytes = Vec::new();
31+
bytes.extend(x.to_be_bytes());
32+
bytes.extend(nonce.to_be_bytes());
33+
u32::from_be_bytes(sha256(&bytes)[0..4].try_into().unwrap())
34+
});
35+
filtered_inputs.resize(B, dummy);
36+
37+
output_stream.write_value::<ArrayVariable<U32Variable, B>>(filtered_inputs);
38+
}
39+
}
40+
41+
impl<L: PlonkParameters<D>, const D: usize> CircuitBuilder<L, D> {
42+
pub fn permute_with_dummy<const B: usize>(
43+
&mut self,
44+
inputs: ArrayVariable<U32Variable, B>,
45+
dummy: U32Variable,
46+
gamma: Variable,
47+
nonce: U32Variable,
48+
) -> ArrayVariable<U32Variable, B>
49+
where
50+
<<L as PlonkParameters<D>>::Config as GenericConfig<D>>::Hasher:
51+
AlgebraicHasher<<L as PlonkParameters<D>>::Field>,
52+
{
53+
// Compute the filtered accumulator.
54+
let mut filtered_acc = self.one::<Variable>();
55+
for i in 0..inputs.len() {
56+
let is_dummy = self.is_equal(inputs[i], dummy);
57+
let term = self.sub(gamma, inputs[i].0);
58+
let acc = self.mul(filtered_acc, term);
59+
filtered_acc = self.select(is_dummy, filtered_acc, acc);
60+
}
61+
62+
// Get the permuted inputs.
63+
let mut input_stream = VariableStream::new();
64+
input_stream.write(&inputs);
65+
input_stream.write(&dummy);
66+
input_stream.write(&nonce);
67+
let output_stream = self.hint(input_stream, RandomPermutationHint::<B> {});
68+
let permuted_inputs = output_stream.read::<ArrayVariable<U32Variable, B>>(self);
69+
70+
// Compute the permtued filtered accumulator.
71+
let mut permuted_filtered_acc = self.one::<Variable>();
72+
for i in 0..inputs.len() {
73+
let is_dummy = self.is_equal(permuted_inputs[i], dummy);
74+
let term = self.sub(gamma, permuted_inputs[i].0);
75+
let acc = self.mul(permuted_filtered_acc, term);
76+
permuted_filtered_acc = self.select(is_dummy, permuted_filtered_acc, acc);
77+
}
78+
79+
// Assert that the permuted filtered accumulator is the same as the filtered accumulator.
80+
self.assert_is_equal(permuted_filtered_acc, filtered_acc);
81+
82+
// Check the metric ordering.
83+
let mut metrics = Vec::new();
84+
for i in 0..permuted_inputs.len() {
85+
let mut bytes = Vec::new();
86+
bytes.extend(permuted_inputs[i].encode(self));
87+
bytes.extend(nonce.encode(self));
88+
let h = self.curta_sha256(&bytes);
89+
let metric = U32Variable::decode(self, &h.0[0..4]);
90+
metrics.push(metric);
91+
}
92+
93+
let t = self._true();
94+
let f = self._false();
95+
let mut seen_dummy = self._false();
96+
for i in 0..metrics.len() - 1 {
97+
// If the next is dummy and we've seen one, panic.
98+
let next_is_dummy = self.is_equal(permuted_inputs[i + 1], dummy);
99+
let not_next_is_dummy = self.not(next_is_dummy);
100+
let seen_dummy_and_not_next_is_dummy = self.and(seen_dummy, not_next_is_dummy);
101+
self.assert_is_equal(seen_dummy_and_not_next_is_dummy, f);
102+
103+
// The next metric should be less than or equal to or the next is valid.
104+
let lte = self.lte(metrics[i], metrics[i + 1]);
105+
let valid = self.or(lte, next_is_dummy);
106+
self.assert_is_equal(valid, t);
107+
108+
// If the next thing is a dummy, we've seen a dummy.
109+
seen_dummy = self.select(next_is_dummy, t, seen_dummy);
110+
}
111+
112+
permuted_inputs
113+
}
114+
}
115+
116+
#[cfg(test)]
117+
pub(crate) mod tests {
118+
119+
use plonky2::field::types::Field;
120+
121+
use crate::frontend::uint::uint32::U32Variable;
122+
use crate::prelude::*;
123+
use crate::utils;
124+
125+
#[test]
126+
fn test_simple_circuit_with_field_io() {
127+
utils::setup_logger();
128+
let mut builder = DefaultBuilder::new();
129+
130+
let inputs = builder.constant::<ArrayVariable<U32Variable, 5>>(vec![0, 1, 2, 3, 4]);
131+
let dummy = builder.constant::<U32Variable>(0);
132+
let gamma = builder.constant::<Variable>(GoldilocksField::from_canonical_u64(3));
133+
let nonce = builder.constant::<U32Variable>(1);
134+
135+
let permuted_inputs = builder.permute_with_dummy(inputs, dummy, gamma, nonce);
136+
for i in 0..permuted_inputs.len() {
137+
builder.watch(
138+
&permuted_inputs[i],
139+
format!("permuted_inputs[{}]", i).as_str(),
140+
);
141+
}
142+
143+
let circuit = builder.build();
144+
145+
let input = circuit.input();
146+
let (proof, output) = circuit.prove(&input);
147+
circuit.verify(&proof, &input, &output);
148+
}
149+
}

0 commit comments

Comments
 (0)