Skip to content
Closed
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
14 changes: 12 additions & 2 deletions .github/workflows/fund-sepolia-accounts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ on:
required: false
type: string
default: master
funding_amount:
description: The amount of ETH to fund each account with
required: true
type: number
default: 5
secrets:
GCP_SA_KEY:
required: true
Expand All @@ -43,6 +48,11 @@ on:
required: false
type: string
default: master
funding_amount:
description: The amount of ETH to fund each account with
required: true
type: number
default: 5

jobs:
fund-sepolia-accounts:
Expand Down Expand Up @@ -79,7 +89,7 @@ jobs:
if [[ "${{ steps.get-mnemonic.outputs.new_mnemonic }}" == "true" ]]; then
echo "Generating new mnemonic"
else
MNEMONIC="${{ steps.get-mnemonic.outputs.mnemonic }}"
export MNEMONIC="${{ steps.get-mnemonic.outputs.mnemonic }}"
echo "Using mnemonic from GCP"
fi

Expand All @@ -89,7 +99,7 @@ jobs:
export ETHEREUM_HOST="https://json-rpc.${{ secrets.GCP_SEPOLIA_URL }}?key=${{ secrets.GCP_SEPOLIA_API_KEY }}"

echo "Funding accounts..."
$REPO/spartan/scripts/prepare_sepolia_accounts.sh ${{ inputs.values_file }} 30 "$MNEMONIC_FILE"
$REPO/spartan/scripts/prepare_sepolia_accounts.sh ${{ inputs.values_file }} ${{ inputs.funding_amount }} "$MNEMONIC_FILE"
mnemonic=$(cat "$MNEMONIC_FILE")
rm "$MNEMONIC_FILE"
echo "::add-mask::$mnemonic"
Expand Down
110 changes: 100 additions & 10 deletions barretenberg/cpp/pil/vm2/alu.pil
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace alu;
pol commit sel;

pol commit sel_op_add;
pol commit sel_op_mul;
pol commit sel_op_eq;
pol commit sel_op_lt;
pol commit sel_op_lte;
Expand Down Expand Up @@ -37,24 +38,28 @@ pol commit cf;
pol commit helper1;

// maximum bits the number can hold (i.e. 8 for a u8):
// TODO(MW): Now unused since we redirect the LT/LTE range checks to GT gadget - remove?
pol commit max_bits;
// maximum value the number can hold (i.e. 255 for a u8), we 'mod' by max_value + 1
pol commit max_value;
// we need a selector to conditionally lookup ff_gt when inputs a, b are fields:
pol commit sel_is_ff;
// we need a selector to conditionally perform u128 multiplication:
pol commit sel_is_u128;

pol IS_NOT_FF = 1 - sel_is_ff;
pol IS_NOT_U128 = 1 - sel_is_u128;

sel * (1 - sel) = 0;
cf * (1 - cf) = 0;
sel_is_ff * (1 - sel_is_ff) = 0;
sel_is_u128 * (1 - sel_is_u128) = 0;

// TODO: Consider to gate with (1 - sel_tag_err) for op_id. This might help us remove the (1 - sel_tag_err)
// in various operation relations below.
// Note that the op_ids below represent a binary decomposition (see constants_gen.pil):
#[OP_ID_CHECK]
op_id = sel_op_add * constants.AVM_EXEC_OP_ID_ALU_ADD
+ sel_op_mul * constants.AVM_EXEC_OP_ID_ALU_MUL
+ sel_op_eq * constants.AVM_EXEC_OP_ID_ALU_EQ
+ sel_op_lt * constants.AVM_EXEC_OP_ID_ALU_LT
+ sel_op_lte * constants.AVM_EXEC_OP_ID_ALU_LTE
Expand All @@ -78,18 +83,28 @@ execution.sel_execute_alu {

// IS_FF CHECKING

// TODO(MW): remove this and check for all (i.e. replace with sel), just being lazy for now. For add, we don't care, for lt we need to differentiate.
pol CHECK_TAG_FF = sel_op_lt + sel_op_lte + sel_op_not;
// We prove that sel_is_ff == 1 <==> ia_tag == MEM_TAG_FF
pol TAG_FF_DIFF = ia_tag - constants.MEM_TAG_FF;
pol commit tag_ff_diff_inv;
#[TAG_IS_FF]
CHECK_TAG_FF * (TAG_FF_DIFF * (sel_is_ff * (1 - tag_ff_diff_inv) + tag_ff_diff_inv) + sel_is_ff - 1) = 0;

// IS_U128 CHECKING

pol CHECK_TAG_U128 = sel_op_mul;
// We prove that sel_is_u128 == 1 <==> ia_tag == MEM_TAG_U128
pol TAG_U128_DIFF = ia_tag - constants.MEM_TAG_U128;
pol commit tag_u128_diff_inv;
#[TAG_IS_U128]
CHECK_TAG_U128 * (TAG_U128_DIFF * (sel_is_u128 * (1 - tag_u128_diff_inv) + tag_u128_diff_inv) + sel_is_u128 - 1) = 0;

// Note: if we never need sel_is_ff and sel_is_u128 in the same op, can combine the above checks into one

// TAG CHECKING

// Will become e.g. sel_op_add * ia_tag + (comparison ops) * MEM_TAG_U1 + ....
pol EXPECTED_C_TAG = (sel_op_add + sel_op_truncate) * ia_tag + (sel_op_eq + sel_op_lt + sel_op_lte) * constants.MEM_TAG_U1;
pol EXPECTED_C_TAG = (sel_op_add + sel_op_truncate + sel_op_mul) * ia_tag + (sel_op_eq + sel_op_lt + sel_op_lte) * constants.MEM_TAG_U1;

// The tag of c is generated by the opcode and is never wrong.
// Gating with (1 - sel_tag_err) is necessary because when an error occurs, we have to set the tag to 0,
Expand Down Expand Up @@ -123,6 +138,81 @@ sel_op_add * (1 - sel_op_add) = 0;
#[ALU_ADD]
sel_op_add * (1 - sel_tag_err) * (ia + ib - ic - cf * (max_value + 1)) = 0;

// MUL

sel_op_mul * (1 - sel_op_mul) = 0;

pol commit c_hi;

// MUL - non u128

#[ALU_MUL_NON_U128]
sel_op_mul * IS_NOT_U128 * (1 - sel_tag_err)
* (
ia * ib
- ic
- (max_value + 1) * c_hi
) = 0;

// MUL - u128

pol commit sel_mul_u128;
// sel_op_mul & sel_is_u128:
sel_mul_u128 - sel_is_u128 * sel_op_mul = 0;

// Taken from vm1:
// We express a, b in 64-bit slices: a = a_l + a_h * 2^64
// b = b_l + b_h * 2^64
// => a * b = a_l * b_l + (a_h * b_l + a_l * b_h) * 2^64 + (a_h * b_h) * 2^128 = c_hi_full * 2^128 + c
// => the 'top bits' are given by (c_hi_full - (a_h * b_h)) * 2^128
// We can show for a 64 bit c_hi = c_hi_full - (a_h * b_h) % 2^64 that:
// a_l * b_l + (a_h * b_l + a_l * b_h) * 2^64 = c_hi * 2^128 + c
// Equivalently (cf = 0 if a_h & b_h = 0):
// a * b_l + a_l * b_h * 2^64 = (cf * 2^64 + c_hi) * 2^128 + c
// => no need for a_h in final relation

pol commit a_lo;
pol commit a_hi;
pol commit b_lo;
pol commit b_hi;
pol TWO_POW_64 = 2 ** 64;

#[A_MUL_DECOMPOSITION]
sel_mul_u128 * (ia - (a_lo + TWO_POW_64 * a_hi)) = 0;
#[B_MUL_DECOMPOSITION]
sel_mul_u128 * (ib - (b_lo + TWO_POW_64 * b_hi)) = 0;

#[ALU_MUL_U128]
sel_mul_u128 * (1 - sel_tag_err)
* (
ia * b_lo + a_lo * b_hi * TWO_POW_64 // a * b without the hi bits
- ic // c_lo
- (max_value + 1) * (cf * TWO_POW_64 + c_hi) // c_hi * 2^128 + (cf ? 2^192 : 0)
) = 0;

// TODO: Once lookups support expression in tuple, we can inline constant_64 into the lookup.
// Note: only used for MUL, so gated by sel_op_mul
pol commit constant_64;
sel_op_mul * (64 - constant_64) = 0;

#[RANGE_CHECK_MUL_U128_A_LO]
sel_mul_u128 { a_lo, constant_64 } in range_check.sel { range_check.value, range_check.rng_chk_bits };

#[RANGE_CHECK_MUL_U128_A_HI]
sel_mul_u128 { a_hi, constant_64 } in range_check.sel { range_check.value, range_check.rng_chk_bits };

#[RANGE_CHECK_MUL_U128_B_LO]
sel_mul_u128 { b_lo, constant_64 } in range_check.sel { range_check.value, range_check.rng_chk_bits };

#[RANGE_CHECK_MUL_U128_B_HI]
sel_mul_u128 { b_hi, constant_64 } in range_check.sel { range_check.value, range_check.rng_chk_bits };

// No need to range_check c_hi for cases other than u128 because we know a and b's size from the tags and have looked
// up max_value. i.e. we cannot provide a malicious c, c_hi such that a + b - c_hi * 2^n = c passes for n < 128.
// No need to range_check c_lo = ic because the memory write will ensure ic <= max_value.
#[RANGE_CHECK_MUL_U128_C_HI]
sel_mul_u128 { c_hi, constant_64 } in range_check.sel { range_check.value, range_check.rng_chk_bits };

// EQ

sel_op_eq * (1 - sel_op_eq) = 0;
Expand Down Expand Up @@ -280,21 +370,21 @@ sel_op_truncate = sel_trunc_non_trivial + sel_trunc_trivial;
#[TRUNC_TRIVIAL_CASE]
sel_trunc_trivial * (ia - ic) = 0;

pol commit lo_128; // 128-bit low limb of ia.
pol commit hi_128; // 128-bit high limb of ia.
// NOTE: reusing a_lo and a_hi columns from MUL in TRUNC:
// For truncate, a_lo = 128-bit low limb of ia and a_hi = 128-bit high limb of ia.
pol commit mid;

#[LARGE_TRUNC_CANONICAL_DEC]
sel_trunc_gte_128 { ia, lo_128, hi_128 }
sel_trunc_gte_128 { ia, a_lo, a_hi }
in
ff_gt.sel_dec { ff_gt.a, ff_gt.a_lo, ff_gt.a_hi };

#[SMALL_TRUNC_VAL_IS_LO]
sel_trunc_lt_128 * (lo_128 - ia) = 0;
sel_trunc_lt_128 * (a_lo - ia) = 0;

// lo_128 = ic + mid * 2^ia_tag_bits, where 2^ia_tag_bits is max_value + 1.
// a_lo = ic + mid * 2^ia_tag_bits, where 2^ia_tag_bits is max_value + 1.
#[TRUNC_LO_128_DECOMPOSITION]
sel_trunc_non_trivial * (ic + mid * (max_value + 1) - lo_128) = 0;
sel_trunc_non_trivial * (ic + mid * (max_value + 1) - a_lo) = 0;

// TODO: Once lookups support expression in tuple, we can inline mid_bits into the lookup.
pol commit mid_bits;
Expand All @@ -305,4 +395,4 @@ mid_bits = sel_trunc_non_trivial * (128 - max_bits);
// is supported by our range_check gadget.
// No need to range_check ic because the memory write will ensure ic <= max_value.
#[RANGE_CHECK_TRUNC_MID]
sel_trunc_non_trivial {mid, mid_bits} in range_check.sel { range_check.value, range_check.rng_chk_bits };
sel_trunc_non_trivial { mid, mid_bits } in range_check.sel { range_check.value, range_check.rng_chk_bits };
60 changes: 27 additions & 33 deletions barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ library Honk {
}

struct VerificationKey {
// Hash of all of the field elements in the verification key
uint256 vkHash;
// Misc Params
uint256 circuitSize;
uint256 logCircuitSize;
Expand Down Expand Up @@ -342,14 +344,12 @@ library TranscriptLib {
function generateTranscript(
Honk.Proof memory proof,
bytes32[] calldata publicInputs,
uint256 circuitSize,
uint256 publicInputsSize,
uint256 pubInputsOffset
uint256 vkHash,
uint256 publicInputsSize
) internal pure returns (Transcript memory t) {
Fr previousChallenge;
(t.relationParameters, previousChallenge) = generateRelationParametersChallenges(
proof, publicInputs, circuitSize, publicInputsSize, pubInputsOffset, previousChallenge
);
(t.relationParameters, previousChallenge) =
generateRelationParametersChallenges(proof, publicInputs, vkHash, publicInputsSize, previousChallenge);

(t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof);

Expand Down Expand Up @@ -379,50 +379,46 @@ library TranscriptLib {
function generateRelationParametersChallenges(
Honk.Proof memory proof,
bytes32[] calldata publicInputs,
uint256 circuitSize,
uint256 vkHash,
uint256 publicInputsSize,
uint256 pubInputsOffset,
Fr previousChallenge
) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) {
(rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) =
generateEtaChallenge(proof, publicInputs, circuitSize, publicInputsSize, pubInputsOffset);
generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize);

(rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof);
}

function generateEtaChallenge(
Honk.Proof memory proof,
bytes32[] calldata publicInputs,
uint256 circuitSize,
uint256 publicInputsSize,
uint256 pubInputsOffset
uint256 vkHash,
uint256 publicInputsSize
) internal pure returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) {
bytes32[] memory round0 = new bytes32[](3 + publicInputsSize + 12);
round0[0] = bytes32(circuitSize);
round0[1] = bytes32(publicInputsSize);
round0[2] = bytes32(pubInputsOffset);
bytes32[] memory round0 = new bytes32[](1 + publicInputsSize + 12);
round0[0] = bytes32(vkHash);

for (uint256 i = 0; i < publicInputsSize - PAIRING_POINTS_SIZE; i++) {
round0[3 + i] = bytes32(publicInputs[i]);
round0[1 + i] = bytes32(publicInputs[i]);
}
for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) {
round0[3 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]);
round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]);
}

// Create the first challenge
// Note: w4 is added to the challenge later on
round0[3 + publicInputsSize] = bytes32(proof.w1.x_0);
round0[3 + publicInputsSize + 1] = bytes32(proof.w1.x_1);
round0[3 + publicInputsSize + 2] = bytes32(proof.w1.y_0);
round0[3 + publicInputsSize + 3] = bytes32(proof.w1.y_1);
round0[3 + publicInputsSize + 4] = bytes32(proof.w2.x_0);
round0[3 + publicInputsSize + 5] = bytes32(proof.w2.x_1);
round0[3 + publicInputsSize + 6] = bytes32(proof.w2.y_0);
round0[3 + publicInputsSize + 7] = bytes32(proof.w2.y_1);
round0[3 + publicInputsSize + 8] = bytes32(proof.w3.x_0);
round0[3 + publicInputsSize + 9] = bytes32(proof.w3.x_1);
round0[3 + publicInputsSize + 10] = bytes32(proof.w3.y_0);
round0[3 + publicInputsSize + 11] = bytes32(proof.w3.y_1);
round0[1 + publicInputsSize] = bytes32(proof.w1.x_0);
round0[1 + publicInputsSize + 1] = bytes32(proof.w1.x_1);
round0[1 + publicInputsSize + 2] = bytes32(proof.w1.y_0);
round0[1 + publicInputsSize + 3] = bytes32(proof.w1.y_1);
round0[1 + publicInputsSize + 4] = bytes32(proof.w2.x_0);
round0[1 + publicInputsSize + 5] = bytes32(proof.w2.x_1);
round0[1 + publicInputsSize + 6] = bytes32(proof.w2.y_0);
round0[1 + publicInputsSize + 7] = bytes32(proof.w2.y_1);
round0[1 + publicInputsSize + 8] = bytes32(proof.w3.x_0);
round0[1 + publicInputsSize + 9] = bytes32(proof.w3.x_1);
round0[1 + publicInputsSize + 10] = bytes32(proof.w3.y_0);
round0[1 + publicInputsSize + 11] = bytes32(proof.w3.y_1);

previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round0)));
(eta, etaTwo) = splitChallenge(previousChallenge);
Expand Down Expand Up @@ -1740,9 +1736,7 @@ abstract contract BaseHonkVerifier is IVerifier {
}

// Generate the fiat shamir challenges for the whole protocol
Transcript memory t = TranscriptLib.generateTranscript(
p, publicInputs, vk.circuitSize, $NUM_PUBLIC_INPUTS, /*pubInputsOffset=*/ 1
);
Transcript memory t = TranscriptLib.generateTranscript(p, publicInputs, vk.vkHash, $NUM_PUBLIC_INPUTS);

// Derive public input delta
t.relationParameters.publicInputsDelta = computePublicInputDelta(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ uint256 constant NUMBER_UNSHIFTED = 36;
uint256 constant NUMBER_TO_BE_SHIFTED = 5;
uint256 constant PAIRING_POINTS_SIZE = 16;

uint256 constant VK_HASH = {{ VK_HASH }};
uint256 constant CIRCUIT_SIZE = {{ CIRCUIT_SIZE }};
uint256 constant LOG_N = {{ LOG_CIRCUIT_SIZE }};
uint256 constant NUMBER_PUBLIC_INPUTS = {{ NUM_PUBLIC_INPUTS }};
Expand Down Expand Up @@ -1343,21 +1344,19 @@ contract HonkVerifier is IVerifier {
// Note: can be mcpyed from proof
// TODO: work what memory can be used here - if we use 0 solidity at all we can get
// away with ignoring free memory practices entirely
mstore(0x00, CIRCUIT_SIZE)
mstore(0x20, NUMBER_PUBLIC_INPUTS)
mstore(0x40, PUBLIC_INPUTS_OFFSET)
mstore(0x00, VK_HASH)

let public_inputs_start := add(calldataload(0x24), 0x24)
let public_inputs_size := mul(REAL_NUMBER_PUBLIC_INPUTS, 0x20)
// Copy the public inputs into the eta buffer
calldatacopy(0x60, public_inputs_start, public_inputs_size)
calldatacopy(0x20, public_inputs_start, public_inputs_size)

// Copy Pairing points into eta buffer
let public_inputs_end := add(0x60, public_inputs_size)
let public_inputs_end := add(0x20, public_inputs_size)
mcopy(public_inputs_end, PAIRING_POINT_0, 0x200)

// 0x1e0 = 3 * 32 bytes + 4 * 96 bytes for (w1,w2,w3) + 0x200 for pairing points
let eta_input_length := add(0x3e0, public_inputs_size)
// 0x1e0 = 1 * 32 bytes + 4 * 96 bytes for (w1,w2,w3) + 0x200 for pairing points
let eta_input_length := add(0x3a0, public_inputs_size)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -1377,7 +1376,7 @@ contract HonkVerifier is IVerifier {
// Note: size will change once proof points are made smaller for keccak flavor
// Right now it is 0x20 * 16 - should be 8
// End of public inputs + pairing point
mcopy(add(0x260, public_inputs_size), W_L_X0_LOC, 0x1a0)
mcopy(add(0x220, public_inputs_size), W_L_X0_LOC, 0x1a0)

let prev_challenge := mod(keccak256(0x00, eta_input_length), p)
mstore(0x00, prev_challenge)
Expand Down Expand Up @@ -4231,6 +4230,7 @@ inline std::string get_optimized_honk_solidity_verifier(auto const& verification
}
};

set_template_param("VK_HASH", field_to_hex(verification_key->hash()));
set_template_param("CIRCUIT_SIZE", std::to_string(1 << verification_key->log_circuit_size));
set_template_param("LOG_CIRCUIT_SIZE", std::to_string(verification_key->log_circuit_size));
set_template_param("NUM_PUBLIC_INPUTS", std::to_string(verification_key->num_public_inputs));
Expand Down
Loading
Loading