Skip to content

Commit

Permalink
Solidity verifier sponge (#83)
Browse files Browse the repository at this point in the history
* Refactor into bn254 dir

* Added fields operations

* Added sponges

* Started poseidon hash, added sbox and mds

* Added round

* Finished poseidon

* Finished base sponge

* Replace poseidon with keccak sponge

* Added sponge in fiat-shamir algorithm

* Fix sponge

---------

Co-authored-by: Pablo Deymonnaz <[email protected]>
  • Loading branch information
xqft and pablodeymo authored Nov 17, 2023
1 parent e6f6fe1 commit df08387
Show file tree
Hide file tree
Showing 16 changed files with 208 additions and 44 deletions.
2 changes: 1 addition & 1 deletion eth_verifier/lib/Alphas.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

import "./Fields.sol";
import "./bn254/Fields.sol";

using {Scalar.mul} for Scalar.FE;

Expand Down
4 changes: 2 additions & 2 deletions eth_verifier/lib/Commitment.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

import "./BN254.sol";
import "./Fields.sol";
import "./bn254/BN254.sol";
import "./bn254/Fields.sol";
import "./Utils.sol";

using { BN254.add, BN254.scale_scalar } for BN254.G1Point;
Expand Down
2 changes: 1 addition & 1 deletion eth_verifier/lib/Evaluations.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

import "./Fields.sol";
import "./bn254/Fields.sol";

struct PointEvaluations {
/// evaluation at the challenge point zeta
Expand Down
58 changes: 39 additions & 19 deletions eth_verifier/lib/Oracles.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

import "./Fields.sol";
import "./bn254/Fields.sol";
import "./VerifierIndex.sol";
import "./Evaluations.sol";
import "./Alphas.sol";
import "./sponge/Sponge.sol";
import "./Commitment.sol";

library Oracles {
using {to_field_with_length, to_field} for ScalarChallenge;
Expand All @@ -16,27 +18,57 @@ library Oracles {
Scalar.pow
} for Scalar.FE;
using {AlphasLib.instantiate} for Alphas;
using {
KeccakSponge.reinit,
KeccakSponge.absorb_base,
KeccakSponge.absorb_scalar,
KeccakSponge.absorb_commitment,
KeccakSponge.challenge_base,
KeccakSponge.challenge_scalar,
KeccakSponge.digest_base,
KeccakSponge.digest_scalar
} for Sponge;

uint64 internal constant CHALLENGE_LENGTH_IN_LIMBS = 2;

function fiat_shamir(VerifierIndex storage index) public {
// WARN: We'll skip the use of a sponge and generate challenges from pseudo-random numbers
function fiat_shamir(
VerifierIndex storage index,
PolyComm memory public_comm,
Sponge storage base_sponge,
Sponge storage scalar_sponge
) public {
Scalar.FE endo_coeff = Scalar.from(0); // FIXME: not zero

base_sponge.reinit();

base_sponge.absorb_base(verifier_digest(index));
base_sponge.absorb_commitment(public_comm);

// TODO: absorb the commitments to the registers / witness columns
// TODO: lookups

// Sample beta and gamma from the sponge
Scalar.FE beta = challenge();
Scalar.FE gamma = challenge();
Scalar.FE beta = base_sponge.challenge_scalar();
Scalar.FE gamma = base_sponge.challenge_scalar();

// Sample alpha prime
ScalarChallenge memory alpha_chal = scalar_chal();
ScalarChallenge memory alpha_chal = ScalarChallenge(base_sponge.challenge_scalar());
// Derive alpha using the endomorphism
Scalar.FE alpha = alpha_chal.to_field(endo_coeff);

// TODO: enforce length of the $t$ commitment

// TODO: absorb commitment to the quotient poly

// Sample alpha prime
ScalarChallenge memory zeta_chal = scalar_chal();
ScalarChallenge memory zeta_chal = ScalarChallenge(base_sponge.challenge_scalar());
// Derive alpha using the endomorphism
Scalar.FE zeta = zeta_chal.to_field(endo_coeff);

scalar_sponge.reinit();
scalar_sponge.absorb_scalar(base_sponge.digest_scalar());


// often used values
Scalar.FE zeta1 = zeta.pow(index.domain_size);
Scalar.FE zetaw = zeta.mul(index.domain_gen);
Expand Down Expand Up @@ -71,18 +103,6 @@ library Oracles {
// combined inner prod
}

/// @notice creates a challenge frm hashing the current block timestamp.
/// @notice this function is only going to be used for the demo and never in
/// @notice a serious environment. DO NOT use this in any other case.
function challenge() internal view returns (Scalar.FE) {
Scalar.from(uint256(keccak256(abi.encode(block.timestamp))));
}

/// @notice creates a `ScaharChallenge` using `challenge()`.
function scalar_chal() internal view returns (ScalarChallenge memory) {
return ScalarChallenge(challenge());
}

struct ScalarChallenge {
Scalar.FE chal;
}
Expand Down
4 changes: 2 additions & 2 deletions eth_verifier/lib/Utils.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

import "./BN254.sol";
import "./Fields.sol";
import "./bn254/BN254.sol";
import "./bn254/Fields.sol";
import "./UtilsExternal.sol";
import "forge-std/console.sol";

Expand Down
9 changes: 7 additions & 2 deletions eth_verifier/lib/VerifierIndex.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

import {BN254} from "./BN254.sol";
import {BN254} from "./bn254/BN254.sol";
import {URS} from "./Commitment.sol";
import "./Fields.sol";
import "./bn254/Fields.sol";
import "./Alphas.sol";
import "./Evaluations.sol";

Expand All @@ -15,3 +15,8 @@ struct VerifierIndex {
Scalar.FE domain_gen;
Alphas powers_of_alpha;
}

function verifier_digest(VerifierIndex storage index) returns (Base.FE) {
// FIXME: todo!
return Base.from(42);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

pragma solidity ^0.8.0;

import "./UtilsExternal.sol";
import "../UtilsExternal.sol";
import "./Fields.sol";

/// @notice Barreto-Naehrig curve over a 254 bit prime field
Expand Down
44 changes: 40 additions & 4 deletions eth_verifier/lib/Fields.sol → eth_verifier/lib/bn254/Fields.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ library Base {
uint256 public constant MODULUS =
21888242871839275222246405745257275088696311157297823662689037894645226208583;

function zero() public pure returns (FE) {
return FE.wrap(0);
}

function from(uint n) public pure returns (FE) {
return FE.wrap(n % MODULUS);
}

function from_bytes_be(bytes memory b) public pure returns (FE) {
uint256 integer = 0;
for (uint i = 0; i < 32; i++) {
integer <<= 8;
integer += uint8(b[i]);
}
return FE.wrap(integer % MODULUS);
}

function add(
FE self,
FE other
Expand All @@ -27,12 +44,16 @@ library Base {
}

function square(FE self) public pure returns (FE res) {
res = mul(self, self);
assembly {
res := mulmod(self, self, MODULUS) // mulmod has arbitrary precision
}
}

function inv(FE self) public view returns (FE) {
// TODO:
return FE.wrap(0);
(uint inverse, uint gcd) = Aux.xgcd(FE.unwrap(self), MODULUS);
require(gcd == 1, "gcd not 1");

return FE.wrap(inverse);
}

function neg(FE self) public pure returns (FE) {
Expand Down Expand Up @@ -77,7 +98,6 @@ library Base {
}
}
}
import "forge-std/console.sol";

/// @notice Implements 256 bit modular arithmetic over the scalar field of bn254.
library Scalar {
Expand All @@ -92,10 +112,26 @@ library Scalar {
19103219067921713944291392827692070036145651957329286315305642004821462161904;
uint256 public constant TWO_ADICITY = 28;

function zero() public pure returns (FE) {
return FE.wrap(0);
}

function from(uint n) public pure returns (FE) {
return FE.wrap(n % MODULUS);
}

function from_bytes_be(bytes memory b) public pure returns (FE) {
uint256 integer = 0;
uint count = b.length <= 32 ? b.length : 32;

for (uint i = 0; i < count; i++) {
integer <<= 8;
integer += uint8(b[i]);
}
integer <<= (32 - count) * 8;
return FE.wrap(integer % MODULUS);
}

function add(
FE self,
FE other
Expand Down
3 changes: 1 addition & 2 deletions eth_verifier/lib/msgpack/Deserialize.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ pragma solidity >=0.4.16 <0.9.0;

import {Kimchi} from "../../src/Verifier.sol";
import "../Commitment.sol";
import "../BN254.sol";
import "../bn254/BN254.sol";
import "../Evaluations.sol";
import "../Proof.sol";
import "../State.sol";
import "../Utils.sol";
import {console} from "forge-std/console.sol";

library MsgPk {
struct Stream {
Expand Down
101 changes: 101 additions & 0 deletions eth_verifier/lib/sponge/Sponge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

import "../bn254/Fields.sol";
import "../bn254/BN254.sol";
import "../Commitment.sol";

struct Sponge {
bytes state;
}

library KeccakSponge {
// Basic methods

function reinit(Sponge storage self) external {
self.state = new bytes(0);
}

function absorb(Sponge storage self, bytes memory b) external {
for (uint i = 0; i < b.length; i++) {
self.state.push(b[i]);
}
}

function squeeze(
Sponge memory self,
uint byte_count
) public pure returns (bytes memory digest) {
digest = new bytes(byte_count);
bytes32 output;

for (uint i = 0; i < byte_count; i++) {
if (i % 32 == 0) {
output = keccak256(self.state);
self.state = abi.encode(output);
}

digest[i] = output[i % 32];
}
}

// KZG methods

function absorb_base(Sponge storage self, Base.FE elem) external {
bytes memory b = abi.encode(elem);
for (uint i = 0; i < b.length; i++) {
self.state.push(b[i]);
}
}

function absorb_scalar(Sponge storage self, Scalar.FE elem) external {
bytes memory b = abi.encode(elem);
for (uint i = 0; i < b.length; i++) {
self.state.push(b[i]);
}
}

function absorb_g(
Sponge storage self,
BN254.G1Point memory point
) external {
bytes memory b = abi.encode(point);
for (uint i = 0; i < b.length; i++) {
self.state.push(b[i]);
}
}

function absorb_commitment(
Sponge storage self,
PolyComm memory comm
) external {
bytes memory b = abi.encode(comm);
for (uint i = 0; i < b.length; i++) {
self.state.push(b[i]);
}
}

function challenge_base(
Sponge storage self
) external pure returns (Base.FE chal) {
chal = Base.from_bytes_be(squeeze(self, 16));
}

function challenge_scalar(
Sponge storage self
) external pure returns (Scalar.FE chal) {
chal = Scalar.from_bytes_be(squeeze(self, 16));
}

function digest_base(
Sponge storage self
) external pure returns (Base.FE digest) {
digest = Base.from_bytes_be(squeeze(self, 32));
}

function digest_scalar(
Sponge storage self
) external pure returns (Scalar.FE digest) {
digest = Scalar.from_bytes_be(squeeze(self, 32));
}
}
9 changes: 6 additions & 3 deletions eth_verifier/src/Verifier.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

import "../lib/Fields.sol";
import "../lib/BN254.sol";
import "../lib/bn254/Fields.sol";
import "../lib/bn254/BN254.sol";
import "../lib/VerifierIndex.sol";
import "../lib/Commitment.sol";
import "../lib/Oracles.sol";
Expand Down Expand Up @@ -48,6 +48,9 @@ contract KimchiVerifier {
VerifierIndex verifier_index;
ProverProof proof;

Sponge base_sponge;
Sponge scalar_sponge;

State internal state;
bool state_available;

Expand Down Expand Up @@ -156,7 +159,7 @@ contract KimchiVerifier {
).commitment;
}

Oracles.fiat_shamir(verifier_index);
Oracles.fiat_shamir(verifier_index, public_comm, base_sponge, scalar_sponge);
}

/*
Expand Down
Loading

0 comments on commit df08387

Please sign in to comment.