Пример #1
0
        public static Variable NizkCombineFunctionResult(StatementResult result, NType resultNType)
        {
            switch (result)
            {
            case StatementResultOneCase ret:
                switch (ret.ExecutionResultType)
                {
                case StatementResultType.Continue:
                case StatementResultType.Break:
                    throw new Exception($"Unexpected \"{ ret.ExecutionResultType.ToString()}\" statement.");

                case StatementResultType.Normal:
                case StatementResultType.Return:

                    Debug.Assert((ret.ExecutionResultType != StatementResultType.Normal) || ret.ReturnVariable == null);
                    if (ret.ReturnVariable != null)
                    {
                        return(ret.ReturnVariable.Assign(resultNType));
                    }

                    if (resultNType == NType.Void)
                    {
                        return(NType.Void.GetEmptyVariable());
                    }
                    else
                    {
                        throw new Exception("Missing \"return\" statement.");
                    }

                default:
                    throw CommonException.AssertFailedException();
                }

            case StatementResultTwoCase ret:
                if (resultNType == NType.Void)
                {
                    return(NType.Void.GetEmptyVariable());
                }

                var trueVar  = NizkCombineFunctionResult(ret.TrueCase, resultNType);
                var falseVar = NizkCombineFunctionResult(ret.FalseCase, resultNType);



                return(NizkConditionVariable(ret.Condition, trueVar, falseVar));

            default:
                throw CommonException.AssertFailedException();
            }
        }
Пример #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!
        }
Пример #3
0
        public static VariableMap GetMapFromVariableConnection(ICollection <VariableRef> inputVariables, ICollection <VariableRef> nizkVariables, ICollection <VariableRef> outputVariables)
        {
            var varToVarRefs = new Dictionary <RawVariable, VariableRef>();

            foreach (var inputVariable in inputVariables)
            {
                varToVarRefs.Add(inputVariable.Variable.RawVariable, inputVariable);
            }
            foreach (var nizkVariable in nizkVariables)
            {
                varToVarRefs.Add(nizkVariable.Variable.RawVariable, nizkVariable);
            }
            foreach (var outputVariable in outputVariables)
            {
                varToVarRefs.Add(outputVariable.Variable.RawVariable, outputVariable);
            }

            var varToNode = new Dictionary <RawVariable, VariableNode>();

            var conToNode = new Dictionary <VariableConnection, OperationNode>();

            var mapAllNodes  = new List <IVariableMapNode>();
            var mapRootNodes = new List <IVariableMapNode>();

            VariableNode AddVariableNode(Variable itemVariable)
            {
                if (varToNode.ContainsKey(itemVariable.RawVariable))
                {
                    return(varToNode[itemVariable.RawVariable]);
                }

                VariableNode varNode;

                if (varToVarRefs.ContainsKey(itemVariable.RawVariable))
                {
                    var varRef = varToVarRefs[itemVariable.RawVariable];
                    switch (varRef.NizkAttribute)
                    {
                    case NizkVariableType.Input:
                    case NizkVariableType.NizkInput:
                    case NizkVariableType.Output:
                        varNode = new VariableNode(varRef);
                        break;

                    case NizkVariableType.Intermediate:
                    default:
                        throw CommonException.AssertFailedException();
                    }
                }
                else
                {
                    varNode = new VariableNode(itemVariable);
                }

                varToNode.Add(itemVariable.RawVariable, varNode);
                mapAllNodes.Add(varNode);

                if (0 == (itemVariable.ParentConnections?.Count ?? 0))
                {
                    mapRootNodes.Add(varNode);
                }
                else
                {
                    foreach (var connection in itemVariable.ParentConnections)
                    {
                        //save connection
                        if (!conToNode.ContainsKey(connection))
                        {
                            var conNode = new OperationNode()
                            {
                                ConnectionType = connection.OperationType,
                            };

                            conToNode.Add(connection, conNode);
                            mapAllNodes.Add(conNode);

                            //find other out var
                            //note: keep the order of conNode.NextNodes
                            foreach (var connectionOutVariable in connection.OutVariables)
                            {
                                var outNode = AddVariableNode(connectionOutVariable);
                                conNode.NextNodes.Add(outNode);
                                outNode.PrevNodes.Add(conNode);
                            }

                            //find other in var
                            //note: keep the order of conNode.PrevNodes
                            foreach (var connectionInVariable in connection.InVariables)
                            {
                                var inNode = AddVariableNode(connectionInVariable);
                                conNode.PrevNodes.Add(inNode);
                                inNode.NextNodes.Add(conNode);
                            }
                        }
                    }
                }

                return(varNode);
            }

            foreach (var variableRef in outputVariables)
            {
                _ = AddVariableNode(variableRef.Variable);
            }

            Debug.Assert(mapAllNodes.Where(node => node.PrevNodes.Count == 0).Intersect(mapRootNodes).Count() == mapRootNodes.Count);



            foreach (var mapNode in mapRootNodes)
            {
                // only the following are permitted: (IsConstant=True) or (IsConstant=false and input/nizk)

                if (mapNode is VariableNode varNode)
                {
                    if (!varNode.RawVariable.Value.IsConstant)
                    {
                        // is special var: has varRef
                        if (varToVarRefs.ContainsKey(varNode.RawVariable))
                        {
                            Debug.Assert(!varNode.RawVariable.Value.IsConstant);

                            var varRef = varToVarRefs[varNode.RawVariable];
                            switch (varRef.NizkAttribute)
                            {
                            case NizkVariableType.Input:
                            case NizkVariableType.NizkInput:
                                break;

                            case NizkVariableType.Output:
                                throw new Exception(
                                          $"Runtime error: output variable \"{varRef.VarName}\" has not been assigned.");

                            case NizkVariableType.Intermediate:
                            default:
                                throw CommonException.AssertFailedException();
                            }
                        }
                    }
                    else
                    {
                        // okay
                    }
                }
                else
                {
                    throw CommonException.AssertFailedException();
                }
            }

            return(new VariableMap()
            {
                nodes = mapAllNodes.ToHashSet(),
                rootNodes = mapRootNodes,
            });
        }
Пример #4
0
        public static StatementResult NizkCombineStatementResult(StatementResult result, BasicBlock currentBlock)
        {
            switch (result)
            {
            case StatementResultOneCase ret:
                return(ret);

            case StatementResultTwoCase ret:
                var trueCase  = NizkCombineStatementResult(ret.TrueCase, currentBlock);
                var falseCase = NizkCombineStatementResult(ret.FalseCase, currentBlock);
                if (trueCase is StatementResultOneCase trueOneCase && falseCase is StatementResultOneCase falseOneCase)
                {
                    var trueRetType  = trueOneCase.ExecutionResultType;
                    var falseRetType = falseOneCase.ExecutionResultType;
                    if (trueRetType == falseRetType)
                    {
                        switch (trueRetType)
                        {
                        case StatementResultType.Normal:
                        case StatementResultType.Break:
                        case StatementResultType.Continue:
                            Debug.Assert(trueOneCase.ReturnVariable == null);
                            Debug.Assert(falseOneCase.ReturnVariable == null);
                            Overlay retOverlay;
                            if (trueOneCase.Overlay != falseOneCase.Overlay)
                            {
                                Debug.Assert(trueOneCase.Overlay.ParentOverlay == falseOneCase.Overlay.ParentOverlay);
                                retOverlay = trueOneCase.Overlay.ParentOverlay;

                                //combine two overlay
                                NizkCombineOverlay(
                                    ret.Condition,
                                    new OverlayBlock(trueOneCase.Overlay, currentBlock),
                                    new OverlayBlock(falseOneCase.Overlay, currentBlock),
                                    retOverlay
                                    );
                            }
                            else
                            {
                                //todo is it possible or not?
                                Debug.Assert(false);
                                throw new NotImplementedException();
                            }

                            return(new StatementResultOneCase()
                            {
                                ExecutionResultType = trueRetType,
                                Overlay = retOverlay,
                            });

                        case StatementResultType.Return:
                            // currently, not combining "return"
                            return(ret);

                        default:
                            throw CommonException.AssertFailedException();
                        }
                    }
                    else
                    {
                        return(ret);
                    }
                }
                else
                {
                    return(new StatementResultTwoCase()
                    {
                        Condition = ret.Condition,
                        FalseCase = falseCase,
                        TrueCase = trueCase,
                    });
                }
Пример #5
0
        internal static IEnumerable <Token> Analyze(Stream stream, Encoding encoding)
        {
            using StreamReader reader = new StreamReader(stream, encoding, false, -1, true);

            StringBuilder sb    = new StringBuilder();
            LexState      state = LexState.Empty;

            int row    = 1;
            int column = 0;

            while (true)
            {
                LexChoice choice;

                Int32       nextCharInt  = reader.Peek();
                char        nextChar     = Char.MinValue;
                LexCharType nextCharType = LexCharType.Unknown;

                Debug.Assert((sb.Length == 0) == (state == LexState.Empty));

                if (nextCharInt == -1) // EOL
                {
                    if (state == LexState.Empty)
                    {
                        choice = LexChoice.Terminate;
                    }
                    else if (state == LexState.String || state == LexState.StringEscaping)
                    {
                        throw new Exception("Unexpected end of line. The string is not closed.");
                    }
                    else
                    {
                        choice = LexChoice.PeekReturn;
                    }
                }
                else
                {
                    nextChar = (char)nextCharInt;

                    ++column;
                    if (nextChar == '\n')
                    {
                        column = 0;
                        ++row;
                    }

                    nextCharType = GetCharType(nextChar);

                    switch (state) // a 5 by 6 table
                    {
                    case LexState.LetterOrDigitOrUnderscore when nextCharType == LexCharType.Unknown:
                    case LexState.Empty when nextCharType == LexCharType.Unknown:
                    case LexState.Punctuation when nextCharType == LexCharType.Unknown:
                        throw new Exception("Unrecognized character \"" + nextChar.ToString() + "\"");

                    case LexState.Empty when nextCharType == LexCharType.WhiteSpace:
                        choice = LexChoice.Drop;
                        break;


                    case LexState.LetterOrDigitOrUnderscore when nextCharType == LexCharType.LetterOrDigitOrUnderscore:
                    case LexState.Empty when nextCharType == LexCharType.QuotationMark:
                    case LexState.Empty when nextCharType == LexCharType.Backslash:
                    case LexState.Empty when nextCharType == LexCharType.LetterOrDigitOrUnderscore:
                    case LexState.Empty when nextCharType == LexCharType.OtherPunctuation:
                    case LexState.String when nextCharType == LexCharType.Unknown:
                    case LexState.String when nextCharType == LexCharType.WhiteSpace:
                    case LexState.String when nextCharType == LexCharType.LetterOrDigitOrUnderscore:
                    case LexState.String when nextCharType == LexCharType.OtherPunctuation:
                        choice = LexChoice.ReadAppend;
                        break;

                    case LexState.String when nextCharType == LexCharType.QuotationMark:
                        choice = LexChoice.ReadAppendReturn;
                        break;

                    case LexState.String when nextCharType == LexCharType.Backslash:
                        choice = LexChoice.ReadAppendStringEscapeIn;
                        break;

                    case LexState.StringEscaping when nextCharType == LexCharType.Unknown:
                    case LexState.StringEscaping when nextCharType == LexCharType.WhiteSpace:
                    case LexState.StringEscaping when nextCharType == LexCharType.Backslash:
                    case LexState.StringEscaping when nextCharType == LexCharType.QuotationMark:
                    case LexState.StringEscaping when nextCharType == LexCharType.LetterOrDigitOrUnderscore:
                    case LexState.StringEscaping when nextCharType == LexCharType.OtherPunctuation:
                        choice = LexChoice.ReadAppendStringEscapeOut;
                        break;

                    case LexState.Punctuation when nextCharType == LexCharType.WhiteSpace:
                    case LexState.LetterOrDigitOrUnderscore when nextCharType == LexCharType.WhiteSpace:
                        choice = LexChoice.DropReturn;
                        break;

                    case LexState.Punctuation when nextCharType == LexCharType.LetterOrDigitOrUnderscore:
                    case LexState.LetterOrDigitOrUnderscore when nextCharType == LexCharType.OtherPunctuation:
                    case LexState.LetterOrDigitOrUnderscore when nextCharType == LexCharType.Backslash:
                    case LexState.LetterOrDigitOrUnderscore when nextCharType == LexCharType.QuotationMark:
                        choice = LexChoice.PeekReturn;
                        break;

                    case LexState.Punctuation when nextCharType == LexCharType.Backslash:
                    case LexState.Punctuation when nextCharType == LexCharType.QuotationMark:
                    case LexState.Punctuation when nextCharType == LexCharType.OtherPunctuation:
                        // consider '&' and '&&'
                        if (GetTokenType(sb.ToString()) != null)
                        {
                            if (GetTokenType(sb.ToString() + nextChar) != null)
                            {
                                choice = LexChoice.ReadAppend;
                            }
                            else
                            {
                                choice = LexChoice.PeekReturn;
                            }
                        }
                        else
                        {
                            choice = LexChoice.ReadAppend;
                        }
                        break;

                    default:
                        throw CommonException.AssertFailedException();
                    }
                }

                switch (choice)
                {
                case LexChoice.PeekReturn:
                    yield return(GetToken(sb.ToString(), row, column));

                    _     = sb.Clear();
                    state = LexState.Empty;
                    break;

                case LexChoice.DropReturn:
                    _ = reader.Read();
                    yield return(GetToken(sb.ToString(), row, column));

                    _     = sb.Clear();
                    state = LexState.Empty;
                    break;

                case LexChoice.Drop:
                    _ = reader.Read();
                    break;

                case LexChoice.ReadAppendStringEscapeOut:
                case LexChoice.ReadAppendReturn:
                case LexChoice.ReadAppendStringEscapeIn:
                case LexChoice.ReadAppend:
                    _ = reader.Read();
                    if (state == LexState.Empty)
                    {
                        switch (nextCharType)
                        {
                        case LexCharType.QuotationMark:
                            state = LexState.String;
                            break;

                        case LexCharType.LetterOrDigitOrUnderscore:
                            state = LexState.LetterOrDigitOrUnderscore;
                            break;

                        case LexCharType.Backslash:
                        case LexCharType.OtherPunctuation:
                            state = LexState.Punctuation;
                            break;

                        default:
                            throw CommonException.AssertFailedException();
                        }
                    }
                    _ = sb.Append(nextChar);

                    if (choice == LexChoice.ReadAppendReturn)
                    {
                        yield return(GetToken(sb.ToString(), row, column));

                        _     = sb.Clear();
                        state = LexState.Empty;
                    }
                    else if (choice == LexChoice.ReadAppendStringEscapeIn)
                    {
                        Debug.Assert(state == LexState.String);
                        state = LexState.StringEscaping;
                    }
                    else if (choice == LexChoice.ReadAppendStringEscapeOut)
                    {
                        Debug.Assert(state == LexState.StringEscaping);
                        state = LexState.String;
                    }

                    break;

                case LexChoice.Terminate:
                    yield return(GetEOL(row, column));

                    yield break;

                default:
                    throw CommonException.AssertFailedException();
                }
            }
        }
Пример #6
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.");
            },
        };
Пример #7
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.");
            },
        };