--- /dev/null
+class AV:
+ def __init__(self, a, v):
+ self.A = a
+ self.V = bytes(v)
+
--- /dev/null
+from cm import av
+from copy import deepcopy
+from cm.sign.prv import PrvMagic
+from cm.sign.pub import PubParse, PubLoad, Can, KUKEM as sign_KUKEM
+from cm.sign.signed import Signed
+import cm.enc.magic as cmenc_magic
+from cm.enc.enc import Encrypted
+from cm.enc.chapoly.dem import Open, CEKLen, DEMAlgo as chapoly_DEMAlgo
+from cm.enc.balloon.decap import Decapsulate, BalloonBLAKE2bHKDF as cmballoon_BalloonBLAKE2bHKDF
+from cm.hash.algo import DefaultNumCPU as cmhash_DefaultNumCPU
+from cm.enc.sntrup4591761x25519.algo import SNTRUP4591761X25519HKDFBLAKE2b, SNTRUP4591761X25519
+import keks
+import hashlib
+import logging
+import argparse
+import os
+import getpass
+import sys
+
+
+logging.basicConfig(
+ level=logging.DEBUG,
+ format="%(asctime)s - %(levelname)s - %(message)s",
+)
+logging.debug("Debug mode")
+logging.info("Info message here")
+logging.warning("Warning!")
+logging.error("Error while running")
+logging.critical("Critical error")
+
+FdPubR = 4
+FdPrvR = 8
+
+
+def blake2bHash() -> hashlib.blake2b:
+ try:
+ h = hashlib.blake2b(
+ digest_size=512
+ )
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+ return h
+
+
+def readPasswd(prompt: str) -> bytearray:
+ try:
+ if raw := os.environ["CMENCTOOL_PASSPHRASE"]:
+ return bytearray(raw)
+ else:
+ if sys.stdin.isatty():
+ p = getpass.getpass(prompt)
+ else:
+ print(prompt)
+ p = sys.stdin.readline().rstrip()
+ return bytearray(p)
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+
+
+def parsePrv(data) -> tuple[av.AV, bytearray]:
+ magic = None
+ #magic, data = keks.StripMagic(data) - нет такого метода
+ if magic == PrvMagic:
+ pass
+ elif magic == cmenc_magic.Magic:
+ encrypted = Encrypted()
+ try:
+ d = keks.NewDecoderFromBytes(data) # нет такого метода
+ d.DecodeStruct(encrypted)
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+ try:
+ if encrypted.DEM.A != chapoly_DEMAlgo:
+ logging.error("unsupported prv encryption DEM")
+ if len(encrypted.kem) != 1 or encrypted.kem[0].A != cmballoon_BalloonBLAKE2bHKDF or len(encrypted.Payload) == 0:
+ logging.error("wrong prv encryption KEM")
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+ passwd = readPasswd("Passphrase for private key:")
+ #cek = bytearray()
+ try:
+ cek = Decapsulate(encrypted.KEM[0], encrypted.Id[:], passwd)
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+ buf = None
+ try:
+ buf = Open(buf, encrypted.Payload, cek, 1)
+ return #?
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+ # дописать
+ pass
+ else:
+ logging.error("wrong magic")
+ try:
+ d = keks.NewDecoderFromBytes(data, keks.DecodeOpts(MaxStrLen=10e16))
+ d.DecodeStruct(av)
+ tail = d.B
+ return #?
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+
+
+def main():
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument(
+ "--id",
+ type=str,
+ default="",
+ action="store",
+ dest="setSalt",
+ help="Set that /id instead of autogeneration",
+ )
+ parser.add_argument(
+ "--include-to",
+ type=bool,
+ default=False,
+ action="store",
+ dest="includeTo",
+ help='Include "to" field in KEMs',
+ )
+ parser.add_argument(
+ "--p",
+ type=bool,
+ default=False,
+ action="store",
+ dest="passphrase",
+ help="Use passphrase",
+ )
+ parser.add_argument(
+ "--balloon-s",
+ type=int,
+ default=2**16,
+ action="store",
+ dest="balloonS",
+ help="Balloon's space cost",
+ )
+ parser.add_argument(
+ "--balloon-t",
+ type=int,
+ default=4,
+ action="store",
+ dest="balloonT",
+ help="Balloon's time cost",
+ )
+ parser.add_argument(
+ "--balloon-p",
+ type=int,
+ default=2,
+ action="store",
+ dest="balloonP",
+ help="Balloon's number of threads",
+ )
+ parser.add_argument(
+ "--d",
+ type=bool,
+ default=False,
+ action="store",
+ dest="doDecrypt",
+ )
+ parser.add_argument(
+ "--parallel",
+ type=int,
+ default=cmhash_DefaultNumCPU,
+ action="store",
+ dest="doDecrypt",
+ help="Parallel cryptors",
+ )
+ parser.add_argument(
+ "--embed",
+ type=bool,
+ default=False,
+ action="store",
+ dest="noblob",
+ help="Include payload into container",
+ )
+ args = parser.parse_args()
+
+ try:
+ with open(FdPubR, "rb") as f:
+ pubs = [] # list of cm.AV
+ pubIds = [] # list of bytearrays
+
+ if data := f.read():
+ while len(data) > 0:
+ signed = None # Signed from signed.py
+ signed, data = PubParse(data)
+ load = PubLoad()
+ if not load.Can(sign_KUKEM):
+ logging.error(f"public key: {len(pubs)} does not have {sign_KUKEM} key usage")
+ if len(load.Pub) != 1:
+ logging.critical(f"public key {len(pubs)}: expected single public key")
+ pubs.append(load.Pub[0])
+ pubIds.append(load.Id)
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+
+ try:
+ with open(FdPrvR, "rb") as f:
+ prvs = [] # list of cm.AV
+
+ if data := f.read():
+ while len(data) > 0:
+ av = None
+ av, data = parsePrv(data)
+ prvs.append(prvs, av)
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+ logging.critical(f"private key: {len(prvs)}: {e.__class__.__name__}")
+
+ if args.doDecrypt:
+ try:
+ d = keks.newDecoderFromReader(sys.stdin, keks.MagicDecodeOpts)
+ t = d.DecodeAtom()
+ if not isinstance(t, cmenc_magic.Magic):
+ logging.critical("no magic met")
+ if not isinstance(d.Iter().Magic(), cmenc_magic.Magic):
+ logging.critical("wrong magic")
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+
+ try:
+ encrypted = None
+ d = keks.NewDecoderFromReader(sys.stdin, None)
+ d.DecodeStruct(encrypted)
+ except Exception as e:
+ logging.error(f"An error occurred: {e.__class__.__name__}")
+
+ if encrypted.DEM.A != chapoly_DEMAlgo:
+ logging.error(f"unsupported DEM: {encrypted.DEM.A}")
+
+ if len(encrypted.KEM) == 0:
+ logging.error("no KEMs")
+
+ try:
+ for kemIdx, kem in enumerate(encrypted.KEM):
+ #case
+ if kem.A == cmballoon_BalloonBLAKE2bHKDF:
+ if not args.passphrase:
+ logging.error(f"{kemIdx}, {kem.A}, skipping because no -passwd")
+
+ passwd = readPasswd(f"Passphrase for {kemIdx} KEM:")
+ cek = Decapsulate(kem, encrypted.Id[:], passwd)
+
+ if len(cek) != CEKLen:
+ logging.error(f"{kemIdx}, {kem.A}, wrong key len, skipping")
+
+ #case
+ elif kem.A == SNTRUP4591761X25519HKDFBLAKE2b:
+ if len(prvs) == 0:
+ logging.info(f"{kemIdx}, {kem.A}, skipping because no private key specified")
+ if kem.Encap is None:
+ logging.error("missing encap")
+
+ if len(kem.Encap) != sntrup4591761.CiphertextSize + 32: # найти реализацию пакета
+ logging.error("invalid encap len")
+
+ for prv in prvs:
+ if prv.A != SNTRUP4591761X25519:
+ continue
+ if len(prv.V) != sntrup4591761.PrivateKeySize + 32: # найти реализацию пакета
+ logging.error("invalid private key len")
+ ourSNTRUP = deepcopy()
--- /dev/null
+# keytool -- dealing with KEKS-encoded keypairs utility
+
+import cm.enc.mceliece6960119x25519.algo as mceliece6960119x25519
+import cm.enc.sntrup4591761x25519.algo as sntrup4591761x25519
+import cm.hash.algo as cmhash
+import keks
+from cm import av
+from cm.enc.mceliece6960119x25519.kp import NewKeypair as mceliece6960119x25519_NewKeypair
+from cm.enc.sntrup4591761x25519.kp import NewKeypair as sntrup4591761x25519_NewKeypair
+from cm.hash.algo import ByName as cmhash_ByName
+from cm.sign.ed25519_blake2b import algo
+from cm.sign.ed25519_blake2b.kp import NewKeypair as ed25519blake2b_NewKeypair
+from cm.sign.gost import gost
+from cm.sign.ed25519_blake2b.ed25519 import Ed25519BLAKE2b
+from cm.sign.gost.kp import NewKeypair as gost_NewKeypair
+from cm.sign.pub import CertificationVerify
+from cm.sign.pub import PubMagic
+from cm.sign.pub import PubParse
+from cm.sign.signed import CertifyWith
+from cm.sign.signed import Load
+from cm.sign.signed import Signed
+
+from sys import stdin
+from sys import stdout
+import argparse
+from datetime import datetime
+from datetime import timedelta
+from datetime import timezone
+import logging
+from hashlib import blake2b
+from uuid import uuid4
+
+
+logging.basicConfig(
+ level=logging.DEBUG,
+ format="%(asctime)s - %(levelname)s - %(message)s",
+)
+
+FdPubR = 4
+FdPubW = 5
+FdPrvR = 8
+FdPrvW = 9
+
+
+def PubParse(data):
+ signed, tail = keks.loads(data)
+ if signed["load"]["t"] != "pub":
+ raise ValueError("TODO: not pub")
+ return signed, tail
+ # тут должны проверить типа напротив схемы
+
+
+def PrvParse(data):
+ av, tail = keks.loads(data)
+ if len(tail) > 0:
+ raise ValueError("prv has tail")
+ # тут должны проверить типа напротив схемы
+ if av["a"] == algo.Ed25519BLAKE2b:
+ return Ed25519BLAKE2b(av["v"], None)
+ # TODO
+ # if av["a"] == GOST
+ # return Ed25519BLAKE2b(av["v"])
+ raise ValueError("unknown prv algorigthm")
+
+
+def CertifyWith(pubLoad, caPubLoad, caPrv, since, till):
+ tbs = {
+ "cid": uuid4(),
+ "sid": caPubLoad["id"],
+ "exp": [since, till],
+ }
+ signAlgo, sign = caPrv.sign(keks.dumps(pubLoad) + keks.dumps(tbs))
+ return { "tbs": tbs, "sign": {"a": signAlgo, "v": sign}, }
+
+
+# /load || sig-tbs
+
+
+def mustReadAll(fd) -> bytes:
+ with open(fd, "rb") as f:
+ data = f.read()
+ return data
+
+
+def main():
+ parser = argparse.ArgumentParser()
+
+ ku = dict()
+ sub = dict()
+
+ # python main.py --ku sig --ku kem --ku ca
+ parser.add_argument(
+ "--ku",
+ type=str,
+ action="append",
+ )
+
+ # python main.py --sub n=ya.ru --sub c=ru --sub org=atlas
+ parser.add_argument(
+ "--sub",
+ type=str,
+ action="append",
+ )
+
+ parser.add_argument(
+ "--since",
+ default="",
+ dest='sinceRaw',
+ help="Optional notBefore, \"2006-01-02 15:04:05\" format",
+ )
+ parser.add_argument(
+ "--lifetime",
+ action='store',
+ default=365,
+ help="Lifetime of the certification, days",
+ )
+ parser.add_argument(
+ "--algo",
+ action='store',
+ default=algo.Ed25519BLAKE2b,
+ help="Public key algorithm",
+ )
+ parser.add_argument(
+ "--verify",
+ action='store',
+ default=False,
+ help="Verify provided -pub with -ca-pub",
+ )
+ parser.add_argument(
+ "--list-algo",
+ action='store',
+ default=False,
+ dest='doList',
+ help="List available algorithms",
+ )
+
+ args = parser.parse_args()
+
+ if args.ku:
+ for _ku in args.ku:
+ ku[_ku] = None
+
+ if args.sub:
+ for _sub in args.sub:
+ s = (_sub).split('=', maxsplit=2) # TODO: проверить sub как список
+ if len(s) != 2:
+ raise("invalid key=value")
+
+ sub[s[0]] = s[1]
+ if args.doList:
+ algos = [
+ algo.Ed25519BLAKE2b,
+ gost.GOST3410256A,
+ gost.GOST3410512C,
+ #sntrup4591761x25519.SNTRUP4591761X25519,
+ #mceliece6960119x25519.ClassicMcEliece6960119X25519,
+ ]
+ algos.sort()
+ for _alg in algos:
+ print(_alg)
+
+ fdPubR = FdPubR
+ fdPubW = FdPubW
+ fdPrvR = FdPrvR
+ fdPrvW = FdPrvW
+
+ doCertify = len(sub) == 0 and not args.verify
+
+ since = datetime.time
+ if args.sinceRaw == "":
+ since = datetime.now()
+ if args.sinceRaw is None or args.sinceRaw == "":
+ since = datetime.now(timezone.utc).replace(
+ microsecond=0) # Текущая дата и время, округленная до секунды
+ else:
+ since = datetime.strptime(args.sinceRaw, "%Y-%m-%d %H:%M:%S") # Парсинг даты
+
+ till = since + timedelta(days=args.lifetime) # Вычисление даты окончания
+
+ caPrv = None
+ caPubs = [] # list of Signed
+ if doCertify or args.verify:
+ data = mustReadAll(fdPubR)
+ while len(data) > 0:
+ signed, data = PubParse(data)
+ caPubs.append(signed)
+ if doCertify:
+ caPrv = PrvParse(mustReadAll(fdPrvR))
+
+ signed = Signed()
+ if doCertify or args.verify:
+ signed, _ = PubParse(mustReadAll(stdin.fileno()))
+
+ if args.verify:
+ CertificationVerify(caPubs, datetime.now(timezone.utc))
+
+ prv = None
+ pubLoad = dict()
+ if doCertify:
+ pubLoad = signed["load"]["v"]
+ else: # создание шаблона
+ pub = bytearray()
+ if args.algo == algo.Ed25519BLAKE2b:
+ prvRaw, pub = Ed25519BLAKE2b.generate_keypair()
+ elif args.algo == gost.GOST3410256A or args.algo == gost.GOST3410512C:
+ _, prvRaw, pub = gost_NewKeypair(args.algo)
+ elif args.algo == sntrup4591761x25519.SNTRUP4591761X25519:
+ prvRaw, pub = sntrup4591761x25519_NewKeypair()
+ elif args.algo == mceliece6960119x25519.ClassicMcEliece6960119X25519:
+ prvRaw, pub = mceliece6960119x25519_NewKeypair()
+
+ prv = { "a": args.algo, "v": prvRaw }
+ pubLoad = {
+ "sub": sub,
+ "pub": [ { "a" : args.algo, "v" : pub, } ],
+ }
+ hasher = None # в Go это билдин интерфейс
+
+ if args.algo == algo.Ed25519BLAKE2b or args.algo == sntrup4591761x25519.SNTRUP4591761X25519:
+ hasher = blake2b(digest_size=32)
+ elif args.algo == gost.GOST3410256A or args.algo == gost.GOST3410512C:
+ hasher = cmhash_ByName(cmhash.Streebog256)
+ elif args.algo == mceliece6960119x25519.ClassicMcEliece6960119X25519:
+ hasher = cmhash_ByName(cmhash.SHAKE128)
+
+ #keks.loads(hasher, pubLoad["pub"], None)
+ hasher.update(keks.dumps((pubLoad["pub"])))
+ pubLoad["id"] = hasher.digest()
+
+ if len(ku) > 0:
+ pubLoad["ku"] = ku
+
+ pubLoadAny = None # Go any(pubLoad) - какой-то интерфейс встроенный
+ signed = {
+ "load": {
+ "t": "pub",
+ "v": pubLoad,
+ }
+ }
+
+ if doCertify:
+ signed["sigs"] = [CertifyWith(
+ signed["load"],
+ caPubs[0]["load"]["v"],
+ caPrv,
+ since,
+ till,
+ )]
+ stdout.buffer.write(keks.dumps(signed))
+ else:
+ with open(FdPubW, "wb") as fd:
+ fd.write(keks.dumps(signed))
+ if prv is not None:
+ with open(FdPrvW, "wb") as fd:
+ fd.write(keks.dumps(prv))
+
+# tmp_buf = None # по сути этот буфер нужен для временного хранения набора байтов
+#
+# keks.loads(tmp_buf, PubMagic, None)
+#
+# keks.loads(tmp_buf, signed, None)
+#
+ #if _, err = io.Copy(fdPubW, &buf); err != nil {
+ # log.Fatal(err) # копирование из буффера в файл (в файловый дескриптор как файл)s
+
+if __name__ == "__main__":
+ main()
+
--- /dev/null
+BalloonBLAKE2bHKDF = "balloon-blake2b-hkdf"
+SaltLen = 16
+HKDFInfo = "cm/encrypted/balloon-blake2b-hkdf"
+
+
+
+def Decapsulate():
+ pass
--- /dev/null
+import hashlib
+
+
+ChunkLen = 128 * 1024
+CommitmentLen = 32
+CEKLen = hashlib.blake2b.digest_size
+DEMAlgo = "chapoly-krkc"
+
+
+
+def Open():
+ pass
--- /dev/null
+class DEM:
+ def __init__(self):
+ self.A = ""
--- /dev/null
+from .dem import DEM
+from .kem import KEM
+import uuid
+
+
+class Encrypted:
+ def __init__(self):
+ self.dem = DEM()
+ self.kem = KEM()
+ self.Payload = bytearray()
+ self.Id = uuid.UUID()
--- /dev/null
+class KEM:
+ def __init__(self):
+ self.A = ""
+ self.CEK = bytearray()
+ self.To = bytearray()
+ self.BallonCost = None #
+ self.salt = bytearray() #
+ self.Encap = bytearray() #
--- /dev/null
+import keks
+
+Magic = keks.Magic("cm/encrypted")
--- /dev/null
+ClassicMcEliece6960119X25519 = "mceliece6960119-x25519"
+ClassicMcEliece6960119X25519HKDFSHAKE256 = "mceliece6960119-x25519-hkdf-shake256"
+
--- /dev/null
+def NewKeypair():
+ pass
--- /dev/null
+SNTRUP4591761X25519 = "sntrup4591761-x25519"
+SNTRUP4591761X25519HKDFBLAKE2b = "sntrup4591761-x25519-hkdf-blake2b"
--- /dev/null
+def NewKeypair():
+ pass
--- /dev/null
+import os
+
+
+BLAKE2b = "blake2b"
+BLAKE2b256 = "blake2b256"
+SHA2512 = "sha2-512"
+SHAKE128 = "shake128"
+SHAKE256 = "shake256"
+Streebog256 = "streebog256"
+Streebog512 = "streebog512"
+
+BLAKE2bMerkle = "blake2b-merkle"
+SHAKE128Merkle = "shake128-merkle"
+SHAKE256Merkle = "shake256-merkle"
+Streebog256Merkle = "streebog256-merkle"
+Streebog512Merkle = "streebog512-merkle"
+
+DefaultNumCPU = max(1, os.cpu_count() // 2)
+
+
+def ByName():
+ pass
--- /dev/null
+from abc import ABCMeta
+from abc import abstractmethod
+
+
+class Signer(metaclass=ABCMeta):
+ @abstractmethod
+ def generate_keypair(self) -> [bytes, bytes]:
+ """TODO
+ """
+
+ @abstractmethod
+ def sign(self, sk: bytes, data: bytes) -> bytes:
+ """TODO
+ """
--- /dev/null
+class Ed25519BLAKE2b:
+ def __init__(self):
+ pass
+
--- /dev/null
+Ed25519BLAKE2b = "ed25519-blake2b"
+Ed25519PhBLAKE2b = "ed25519ph-blake2b"
+Ed25519PhBLAKE2bMerkle = "ed25519ph-blake2b-merkle"
--- /dev/null
+#!/usr/bin/env python
+
+from hashlib import blake2b
+from os import urandom
+
+from cm.sign import Signer
+
+
+b = 256
+q = 2**255 - 19
+l = 2**252 + 27742317777372353535851937790883648493
+
+
+def H(m):
+ return blake2b(m).digest()
+
+
+def expmod(b, e, m):
+ if e == 0:
+ return 1
+ t = expmod(b, e//2, m)**2 % m
+ if e & 1 == 1:
+ t = (t*b) % m
+ return t
+
+
+def inv(x):
+ return expmod(x, q-2, q)
+
+
+d = -121665 * inv(121666)
+I = expmod(2, (q-1)//4, q)
+
+
+def xrecover(y):
+ xx = (y*y-1) * inv(d*y*y+1)
+ x = expmod(xx, (q+3)//8, q)
+ if (x*x - xx) % q != 0:
+ x = (x*I) % q
+ if x % 2 != 0:
+ x = q-x
+ return x
+
+
+By = 4 * inv(5)
+Bx = xrecover(By)
+B = (Bx % q, By % q)
+
+
+def edwards(P, Q):
+ x1, y1 = P
+ x2, y2 = Q
+ x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
+ y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
+ return (x3 % q, y3 % q)
+
+
+def scalarmult(P, e):
+ if e == 0:
+ return (0, 1)
+ Q = scalarmult(P, e//2)
+ Q = edwards(Q, Q)
+ if e & 1 == 1:
+ Q = edwards(Q, P)
+ return Q
+
+
+def encodeint(y):
+ return y.to_bytes(32, "little")
+
+
+def decodeint(s):
+ return int.from_bytes(s, byteorder="little")
+
+
+def Hint(m):
+ return decodeint(H(m))
+
+
+def encodepoint(P):
+ x, y = P
+ return ((y & ((1 << 255)-1)) | ((x & 1) << 255)).to_bytes(32, "little")
+
+
+def bit(h, i):
+ return (bytearray(h)[i//8] >> (i % 8)) & 1
+
+
+def publickey(sk):
+ h = H(sk)
+ a = 2**(b-2) + sum(2**i * bit(h, i) for i in range(3, b-2))
+ A = scalarmult(B, a)
+ return encodepoint(A)
+
+
+def signature(m, sk, pk):
+ h = bytearray(H(sk))
+ a = 2**(b-2) + sum(2**i * bit(h, i) for i in range(3, b-2))
+ r = Hint(bytes(bytearray([h[i] for i in range(b//8, b//4)])) + m)
+ R = scalarmult(B, r)
+ S = (r + Hint(encodepoint(R) + pk + m) * a) % l
+ return encodepoint(R) + encodeint(S)
+
+
+def isoncurve(P):
+ x, y = P
+ return (-x*x + y*y - 1 - d*x*x*y*y) % q == 0
+
+
+def decodepoint(s):
+ y = sum(2**i * bit(s, i) for i in range(0, b-1))
+ x = xrecover(y)
+ if x & 1 != bit(s, b-1):
+ x = q-x
+ P = (x, y)
+ if not isoncurve(P):
+ raise ValueError("decoding point that is not on curve")
+ return P
+
+
+def checkvalid(s, m, pk):
+ if len(s) != b//4:
+ raise ValueError("signature length is wrong")
+ if len(pk) != b//8:
+ raise ValueError("public-key length is wrong")
+ try:
+ R = decodepoint(s[0:b//8])
+ A = decodepoint(pk)
+ S = decodeint(s[b//8:b//4])
+ except ValueError:
+ return False
+ h = Hint(encodepoint(R) + pk + m)
+ return scalarmult(B, S) == edwards(R, scalarmult(A, h))
+
+
+class Ed25519BLAKE2b(Signer):
+ def __init__(self, sk, pk):
+ self.sk = sk
+ if pk is None:
+ self.pk = publickey(sk)
+
+ @classmethod
+ def generate_keypair(cls):
+ sk = urandom(32)
+ pk = publickey(sk)
+ return sk, pk
+
+ def sign(self, data):
+ if self.sk is None:
+ raise ValueError("no prv")
+ from sys import stderr
+ print("WE ARE SIGNING:", data.hex(), self.pk.hex(), file=stderr)
+ return "ed25519-blake2b", signature(data, self.sk, self.pk)
--- /dev/null
+def NewKeypair():
+ pass
--- /dev/null
+GOST3410256A = "gost3410-256A"
+GOST3410512C = "gost3410-512C"
+GOST3410256AMerkle = "gost3410-256A-merkle"
+GOST3410512CMerkle = "gost3410-512C-merkle"
+
+
+def CurveByName():
+ pass
--- /dev/null
+def NewKeypair():
+ pass
--- /dev/null
+from abc import ABCMeta
+from abc import abstractmethod
+
+# class Iface:
+# def __init__(self):
+# self.Signer = None
+
+# def SetMode():
+# pass
+
+# def Prehasher():
+# pass
+
+# def Algo():
+# pass
+
+# def Mode():
+# pass
+
+
+class Signer(metaclass=ABCMeta):
+ @abstractmethod
+ def generate_keypair(self) -> [bytes, bytes]:
+ """TODO
+ """
+
+ @abstractmethod
+ def sign(self, sk: bytes, data: bytes) -> bytes:
+ """TODO
+ """
--- /dev/null
+import keks
+
+
+
+PrvMagic = keks.Magic("cm/prv")
+
+
+def PrvParse():
+ pass
--- /dev/null
+from keks import Magic
+from magic import StripMagic
+from .signed import Signed, SignedParse
+
+
+KUCA = "ca" #// CA-capable key usage
+KUSig = "sig" #// Signing-capable key usage
+KUKEM = "kem" #// Key-encapsulation-mechanism key usage
+PubMagic = Magic("cm/pub")
+FPRLen = 32 #// fingerprint's length
+
+
+def PubParse(data: bytes) -> tuple[Signed, bytes]:
+ magic, data = StripMagic(data)
+ try:
+ if magic != "" and magic != PubMagic:
+ raise Exception("Wrong magic")
+ else:
+ signed, tail = SignedParse(data)
+ except Exception as e:
+ print(e)
+ try:
+ signed, tail = SignedParse(data)
+ except Exception as e:
+ print(e)
+ # = PubParse() внизу
+ return signed, tail
+
+
+# добавить перегруженную функцию PubParse аналогично след
+def PubParse():
+ pass
+"""
+func (signed *Signed) PubParse() error {
+ if signed.Load.T != "pub" {
+ return errors.New("PubParse: wrong load type")
+ }
+ for _, sig := range signed.Sigs {
+ if _, ok := sig.TBS["cid"]; !ok {
+ return errors.New("PubParse: missing cid")
+ }
+ if _, ok := sig.TBS["exp"]; !ok {
+ return errors.New("PubParse: missing exp")
+ }
+ }
+ if signed.Load.V == nil {
+ return errors.New("PubParse: missing /load/v")
+ }
+ var load PubLoad
+ var err error
+ if v, ok := (*signed.Load.V).(map[string]any); ok {
+ mapAny := any(v)
+ signed.Load.V = &mapAny
+ err = keks.Map2Struct(&load, v)
+ } else {
+ err = errors.New("PubParse: wrong /load/v")
+ }
+ if err != nil {
+ return err
+ }
+ if len(load.Sub) == 0 {
+ return errors.New("PubParse: empty sub")
+ }
+ if len(load.Crit) != 0 {
+ return errors.New("PubParse: currently no critical extensions are supported")
+ }
+ if len(load.Pub) == 0 {
+ return errors.New("PubParse: empty pub")
+ }
+ if len(load.Id) != FPRLen {
+ return errors.New("PubParse: invalid id len")
+ }
+ for _, pub := range load.Pub {
+ if len(pub.A) == 0 || len(pub.V) == 0 {
+ return errors.New("PubParse: non-filled pub")
+ }
+ }
+ return nil
+}
+"""
+
+
+def CertificationVerify():
+ pass
+
+
+def PubLoad():
+ pass
+
+
+def Can():
+ pass
--- /dev/null
+class Load:
+ def __init__(self):
+ self.V = None
+ self.T = ""
+
+
+class Signed:
+ def __init__(self):
+ self.load = Load()
+ self.pubs = []
+ self.sigs = []
+
+
+def CertifyWith():
+ pass
+
+
+def SignedParse(data: bytes) -> tuple[Signed, bytes]:
+ pass
--- /dev/null
+def StripMagic():
+ pass