Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
keccak.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#include "keccak.hpp"
15namespace bb::stdlib {
16
17using namespace bb::plookup;
18
35template <typename Builder>
36template <size_t lane_index>
38{
39 // left_bits = the number of bits that wrap around 11^64 (left_bits)
40 constexpr size_t left_bits = ROTATIONS[lane_index];
41
42 // right_bits = the number of bits that don't wrap
43 constexpr size_t right_bits = 64 - ROTATIONS[lane_index];
44
45 // TODO read from same source as plookup table code
46 constexpr size_t max_bits_per_table = plookup::keccak_tables::Rho<>::MAXIMUM_MULTITABLE_BITS;
47
48 // compute the number of lookups required for our left and right bit slices
49 constexpr size_t num_left_tables = left_bits / max_bits_per_table + (left_bits % max_bits_per_table > 0 ? 1 : 0);
50 constexpr size_t num_right_tables = right_bits / max_bits_per_table + (right_bits % max_bits_per_table > 0 ? 1 : 0);
51
52 // get the numerical value of the left and right bit slices
53 // (lookup table input values derived from left / right)
54 uint256_t input = limb.get_value();
55 constexpr uint256_t slice_divisor = BASE.pow(right_bits);
56 const auto [left, right] = input.divmod(slice_divisor);
57
58 // compute the normalized values for the left and right bit slices
59 // (lookup table output values derived from left_normalised / right_normalized)
60 uint256_t left_normalized = normalize_sparse(left);
61 uint256_t right_normalized = normalize_sparse(right);
62
103
104 // compute plookup witness values for a given slice
105 // (same lambda can be used to compute witnesses for left and right slices)
106 auto compute_lookup_witnesses_for_limb = [&]<size_t limb_bits, size_t num_lookups>(uint256_t& normalized) {
107 // (use a constexpr loop to make some pow and div operations compile-time)
108 bb::constexpr_for<0, num_lookups, 1>([&]<size_t i> {
109 constexpr size_t num_bits_processed = i * max_bits_per_table;
110
111 // How many bits can this slice contain?
112 // We want to implicitly range-constrain `normalized < 11^{limb_bits}`,
113 // which means potentially using a lookup table that is not of size 11^{max_bits_per_table}
114 // for the most-significant slice
115 constexpr size_t bit_slice = (num_bits_processed + max_bits_per_table > limb_bits)
116 ? limb_bits % max_bits_per_table
117 : max_bits_per_table;
118
119 // current column values are tracked via 'input' and 'normalized'
120 lookup[ColumnIdx::C1].push_back(input);
121 lookup[ColumnIdx::C2].push_back(normalized);
122
123 constexpr uint64_t divisor = numeric::pow64(static_cast<uint64_t>(BASE), bit_slice);
124 constexpr uint64_t msb_divisor = divisor / static_cast<uint64_t>(BASE);
125
126 // compute the value of the most significant bit of this slice and store in C3
127 const auto [normalized_quotient, normalized_slice] = normalized.divmod(divisor);
128
129 // 256-bit divisions are expensive! cast to u64s when we don't need the extra bits
130 const uint64_t normalized_msb = (static_cast<uint64_t>(normalized_slice) / msb_divisor);
131 lookup[ColumnIdx::C3].push_back(normalized_msb);
132
133 // We need to provide a key/value object for this lookup in order for the Builder
134 // to compute the plookup sorted list commitment
135 const auto [input_quotient, input_slice] = input.divmod(divisor);
136 lookup.lookup_entries.push_back(
137 { { static_cast<uint64_t>(input_slice), 0 }, { normalized_slice, normalized_msb } });
138
139 // reduce the input and output by 11^{bit_slice}
140 input = input_quotient;
141 normalized = normalized_quotient;
142 });
143 };
144
145 // template lambda syntax is a little funky.
146 // Need to explicitly write `.template operator()` (instead of just `()`).
147 // Otherwise compiler cannot distinguish between `>` symbol referring to closing the template parameter list,
148 // OR `>` being a greater-than operator :/
149 compute_lookup_witnesses_for_limb.template operator()<right_bits, num_right_tables>(right_normalized);
150 compute_lookup_witnesses_for_limb.template operator()<left_bits, num_left_tables>(left_normalized);
151
152 // Call builder method to create plookup constraints.
153 // The MultiTable table index can be derived from `lane_idx`
154 // Each lane_idx has a different rotation amount, which changes sizes of left/right slices
155 // and therefore the selector constants required (i.e. the Q1, Q2, Q3 values in the earlier example)
156 const auto accumulator_witnesses = limb.context->create_gates_from_plookup_accumulators(
158 lookup,
160
161 // extract the most significant bit of the normalized output from the final lookup entry in column C3
163 accumulator_witnesses[ColumnIdx::C3][num_left_tables + num_right_tables - 1]);
164
165 // Extract the witness that maps to the normalized right slice
166 const field_t<Builder> right_output =
167 field_t<Builder>::from_witness_index(limb.get_context(), accumulator_witnesses[ColumnIdx::C2][0]);
168
169 if (num_left_tables == 0) {
170 // if the left slice size is 0 bits (i.e. no rotation), return `right_output`
171 return right_output;
172 } else {
173 // Extract the normalized left slice
175 limb.get_context(), accumulator_witnesses[ColumnIdx::C2][num_right_tables]);
176
177 // Stitch the right/left slices together to create our rotated output
178 constexpr uint256_t shift = BASE.pow(ROTATIONS[lane_index]);
179 return (left_output + right_output * shift);
180 }
181}
182
199template <typename Builder> void keccak<Builder>::compute_twisted_state(keccak_state& internal)
200{
201 for (size_t i = 0; i < NUM_KECCAK_LANES; ++i) {
202 internal.twisted_state[i] = ((internal.state[i] * 11) + internal.state_msb[i]).normalize();
203 }
204}
205
253template <typename Builder> void keccak<Builder>::theta(keccak_state& internal)
254{
257
258 auto& state = internal.state;
259 const auto& twisted_state = internal.twisted_state;
260 for (size_t i = 0; i < 5; ++i) {
261
270 C[i] = field_ct::accumulate({ twisted_state[i],
271 twisted_state[5 + i],
272 twisted_state[10 + i],
273 twisted_state[15 + i],
274 twisted_state[20 + i] });
275 }
276
281 for (size_t i = 0; i < 5; ++i) {
282 const auto non_shifted_equivalent = (C[(i + 4) % 5]);
283 const auto shifted_equivalent = C[(i + 1) % 5] * BASE;
284 D[i] = (non_shifted_equivalent + shifted_equivalent);
285 }
286
303 static constexpr uint256_t divisor = BASE.pow(64);
304 static constexpr uint256_t multiplicand = BASE.pow(65);
305 for (size_t i = 0; i < 5; ++i) {
306 uint256_t D_native = D[i].get_value();
307 const auto [D_quotient, lo_native] = D_native.divmod(BASE);
308 const uint256_t hi_native = D_quotient / divisor;
309 const uint256_t mid_native = D_quotient - hi_native * divisor;
310
311 field_ct hi(witness_ct(internal.context, hi_native));
312 field_ct mid(witness_ct(internal.context, mid_native));
313 field_ct lo(witness_ct(internal.context, lo_native));
314
315 // assert equal should cost 1 gate (multipliers are all constants)
316 D[i].assert_equal((hi * multiplicand).add_two(mid * 11, lo));
317 internal.context->create_new_range_constraint(hi.get_witness_index(), static_cast<uint64_t>(BASE));
318 internal.context->create_new_range_constraint(lo.get_witness_index(), static_cast<uint64_t>(BASE));
319
320 // If number of bits in KECCAK_THETA_OUTPUT table does NOT cleanly divide 64,
321 // we need an additional range constraint to ensure that mid < 11^64
322 if constexpr (64 % plookup::keccak_tables::Theta::TABLE_BITS == 0) {
323 // N.B. we could optimize out 5 gates per round here but it's very fiddly...
324 // In previous section, D[i] = X + Y (non shifted equiv and shifted equiv)
325 // We also want to validate D[i] == hi' + mid' + lo (where hi', mid' are hi, mid scaled by constants)
326 // We *could* create a big addition gate to validate the previous logic w. following structure:
327 // | w1 | w2 | w3 | w4 |
328 // | -- | --- | -- | -- |
329 // | hi | mid | lo | X |
330 // | P0 | P1 | P2 | Y |
331 // To save a gate, we would need to place the wires for the first KECCAK_THETA_OUTPUT plookup gate
332 // at P0, P1, P2. This is fiddly builder logic that is circuit-width-dependent
333 // (this would save 120 gates per hash block... not worth making the code less readable for that)
335 } else {
337 D[i] = accumulators[ColumnIdx::C2][0];
338
339 // Ensure input to lookup is < 11^64,
340 // by validating most significant input slice is < 11^{64 mod slice_bits}
341 const field_ct most_significant_slice = accumulators[ColumnIdx::C1][accumulators[ColumnIdx::C1].size() - 1];
342
343 // N.B. cheaper to validate (11^{64 mod slice_bits} - slice < 2^14) as this
344 // prevents an extra range table from being created
345 constexpr uint256_t maximum = BASE.pow(64 % plookup::keccak_tables::Theta::TABLE_BITS);
346 const field_ct target = -most_significant_slice + maximum;
347 BB_ASSERT_GT((uint256_t(1) << Builder::DEFAULT_PLOOKUP_RANGE_BITNUM) - 1, maximum);
348 target.create_range_constraint(Builder::DEFAULT_PLOOKUP_RANGE_BITNUM,
349 "input to KECCAK_THETA_OUTPUT too large!");
350 }
351 }
352
353 // compute state[j * 5 + i] XOR D[i] in base-11 representation
354 for (size_t i = 0; i < 5; ++i) {
355 for (size_t j = 0; j < 5; ++j) {
356 state[j * 5 + i] = state[j * 5 + i] + D[i];
357 }
358 }
359}
360
387template <typename Builder> void keccak<Builder>::rho(keccak_state& internal)
388{
389 constexpr_for<0, NUM_KECCAK_LANES, 1>(
390 [&]<size_t i>() { internal.state[i] = normalize_and_rotate<i>(internal.state[i], internal.state_msb[i]); });
391}
392
402template <typename Builder> void keccak<Builder>::pi(keccak_state& internal)
403{
405
406 for (size_t j = 0; j < 5; ++j) {
407 for (size_t i = 0; i < 5; ++i) {
408 B[j * 5 + i] = internal.state[j * 5 + i];
409 }
410 }
411
412 for (size_t y = 0; y < 5; ++y) {
413 for (size_t x = 0; x < 5; ++x) {
414 size_t u = (0 * x + 1 * y) % 5;
415 size_t v = (2 * x + 3 * y) % 5;
416
417 internal.state[v * 5 + u] = B[5 * y + x];
418 }
419 }
420}
421
438template <typename Builder> void keccak<Builder>::chi(keccak_state& internal)
439{
440 // (cost = 12 * 25 = 300?)
441 auto& state = internal.state;
442
443 for (size_t y = 0; y < 5; ++y) {
444 std::array<field_ct, 5> lane_outputs;
445 for (size_t x = 0; x < 5; ++x) {
446 const auto A = state[y * 5 + x];
447 const auto B = state[y * 5 + ((x + 1) % 5)];
448 const auto C = state[y * 5 + ((x + 2) % 5)];
449
450 // vv should cost 1 gate
451 lane_outputs[x] = (A + A + CHI_OFFSET).add_two(-B, C);
452 }
453 for (size_t x = 0; x < 5; ++x) {
454 // Normalize lane outputs and assign to internal.state
455 auto accumulators = plookup_read<Builder>::get_lookup_accumulators(KECCAK_CHI_OUTPUT, lane_outputs[x]);
456 internal.state[y * 5 + x] = accumulators[ColumnIdx::C2][0];
457 internal.state_msb[y * 5 + x] = accumulators[ColumnIdx::C3][accumulators[ColumnIdx::C3].size() - 1];
458 }
459 }
460}
461
471template <typename Builder> void keccak<Builder>::iota(keccak_state& internal, size_t round)
472{
473 const field_ct xor_result = internal.state[0] + SPARSE_RC[round];
474
475 // normalize lane value so that we don't overflow our base11 modulus boundary in the next round
476 internal.state[0] = normalize_and_rotate<0>(xor_result, internal.state_msb[0]);
477
478 // No need to add constraints to compute twisted repr if this is the last round
479 if (round != NUM_KECCAK_ROUNDS - 1) {
480 compute_twisted_state(internal);
481 }
482}
483
484template <typename Builder> void keccak<Builder>::keccakf1600(keccak_state& internal)
485{
486 for (size_t i = 0; i < NUM_KECCAK_ROUNDS; ++i) {
487 theta(internal);
488 rho(internal);
489 pi(internal);
490 chi(internal);
491 iota(internal, i);
492 }
493}
494
495template <typename Builder>
497 const std::vector<field_ct>& input_buffer,
498 const std::vector<field_ct>& msb_buffer)
499{
500 const size_t l = input_buffer.size();
501
502 const size_t num_blocks = l / (BLOCK_SIZE / 8);
503
504 for (size_t i = 0; i < num_blocks; ++i) {
505 if (i == 0) {
506 for (size_t j = 0; j < LIMBS_PER_BLOCK; ++j) {
507 internal.state[j] = input_buffer[j];
508 internal.state_msb[j] = msb_buffer[j];
509 }
510 for (size_t j = LIMBS_PER_BLOCK; j < NUM_KECCAK_LANES; ++j) {
511 internal.state[j] = witness_ct::create_constant_witness(internal.context, 0);
512 internal.state_msb[j] = witness_ct::create_constant_witness(internal.context, 0);
513 }
514 } else {
515 for (size_t j = 0; j < LIMBS_PER_BLOCK; ++j) {
516 internal.state[j] += input_buffer[i * LIMBS_PER_BLOCK + j];
517 internal.state[j] = normalize_and_rotate<0>(internal.state[j], internal.state_msb[j]);
518 }
519 }
520
521 compute_twisted_state(internal);
522 keccakf1600(internal);
523 }
524}
525
527{
528 byte_array_ct result(internal.context);
529
530 // Each hash limb represents a little-endian integer. Need to reverse bytes before we write into the output array
531 for (size_t i = 0; i < 4; ++i) {
533 byte_array_ct limb_bytes(output_limb, 8);
534 byte_array_ct little_endian_limb_bytes(internal.context, 8);
535 little_endian_limb_bytes[0] = limb_bytes[7];
536 little_endian_limb_bytes[1] = limb_bytes[6];
537 little_endian_limb_bytes[2] = limb_bytes[5];
538 little_endian_limb_bytes[3] = limb_bytes[4];
539 little_endian_limb_bytes[4] = limb_bytes[3];
540 little_endian_limb_bytes[5] = limb_bytes[2];
541 little_endian_limb_bytes[6] = limb_bytes[1];
542 little_endian_limb_bytes[7] = limb_bytes[0];
543 result.write(little_endian_limb_bytes);
544 }
545 return result;
546}
547
560{
561 auto* ctx = input.get_context();
562
563 const size_t input_size = input.size();
564 // max_blocks_length = maximum number of bytes to hash
565 const size_t max_blocks = (input_size + BLOCK_SIZE) / BLOCK_SIZE;
566 const size_t max_blocks_length = (BLOCK_SIZE * (max_blocks));
567
568 byte_array_ct block_bytes(input);
569
570 const size_t byte_difference = max_blocks_length - input_size;
571 byte_array_ct padding_bytes(ctx, byte_difference);
572 for (size_t i = 0; i < byte_difference; ++i) {
573 padding_bytes[i] = witness_ct::create_constant_witness(ctx, 0);
574 }
575 block_bytes.write(padding_bytes);
576
577 // Keccak requires that 0x1 is appended after the final byte of input data.
578 // Similarly, the final byte of the final padded block must be 0x80.
579 const auto terminating_byte = input_size;
580 const auto terminating_block_byte = block_bytes.size() - 1;
581 block_bytes[terminating_byte] = witness_ct::create_constant_witness(ctx, 0x1);
582 block_bytes[terminating_block_byte] = witness_ct::create_constant_witness(ctx, 0x80);
583
584 // keccak lanes interpret memory as little-endian integers,
585 // means we need to swap our byte ordering...
586 for (size_t i = 0; i < block_bytes.size(); i += 8) {
588 for (size_t j = 0; j < 8; ++j) {
589 temp[j] = block_bytes[i + j];
590 }
591 block_bytes[i] = temp[7];
592 block_bytes[i + 1] = temp[6];
593 block_bytes[i + 2] = temp[5];
594 block_bytes[i + 3] = temp[4];
595 block_bytes[i + 4] = temp[3];
596 block_bytes[i + 5] = temp[2];
597 block_bytes[i + 6] = temp[1];
598 block_bytes[i + 7] = temp[0];
599 }
600 const size_t byte_size = block_bytes.size();
601
602 const size_t num_limbs = byte_size / WORD_SIZE;
603 std::vector<field_ct> sliced_buffer;
604
605 // populate a vector of 64-bit limbs from our byte array
606 for (size_t i = 0; i < num_limbs; ++i) {
607 field_ct sliced;
608 if (i * WORD_SIZE + WORD_SIZE > byte_size) {
609 const size_t slice_size = byte_size - (i * WORD_SIZE);
610 const size_t byte_shift = (WORD_SIZE - slice_size) * 8;
611 sliced = field_ct(block_bytes.slice(i * WORD_SIZE, slice_size));
612 sliced = (sliced * (uint256_t(1) << byte_shift)).normalize();
613 } else {
614 sliced = field_ct(block_bytes.slice(i * WORD_SIZE, WORD_SIZE));
615 }
616 sliced_buffer.emplace_back(sliced);
617 }
618
619 return sliced_buffer;
620}
621
622// Returns the keccak f1600 permutation of the input state
623// We first convert the state into 'extended' representation, along with the 'twisted' state
624// and then we call keccakf1600() with this keccak 'internal state'
625// Finally, we convert back the state from the extented representation
626template <typename Builder>
628 std::array<field_t<Builder>, NUM_KECCAK_LANES> state, Builder* ctx)
629{
630 std::vector<field_t<Builder>> converted_buffer(NUM_KECCAK_LANES);
631 std::vector<field_t<Builder>> msb_buffer(NUM_KECCAK_LANES);
632 // populate keccak_state, convert our 64-bit lanes into an extended base-11 representation
633 keccak_state internal;
634 internal.context = ctx;
635 for (size_t i = 0; i < state.size(); ++i) {
636 const auto accumulators = plookup_read<Builder>::get_lookup_accumulators(KECCAK_FORMAT_INPUT, state[i]);
637 internal.state[i] = accumulators[ColumnIdx::C2][0];
638 internal.state_msb[i] = accumulators[ColumnIdx::C3][accumulators[ColumnIdx::C3].size() - 1];
639 }
640 compute_twisted_state(internal);
641 keccakf1600(internal);
642 // we convert back to the normal lanes
643 return extended_2_normal(internal);
644}
645
646// This function is similar to sponge_absorb()
647// but it uses permutation_opcode() instead of calling directly keccakf1600().
648// As a result, this function is less efficient and should only be used to test permutation_opcode()
649template <typename Builder>
651 std::vector<field_t<Builder>>& input_buffer,
652 const size_t input_size)
653{
654 // populate keccak_state
655 const size_t num_blocks = input_size / (BLOCK_SIZE / 8);
656 for (size_t i = 0; i < num_blocks; ++i) {
657 if (i == 0) {
658 for (size_t j = 0; j < LIMBS_PER_BLOCK; ++j) {
659 internal.state[j] = input_buffer[j];
660 }
661 for (size_t j = LIMBS_PER_BLOCK; j < NUM_KECCAK_LANES; ++j) {
662 internal.state[j] = witness_ct::create_constant_witness(internal.context, 0);
663 }
664 } else {
665 for (size_t j = 0; j < LIMBS_PER_BLOCK; ++j) {
666 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1494): potential issue with usage of
667 // `create_logic_constraint`?
669 internal.state[j], input_buffer[i * LIMBS_PER_BLOCK + j], 64, true);
670 }
671 }
672 internal.state = permutation_opcode(internal.state, internal.context);
673 }
674}
675
676// This function computes the keccak hash, like the hash() function
677// but it uses permutation_opcode() instead of calling directly keccakf1600().
678// As a result, this function is less efficient and should only be used to test permutation_opcode()
679template <typename Builder>
681{
682 auto ctx = input.get_context();
683
684 if (ctx == nullptr) {
685 // if buffer is constant compute hash and return w/o creating constraints
686 byte_array_ct output(nullptr, 32);
687 const std::vector<uint8_t> result = hash_native(input.get_value());
688 for (size_t i = 0; i < 32; ++i) {
689 output[i] = result[i];
690 }
691 return output;
692 }
693
694 // convert the input byte array into 64-bit keccak lanes (+ apply padding)
695 auto formatted_slices = format_input_lanes(input);
696
697 keccak_state internal;
698 internal.context = ctx;
699 sponge_absorb_with_permutation_opcode(internal, formatted_slices, formatted_slices.size());
700
701 auto result = sponge_squeeze_for_permutation_opcode(internal.state, ctx);
702
703 return result;
704}
705
707{
708 auto ctx = input.get_context();
709
710 const auto constant_case = [&] { // if buffer is constant, compute hash and return w/o creating constraints
711 byte_array_ct output(nullptr, 32);
712 const std::vector<uint8_t> result = hash_native(input.get_value());
713 for (size_t i = 0; i < 32; ++i) {
714 output[i] = result[i];
715 }
716 return output;
717 };
718
719 if (ctx == nullptr) {
720 return constant_case();
721 }
722
723 // convert the input byte array into 64-bit keccak lanes (+ apply padding)
724 auto formatted_slices = format_input_lanes(input);
725
726 std::vector<field_ct> converted_buffer(formatted_slices.size());
727 std::vector<field_ct> msb_buffer(formatted_slices.size());
728
729 // populate keccak_state, convert our 64-bit lanes into an extended base-11 representation
730 keccak_state internal;
731 internal.context = ctx;
732 for (size_t i = 0; i < formatted_slices.size(); ++i) {
733 const auto accumulators =
735 converted_buffer[i] = accumulators[ColumnIdx::C2][0];
736 msb_buffer[i] = accumulators[ColumnIdx::C3][accumulators[ColumnIdx::C3].size() - 1];
737 }
738
739 sponge_absorb(internal, converted_buffer, msb_buffer);
740
741 auto result = sponge_squeeze(internal);
742
743 return result;
744}
745
746// Convert the 'extended' representation of the internal Keccak state into the usual array of 64 bits lanes
747template <typename Builder>
749 keccak_state& internal)
750{
751 std::array<field_t<Builder>, NUM_KECCAK_LANES> conversion;
752
753 // Each hash limb represents a little-endian integer. Need to reverse bytes before we write into the output array
754 for (size_t i = 0; i < internal.state.size(); ++i) {
756 conversion[i] = output_limb;
757 }
758
759 return conversion;
760}
761
762// This function is the same as sponge_squeeze, except that it does not convert
763// from extended representation and assumes the input has already being converted
764template <typename Builder>
766 std::array<field_t<Builder>, NUM_KECCAK_LANES> lanes, Builder* context)
767{
768 byte_array_ct result(context);
769
770 // Each hash limb represents a little-endian integer. Need to reverse bytes before we write into the output array
771 for (size_t i = 0; i < 4; ++i) {
772 byte_array_ct limb_bytes(lanes[i], 8);
773 byte_array_ct little_endian_limb_bytes(context, 8);
774 little_endian_limb_bytes[0] = limb_bytes[7];
775 little_endian_limb_bytes[1] = limb_bytes[6];
776 little_endian_limb_bytes[2] = limb_bytes[5];
777 little_endian_limb_bytes[3] = limb_bytes[4];
778 little_endian_limb_bytes[4] = limb_bytes[3];
779 little_endian_limb_bytes[5] = limb_bytes[2];
780 little_endian_limb_bytes[6] = limb_bytes[1];
781 little_endian_limb_bytes[7] = limb_bytes[0];
782 result.write(little_endian_limb_bytes);
783 }
784 return result;
785}
786
794template <typename Builder> void generate_keccak_test_circuit(Builder& builder, size_t num_iterations)
795{
796 std::string in = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01";
797
799 for (size_t i = 0; i < num_iterations; i++) {
800 input = stdlib::keccak<Builder>::hash(input);
801 }
802}
803
804template class keccak<bb::UltraCircuitBuilder>;
805template class keccak<bb::MegaCircuitBuilder>;
808
809} // namespace bb::stdlib
#define BB_ASSERT_GT(left, right,...)
Definition assert.hpp:87
constexpr uint256_t pow(const uint256_t &exponent) const
constexpr std::pair< uint256_t, uint256_t > divmod(const uint256_t &b) const
Container type for lookup table reads.
Definition types.hpp:418
std::vector< BasicTable::LookupEntry > lookup_entries
Definition types.hpp:424
Generate the plookup tables used for the RHO round of the Keccak hash algorithm.
static constexpr size_t TABLE_BITS
Represents a dynamic array of bytes in-circuit.
byte_array slice(size_t offset) const
Slice bytes from the byte array starting at offset. Does not add any constraints.
byte_array & write(byte_array const &other)
Appends the contents of another byte_array (other) to the end of this one.
std::vector< uint8_t > get_value() const
A helper converting a byte_array into the vector of its uint8_t values.
size_t size() const
Builder * get_context() const
static field_t from_witness_index(Builder *ctx, uint32_t witness_index)
Definition field.cpp:59
static field_t accumulate(const std::vector< field_t > &input)
Efficiently compute the sum of vector entries. Using big_add_gate we reduce the number of gates neede...
Definition field.cpp:1147
void create_range_constraint(size_t num_bits, std::string const &msg="field_t::range_constraint") const
Let x = *this.normalize(), constrain x.v < 2^{num_bits}.
Definition field.cpp:908
Builder * context
Definition field.hpp:51
Builder * get_context() const
Definition field.hpp:389
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:827
field_t normalize() const
Return a new element, where the in-circuit witness contains the actual represented value (multiplicat...
Definition field.cpp:635
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:461
KECCAAAAAAAAAAK.
Definition keccak.hpp:25
static void rho(keccak_state &state)
RHO round.
Definition keccak.cpp:387
static void sponge_absorb_with_permutation_opcode(keccak_state &internal, std::vector< field_ct > &input_buffer, const size_t input_size)
Definition keccak.cpp:650
static byte_array_ct sponge_squeeze_for_permutation_opcode(std::array< field_ct, NUM_KECCAK_LANES > lanes, Builder *context)
Definition keccak.cpp:765
static void pi(keccak_state &state)
PI.
Definition keccak.cpp:402
static void theta(keccak_state &state)
THETA round.
Definition keccak.cpp:253
static std::vector< field_ct > format_input_lanes(byte_array_ct &input)
Convert the input buffer into 8-bit keccak lanes in little-endian form. Additionally,...
Definition keccak.cpp:559
static void compute_twisted_state(keccak_state &internal)
Compute twisted representation of hash lane.
Definition keccak.cpp:199
static void chi(keccak_state &state)
CHI.
Definition keccak.cpp:438
static byte_array_ct sponge_squeeze(keccak_state &internal)
Definition keccak.cpp:526
static field_t< Builder > normalize_and_rotate(const field_ct &limb, field_ct &msb)
Normalize a base-11 limb and left-rotate by keccak::ROTATIONS[lane_index] bits. This method also extr...
Definition keccak.cpp:37
static std::array< field_ct, NUM_KECCAK_LANES > permutation_opcode(std::array< field_ct, NUM_KECCAK_LANES > state, Builder *context)
Definition keccak.cpp:627
static std::array< field_ct, NUM_KECCAK_LANES > extended_2_normal(keccak_state &internal)
Definition keccak.cpp:748
static byte_array_ct hash_using_permutation_opcode(byte_array_ct &input)
Definition keccak.cpp:680
static void keccakf1600(keccak_state &state)
Definition keccak.cpp:484
static byte_array_ct hash(byte_array_ct &input)
Definition keccak.cpp:706
static void sponge_absorb(keccak_state &internal, const std::vector< field_ct > &input_buffer, const std::vector< field_ct > &msb_buffer)
Definition keccak.cpp:496
static void iota(keccak_state &state, size_t round)
IOTA.
Definition keccak.cpp:471
static field_pt create_logic_constraint(field_pt &a, field_pt &b, size_t num_bits, bool is_xor_gate, const std::function< std::pair< uint256_t, uint256_t >(uint256_t, uint256_t, size_t)> &get_chunk=[](uint256_t left, uint256_t right, size_t chunk_size) { uint256_t left_chunk=left &((uint256_t(1)<< chunk_size) - 1);uint256_t right_chunk=right &((uint256_t(1)<< chunk_size) - 1);return std::make_pair(left_chunk, right_chunk);})
A logical AND or XOR over a variable number of bits.
Definition logic.cpp:32
static witness_t create_constant_witness(Builder *parent_context, const bb::fr &in)
Definition witness.hpp:45
AluTraceBuilder builder
Definition alu.test.cpp:123
StrictMock< MockContext > context
bb::avm2::Column C
bn254::witness_ct witness_ct
stdlib::field_t< Builder > field_ct
constexpr uint64_t pow64(const uint64_t input, const uint64_t exponent)
Definition pow.hpp:13
@ KECCAK_FORMAT_INPUT
Definition types.hpp:135
@ KECCAK_FORMAT_OUTPUT
Definition types.hpp:136
@ KECCAK_NORMALIZE_AND_ROTATE
Definition types.hpp:137
@ KECCAK_CHI_OUTPUT
Definition types.hpp:134
@ KECCAK_THETA_OUTPUT
Definition types.hpp:133
void generate_keccak_test_circuit(Builder &builder, size_t num_iterations)
Generate a simple keccak circuit for testing purposes.
Definition keccak.cpp:794
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::array< field_ct, NUM_KECCAK_LANES > state
Definition keccak.hpp:159
std::array< field_ct, NUM_KECCAK_LANES > twisted_state
Definition keccak.hpp:161
std::array< field_ct, NUM_KECCAK_LANES > state_msb
Definition keccak.hpp:160