Skip to content

Commit

Permalink
Compress y. (#111)
Browse files Browse the repository at this point in the history
* Initial commit compress y.

* Fix VerifyWesoSegment arguments.

* One more fix.

* Move result outside GIL scope.
  • Loading branch information
fchirica committed May 9, 2022
1 parent 54ed20f commit 5478032
Show file tree
Hide file tree
Showing 3 changed files with 248 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/python_bindings/fastvdf.cpp
Expand Up @@ -65,4 +65,35 @@ PYBIND11_MODULE(chiavdf, m) {
py::bytes ret = py::bytes(reinterpret_cast<char*>(result.data()), result.size());
return ret;
});

// Checks an N wesolowski proof, given y is given by 'GetB()' instead of a form.
m.def("verify_n_wesolowski_with_b", [] (const string& discriminant,
const string& B,
const string& x_s,
const string& proof_blob,
const uint64_t num_iterations, const uint64_t recursion) {
std::pair<bool, std::vector<uint8_t>> result;
{
py::gil_scoped_release release;
std::string proof_blob_str(proof_blob);
uint8_t *proof_blob_ptr = reinterpret_cast<uint8_t *>(proof_blob_str.data());
int proof_blob_size = proof_blob.size();
result = CheckProofOfTimeNWesolowskiWithB(integer(discriminant), integer(B), (const uint8_t *)x_s.data(), proof_blob_ptr, proof_blob_size, num_iterations, recursion);
}
py::bytes res_bytes = py::bytes(reinterpret_cast<char*>(result.second.data()), result.second.size());
py::tuple res_tuple = py::make_tuple(result.first, res_bytes);
return res_tuple;
});

m.def("get_b_from_n_wesolowski", [] (const string& discriminant,
const string& x_s,
const string& proof_blob,
const uint64_t num_iterations, const uint64_t recursion) {
py::gil_scoped_release release;
std::string proof_blob_str(proof_blob);
uint8_t *proof_blob_ptr = reinterpret_cast<uint8_t *>(proof_blob_str.data());
int proof_blob_size = proof_blob.size();
integer B = GetBFromProof(integer(discriminant), (const uint8_t *)x_s.data(), proof_blob_ptr, proof_blob_size, num_iterations, recursion);
return B.to_string();
});
}
69 changes: 69 additions & 0 deletions src/verifier.h
Expand Up @@ -76,4 +76,73 @@ bool CheckProofOfTimeNWesolowski(integer D, const uint8_t* x_s, const uint8_t* p
return is_valid;
}

bool CheckProofOfTimeNWesolowskiCommon(integer& D, form& x, const uint8_t* proof_blob, int32_t proof_blob_len, uint64_t& iterations, int last_segment, bool skip_check = false) {
int form_size = BQFC_FORM_SIZE;
int segment_len = 8 + B_bytes + form_size;
int i = proof_blob_len - segment_len;
PulmarkReducer reducer;

for (; i >= last_segment; i -= segment_len) {
uint64_t segment_iters = BytesToInt64(&proof_blob[i]);
form proof = DeserializeForm(D, &proof_blob[i + 8 + B_bytes], form_size);
integer B(&proof_blob[i + 8], B_bytes);
form xnew;
if (!skip_check) {
if (VerifyWesoSegment(D, x, proof, B, segment_iters, xnew))
return false;
} else {
integer L = root(-D, 4);
integer r = FastPow(2, segment_iters, B);
form f1 = FastPowFormNucomp(proof, D, B, L, reducer);
form f2 = FastPowFormNucomp(x, D, r, L, reducer);
xnew = f1 * f2;
}

x = xnew;
if (segment_iters > iterations) {
return false;
}
iterations -= segment_iters;
}
return true;
}

std::pair<bool, std::vector<uint8_t>> CheckProofOfTimeNWesolowskiWithB(integer D, integer B, const uint8_t* x_s, const uint8_t* proof_blob, int32_t proof_blob_len, uint64_t iterations, int32_t depth) {
int form_size = BQFC_FORM_SIZE;
int segment_len = 8 + B_bytes + form_size;
form x = DeserializeForm(D, x_s, form_size);
std::vector<uint8_t> result;
if (proof_blob_len != form_size + depth * segment_len) {
return {false, result};
}
bool is_valid = CheckProofOfTimeNWesolowskiCommon(D, x, proof_blob, proof_blob_len, iterations, form_size);
if (is_valid == false) {
return {false, result};
}
form proof = DeserializeForm(D, proof_blob, form_size);
form y_result;
if (VerifyWesoSegment(D, x, proof, B, iterations, y_result) == -1) {
return {false, result};
}
int d_bits = D.num_bits();
result = SerializeForm(y_result, d_bits);
return {true, result};
}

// TODO: Perhaps move?
integer GetBFromProof(integer D, const uint8_t* x_s, const uint8_t* proof_blob, int32_t proof_blob_len, uint64_t iterations, int32_t depth) {
int form_size = BQFC_FORM_SIZE;
int segment_len = 8 + B_bytes + form_size;
form x = DeserializeForm(D, x_s, form_size);
if (proof_blob_len != 2 * form_size + depth * segment_len) {
throw std::runtime_error("Invalid proof.");
}
bool is_valid = CheckProofOfTimeNWesolowskiCommon(D, x, proof_blob, proof_blob_len, iterations, 2 * form_size, true);
if (is_valid == false) {
throw std::runtime_error("Invalid proof.");
}
form y = DeserializeForm(D, proof_blob, form_size);
return GetB(D, x, y);
}

#endif // VERIFIER_H
148 changes: 148 additions & 0 deletions tests/test_n_weso_verifier.py
@@ -0,0 +1,148 @@
import secrets

from chiavdf import (
create_discriminant,
prove,
verify_wesolowski,
verify_n_wesolowski,
verify_n_wesolowski_with_b,
get_b_from_n_wesolowski,
)


def prove_n_weso(discriminant_challenge, x, discriminant_size, form_size, iters, witness, wrong_segm):
iters_chunk = iters // (witness + 1)
partials = []
discriminant = create_discriminant(discriminant_challenge, discriminant_size)
for _ in range(witness):
result = prove(discriminant_challenge, x, discriminant_size, iters_chunk)
y = result[:form_size]
proof = result[form_size : 2 * form_size]
partials.append((x, y, proof))
x = y
iters -= iters_chunk * witness
result = prove(discriminant_challenge, x, discriminant_size, iters)
y_result = result[:form_size]
y_proof = result[form_size : 2 * form_size]
assert verify_wesolowski(discriminant, x, y_result, y_proof, iters)
b_hex = get_b_from_n_wesolowski(discriminant, x, y_result + y_proof, iters, 0)
is_valid, y_from_compression = verify_n_wesolowski_with_b(
discriminant,
b_hex,
x,
y_proof,
iters,
0,
)
assert is_valid
assert y_from_compression == y_result
inner_proof = b""
for x, y, proof in reversed(partials):
b_hex = get_b_from_n_wesolowski(discriminant, x, y + proof, iters_chunk, 0)
b = int(b_hex, 16)
assert verify_wesolowski(discriminant, x, y, proof, iters_chunk)
is_valid, y_from_compression = verify_n_wesolowski_with_b(
discriminant,
b_hex,
x,
proof,
iters_chunk,
0,
)
assert is_valid
assert y == y_from_compression
if not wrong_segm:
inner_proof += iters_chunk.to_bytes(8, byteorder='big')
else:
iters_wrong = iters_chunk + 1
inner_proof += iters_wrong.to_bytes(8, byteorder='big')
wrong_segm = False
inner_proof += b.to_bytes(33, byteorder='big')
inner_proof += proof
return y_result, y_proof + inner_proof


def test_prove_n_weso_and_verify():
discriminant_challenge = secrets.token_bytes(10)
discriminant_size = 512
discriminant = create_discriminant(discriminant_challenge, discriminant_size)
form_size = 100
initial_el = b"\x08" + (b"\x00" * 99)

for iters in [1000000, 5000000, 10000000]:
y, proof = prove_n_weso(discriminant_challenge, initial_el, discriminant_size, form_size, iters, 5, False)
is_valid = verify_n_wesolowski(
str(discriminant),
initial_el,
y + proof,
iters,
discriminant_size,
5,
)
assert is_valid
is_valid = verify_n_wesolowski(
str(discriminant),
initial_el,
y + proof,
iters + 1,
discriminant_size,
5,
)
assert not is_valid
y, proof_wrong = prove_n_weso(discriminant_challenge, initial_el, discriminant_size, form_size, iters, 10, True)
is_valid = verify_n_wesolowski(
str(discriminant),
initial_el,
y + proof_wrong,
iters,
discriminant_size,
10,
)
assert not is_valid
b_hex = get_b_from_n_wesolowski(discriminant, initial_el, y + proof, iters, 5)
is_valid, y_from_compression = verify_n_wesolowski_with_b(
discriminant,
b_hex,
initial_el,
proof,
iters,
5,
)
assert is_valid
assert y_from_compression == y
B = str(int(b_hex, 16))
is_valid, y_from_compression = verify_n_wesolowski_with_b(
discriminant,
B,
initial_el,
proof,
iters,
5,
)
assert is_valid
assert y_from_compression == y
B_wrong = str(int(b_hex, 16) + 1)
is_valid, y_from_compression = verify_n_wesolowski_with_b(
discriminant,
B_wrong,
initial_el,
proof,
iters,
5,
)
assert not is_valid
assert y_from_compression == b""
is_valid, y_from_compression = verify_n_wesolowski_with_b(
discriminant,
B,
initial_el,
proof_wrong,
iters,
10,
)
assert not is_valid
assert y_from_compression == b""
initial_el = y


test_prove_n_weso_and_verify()

0 comments on commit 5478032

Please sign in to comment.