Stabilize x25519c.lua

This commit is contained in:
Miguel Oliveira 2023-10-29 19:37:38 -03:00
parent 9d7943920f
commit 91072fa555
3 changed files with 13 additions and 92 deletions

View file

@ -26,21 +26,7 @@ local function exchange(sk, pk)
return c25.encode(c25.scale(c25.ladder8(c25.decode(pk), util.bits8(sk)))) return c25.encode(c25.scale(c25.ladder8(c25.decode(pk), util.bits8(sk))))
end end
--- Performs the key exchange, but decoding the public key as an Edwards25519
--- point, using the birational map.
--- @param sk string A Curve25519 secret key
--- @param pk string An Edwards25519 public key, usually derived from someone else's secret key.
--- @return string ss The 32-byte shared secret between both keys.
local function exchangeEd(sk, pk)
expect(1, sk, "string")
lassert(#sk == 32, "secret key length must be 32", 2)
expect(2, pk, "string")
lassert(#pk == 32, "public key length must be 32", 2) --- @cast pk String32
return c25.encode(c25.scale(c25.ladder8(c25.decodeEd(pk), util.bits8(sk))))
end
return { return {
publicKey = publicKey, publicKey = publicKey,
exchange = exchange, exchange = exchange,
_EXPERIMENTAL_exchangeEd = exchangeEd,
} }

View file

@ -3,14 +3,13 @@ local lassert = require "ccryptolib.internal.util".lassert
local fq = require "ccryptolib.internal.fq" local fq = require "ccryptolib.internal.fq"
local fp = require "ccryptolib.internal.fp" local fp = require "ccryptolib.internal.fp"
local c25 = require "ccryptolib.internal.curve25519" local c25 = require "ccryptolib.internal.curve25519"
local ed = require "ccryptolib.internal.edwards25519"
local sha512 = require "ccryptolib.internal.sha512" local sha512 = require "ccryptolib.internal.sha512"
local random = require "ccryptolib.random" local random = require "ccryptolib.random"
--- Masks an exchange secret key. --- Masks an exchange secret key.
--- @param sk string A random 32-byte Curve25519 secret key. --- @param sk string A random 32-byte Curve25519 secret key.
--- @return string msk A masked secret key. --- @return string msk A masked secret key.
local function maskX(sk) local function mask(sk)
expect(1, sk, "string") expect(1, sk, "string")
lassert(#sk == 32, "secret key length must be 32", 2) lassert(#sk == 32, "secret key length must be 32", 2)
local mask = random.random(32) local mask = random.random(32)
@ -26,7 +25,7 @@ end
function maskS(sk) function maskS(sk)
expect(1, sk, "string") expect(1, sk, "string")
lassert(#sk == 32, "secret key length must be 32", 2) lassert(#sk == 32, "secret key length must be 32", 2)
return maskX(sha512.digest(sk):sub(1, 32)) return mask(sha512.digest(sk):sub(1, 32))
end end
--- Rerandomizes the masking on a masked key. --- Rerandomizes the masking on a masked key.
@ -115,24 +114,12 @@ end
--- Returns the X25519 public key of this masked key. --- Returns the X25519 public key of this masked key.
--- @param msk string A masked secret key. --- @param msk string A masked secret key.
local function publicKeyX(msk) local function publicKey(msk)
expect(1, msk, "string") expect(1, msk, "string")
lassert(#msk == 64, "masked secret key length must be 64", 2) lassert(#msk == 64, "masked secret key length must be 64", 2)
return (exchangeOnPoint(msk, c25.G)) return (exchangeOnPoint(msk, c25.G))
end end
--- Returns the Ed25519 public key of this masked key.
--- @param msk string A masked secret key.
--- @return string pk The Ed25519 public key matching this masked key.
local function publicKeyS(msk)
expect(1, msk, "string")
lassert(#msk == 64, "masked secret key length must be 64", 2)
local xr = fq.decode(msk:sub(1, 32))
local r = fq.decodeClamped(msk:sub(33))
local y = ed.add(ed.mulG(fq.bits(xr)), ed.niels(ed.mulG(fq.bits(r))))
return ed.encode(ed.scale(y))
end
--- Performs a double key exchange. --- Performs a double key exchange.
--- ---
--- Returns 0 if the input public key has small order or if it isn't in the base --- Returns 0 if the input public key has small order or if it isn't in the base
@ -146,7 +133,7 @@ end
--- @param pk string An X25519 public key. --- @param pk string An X25519 public key.
--- @return string sss The shared secret between the public key and the static half of the masked key. --- @return string sss The shared secret between the public key and the static half of the masked key.
--- @return string sse The shared secret betwen the public key and the ephemeral half of the masked key. --- @return string sse The shared secret betwen the public key and the ephemeral half of the masked key.
local function exchangeX(sk, pk) local function exchange(sk, pk)
expect(1, sk, "string") expect(1, sk, "string")
lassert(#sk == 64, "masked secret key length must be 64", 2) lassert(#sk == 64, "masked secret key length must be 64", 2)
expect(2, pk, "string") expect(2, pk, "string")
@ -154,62 +141,10 @@ local function exchangeX(sk, pk)
return exchangeOnPoint(sk, c25.decode(pk)) return exchangeOnPoint(sk, c25.decode(pk))
end end
--- Performs an exchange against an Ed25519 key.
---
--- This is done by converting the key into X25519 before passing it to the
--- regular exchange. Using this function on the result of @{signaturePk} leads
--- to the same value as using @{exchange} on the result of @{exchangePk}.
---
--- @param sk string A masked secret key.
--- @param pk string An Ed25519 public key.
--- @return string sss The shared secret between the public key and the static half of the masked key.
--- @return string sse The shared secret betwen the public key and the ephemeral half of the masked key.
local function exchangeS(sk, pk)
expect(1, sk, "string")
lassert(#sk == 64, "masked secret key length must be 64", 2)
expect(2, pk, "string")
lassert(#pk == 32, "public key length must be 32", 2) --- @cast pk String32
return exchangeOnPoint(sk, c25.decodeEd(pk))
end
--- Signs a message using Ed25519.
--- @param sk string A masked secret key.
--- @param pk string The Ed25519 public key matching the secret key.
--- @param msg string A message to sign.
--- @return string sig The signature on the message.
local function sign(sk, pk, msg)
expect(1, sk, "string")
lassert(#sk == 64, "masked secret key length must be 64", 2)
expect(2, pk, "string")
lassert(#pk == 32, "public key length must be 32", 2)
expect(3, msg, "string")
-- Secret key.
local xr = fq.decode(sk:sub(1, 32))
local r = fq.decodeClamped(sk:sub(33))
-- Commitment.
local k = fq.decodeWide(random.random(64))
local rStr = ed.encode(ed.mulG(fq.bits(k)))
-- Challenge.
local e = fq.decodeWide(sha512.digest(rStr .. pk .. msg))
-- Response.
local s = fq.add(fq.add(k, fq.mul(xr, e)), fq.mul(r, e))
local sStr = fq.encode(s)
return rStr .. sStr
end
return { return {
_EXPERIMENTAL_maskX = maskX, mask = mask,
_EXPERIMENTAL_maskS = maskS, remask = remask,
_EXPERIMENTAL_remask = remask, publicKey = publicKey,
_EXPERIMENTAL_publicKeyX = publicKeyX, ephemeralSk = ephemeralSk,
_EXPERIMENTAL_ephemeralSk = ephemeralSk, exchange = exchange,
_EXPERIMENTAL_publicKeyS = publicKeyS,
_EXPERIMENTAL_exchangeX = exchangeX,
_EXPERIMENTAL_exchangeS = exchangeS,
_EXPERIMENTAL_sign = sign,
} }

View file

@ -9,12 +9,12 @@ local x25519c = require "ccryptolib.x25519c"
require "ccryptolib.random".init("mock initialization") require "ccryptolib.random".init("mock initialization")
local function exchange(sk, pk) local function exchange(sk, pk)
local sk = x25519c._EXPERIMENTAL_maskX(sk) local sk = x25519c.mask(sk)
sk = x25519c._EXPERIMENTAL_remask(sk) sk = x25519c.remask(sk)
return (x25519c._EXPERIMENTAL_exchangeX(sk, pk)) return (x25519c.exchange(sk, pk))
end end
describe("x25519c._EXPERIMENTAL_exchangeX", function() describe("x25519c.exchange", function()
it("passes the section 5.2 test vector #1", function() it("passes the section 5.2 test vector #1", function()
local x = util.hexcat { local x = util.hexcat {
"a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4", "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",