Replies: 7 comments 25 replies
-
There are couple of advantages of not doing a DSL;
That being said, as you pointed out, a DSL can lead to better ergonomics & even in some cases (but not always) enable some frontend optimisations by providing more context to the compiler. I think we should evolve gnark in a way that "plugging" different frontends or DSL (like CsGo, CirC or Noir: https://github.com/lambdaclass/noir_backend_using_gnark ), is straightforward, and if at some point the DSL ecosystem is mature enough, look for tighter integration. |
Beta Was this translation helpful? Give feedback.
-
Hi @aybehrouz , thanks for the writeup, when you say "declaring polynomial constraint systems", do you mean custom gates? Like a generalisation of plonk where the constraints definition is up to the user, for instance instead of having So far the solution that seems the most flexible is to let the user register a function If you look at the way the plonk prover is implemented on the |
Beta Was this translation helpful? Give feedback.
-
Yup, in some contexts it would really benefit to have some DSL. In my case when I implemented field emulation then I'd prefer to know if any variable is used later as an input to other operations or not and use this information to ensure/avoid modular reductions. But it seemed too complicated vs. exposing different variations of the operations ( |
Beta Was this translation helpful? Give feedback.
-
Another important issue that we should consider here is portability. Let's say I have a complex circuit, and Implementing/declaring it takes a lot time. Certainly I'd prefer to implement/describe this circuit in a way that is not coupled with a backend, so I can easily use different proof systems or even different implementations of the same proof system. A DSL can be designed to be proof system agnostic. The compilers can be written to support targeting different backends, or even backend implementers may decide to provide special compilers for some DSLs. On the other hand an API is usually coupled with its backend, unless we use some smart hacks. For example we should add the ability to generate some type of intermediate representation (IR) of the circuit, which is compatible with other backends/implementations. (This is actually some type of DSL usage, since an IR is a low level DSL) However an IR which is supported by different backends may not be available always. |
Beta Was this translation helpful? Give feedback.
-
@ivokub @gbotrel func stepMask(api frontend.API, outputLen int,
stepPosition, startValue, endValue csv) []csv {
if outputLen < 2 {
panic("the output len of StepMask must be >= 2")
}
// get the output as a hint
out, err := api.Compiler().NewHint(stepOutput, outputLen, stepPosition, startValue, endValue)
if err != nil {
panic(fmt.Sprintf("error in calling StepMask hint: %v", err))
}
// add the boundary constraints:
(out[0] - startValue) * stepPosition === 0
(out[len(out)-1] - endValue) * (len(out) - stepPosition) === 0
// add constraints for the correct form of a step function that steps at the stepPosition
for i := 1; i < len(out); i++ {
(out[i] - out[i-1]) * (i - stepPosition) === 0
}
return out
} ...and it gets converted to this, which is exactly like the original source code: func stepMask(api frontend.API, outputLen int,
stepPosition, startValue, endValue frontend.Variable) []frontend.Variable {
if outputLen < 2 {
panic("the output len of StepMask must be >= 2")
}
// get the output as a hint
out, err := api.Compiler().NewHint(stepOutput, outputLen, stepPosition, startValue, endValue)
if err != nil {
panic(fmt.Sprintf("error in calling StepMask hint: %v", err))
}
// add the boundary constraints:
api.AssertIsEqual(api.Mul(api.Sub(out[0], startValue), stepPosition), 0)
api.AssertIsEqual(api.Mul(api.Sub(out[len(out)-1], endValue), api.Sub(len(out), stepPosition)), 0)
// add constraints for the correct form of a step function that steps at the stepPosition
for i := 1; i < len(out); i++ {
api.AssertIsEqual(api.Mul(api.Sub(out[i], out[i-1]), api.Sub(i, stepPosition)), 0)
}
return out
} |
Beta Was this translation helpful? Give feedback.
-
an idea that cross my mind few times is to use something like that a bit like scripting languages (like Lua) in game engine; i.e have an interpreter that runs in your process to parse these snippets. Not talking too much on this thread because I personally prefer this with IDE auto complete across the projects, in tests etc:
than having a script that transpiles my circuit each time I do a modif on it 🙄 |
Beta Was this translation helpful? Give feedback.
-
Very intersting subject, I started tackling this, but instead of creating a language, reusing an existing one (https://dhall-lang.org/#). let State = { dummy : Natural, counter : Natural }
let Message = < One | Ten | Hundred >
let Cpu =
{ load :
forall (State : Type) ->
forall (Message : Type) ->
{ state : State, message : Message }
, save : forall (State : Type) -> State -> {}
}
in \(cpu : Cpu) ->
let input = cpu.load State Message
in cpu.save
State
{ dummy = input.state.dummy + input.state.counter + 1
, counter =
input.state.counter
+ merge { One = 1, Ten = 10, Hundred = 100 } input.message
}
The interface is simple, you define a
|
Beta Was this translation helpful? Give feedback.
-
I've written a description for a language that is inspired by gnark's API, and can be used for declaring polynomial constraint systems. I call it CsGo: Constraint systems with Go! It is very similar to the current gnark's API. However, it can improve ergonomics and clarify semantics. I'd love to know what you think and have some feedback from you. The document is still a draft and likely has lots of errors! 😅
My idea is to write a transpiler that translates CsGo code to gnark code. I believe that would be relatively easy, since they are very close. The CsGo transpiler could be added to gnark and users could optionally use it if they want to. Some gnark's users may prefer using a domain specific language.
Github repo:
https://github.com/aybehrouz/csgo/tree/main
Beta Was this translation helpful? Give feedback.
All reactions