Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug fix: UltraPlonk RAM witnesses affect verification key #520

Merged
merged 1 commit into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,21 @@ void UltraHonkComposerHelper::compute_witness(CircuitConstructor& circuit_constr
proving_key->sorted_3 = s_3;
proving_key->sorted_4 = s_4;

// Copy memory read/write record data into proving key. Prover needs to know which gates contain a read/write
// 'record' witness on the 4th wire. This wire value can only be fully computed once the first 3 wire polynomials
// have been committed to. The 4th wire on these gates will be a random linear combination of the first 3 wires,
// using the plookup challenge `eta`
proving_key->memory_read_records = std::vector<uint32_t>();
proving_key->memory_write_records = std::vector<uint32_t>();
proving_key->memory_read_records.reserve(circuit_constructor.memory_read_records.size());
proving_key->memory_write_records.reserve(circuit_constructor.memory_write_records.size());
std::copy(circuit_constructor.memory_read_records.begin(),
circuit_constructor.memory_read_records.end(),
std::back_inserter(proving_key->memory_read_records));
std::copy(circuit_constructor.memory_write_records.begin(),
circuit_constructor.memory_write_records.end(),
std::back_inserter(proving_key->memory_write_records));

computed_witness = true;
}

Expand Down Expand Up @@ -279,17 +294,6 @@ std::shared_ptr<UltraHonkComposerHelper::Flavor::ProvingKey> UltraHonkComposerHe
proving_key->table_3 = poly_q_table_column_3;
proving_key->table_4 = poly_q_table_column_4;

// Copy memory read/write record data into proving key. Prover needs to know which gates contain a read/write
// 'record' witness on the 4th wire. This wire value can only be fully computed once the first 3 wire polynomials
// have been committed to. The 4th wire on these gates will be a random linear combination of the first 3 wires,
// using the plookup challenge `eta`
std::copy(circuit_constructor.memory_read_records.begin(),
circuit_constructor.memory_read_records.end(),
std::back_inserter(proving_key->memory_read_records));
std::copy(circuit_constructor.memory_write_records.begin(),
circuit_constructor.memory_write_records.end(),
std::back_inserter(proving_key->memory_write_records));

proving_key->recursive_proof_public_input_indices =
std::vector<uint32_t>(recursive_proof_public_input_indices.begin(), recursive_proof_public_input_indices.end());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,21 @@ void UltraPlonkComposerHelper::compute_witness(CircuitConstructor& circuit_const
circuit_proving_key->polynomial_store.put("s_3_lagrange", std::move(s_3));
circuit_proving_key->polynomial_store.put("s_4_lagrange", std::move(s_4));

// Copy memory read/write record data into proving key. Prover needs to know which gates contain a read/write
// 'record' witness on the 4th wire. This wire value can only be fully computed once the first 3 wire polynomials
// have been committed to. The 4th wire on these gates will be a random linear combination of the first 3 wires,
// using the plookup challenge `eta`
circuit_proving_key->memory_read_records = std::vector<uint32_t>();
circuit_proving_key->memory_write_records = std::vector<uint32_t>();
circuit_proving_key->memory_read_records.reserve(circuit_constructor.memory_read_records.size());
circuit_proving_key->memory_write_records.reserve(circuit_constructor.memory_write_records.size());
std::copy(circuit_constructor.memory_read_records.begin(),
circuit_constructor.memory_read_records.end(),
std::back_inserter(circuit_proving_key->memory_read_records));
std::copy(circuit_constructor.memory_write_records.begin(),
circuit_constructor.memory_write_records.end(),
std::back_inserter(circuit_proving_key->memory_write_records));

computed_witness = true;
}

Expand Down Expand Up @@ -453,17 +468,6 @@ std::shared_ptr<proving_key> UltraPlonkComposerHelper::compute_proving_key(Circu
circuit_proving_key->polynomial_store.put("z_lookup_fft", std::move(z_lookup_fft));
circuit_proving_key->polynomial_store.put("s_fft", std::move(s_fft));

// Copy memory read/write record data into proving key. Prover needs to know which gates contain a read/write
// 'record' witness on the 4th wire. This wire value can only be fully computed once the first 3 wire polynomials
// have been committed to. The 4th wire on these gates will be a random linear combination of the first 3 wires,
// using the plookup challenge `eta`
std::copy(circuit_constructor.memory_read_records.begin(),
circuit_constructor.memory_read_records.end(),
std::back_inserter(circuit_proving_key->memory_read_records));
std::copy(circuit_constructor.memory_write_records.begin(),
circuit_constructor.memory_write_records.end(),
std::back_inserter(circuit_proving_key->memory_write_records));

circuit_proving_key->recursive_proof_public_input_indices =
std::vector<uint32_t>(recursive_proof_public_input_indices.begin(), recursive_proof_public_input_indices.end());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2389,6 +2389,8 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_
std::sort(std::execution::par_unseq, ram_array.records.begin(), ram_array.records.end());
#endif

std::vector<RamRecord> sorted_ram_records;

// Iterate over all but final RAM record.
for (size_t i = 0; i < ram_array.records.size(); ++i) {
const RamRecord& record = ram_array.records[i];
Expand All @@ -2409,6 +2411,9 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_
.gate_index = 0,
};

// create a list of sorted ram records
sorted_ram_records.emplace_back(sorted_record);

// We don't apply the RAM consistency check gate to the final record,
// as this gate expects a RAM record to be present at the next gate
if (i < ram_array.records.size() - 1) {
Expand Down Expand Up @@ -2454,10 +2459,10 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_
// Step 2: Create gates that validate correctness of RAM timestamps

std::vector<uint32_t> timestamp_deltas;
for (size_t i = 0; i < ram_array.records.size() - 1; ++i) {
for (size_t i = 0; i < sorted_ram_records.size() - 1; ++i) {
// create_RAM_timestamp_gate(sorted_records[i], sorted_records[i + 1])
const auto& current = ram_array.records[i];
const auto& next = ram_array.records[i + 1];
const auto& current = sorted_ram_records[i];
const auto& next = sorted_ram_records[i + 1];

const bool share_index = current.index == next.index;

Expand All @@ -2483,7 +2488,7 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_

// add the index/timestamp values of the last sorted record in an empty add gate.
// (the previous gate will access the wires on this gate and requires them to be those of the last record)
const auto& last = ram_array.records[ram_array.records.size() - 1];
const auto& last = sorted_ram_records[ram_array.records.size() - 1];
create_big_add_gate({
last.index_witness,
last.timestamp_witness,
Expand Down