Rework comments to new annotation style
This commit is contained in:
parent
6fbbab378a
commit
cb620cfb0a
|
@ -1,7 +1,4 @@
|
|||
--- The ChaCha20Poly1305AEAD authenticated encryption with associated data (AEAD) construction.
|
||||
--
|
||||
-- @module aead
|
||||
--
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
local lassert = require "ccryptolib.internal.util".lassert
|
||||
|
@ -14,15 +11,13 @@ local u4x4, fmt4x4 = packing.compileUnpack("<I4I4I4I4")
|
|||
local bxor = bit32.bxor
|
||||
|
||||
--- Encrypts a message.
|
||||
--
|
||||
-- @tparam string key A 32-byte random key.
|
||||
-- @tparam string nonce A 12-byte per-message unique nonce.
|
||||
-- @tparam string message The message to be encrypted.
|
||||
-- @tparam string aad Arbitrary associated data to authenticate on decryption.
|
||||
-- @tparam[opt=20] number rounds The number of ChaCha20 rounds to use.
|
||||
-- @treturn string The ciphertext.
|
||||
-- @treturn string The 16-byte authentication tag.
|
||||
--
|
||||
--- @param key string A 32-byte random key.
|
||||
--- @param nonce string A 12-byte per-message unique nonce.
|
||||
--- @param message string The message to be encrypted.
|
||||
--- @param aad string aad Arbitrary associated data to also authenticate.
|
||||
--- @param rounds number? The number of ChaCha20 rounds to use. Defaults to 20.
|
||||
--- @return string ctx The ciphertext.
|
||||
--- @return string tag The 16-byte authentication tag.
|
||||
local function encrypt(key, nonce, message, aad, rounds)
|
||||
expect(1, key, "string")
|
||||
lassert(#key == 32, "key length must be 32", 2)
|
||||
|
@ -53,16 +48,13 @@ local function encrypt(key, nonce, message, aad, rounds)
|
|||
end
|
||||
|
||||
--- Decrypts a message.
|
||||
--
|
||||
-- @tparam string key The key used on encryption.
|
||||
-- @tparam string nonce The nonce used on encryption.
|
||||
-- @tparam string ciphertext The ciphertext to be decrypted.
|
||||
-- @tparam string aad The arbitrary associated data used on encryption.
|
||||
-- @tparam string tag The authentication tag returned on encryption.
|
||||
-- @tparam[opt=20] number rounds The number of rounds used on encryption.
|
||||
-- @treturn[1] string The decrypted plaintext.
|
||||
-- @treturn[2] nil If authentication has failed.
|
||||
--
|
||||
--- @param key string The key used on encryption.
|
||||
--- @param nonce string The nonce used on encryption.
|
||||
--- @param ciphertext string The ciphertext to be decrypted.
|
||||
--- @param aad string The arbitrary associated data used on encryption.
|
||||
--- @param tag string The authentication tag returned on encryption.
|
||||
--- @param rounds number The number of rounds used on encryption.
|
||||
--- @return string? msg The decrypted plaintext. Or nil on auth failure.
|
||||
local function decrypt(key, nonce, tag, ciphertext, aad, rounds)
|
||||
expect(1, key, "string")
|
||||
lassert(#key == 32, "key length must be 32", 2)
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
--- The BLAKE3 cryptographic hash function.
|
||||
--
|
||||
-- @module blake3
|
||||
--
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
local lassert = require "ccryptolib.internal.util".lassert
|
||||
|
@ -208,11 +205,9 @@ end
|
|||
local mod = {}
|
||||
|
||||
--- Hashes data using BLAKE3.
|
||||
--
|
||||
-- @tparam string message The input message.
|
||||
-- @tparam[opt=32] number len The desired hash length, in bytes.
|
||||
-- @treturn string The hash.
|
||||
--
|
||||
--- @param message string The input message.
|
||||
--- @param len number? The desired hash length, in bytes. Defaults to 32.
|
||||
--- @return string hash The hash.
|
||||
function mod.digest(message, len)
|
||||
expect(1, message, "string")
|
||||
len = expect(2, len, "number", "nil") or 32
|
||||
|
@ -222,12 +217,10 @@ function mod.digest(message, len)
|
|||
end
|
||||
|
||||
--- Performs a keyed hash.
|
||||
--
|
||||
-- @tparam string key A 32-byte random key.
|
||||
-- @tparam string message The input message.
|
||||
-- @tparam[opt=32] number len The desired hash length, in bytes.
|
||||
-- @treturn string The keyed hash.
|
||||
--
|
||||
--- @param key string A 32-byte random key.
|
||||
--- @param message string The input message.
|
||||
--- @param len number? The desired hash length, in bytes. Defaults to 32.
|
||||
--- @return string hash The keyed hash.
|
||||
function mod.digestKeyed(key, message, len)
|
||||
expect(1, key, "string")
|
||||
lassert(#key == 32, "key length must be 32", 2)
|
||||
|
@ -239,14 +232,15 @@ function mod.digestKeyed(key, message, len)
|
|||
end
|
||||
|
||||
--- Makes a context-based key derivation function (KDF).
|
||||
--
|
||||
-- @tparam string context The context for the KDF.
|
||||
-- @treturn function(material:string [, len:number]):string The KDF.
|
||||
--
|
||||
--- @param context string The context for the KDF.
|
||||
--- @return fun(material: string, len: number?): string kdf The KDF.
|
||||
function mod.deriveKey(context)
|
||||
expect(1, context, "string")
|
||||
local iv = {u8x4(fmt8x4, blake3(IV, DERIVE_KEY_CONTEXT, context, 32), 1)}
|
||||
|
||||
--- Derives a key.
|
||||
--- @param material string The keying material.
|
||||
--- @param len number? The desired hash length, in bytes. Defaults to 32.
|
||||
return function(material, len)
|
||||
expect(1, material, "string")
|
||||
len = expect(2, len, "number", "nil") or 32
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
--- The ChaCha20 stream cipher.
|
||||
--
|
||||
-- @module chacha20
|
||||
--
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
local lassert = require "ccryptolib.internal.util".lassert
|
||||
|
@ -17,14 +14,12 @@ local u16x4 = packing.compileUnpack(fmt16x4)
|
|||
local mod = {}
|
||||
|
||||
--- Encrypts/Decrypts data using ChaCha20.
|
||||
--
|
||||
-- @tparam string key A 32-byte random key.
|
||||
-- @tparam string nonce A 12-byte per-message unique nonce.
|
||||
-- @tparam string message A plaintext or ciphertext.
|
||||
-- @tparam[opt=20] number rounds The number of ChaCha20 rounds to use.
|
||||
-- @tparam[opt=1] number offset The block offset to generate the keystream at.
|
||||
-- @treturn string The resulting ciphertext or plaintext.
|
||||
--
|
||||
--- @param key string A 32-byte random key.
|
||||
--- @param nonce string A 12-byte per-message unique nonce.
|
||||
--- @param message string A plaintext or ciphertext.
|
||||
--- @param rounds number? The number of ChaCha20 rounds to use. Defaults to 20.
|
||||
--- @param offset number? The block offset to generate the keystream at. Defaults to 1.
|
||||
--- @return string out The resulting ciphertext or plaintext.
|
||||
function mod.crypt(key, nonce, message, rounds, offset)
|
||||
expect(1, key, "string")
|
||||
lassert(#key == 32, "key length must be 32", 2)
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
--- The Ed25519 digital signature scheme.
|
||||
--
|
||||
-- @module ed25519
|
||||
--
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
local lassert = require "ccryptolib.internal.util".lassert
|
||||
|
@ -13,10 +10,8 @@ local random = require "ccryptolib.random"
|
|||
local mod = {}
|
||||
|
||||
--- Computes a public key from a secret key.
|
||||
--
|
||||
-- @tparam string sk A random 32-byte secret key.
|
||||
-- @treturn string The matching 32-byte public key.
|
||||
--
|
||||
--- @param sk string A random 32-byte secret key.
|
||||
--- @return string pk The matching 32-byte public key.
|
||||
function mod.publicKey(sk)
|
||||
expect(1, sk, "string")
|
||||
assert(#sk == 32, "secret key length must be 32")
|
||||
|
@ -28,12 +23,10 @@ function mod.publicKey(sk)
|
|||
end
|
||||
|
||||
--- Signs a message.
|
||||
--
|
||||
-- @tparam string sk The signer's secret key.
|
||||
-- @tparam string pk The signer's public key.
|
||||
-- @tparam string msg The message to be signed.
|
||||
-- @treturn string The 64-byte signature on the message.
|
||||
--
|
||||
--- @param sk string The signer's secret key.
|
||||
--- @param pk string The signer's public key.
|
||||
--- @param msg string The message to be signed.
|
||||
--- @return string sig The 64-byte signature on the message.
|
||||
function mod.sign(sk, pk, msg)
|
||||
expect(1, sk, "string")
|
||||
lassert(#sk == 32, "secret key length must be 32", 2)
|
||||
|
@ -62,21 +55,19 @@ function mod.sign(sk, pk, msg)
|
|||
end
|
||||
|
||||
--- Verifies a signature on a message.
|
||||
--
|
||||
-- @tparam string pk The signer's public key.
|
||||
-- @tparam string msg The signed message.
|
||||
-- @tparam string sig The signature.
|
||||
-- @treturn boolean Whether the signature is valid or not.
|
||||
--
|
||||
--- @param pk string The signer's public key.
|
||||
--- @param msg string The signed message.
|
||||
--- @param sig string The alleged signature.
|
||||
--- @return boolean valid Whether the signature is valid or not.
|
||||
function mod.verify(pk, msg, sig)
|
||||
expect(1, pk, "string")
|
||||
lassert(#pk == 32, "public key length must be 32", 2)
|
||||
lassert(#pk == 32, "public key length must be 32", 2) --- @cast pk String32
|
||||
expect(2, msg, "string")
|
||||
expect(3, sig, "string")
|
||||
lassert(#sig == 64, "signature length must be 64", 2)
|
||||
|
||||
local y = ed.decode(pk)
|
||||
if not y then return nil end
|
||||
if not y then return false end
|
||||
|
||||
local rStr = sig:sub(1, 32)
|
||||
local sStr = sig:sub(33)
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
--- Point arithmetic on the Curve25519 Montgomery curve.
|
||||
--
|
||||
-- :::note Internal Module
|
||||
-- This module is meant for internal use within the library. Its API is unstable
|
||||
-- and subject to change without major version bumps.
|
||||
-- :::
|
||||
--
|
||||
-- <br />
|
||||
--
|
||||
-- @module[kind=internal] internal.curve25519
|
||||
--
|
||||
|
||||
local fp = require "ccryptolib.internal.fp"
|
||||
local ed = require "ccryptolib.internal.edwards25519"
|
||||
local random = require "ccryptolib.random"
|
||||
|
||||
--- @class MtPoint A point class on Curve25519, in XZ coordinates.
|
||||
--- @field [1] number[] The X coordinate.
|
||||
--- @field [2] number[] The Z coordinate.
|
||||
|
||||
--- Doubles a point.
|
||||
--- @param P1 MtPoint The point to double.
|
||||
--- @return MtPoint P2 P1 + P1.
|
||||
local function double(P1)
|
||||
local x1, z1 = P1[1], P1[2]
|
||||
local a = fp.add(x1, z1)
|
||||
|
@ -26,6 +23,11 @@ local function double(P1)
|
|||
return {x3, z3}
|
||||
end
|
||||
|
||||
--- Computes differential addition on two points.
|
||||
--- @param DP MtPoint P1 - P2.
|
||||
--- @param P1 MtPoint The first point to add.
|
||||
--- @param P2 MtPoint The second point to add.
|
||||
--- @return MtPoint P3 P1 + P2.
|
||||
local function dadd(DP, P1, P2)
|
||||
local dx, dz = DP[1], DP[2]
|
||||
local x1, z1 = P1[1], P1[2]
|
||||
|
@ -42,13 +44,11 @@ local function dadd(DP, P1, P2)
|
|||
end
|
||||
|
||||
--- Performs a step on the Montgomery ladder.
|
||||
--
|
||||
-- @param C A - B.
|
||||
-- @param A The first point.
|
||||
-- @param B The second point.
|
||||
-- @return 2A
|
||||
-- @return A + B
|
||||
--
|
||||
--- @param DP MtPoint P1 - P2.
|
||||
--- @param P1 MtPoint The first point.
|
||||
--- @param P2 MtPoint The second point.
|
||||
--- @return MtPoint P3 2A
|
||||
--- @return MtPoint P4 A + B
|
||||
local function step(DP, P1, P2)
|
||||
local dx, dz = DP[1], DP[2]
|
||||
local x1, z1 = P1[1], P1[2]
|
||||
|
@ -85,50 +85,46 @@ local function ladder(DP, bits)
|
|||
end
|
||||
|
||||
--- Performs a scalar multiplication operation with multiplication by 8.
|
||||
--
|
||||
-- @tparam point P The base point.
|
||||
-- @tparam {number...} bits The scalar multiplier, in little-endian bits.
|
||||
-- @treturn point The product, multiplied by 8.
|
||||
--
|
||||
--- @param P MtPoint The base point.
|
||||
--- @param bits number[] The scalar multiplier, in little-endian bits.
|
||||
--- @return MtPoint product The product, multiplied by 8.
|
||||
local function ladder8(P, bits)
|
||||
-- Randomize.
|
||||
local rf = fp.decode(random.random(32))
|
||||
local rf = fp.decode(random.random(32) --[[@as String32, length is given]])
|
||||
P = {fp.mul(P[1], rf), fp.mul(P[2], rf)}
|
||||
|
||||
-- Multiply.
|
||||
return double(double(double(ladder(P, bits))))
|
||||
end
|
||||
|
||||
--- Scales a point's coordinates.
|
||||
--- @param P MtPoint The input point.
|
||||
--- @return MtPoint Q The same point P, but with Z = 1.
|
||||
local function scale(P)
|
||||
return {fp.mul(P[1], fp.invert(P[2])), fp.num(1)}
|
||||
end
|
||||
|
||||
--- Encodes a point.
|
||||
--
|
||||
-- @tparam point P1 The scaled point to encode.
|
||||
-- @treturn string The 32-byte encoded point.
|
||||
--
|
||||
--- Encodes a scaled point.
|
||||
--- @param P MtPoint The scaled point to encode.
|
||||
--- @return string encoded P, encoded into a 32-byte string.
|
||||
local function encode(P)
|
||||
return fp.encode(P[1])
|
||||
end
|
||||
|
||||
--- Decodes a point.
|
||||
--
|
||||
-- @tparam string str A 32-byte encoded point.
|
||||
-- @treturn point The decoded point.
|
||||
--
|
||||
--- @param str String32 A 32-byte encoded point.
|
||||
--- @return MtPoint pt The decoded point.
|
||||
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.
|
||||
--
|
||||
---
|
||||
--- 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.
|
||||
---
|
||||
--- @param str String32 A 32-byte encoded Edwards25519 point.
|
||||
--- @return MtPoint pt 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))
|
||||
|
@ -141,10 +137,8 @@ local function decodeEd(str)
|
|||
end
|
||||
|
||||
--- Performs a scalar multiplication by the base point G.
|
||||
--
|
||||
-- @tparam {number...} bits The scalar multiplier, in little-endian bits.
|
||||
-- @return The product point.
|
||||
--
|
||||
--- @param bits number[] The scalar multiplier, in little-endian bits.
|
||||
--- @return MtPoint product The product point.
|
||||
local function mulG(bits)
|
||||
-- Multiply by G on Edwards25519.
|
||||
local P = ed.mulG(bits)
|
||||
|
@ -159,17 +153,17 @@ local function mulG(bits)
|
|||
end
|
||||
|
||||
--- Computes a twofold product from a ruleset.
|
||||
--
|
||||
-- @tparam point P The base point.
|
||||
-- @tparam {{number...}, {number...}} The ruleset generated by scalars m, n.
|
||||
-- @treturn[1] point [8m]P
|
||||
-- @treturn[1] point [8n]P
|
||||
-- @treturn[1] point [8m]P - [8n]P
|
||||
-- @treturn[2] nil If any of the three results is equal to O.
|
||||
--
|
||||
---
|
||||
--- Returns nil if any of the results would be equal to the identity.
|
||||
---
|
||||
--- @param P MtPoint The base point.
|
||||
--- @param ruleset __TYPE_TODO The ruleset generated by scalars m, n.
|
||||
--- @return MtPoint? A [8m]P.
|
||||
--- @return MtPoint? B [8n]P.
|
||||
--- @return MtPoint? C [8m]P - [8n]P.
|
||||
local function prac(P, ruleset)
|
||||
-- Randomize.
|
||||
local rf = fp.decode(random.random(32))
|
||||
local rf = fp.decode(random.random(32) --[[@as String32, length is given]])
|
||||
local A = {fp.mul(P[1], rf), fp.mul(P[2], rf)}
|
||||
|
||||
-- Start the base at [8]P.
|
||||
|
@ -184,7 +178,7 @@ local function prac(P, ruleset)
|
|||
|
||||
-- Reject rulesets where m = n.
|
||||
local rules = ruleset[2]
|
||||
if #rules == 0 then return nil end
|
||||
if #rules == 0 then return end
|
||||
|
||||
-- Evaluate the first rule.
|
||||
-- Since e = d, this means A - B = C = O. Differential addition fails when
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
--- Point arithmetic on the Edwards25519 Edwards curve.
|
||||
--
|
||||
-- :::note Internal Module
|
||||
-- This module is meant for internal use within the library. Its API is unstable
|
||||
-- and subject to change without major version bumps.
|
||||
-- :::
|
||||
--
|
||||
-- <br />
|
||||
--
|
||||
-- @module[kind=internal] internal.edwards25519
|
||||
--
|
||||
|
||||
local fp = require "ccryptolib.internal.fp"
|
||||
|
||||
local unpack = unpack or table.unpack
|
||||
|
||||
--- @class EdPoint A point on Edwards25519, in extended coordinates.
|
||||
--- @field [1] number[] The X coordinate.
|
||||
--- @field [2] number[] The Y coordinate.
|
||||
--- @field [3] number[] The Z coordinate.
|
||||
--- @field [4] number[] The T coordinate.
|
||||
|
||||
--- @class NsPoint A point on Edwards25519, in Niels' coordinates.
|
||||
--- @field [1] number[] Preprocessed Y + X.
|
||||
--- @field [2] number[] Preprocessed Y - X.
|
||||
--- @field [3] number[] Preprocessed 2Z.
|
||||
--- @field [4] number[] Preprocessed 2DT.
|
||||
|
||||
local D = fp.mul(fp.num(-121665), fp.invert(fp.num(121666)))
|
||||
local K = fp.kmul(D, 2)
|
||||
|
||||
--- @type EdPoint
|
||||
local O = {fp.num(0), fp.num(1), fp.num(1), fp.num(0)}
|
||||
local G = nil
|
||||
|
||||
--- Doubles a point.
|
||||
--
|
||||
-- @tparam point P1 The point to double.
|
||||
-- @treturn point Twice P1.
|
||||
--
|
||||
--- @param P1 EdPoint The point to double.
|
||||
--- @return EdPoint P2 P1 + P1.
|
||||
local function double(P1)
|
||||
-- Unsoundness: fp.sub(g, e), and fp.sub(d, i) break fp.sub's contract since
|
||||
-- it doesn't accept an fp2. Although not ideal, in practice this doesn't
|
||||
|
@ -48,14 +49,12 @@ local function double(P1)
|
|||
end
|
||||
|
||||
--- Adds two points.
|
||||
--
|
||||
-- @tparam point P1 The first summand point.
|
||||
-- @tparam niels N1 The second summand point, in Niels form. See @{niels}.
|
||||
-- @treturn point The sum.
|
||||
--
|
||||
local function add(P1, N1)
|
||||
--- @param P1 EdPoint The first summand point.
|
||||
--- @param N2 NsPoint The second summand point.
|
||||
--- @return EdPoint P3 P1 + P2, where N2 = niels(P2).
|
||||
local function add(P1, N2)
|
||||
local P1x, P1y, P1z, P1t = unpack(P1)
|
||||
local N1p, N1m, N1z, N1t = unpack(N1)
|
||||
local N1p, N1m, N1z, N1t = unpack(N2)
|
||||
local a = fp.sub(P1y, P1x)
|
||||
local b = fp.mul(a, N1m)
|
||||
local c = fp.add(P1y, P1x)
|
||||
|
@ -73,9 +72,13 @@ local function add(P1, N1)
|
|||
return {P3x, P3y, P3z, P3t}
|
||||
end
|
||||
|
||||
local function sub(P1, N1)
|
||||
--- Subtracts one point from another.
|
||||
--- @param P1 EdPoint The first summand point.
|
||||
--- @param N2 NsPoint The second summand point.
|
||||
--- @return EdPoint P3 P1 - P2, where N2 = niels(P2).
|
||||
local function sub(P1, N2)
|
||||
local P1x, P1y, P1z, P1t = unpack(P1)
|
||||
local N1p, N1m, N1z, N1t = unpack(N1)
|
||||
local N1p, N1m, N1z, N1t = unpack(N2)
|
||||
local a = fp.sub(P1y, P1x)
|
||||
local b = fp.mul(a, N1p)
|
||||
local c = fp.add(P1y, P1x)
|
||||
|
@ -94,10 +97,8 @@ local function sub(P1, N1)
|
|||
end
|
||||
|
||||
--- Computes the Niels representation of a point.
|
||||
--
|
||||
-- @tparam point P1
|
||||
-- @treturn niels P1's Niels representation.
|
||||
--
|
||||
--- @param P1 EdPoint The input point.
|
||||
--- @return NsPoint N1 Niels' precomputation applied to P1.
|
||||
local function niels(P1)
|
||||
local P1x, P1y, P1z, P1t = unpack(P1)
|
||||
local N3p = fp.add(P1y, P1x)
|
||||
|
@ -107,6 +108,9 @@ local function niels(P1)
|
|||
return {N3p, N3m, N3z, N3t}
|
||||
end
|
||||
|
||||
--- Scales a point.
|
||||
--- @param P1 EdPoint The input point.
|
||||
--- @return EdPoint P2 The same point as P1, but with Z = 1.
|
||||
local function scale(P1)
|
||||
local P1x, P1y, P1z = unpack(P1)
|
||||
local zInv = fp.invert(P1z)
|
||||
|
@ -117,11 +121,9 @@ local function scale(P1)
|
|||
return {P3x, P3y, P3z, P3t}
|
||||
end
|
||||
|
||||
--- Encodes a point.
|
||||
--
|
||||
-- @tparam point P1 The scaled point to encode.
|
||||
-- @treturn string The 32-byte encoded point.
|
||||
--
|
||||
--- Encodes a scaled point.
|
||||
--- @param P1 EdPoint The scaled point to encode.
|
||||
--- @return string out P1 encoded as a 32-byte string.
|
||||
local function encode(P1)
|
||||
P1 = scale(P1)
|
||||
local P1x, P1y = unpack(P1)
|
||||
|
@ -131,11 +133,8 @@ local function encode(P1)
|
|||
end
|
||||
|
||||
--- Decodes a point.
|
||||
--
|
||||
-- @tparam string str A 32-byte encoded point.
|
||||
-- @treturn[1] point The decoded point.
|
||||
-- @treturn[2] nil If the string did not represent a valid encoded point.
|
||||
--
|
||||
--- @param str String32 A 32-byte encoded point.
|
||||
--- @return EdPoint? P1 The decoded point, or nil if it isn't on the curve.
|
||||
local function decode(str)
|
||||
local P3y = fp.decode(str)
|
||||
local a = fp.square(P3y)
|
||||
|
@ -153,8 +152,12 @@ local function decode(str)
|
|||
return {P3x, P3y, P3z, P3t}
|
||||
end
|
||||
|
||||
G = decode("Xfffffffffffffffffffffffffffffff")
|
||||
G = decode("Xfffffffffffffffffffffffffffffff") --[[@as EdPoint, G is valid]]
|
||||
|
||||
--- Transforms little-endian bits into a signed radix-2^w form.
|
||||
--- @param bits number[]
|
||||
--- @param w number Log2 of the radix, must be at least 1.
|
||||
--- @return number[]
|
||||
local function signedRadixW(bits, w)
|
||||
-- TODO Find a more elegant way of doing this.
|
||||
local wPow = 2 ^ w
|
||||
|
@ -176,6 +179,10 @@ local function signedRadixW(bits, w)
|
|||
return out
|
||||
end
|
||||
|
||||
--- Computes a multiplication table for radix-2^w form multiplication.
|
||||
--- @param P EdPoint The base point.
|
||||
--- @param w number Log2 of the radix, must be at least 1.
|
||||
--- @return NsPoint[][]
|
||||
local function radixWTable(P, w)
|
||||
local out = {}
|
||||
for i = 1, math.ceil(256 / w) do
|
||||
|
@ -190,10 +197,21 @@ local function radixWTable(P, w)
|
|||
return out
|
||||
end
|
||||
|
||||
--- The radix logarithm of the precomputed table for G.
|
||||
local G_W = 5
|
||||
|
||||
--- The precomputed multiplication table for G.
|
||||
local G_TABLE = radixWTable(G, G_W)
|
||||
|
||||
local function WNAF(bits, w)
|
||||
--- Transforms little-endian bits into a signed radix-2^w non-adjacent form.
|
||||
---
|
||||
--- The returned array contains a 0 whenever a single doubling is needed, or an
|
||||
--- odd integer when an addition with a multiple of the base is needed.
|
||||
---
|
||||
--- @param bits number[]
|
||||
--- @param w number Log2 of the radix, must be at least 1.
|
||||
--- @return number[]
|
||||
local function wNaf(bits, w)
|
||||
-- TODO Find a more elegant way of doing this.
|
||||
local wPow = 2 ^ w
|
||||
local wPowh = wPow / 2
|
||||
|
@ -220,6 +238,10 @@ local function WNAF(bits, w)
|
|||
return out
|
||||
end
|
||||
|
||||
--- Computes a multiplication table for wNAF form multiplication.
|
||||
--- @param P EdPoint The base point.
|
||||
--- @param w number Log2 of the radix, must be at least 1.
|
||||
--- @return NsPoint[]
|
||||
local function WNAFTable(P, w)
|
||||
local dP = double(P)
|
||||
local out = {niels(P)}
|
||||
|
@ -230,10 +252,8 @@ local function WNAFTable(P, w)
|
|||
end
|
||||
|
||||
--- Performs a scalar multiplication by the base point G.
|
||||
--
|
||||
-- @tparam {number...} bits The scalar multiplier, in little-endian bits.
|
||||
-- @treturn point The product.
|
||||
--
|
||||
--- @param bits number[] The scalar multiplicand little-endian bits.
|
||||
--- @return EdPoint
|
||||
local function mulG(bits)
|
||||
local sw = signedRadixW(bits, G_W)
|
||||
local R = O
|
||||
|
@ -249,13 +269,11 @@ local function mulG(bits)
|
|||
end
|
||||
|
||||
--- Performs a scalar multiplication operation.
|
||||
--
|
||||
-- @tparam point P The base point.
|
||||
-- @tparam {number...} bits The scalar multiplier, in little-endian bits.
|
||||
-- @treturn point The product.
|
||||
--
|
||||
--- @param P EdPoint The base point.
|
||||
--- @param bits number[] The scalar multiplicand little-endian bits.
|
||||
--- @return EdPoint
|
||||
local function mul(P, bits)
|
||||
local naf = WNAF(bits, 5)
|
||||
local naf = wNaf(bits, 5)
|
||||
local tbl = WNAFTable(P, 5)
|
||||
local R = O
|
||||
for i = #naf, 1, -1 do
|
||||
|
|
|
@ -1,21 +1,19 @@
|
|||
--- Arithmetic on Curve25519's base field.
|
||||
--
|
||||
-- :::note Internal Module
|
||||
-- This module is meant for internal use within the library. Its API is unstable
|
||||
-- and subject to change without major version bumps.
|
||||
-- :::
|
||||
--
|
||||
-- <br />
|
||||
--
|
||||
-- @module[kind=internal] internal.fp
|
||||
--
|
||||
|
||||
local packing = require "ccryptolib.internal.packing"
|
||||
|
||||
local unpack = unpack or table.unpack
|
||||
local ufp, fmtfp = packing.compileUnpack("<I3I3I2I3I3I2I3I3I2I3I3I2")
|
||||
|
||||
--- @class Fq An element of the field of integers modulo 2²⁵⁵ - 19.
|
||||
|
||||
--- @class FpR2: Fq An Fp element with limbs inside twice the standard range.
|
||||
|
||||
--- @class FpR1: FpR2 An Fp element with limbs inside the standard range. See
|
||||
--- the Curve25519 polynomial representation for more info around this.
|
||||
|
||||
--- The modular square root of -1.
|
||||
--- @type FpR1
|
||||
local I = {
|
||||
0958640 * 2 ^ 0,
|
||||
0826664 * 2 ^ 22,
|
||||
|
@ -32,19 +30,15 @@ local I = {
|
|||
}
|
||||
|
||||
--- Converts a Lua number to an element.
|
||||
--
|
||||
-- @tparam number n A number n in [0..2²²).
|
||||
-- @treturn fp1
|
||||
--
|
||||
--- @param n number A number n in [0..2²²).
|
||||
--- @return FpR1 out The number as an element.
|
||||
local function num(n)
|
||||
return {n, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
end
|
||||
|
||||
--- Negates an element.
|
||||
--
|
||||
-- @tparam fp1 a
|
||||
-- @treturn fp1 -a.
|
||||
--
|
||||
--- @param a FpR1
|
||||
--- @return FpR1 out -a.
|
||||
local function neg(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
return {
|
||||
|
@ -64,11 +58,9 @@ local function neg(a)
|
|||
end
|
||||
|
||||
--- Adds two elements.
|
||||
--
|
||||
-- @tparam fp1 a
|
||||
-- @tparam fp1 b
|
||||
-- @treturn fp2 a + b.
|
||||
--
|
||||
--- @param a FpR1
|
||||
--- @param b FpR1
|
||||
--- @return FpR2 out a + b.
|
||||
local function add(a, b)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11 = unpack(b)
|
||||
|
@ -89,11 +81,9 @@ local function add(a, b)
|
|||
end
|
||||
|
||||
--- Subtracts an element from another.
|
||||
--
|
||||
-- @tparam fp1 a
|
||||
-- @tparam fp1 b
|
||||
-- @treturn fp2 a - b.
|
||||
--
|
||||
--- @param a FpR1
|
||||
--- @param b FpR1
|
||||
--- @return FpR2 out a - b.
|
||||
local function sub(a, b)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11 = unpack(b)
|
||||
|
@ -113,13 +103,9 @@ local function sub(a, b)
|
|||
}
|
||||
end
|
||||
|
||||
--- Carries an element.
|
||||
--
|
||||
-- Also performs a small reduction modulo p.
|
||||
--
|
||||
-- @tparam fp2 a
|
||||
-- @treturn fp1 a' ≡ a (mod p).
|
||||
--
|
||||
--- Carries an element. Also performs a small reduction modulo p.
|
||||
--- @param a FpR2 The element to carry.
|
||||
--- @return FpR1 out The same element as a but in a tighter range.
|
||||
local function carry(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11
|
||||
|
@ -157,14 +143,14 @@ local function carry(a)
|
|||
end
|
||||
|
||||
--- Returns the canoncal representative of a modp number.
|
||||
--
|
||||
-- Some elements can be represented by two different arrays of floats. This
|
||||
-- returns the canonical element of the represented equivalence class. We define
|
||||
-- an element as canonical if it's the smallest nonnegative number in its class.
|
||||
--
|
||||
-- @tparam fp2 a
|
||||
-- @treturn fp1 A canonical element a' ≡ a (mod p).
|
||||
--
|
||||
---
|
||||
--- Some elements can be represented by two different arrays of floats. This
|
||||
--- returns the canonical element of the represented equivalence class. We
|
||||
--- define an element as canonical if it's the smallest nonnegative number in
|
||||
--- its class.
|
||||
---
|
||||
--- @param a FpR2
|
||||
--- @return FpR1 out A canonical element a' ≡ a (mod p).
|
||||
local function canonicalize(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11
|
||||
|
@ -205,11 +191,9 @@ local function canonicalize(a)
|
|||
end
|
||||
|
||||
--- Returns whether two elements are the same.
|
||||
--
|
||||
-- @tparam fp1 a
|
||||
-- @tparam fp1 b
|
||||
-- @treturn boolean Whether the two elements are the same mod p.
|
||||
--
|
||||
--- @param a FpR1
|
||||
--- @param b FpR1
|
||||
--- @return boolean eq Whether a ≡ b (mod p).
|
||||
local function eq(a, b)
|
||||
local c = canonicalize(sub(a, b))
|
||||
for i = 1, 12 do if c[i] ~= 0 then return false end end
|
||||
|
@ -217,11 +201,9 @@ local function eq(a, b)
|
|||
end
|
||||
|
||||
--- Multiplies two elements.
|
||||
--
|
||||
-- @tparam fp2 a
|
||||
-- @tparam fp2 b
|
||||
-- @treturn fp1 c ≡ a × b (mod p).
|
||||
--
|
||||
--- @param a FpR2
|
||||
--- @param b FpR2
|
||||
--- @return FpR1 c An element such that c ≡ a × b (mod p).
|
||||
local function mul(a, b)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11 = unpack(b)
|
||||
|
@ -421,10 +403,8 @@ local function mul(a, b)
|
|||
end
|
||||
|
||||
--- Squares an element.
|
||||
--
|
||||
-- @tparam fp2 a
|
||||
-- @treturn fp1 c ≡ a² (mod p).
|
||||
--
|
||||
--- @param a FpR2
|
||||
--- @return FpR1 b An element such that b ≡ a² (mod p).
|
||||
local function square(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local d00, d01, d02, d03, d04, d05, d06, d07, d08, d09, d10
|
||||
|
@ -571,11 +551,9 @@ local function square(a)
|
|||
end
|
||||
|
||||
--- Multiplies an element by a number.
|
||||
--
|
||||
-- @tparam fp2 a
|
||||
-- @tparam number k A number k in [0..2²²).
|
||||
-- @treturn fp1 c ≡ a × k (mod p).
|
||||
--
|
||||
--- @param a FpR2
|
||||
--- @param k number A number in [0..2²²).
|
||||
--- @return FpR1 c An element such that c ≡ a × k (mod p).
|
||||
local function kmul(a, k)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11
|
||||
|
@ -627,24 +605,20 @@ local function kmul(a, k)
|
|||
end
|
||||
|
||||
--- Squares an element n times.
|
||||
--
|
||||
-- @tparam fp2 a
|
||||
-- @tparam number n A positive integer.
|
||||
-- @treturn fp1 c ≡ a ^ 2 ^ n (mod p).
|
||||
--
|
||||
--- @param a FpR2
|
||||
--- @param n number The number of times to square a.
|
||||
--- @return FpR1 c A number c such that c ≡ a ^ 2 ^ n (mod p).
|
||||
local function nsquare(a, n)
|
||||
for _ = 1, n do a = square(a) end
|
||||
return a
|
||||
end
|
||||
|
||||
--- Computes the inverse of an element.
|
||||
--
|
||||
-- Computation of the inverse requires 11 multiplications and 252 squarings.
|
||||
--
|
||||
-- @tparam fp2 a
|
||||
-- @treturn[1] fp1 c ≡ a⁻¹ (mod p), if a ≠ 0.
|
||||
-- @treturn[2] fp1 c ≡ 0 (mod p), if a = 0.
|
||||
--
|
||||
---
|
||||
--- Performance: 11 multiplications and 252 squarings.
|
||||
---
|
||||
--- @param a FpR2
|
||||
--- @return FpR1 c An element such that c ≡ a⁻¹ (mod p), or 0 if c doesn't exist.
|
||||
local function invert(a)
|
||||
local a2 = square(a)
|
||||
local a9 = mul(a, nsquare(a2, 2))
|
||||
|
@ -662,15 +636,13 @@ local function invert(a)
|
|||
return mul(nsquare(x250, 5), a11)
|
||||
end
|
||||
|
||||
--- Returns an element x that satisfies v * x² = u.
|
||||
--
|
||||
-- Note that when v = 0, the returned element can take any value.
|
||||
--
|
||||
-- @tparam fp2 u
|
||||
-- @tparam fp2 v
|
||||
-- @treturn[1] fp1 x.
|
||||
-- @treturn[2] nil if there is no solution.
|
||||
--
|
||||
--- Returns an element x that satisfies vx² = u.
|
||||
---
|
||||
--- Note that when v = 0, the returned element can take any value.
|
||||
---
|
||||
--- @param u FpR2
|
||||
--- @param v FpR2
|
||||
--- @return FpR1? x An element such that vx² ≡ u (mod p), if it exists.
|
||||
local function sqrtDiv(u, v)
|
||||
u = carry(u)
|
||||
|
||||
|
@ -711,11 +683,11 @@ local function sqrtDiv(u, v)
|
|||
end
|
||||
end
|
||||
|
||||
--- @class String32: string A string with length equal to 32 bytes.
|
||||
|
||||
--- Encodes an element in little-endian.
|
||||
--
|
||||
-- @tparam fp2 a
|
||||
-- @treturn string A 32-byte string. Always represents the canonical element.
|
||||
--
|
||||
--- @param a FpR1
|
||||
--- @return String32 out The 32-byte canonical encoding of a.
|
||||
local function encode(a)
|
||||
a = canonicalize(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
|
@ -744,14 +716,12 @@ local function encode(a)
|
|||
putBytes(3) acc = acc + a11 / 2 ^ 232
|
||||
putBytes(3)
|
||||
|
||||
return string.char(unpack(bytes))
|
||||
return string.char(unpack(bytes)) --[[@as String32, putBytes sums to 32]]
|
||||
end
|
||||
|
||||
--- Decodes an element in little-endian.
|
||||
--
|
||||
-- @tparam string b A 32-byte string. The most-significant bit is discarded.
|
||||
-- @treturn fp1 The decoded element. May not be canonical.
|
||||
--
|
||||
--- @param b String32 A 32-byte string, the most-significant bit is discarded.
|
||||
--- @return FpR1 out The decoded element. It may not be canonical.
|
||||
local function decode(b)
|
||||
local w00, w01, w02, w03, w04, w05, w06, w07, w08, w09, w10, w11 =
|
||||
ufp(fmtfp, b, 1)
|
||||
|
@ -774,11 +744,9 @@ local function decode(b)
|
|||
}
|
||||
end
|
||||
|
||||
--- Checks if two elements are equal.
|
||||
--
|
||||
-- @tparam fp2 a
|
||||
-- @treturn boolean Whether a ≡ 0 (mod p).
|
||||
--
|
||||
--- Checks if the given element is equal to 0.
|
||||
--- @param a FpR2
|
||||
--- @return boolean eqz Whether a ≡ 0 (mod p).
|
||||
local function eqz(a)
|
||||
local c = canonicalize(a)
|
||||
local c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11 = unpack(c)
|
||||
|
|
|
@ -90,14 +90,12 @@ local function reduce(a)
|
|||
local c = mp.sub(a, Q)
|
||||
|
||||
-- Return carry(a) if a < q.
|
||||
if mp.approx(c) < 0 then return mp.carry(a) end
|
||||
if mp.approx(c) < 0 then return (mp.carry(a)) end
|
||||
|
||||
-- c >= q means c - q >= 0.
|
||||
-- Since q < 2²⁸⁸, c < 2q means c - q < q < 2²⁸⁸.
|
||||
-- c's limbs fit in (-2²⁶..2²⁶), since subtraction adds at most one bit.
|
||||
local cc = mp.carry(c)
|
||||
cc[12] = nil -- cc < q implies that cc[12] = 0.
|
||||
return cc
|
||||
return (mp.carry(c)) -- cc < q implies that the carry number is 0.
|
||||
end
|
||||
|
||||
--- Adds two scalars mod q.
|
||||
|
@ -170,15 +168,6 @@ local function demontgomery(a)
|
|||
return reduce(s1)
|
||||
end
|
||||
|
||||
--- Converts a Lua number to a scalar.
|
||||
--
|
||||
-- @tparam number n A number n in [0..2²⁴).
|
||||
-- @treturn {number...} 2²⁶⁴ × n mod q as 11 limbs in [0..2²⁴).
|
||||
--
|
||||
local function num(n)
|
||||
return montgomery({n, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
end
|
||||
|
||||
--- Encodes a scalar.
|
||||
--
|
||||
-- @tparam {number...} a A number 2²⁶⁴ × a mod q as 11 limbs in [0..2²⁴).
|
||||
|
@ -378,12 +367,8 @@ local function makeRuleset(a, b)
|
|||
end
|
||||
|
||||
return {
|
||||
num = num,
|
||||
add = add,
|
||||
neg = neg,
|
||||
sub = sub,
|
||||
montgomery = montgomery,
|
||||
demontgomery = demontgomery,
|
||||
mul = mul,
|
||||
encode = encode,
|
||||
decode = decode,
|
||||
|
|
|
@ -12,12 +12,19 @@
|
|||
|
||||
local unpack = unpack or table.unpack
|
||||
|
||||
--- A little-endian big integer of width 11 in (-2⁵²..2⁵²).
|
||||
--- @class MpSW11L52
|
||||
|
||||
--- A little-endian big integer of width 11 in (-2²⁴, 2²⁴).
|
||||
--- @class MpSW11L24: MpSW11L52
|
||||
|
||||
--- A little-endian big integer of width 11 in [0..2²⁴).
|
||||
--- @class MpUW11L24: MpSW11L24
|
||||
|
||||
--- Carries a number in base 2²⁴ into a signed limb form.
|
||||
--
|
||||
-- @tparam {number...} a A number a in (-2²⁸⁸..2²⁸⁸) as 11 limbs in
|
||||
-- [-2⁵²..2⁵²].
|
||||
-- @treturn {number...} a as 12 limbs in (-2²⁴..2²⁴).
|
||||
--
|
||||
--- @param a MpSW11L52
|
||||
--- @return MpSW11L24 low The carried low limbs.
|
||||
--- @return number carry The overflowed carry.
|
||||
local function carryWeak(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10 = unpack(a)
|
||||
|
||||
|
@ -45,16 +52,13 @@ local function carryWeak(a)
|
|||
a08 - h08,
|
||||
a09 - h09,
|
||||
a10 - h10,
|
||||
h10 * 2 ^ -24,
|
||||
}
|
||||
}, h10 * 2 ^ -24
|
||||
end
|
||||
|
||||
--- Carries a number in base 2²⁴.
|
||||
--
|
||||
-- @tparam {number...} a A number a in [0..2²⁸⁸) as 11 limbs in
|
||||
-- [-2⁵²..2⁵²].
|
||||
-- @treturn {number...} a as 12 limbs in [0..2²⁴).
|
||||
--
|
||||
--- @param a MpSW11L52
|
||||
--- @return MpUW11L24 low The low 11 limbs of the output.
|
||||
--- @return number carry The overflow carry.
|
||||
local function carry(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10 = unpack(a)
|
||||
|
||||
|
@ -71,15 +75,13 @@ local function carry(a)
|
|||
local l10 = a10 % 2 ^ 24
|
||||
local h10 = (a10 - l10) * 2 ^ -24
|
||||
|
||||
return {l00, l01, l02, l03, l04, l05, l06, l07, l08, l09, l10, h10}
|
||||
return {l00, l01, l02, l03, l04, l05, l06, l07, l08, l09, l10}, h10
|
||||
end
|
||||
|
||||
--- Adds two numbers.
|
||||
--
|
||||
-- @tparam {number...} a An array of 11 limbs in (k..l).
|
||||
-- @tparam {number...} b An array of 11 limbs in (m..n).
|
||||
-- @treturn {number...} a + b as 11 limbs in ((k + m)..(l + n)).
|
||||
--
|
||||
--- @param a MpSW11L24
|
||||
--- @param b MpSW11L24
|
||||
--- @return MpSW11L52 c a + b
|
||||
local function add(a, b)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10 = unpack(a)
|
||||
local b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10 = unpack(b)
|
||||
|
@ -100,11 +102,9 @@ local function add(a, b)
|
|||
end
|
||||
|
||||
--- Subtracts a number from another.
|
||||
--
|
||||
-- @tparam {number...} a An array of 11 limbs in (k..l).
|
||||
-- @tparam {number...} b An array of 11 limbs in (m..n).
|
||||
-- @treturn {number...} a + b as 11 limbs in ((k - m)..(l - n)).
|
||||
--
|
||||
--- @param a MpSW11L24
|
||||
--- @param b MpSW11L24
|
||||
--- @return MpSW11L52 c a - b
|
||||
local function sub(a, b)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10 = unpack(a)
|
||||
local b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10 = unpack(b)
|
||||
|
@ -125,17 +125,15 @@ local function sub(a, b)
|
|||
end
|
||||
|
||||
--- Computes the lower half of a product between two numbers.
|
||||
--
|
||||
-- @tparam {number...} a A nonnegative integer as 11 limbs in [0..2²⁴).
|
||||
-- @tparam {number...} b A nonnegative integer as 11 limbs in [0..2²⁴).
|
||||
-- @treturn {number...} c ≡ a × b (mod 2²⁶⁴) as 11 limbs in [0..2²⁴).
|
||||
-- @treturn number ⌊a × b ÷ 2²⁶⁴⌋.
|
||||
--
|
||||
--- @param a MpUW11L24
|
||||
--- @param b MpUW11L24
|
||||
--- @return MpUW11L24 c a × b (mod 2²⁶⁴)
|
||||
--- @return number carry ⌊a × b ÷ 2²⁶⁴⌋
|
||||
local function lmul(a, b)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10 = unpack(a)
|
||||
local b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10 = unpack(b)
|
||||
|
||||
local out = carry {
|
||||
return carry {
|
||||
a00 * b00,
|
||||
a01 * b00 + a00 * b01,
|
||||
a02 * b00 + a01 * b01 + a00 * b02,
|
||||
|
@ -148,28 +146,21 @@ local function lmul(a, b)
|
|||
a09 * b00 + a08 * b01 + a07 * b02 + a06 * b03 + a05 * b04 + a04 * b05 + a03 * b06 + a02 * b07 + a01 * b08 + a00 * b09,
|
||||
a10 * b00 + a09 * b01 + a08 * b02 + a07 * b03 + a06 * b04 + a05 * b05 + a04 * b06 + a03 * b07 + a02 * b08 + a01 * b09 + a00 * b10,
|
||||
}
|
||||
|
||||
-- Strip overflow.
|
||||
local of = out[12]
|
||||
out[12] = nil
|
||||
|
||||
return out, of
|
||||
end
|
||||
|
||||
--- Computes the a product between two numbers.
|
||||
--
|
||||
-- @tparam {number...} a An array of 11 limbs in [0..2²⁴).
|
||||
-- @tparam {number...} b An array of 11 limbs in [0..2²⁴).
|
||||
-- @treturn {number...} The first 11 limbs of a × b in [0..2²⁴).
|
||||
-- @treturn {number...} The last 11 limbs of a × b in [0..2²⁴).
|
||||
--
|
||||
--- @param a MpUW11L24
|
||||
--- @param b MpUW11L24
|
||||
--- @return MpUW11L24 low The low 11 limbs of a × b.
|
||||
--- @return MpUW11L24 high The high 11 limbs of a × b.
|
||||
local function mul(a, b)
|
||||
local low, of = lmul(a, b)
|
||||
|
||||
local _, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10 = unpack(a)
|
||||
local _, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10 = unpack(b)
|
||||
|
||||
local high = carry {
|
||||
-- The carry is always 0.
|
||||
return low, (carry {
|
||||
of + a10 * b01 + a09 * b02 + a08 * b03 + a07 * b04 + a06 * b05 + a05 * b06 + a04 * b07 + a03 * b08 + a02 * b09 + a01 * b10,
|
||||
a10 * b02 + a09 * b03 + a08 * b04 + a07 * b05 + a06 * b06 + a05 * b07 + a04 * b08 + a03 * b09 + a02 * b10,
|
||||
a10 * b03 + a09 * b04 + a08 * b05 + a07 * b06 + a06 * b07 + a05 * b08 + a04 * b09 + a03 * b10,
|
||||
|
@ -181,40 +172,31 @@ local function mul(a, b)
|
|||
a10 * b09 + a09 * b10,
|
||||
a10 * b10,
|
||||
0
|
||||
}
|
||||
|
||||
-- Strip overflow (it's always 0).
|
||||
high[12] = nil
|
||||
|
||||
return low, high
|
||||
})
|
||||
end
|
||||
|
||||
--- Computes a double-width sum of two numbers.
|
||||
--
|
||||
-- @tparam {number...} a0 The low part of a as 11 limbs in [0..2²⁴).
|
||||
-- @tparam {number...} a1 The high part of a as 11 limbs in [0..2²⁴).
|
||||
-- @tparam {number...} b0 The low part of b as 11 limbs in [0..2²⁴).
|
||||
-- @tparam {number...} b1 The high part of b as 11 limbs in [0..2²⁴).
|
||||
-- @treturn {number...} The low part of a + b as 11 limbs in [0..2²⁴).
|
||||
-- @treturn {number...} The high part of a + b as 12 limbs in [0..2²⁴).
|
||||
--
|
||||
--- @param a0 MpUW11L24 The low 11 limbs of a.
|
||||
--- @param a1 MpUW11L24 The high 11 limbs of a.
|
||||
--- @param b0 MpUW11L24 The low 11 limbs of b.
|
||||
--- @param b1 MpUW11L24 The high 11 limbs of b.
|
||||
--- @return MpUW11L24 c0 The low 11 limbs of a + b.
|
||||
--- @return MpUW11L24 c1 The high 11 limbs of a + b.
|
||||
--- @return number The carry.
|
||||
local function dwadd(a0, a1, b0, b1)
|
||||
local low = carry(add(a0, b0))
|
||||
local low, c = carry(add(a0, b0))
|
||||
local high = add(a1, b1)
|
||||
high[1] = high[1] + low[12]
|
||||
low[12] = nil
|
||||
high[1] = high[1] + c
|
||||
return low, carry(high)
|
||||
end
|
||||
|
||||
--- Computes half of a number.
|
||||
--
|
||||
-- @tparam {number...} a An even positive integer as 11 limbs in (-2²⁴..2²⁴).
|
||||
-- @treturn {number...} a ÷ 2 as 11 limbs in (-2²⁴..2²⁴).
|
||||
--
|
||||
--- @param a MpSW11L24 The number to halve, must be even.
|
||||
--- @return MpSW11L24 c a ÷ 2
|
||||
local function half(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10 = unpack(a)
|
||||
|
||||
local out = carryWeak {
|
||||
return (carryWeak {
|
||||
a00 * 0.5 + a01 * 2 ^ 23,
|
||||
a02 * 2 ^ 23,
|
||||
a03 * 2 ^ 23,
|
||||
|
@ -226,18 +208,12 @@ local function half(a)
|
|||
a09 * 2 ^ 23,
|
||||
a10 * 2 ^ 23,
|
||||
0,
|
||||
}
|
||||
|
||||
out[12] = nil
|
||||
|
||||
return out
|
||||
})
|
||||
end
|
||||
|
||||
--- Computes a third of a number.
|
||||
--
|
||||
-- @tparam {number...} a A positive multiple of 3 as 11 limbs in (-2²⁶..2²⁶).
|
||||
-- @treturn {number...} a ÷ 3 as 11 limbs in (-2²⁴..2²⁴).
|
||||
--
|
||||
--- @param a MpSW11L24 The number to divide, must be a multiple of 3.
|
||||
--- @return MpSW11L24 c a ÷ 3
|
||||
local function third(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10 = unpack(a)
|
||||
|
||||
|
@ -253,7 +229,9 @@ local function third(a)
|
|||
local d09 = a09 * 0xaaaaaa + d08
|
||||
local d10 = a10 * 0xaaaaaa + d09
|
||||
|
||||
local out = carryWeak {
|
||||
-- We compute the modular division mod 2²⁶⁴. The carry isn't 0 but it isn't
|
||||
-- part of a ÷ 3 either.
|
||||
return (carryWeak {
|
||||
a00 + d00,
|
||||
a01 + d01,
|
||||
a02 + d02,
|
||||
|
@ -265,39 +243,27 @@ local function third(a)
|
|||
a08 + d08,
|
||||
a09 + d09,
|
||||
a10 + d10,
|
||||
}
|
||||
|
||||
-- We compute the modular division mod 2²⁶⁴. out[12] isn't 0 but it's not
|
||||
-- part of a ÷ 3 either.
|
||||
out[12] = nil
|
||||
|
||||
return out
|
||||
})
|
||||
end
|
||||
|
||||
--- Computes a number modulo 2.
|
||||
--
|
||||
-- @tparam {number...} a A number as 11 limbs in (-2²⁶, 2²⁶).
|
||||
-- @treturn number a mod 2.
|
||||
--
|
||||
--- @param a MpSW11L24
|
||||
--- @return number c a mod 2.
|
||||
local function mod2(a)
|
||||
return a[1] % 2
|
||||
end
|
||||
|
||||
--- Computes a number modulo 3.
|
||||
--
|
||||
-- @tparam {number...} a A number as 11 limbs in (-2²⁶, 2²⁶).
|
||||
-- @treturn number a mod 3.
|
||||
--
|
||||
--- @param a MpSW11L24
|
||||
--- @return number c a mod 3.
|
||||
local function mod3(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10 = unpack(a)
|
||||
return (a00 + a01 + a02 + a03 + a04 + a05 + a06 + a07 + a08 + a09 + a10) % 3
|
||||
end
|
||||
|
||||
--- Computes a double representing the most-significant bits of a number.
|
||||
--
|
||||
-- @tparam {number...} a A number as 11 limbs in (-2⁴⁸..2⁴⁸).
|
||||
-- @treturn number A floating-point approximation for the value of a.
|
||||
--
|
||||
--- @param a MpSW11L52
|
||||
--- @return number c A floating-point approximation for the value of a.
|
||||
local function approx(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10 = unpack(a)
|
||||
return a00
|
||||
|
@ -314,11 +280,9 @@ local function approx(a)
|
|||
end
|
||||
|
||||
--- Compares two numbers for ordering.
|
||||
--
|
||||
-- @tparam {number...} a A number as 11 limbs in (-2²⁵..2²⁵).
|
||||
-- @tparam {number...} b A number as 11 limbs in (-2²⁵..2²⁵).
|
||||
-- @treturn number Some number x with x < 0 iff a < b and x = 0 iff a = b.
|
||||
--
|
||||
--- @param a MpSW11L24
|
||||
--- @param b MpSW11L24
|
||||
--- @return number ord Some number with ord < 0 iff a < b and ord = 0 iff a = b.
|
||||
local function cmp(a, b)
|
||||
return approx(sub(a, b))
|
||||
end
|
||||
|
|
|
@ -1,22 +1,11 @@
|
|||
--- High-performance binary packing of integers.
|
||||
--
|
||||
-- :::note Internal Module
|
||||
-- This module is meant for internal use within the library. Its API is unstable
|
||||
-- and subject to change without major version bumps.
|
||||
-- :::
|
||||
--
|
||||
-- <br />
|
||||
--
|
||||
-- :::warning
|
||||
-- For performance reasons, **the generated functions do not check types,
|
||||
-- lengths, nor ranges**. You must ensure that the passed arguments are
|
||||
-- well-formed and respect the format string yourself.
|
||||
-- :::
|
||||
--
|
||||
-- <br />
|
||||
--
|
||||
-- @module[kind=internal] internal.packing
|
||||
--
|
||||
---
|
||||
--- Remark (and warning):
|
||||
--- For performance reasons, **the generated functions do not check types,
|
||||
--- lengths, nor ranges**. You must ensure that the passed arguments are
|
||||
--- well-formed and respect the format string yourself.
|
||||
---
|
||||
--- <br />
|
||||
|
||||
local fmt = string.format
|
||||
|
||||
|
@ -119,14 +108,17 @@ if not string.pack or pcall(string.dump, string.pack) then
|
|||
local packCache = {}
|
||||
local unpackCache = {}
|
||||
|
||||
--- (`string.pack == nil`) Compiles a binary packing function.
|
||||
-- @tparam string fmt A string matched by `^([><])I[I%d]+$`.
|
||||
-- @treturn function A high-performance function that behaves like an unsafe
|
||||
-- version of `string.pack` for the given format string. Note that the third
|
||||
-- argument isn't optional.
|
||||
-- @treturn string fmt
|
||||
-- @throws If the string is invalid or has an invalid integral size.
|
||||
-- @throws If the compiled function is too large.
|
||||
-- I CAN'T EVEN WITH THIS EXTENSION, WHY CAN'T IT HANDLE MORE THAN A SINGLE
|
||||
-- LINE OF RETURN DESCRIPTION? LOOK AT IT!!! THE COMMENT GOES OVER THERE ------------------------------------------------------------------> look! ↓ ↓ ↓
|
||||
|
||||
--- (string.pack is nil) Compiles a binary packing function.
|
||||
---
|
||||
--- Errors if the format string is invalid or has an invalid integral size,
|
||||
--- or if the compiled function turns out too large.
|
||||
---
|
||||
--- @param fmt string A string matched by `^([><])I[I%d]+$`.
|
||||
--- @return fun(_ignored: any, ...: any): string pack A function that behaves like an unsafe version of `string.pack` for the given format string.
|
||||
--- @return string fmt
|
||||
function mod.compilePack(fmt)
|
||||
if not packCache[fmt] then
|
||||
packCache[fmt] = compile(fmt, mkPack)
|
||||
|
@ -134,13 +126,14 @@ if not string.pack or pcall(string.dump, string.pack) then
|
|||
return packCache[fmt], fmt
|
||||
end
|
||||
|
||||
--- (`string.pack == nil`) Compiles a binary unpacking function.
|
||||
-- @tparam string fmt A string matched by `^([><])I[I%d]+$`.
|
||||
-- @treturn function A high-performance function that behaves like an unsafe
|
||||
-- version of `string.unpack` for the given format string.
|
||||
-- @treturn string fmt
|
||||
-- @throws If the string is invalid or has an invalid integral size.
|
||||
-- @throws If the compiled function is too large.
|
||||
--- (string.pack is nil) Compiles a binary unpacking function.
|
||||
---
|
||||
--- Errors if the format string is invalid or has an invalid integral size,
|
||||
--- or if the compiled function turns out too large.
|
||||
---
|
||||
--- @param fmt string A string matched by `^([><])I[I%d]+$`.
|
||||
--- @return fun(_ignored: any, str: string, pos: number) unpack A function that behaves like an unsafe version of `string.unpack` for the given format string. Note that the third argument isn't optional.
|
||||
--- @return string fmt
|
||||
function mod.compileUnpack(fmt)
|
||||
if not unpackCache[fmt] then
|
||||
unpackCache[fmt] = compile(fmt, mkUnpack)
|
||||
|
@ -150,16 +143,16 @@ if not string.pack or pcall(string.dump, string.pack) then
|
|||
|
||||
return mod
|
||||
else
|
||||
--- (`string.pack ~= nil`) Compiles a binary packing function.
|
||||
-- @tparam string fmt
|
||||
-- @treturn function `string.pack`
|
||||
-- @treturn string fmt
|
||||
--- (string.pack isn't nil) It's string.pack! It returns string.pack!
|
||||
--- @param fmt string
|
||||
--- @return fun(fmt: string, ...: any): string pack string.pack!
|
||||
--- @return string fmt
|
||||
mod.compilePack = function(fmt) return string.pack, fmt end
|
||||
|
||||
--- (`string.pack ~= nil`) Compiles a binary unpacking function.
|
||||
-- @tparam string fmt
|
||||
-- @treturn function `string.unpack`
|
||||
-- @treturn string fmt
|
||||
--- (string.pack isn't nil) It's string.unpack! It returns string.unpack!
|
||||
--- @param fmt string
|
||||
--- @return fun(fmt: string, str: string, pos: number) unpack string.unpack!
|
||||
--- @return string fmt
|
||||
mod.compileUnpack = function(fmt) return string.unpack, fmt end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,14 +1,4 @@
|
|||
--- The SHA512 cryptographic hash function.
|
||||
--
|
||||
-- :::note Internal Module
|
||||
-- This module is meant for internal use within the library. Its API is unstable
|
||||
-- and subject to change without major version bumps.
|
||||
-- :::
|
||||
--
|
||||
-- <br />
|
||||
--
|
||||
-- @module[kind=internal] internal.sha512
|
||||
--
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
local packing = require "ccryptolib.internal.packing"
|
||||
|
@ -59,10 +49,8 @@ local K = {
|
|||
}
|
||||
|
||||
--- Hashes data bytes using SHA512.
|
||||
--
|
||||
-- @tparam string data The input data.
|
||||
-- @treturn string The 64-byte hash value.
|
||||
--
|
||||
--- @param data string The input data.
|
||||
--- @return string hash The 64-byte hash value.
|
||||
local function digest(data)
|
||||
expect(1, data, "string")
|
||||
|
||||
|
|
|
@ -4,12 +4,10 @@ local function lassert(val, err, level)
|
|||
end
|
||||
|
||||
--- Converts a little-endian array from one power-of-two base to another.
|
||||
--
|
||||
-- @tparam {number...} a The array to convert, in little-endian.
|
||||
-- @tparam number base1 The base to convert from. Must be a power of 2.
|
||||
-- @tparam number base2 The base to convert to. Must be a power of 2.
|
||||
-- @treturn {number...}
|
||||
--
|
||||
--- @param a number[] The array to convert, in little-endian.
|
||||
--- @param base1 number The base to convert from. Must be a power of 2.
|
||||
--- @param base2 number The base to convert to. Must be a power of 2.
|
||||
--- @return number[]
|
||||
local function rebaseLE(a, base1, base2) -- TODO Write contract properly.
|
||||
local out = {}
|
||||
local outlen = 1
|
||||
|
@ -33,10 +31,8 @@ local function rebaseLE(a, base1, base2) -- TODO Write contract properly.
|
|||
end
|
||||
|
||||
--- Decodes bits with X25519/Ed25519 exponent clamping.
|
||||
--
|
||||
-- @taparm string str The 32-byte encoded exponent.
|
||||
-- @treturn {number...} The decoded clamped bits.
|
||||
--
|
||||
--- @param str string The 32-byte encoded exponent.
|
||||
--- @return number[] bits The decoded clamped bits.
|
||||
local function bits(str)
|
||||
-- Decode.
|
||||
local bytes = {str:byte(1, 32)}
|
||||
|
@ -61,10 +57,8 @@ local function bits(str)
|
|||
end
|
||||
|
||||
--- Decodes bits with X25519/Ed25519 exponent clamping and division by 8.
|
||||
--
|
||||
-- @taparm string str The 32-byte encoded exponent.
|
||||
-- @treturn {number...} The decoded clamped bits, divided by 8.
|
||||
--
|
||||
--- @param str string The 32-byte encoded exponent.
|
||||
--- @return number[] bits The decoded clamped bits, divided by 8.
|
||||
local function bits8(str)
|
||||
return {unpack(bits(str), 4)}
|
||||
end
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
--- The Poly1305 one-time authenticator.
|
||||
--
|
||||
-- @module poly1305
|
||||
--
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
local lassert = require "ccryptolib.internal.util".lassert
|
||||
|
@ -13,11 +10,9 @@ local p4x4 = packing.compilePack(fmt4x4)
|
|||
local mod = {}
|
||||
|
||||
--- Computes a Poly1305 message authentication code.
|
||||
--
|
||||
-- @tparam string key A 32-byte single-use random key.
|
||||
-- @tparam string message The message to authenticate.
|
||||
-- @treturn string The 16-byte authentication tag.
|
||||
--
|
||||
--- @param key string A 32-byte single-use random key.
|
||||
--- @param message string The message to authenticate.
|
||||
--- @return string tag The 16-byte authentication tag.
|
||||
function mod.mac(key, message)
|
||||
expect(1, key, "string")
|
||||
lassert(#key == 32, "key length must be 32", 2)
|
||||
|
|
|
@ -22,9 +22,7 @@ local initialized = false
|
|||
local mod = {}
|
||||
|
||||
--- Mixes entropy into the generator, and marks it as initialized.
|
||||
--
|
||||
-- @tparam string seed The seed data.
|
||||
--
|
||||
--- @param seed string The seed data.
|
||||
function mod.init(seed)
|
||||
expect(1, seed, "string")
|
||||
state = blake3.digestKeyed(state, seed)
|
||||
|
@ -32,18 +30,14 @@ function mod.init(seed)
|
|||
end
|
||||
|
||||
--- Mixes extra entropy into the generator state.
|
||||
--
|
||||
-- @tparam string seed The additional entropy to mix.
|
||||
--
|
||||
--- @param data string The additional entropy to mix.
|
||||
function mod.mix(data)
|
||||
state = blake3.digestKeyed(state, data)
|
||||
end
|
||||
|
||||
--- Generates random bytes.
|
||||
--
|
||||
-- @tparam number len The desired output length.
|
||||
-- @throws If the generator hasn't been initialized.
|
||||
--
|
||||
--- @param len number The desired output length.
|
||||
--- @return string bytes
|
||||
function mod.random(len)
|
||||
expect(1, len, "number")
|
||||
lassert(initialized, "attempt to use an uninitialized random generator", 2)
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
--- The SHA256 cryptographic hash function.
|
||||
--
|
||||
-- @module sha256
|
||||
--
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
local lassert = require "ccryptolib.internal.util".lassert
|
||||
|
@ -79,10 +76,8 @@ local function compress(h, w)
|
|||
end
|
||||
|
||||
--- Hashes data using SHA256.
|
||||
--
|
||||
-- @tparam string data Input bytes.
|
||||
-- @treturn string The 32-byte hash value.
|
||||
--
|
||||
--- @param data string Input bytes.
|
||||
--- @return string hash The 32-byte hash value.
|
||||
local function digest(data)
|
||||
expect(1, data, "string")
|
||||
|
||||
|
@ -101,12 +96,10 @@ local function digest(data)
|
|||
end
|
||||
|
||||
--- Hashes a password using PBKDF2-HMAC-SHA256.
|
||||
--
|
||||
-- @tparam password string The password to hash.
|
||||
-- @tparam salt string The password's salt.
|
||||
-- @tparam iter number The number of iterations to perform.
|
||||
-- @treturn string The 32-byte derived key.
|
||||
--
|
||||
--- @param password string The password to hash.
|
||||
--- @param salt string The password's salt.
|
||||
--- @param iter number The number of iterations to perform.
|
||||
--- @return string dk The 32-byte derived key.
|
||||
local function pbkdf2(password, salt, iter)
|
||||
expect(1, password, "string")
|
||||
expect(2, salt, "string")
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
--- The X25519 key exchange scheme.
|
||||
--
|
||||
-- @module x25519
|
||||
--
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
local lassert = require "ccryptolib.internal.util".lassert
|
||||
|
@ -11,10 +8,8 @@ local c25 = require "ccryptolib.internal.curve25519"
|
|||
local mod = {}
|
||||
|
||||
--- Computes the public key from a secret key.
|
||||
--
|
||||
-- @tparam string sk A random 32-byte secret key.
|
||||
-- @treturn string The matching public key.
|
||||
--
|
||||
--- @param sk string A random 32-byte secret key.
|
||||
--- @return string pk The matching public key.
|
||||
function mod.publicKey(sk)
|
||||
expect(1, sk, "string")
|
||||
assert(#sk == 32, "secret key length must be 32")
|
||||
|
@ -22,25 +17,27 @@ function mod.publicKey(sk)
|
|||
end
|
||||
|
||||
--- Performs the key exchange.
|
||||
--
|
||||
-- @tparam string sk A secret key.
|
||||
-- @tparam string pk A public key, usually derived from a second secret key.
|
||||
-- @treturn string The 32-byte shared secret between both keys.
|
||||
--
|
||||
--- @param sk string A Curve25519 secret key.
|
||||
--- @param pk string A public key, usually derived from someone else's secret key.
|
||||
--- @return string ss The 32-byte shared secret between both keys.
|
||||
function mod.exchange(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)
|
||||
lassert(#pk == 32, "public key length must be 32", 2) --- @cast pk String32
|
||||
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.
|
||||
--- 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.
|
||||
function mod.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)
|
||||
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
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ local sha512 = require "ccryptolib.internal.sha512"
|
|||
local random = require "ccryptolib.random"
|
||||
|
||||
--- Masks an exchange secret key.
|
||||
--- @param sk string A random 32-byte Curve25519 secret key.
|
||||
--- @return string msk A masked secret key.
|
||||
local function maskX(sk)
|
||||
expect(1, sk, "string")
|
||||
lassert(#sk == 32, "secret key length must be 32", 2)
|
||||
|
@ -19,6 +21,8 @@ local function maskX(sk)
|
|||
end
|
||||
|
||||
--- Masks a signature secret key.
|
||||
--- @param sk string A random 32-byte Edwards25519 secret key.
|
||||
--- @return string msk A masked secret key.
|
||||
function maskS(sk)
|
||||
expect(1, sk, "string")
|
||||
lassert(#sk == 32, "secret key length must be 32", 2)
|
||||
|
@ -26,27 +30,29 @@ function maskS(sk)
|
|||
end
|
||||
|
||||
--- Rerandomizes the masking on a masked key.
|
||||
local function remask(sk)
|
||||
expect(1, sk, "string")
|
||||
lassert(#sk == 64, "masked secret key length must be 64", 2)
|
||||
--- @param msk string A masked secret key.
|
||||
--- @return string msk The same secret key, but with another mask.
|
||||
local function remask(msk)
|
||||
expect(1, msk, "string")
|
||||
lassert(#msk == 64, "masked secret key length must be 64", 2)
|
||||
local newMask = random.random(32)
|
||||
local xr = fq.decode(sk:sub(1, 32))
|
||||
local r = fq.decodeClamped(sk:sub(33))
|
||||
local xr = fq.decode(msk:sub(1, 32))
|
||||
local r = fq.decodeClamped(msk:sub(33))
|
||||
local s = fq.decodeClamped(newMask)
|
||||
local xs = fq.add(xr, fq.sub(r, s))
|
||||
return fq.encode(xs) .. newMask
|
||||
end
|
||||
|
||||
--- Returns the ephemeral exchange secret key of this masked key.
|
||||
--
|
||||
-- This is the second secret key in the "double key exchange" in @{exchange},
|
||||
-- the first being the key that has been masked. The ephemeral key changes every
|
||||
-- time @{remask} is called.
|
||||
--
|
||||
local function ephemeralSk(sk)
|
||||
expect(1, sk, "string")
|
||||
lassert(#sk == 64, "masked secret key length must be 64", 2)
|
||||
return sk:sub(33)
|
||||
--- This is the second secret key in the "double key exchange" in @{exchange},
|
||||
--- the first being the key that has been masked. The ephemeral key changes
|
||||
--- every time @{remask} is called.
|
||||
--- @param msk string A masked secret key.
|
||||
--- @return string esk The ephemeral half of the masked secret key.
|
||||
local function ephemeralSk(msk)
|
||||
expect(1, msk, "string")
|
||||
lassert(#msk == 64, "masked secret key length must be 64", 2)
|
||||
return msk:sub(33)
|
||||
end
|
||||
|
||||
local function exchangeOnPoint(sk, P)
|
||||
|
@ -108,54 +114,69 @@ local function exchangeOnPoint(sk, P)
|
|||
end
|
||||
|
||||
--- Returns the X25519 public key of this masked key.
|
||||
local function publicKeyX(sk)
|
||||
expect(1, sk, "string")
|
||||
lassert(#sk == 64, "masked secret key length must be 64", 2)
|
||||
return (exchangeOnPoint(sk, c25.G))
|
||||
--- @param msk string A masked secret key.
|
||||
local function publicKeyX(msk)
|
||||
expect(1, msk, "string")
|
||||
lassert(#msk == 64, "masked secret key length must be 64", 2)
|
||||
return (exchangeOnPoint(msk, c25.G))
|
||||
end
|
||||
|
||||
--- Returns the Ed25519 public key of this masked key.
|
||||
local function publicKeyS(sk)
|
||||
expect(1, sk, "string")
|
||||
lassert(#sk == 64, "masked secret key length must be 64", 2)
|
||||
local xr = fq.decode(sk:sub(1, 32))
|
||||
local r = fq.decodeClamped(sk:sub(33))
|
||||
--- @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.
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
---
|
||||
--- 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.
|
||||
---
|
||||
--- @param sk string A masked secret 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 sse The shared secret betwen the public key and the ephemeral half of the masked key.
|
||||
local function exchangeX(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)
|
||||
lassert(#pk == 32, "public key length must be 32", 2) --- @cast pk String32
|
||||
return exchangeOnPoint(sk, c25.decode(pk))
|
||||
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}.
|
||||
--
|
||||
---
|
||||
--- 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)
|
||||
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)
|
||||
|
|
|
@ -16,15 +16,15 @@ describe("aead.encrypt", function()
|
|||
|
||||
-- Types
|
||||
expect.error(aead.encrypt, nil, nonce, msg, aad, rounds)
|
||||
:eq("bad argument #1 (expected string, got nil)")
|
||||
:eq("bad argument #1 (string expected, got nil)")
|
||||
expect.error(aead.encrypt, key, nil, msg, aad, rounds)
|
||||
:eq("bad argument #2 (expected string, got nil)")
|
||||
:eq("bad argument #2 (string expected, got nil)")
|
||||
expect.error(aead.encrypt, key, nonce, nil, aad, rounds)
|
||||
:eq("bad argument #3 (expected string, got nil)")
|
||||
:eq("bad argument #3 (string expected, got nil)")
|
||||
expect.error(aead.encrypt, key, nonce, msg, nil, rounds)
|
||||
:eq("bad argument #4 (expected string, got nil)")
|
||||
:eq("bad argument #4 (string expected, got nil)")
|
||||
expect.error(aead.encrypt, key, nonce, msg, aad, {})
|
||||
:eq("bad argument #5 (expected number, got table)")
|
||||
:eq("bad argument #5 (number expected, got table)")
|
||||
|
||||
-- String lengths
|
||||
expect.error(aead.encrypt, key .. "a", nonce, msg, aad, rounds)
|
||||
|
@ -155,17 +155,17 @@ describe("aead.decrypt", function()
|
|||
|
||||
-- Types
|
||||
expect.error(aead.decrypt, nil, nonce, tag, ctx, aad, rounds)
|
||||
:eq("bad argument #1 (expected string, got nil)")
|
||||
:eq("bad argument #1 (string expected, got nil)")
|
||||
expect.error(aead.decrypt, key, nil, tag, ctx, aad, rounds)
|
||||
:eq("bad argument #2 (expected string, got nil)")
|
||||
:eq("bad argument #2 (string expected, got nil)")
|
||||
expect.error(aead.decrypt, key, nonce, nil, ctx, aad, rounds)
|
||||
:eq("bad argument #3 (expected string, got nil)")
|
||||
:eq("bad argument #3 (string expected, got nil)")
|
||||
expect.error(aead.decrypt, key, nonce, tag, nil, aad, rounds)
|
||||
:eq("bad argument #4 (expected string, got nil)")
|
||||
:eq("bad argument #4 (string expected, got nil)")
|
||||
expect.error(aead.decrypt, key, nonce, tag, ctx, nil, rounds)
|
||||
:eq("bad argument #5 (expected string, got nil)")
|
||||
:eq("bad argument #5 (string expected, got nil)")
|
||||
expect.error(aead.decrypt, key, nonce, tag, ctx, aad, {})
|
||||
:eq("bad argument #6 (expected number, got table)")
|
||||
:eq("bad argument #6 (number expected, got table)")
|
||||
|
||||
-- String lengths
|
||||
expect.error(aead.decrypt, key .. "a", nonce, tag, ctx, aad, rounds)
|
||||
|
|
|
@ -17,9 +17,9 @@ describe("blake3.digest", function()
|
|||
it("validates arguments", function()
|
||||
-- Types
|
||||
expect.error(blake3.digest, nil)
|
||||
:eq("bad argument #1 (expected string, got nil)")
|
||||
:eq("bad argument #1 (string expected, got nil)")
|
||||
expect.error(blake3.digest, "", {})
|
||||
:eq("bad argument #2 (expected number, got table)")
|
||||
:eq("bad argument #2 (number expected, got table)")
|
||||
|
||||
-- Length
|
||||
expect.error(blake3.digest, "", 0.5)
|
||||
|
@ -51,11 +51,11 @@ describe("blake3.digestKeyed", function()
|
|||
|
||||
-- Types
|
||||
expect.error(blake3.digestKeyed, nil, "")
|
||||
:eq("bad argument #1 (expected string, got nil)")
|
||||
:eq("bad argument #1 (string expected, got nil)")
|
||||
expect.error(blake3.digestKeyed, key, nil)
|
||||
:eq("bad argument #2 (expected string, got nil)")
|
||||
:eq("bad argument #2 (string expected, got nil)")
|
||||
expect.error(blake3.digestKeyed, key, "", {})
|
||||
:eq("bad argument #3 (expected number, got table)")
|
||||
:eq("bad argument #3 (number expected, got table)")
|
||||
|
||||
-- String lengths
|
||||
expect.error(blake3.digestKeyed, key .. "a", "")
|
||||
|
@ -90,11 +90,11 @@ describe("blake3.deriveKey", function()
|
|||
it("validates arguments", function()
|
||||
-- Types
|
||||
expect.error(blake3.deriveKey, nil)
|
||||
:eq("bad argument #1 (expected string, got nil)")
|
||||
:eq("bad argument #1 (string expected, got nil)")
|
||||
expect.error(blake3.deriveKey(""), nil)
|
||||
:eq("bad argument #1 (expected string, got nil)")
|
||||
:eq("bad argument #1 (string expected, got nil)")
|
||||
expect.error(blake3.deriveKey(""), "", {})
|
||||
:eq("bad argument #2 (expected number, got table)")
|
||||
:eq("bad argument #2 (number expected, got table)")
|
||||
|
||||
-- Length
|
||||
expect.error(blake3.deriveKey(""), "", 0.5)
|
||||
|
|
|
@ -16,15 +16,15 @@ describe("chacha20.crypt", function()
|
|||
|
||||
-- Types
|
||||
expect.error(chacha20.crypt, nil, nonce, msg, rounds, offset)
|
||||
:eq("bad argument #1 (expected string, got nil)")
|
||||
:eq("bad argument #1 (string expected, got nil)")
|
||||
expect.error(chacha20.crypt, key, nil, msg, rounds, offset)
|
||||
:eq("bad argument #2 (expected string, got nil)")
|
||||
:eq("bad argument #2 (string expected, got nil)")
|
||||
expect.error(chacha20.crypt, key, nonce, nil, rounds, offset)
|
||||
:eq("bad argument #3 (expected string, got nil)")
|
||||
:eq("bad argument #3 (string expected, got nil)")
|
||||
expect.error(chacha20.crypt, key, nonce, msg, {}, offset)
|
||||
:eq("bad argument #4 (expected number, got table)")
|
||||
:eq("bad argument #4 (number expected, got table)")
|
||||
expect.error(chacha20.crypt, key, nonce, msg, nil, {})
|
||||
:eq("bad argument #5 (expected number, got table)")
|
||||
:eq("bad argument #5 (number expected, got table)")
|
||||
|
||||
-- String lengths
|
||||
expect.error(chacha20.crypt, key .. "a", nonce, msg, rounds, offset)
|
||||
|
|
|
@ -13,9 +13,9 @@ describe("poly1305.mac", function()
|
|||
|
||||
-- Types
|
||||
expect.error(poly1305.mac, nil, msg)
|
||||
:eq("bad argument #1 (expected string, got nil)")
|
||||
:eq("bad argument #1 (string expected, got nil)")
|
||||
expect.error(poly1305.mac, key, nil)
|
||||
:eq("bad argument #2 (expected string, got nil)")
|
||||
:eq("bad argument #2 (string expected, got nil)")
|
||||
|
||||
-- Key length
|
||||
expect.error(poly1305.mac, key .. "a", msg)
|
||||
|
|
|
@ -12,7 +12,7 @@ local longMsg = require "spec.vec.sha256.long"
|
|||
describe("sha256.digest", function()
|
||||
it("validates arguments", function()
|
||||
expect.error(sha256.digest, nil)
|
||||
:eq("bad argument #1 (expected string, got nil)")
|
||||
:eq("bad argument #1 (string expected, got nil)")
|
||||
end)
|
||||
|
||||
it("passes the NIST SHAVS byte-oriented short messages test", function()
|
||||
|
|
|
@ -9,10 +9,10 @@ local sha512 = require "ccryptolib.internal.sha512"
|
|||
local shortMsg = require "spec.vec.sha512.short"
|
||||
local longMsg = require "spec.vec.sha512.long"
|
||||
|
||||
describe("sha256.digest", function()
|
||||
describe("sha512.digest", function()
|
||||
it("validates arguments", function()
|
||||
expect.error(sha512.digest, nil)
|
||||
:eq("bad argument #1 (expected string, got nil)")
|
||||
:eq("bad argument #1 (string expected, got nil)")
|
||||
end)
|
||||
|
||||
it("passes the NIST SHAVS byte-oriented short messages test", function()
|
||||
|
|
Loading…
Reference in a new issue