Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up
Find file
Copy path
Fetching contributors…
| from permuted_tree import merkelize, mk_branch, verify_branch, mk_multi_branch, verify_multi_branch | |
| from utils import get_power_cycle, get_pseudorandom_indices | |
| from poly_utils import PrimeField | |
| # Generate an FRI proof that the polynomial that has the specified | |
| # values at successive powers of the specified root of unity has a | |
| # degree lower than maxdeg_plus_1 | |
| # | |
| # We use maxdeg+1 instead of maxdeg because it's more mathematically | |
| # convenient in this case. | |
| def prove_low_degree(values, root_of_unity, maxdeg_plus_1, modulus, exclude_multiples_of=0): | |
| f = PrimeField(modulus) | |
| print('Proving %d values are degree <= %d' % (len(values), maxdeg_plus_1)) | |
| # If the degree we are checking for is less than or equal to 32, | |
| # use the polynomial directly as a proof | |
| if maxdeg_plus_1 <= 16: | |
| print('Produced FRI proof') | |
| return [[x.to_bytes(32, 'big') for x in values]] | |
| # Calculate the set of x coordinates | |
| xs = get_power_cycle(root_of_unity, modulus) | |
| assert len(values) == len(xs) | |
| # Put the values into a Merkle tree. This is the root that the | |
| # proof will be checked against | |
| m = merkelize(values) | |
| # Select a pseudo-random x coordinate | |
| special_x = int.from_bytes(m[1], 'big') % modulus | |
| # Calculate the "column" at that x coordinate | |
| # (see https://vitalik.ca/general/2017/11/22/starks_part_2.html) | |
| # We calculate the column by Lagrange-interpolating each row, and not | |
| # directly from the polynomial, as this is more efficient | |
| quarter_len = len(xs)//4 | |
| x_polys = f.multi_interp_4( | |
| [[xs[i+quarter_len*j] for j in range(4)] for i in range(quarter_len)], | |
| [[values[i+quarter_len*j] for j in range(4)] for i in range(quarter_len)] | |
| ) | |
| column = [f.eval_quartic(p, special_x) for p in x_polys] | |
| m2 = merkelize(column) | |
| # Pseudo-randomly select y indices to sample | |
| ys = get_pseudorandom_indices(m2[1], len(column), 40, exclude_multiples_of=exclude_multiples_of) | |
| # Compute the positions for the values in the polynomial | |
| poly_positions = sum([[y + (len(xs) // 4) * j for j in range(4)] for y in ys], []) | |
| # This component of the proof, including Merkle branches | |
| o = [m2[1], mk_multi_branch(m2, ys), mk_multi_branch(m, poly_positions)] | |
| # Recurse... | |
| return [o] + prove_low_degree(column, f.exp(root_of_unity, 4), | |
| maxdeg_plus_1 // 4, modulus, exclude_multiples_of=exclude_multiples_of) | |
| # Verify an FRI proof | |
| def verify_low_degree_proof(merkle_root, root_of_unity, proof, maxdeg_plus_1, modulus, exclude_multiples_of=0): | |
| f = PrimeField(modulus) | |
| # Calculate which root of unity we're working with | |
| testval = root_of_unity | |
| roudeg = 1 | |
| while testval != 1: | |
| roudeg *= 2 | |
| testval = (testval * testval) % modulus | |
| # Powers of the given root of unity 1, p, p**2, p**3 such that p**4 = 1 | |
| quartic_roots_of_unity = [1, | |
| f.exp(root_of_unity, roudeg // 4), | |
| f.exp(root_of_unity, roudeg // 2), | |
| f.exp(root_of_unity, roudeg * 3 // 4)] | |
| # Verify the recursive components of the proof | |
| for prf in proof[:-1]: | |
| root2, column_branches, poly_branches = prf | |
| print('Verifying degree <= %d' % maxdeg_plus_1) | |
| # Calculate the pseudo-random x coordinate | |
| special_x = int.from_bytes(merkle_root, 'big') % modulus | |
| # Calculate the pseudo-randomly sampled y indices | |
| ys = get_pseudorandom_indices(root2, roudeg // 4, 40, | |
| exclude_multiples_of=exclude_multiples_of) | |
| # Compute the positions for the values in the polynomial | |
| poly_positions = sum([[y + (roudeg // 4) * j for j in range(4)] for y in ys], []) | |
| # Verify Merkle branches | |
| column_values = verify_multi_branch(root2, ys, column_branches) | |
| poly_values = verify_multi_branch(merkle_root, poly_positions, poly_branches) | |
| # For each y coordinate, get the x coordinates on the row, the values on | |
| # the row, and the value at that y from the column | |
| xcoords = [] | |
| rows = [] | |
| columnvals = [] | |
| for i, y in enumerate(ys): | |
| # The x coordinates from the polynomial | |
| x1 = f.exp(root_of_unity, y) | |
| xcoords.append([(quartic_roots_of_unity[j] * x1) % modulus for j in range(4)]) | |
| # The values from the original polynomial | |
| row = [int.from_bytes(x, 'big') for x in poly_values[i*4: i*4+4]] | |
| rows.append(row) | |
| columnvals.append(int.from_bytes(column_values[i], 'big')) | |
| # Verify for each selected y coordinate that the four points from the | |
| # polynomial and the one point from the column that are on that y | |
| # coordinate are on the same deg < 4 polynomial | |
| polys = f.multi_interp_4(xcoords, rows) | |
| for p, c in zip(polys, columnvals): | |
| assert f.eval_quartic(p, special_x) == c | |
| # Update constants to check the next proof | |
| merkle_root = root2 | |
| root_of_unity = f.exp(root_of_unity, 4) | |
| maxdeg_plus_1 //= 4 | |
| roudeg //= 4 | |
| # Verify the direct components of the proof | |
| data = [int.from_bytes(x, 'big') for x in proof[-1]] | |
| print('Verifying degree <= %d' % maxdeg_plus_1) | |
| assert maxdeg_plus_1 <= 16 | |
| # Check the Merkle root matches up | |
| mtree = merkelize(data) | |
| assert mtree[1] == merkle_root | |
| # Check the degree of the data | |
| powers = get_power_cycle(root_of_unity, modulus) | |
| if exclude_multiples_of: | |
| pts = [x for x in range(len(data)) if x % exclude_multiples_of] | |
| else: | |
| pts = range(len(data)) | |
| poly = f.lagrange_interp([powers[x] for x in pts[:maxdeg_plus_1]], | |
| [data[x] for x in pts[:maxdeg_plus_1]]) | |
| for x in pts[maxdeg_plus_1:]: | |
| assert f.eval_poly_at(poly, powers[x]) == data[x] | |
| print('FRI proof verified') | |
| return True |