Rather than be influenced/confused by your shader, I started my own. Here's mine.

I am using a 12 inch square of my own construction, so I'm creating a hemisphere of radius 6 inches.

My calculation starts with 2 * U - 1 and 2 * V - 1, resulting in -1 to 1 as my x,y coordinates. A simple Sqrt(x^2 + y^2) [not shown] gives me distance (d) from center on the 2D circle. For the bump height I need h = 6 inch * Sqrt(1 - d^2) which is what you see calculated here into the PoserSurface. For the CyclesSurface I use the Bump node which strictly is meters. Regardless of which root I render, the image is the same.

Grrrrr. Even when I use my height map calculation (spherical center 1, edge 0) I still don't get a match between the bump map and the normal map. I get a mismatch both in FF and SF but the mismatch is different for each.

I'm half-asleep at the moment (and likely half-asleep when I was doing all this too). but yes.

The radius of my hemisphere's 0.5, the distance in the UV plane to any point (u,v) on or within the hemisphere is r = sqrt( (u-0.5)^2 + (v-0.5)^2 ), and I'm trying to calculate the height of the hemisphere above that point in the UV plane using h = sqrt ( (hemisphereRadius)^2 - d^2 )

I opened up Poser Pro 2014 just to confirm my findings because they are strange.

Here are my findings:

As with red (x) and green (y), the blue (z) value is scaled identically. So the blue value for forward-facing/outward normals always has a positive z and therefore the blue value is always at least .5. A blue value of 0 indicates a reversed normal pointing straight into the surface.

FireFly does not use the blue channel value from the normal map AT ALL. It calculates it on its own using exactly the equation you were trying to build with nodes. You don't need to plug anything into the blue channel to use a constructed normal map -- all that matters is that the red and green are set correctly.

FireFly appears to be calculating the actual normal incorrectly. I have always suspected this as every time I constructed a normal map image from a bump map image, the FireFly render with the normal map NEVER matched that of the bump map from which it was derived. It may be that FireFly is using the wrong mapping for blue value. As a consequence, it is impossible to get FireFly to render the correct normals using a normal map.

As I said, I am able to exactly reproduce results in SuperFly with correctly derived normals based on a height map using the hemisphere construction.

Note that I will probably get lots of users objecting that they've used normal maps just fine for years.

That is easily explained without contradiction of my findings.

Here is the explanation:

You never cared that it was wrong because you only did modest normal map deviations. The error I see in FireFly is only severe for normals pointing way off center. For normals that are only slightly off center, everything is directionally correct and only going to be noticed if you really pay attention to every little detail of a reference image from a renderer that is built correctly.

Here are identical setups but rendered with SuperFly. Here, the normal is generated the same in the shader, but the render is very much different. Clearly FireFly is broken.

But! I do see some error in SuperFly handling the SHADOW side with the indirect light. It turns out FireFly did this better than we see here. Peculiar.

Here we are at yRotate = 90 and SuperFly is now making a mistake on the lit side as well -- the same mistake with bump or normal. It's not lit as bright as it should be. Sigh...
And at yRotate = 120, SuperFly has completely lost its marbles. My God -- is it so hard to implement a damn renderer? I know real-time GAMES that do better than this. Jeez.
I almost didn't bother with the 180 degree case, but I'm here already so blah.

Do not waste your time with normals in either FF or SF - just, seriously, don't waste your time.

If you have to use something, use bump, and recognize that SF is actually not as good at this as FF is. On top of that insult, SF is slower. But if you actually want a realistic picture, then use real geometry.

Moral of the story
Do not waste your time with normals in either FF or SF - just, seriously, don't waste your time.
If you have to use something, use bump, and recognize that SF is actually not as good at this as FF is. On top of that insult, SF is slower. But if you actually want a realistic picture, then use real geometry.