Fix exchange validation
Now that it accepts any (projective) base as input, we need to check the projective equation, rather than the affine one, which assumes Z = 1.
This commit is contained in:
		
							parent
							
								
									73e0df0b5e
								
							
						
					
					
						commit
						dcd7f93a3c
					
				| 
						 | 
					@ -62,37 +62,43 @@ local function exchangeOnPoint(sk, P)
 | 
				
			||||||
    local xP = c25.dadd(dP, rP, xrP)
 | 
					    local xP = c25.dadd(dP, rP, xrP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Extract coordinates for scaling.
 | 
					    -- Extract coordinates for scaling.
 | 
				
			||||||
 | 
					    local Px, Pz = P[1], P[2]
 | 
				
			||||||
    local xPx, xPz = xP[1], xP[2]
 | 
					    local xPx, xPz = xP[1], xP[2]
 | 
				
			||||||
    local rPx, rPz = rP[1], rP[2]
 | 
					    local rPx, rPz = rP[1], rP[2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- Ensure all Z coordinates are squares.
 | 
				
			||||||
 | 
					    Px, Pz = fp.mul(Px, Pz), fp.square(Pz)
 | 
				
			||||||
 | 
					    xPx, xPz = fp.mul(xPx, xPz), fp.square(xPz)
 | 
				
			||||||
 | 
					    rPx, rPz = fp.mul(rPx, rPz), fp.square(rPz)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- We're splitting the secret x into (x - r (mod q), r). The multiplication
 | 
					    -- We're splitting the secret x into (x - r (mod q), r). The multiplication
 | 
				
			||||||
    -- adds them back together, but this only works if P's order is q, which is
 | 
					    -- adds them back together, but this only works if P's order is q, which is
 | 
				
			||||||
    -- not the case on the twist.
 | 
					    -- not the case on the twist.
 | 
				
			||||||
    -- As a result, we need to check if P is on the twist and return 0 so as to
 | 
					    -- As a result, we need to check if P is on the twist and return 0 so as to
 | 
				
			||||||
    -- not leak part of x. We do this by checking the curve equation against P.
 | 
					    -- not leak part of x. We do this by checking the curve equation against P.
 | 
				
			||||||
    -- The equation for Curve25519 is y² = x³ + 486662x² + x. Checking it
 | 
					    -- The projective equation for curve25519 is Y²Z = X(X² + AXZ + Z²). Since Z
 | 
				
			||||||
    -- amounts to verifying that x³ + 486662x² + x is a quadratic residue.
 | 
					    -- is a square, checking validity means checking the right-hand side to be a
 | 
				
			||||||
    local Px = P[1]
 | 
					    -- square.
 | 
				
			||||||
    local Px2 = fp.square(Px)
 | 
					    local Px2 = fp.square(Px)
 | 
				
			||||||
    local Px3 = fp.mul(Px2, Px)
 | 
					    local Pz2 = fp.square(Pz)
 | 
				
			||||||
    local APx2 = fp.kmul(Px2, 486662)
 | 
					    local Pxz = fp.mul(Px, Pz)
 | 
				
			||||||
    local Py2 = fp.carry(fp.add(fp.carry(fp.add(Px3, APx2)), Px))
 | 
					    local APxz = fp.kmul(Pxz, 486662)
 | 
				
			||||||
 | 
					    local rhs = fp.mul(Px, fp.add(Px2, fp.carry(fp.add(APxz, Pz2))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Square the Z coordinate on both products.
 | 
					    -- Find the square root of 1 / (rhs * xPz * rPz).
 | 
				
			||||||
    xPx, xPz = fp.mul(xPx, xPz), fp.square(xPz)
 | 
					    -- Neither rPz, xPz, nor rhs are 0:
 | 
				
			||||||
    rPx, rPz = fp.mul(rPx, rPz), fp.square(rPz)
 | 
					    -- - If rhs was 0, then P would be low order, which would return at (1).
 | 
				
			||||||
 | 
					 | 
				
			||||||
    -- Find the square root of 1 / (Py2 * xPz * rPz).
 | 
					 | 
				
			||||||
    -- Neither rPz, xPz, nor Py2 are 0:
 | 
					 | 
				
			||||||
    -- - If Py2 was 0, then P would be low order, which would return at (1).
 | 
					 | 
				
			||||||
    -- - Since P isn't low order, clamping prevents the ladder from returning O.
 | 
					    -- - Since P isn't low order, clamping prevents the ladder from returning O.
 | 
				
			||||||
    -- Since we've just squared both xPz and rPz, the root will exist iff Py2 is
 | 
					    -- Since we've just squared both xPz and rPz, the root will exist iff rhs is
 | 
				
			||||||
    -- a quadratic residue. This checks the curve equation, so we're done.
 | 
					    -- a square. This checks the curve equation, so we're done.
 | 
				
			||||||
    local root = fp.sqrtDiv(fp.num(1), fp.mul(fp.mul(xPz, rPz), Py2))
 | 
					    local root = fp.sqrtDiv(fp.num(1), fp.mul(fp.mul(xPz, rPz), rhs))
 | 
				
			||||||
    if not root then return fp.encode(fp.num(0)) end
 | 
					    if not root then
 | 
				
			||||||
 | 
					        local out = fp.encode(fp.num(0))
 | 
				
			||||||
 | 
					        return out, out
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Get the inverses of both Z values.
 | 
					    -- Get the inverses of both Z values.
 | 
				
			||||||
    local xPzrPzInv = fp.mul(fp.square(root), Py2)
 | 
					    local xPzrPzInv = fp.mul(fp.square(root), rhs)
 | 
				
			||||||
    local xPzInv = fp.mul(xPzrPzInv, rPz)
 | 
					    local xPzInv = fp.mul(xPzrPzInv, rPz)
 | 
				
			||||||
    local rPzInv = fp.mul(xPzrPzInv, xPz)
 | 
					    local rPzInv = fp.mul(xPzrPzInv, xPz)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue