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

Sumcheck #18

Merged
merged 26 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from 24 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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ To re-generate contract-helper for correspondent step of Nova verification:
python src/verifier/step1/step1-data-contract-gen.py compressed-snark.json > src/verifier/step1/Step1Data.sol
python src/verifier/step2/step2-data-contract-gen.py verifier-key.json compressed-snark.json > src/verifier/step2/Step2Data.sol
python src/verifier/step3/step3-data-contract-gen.py verifier-key.json compressed-snark.json > src/verifier/step3/Step3Data.sol
python src/verifier/step4/sumcheck-data-contract-gen.py verifier-key.json compressed-snark.json > src/verifier/step4/SumcheckData.sol
```
108 changes: 108 additions & 0 deletions src/Polynomial.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.16;

import "src/verifier/step4/EqPolynomial.sol";

library PolyLib {
struct UniPoly {
uint256[] coeffs;
}

struct CompressedUniPoly {
uint256[] coeffs_except_linear_term;
}

function degree(UniPoly memory poly) public pure returns (uint256) {
return poly.coeffs.length - 1;
}

function evalAtZero(UniPoly memory poly) public pure returns (uint256) {
return poly.coeffs[0];
}

function evalAtOne(UniPoly memory poly, uint256 mod) public pure returns (uint256 result) {
for (uint256 i = 0; i < poly.coeffs.length; i++) {
// result += poly.coeffs[i];
result = addmod(result, poly.coeffs[i], mod);
}
}

function evaluate(UniPoly memory poly, uint256 r, uint256 mod) public pure returns (uint256) {
uint256 power = r;
uint256 result = poly.coeffs[0];
for (uint256 i = 1; i < poly.coeffs.length; i++) {
// result += power * poly.coeffs[i];
result = addmod(result, mulmod(power, poly.coeffs[i], mod), mod);
// power *= r;
power = mulmod(power, r, mod);
}

return result;
}

function negate(uint256 x, uint256 mod) internal pure returns (uint256) {
return mod - (x % mod);
}

function decompress(CompressedUniPoly calldata poly, uint256 hint, uint256 mod)
public
pure
returns (UniPoly memory)
{
// uint256 linear_term = hint - poly.coeffs_except_linear_term[0] - poly.coeffs_except_linear_term[0];
uint256 linear_term = addmod(
hint, negate(addmod(poly.coeffs_except_linear_term[0], poly.coeffs_except_linear_term[0], mod), mod), mod
);

for (uint256 i = 1; i < poly.coeffs_except_linear_term.length; i++) {
// linear_term -= poly.coeffs_except_linear_term[i];
linear_term = addmod(linear_term, negate(poly.coeffs_except_linear_term[i], mod), mod);
}

uint256 coeff_index = 0;
uint256[] memory coeffs = new uint256[](poly.coeffs_except_linear_term.length + 1);
coeffs[coeff_index] = poly.coeffs_except_linear_term[0];
coeff_index++;
coeffs[coeff_index] = linear_term;
coeff_index++;

for (uint256 i = 1; i < poly.coeffs_except_linear_term.length; i++) {
coeffs[coeff_index] = poly.coeffs_except_linear_term[i];
coeff_index++;
}

return UniPoly(coeffs);
}

function toUInt8Array(uint256 input) private pure returns (uint8[] memory) {
uint8[] memory result = new uint8[](32);

bytes32 input_bytes = bytes32(input);

for (uint256 i = 0; i < 32; i++) {
result[i] = uint8(input_bytes[31 - i]);
}
return result;
}

function toTranscriptBytes(UniPoly memory poly) public pure returns (uint8[] memory) {
uint8[] memory result = new uint8[](32 * (poly.coeffs.length - 1));

uint256 offset;
uint8[] memory coeff_bytes = toUInt8Array(poly.coeffs[0]);
for (uint256 i = 0; i < 32; i++) {
result[i] = coeff_bytes[i];
}
offset += 32;

for (uint256 i = 2; i < poly.coeffs.length; i++) {
coeff_bytes = toUInt8Array(poly.coeffs[i]);
for (uint256 j = 0; j < 32; j++) {
result[offset + j] = coeff_bytes[j];
}
offset += 32;
}

return result;
}
}
113 changes: 107 additions & 6 deletions src/verifier/step4/KeccakTranscript.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.16;

import "src/pasta/Vesta.sol";
import "src/pasta/Pallas.sol";
import "src/Polynomial.sol";

library ScalarFromUniformLib {
uint256 private constant SCALAR_UNIFORM_BYTE_SIZE = 64;
Expand Down Expand Up @@ -325,7 +326,7 @@ library KeccakTranscriptLib {
uint32 private constant DOM_SEP_TAG = 0x4e6f4453;
uint8 private constant KECCAK256_PREFIX_CHALLENGE_LO = 0x00;
uint8 private constant KECCAK256_PREFIX_CHALLENGE_HI = 0x01;
uint256 private constant KECCAK_TRANSCRIPT_STATE_BYTE_LEN = 64;
uint256 public constant KECCAK_TRANSCRIPT_STATE_BYTE_LEN = 64;

struct KeccakTranscript {
uint16 round;
Expand Down Expand Up @@ -393,13 +394,12 @@ library KeccakTranscriptLib {
return updatedState;
}

function absorb(KeccakTranscript memory keccak, uint8[] memory label, uint256 input)
function absorb(KeccakTranscript memory keccak, uint8[] memory label, uint8[] memory input)
public
pure
returns (KeccakTranscript memory)
{
// uint256 input will always take 32 bytes
uint8[] memory transcript = new uint8[](keccak.transcript.length + label.length + 32);
uint8[] memory transcript = new uint8[](keccak.transcript.length + label.length + input.length);
uint256 index = 0;
// TODO think how to make it more efficient (without copying current transcript)
// copy current transcript
Expand All @@ -415,14 +415,115 @@ library KeccakTranscriptLib {
index += label.length;

// append input
for (uint256 i = 0; i < 32; i++) {
transcript[index + i] = uint8(bytes1(bytes32(input)[31 - i]));
for (uint256 i = 0; i < input.length; i++) {
transcript[index + i] = input[i];
}

// TODO This should be workarounded by interacting with the blockchain, that holds the state
return KeccakTranscript(keccak.round, keccak.state, transcript);
}

function scalarToBytes(uint256 input) private pure returns (uint8[] memory) {
uint8[] memory input_bytes = new uint8[](32);

for (uint256 i = 0; i < 32; i++) {
input_bytes[i] = uint8(bytes32(input)[31 - i]);
}

return input_bytes;
}

function absorb(KeccakTranscript memory keccak, uint8[] memory label, uint256 input)
public
pure
returns (KeccakTranscript memory)
{
uint8[] memory input_bytes = scalarToBytes(input);
return absorb(keccak, label, input_bytes);
}

function absorb(KeccakTranscript memory keccak, uint8[] memory label, Pallas.PallasAffinePoint memory point)
public
pure
returns (KeccakTranscript memory)
{
uint8 is_infinity;
if (Pallas.isInfinity(point)) {
is_infinity = 0;
} else {
is_infinity = 1;
}

uint8[] memory x_bytes = scalarToBytes(point.x);
uint8[] memory y_bytes = scalarToBytes(point.y);

uint8[] memory input = new uint8[](x_bytes.length + y_bytes.length + 1);

for (uint256 i = 0; i < x_bytes.length; i++) {
input[i] = x_bytes[i];
}
for (uint256 i = 0; i < y_bytes.length; i++) {
input[x_bytes.length + i] = y_bytes[i];
}
input[x_bytes.length + y_bytes.length] = is_infinity;

return absorb(keccak, label, input);
}

function absorb(KeccakTranscript memory keccak, uint8[] memory label, Vesta.VestaAffinePoint memory point)
public
pure
returns (KeccakTranscript memory)
{
uint8 is_infinity;
if (Vesta.isInfinity(point)) {
is_infinity = 0;
} else {
is_infinity = 1;
}

uint8[] memory x_bytes = scalarToBytes(point.x);
uint8[] memory y_bytes = scalarToBytes(point.y);

uint8[] memory input = new uint8[](x_bytes.length + y_bytes.length + 1);

for (uint256 i = 0; i < x_bytes.length; i++) {
input[i] = x_bytes[i];
}
for (uint256 i = 0; i < y_bytes.length; i++) {
input[x_bytes.length + i] = y_bytes[i];
}
input[x_bytes.length + y_bytes.length] = is_infinity;

return absorb(keccak, label, input);
}

function absorb(KeccakTranscript memory keccak, uint8[] memory label, uint256[] memory inputs)
public
pure
returns (KeccakTranscript memory)
{
uint8[] memory input = new uint8[](32 * inputs.length);

for (uint256 i = 0; i < inputs.length; i++) {
uint8[] memory input_bytes = scalarToBytes(inputs[i]);

for (uint256 j = 0; j < 32; j++) {
input[32 * i + j] = input_bytes[j];
}
}

return absorb(keccak, label, input);
}

function absorb(KeccakTranscript memory keccak, uint8[] memory label, PolyLib.UniPoly memory poly)
public
pure
returns (KeccakTranscript memory)
{
return absorb(keccak, label, PolyLib.toTranscriptBytes(poly));
}

function squeeze(KeccakTranscript memory keccak, ScalarFromUniformLib.Curve curve, uint8[] memory label)
public
pure
Expand Down
Loading
Loading