Skip to content

Conversation

@dreamATD
Copy link
Collaborator

Description

Sha extend circuit

This PR adds sha extend precompile, computing the parameter w[0..64] defined as follows:

// w[0..16] are copied from the input
for i in 16..64 {
    let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
    let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
    w[i] = w[i - 16]
        .wrapping_add(s0)
        .wrapping_add(w[i - 7])
        .wrapping_add(s1);
}

The sha extend circuit consists of 48 cycles. In each cycle, it fetches the instruction at the same pc as the first cycle, reads the same register, and defines the global state with increasing cycles. I each instance, it reads w[i - 2], w[i - 7], w[i - 15], w[i - 16] from the memory and computes w[i] and writes it back.

Support multi-cycle instruction in ceno_emul

To support multi-cycle instruction in ceno_emul, we store a Option<MultiCycleState> object pending_multi_cycle_insn in VMState, and if it is Some(insn, state), we generate the next step from state.

Support rotation with length 63

Since the number of rounds in SHA256 is 64, we support the 63-element cycle defined by X^6 + X + 1. The indices could be generated by the following sage code:

F2 = GF(2)
R.<x> = PolynomialRing(F2)
f = x^6 + x + 1
f.is_irreducible()

def poly_to_bits(index, p, n=6):
    """
    p: polynomial in GF(2)[x], degree < n
    returns string like 0b010101
    """
    coeffs = p.list()              # [c0, c1, c2, ...]
    bits = [(coeffs[i] if i < len(coeffs) else 0) for i in range(n)]
    value = sum(int(bits[i]) << i for i in range(n))
    return "0b" + format(value, f"0{n}b") + f", // {index} = decimal {value}"

K.<a> = R.quotient(f)
for i in range(65):
    p = (a^i).lift()
    print(f"{poly_to_bits(i, p)}")

Tiny change of SelectTypeLayout

The original definition is as follows:

#[derive(Clone, Debug)]
pub struct SelectorTypeLayout<E: ExtensionField> {
    pub sel_mem_read: SelectorType<E>,
    pub sel_mem_write: SelectorType<E>,
    pub sel_lookup: SelectorType<E>,
    pub sel_zero: SelectorType<E>,
}

while they are sometimes duplicated and in sha extend circuit, it needs to set round_i = 16 in the first round and update pc during the last round. Therefore, the definition is changed as follows:

#[derive(Clone, Debug)]
pub struct SelectorTypeLayout<E: ExtensionField> {
    pub sel_first: Option<SelectorType<E>>,
    pub sel_last: Option<SelectorType<E>>,
    pub sel_all: SelectorType<E>,
}

@dreamATD dreamATD force-pushed the precompiles/sha256 branch 3 times, most recently from 1df7726 to e8efcb6 Compare December 31, 2025 19:33
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.

2 participants