diff --git a/spec/keccak.typ b/spec/keccak.typ index e6e16f43f..11d900c73 100644 --- a/spec/keccak.typ +++ b/spec/keccak.typ @@ -105,6 +105,11 @@ Lastly, the round chip contributes the following interactions to the lookup: == Notes/potential optimizations - one does not have to repeat `addr` in `state_ptr`; this saves 4 columns and 4 `IS_HALF` checks. - step $rho$ does not need to be applied to `state[0][0]`; its has a zero-shift. This saves 16 columns and 4 `HWSL` interactions. +- when the output of `HWSL` are `Byte`s mapped as `Half`s, we find that out of every four output bytes, at least one is zero. + Since `rnc` is constant, @keccak:c:rho_rotation makes those zero-bytes show up in `rot_left` and `rot_right` at constant locations. + This means 96 columns can be removed from the chip at no cost. + Likewise, 96 `IS_BYTE` interactions can be dropped from @keccak:c:range_rot_left and @keccak:c:range_rot_right. + - the shift-constants are equivalent to $1 mod 16$ for $(#`x`, #`y`) = (1, 0)$ and $-1 mod 16$ for $(2, 3)$. This means that for those lanes it suffices to constrain `rot_left`/`rot_right` as `Bit`s rather than `Byte`s, saving an additional 8 `IS_BYTE` interactions. - $#`rc[2]` = #`rc[4]` = #`rc[5]` = #`rc[6]` = 0$. As such, those elements need not be stored in `rc`, and need not be XORed into the state in the $iota$-step. This saves 8 columns and 4 `XOR_BYTE` interactions. - when executed in large volumnes, `KECCAK_RND` could benefit from having a three-way XOR lookup table. With this in place, the 80 interactions in @keccak:c:theta_cxz_start and @keccak:c:theta_cxz could be dropped. Likewise, 80 columns could be removed from the chip (a \~5% savings). diff --git a/spec/src/keccak.toml b/spec/src/keccak.toml index b8f2d91c2..1c3bade44 100644 --- a/spec/src/keccak.toml +++ b/spec/src/keccak.toml @@ -48,7 +48,7 @@ name = "output" [[constraints.output]] kind = "interaction" tag = "ECALL" -input = ["timestamp", ["arr", ["-", ["^", 2, 32], 1], ["-", ["^", 2, 32], 2]]] +input = ["timestamp", ["cast", ["-", ["^", 2, 64], 2], "DWordWL"]] multiplicity = ["-", "μ"] [[constraint_groups]] diff --git a/spec/src/keccak_round.toml b/spec/src/keccak_round.toml index d41b7c472..59daba923 100644 --- a/spec/src/keccak_round.toml +++ b/spec/src/keccak_round.toml @@ -28,8 +28,8 @@ desc = "the left-rotated component of `rotated_Cxz`" [[variables.auxiliary]] name = "Cxz_right" -type = [["Byte", 8], 5] -desc = "the right-rotated component of `rotated_Cxz`" +type = [["Bit", 4], 5] +desc = "the right-rotated component of `rotated_Cxz` (which is a single bit)" [[variables.auxiliary]] name = "Dxz" @@ -75,7 +75,16 @@ desc = "state update following from step $iota$." name = "rotated_Cxz" type = [["Byte", 8], 5] desc = "$#`Cxz[x,`3#`,z]` <<< 1$" -def = {iters=[["x", 0, 4], ["z", 0, 7]], poly=["+", ["idx", ["idx", "Cxz_left", "x"], "z"], ["idx", ["idx", "Cxz_right", "x"], ["mod", ["-", "z", 1], 8]]]} +def = {polys=[ + {iters=[["x", 0, 4], ["z", 0]], poly=["+", ["idx", ["idx", "Cxz_left", "x"], "z"], ["idx", ["idx", "Cxz_right", "x"], 3]]}, + {iters=[["x", 0, 4], ["z", 1]], poly=["idx", ["idx", "Cxz_left", "x"], "z"]}, + {iters=[["x", 0, 4], ["z", 2]], poly=["+", ["idx", ["idx", "Cxz_left", "x"], "z"], ["idx", ["idx", "Cxz_right", "x"], 0]]}, + {iters=[["x", 0, 4], ["z", 3]], poly=["idx", ["idx", "Cxz_left", "x"], "z"]}, + {iters=[["x", 0, 4], ["z", 4]], poly=["+", ["idx", ["idx", "Cxz_left", "x"], "z"], ["idx", ["idx", "Cxz_right", "x"], 1]]}, + {iters=[["x", 0, 4], ["z", 5]], poly=["idx", ["idx", "Cxz_left", "x"], "z"]}, + {iters=[["x", 0, 4], ["z", 6]], poly=["+", ["idx", ["idx", "Cxz_left", "x"], "z"], ["idx", ["idx", "Cxz_right", "x"], 2]]}, + {iters=[["x", 0, 4], ["z", 7]], poly=["idx", ["idx", "Cxz_left", "x"], "z"]}, +]} [[variables.virtual]] name = "out" @@ -91,7 +100,7 @@ def = {polys=[ [[variables.virtual]] name = "rho" type = [[["Byte", 8], 5], 5] -desc = "$(rho compose theta)(#`start`)$; the state state after applying $rho$" +desc = "$(rho compose theta)(#`start`)$; the state after applying $rho$" def = {iters=[["x", 0, 4], ["y", 0, 4], ["z", 0, 7]], poly=[ "+", ["*", @@ -99,7 +108,7 @@ def = {iters=[["x", 0, 4], ["y", 0, 4], ["z", 0, 7]], poly=[ ["not", ["idx", ["idx", ["idx", "rbc", "x"], "y"], 1]], ["+", ["idx", ["idx", ["idx", "rot_left", "x"], "y"], "z"], - ["idx", ["idx", ["idx", "rot_right", "x"], "y"], ["mod", ["-", "z", 1], 8]], + ["idx", ["idx", ["idx", "rot_right", "x"], "y"], ["mod", ["-", "z", 2], 8]], ] ], ["*", @@ -107,7 +116,7 @@ def = {iters=[["x", 0, 4], ["y", 0, 4], ["z", 0, 7]], poly=[ ["not", ["idx", ["idx", ["idx", "rbc", "x"], "y"], 1]], ["+", ["idx", ["idx", ["idx", "rot_left", "x"], "y"], ["mod", ["-", "z", 2], 8]], - ["idx", ["idx", ["idx", "rot_right", "x"], "y"], ["mod", ["-", "z", 3], 8]], + ["idx", ["idx", ["idx", "rot_right", "x"], "y"], ["mod", ["-", "z", 4], 8]], ] ], ["*", @@ -115,7 +124,7 @@ def = {iters=[["x", 0, 4], ["y", 0, 4], ["z", 0, 7]], poly=[ ["idx", ["idx", ["idx", "rbc", "x"], "y"], 1], ["+", ["idx", ["idx", ["idx", "rot_left", "x"], "y"], ["mod", ["-", "z", 4], 8]], - ["idx", ["idx", ["idx", "rot_right", "x"], "y"], ["mod", ["-", "z", 5], 8]], + ["idx", ["idx", ["idx", "rot_right", "x"], "y"], ["mod", ["-", "z", 6], 8]], ] ], ["*", @@ -123,7 +132,7 @@ def = {iters=[["x", 0, 4], ["y", 0, 4], ["z", 0, 7]], poly=[ ["idx", ["idx", ["idx", "rbc", "x"], "y"], 1], ["+", ["idx", ["idx", ["idx", "rot_left", "x"], "y"], ["mod", ["-", "z", 6], 8]], - ["idx", ["idx", ["idx", "rot_right", "x"], "y"], ["mod", ["-", "z", 7], 8]], + ["idx", ["idx", ["idx", "rot_right", "x"], "y"], "z"], ] ], ]} @@ -202,7 +211,10 @@ ref = "keccak:c:theta_cxz" kind = "interaction" tag = "HWSL" input = [["idx", ["cast", ["idx", ["idx", "Cxz", "x"], 3], "DWordHL"], "z"], 1] -output = ["arr", ["idx", ["cast", ["idx", "Cxz_left", "x"], "DWordHL"], "z"], ["idx", ["cast", ["idx", "Cxz_right", "x"], "DWordHL"], "z"]] +output = ["arr", + ["idx", ["cast", ["idx", "Cxz_left", "x"], "DWordHL"], "z"], + ["cast", ["idx", ["idx", "Cxz_right", "x"], "z"], "Half"] +] iters = [["x", 0, 4], ["z", 0, 3]] multiplicity = "μ" @@ -219,10 +231,9 @@ cond = "μ" [[constraints.theta]] kind = "template" -tag = "IS_BYTE" +tag = "IS_BIT" input = [["idx", ["idx", "Cxz_right", "x"], "z"]] -iters = [["x", 0, 4], ["z", 0, 7]] -cond = "μ" +iters = [["x", 0, 4], ["z", 0, 3]] [[constraints.theta]] kind = "interaction" @@ -251,6 +262,7 @@ input = [["idx", ["cast", ["idx", ["idx", "theta", "x"], "y"], "DWordHL"], "z"], output = ["arr", ["idx", ["cast", ["idx", ["idx", "rot_left", "x"], "y"], "DWordHL"], "z"], ["idx", ["cast", ["idx", ["idx", "rot_right", "x"], "y"], "DWordHL"], "z"]] iters = [["x", 0, 4], ["y", 0, 4], ["z", 0, 3]] multiplicity = "μ" +ref = "keccak:c:rho_rotation" # Note: these IS_BYTE checks are necessary. # Without them, it is possible to prove 0 <<< S evaluates to -1 by setting @@ -260,8 +272,9 @@ multiplicity = "μ" kind = "template" tag = "IS_BYTE" input = [["idx", ["idx", ["idx", "rot_left", "x"], "y"], "z"]] -iters = [["x", 0, 4], ["y", 0, 4], ["z", 0, 7]] +iters = [["x", 0, 4], ["y", 0, 4], ["z", 0, 7]] cond = "μ" +ref = "keccak:c:range_rot_left" [[constraints.rho]] kind = "template" @@ -269,6 +282,7 @@ tag = "IS_BYTE" input = [["idx", ["idx", ["idx", "rot_right", "x"], "y"], "z"]] iters = [["x", 0, 4], ["y", 0, 4], ["z", 0, 7]] cond = "μ" +ref = "keccak:c:range_rot_right" [[constraint_groups]] name = "chi" diff --git a/spec/src/sha256.toml b/spec/src/sha256.toml index 78d022515..59d710998 100644 --- a/spec/src/sha256.toml +++ b/spec/src/sha256.toml @@ -266,5 +266,5 @@ input = ["μ"] [[constraints.lookup]] kind = "interaction" tag = "ECALL" -input = ["timestamp", ["arr", ["-", ["^", 2, 32], 1], ["-", ["^", 2, 32], 1]]] +input = ["timestamp", ["cast", ["-", ["^", 2, 64], 1], "DWordWL"]] multiplicity = ["-", "μ"]