Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
884c5ad
spec/EC: introduce ECSM
erik-3milabs May 29, 2026
1c274bd
spec/ECSM: introduce EC_SCALAR
erik-3milabs Jun 2, 2026
d2d08d8
spec/ECSM: introduce ECDAS
erik-3milabs Jun 3, 2026
3a46d5a
spec/ECSM: two carry proofs
erik-3milabs Jun 3, 2026
bd64b62
spec/ECSM: update lemma
erik-3milabs Jun 4, 2026
d098975
spec/ECSM: carry computation tool
erik-3milabs Jun 4, 2026
47a5be3
spec/ECSM: fix lint issues
erik-3milabs Jun 5, 2026
b9530a9
spec/ECSM: update extension names
erik-3milabs Jun 5, 2026
5ae2283
spec/ECSM: update introduction
erik-3milabs Jun 5, 2026
e3848b5
Spec/ECSM: update ecsm to work with offsets
erik-3milabs Jun 5, 2026
fe4e3dd
spec/ECDAS: update non-inf argumentation
erik-3milabs Jun 8, 2026
7e12156
spec: fix cwrap for repeated subtractions
erik-3milabs Jun 8, 2026
7988057
spec/ECSM: tweaks and fixes
erik-3milabs Jun 9, 2026
6db8da4
spec/ECSM: fix scalar read/serve timestamp
erik-3milabs Jun 9, 2026
aab3904
spec/ecsm: more tweaks and fixes
erik-3milabs Jun 9, 2026
0a9d87e
spec/ECSM: update carries
erik-3milabs Jun 9, 2026
d9a1c3e
spec/ECSM: drop carry.py
erik-3milabs Jun 9, 2026
33d65ea
Apply suggestions from code review
erik-3milabs Jun 9, 2026
bac746b
Update spec/ecsm.typ
erik-3milabs Jun 9, 2026
f604cd5
spec/ECSM: fix incorrect carry index
erik-3milabs Jun 9, 2026
18a815a
spec/ECSM: fix recursive `SERVE_K` multiplicity
erik-3milabs Jun 9, 2026
d7cefb2
spec/ECSM: define padding
erik-3milabs Jun 9, 2026
1b4a50d
spec/ECSM: fix missing trailing emptyline
erik-3milabs Jun 9, 2026
1764697
spec/ECDAS: fix missing multiplicity range check
erik-3milabs Jun 11, 2026
93c7eb0
spec/ECDAS: fix BIT-interaction multiplicity negation
erik-3milabs Jun 11, 2026
33e846e
spec/ECSM: fix padding bug
erik-3milabs Jun 11, 2026
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
3 changes: 2 additions & 1 deletion spec/about_ecalls.typ
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ Negative numbers (represented as 2s complement 64-bit numbers), are used for our
/ 64: `write` (@commit)
/ 93: `exit` (@halt)
/ -1: `SHA256` (@sha256)
/ -2: `KECCAK` (@keccak)
/ -2: `KECCAK` (@keccak)
/ -3: `ECSM` (@ecsm)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe interesting to make this -11 instead, so that we essentially reserve some extra space for more hashes?

1 change: 1 addition & 0 deletions spec/book.typ
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
("commit.typ", [`COMMIT` chip], <commit>),
("sha256.typ", [`SHA256` accelerator], <sha256>),
("keccak.typ", [`KECCAK` accelerator], <keccak>),
("ecsm.typ", [`ECSM` accelerator], <ecsm>),
))
)
)
Expand Down
453 changes: 453 additions & 0 deletions spec/ecsm.typ

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion spec/expr.typ
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
cwrap(`-` + rec(PREC.neg, e.at(1)), pp < PREC.neg)
} else {
// Subtraction
cwrap(e.slice(1).map(rec.with(PREC.sub)).join(` - `), pp < PREC.sub)
cwrap(e.slice(1).map(rec.with(PREC.sub)).join(` - `), pp <= PREC.sub)
}
},
"cast": (pp, rec, e) => {
Expand Down
32 changes: 32 additions & 0 deletions spec/src/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,38 @@ desc = """\
Represented as an array of four `Word` variables.\
"""

[[variables.types]]
label = "U256BL"
subtypes = ["Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte"]
desc = """\
Variable that can only assume values in the range $[0, 2^256)$. \\
Represented as an array of thirty-two `Byte` variables.\
"""

[[variables.types]]
label = "U256HL"
subtypes = ["Half", "Half", "Half", "Half", "Half", "Half", "Half", "Half", "Half", "Half", "Half", "Half", "Half", "Half", "Half", "Half"]
desc = """\
Variable that can only assume values in the range $[0, 2^256)$. \\
Represented as an array of sixteen `Half` variables.\
"""

[[variables.types]]
label = "U256WL"
subtypes = ["Word", "Word", "Word", "Word", "Word", "Word", "Word", "Word"]
desc = """\
Variable that can only assume values in the range $[0, 2^256)$. \\
Represented as an array of eight `Word` variables.\
"""

[[variables.types]]
label = "U512BL"
subtypes = ["Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte", "Byte"]
desc = """\
Variable that can only assume values in the range $[0, 2^512)$. \\
Represented as an array of sixty-four `Byte` variables.\
"""

[[variables.types]]
label = "Timestamp"
subtypes = ["DWordWL"]
Expand Down
117 changes: 117 additions & 0 deletions spec/src/ec_scalar.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name = "EC_SCALAR"

[[variables.input]]
name = "timestamp"
type = "DWordWL"
desc = "timestamp at which to serve the constant"
pad = 0

[[variables.input]]
name = "ptr"
type = "DWordWL"
desc = "pointer to the first byte of the scalar"
pad = 0
Comment on lines +9 to +13

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why are we doing a bunch of MEMWs in this chip? The calling ECSM has already read all of K into byte limbs, so we can just take in the limb as input and decompose it, right?

I guess the reason is that EC_SCALAR recurses onto itself, reducing the interactions in the ECSM table, but I think for total area it'd be better feed in the bytes directly; at which point, there may be some tradeoff between how many bits EC_SCALAR does at once for width vs depth, but again probably total area tells us to just make it 256 wide?
In the case 256 columns wide wouldn't be the right call, just making multiple calls into EC_SCALAR from ECSM should nevertheless still be the same area cost as the recursion, but simpler because there's no recursion logic to be performed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There may even be some approach where we avoid the recursion of ECDAS as well, and simply let the EC_SCALAR chip emit the sequence of double/add steps that need to be performed. Not entirely sure if that wouldn't introduce too many more interactions atm, but it's potentially cleaner than having to reason about the recursion stopping.


[[variables.input]]
name = "offset"
type = "Byte"
desc = "index of limb"
pad = 0

[[variables.auxiliary]]
name = "limb_bits"
type = ["Bit", 8]
desc = "bit-decomposition of the limb being read"
pad = ["arr", 0, 0, 0, 0, 0, 0, 0, 0]

[[variables.auxiliary]]
name = "last_limb"
type = "Bit"
desc = "whether this is the last limb to read"
pad = 0

[[variables.virtual]]
name = "limb"
type = "Byte"
desc = "limb being read"
def = {poly=["sum", ["=", "i", 0], 7, ["*", ["^", 2, "i"], ["idx", "limb_bits", "i"]]]}

[[variables.multiplicity]]
name = "μ"
type = "Bit"
desc = ""
pad = 0

[[assumptions]]
desc = "$#`ptr` + #`offset`$ does not overflow the bottom limb"

[[constraint_groups]]
name = "recv"

[[constraints.recv]]
kind = "interaction"
tag = "SERVE_K"
input = ["timestamp", "ptr", "offset"]
multiplicity = ["-", "μ"]

[[constraints.recv]]
kind = "template"
tag = "IS_BIT"
input = ["μ"]

[[constraint_groups]]
name = "read"

[[constraints.read]]
kind = "interaction"
tag = "MEMW"
input = [0, ["+", "ptr", ["arr", ["cast", "offset", "Word"], 0]], ["arr", "limb", 0, 0, 0, 0, 0, 0, 0], ["+", "timestamp", ["cast", 1, "DWordWL"]], 0, 0, 0]
output = ["arr", "limb", 0, 0, 0, 0, 0, 0, 0]
multiplicity = "μ"

[[constraints.read]]
kind = "template"
tag = "IS_BIT"
input = [["idx", "limb_bits", "i"]]
iter = ["i", 0, 7]


[[constraint_groups]]
name = "serve"

[[constraints.serve]]
kind = "interaction"
tag = "BIT"
input = ["timestamp", ["+", ["*", 8, "offset"], "i"]]
iter = ["i", 0, 7]
multiplicity = ["idx", "limb_bits", "i"]

[[constraints.serve]]
kind = "arith"
constraint = "$#`limb_bits`_i = 1 => #`μ` = 1$"
poly = ["*", ["idx", "limb_bits", "i"], ["not", "μ"]]
iter = ["i", 0, 7]

[[constraint_groups]]
name = "recurse"

[[constraints.recurse]]
kind = "template"
tag = "IS_BIT"
input = ["last_limb"]

[[constraints.recurse]]
kind = "arith"
constraint = "$#`last_limb` = 1 => #`μ` = 1$"
poly = ["*", "last_limb", ["not", "μ"]]

[[constraints.recurse]]
kind = "arith"
constraint = "$#`last_limb` = 1 => #`offset` = 0$"
poly = ["*", "last_limb", "offset"]

[[constraints.recurse]]
kind = "interaction"
tag = "SERVE_K"
input = ["timestamp", "ptr", ["-", "offset", 1]]
multiplicity = ["-", "μ", "last_limb"]
Loading
Loading