Skip to content

Add decomposed Blake gates (BlakeG, TripleXor, M31ToU32) with packed-…#337

Open
alon-f wants to merge 4 commits intomainfrom
alon/decomposed-blake-gates
Open

Add decomposed Blake gates (BlakeG, TripleXor, M31ToU32) with packed-…#337
alon-f wants to merge 4 commits intomainfrom
alon/decomposed-blake-gates

Conversation

@alon-f
Copy link
Copy Markdown
Contributor

@alon-f alon-f commented Mar 11, 2026

…limbs representation

State words use packed u16 limbs in a single QM31: (low, high, 0, 0). All wire values are canonical M31. Input extraction uses Simd::unpack_idx. Introduces U32Wrapper type for type-safe u32 packed-limbs wires. BLAKE2S_IV moved from circuit_air to circuits::blake (single source of truth). Includes blake_from_gates() and comparison test against monolithic blake.

@alon-f alon-f self-assigned this Mar 11, 2026
@reviewable-StarkWare
Copy link
Copy Markdown
Collaborator

This change is Reviewable

…limbs representation

State words use packed u16 limbs in a single QM31: (low, high, 0, 0).
All wire values are canonical M31. Input extraction uses Simd::unpack_idx.
Introduces U32Wrapper<T> type for type-safe u32 packed-limbs wires.
BLAKE2S_IV moved from circuit_air to circuits::blake (single source of truth).
Includes blake_from_gates() and comparison test against monolithic blake.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@alon-f alon-f force-pushed the alon/decomposed-blake-gates branch from 9eb4d21 to e04f49f Compare March 11, 2026 16:30
Copy link
Copy Markdown
Collaborator

@Stavbe Stavbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Stavbe reviewed 2 files and made 36 comments.
Reviewable status: 2 of 8 files reviewed, 36 unresolved discussions (waiting on alon-f, Gali-StarkWare, gilbens-starkware, and ilyalesokhin-starkware).


crates/circuits/src/blake.rs line 133 at r1 (raw file):

}

// --- Constants for Blake2s ---

remove

Code quote:

// --- Constants for Blake2s ---

crates/circuits/src/blake.rs line 164 at r1 (raw file):

];

// --- Helpers ---

remove

Code quote:

// --- Helpers ---

crates/circuits/src/blake.rs line 171 at r1 (raw file):

}

/// Reconstructs a u32 from a packed-limbs QM31: `coord0 + coord1 * 65536`.

(limb_low, limb_high, 0, 0)

Code quote:

`coord0 + coord1 * 65536`.

crates/circuits/src/blake.rs line 173 at r1 (raw file):

/// Reconstructs a u32 from a packed-limbs QM31: `coord0 + coord1 * 65536`.
pub fn unpack_u32(v: QM31) -> u32 {
    v.0.0.0 + v.0.1.0 * 65536

Replace the .0.0.0 it looks weird, don't we have getter for that?. Also please write the constant as 2^(

Code quote:

 v.0.0.0 + v.0.1.0 * 65536

crates/circuits/src/blake.rs line 177 at r1 (raw file):

/// Wraps a single M31 value as a QM31: `(value, 0, 0, 0)`.
pub fn u32_to_qm31(v: u32) -> QM31 {

m31

Code quote:

u32

crates/circuits/src/blake.rs line 181 at r1 (raw file):

}

// --- Builder functions ---

please remove

Code quote:

// --- Builder functions ---

crates/circuits/src/blake.rs line 195 at r1 (raw file):

    m1: U32Var,
) -> (U32Var, U32Var, U32Var, U32Var) {
    let mut a_val = unpack_u32(ctx.get(*a.get()));

Why not updating the input for the helper function to be U32VAR


crates/circuits/src/blake.rs line 202 at r1 (raw file):

    let m1_val = unpack_u32(ctx.get(*m1.get()));

    a_val = a_val.wrapping_add(b_val).wrapping_add(m0_val);

it this mode P?

Code quote:

.wrapping_add

crates/circuits/src/blake.rs line 269 at r1 (raw file):

/// Computes Blake2s hash using decomposed gates (BlakeG, TripleXor, M31ToU32) instead of the
/// monolithic Blake gate. Produces the same output as [`blake`].

remove
and add all the comments that the other blake have

Code quote:

/// Computes Blake2s hash using decomposed gates (BlakeG, TripleXor, M31ToU32) instead of the
/// monolithic Blake gate. Produces the same output as [`blake`].

crates/circuits/src/blake.rs line 274 at r1 (raw file):

    // 1. Extract individual M31 message words from input QM31 vars, then convert each to U32Wrapper
    //    packed limbs for blake_g_gate.

// Unpack each QM31 containing the messgae into U32Vars

Code quote:

    // 1. Extract individual M31 message words from input QM31 vars, then convert each to U32Wrapper
    //    packed limbs for blake_g_gate.

crates/circuits/src/blake.rs line 277 at r1 (raw file):

    let mut message_u32s: Vec<U32Var> = Vec::new();
    for &var in input {
        let simd = Simd::from_packed(vec![var], 4);

Maybe we can do even more then 4 together


crates/circuits/src/blake.rs line 284 at r1 (raw file):

    }

    // 2. Pad message to complete 64-byte (16 u32-word) blocks.

remove the 2.


crates/circuits/src/blake.rs line 285 at r1 (raw file):

    // 2. Pad message to complete 64-byte (16 u32-word) blocks.
    let n_blocks = std::cmp::max(1, n_bytes.div_ceil(64));

const

Code quote:

64

crates/circuits/src/blake.rs line 286 at r1 (raw file):

    // 2. Pad message to complete 64-byte (16 u32-word) blocks.
    let n_blocks = std::cmp::max(1, n_bytes.div_ceil(64));
    let total_words = n_blocks * 16;

const

Code quote:

16

crates/circuits/src/blake.rs line 293 at r1 (raw file):

    // 3. Initialize chaining value: IV with parameter block XOR, as packed-limbs constants. All
    //    limb values are < 2^16 < P, so ctx.constant() is safe.

Initlialize 'h'

Code quote:

    // 3. Initialize chaining value: IV with parameter block XOR, as packed-limbs constants. All
    //    limb values are < 2^16 < P, so ctx.constant() is safe.

crates/circuits/src/blake.rs line 295 at r1 (raw file):

    //    limb values are < 2^16 < P, so ctx.constant() is safe.
    let mut h: [U32Var; 8] = std::array::from_fn(|i| {
        let iv_val = if i == 0 { BLAKE2S_IV[0] ^ 0x01010020 } else { BLAKE2S_IV[i] };

Document: (config: no key, 32 bytes output).


crates/circuits/src/blake.rs line 299 at r1 (raw file):

    });

    // 4. Compress each block.

remove the 4:


crates/circuits/src/blake.rs line 302 at r1 (raw file):

    for block_idx in 0..n_blocks {
        let block: [U32Var; 16] = std::array::from_fn(|i| message_u32s[block_idx * 16 + i]);
        let t = std::cmp::min(n_bytes, (block_idx + 1) * 64) as u64;

Document


crates/circuits/src/blake.rs line 305 at r1 (raw file):

        let last = block_idx == n_blocks - 1;

        let old_h = h;

current_h. it is not ols


crates/circuits/src/blake.rs line 308 at r1 (raw file):

        // Set up working vector: v[0..8] = h, v[8..16] = IV with counter/flag pre-XORed.
        let t_low = (t & 0xFFFFFFFF) as u32;

t can be u32 from the beginning


crates/circuits/src/blake.rs line 325 at r1 (raw file):

        // 10 rounds of mixing.
        for s in &BLAKE_SIGMA {

current_petmutation in &


crates/circuits/src/blake.rs line 326 at r1 (raw file):

        // 10 rounds of mixing.
        for s in &BLAKE_SIGMA {
            for g_idx in 0..8 {

8- const


crates/circuits/src/blake.rs line 328 at r1 (raw file):

            for g_idx in 0..8 {
                let [ai, bi, ci, di] = G_STATE_INDICES[g_idx];
                let (na, nb, nc, nd) = blake_g_gate(

new_a, new_b


crates/circuits/src/blake.rs line 337 at r1 (raw file):

                    block[s[g_idx * 2 + 1] as usize],
                );
                v[ai] = na;

can't we put it in the ouput directly?


crates/circuits/src/blake.rs line 346 at r1 (raw file):

        // Finalize current compress: h[i] = old_h[i] ^ v[i] ^ v[i+8].
        for i in 0..8 {
            h[i] = triple_xor_gate(ctx, old_h[i], v[i], v[i + 8]);

why do we put in h here and also do old_h = h ?
maybe it better to call it output


crates/circuits/src/blake.rs line 351 at r1 (raw file):

    // 5. Apply reduce_to_m31: extract low/high from packed limbs via Simd::unpack_idx, then low +
    //    high * 65536 in M31 arithmetic naturally reduces mod P.

Pack result in QM31

Code quote:

    // 5. Apply reduce_to_m31: extract low/high from packed limbs via Simd::unpack_idx, then low +
    //    high * 65536 in M31 arithmetic naturally reduces mod P.

crates/circuits/src/blake.rs line 352 at r1 (raw file):

    // 5. Apply reduce_to_m31: extract low/high from packed limbs via Simd::unpack_idx, then low +
    //    high * 65536 in M31 arithmetic naturally reduces mod P.
    let c65536 = ctx.constant(u32_to_qm31(65536));

call it 2^?

Code quote:

    let c65536 = ctx.constant(u32_to_qm31(65536));

crates/circuits/src/blake.rs line 354 at r1 (raw file):

    let c65536 = ctx.constant(u32_to_qm31(65536));
    let reduced: [Var; 8] = std::array::from_fn(|i| {
        let h_simd = Simd::from_packed(vec![*h[i].get()], 2);

maybe we can do all of them together?


crates/circuits/src/blake.rs line 360 at r1 (raw file):

    });

    // 6. Pack into 2 QM31 outputs.

remove the 6.


crates/circuits/src/blake_test.rs line 53 at r1 (raw file):

#[test]
fn test_blake_from_gates() {

Please add a test that tests this Blake independently, because we will remove the other Blake in the near future.
Can you use those values for the messgae:


assert random\_message\[1\] = 1766240503;

assert random\_message\[2\] = 3660871006;

assert random\_message\[3\] = 388409270;

assert random\_message\[4\] = 1948594622;

assert random\_message\[5\] = 3119396969;

assert random\_message\[6\] = 3924579183;

assert random\_message\[7\] = 2089920034;

assert random\_message\[8\] = 3857888532;

assert random\_message\[9\] = 929304360;

assert random\_message\[10\] = 1810891574;

assert random\_message\[11\] = 860971754;

assert random\_message\[12\] = 1822893775;

assert random\_message\[13\] = 2008495810;

assert random\_message\[14\] = 2958962335;

assert random\_message\[15\] = 2340515744;

crates/circuits/src/circuit.rs line 209 at r1 (raw file):

/// Represents a Blake2s G mixing function gate.
/// State words `a, b, c, d` are each a single QM31 wire with packed limbs: `(low_u16, high_u16,
/// 0, 0)`. Message words `m0, m1` are single M31 wires `(value, 0, 0, 0)`.

also the messgae is (low and high)


crates/circuits/src/circuit.rs line 225 at r1 (raw file):

impl BlakeGGate {
    /// Reconstructs a u32 from a packed-limbs QM31: `low + high * 65536`.
    fn unpack_u32(v: QM31) -> u32 {

This function is defined twice


crates/circuits/src/circuit.rs line 231 at r1 (raw file):

    /// Creates a packed-limbs QM31 from a u32: `(low_u16, high_u16, 0, 0)`.
    fn pack_u32(v: u32) -> QM31 {
        use crate::ivalue::qm31_from_u32s;

It doesn't make sense. just use the one that is outside the impl
use crate::ivalue::qm31_from_u32s;


crates/circuits/src/circuit.rs line 251 at r1 (raw file):

        d = (d ^ a).rotate_right(8);
        c = c.wrapping_add(d);
        b = (b ^ c).rotate_right(7);

This should be exorted to a function and not defined twice

Code quote:

        a = a.wrapping_add(b).wrapping_add(m0);
        d = (d ^ a).rotate_right(16);
        c = c.wrapping_add(d);
        b = (b ^ c).rotate_right(12);
        a = a.wrapping_add(b).wrapping_add(m1);
        d = (d ^ a).rotate_right(8);
        c = c.wrapping_add(d);
        b = (b ^ c).rotate_right(7);

crates/circuits/src/circuit.rs line 320 at r1 (raw file):

}

/// Converts an M31 value `(x, 0, 0, 0)` to a [`U32Wrapper`](crate::wrappers::U32Wrapper)

remove the

Code quote:

`U32Wrapper`](crate::wrappers::U32Wrapper)

crates/circuits/src/wrappers.rs line 72 at r1 (raw file):

/// Represents a u32 value stored as packed limbs in a QM31 wire: `(low_u16, high_u16, 0, 0)`.
#[derive(Clone, Copy, PartialEq)]
pub struct U32Wrapper<T>(T);

Can you explain why is this needed?

- Remove section header comments, numbered prefixes
- Extract blake_g_mixing() to deduplicate G mixing logic
- Extract read_u32() helper for U32Var -> u32 conversion
- Delete u32_to_qm31, use M31::from().into() directly
- Rename variables for clarity (prev_h, current_permutation, new_a/b/c/d)
- Extract constants (BLOCK_BYTES, WORDS_PER_BLOCK, N_G_CALLS_PER_ROUND)
- Fix docs (BlakeGGate message format, M31ToU32Gate, unpack_u32)
- Use crate::blake::{pack_u32, unpack_u32} in circuit.rs instead of duplicating
- Add independent test for blake_from_gates

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@alon-f
Copy link
Copy Markdown
Contributor Author

alon-f commented Mar 15, 2026

Review replies

Comment 4a (.0.0.0 getter) — No getter in stwo's QM31 — nested tuple structs. Same pattern used throughout the codebase. Changed 65536 to 1 << 16.

Comment 7 (U32Var input) — Done — added read_u32(ctx, v) helper.

Comment 8 (wrapping_add mode P?) — No, wrapping_add is mod 2^32 per Blake2s spec.

Comment 11 (batch Simd unpack) — Same number of gates either way, not an optimization.

Comment 19 (old_hcurrent_h) — Renamed to prev_h — clearer at the usage site since h is being overwritten during finalization.

Comment 24 (put in output directly) — Rust doesn't allow destructuring a tuple into array indices.

Comment 25 (why prev_h = h) — Blake2s finalization needs pre-compression h: h[i] = prev_h[i] ^ v[i] ^ v[i+8]. prev_h saves h before it gets overwritten.

Comment 28 (batch Simd reduce) — Same as 11 — same gate count either way.

Comment 36 (why U32Wrapper) — Type safety — marks that a Var holds packed-limbs (low_u16, high_u16, 0, 0), preventing accidental mixing with raw QM31 wires at compile time.

All other comments have been addressed in commit fb5024d.

alon-f and others added 2 commits March 15, 2026 13:28
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor Author

@alon-f alon-f left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alon-f made 36 comments.
Reviewable status: 2 of 8 files reviewed, 36 unresolved discussions (waiting on Gali-StarkWare, gilbens-starkware, ilyalesokhin-starkware, and Stavbe).


crates/circuits/src/blake.rs line 133 at r1 (raw file):

Previously, Stavbe wrote…

remove

Done.


crates/circuits/src/blake.rs line 164 at r1 (raw file):

Previously, Stavbe wrote…

remove

Done.


crates/circuits/src/blake.rs line 171 at r1 (raw file):

Previously, Stavbe wrote…

(limb_low, limb_high, 0, 0)

Done.


crates/circuits/src/blake.rs line 173 at r1 (raw file):

Previously, Stavbe wrote…

Replace the .0.0.0 it looks weird, don't we have getter for that?. Also please write the constant as 2^(

No getter in stwo's QM31 — nested tuple structs. Same pattern used throughout the codebase.


crates/circuits/src/blake.rs line 177 at r1 (raw file):

Previously, Stavbe wrote…

m31

Look at how the code looks now.


crates/circuits/src/blake.rs line 181 at r1 (raw file):

Previously, Stavbe wrote…

please remove

Done.


crates/circuits/src/blake.rs line 195 at r1 (raw file):

Previously, Stavbe wrote…

Why not updating the input for the helper function to be U32VAR

Done — added read_u32(ctx, v) helper.


crates/circuits/src/blake.rs line 202 at r1 (raw file):

Previously, Stavbe wrote…

it this mode P?

No, wrapping_add is mod 2^32 per Blake2s spec.


crates/circuits/src/blake.rs line 269 at r1 (raw file):

Previously, Stavbe wrote…

remove
and add all the comments that the other blake have

Done.


crates/circuits/src/blake.rs line 274 at r1 (raw file):

Previously, Stavbe wrote…

// Unpack each QM31 containing the messgae into U32Vars

Done.


crates/circuits/src/blake.rs line 277 at r1 (raw file):

Previously, Stavbe wrote…

Maybe we can do even more then 4 together

Same number of gates either way.


crates/circuits/src/blake.rs line 284 at r1 (raw file):

Previously, Stavbe wrote…

remove the 2.

Done.


crates/circuits/src/blake.rs line 285 at r1 (raw file):

Previously, Stavbe wrote…

const

Done.


crates/circuits/src/blake.rs line 286 at r1 (raw file):

Previously, Stavbe wrote…

const

Done.


crates/circuits/src/blake.rs line 293 at r1 (raw file):

Previously, Stavbe wrote…

Initlialize 'h'

Done.


crates/circuits/src/blake.rs line 295 at r1 (raw file):

Previously, Stavbe wrote…

Document: (config: no key, 32 bytes output).

Done.


crates/circuits/src/blake.rs line 299 at r1 (raw file):

Previously, Stavbe wrote…

remove the 4:

Done.


crates/circuits/src/blake.rs line 302 at r1 (raw file):

Previously, Stavbe wrote…

Document

Done


crates/circuits/src/blake.rs line 305 at r1 (raw file):

Previously, Stavbe wrote…

current_h. it is not ols

claude writes: Renamed to prev_h — clearer at the usage site since h is being overwritten.
I write: it's not current. the current h changes multiple times and we need the old h from before.


crates/circuits/src/blake.rs line 308 at r1 (raw file):

Previously, Stavbe wrote…

t can be u32 from the beginning

Done.


crates/circuits/src/blake.rs line 325 at r1 (raw file):

Previously, Stavbe wrote…

current_petmutation in &

(i write) I changed it to permutation. it's very weird to write current in a for loop. no one writes for current_i in range(n)


crates/circuits/src/blake.rs line 326 at r1 (raw file):

Previously, Stavbe wrote…

8- const

Done.


crates/circuits/src/blake.rs line 328 at r1 (raw file):

Previously, Stavbe wrote…

new_a, new_b

Done


crates/circuits/src/blake.rs line 337 at r1 (raw file):

Previously, Stavbe wrote…

can't we put it in the ouput directly?

Rust doesn't allow destructuring a tuple into array indices.


crates/circuits/src/blake.rs line 346 at r1 (raw file):

Previously, Stavbe wrote…

why do we put in h here and also do old_h = h ?
maybe it better to call it output

Blake2s finalization needs pre-compression h: h[i] = prev_h[i] ^ v[i] ^ v[i+8]. prev_h saves h before it gets overwritten.


crates/circuits/src/blake.rs line 351 at r1 (raw file):

Previously, Stavbe wrote…

Pack result in QM31

Done.


crates/circuits/src/blake.rs line 352 at r1 (raw file):

Previously, Stavbe wrote…

call it 2^?

Renamed to something else.


crates/circuits/src/blake.rs line 354 at r1 (raw file):

Previously, Stavbe wrote…

maybe we can do all of them together?

again, same gate count.


crates/circuits/src/blake.rs line 360 at r1 (raw file):

Previously, Stavbe wrote…

remove the 6.

Done.


crates/circuits/src/blake_test.rs line 53 at r1 (raw file):

Previously, Stavbe wrote…

Please add a test that tests this Blake independently, because we will remove the other Blake in the near future.
Can you use those values for the messgae:


assert random\_message\[1\] = 1766240503;

assert random\_message\[2\] = 3660871006;

assert random\_message\[3\] = 388409270;

assert random\_message\[4\] = 1948594622;

assert random\_message\[5\] = 3119396969;

assert random\_message\[6\] = 3924579183;

assert random\_message\[7\] = 2089920034;

assert random\_message\[8\] = 3857888532;

assert random\_message\[9\] = 929304360;

assert random\_message\[10\] = 1810891574;

assert random\_message\[11\] = 860971754;

assert random\_message\[12\] = 1822893775;

assert random\_message\[13\] = 2008495810;

assert random\_message\[14\] = 2958962335;

assert random\_message\[15\] = 2340515744;

Done.


crates/circuits/src/circuit.rs line 209 at r1 (raw file):

Previously, Stavbe wrote…

also the messgae is (low and high)

Done.


crates/circuits/src/circuit.rs line 225 at r1 (raw file):

Previously, Stavbe wrote…

This function is defined twice

Done.


crates/circuits/src/circuit.rs line 231 at r1 (raw file):

Previously, Stavbe wrote…

It doesn't make sense. just use the one that is outside the impl
use crate::ivalue::qm31_from_u32s;

Done.


crates/circuits/src/circuit.rs line 251 at r1 (raw file):

Previously, Stavbe wrote…

This should be exorted to a function and not defined twice

Done.


crates/circuits/src/circuit.rs line 320 at r1 (raw file):

Previously, Stavbe wrote…

remove the

Done.


crates/circuits/src/wrappers.rs line 72 at r1 (raw file):

Previously, Stavbe wrote…

Can you explain why is this needed?

Type safety — marks that a Var holds packed-limbs (low_u16, high_u16, 0, 0), preventing accidental mixing with raw QM31 wires at compile time.

@ilyalesokhin-starkware
Copy link
Copy Markdown
Contributor

crates/circuits/src/blake.rs line 284 at r3 (raw file):

/// For example, if `n_bytes` is 4, only the first coordinate of the [QM31] may be non-zero.
/// If `n_bytes` is 1, that coordinate must be < 256.
pub fn blake_from_gates(ctx: &mut TraceContext, input: &[Var], n_bytes: usize) -> HashValue<Var> {

Suggestion:

pub fn blake_from_gates<Value: IValue>(ctx: &mut Context<Value>, input: &[Var], n_bytes: usize) -> HashValue<Var>

Copy link
Copy Markdown
Collaborator

@Stavbe Stavbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Stavbe made 21 comments and resolved 35 discussions.
Reviewable status: 2 of 8 files reviewed, 23 unresolved discussions (waiting on alon-f, Gali-StarkWare, gilbens-starkware, and ilyalesokhin-starkware).


-- commits line 1 at r3:
need to be squash to one commit


crates/circuits/src/blake.rs line 163 at r3 (raw file):

    [2, 7, 8, 13],
    [3, 4, 9, 14],
];

Please take all the const to the top og file

Code quote:

pub const BLAKE2S_IV: [u32; 8] = [
    0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
];
    [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
];

const N_G_CALLS_PER_ROUND: usize = 8;

/// The 8 (a,b,c,d) state index tuples per round: 4 columns then 4 diagonals.
pub const G_STATE_INDICES: [[usize; 4]; 8] = [
    [0, 4, 8, 12],
    [1, 5, 9, 13],
    [2, 6, 10, 14],
    [3, 7, 11, 15],
    [0, 5, 10, 15],
    [1, 6, 11, 12],
    [2, 7, 8, 13],
    [3, 4, 9, 14],
];

crates/circuits/src/blake.rs line 176 at r3 (raw file):

}

/// Computes one Blake2s G mixing step on u32 values: two half-rounds of add+xor+rotate.

/// Computes Blake G.

Code quote:

/// Computes one Blake2s G mixing step on u32 values: two half-rounds of add+xor+rotate

crates/circuits/src/blake.rs line 177 at r3 (raw file):

/// Computes one Blake2s G mixing step on u32 values: two half-rounds of add+xor+rotate.
pub fn blake_g_mixing(

blak_g

Code quote:

blake_g_mixing

crates/circuits/src/blake.rs line 196 at r3 (raw file):

}

type U32Var = U32Wrapper<Var>;

I am not sure this is the right place to define it.

Code quote:

type U32Var = U32Wrapper<Var>;

crates/circuits/src/blake.rs line 200 at r3 (raw file):

/// Reads a [`U32Var`] from the context and unpacks it to a u32.
fn read_u32(ctx: &TraceContext, v: U32Var) -> u32 {
    unpack_u32(ctx.get(*v.get()))

I don't think this function is called anywhere else but from here, so you can write the unpacking inline.

Code quote:

 unpack_u32(ctx.get(*v.get()))

crates/circuits/src/blake.rs line 277 at r3 (raw file):

}

/// Adds a blake hash using decomposed gates to the circuit, and returns the two output variables

BlakeG gate, TripleXor gate and M31ToU32)

Code quote:

 decomposed gates

crates/circuits/src/blake.rs line 277 at r3 (raw file):

}

/// Adds a blake hash using decomposed gates to the circuit, and returns the two output variables

Please also mention the reduction that occurr to output (it is not a regular blake)3q


crates/circuits/src/blake.rs line 308 at r3 (raw file):

    // Initialize h: IV XORed with the parameter block.
    // 0x01010020: depth=1, fanout=1, key_length=0, digest_length=32.

move this doc above the value

Code quote:

 // 0x01010020: depth=1, fanout=1, key_length=0, digest_length=32.

crates/circuits/src/blake.rs line 366 at r3 (raw file):

    }

    // Pack result in QM31.

// Reduce each U32Var to M31.

Code quote:

  // Pack result in QM31.

crates/circuits/src/blake_test.rs line 82 at r3 (raw file):

#[test]
fn test_blake_from_gates_independent() {

remove

Code quote:

_independent

crates/circuits/src/circuit.rs line 225 at r3 (raw file):

impl Gate for BlakeGGate {
    fn check(&self, values: &[QM31]) -> Result<(), String> {
        use crate::blake::{blake_g_mixing, pack_u32, unpack_u32};

Please move to the top of the file

Code quote:

  use crate::blake::{blake_g_mixing, pack_u32, unpack_u32};

crates/circuits/src/circuit.rs line 281 at r3 (raw file):

impl Gate for TripleXorGate {
    fn check(&self, values: &[QM31]) -> Result<(), String> {
        use crate::blake::{pack_u32, unpack_u32};

move the top of the file

Code quote:

 use crate::blake::{pack_u32, unpack_u32};

crates/circuits/src/circuit.rs line 303 at r3 (raw file):

}

/// Converts an M31 value `(x, 0, 0, 0)` to packed-limbs representation `(low_u16, high_u15, 0, 0)`,

Represent a ... gate


crates/circuits/src/circuit.rs line 314 at r3 (raw file):

        let input = values[self.input];
        if input.0.1.0 != 0 || input.1.0.0 != 0 || input.1.1.0 != 0 {
            return Err(format!("SplitM31: input coords 1-3 not zero, got {input}"));

M31ToU32Gate: Expected M31, but got {input}.

Code quote:

"SplitM31: input coords 1-3 not zero, got {input}"

crates/circuits/src/circuit.rs line 319 at r3 (raw file):

        let out = values[self.out];
        if out.1.0.0 != 0 || out.1.1.0 != 0 {
            return Err(format!("SplitM31: output coords 2-3 not zero, got {out}"));

[M31ToU32Gate: Expected U32, but got {out}

Code quote:

"SplitM31: output coords 2-3 not zero, got {out}"

crates/circuits/src/circuit.rs line 323 at r3 (raw file):

        let low = out.0.0.0;
        let high = out.0.1.0;
        if low + high * 65536 != x {

2^ ?

Code quote:

 65536

crates/circuits/src/circuit.rs line 324 at r3 (raw file):

        let high = out.0.1.0;
        if low + high * 65536 != x {
            return Err(format!("SplitM31: {low} + {high} * 65536 != {x}"));

same

Code quote:

65536

crates/circuits/src/circuit.rs line 324 at r3 (raw file):

        let high = out.0.1.0;
        if low + high * 65536 != x {
            return Err(format!("SplitM31: {low} + {high} * 65536 != {x}"));

Name of the gate

Code quote:

SplitM31

crates/circuits/src/circuit.rs line 327 at r3 (raw file):

        }
        if low >= (1 << 16) {
            return Err(format!("SplitM31: low {low} >= 2^16"));

fix

Code quote:

"SplitM31

crates/circuits/src/circuit.rs line 330 at r3 (raw file):

        }
        if high >= (1 << 15) {
            return Err(format!("SplitM31: high {high} >= 2^15"));

fix

Code quote:

"SplitM31

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants