typename Signal::result_type ViewportGadget::dispatchEvent( GadgetPtr gadget, Signal &(Gadget::*signalGetter)(), const Event &event ) { Event transformedEvent( event ); eventToGadgetSpace( transformedEvent, gadget.get() ); Signal &s = (gadget.get()->*signalGetter)(); return s( gadget.get(), transformedEvent ); }
std::string ViewportGadget::getToolTip( const IECore::LineSegment3f &line ) const { std::string result = IndividualContainer::getToolTip( line ); if( result.size() ) { return result; } std::vector<GadgetPtr> gadgets; gadgetsAt( V2f( line.p0.x, line.p0.y ), gadgets ); for( std::vector<GadgetPtr>::const_iterator it = gadgets.begin(), eIt = gadgets.end(); it != eIt; it++ ) { GadgetPtr gadget = *it; while( gadget && gadget != this ) { IECore::LineSegment3f lineInGadgetSpace = rasterToGadgetSpace( V2f( line.p0.x, line.p0.y) ); result = gadget->getToolTip( lineInGadgetSpace ); if( result.size() ) { return result; } gadget = gadget->parent<Gadget>(); } } return result; }
Gnomon( SceneView *view ) : m_view( view ), m_gadget( new GnomonGadget() ) { ValuePlugPtr plug = new ValuePlug( "gnomon" ); view->addChild( plug ); plug->addChild( new BoolPlug( "visible", Plug::In, true ) ); GadgetPtr xyPlane = new GnomonPlane(); GadgetPtr yzPlane = new GnomonPlane(); GadgetPtr xzPlane = new GnomonPlane(); yzPlane->setTransform( M44f().rotate( V3f( 0, -M_PI / 2.0f, 0 ) ) ); xzPlane->setTransform( M44f().rotate( V3f( M_PI / 2.0f, 0, 0 ) ) ); m_gadget->setChild( "xy", xyPlane ); m_gadget->setChild( "yz", yzPlane ); m_gadget->setChild( "xz", xzPlane ); xyPlane->buttonPressSignal().connect( boost::bind( &Gnomon::buttonPress, this, ::_1, ::_2 ) ); yzPlane->buttonPressSignal().connect( boost::bind( &Gnomon::buttonPress, this, ::_1, ::_2 ) ); xzPlane->buttonPressSignal().connect( boost::bind( &Gnomon::buttonPress, this, ::_1, ::_2 ) ); view->viewportGadget()->setChild( "__gnomon", m_gadget ); view->plugDirtiedSignal().connect( boost::bind( &Gnomon::plugDirtied, this, ::_1 ) ); update(); }
void HashDifficultyEnforcer_Gadget::generateWitness() { // Take the packed representation and unpack to bits. hashValueUnpacker_->generateWitness(); // In a real setting we would add an assertion that the value will indeed satisfy the // difficulty constraint, and notify the user with an error otherwise. As this is a tutorial, // we'll let invalid values pass through so that we can see how isSatisfied() returns false. }
void ViewportGadget::emitEnterLeaveEvents( GadgetPtr newGadgetUnderMouse, GadgetPtr oldGadgetUnderMouse, const ButtonEvent &event ) { // figure out the lowest point in the hierarchy where the entered status is unchanged. GadgetPtr lowestUnchanged = this; if( oldGadgetUnderMouse && newGadgetUnderMouse ) { if( oldGadgetUnderMouse->isAncestorOf( newGadgetUnderMouse ) ) { lowestUnchanged = oldGadgetUnderMouse; } else if( newGadgetUnderMouse->isAncestorOf( oldGadgetUnderMouse ) ) { lowestUnchanged = newGadgetUnderMouse; } else { lowestUnchanged = oldGadgetUnderMouse->commonAncestor<Gadget>( newGadgetUnderMouse ); } } // emit leave events, innermost first if( oldGadgetUnderMouse ) { GadgetPtr leaveTarget = oldGadgetUnderMouse; while( leaveTarget != lowestUnchanged ) { dispatchEvent( leaveTarget, &Gadget::leaveSignal, event ); leaveTarget = leaveTarget->parent<Gadget>(); } } // emit enter events, outermost first if( newGadgetUnderMouse ) { std::vector<GadgetPtr> enterTargets; GadgetPtr enterTarget = newGadgetUnderMouse; while( enterTarget != lowestUnchanged ) { enterTargets.push_back( enterTarget ); enterTarget = enterTarget->parent<Gadget>(); } for( std::vector<GadgetPtr>::const_reverse_iterator it = enterTargets.rbegin(); it!=enterTargets.rend(); it++ ) { dispatchEvent( *it, &Gadget::enterSignal, event ); } } };
void HashDifficultyEnforcer_Gadget::generateConstraints() { // enforce that both representations are equal hashValueUnpacker_->generateConstraints(); // add constraints asserting that the first 'difficultyBits' bits of 'hashValue' equal 0. Note // endianness, unpacked()[0] is LSB and unpacked()[63] is MSB for (size_t i = 0; i < difficultyBits_; ++i) { addUnaryConstraint(hashValue_.unpacked()[63 - i], GADGETLIB2_FMT("hashValue[%u] == 0", 63 - i)); } }
ConnectionGadget *GraphGadget::reconnectionGadgetAt( NodeGadget *gadget, const IECore::LineSegment3f &lineInGadgetSpace ) const { std::vector<GadgetPtr> gadgetsUnderMouse; Imath::V3f center = gadget->transformedBound( this ).center(); const Imath::V3f corner0 = center - Imath::V3f( 2, 2, 1 ); const Imath::V3f corner1 = center + Imath::V3f( 2, 2, 1 ); std::vector<IECoreGL::HitRecord> selection; { ViewportGadget::SelectionScope selectionScope( corner0, corner1, this, selection, IECoreGL::Selector::IDRender ); const Style *s = style(); s->bind(); for ( ChildContainer::const_iterator it = children().begin(); it != children().end(); ++it ) { if ( ConnectionGadget *c = IECore::runTimeCast<ConnectionGadget>( it->get() ) ) { // don't consider the node's own connections, or connections without a source nodule if ( c->srcNodule() && gadget->node() != c->srcNodule()->plug()->node() && gadget->node() != c->dstNodule()->plug()->node() ) { c->render( s ); } } } } for ( std::vector<IECoreGL::HitRecord>::const_iterator it = selection.begin(); it != selection.end(); ++it ) { GadgetPtr gadget = Gadget::select( it->name.value() ); if ( gadget ) { return runTimeCast<ConnectionGadget>( gadget.get() ); } } return 0; }
void NAND_Gadget::generateWitness() { // First we can assert that all input values are indeed boolean. The purpose of this assertion // is simply to print a clear error message, it is not security critical. // Notice the method val() which returns a reference to the current assignment for a variable for (const auto& input : inputs_) { GADGETLIB_ASSERT(val(input) == 0 || val(input) == 1, "NAND input is not boolean"); } // we will invoke the AND gate witness generator, this will set andResult_ correctly andGadget_->generateWitness(); // and now we set the value of output_ val(output_) = 1 - val(andResult_); // notice the use of 'val()' to tell the protoboard to assign this new value to the // variable 'output_'. The variable itself is only a formal variable and never changes. }
// And now for a test which will exemplify the usage: TEST(Examples, NAND_Gadget) { // initialize the field initPublicParamsFromDefaultPp(); // create a protoboard for a system of rank 1 constraints over a prime field. ProtoboardPtr pb = Protoboard::create(R1P); // create 5 variables inputs[0]...iputs[4]. The string "inputs" is used for debug messages FlagVariableArray inputs(5, "inputs"); FlagVariable output("output"); GadgetPtr nandGadget = NAND_Gadget::create(pb, inputs, output); // now we can generate a constraint system (or circuit) nandGadget->generateConstraints(); // if we try to evaluate the circuit now, an exception will be thrown, because we will // be attempting to evaluate unasigned variables. EXPECT_ANY_THROW(pb->isSatisfied()); // so lets assign the input variables for NAND and try again after creating the witness for (const auto& input : inputs) { pb->val(input) = 1; } nandGadget->generateWitness(); EXPECT_TRUE(pb->isSatisfied()); EXPECT_TRUE(pb->val(output) == 0); // now lets try to ruin something and see what happens pb->val(inputs[2]) = 0; EXPECT_FALSE(pb->isSatisfied()); // now let try to cheat. If we hadn't enforced booleanity, this would have worked! pb->val(inputs[1]) = 2; EXPECT_FALSE(pb->isSatisfied()); // now lets reset inputs[1] to a valid value pb->val(inputs[1]) = 1; // before, we set both the inputs and the output. Notice the output is still set to '0' EXPECT_TRUE(pb->val(output) == 0); // Now we will let the gadget compute the result using generateWitness() and see what happens nandGadget->generateWitness(); EXPECT_TRUE(pb->val(output) == 1); EXPECT_TRUE(pb->isSatisfied()); }
void NAND_Gadget::generateConstraints() { // we will invoke the AND gate constraint generator andGadget_->generateConstraints(); // and add our out negation constraint in order to make this a NAND gate addRank1Constraint(1, 1 - andResult_, output_, "1 * (1 - andResult) = output"); // Another way to write the same constraint is: // addUnaryConstraint(1 - andResult_ - output_, "1 - andResult == output"); // // At first look, it would seem that this is enough. However, the AND_Gadget expects all of its // inputs to be boolean, a dishonest prover could put non-boolean inputs, so we must check this // here. Notice 'FlagVariable' means a variable which we intend to hold only '0' or '1', but // this is just a convention (it is a typedef for Variable) and we must enforce it. // Look into the internals of the R1P implementation of AND_Gadget and see that // {2, 1, 0} as inputs with {1} as output would satisfy all constraints, even though this is // clearly not our intent! for (const auto& input : inputs_) { enforceBooleanity(input); // This adds a constraint of the form: input * (1 - input) == 0 } }
void NoduleLayout::updateLayout() { // Figure out the order we want to display things in // and clear our main container ready for filling in // that order. vector<GadgetKey> items = layoutOrder(); LinearContainer *gadgetContainer = noduleContainer(); gadgetContainer->clearChildren(); vector<Gadget *> added; vector<GadgetPtr> removed; // Iterate over the items we need to lay out, creating // or reusing gadgets and adding them to the layout. for( vector<GadgetKey>::const_iterator it = items.begin(), eIt = items.end(); it != eIt; ++it ) { const GadgetKey &item = *it; const IECore::InternedString gadgetType = ::gadgetType( m_parent.get(), *it ); GadgetPtr gadget; GadgetMap::iterator gadgetIt = m_gadgets.find( item ); if( gadgetIt != m_gadgets.end() && gadgetIt->second.type == gadgetType ) { gadget = gadgetIt->second.gadget; } else { // No gadget created yet, or it's the wrong type if( item.which() == 0 ) { gadget = Nodule::create( const_cast<Plug *>( boost::get<const Plug *>( item ) ) ); /// \todo Fix cast } else { gadget = createCustomGadget( gadgetType, m_parent.get() ); } added.push_back( gadget.get() ); if( gadgetIt != m_gadgets.end() ) { removed.push_back( gadgetIt->second.gadget ); } m_gadgets[item] = TypeAndGadget( gadgetType, gadget ); } if( gadget ) { gadgetContainer->addChild( gadget ); } } // Remove any gadgets we didn't use boost::container::flat_set<GadgetKey> itemsSet( items.begin(), items.end() ); for( GadgetMap::iterator it = m_gadgets.begin(), eIt = m_gadgets.end(); it != eIt; ) { GadgetMap::iterator next = it; ++next; if( itemsSet.find( it->first ) == itemsSet.end() ) { removed.push_back( it->second.gadget ); m_gadgets.erase( it ); } it = next; } // Let everyone know what we've done. /// \todo Maybe we shouldn't know about the NodeGadget? if( NodeGadget *nodeGadget = ancestor<NodeGadget>() ) { for( vector<GadgetPtr>::const_iterator it = removed.begin(), eIt = removed.end(); it != eIt; ++it ) { if( Nodule *n = runTimeCast<Nodule>( it->get() ) ) { nodeGadget->noduleRemovedSignal()( nodeGadget, n ); } } for( vector<Gadget *>::const_iterator it = added.begin(), eIt = added.end(); it != eIt; ++it ) { if( Nodule *n = runTimeCast<Nodule>( *it ) ) { nodeGadget->noduleAddedSignal()( nodeGadget, n ); } } } }