Beispiel #1
0
        public static readonly NType Bool = new NType("bool")
        {
            GetCommonConstantValueFunc = commonConstant =>
            {
                if (commonConstant == VariableCommonConstant.Zero)
                {
                    return(new RawVariable()
                    {
                        Type = NType.Bool,
                        Value = new NizkBoolValue()
                        {
                            IsConstant = true,
                            Value = false,
                        }
                    });
                }
                else if (commonConstant == VariableCommonConstant.One)
                {
                    return(new RawVariable()
                    {
                        Type = NType.Bool,
                        Value = new NizkBoolValue()
                        {
                            IsConstant = true,
                            Value = true,
                        }
                    });
                }
                else
                {
                    throw new Exception($"Type \"{ NType.Bool}\" doesn't provide a constant for \"{commonConstant}\".");
                }
            },
            ParseFunc = (str) =>
            {
                if (System.Boolean.TryParse(str, out System.Boolean retV))
                {
                    return(new Variable(new RawVariable()
                    {
                        Type = NType.Bool,
                        Value = new NizkBoolValue()
                        {
                            IsConstant = true,
                            Value = retV,
                        }
                    }));
                }
                else
                {
                    throw new Exception($"Can't parse \"{str}\" as \"{NType.Bool.TypeCodeName}\".");
                }
            },
            GetVariableStringFunc  = variable => ((NizkBoolValue)variable.Value).Value.ToString(CultureInfo.InvariantCulture),
            GetVariableIntFunc     = variable => ((NizkBoolValue)variable.Value).Value == false ? 0 : 1,
            GetNewNizkVariableFunc = () => new Variable(new RawVariable()
            {
                Type  = NType.Bool,
                Value = new NizkBoolValue()
                {
                    IsConstant = false,
                    Value      = false,
                }
            }),
            InternalConvertFunc = (variable, type) => NType.Bool.ImplicitConvertFunc(variable, type),
            ImplicitConvertFunc = (variable, type) =>
            {
                var selfType = NType.Bool;
                if (type == selfType)
                {
                    return(variable);
                }
                if (!variable.Value.IsConstant)
                {
                    return(type.GetNewNizkVariable());
                }
                if (type == NType.Field)
                {
                    return(NType.Field.GetCommonConstantValue(((NizkBoolValue)variable.Value).Value ? VariableCommonConstant.One : VariableCommonConstant.Zero));
                }
                else if (type == NType.UInt32)
                {
                    return(NType.UInt32.GetCommonConstantValue(((NizkBoolValue)variable.Value).Value ? VariableCommonConstant.One : VariableCommonConstant.Zero));
                }
                else if (type == NType.Bool)
                {
                    throw CommonException.AssertFailedException();
                }
                else
                {
                    throw new Exception($"Can't convert \"{selfType.TypeCodeName }\" to \"{type.TypeCodeName}\".");
                }
            },
            ExplicitConvertFunc = (variable, type) => NType.Bool.ImplicitConvertFunc(variable, type),
            UnaryOperationFuncs = new Dictionary <VariableOperationType, Func <Variable, Variable> >()
            {
                { VariableOperationType.Unary_BooleanNot, (var1) =>
                  {
                      var v1 = ((NizkBoolValue)var1.Value);
                      return(new Variable(new RawVariable()
                        {
                            Type = NType.Bool,
                            Value = (v1.IsConstant) ?
                                    new NizkBoolValue()
                            {
                                IsConstant = true,
                                Value = !v1.Value,
                            }
                            : new NizkBoolValue()
                            {
                                IsConstant = false,
                            }
                        }));
                  } },
            },
            BinaryOperationFuncs = new Dictionary <VariableOperationType, Func <Variable, Variable, Variable> >()
            {
                { VariableOperationType.Binary_EqualTo, (var1, var2) =>
                  {
                      var newVar1 = var1;
                      var newVar2 = var2.Assign(NType.Bool);
                      var v1      = ((NizkBoolValue)newVar1.Value);
                      var v2      = ((NizkBoolValue)newVar2.Value);
                      return(new Variable(new RawVariable()
                        {
                            Type = NType.Bool,
                            Value = (v1.IsConstant && v2.IsConstant) ?
                                    new NizkBoolValue()
                            {
                                IsConstant = true,
                                Value = v1.Value == v2.Value,
                            }
                            : new NizkBoolValue()
                            {
                                IsConstant = false,
                            }
                        }));
                  } },

                { VariableOperationType.Binary_NotEqualTo, (var1, var2) =>
                  {
                      var newVar1 = var1;
                      var newVar2 = var2.Assign(NType.Bool);
                      var v1      = ((NizkBoolValue)newVar1.Value);
                      var v2      = ((NizkBoolValue)newVar2.Value);
                      return(new Variable(new RawVariable()
                        {
                            Type = NType.Bool,
                            Value = (v1.IsConstant && v2.IsConstant) ?
                                    new NizkBoolValue()
                            {
                                IsConstant = true,
                                Value = v1.Value != v2.Value,
                            }
                            : new NizkBoolValue()
                            {
                                IsConstant = false,
                            }
                        }));
                  } },

                { VariableOperationType.Binary_BooleanAnd, (var1, var2) =>
                  {
                      var newVar1 = var1;
                      var newVar2 = var2.Assign(NType.Bool);
                      var v1      = ((NizkBoolValue)newVar1.Value);
                      var v2      = ((NizkBoolValue)newVar2.Value);
                      return(new Variable(new RawVariable()
                        {
                            Type = NType.Bool,
                            Value = (v1.IsConstant && v2.IsConstant) ?
                                    new NizkBoolValue()
                            {
                                IsConstant = true,
                                Value = v1.Value && v2.Value,
                            }
                            : new NizkBoolValue()
                            {
                                IsConstant = false,
                            }
                        }));
                  } },

                { VariableOperationType.Binary_BooleanOr, (var1, var2) =>
                  {
                      var newVar1 = var1;
                      var newVar2 = var2.Assign(NType.Bool);
                      var v1      = ((NizkBoolValue)newVar1.Value);
                      var v2      = ((NizkBoolValue)newVar2.Value);
                      return(new Variable(new RawVariable()
                        {
                            Type = NType.Bool,
                            Value = (v1.IsConstant && v2.IsConstant) ?
                                    new NizkBoolValue()
                            {
                                IsConstant = true,
                                Value = v1.Value || v2.Value,
                            }
                            : new NizkBoolValue()
                            {
                                IsConstant = false,
                            }
                        }));
                  } },

                { VariableOperationType.Binary_BooleanXor, (var1, var2) =>
                  {
                      var newVar1 = var1;
                      var newVar2 = var2.Assign(NType.Bool);
                      var v1      = ((NizkBoolValue)newVar1.Value);
                      var v2      = ((NizkBoolValue)newVar2.Value);
                      return(new Variable(new RawVariable()
                        {
                            Type = NType.Bool,
                            Value = (v1.IsConstant && v2.IsConstant) ?
                                    new NizkBoolValue()
                            {
                                IsConstant = true,
                                Value = v1.Value != v2.Value,
                            }
                            : new NizkBoolValue()
                            {
                                IsConstant = false,
                            }
                        }));
                  } },
            },

            VariableNodeToPinocchioFunc = (rawVariable, commonArg, checkRange) =>
            {
                var ret = new PinocchioSubOutput();

                var retWire = new PinocchioWire();
                ret.VariableWires = new PinocchioVariableWires(rawVariable, retWire);

                if (rawVariable.Value.IsConstant)
                {
                    //var con = new ConstWireConstraint();
                    //ret.Constraints.Add(con);
                    //con.ConstVariableWires = ret.VariableWires;
                }
                else
                {
                    if (checkRange)
                    {
                        // R * (R-1) = 0
                        var wire3 = new PinocchioWire();
                        ret.AnonymousWires.Add(wire3);

                        var addCon = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Add);
                        ret.Constraints.Add(addCon);

                        addCon.InWires.Add(retWire);
                        addCon.InWires.Add(commonArg.MinusOneWire);
                        addCon.OutWires.Add(wire3);

                        var mulCom = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Mul);
                        ret.Constraints.Add(mulCom);

                        mulCom.InWires.Add(retWire);
                        mulCom.InWires.Add(wire3);
                        mulCom.OutWires.Add(commonArg.ZeroWire);
                    }
                }

                return(ret);
            },


            OperationNodeToPinocchioFunc = (operationType, inVars, outputVariable, commonArg) =>
            {
                switch (operationType.Type)
                {
                case VariableOperationTypeType.TypeCast:
                    Debug.Assert(inVars.Count == 1);
                    Debug.Assert(inVars[0].Wires.Count == 1);
                    if (operationType == VariableOperationType.TypeCast_NoCheckRange || operationType == VariableOperationType.TypeCast_Trim)
                    {
                        Debug.Assert(outputVariable.Type == NType.Field || outputVariable.Type == NType.UInt32 || outputVariable.Type == NType.Bool);

                        PinocchioSubOutput ret;
                        PinocchioWire      outputWire;
                        {
                            var outVarWires = outputVariable.Type.VariableNodeToPinocchio(outputVariable, commonArg, false);
                            Debug.Assert(outVarWires.VariableWires.Wires.Count == 1);
                            outputWire = outVarWires.VariableWires.Wires[0];

                            ret = new PinocchioSubOutput()
                            {
                                VariableWires = outVarWires.VariableWires
                            };
                            outVarWires.Constraints.ForEach(ret.Constraints.Add);
                        }
                        if (operationType == VariableOperationType.TypeCast_NoCheckRange ||
                            operationType == VariableOperationType.TypeCast_Trim && outputVariable.Type == NType.Field ||
                            operationType == VariableOperationType.TypeCast_Trim && outputVariable.Type == NType.UInt32)
                        {
                            var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Mul);
                            ret.Constraints.Add(con);

                            con.InWires.Add(inVars[0].Wires[0]);
                            con.InWires.Add(commonArg.OneWire);
                            con.OutWires.Add(outputWire);

                            return(ret);
                        }
                        else
                        {
                            throw CommonException.AssertFailedException();
                        }
                    }
                    else
                    {
                        break;
                    }

                case VariableOperationTypeType.Unary:
                    Debug.Assert(inVars.Count == 1);
                    Debug.Assert(inVars[0].Wires.Count == 1);
                    if (operationType == VariableOperationType.Unary_BooleanNot)
                    {
                        Debug.Assert(outputVariable.Type == NType.Bool);

                        PinocchioSubOutput ret;
                        PinocchioWire      outputWire;
                        {
                            var outVarWires = outputVariable.Type.VariableNodeToPinocchio(outputVariable, commonArg, false);
                            Debug.Assert(outVarWires.VariableWires.Wires.Count == 1);
                            outputWire = outVarWires.VariableWires.Wires[0];

                            ret = new PinocchioSubOutput()
                            {
                                VariableWires = outVarWires.VariableWires
                            };
                            outVarWires.Constraints.ForEach(ret.Constraints.Add);
                        }

                        //operationType == VariableOperationType.Unary_BooleanNot
                        var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Xor);
                        ret.Constraints.Add(con);

                        con.InWires.Add(inVars[0].Wires[0]);
                        con.InWires.Add(commonArg.OneWire);
                        con.OutWires.Add(outputWire);

                        return(ret);
                    }
                    else
                    {
                        break;
                    }

                case VariableOperationTypeType.Binary:
                    Debug.Assert(inVars.Count == 2);
                    Debug.Assert(inVars[0].Wires.Count == 1);
                    Debug.Assert(inVars[1].Wires.Count == 1);
                    if (operationType == VariableOperationType.Binary_EqualTo ||
                        operationType == VariableOperationType.Binary_NotEqualTo ||
                        operationType == VariableOperationType.Binary_BooleanAnd ||
                        operationType == VariableOperationType.Binary_BooleanOr ||
                        operationType == VariableOperationType.Binary_BooleanXor)
                    {
                        Debug.Assert(outputVariable.Type == NType.Bool);

                        PinocchioSubOutput ret;
                        PinocchioWire      outputWire;
                        {
                            var outVarWires = outputVariable.Type.VariableNodeToPinocchio(outputVariable, commonArg, false);
                            Debug.Assert(outVarWires.VariableWires.Wires.Count == 1);
                            outputWire = outVarWires.VariableWires.Wires[0];

                            ret = new PinocchioSubOutput()
                            {
                                VariableWires = outVarWires.VariableWires
                            };
                            outVarWires.Constraints.ForEach(ret.Constraints.Add);
                        }

                        if (operationType == VariableOperationType.Binary_BooleanAnd)
                        {
                            var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Mul);
                            ret.Constraints.Add(con);

                            con.InWires.Add(inVars[0].Wires[0]);
                            con.InWires.Add(inVars[0].Wires[1]);
                            con.OutWires.Add(outputWire);

                            return(ret);
                        }
                        else if (operationType == VariableOperationType.Binary_BooleanOr)
                        {
                            var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Or);
                            ret.Constraints.Add(con);

                            con.InWires.Add(inVars[0].Wires[0]);
                            con.InWires.Add(inVars[0].Wires[1]);
                            con.OutWires.Add(outputWire);

                            return(ret);
                        }
                        else if (operationType == VariableOperationType.Binary_BooleanXor || operationType == VariableOperationType.Binary_NotEqualTo)
                        {
                            var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Xor);
                            ret.Constraints.Add(con);

                            con.InWires.Add(inVars[0].Wires[0]);
                            con.InWires.Add(inVars[0].Wires[1]);
                            con.OutWires.Add(outputWire);

                            return(ret);
                        }
                        else if (operationType == VariableOperationType.Binary_EqualTo)
                        {
                            var wire1 = new PinocchioWire();
                            ret.AnonymousWires.Add(wire1);

                            var con1 = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Xor);
                            ret.Constraints.Add(con1);

                            con1.InWires.Add(inVars[0].Wires[0]);
                            con1.InWires.Add(inVars[0].Wires[1]);
                            con1.OutWires.Add(wire1);

                            var con2 = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Xor);
                            ret.Constraints.Add(con2);

                            con2.InWires.Add(wire1);
                            con2.InWires.Add(commonArg.OneWire);
                            con2.OutWires.Add(outputWire);

                            return(ret);
                        }
                        else
                        {
                            throw CommonException.AssertFailedException();
                        }
                    }
                    else
                    {
                        break;
                    }

                default:
                    throw CommonException.AssertFailedException();
                }
                throw new Exception($"Type \"{NType.Field}\" doesn't support \"{operationType.ToString()}\" operation.");
            },
        };
Beispiel #2
0
        public void OutputCircuit(TextWriter arithWriter, TextWriter inHelperWriter)
        {
            var wireToID = new Dictionary <PinocchioWire, int>();

            void AddWire(PinocchioWire wire)
            {
                if (wireToID.ContainsKey(wire))
                {
                    return;
                }
                wireToID.Add(wire, wireToID.Keys.Count);
            }

            var conList = new List <IPinocchioConstraint>();

            void AddConstraint(IPinocchioConstraint con)
            {
                conList.Add(con);
            }

            var rawVarToWires = new Dictionary <RawVariable, PinocchioVariableWires>();

            void AddVariableWires(PinocchioVariableWires variableWires)
            {
                if (rawVarToWires.ContainsKey(variableWires.RawVariable))
                {
                    return;
                }

                rawVarToWires.Add(variableWires.RawVariable, variableWires);

                variableWires.Wires.ForEach(AddWire);
            }

            void AddPinocchioSubOutput(PinocchioSubOutput ret)
            {
                AddVariableWires(ret.VariableWires);

                ret.AnonymousWires.ForEach(AddWire);

                ret.Constraints.ForEach(AddConstraint);
            }

            var commonArg = new PinocchioCommonArg();
            {
                // 1
                {
                    commonArg.OneWire = new PinocchioWire();
                    AddWire(commonArg.OneWire);

                    var comment = new CommentConstraint();
                    AddConstraint(comment);
                    comment.Comment = "The constant wire, value 1";

                    var con = new ConstWireConstraint();
                    AddConstraint(con);

                    con.ConstVariableWires = new PinocchioVariableWires(
                        NType.Field.GetCommonConstantValue(VariableCommonConstant.One).RawVariable,
                        commonArg.OneWire);
                }
                // 0
                {
                    commonArg.ZeroWire = new PinocchioWire();
                    AddWire(commonArg.ZeroWire);

                    var comment = new CommentConstraint();
                    AddConstraint(comment);
                    comment.Comment = "The constant wire, value 0";

                    var con = new ConstWireConstraint();
                    AddConstraint(con);

                    con.ConstVariableWires = new PinocchioVariableWires(
                        NType.Field.GetCommonConstantValue(VariableCommonConstant.Zero).RawVariable,
                        commonArg.ZeroWire);
                }
                // -1
                {
                    commonArg.MinusOneWire = new PinocchioWire();
                    AddWire(commonArg.MinusOneWire);

                    var comment = new CommentConstraint();
                    AddConstraint(comment);
                    comment.Comment = "The constant wire, value -1";

                    var con = new ConstWireConstraint();
                    AddConstraint(con);

                    con.ConstVariableWires = new PinocchioVariableWires(
                        NType.Field.GetCommonConstantValue(VariableCommonConstant.MinusOne).RawVariable,
                        commonArg.MinusOneWire);
                }
                // 2
                commonArg.PowerOfTwoWires    = new PinocchioWire[My.Config.ModulusPrimeField_Prime_Bit + 1];
                commonArg.PowerOfTwoWires[0] = commonArg.OneWire;

                var powerOfTwoBaseVariable = NType.Field.GetCommonConstantValue(VariableCommonConstant.One);

                foreach (int i in Enumerable.Range(1, My.Config.ModulusPrimeField_Prime_Bit))
                {
                    commonArg.PowerOfTwoWires[i] = new PinocchioWire();
                    AddWire(commonArg.PowerOfTwoWires[i]);

                    powerOfTwoBaseVariable = NType.Field.BinaryOperation(
                        powerOfTwoBaseVariable,
                        powerOfTwoBaseVariable,
                        VariableOperationType.Binary_Addition);

                    var comment = new CommentConstraint();
                    AddConstraint(comment);
                    comment.Comment = $"The constant wire, value (base 10) 2^{i.ToString(CultureInfo.InvariantCulture)}";

                    var con = new ConstWireConstraint();
                    AddConstraint(con);

                    con.ConstVariableWires = new PinocchioVariableWires(powerOfTwoBaseVariable.RawVariable,
                                                                        commonArg.PowerOfTwoWires[i]);

                    //todo: bug: the value of 2^254 is not correct. Figure out why.
                }
            }

            var outputVariableWiresDict = new Dictionary <RawVariable, (PinocchioTypeWires TypeWires, string VarName)>();

            void AddOutputVariableWires(PinocchioVariableWires variableWires, string varName)
            {
                if (!outputVariableWiresDict.ContainsKey(variableWires.RawVariable))
                {
                    outputVariableWiresDict.Add(variableWires.RawVariable, (TypeWires: new PinocchioTypeWires(variableWires), VarName: varName));
                }
                else
                {
                    Debug.Assert(varName == outputVariableWiresDict[variableWires.RawVariable].VarName);
                    Debug.Assert(variableWires.Wires.SequenceEqual(outputVariableWiresDict[variableWires.RawVariable].TypeWires.Wires));
                }
            }

            foreach (var node in this.VariableMap.TopologicalSort())
            {
                switch (node)
                {
                case VariableNode variableNode:
                    // a variable node is either an input/nizk/constant node, which is NOT produced by constraints
                    // or a non-constant intermediate/output node, which has already been produced by constraints

                    PinocchioVariableWires outputVarWires = null;

                    if (!rawVarToWires.ContainsKey(variableNode.RawVariable))
                    {
                        // new wire(s)

                        Debug.Assert(
                            ((variableNode.NizkAttribute == NizkVariableType.Intermediate || variableNode.NizkAttribute == NizkVariableType.Output) && variableNode.RawVariable.Value.IsConstant) ||
                            variableNode.NizkAttribute == NizkVariableType.Input ||
                            variableNode.NizkAttribute == NizkVariableType.NizkInput);

                        if (variableNode.RawVariable.Value.IsConstant)
                        {
                            var output = variableNode.RawVariable.Type.VariableNodeToPinocchio(variableNode.RawVariable, commonArg, false);
                            AddPinocchioSubOutput(output);

                            {
                                var comment = new CommentConstraint();
                                AddConstraint(comment);
                                comment.Comment = $"The following {output.VariableWires.Wires.Count.ToString(CultureInfo.InvariantCulture)} wires are of a constant value (base 10) {variableNode.RawVariable.Type.GetVariableString(variableNode.RawVariable)}.";

                                var con = new ConstWireConstraint();
                                AddConstraint(con);
                                con.ConstVariableWires = output.VariableWires;
                            }

                            if (variableNode.NizkAttribute == NizkVariableType.Output)
                            {
                                outputVarWires = output.VariableWires;
                            }

                            // obsolete: mul by one is handled later
                            //// if the output variable is also constant, mul by one as new outputs
                            //if (variableNode.NizkAttribute == NizkVariableType.Output)
                            //{
                            //    List<PinocchioWire> outputWires = new List<PinocchioWire>();
                            //    foreach (var wire in output.VariableWires.Wires)
                            //    {
                            //        var newWire = new PinocchioWire();
                            //        AddWire(newWire);

                            //        var newCon = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Mul);
                            //        AddConstraint(newCon);

                            //        newCon.InWires.Add(wire);
                            //        newCon.InWires.Add(commonArg.OneWire);
                            //        newCon.OutWires.Add(newWire);

                            //        outputWires.Add(newWire);
                            //    }

                            //    outputVarWires = new PinocchioVariableWires(variableNode.RawVariable, outputWires);
                            //}
                        }
                        else
                        {
                            switch (variableNode.NizkAttribute)
                            {
                            // policy: checkRange is applied for nizkinput, and not applied for others
                            case NizkVariableType.NizkInput:
                            {
                                var comment = new CommentConstraint();
                                AddConstraint(comment);

                                var con = new UserPrivateInputConstraint();
                                AddConstraint(con);

                                var output = variableNode.RawVariable.Type.VariableNodeToPinocchio(variableNode.RawVariable, commonArg, true);
                                AddPinocchioSubOutput(output);

                                comment.Comment = $"The following {output.VariableWires.Wires.Count.ToString(CultureInfo.InvariantCulture)} wires are nizk-input wires of variable \"{variableNode.VarName}\".";
                                con.TypeWires   = new PinocchioTypeWires(output.VariableWires);

                                break;
                            }

                            case NizkVariableType.Input:
                            {
                                var output = variableNode.RawVariable.Type.VariableNodeToPinocchio(variableNode.RawVariable, commonArg, false);
                                AddPinocchioSubOutput(output);

                                var comment = new CommentConstraint();
                                AddConstraint(comment);
                                comment.Comment = $"The following {output.VariableWires.Wires.Count.ToString(CultureInfo.InvariantCulture)} wires are input wires of variable \"{variableNode.VarName}\".";

                                var con = new UserInputConstraint();
                                AddConstraint(con);
                                con.TypeWires = new PinocchioTypeWires(output.VariableWires);
                                break;
                            }

                            default:
                                throw CommonException.AssertFailedException();
                            }
                        }
                    }
                    else
                    {
                        // old wire(s)

                        Debug.Assert(variableNode.NizkAttribute == NizkVariableType.Intermediate ||
                                     variableNode.NizkAttribute == NizkVariableType.Output);
                        Debug.Assert(!variableNode.RawVariable.Value.IsConstant);


                        if (variableNode.NizkAttribute == NizkVariableType.Output)
                        {
                            outputVarWires = rawVarToWires[variableNode.RawVariable];
                        }
                    }

                    if (outputVarWires != null)
                    {
                        AddOutputVariableWires(outputVarWires, variableNode.VarName);
                    }

                    break;

                case OperationNode operationNode:
                    // get all in-variable
                    List <PinocchioVariableWires> inVars = new List <PinocchioVariableWires>();
                    foreach (var prevNode in operationNode.PrevNodes)
                    {
                        var varNode = (VariableNode)prevNode;
                        Debug.Assert(rawVarToWires.ContainsKey(varNode.RawVariable));

                        inVars.Add(rawVarToWires[varNode.RawVariable]);
                    }

                    // currently, assume at least one inVar
                    Debug.Assert(inVars.Count >= 1);

                    // for every outputVar, produce new PinocchioOutput according to the operation
                    foreach (var outNode in operationNode.NextNodes)
                    {
                        var outVarNode            = (VariableNode)outNode;
                        PinocchioSubOutput output = inVars[0].RawVariable.Type.OperationNodeToPinocchio(
                            operationNode.ConnectionType,
                            inVars,
                            outVarNode.RawVariable,
                            commonArg
                            );

                        AddPinocchioSubOutput(output);
                    }
                    break;

                default:
                    throw CommonException.AssertFailedException();
                }
            }

            // todo: optimize redundancy wire & constraints
            // note: even if all the output of some constraints are not used, it is NOT considered useless
            // example here: input 1; split in 1 <1> out 32 <2,3,4,...,33>; this constraint ensure that "input 1" is smaller than 2^32, and must not be deleted while optimizing

            // declare the output wires at the end
            foreach (var(_, (typeWires, varName)) in outputVariableWiresDict)
            {
                var newTypeWires = new PinocchioTypeWires();
                newTypeWires.Type = typeWires.Type;

                // mul by 1
                foreach (var wire in typeWires.Wires)
                {
                    var newWire = new PinocchioWire();
                    AddWire(newWire);

                    var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Mul);
                    AddConstraint(con);

                    con.InWires.Add(wire);
                    con.InWires.Add(commonArg.OneWire);
                    con.OutWires.Add(newWire);

                    newTypeWires.Wires.Add(newWire);
                    // ReSharper disable once UseIndexFromEndExpression
                    Debug.Assert(typeWires.Wires[newTypeWires.Wires.Count - 1] == wire);
                }

                {
                    var comment = new CommentConstraint();
                    AddConstraint(comment);
                    comment.Comment = $"The following {newTypeWires.Wires.Count.ToString(CultureInfo.InvariantCulture)} wires are output wires of variable \"{varName}\".";
                }

                {
                    var con = new OutputConstraint();
                    AddConstraint(con);
                    con.TypeWires = newTypeWires;
                }
            }

            // write these wire & constraints
            arithWriter.WriteLine("total " + (wireToID.Keys.Count.ToString(CultureInfo.InvariantCulture)));
            foreach (var constraint in conList)
            {
                switch (constraint)
                {
                case BasicPinocchioConstraint basicPinocchioConstraint:
                    StringBuilder sb = new StringBuilder();
                    _ = basicPinocchioConstraint.Type switch
                    {
                        BasicPinocchioConstraintType.Add => sb.Append("add"),
                        BasicPinocchioConstraintType.Mul => sb.Append("mul"),
                        BasicPinocchioConstraintType.Or => sb.Append("or"),
                        BasicPinocchioConstraintType.Pack => sb.Append("pack"),
                        BasicPinocchioConstraintType.Split => sb.Append("split"),
                        BasicPinocchioConstraintType.Xor => sb.Append("xor"),
                        BasicPinocchioConstraintType.ZeroP => sb.Append("zerop"),
                        _ => throw CommonException.AssertFailedException(),
                    };

                    // zerop compatibility
                    if (basicPinocchioConstraint.Type == BasicPinocchioConstraintType.ZeroP &&
                        basicPinocchioConstraint.OutWires.Count == 1)
                    {
                        basicPinocchioConstraint.OutWires.Insert(0, commonArg.OneWire);
                    }

                    // zerop compatibility end


                    _ = sb.Append(" in ");
                    _ = sb.Append(basicPinocchioConstraint.InWires.Count.ToString(CultureInfo.InvariantCulture));
                    _ = sb.Append(" <");
                    foreach (var wire in basicPinocchioConstraint.InWires)
                    {
                        _ = sb.Append(" " + wireToID[wire].ToString(CultureInfo.InvariantCulture));
                    }

                    _ = sb.Append(" > out ");
                    _ = sb.Append(basicPinocchioConstraint.OutWires.Count.ToString(CultureInfo.InvariantCulture));
                    _ = sb.Append(" <");
                    foreach (var wire in basicPinocchioConstraint.OutWires)
                    {
                        _ = sb.Append(" " + wireToID[wire].ToString(CultureInfo.InvariantCulture));
                    }
                    _ = sb.Append(" >");

                    arithWriter.WriteLine(sb.ToString());

                    break;

                case UserInputConstraint userInputConstraint:
                    Debug.Assert(userInputConstraint.TypeWires.Wires.Count != 0);
                    userInputConstraint.TypeWires.Wires.ForEach(wire => arithWriter.WriteLine("input " + wireToID[wire] + " #userinput"));
                    userInputConstraint.TypeWires.Wires.ForEach(wire => inHelperWriter.WriteLine(wireToID[wire] + " <to-be-filled-by-user, base 16>"));
                    break;

                case UserPrivateInputConstraint userPrivateInputConstraint:
                    Debug.Assert(userPrivateInputConstraint.TypeWires.Wires.Count != 0);
                    userPrivateInputConstraint.TypeWires.Wires.ForEach(wire => arithWriter.WriteLine("nizkinput " + wireToID[wire] + " #userinput"));
                    userPrivateInputConstraint.TypeWires.Wires.ForEach(wire => inHelperWriter.WriteLine(wireToID[wire] + " <to-be-filled-by-user, base 16>"));
                    break;

                case OutputConstraint outputConstraint:
                    Debug.Assert(outputConstraint.TypeWires.Wires.Count != 0);
                    outputConstraint.TypeWires.Wires.ForEach(wire => arithWriter.WriteLine("output " + wireToID[wire] + " #output"));
                    break;

                case ConstWireConstraint constWireConstraint:
                    Debug.Assert(constWireConstraint.ConstVariableWires.Wires.Count != 0);
                    constWireConstraint.ConstVariableWires.Wires.ForEach(wire => arithWriter.WriteLine("input " + wireToID[wire] + " #const"));
                    if (constWireConstraint.ConstVariableWires.Wires.Count == 1)
                    {
                        constWireConstraint.ConstVariableWires.Wires.ForEach(wire => inHelperWriter.WriteLine(wireToID[wire] + " " + constWireConstraint.ConstVariableWires.RawVariable.Type.GetVariableInt(constWireConstraint.ConstVariableWires.RawVariable).ToString("X", CultureInfo.InvariantCulture)));
                    }
                    else
                    {
                        constWireConstraint.ConstVariableWires.Wires.ForEach(wire => inHelperWriter.WriteLine(wireToID[wire] + " <todo-multiple-wires-constant>"));
                    }

                    break;

                case CommentConstraint commentConstraint:
                    arithWriter.WriteLine("#" + commentConstraint.Comment);
                    break;

                case DivModConstraint divModConstraint:
                    //todo
                    throw new NotImplementedException();

                default:
                    throw CommonException.AssertFailedException();
                }
            }

            // congrats!
        }
Beispiel #3
0
        public static readonly NType Field = new NType("field")
        {
            GetCommonConstantValueFunc = commonConstant =>
            {
                if (commonConstant == VariableCommonConstant.Zero)
                {
                    return(new RawVariable()
                    {
                        Type = NType.Field,
                        Value = new NizkFieldValue()
                        {
                            IsConstant = true,
                            Value = BigInteger.Zero,
                        }
                    });
                }
                else if (commonConstant == VariableCommonConstant.One)
                {
                    return(new RawVariable()
                    {
                        Type = NType.Field,
                        Value = new NizkFieldValue()
                        {
                            IsConstant = true,
                            Value = BigInteger.One,
                        }
                    });
                }
                else if (commonConstant == VariableCommonConstant.MinusOne)
                {
                    return(new RawVariable()
                    {
                        Type = NType.Field,
                        Value = new NizkFieldValue()
                        {
                            IsConstant = true,
                            Value = My.Config.ModulusPrimeField_Prime,
                        }
                    });
                }
                else
                {
                    throw new Exception($"Type \"{ NType.Field}\" doesn't provide a constant for \"{commonConstant}\".");
                }
            },
            ParseFunc = (str) =>
            {
                if (BigInteger.TryParse(str, out BigInteger retV))
                {
                    return(new Variable(new RawVariable()
                    {
                        Type = NType.Field,
                        Value = new NizkFieldValue()
                        {
                            IsConstant = true,
                            Value = retV,
                        }
                    }));
                }
                else
                {
                    throw new Exception($"Can't parse \"{str}\" as \"{NType.Field.TypeCodeName}\".");
                }
            },
            GetVariableStringFunc  = variable => ((NizkFieldValue)variable.Value).Value.ToString(CultureInfo.InvariantCulture),
            GetVariableIntFunc     = variable => ((NizkFieldValue)variable.Value).Value,
            GetNewNizkVariableFunc = () => new Variable(new RawVariable()
            {
                Type  = NType.Field,
                Value = new NizkFieldValue()
                {
                    IsConstant = false,
                    Value      = BigInteger.Zero,
                }
            }),

            InternalConvertFunc = (variable, type) =>
            {
                var selfType = NType.Field;
                if (type == selfType)
                {
                    return(variable);
                }

                var allowedType = new List <NType>()
                {
                    NType.UInt32, NType.Bool,
                };
                if (!allowedType.Contains(type))
                {
                    throw new Exception($"Can't do internal convert from \"{selfType.TypeCodeName }\" to \"{type.TypeCodeName}\".");
                }

                if (!variable.Value.IsConstant)
                {
                    return(type.GetNewNizkVariable());
                }

                if (type == NType.UInt32)
                {
                    if (((NizkFieldValue)variable.Value).Value <= new BigInteger(System.UInt32.MaxValue))
                    {
                        return(new Variable(new RawVariable()
                        {
                            Type = NType.UInt32,
                            Value = new NizkUInt32Value()
                            {
                                IsConstant = true,
                                Value = System.UInt32.Parse((((NizkFieldValue)variable.Value).Value).ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture),
                            }
                        }));
                    }
                    else
                    {
                        throw new Exception($"Overflow detected while doing internal convert from \"{selfType.TypeCodeName }\" to \"{type.TypeCodeName}\".");
                    }
                }
                else if (type == NType.Bool)
                {
                    if (((NizkFieldValue)variable.Value).Value <= BigInteger.One)
                    {
                        return(NType.Bool.GetCommonConstantValue(((NizkFieldValue)variable.Value).Value == BigInteger.One ? VariableCommonConstant.One : VariableCommonConstant.Zero));
                    }
                    else
                    {
                        throw new Exception($"Overflow detected while doing internal convert from \"{selfType.TypeCodeName }\" to \"{type.TypeCodeName}\".");
                    }
                }
                else
                {
                    throw CommonException.AssertFailedException();
                }
            },
            // Implicit Convert: not supported
            ExplicitConvertFunc = (variable, type) =>
            {
                var selfType = NType.Field;
                if (type == selfType)
                {
                    return(variable);
                }

                var allowedType = new List <NType>()
                {
                    NType.UInt32, NType.Bool,
                };
                if (!allowedType.Contains(type))
                {
                    throw new Exception($"Can't explicit convert \"{selfType.TypeCodeName }\" to \"{type.TypeCodeName}\".");
                }

                if (!variable.Value.IsConstant)
                {
                    return(type.GetNewNizkVariable());
                }

                if (type == NType.UInt32)
                {
                    return(new Variable(new RawVariable()
                    {
                        Type = NType.UInt32,
                        Value = new NizkUInt32Value()
                        {
                            IsConstant = true,
                            Value = System.UInt32.Parse((((NizkFieldValue)variable.Value).Value % (new BigInteger(System.UInt32.MaxValue) + 1)).ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture),
                        }
                    }));
                }
                else if (type == NType.Bool)
                {
                    return(NType.Bool.GetCommonConstantValue(((NizkUInt32Value)variable.Value).Value % 2 == 0 ? VariableCommonConstant.One : VariableCommonConstant.Zero));
                }
                else
                {
                    throw CommonException.AssertFailedException();
                }
            },

            BinaryOperationFuncs = new Dictionary <VariableOperationType, Func <Variable, Variable, Variable> >()
            {
                { VariableOperationType.Binary_Addition, (var1, var2) =>
                  {
                      var newVar1 = var1;
                      var newVar2 = var2.Assign(NType.Field);
                      var v1      = ((NizkFieldValue)newVar1.Value);
                      var v2      = ((NizkFieldValue)newVar2.Value);
                      return(new Variable(new RawVariable()
                        {
                            Type = NType.Field,
                            Value = (v1.IsConstant && v2.IsConstant) ?
                                    new NizkFieldValue()
                            {
                                IsConstant = true,
                                Value = (v1.Value + v2.Value) % My.Config.ModulusPrimeField_Prime,
                            }
                            : new NizkFieldValue()
                            {
                                IsConstant = false,
                            }
                        }));
                  } },

                { VariableOperationType.Binary_Subtract, (var1, var2) =>
                  {
                      var newVar1 = var1;
                      var newVar2 = var2.Assign(NType.Field);
                      var v1      = ((NizkFieldValue)newVar1.Value);
                      var v2      = ((NizkFieldValue)newVar2.Value);
                      return(new Variable(new RawVariable()
                        {
                            Type = NType.Field,
                            Value = (v1.IsConstant && v2.IsConstant) ?
                                    new NizkFieldValue()
                            {
                                IsConstant = true,
                                Value = (My.Config.ModulusPrimeField_Prime + v1.Value - v2.Value) % My.Config.ModulusPrimeField_Prime,
                            }
                            : new NizkFieldValue()
                            {
                                IsConstant = false,
                            }
                        }));
                  } },

                { VariableOperationType.Binary_Multiplication, (var1, var2) =>
                  {
                      var newVar1 = var1;
                      var newVar2 = var2.Assign(NType.Field);
                      var v1      = ((NizkFieldValue)newVar1.Value);
                      var v2      = ((NizkFieldValue)newVar2.Value);
                      return(new Variable(new RawVariable()
                        {
                            Type = NType.Field,
                            Value = (v1.IsConstant && v2.IsConstant) ?
                                    new NizkFieldValue()
                            {
                                IsConstant = true,
                                Value = (v1.Value * v2.Value) % My.Config.ModulusPrimeField_Prime,
                            }
                            : new NizkFieldValue()
                            {
                                IsConstant = false,
                            }
                        }));
                  } },
            },

            VariableNodeToPinocchioFunc = (rawVariable, commonArg, checkRange) =>
            {
                var ret = new PinocchioSubOutput();

                var retWire = new PinocchioWire();
                ret.VariableWires = new PinocchioVariableWires(rawVariable, retWire);

                return(ret);
            },
            OperationNodeToPinocchioFunc = (operationType, inVars, outputVariable, commonArg) =>
            {
                switch (operationType.Type)
                {
                case VariableOperationTypeType.TypeCast:
                    Debug.Assert(inVars.Count == 1);
                    Debug.Assert(inVars[0].Wires.Count == 1);
                    if (operationType == VariableOperationType.TypeCast_NoCheckRange || operationType == VariableOperationType.TypeCast_Trim)
                    {
                        Debug.Assert(outputVariable.Type == NType.Field || outputVariable.Type == NType.UInt32 || outputVariable.Type == NType.Bool);

                        PinocchioSubOutput ret;
                        PinocchioWire      outputWire;
                        {
                            var outVarWires = outputVariable.Type.VariableNodeToPinocchio(outputVariable, commonArg, false);
                            Debug.Assert(outVarWires.VariableWires.Wires.Count == 1);
                            outputWire = outVarWires.VariableWires.Wires[0];

                            ret = new PinocchioSubOutput()
                            {
                                VariableWires = outVarWires.VariableWires
                            };
                            outVarWires.Constraints.ForEach(ret.Constraints.Add);
                        }
                        if (operationType == VariableOperationType.TypeCast_NoCheckRange)
                        {
                            var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Mul);
                            ret.Constraints.Add(con);

                            con.InWires.Add(inVars[0].Wires[0]);
                            con.InWires.Add(commonArg.OneWire);
                            con.OutWires.Add(outputWire);

                            return(ret);
                        }
                        else if (operationType == VariableOperationType.TypeCast_Trim)
                        {
                            if (outputVariable.Type == NType.Bool)
                            {
                                var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.ZeroP);
                                ret.Constraints.Add(con);

                                con.InWires.Add(inVars[0].Wires[0]);
                                con.OutWires.Add(outputWire);

                                return(ret);
                            }
                            else if (outputVariable.Type == NType.UInt32)
                            {
                                var splitCon = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Split);
                                ret.Constraints.Add(splitCon);

                                splitCon.InWires.Add(inVars[0].Wires[0]);
                                //todo: [MaxPossibleValue] design "Variable.MaxPossibleValue" and minimize the number of bits here
                                foreach (var _ in Enumerable.Range(0, My.Config.ModulusPrimeField_Prime_Bit))
                                {
                                    var boolWire = new PinocchioWire();
                                    ret.AnonymousWires.Add(boolWire);

                                    // [boolWire01]

                                    splitCon.OutWires.Add(boolWire);
                                }

                                var packCon = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Pack);
                                ret.Constraints.Add(packCon);

                                packCon.OutWires.Add(outputWire);
                                for (int i = My.Config.ModulusPrimeField_Prime_Bit - 1; i <= My.Config.ModulusPrimeField_Prime_Bit - 32; --i)
                                {
                                    var boolWire = new PinocchioWire();
                                    ret.AnonymousWires.Add(boolWire);

                                    // [boolWire01]

                                    packCon.InWires.Add(boolWire);
                                }

                                return(ret);
                            }
                            else
                            {
                                break;
                            }
                        }
                        else
                        {
                            throw CommonException.AssertFailedException();
                        }
                    }
                    else
                    {
                        break;
                    }

                case VariableOperationTypeType.Unary:
                    Debug.Assert(inVars.Count == 1);
                    Debug.Assert(inVars[0].Wires.Count == 1);
                    break;

                case VariableOperationTypeType.Binary:
                    Debug.Assert(inVars.Count == 2);
                    Debug.Assert(inVars[0].Wires.Count == 1);
                    Debug.Assert(inVars[1].Wires.Count == 1);
                    if (operationType == VariableOperationType.Binary_Addition ||
                        operationType == VariableOperationType.Binary_Multiplication ||
                        operationType == VariableOperationType.Binary_Subtract)
                    {
                        PinocchioSubOutput ret;
                        PinocchioWire      outputWire;
                        {
                            var outVarWires = outputVariable.Type.VariableNodeToPinocchio(outputVariable, commonArg, false);
                            Debug.Assert(outVarWires.VariableWires.Wires.Count == 1);
                            outputWire = outVarWires.VariableWires.Wires[0];

                            ret = new PinocchioSubOutput()
                            {
                                VariableWires = outVarWires.VariableWires
                            };
                            outVarWires.Constraints.ForEach(ret.Constraints.Add);
                        }
                        if (operationType == VariableOperationType.Binary_Addition)
                        {
                            var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Add);
                            ret.Constraints.Add(con);

                            con.InWires.Add(inVars[0].Wires[0]);
                            con.InWires.Add(inVars[1].Wires[0]);
                            con.OutWires.Add(outputWire);
                        }
                        else if (operationType == VariableOperationType.Binary_Multiplication)
                        {
                            var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Mul);
                            ret.Constraints.Add(con);

                            con.InWires.Add(inVars[0].Wires[0]);
                            con.InWires.Add(inVars[1].Wires[0]);
                            con.OutWires.Add(outputWire);
                        }
                        else if (operationType == VariableOperationType.Binary_Subtract)
                        {
                            // var3= var2 * (-1)
                            var con1 = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Mul);
                            ret.Constraints.Add(con1);

                            con1.InWires.Add(inVars[1].Wires[0]);
                            con1.InWires.Add(commonArg.MinusOneWire);

                            var var3 = new PinocchioWire();
                            ret.AnonymousWires.Add(var3);

                            con1.OutWires.Add(var3);

                            // ret = var1 + var 3

                            var con = new BasicPinocchioConstraint(BasicPinocchioConstraintType.Add);
                            ret.Constraints.Add(con);

                            con.InWires.Add(inVars[0].Wires[0]);
                            con.InWires.Add(var3);
                            con.OutWires.Add(outputWire);
                        }
                        else
                        {
                            throw CommonException.AssertFailedException();
                        }

                        return(ret);
                    }
                    else
                    {
                        break;
                    }

                default:
                    throw CommonException.AssertFailedException();
                }
                throw new Exception($"Type \"{NType.Field}\" doesn't support \"{operationType.ToString()}\" operation.");
            },
        };