mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 10:27:26 +08:00
* v2.1.0 [omit consensus and adjacent] - this commit will be amended with the full release after the file copy is complete * 2.1.0 main node rollup
133 lines
2.7 KiB
Go
133 lines
2.7 KiB
Go
//
|
|
// gates.go
|
|
//
|
|
// Copyright (c) 2019-2023 Markku Rossi
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
|
|
package circuits
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
|
|
)
|
|
|
|
// Gate implements binary gates.
|
|
type Gate struct {
|
|
Op circuit.Operation
|
|
Visited bool
|
|
Compiled bool
|
|
Dead bool
|
|
A *Wire
|
|
B *Wire
|
|
O *Wire
|
|
}
|
|
|
|
func (g *Gate) String() string {
|
|
return fmt.Sprintf("%s %x %x %x", g.Op, g.A.ID(), g.B.ID(), g.O.ID())
|
|
}
|
|
|
|
// Visit adds gate to the list of pending gates to be compiled.
|
|
func (g *Gate) Visit(cc *Compiler) {
|
|
switch g.Op {
|
|
case circuit.INV:
|
|
if !g.Dead && !g.Visited && g.A.Assigned() {
|
|
g.Visited = true
|
|
cc.pending = append(cc.pending, g)
|
|
}
|
|
|
|
default:
|
|
if !g.Dead && !g.Visited && g.A.Assigned() && g.B.Assigned() {
|
|
g.Visited = true
|
|
cc.pending = append(cc.pending, g)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ShortCircuit replaces gate with the value of the wire o.
|
|
func (g *Gate) ShortCircuit(o *Wire) {
|
|
// Do not short circuit output wires.
|
|
if g.O.Output() {
|
|
return
|
|
}
|
|
|
|
// Add gate's outputs to short circuit output wire.
|
|
g.O.ForEachOutput(func(gate *Gate) {
|
|
gate.ReplaceInput(g.O, o)
|
|
})
|
|
g.O.DisconnectOutputs()
|
|
}
|
|
|
|
// ResetOutput resets the gate's output with the wire o.
|
|
func (g *Gate) ResetOutput(o *Wire) {
|
|
g.O = o
|
|
}
|
|
|
|
// ReplaceInput replaces gate's input wire from with wire to. The
|
|
// function panics if from is not gate's input wire.
|
|
func (g *Gate) ReplaceInput(from, to *Wire) {
|
|
if g.A == from {
|
|
g.A.RemoveOutput(g)
|
|
to.AddOutput(g)
|
|
g.A = to
|
|
} else if g.B == from {
|
|
g.B.RemoveOutput(g)
|
|
to.AddOutput(g)
|
|
g.B = to
|
|
} else {
|
|
panic(fmt.Sprintf("%s is not input for gate %s", from, g))
|
|
}
|
|
}
|
|
|
|
// Prune removes gate from the circuit if gate is dead i.e. its output
|
|
// wire is not connected into circuit's output wires.
|
|
func (g *Gate) Prune() bool {
|
|
if g.Dead || g.O.Output() || g.O.NumOutputs() > 0 {
|
|
return false
|
|
}
|
|
g.Dead = true
|
|
switch g.Op {
|
|
case circuit.XOR, circuit.XNOR, circuit.AND, circuit.OR:
|
|
g.B.RemoveOutput(g)
|
|
fallthrough
|
|
|
|
case circuit.INV:
|
|
g.A.RemoveOutput(g)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Assign assigns gate's output wire ID.
|
|
func (g *Gate) Assign(cc *Compiler) {
|
|
if !g.Dead {
|
|
g.O.Assign(cc)
|
|
cc.assigned = append(cc.assigned, g)
|
|
}
|
|
}
|
|
|
|
// Compile adds gate's binary circuit into compile circuit.
|
|
func (g *Gate) Compile(cc *Compiler) {
|
|
if g.Dead || g.Compiled {
|
|
return
|
|
}
|
|
g.Compiled = true
|
|
switch g.Op {
|
|
case circuit.INV:
|
|
cc.compiled = append(cc.compiled, circuit.Gate{
|
|
Input0: circuit.Wire(g.A.ID()),
|
|
Output: circuit.Wire(g.O.ID()),
|
|
Op: g.Op,
|
|
})
|
|
|
|
default:
|
|
cc.compiled = append(cc.compiled, circuit.Gate{
|
|
Input0: circuit.Wire(g.A.ID()),
|
|
Input1: circuit.Wire(g.B.ID()),
|
|
Output: circuit.Wire(g.O.ID()),
|
|
Op: g.Op,
|
|
})
|
|
}
|
|
}
|