Add birational decoding of Edwards25519 points
I really dislike this interface, I'll probably need to think of something else.
This commit is contained in:
parent
a7d98da04c
commit
374ba5ee4a
|
@ -121,6 +121,25 @@ local function decode(str)
|
|||
return {fp.decode(str), fp.num(1)}
|
||||
end
|
||||
|
||||
--- Decodes an Edwards25519 encoded point into Curve25519, ignoring the sign.
|
||||
--
|
||||
-- There is a single exception: The identity point (0, 1), which gets mapped
|
||||
-- into the 2-torsion point (0, 0), which isn't the identity of Curve25519.
|
||||
--
|
||||
-- @tparam string str A 32-byte encoded Edwards25519 point.
|
||||
-- @treturn point The decoded point, mapped into Curve25519.
|
||||
--
|
||||
local function decodeEd(str)
|
||||
local y = fp.decode(str)
|
||||
local n = fp.carry(fp.add(fp.num(1), y))
|
||||
local d = fp.carry(fp.sub(fp.num(1), y))
|
||||
if fp.eqz(d) then
|
||||
return {fp.num(0), fp.num(1)}
|
||||
else
|
||||
return {n, d}
|
||||
end
|
||||
end
|
||||
|
||||
--- Performs a scalar multiplication by the base point G.
|
||||
--
|
||||
-- @tparam {number...} bits The scalar multiplier, in little-endian bits.
|
||||
|
@ -269,6 +288,7 @@ return {
|
|||
scale = scale,
|
||||
encode = encode,
|
||||
decode = decode,
|
||||
decodeEd = decodeEd,
|
||||
ladder8 = ladder8,
|
||||
mulG = mulG,
|
||||
prac = prac,
|
||||
|
|
|
@ -34,4 +34,13 @@ function mod.exchange(sk, pk)
|
|||
return c25.encode(c25.scale(c25.ladder8(c25.decode(pk), util.bits8(sk))))
|
||||
end
|
||||
|
||||
--- Same as @{exchange}, but decodes the public key as an Edwards25519 point.
|
||||
function mod.exchangeEd(sk, pk)
|
||||
expect(1, sk, "string")
|
||||
assert(#sk == 32, "secret key length must be 32")
|
||||
expect(2, pk, "string")
|
||||
assert(#pk == 32, "public key length must be 32")
|
||||
return c25.encode(c25.scale(c25.ladder8(c25.decodeEd(pk), util.bits8(sk))))
|
||||
end
|
||||
|
||||
return mod
|
||||
|
|
|
@ -27,23 +27,7 @@ local function remask(msk, oldMask)
|
|||
return fq.encode(xs), newMask
|
||||
end
|
||||
|
||||
--- Treats both shares as X25519 keys and performs a double key exchange.
|
||||
--
|
||||
-- Returns 0 if the input public key has small order or if it isn't in the base
|
||||
-- curve. This is different from standard X25519, which performs the exchange
|
||||
-- even on the twist.
|
||||
--
|
||||
-- May incorrectly return 0 with negligible chance if the mask happens to match
|
||||
-- the masked key. I haven't checked if clamping prevents that from happening.
|
||||
--
|
||||
local function exchange(msk, mask, pk)
|
||||
expect(1, msk, "string")
|
||||
assert(#msk == 32, "masked secret key length must be 32")
|
||||
expect(2, mask, "string")
|
||||
assert(#mask == 32, "mask length must be 32")
|
||||
expect(3, pk, "string")
|
||||
assert(#pk == 32, "public key length must be 32")
|
||||
local P = c25.decode(pk)
|
||||
local function exchangeOnPoint(msk, mask, P)
|
||||
local xr = fq.decode(msk)
|
||||
local r = fq.decodeClamped8(mask)
|
||||
local rP, xrP, dP = c25.prac(P, fq.makeRuleset(r, xr))
|
||||
|
@ -95,8 +79,39 @@ local function exchange(msk, mask, pk)
|
|||
return fp.encode(fp.mul(xPx, xPzInv)), fp.encode(fp.mul(rPx, rPzInv))
|
||||
end
|
||||
|
||||
--- Treats both shares as X25519 keys and performs a double key exchange.
|
||||
--
|
||||
-- Returns 0 if the input public key has small order or if it isn't in the base
|
||||
-- curve. This is different from standard X25519, which performs the exchange
|
||||
-- even on the twist.
|
||||
--
|
||||
-- May incorrectly return 0 with negligible chance if the mask happens to match
|
||||
-- the masked key. I haven't checked if clamping prevents that from happening.
|
||||
--
|
||||
local function exchange(msk, mask, pk)
|
||||
expect(1, msk, "string")
|
||||
assert(#msk == 32, "masked secret key length must be 32")
|
||||
expect(2, mask, "string")
|
||||
assert(#mask == 32, "mask length must be 32")
|
||||
expect(3, pk, "string")
|
||||
assert(#pk == 32, "public key length must be 32")
|
||||
return exchangeOnPoint(msk, mask, c25.decode(pk))
|
||||
end
|
||||
|
||||
--- Same as @{exchange}, but decodes the public key as an Edwards25519 point.
|
||||
local function exchangeEd(msk, mask, pk)
|
||||
expect(1, msk, "string")
|
||||
assert(#msk == 32, "masked secret key length must be 32")
|
||||
expect(2, mask, "string")
|
||||
assert(#mask == 32, "mask length must be 32")
|
||||
expect(3, pk, "string")
|
||||
assert(#pk == 32, "public key length must be 32")
|
||||
return exchangeOnPoint(msk, mask, c25.decodeEd(pk))
|
||||
end
|
||||
|
||||
return {
|
||||
mask = mask,
|
||||
remask = remask,
|
||||
exchange = exchange,
|
||||
exchangeEd = exchangeEd,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue