Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
tamper_proof.hpp
Go to the documentation of this file.
1#pragma once
2
6
7namespace bb {
8
9enum class TamperType {
10 MODIFY_SUMCHECK_UNIVARIATE, // Tamper with coefficients of a Sumcheck Round Univariate
11 MODIFY_SUMCHECK_EVAL, // Tamper with a multilinear evaluation of an entity
12 MODIFY_Z_PERM_COMMITMENT, // Tamper with the commitment to z_perm
13 MODIFY_GEMINI_WITNESS, // Tamper with a fold polynomial
14 END
15};
16
21template <typename Flavor> size_t compute_proof_length_for_export(size_t num_public_inputs)
22{
23 size_t num_frs = Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS() + num_public_inputs;
24 if constexpr (HasIPAAccumulator<Flavor>) {
25 num_frs -= IPA_PROOF_LENGTH;
26 }
27 return num_frs;
28}
29
35template <typename InnerProver, typename InnerFlavor, typename ProofType>
36void tamper_with_proof(InnerProver& inner_prover, ProofType& inner_proof, TamperType type)
37{
38 using FF = typename InnerFlavor::FF;
39 static constexpr size_t FIRST_WITNESS_INDEX = InnerFlavor::NUM_PRECOMPUTED_ENTITIES;
40
41 // Deserialize proof into structured form
42 StructuredProof<InnerFlavor> structured_proof;
43 const auto num_public_inputs = inner_prover.prover_instance->num_public_inputs();
44 const size_t log_n =
45 InnerFlavor::USE_PADDING ? CONST_PROOF_SIZE_LOG_N : inner_prover.prover_instance->log_dyadic_size();
46 structured_proof.deserialize(inner_prover.transcript->test_get_proof_data(), num_public_inputs, log_n);
47
48 // Apply tampering based on type
49 switch (type) {
51 FF delta = FF::random_element();
52 // Preserve S_0(0) + S_0(1) = target_total_sum, but S_0(u_0) = S_1(0) + S_1(1) will fail
53 structured_proof.sumcheck_univariates[0].value_at(0) += delta;
54 structured_proof.sumcheck_univariates[0].value_at(1) -= delta;
55 break;
56 }
58 structured_proof.sumcheck_evaluations[FIRST_WITNESS_INDEX] = FF::random_element();
59 break;
61 structured_proof.z_perm_comm = structured_proof.z_perm_comm * FF::random_element();
62 break;
64 structured_proof.gemini_fold_comms[0] = structured_proof.gemini_fold_comms[0] * FF::random_element();
65 structured_proof.gemini_fold_evals[0] = FF::zero();
66 break;
67 case TamperType::END:
68 break;
69 }
70
71 // Serialize back and re-export the tampered proof
72 structured_proof.serialize(inner_prover.transcript->test_get_proof_data(), log_n);
73 inner_prover.transcript->test_set_proof_parsing_state(
74 0, compute_proof_length_for_export<InnerFlavor>(num_public_inputs));
75 inner_proof = inner_prover.export_proof();
76}
77
83template <typename InnerProver, typename InnerFlavor, typename ProofType = typename InnerFlavor::Transcript::Proof>
84void tamper_with_proof(ProofType& inner_proof, bool end_of_proof)
85{
86 using Commitment = typename InnerFlavor::Curve::AffineElement;
87 using FF = typename InnerFlavor::FF;
88 using ProofFF = typename ProofType::value_type;
89 using Codec = typename InnerFlavor::Transcript::Codec;
90
91 static constexpr size_t NUM_FRS_PER_COMMITMENT = Codec::template calc_num_fields<Commitment>();
92
93 if (end_of_proof) {
94 // Tamper with the last commitment in the proof
95 size_t offset = inner_proof.size() - NUM_FRS_PER_COMMITMENT;
96 auto element_span = std::span{ inner_proof }.subspan(offset, NUM_FRS_PER_COMMITMENT);
97 auto commitment = Codec::template deserialize_from_fields<Commitment>(element_span);
98 commitment = commitment * FF(2);
99 auto serialized = Codec::serialize_to_fields(commitment);
100 std::copy(serialized.begin(), serialized.end(), inner_proof.begin() + static_cast<std::ptrdiff_t>(offset));
101 } else {
102 // Tamper with the first pairing point (P0) by adding the generator
103 // Pairing points use a different encoding (reconstruct_from_public) than regular commitments
104 static constexpr size_t FRS_PER_POINT = Commitment::PUBLIC_INPUTS_SIZE;
105 static constexpr size_t NUM_LIMB_BITS = bb::stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION;
106
107 if (inner_proof.size() >= FRS_PER_POINT) {
108 // Deserialize P0 using the native reconstruct_from_public method
110 std::copy_n(inner_proof.begin(), FRS_PER_POINT, p0_limbs.begin());
111 Commitment P0 = Commitment::reconstruct_from_public(p0_limbs);
112
113 // Tamper: P0 + G (still on curve, but invalid for verification)
114 Commitment tampered = P0 + Commitment::one();
115
116 // Serialize back based on curve type
117 if constexpr (FRS_PER_POINT == 8) {
118 // BN254: 4 limbs per coordinate
119 constexpr uint256_t LIMB_MASK = (uint256_t(1) << NUM_LIMB_BITS) - 1;
120 uint256_t x_val = uint256_t(tampered.x);
121 uint256_t y_val = uint256_t(tampered.y);
122 for (size_t i = 0; i < 4; ++i) {
123 inner_proof[i] = ProofFF((x_val >> (i * NUM_LIMB_BITS)) & LIMB_MASK);
124 inner_proof[i + 4] = ProofFF((y_val >> (i * NUM_LIMB_BITS)) & LIMB_MASK);
125 }
126 } else if constexpr (FRS_PER_POINT == 2) {
127 // Grumpkin: 1 field element per coordinate
128 inner_proof[0] = ProofFF(tampered.x);
129 inner_proof[1] = ProofFF(tampered.y);
130 } else {
131 static_assert(FRS_PER_POINT == 8 || FRS_PER_POINT == 2,
132 "Unsupported curve: FRS_PER_POINT must be 8 (BN254) or 2 (Grumpkin)");
133 }
134 }
135 }
136}
137
138} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:22
static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS
ssize_t offset
Definition engine.cpp:36
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
@ MODIFY_SUMCHECK_UNIVARIATE
size_t compute_proof_length_for_export(size_t num_public_inputs)
Compute the proof length for re-exporting after tampering.
void tamper_with_proof(InnerProver &inner_prover, ProofType &inner_proof, TamperType type)
Test method that provides several ways to tamper with a proof. TODO(https://github....
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Test utility for deserializing/serializing proof data into typed structures.
static field random_element(numeric::RNG *engine=nullptr) noexcept