src/crypto/ed25519/ed25519.bend source
src/crypto/ed25519/ed25519.bend on the hub · documented module
import Baseimport ../hash.bend as Himport ../curve25519/field.bend as Fimport ../curve25519/x25519.bend as Ximport ./scalar.bend as SCimport ./point.bend as PT# Ed25519 (RFC 8032 section 5.1): key generation (5.1.5), signing (5.1.6)# and cofactorless verification (5.1.7: [S]B == R + [k]A', S < L checked)# on byte strings (U32 values below 256); SHA-512 is ../hash.bend's (proved# equal to FIPS 180-4).def cat(xs: List<&2, U32>, ys: List<&2, U32>) -> List<&2, U32>: match xs: case Nil{}: ys case Con{x, xt}: Con{x, cat(xt, ys)}# k = SHA-512(R || A || M) mod Ldef hram(rb: List<&2, U32>, +a: List<&2, U32>, +msg: List<&2, U32>) -> List<&2, U32>: match rb: case Nil{}: SC.reduce(H.sha512(cat(Nil{}, cat(a, msg)))) case Con{x, xt}: SC.reduce(H.sha512(cat(Con{x, xt}, cat(a, msg))))# the secret scalar s (pruned lower half of SHA-512(seed)) and the prefixdef secret(+h: List<&2, U32>) -> List<&2, U32>: X.clamp(F.take(32n, h))def prefix(+h: List<&2, U32>) -> List<&2, U32>: F.drop(32n, h)# xs: an input (the seed or the public key), which keeps the proof checker# from computing the curve constants (see PT.lit)def public_of(+c: PT.Cs, +xs: List<&2, U32>, +h: List<&2, U32>) -> List<&2, U32>: PT.encode(PT.mul(c, secret(h), PT.base(c, xs)))# A = [s]B, encodeddef public_key(+seed: List<&2, U32>) -> List<&2, U32>: public_of(PT.consts(seed), seed, H.sha512(seed))def sign_with(+c: PT.Cs, +xs: List<&2, U32>, +h: List<&2, U32>, +msg: List<&2, U32>) -> List<&2, U32>: +b = PT.base(c, xs) +a = public_of(c, xs, h) +r = SC.reduce(H.sha512(cat(prefix(h), msg))) +rb = PT.encode(PT.mul(c, r, b)) +k = hram(rb, a, msg) cat(rb, SC.mul_add(k, SC.reduce(secret(h)), r))def sign_raw(+seed: List<&2, U32>, +msg: List<&2, U32>) -> List<&2, U32>: sign_with(PT.consts(seed), seed, H.sha512(seed), msg)def check(+c: PT.Cs, +sb: List<&2, U32>, +rb: List<&2, U32>, +pk: List<&2, U32>, +msg: List<&2, U32>, ra: Maybe<&2, PT.Pt>, aa: Maybe<&2, PT.Pt>) -> Bool: match ra aa: case Some{r} Some{+a}: +k = hram(rb, pk, msg) +b = PT.base(c, pk) PT.equal(PT.mul(c, sb, b), PT.add(c, r, PT.mul(c, k, a))) case _ _: False{}def verify_with(+c: PT.Cs, +pk: List<&2, U32>, +msg: List<&2, U32>, +rb: List<&2, U32>, +sb: List<&2, U32>, s_ok: Bool) -> Bool: match s_ok: case True{}: check(c, sb, rb, pk, msg, PT.decode(c, rb), PT.decode(c, pk)) case False{}: False{}def verify_raw(+pk: List<&2, U32>, +msg: List<&2, U32>, +sig: List<&2, U32>) -> Bool: +sb = F.drop(32n, sig) verify_with(PT.consts(pk), pk, msg, F.take(32n, sig), sb, SC.lt_l(sb))