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! }
public PinocchioVariableWires(RawVariable rawVariable, PinocchioWire singleWire) : this(rawVariable) { this.Wires.Add(singleWire); }
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."); }, };
public PinocchioTypeWires(NType type, PinocchioWire singleWire) { this.Type = type; this.Wires.Add(singleWire); }
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."); }, };