import (
"bytes"
"hash"
- "log"
"github.com/google/uuid"
- "go.cypherpunks.su/gogost/v6/gost3410"
"go.cypherpunks.su/gogost/v6/gost34112012256"
"go.cypherpunks.su/gogost/v6/gost34112012512"
"go.cypherpunks.su/yac/gyac"
"go.cypherpunks.su/yac/gyac/yacpki/utils"
+ "golang.org/x/crypto/blake2b"
)
const (
- AlgoStreebog256 = "streebog256"
- AlgoStreebog512 = "streebog512"
- AlgoGOST3410256A = "gost3410-256A"
- AlgoGOST3410256B = "gost3410-256B"
- AlgoGOST3410256C = "gost3410-256C"
- AlgoGOST3410256D = "gost3410-256D"
- AlgoGOST3410512A = "gost3410-512A"
- AlgoGOST3410512B = "gost3410-512B"
- AlgoGOST3410512C = "gost3410-512C"
+ AlgoEd25519BLAKE2b = "ed25519-blake2b"
+ AlgoGOST3410256A = "gost3410-256A"
+ AlgoGOST3410512C = "gost3410-512C"
+ AlgoStreebog256 = "streebog256"
+ AlgoStreebog512 = "streebog512"
)
var HashToNew = map[string]func() hash.Hash{
func (av *AV) Id() (id uuid.UUID) {
var hasher hash.Hash
switch av.A {
- case AlgoGOST3410256A, AlgoGOST3410256B, AlgoGOST3410256C, AlgoGOST3410256D, AlgoGOST3410512A, AlgoGOST3410512B, AlgoGOST3410512C:
+ case AlgoEd25519BLAKE2b:
+ var err error
+ hasher, err = blake2b.New256(nil)
+ if err != nil {
+ panic(err)
+ }
+ case AlgoGOST3410256A, AlgoGOST3410512C:
hasher = gost34112012256.New()
default:
panic("unsupported algorithm")
}
return id
}
-
-func GOST3410CurveByName(name string) (curve *gost3410.Curve) {
- switch name {
- case AlgoGOST3410256A:
- curve = gost3410.CurveIdtc26gost341012256paramSetA()
- case AlgoGOST3410256B:
- curve = gost3410.CurveIdtc26gost341012256paramSetB()
- case AlgoGOST3410256C:
- curve = gost3410.CurveIdtc26gost341012256paramSetC()
- case AlgoGOST3410256D:
- curve = gost3410.CurveIdtc26gost341012256paramSetD()
- case AlgoGOST3410512A:
- curve = gost3410.CurveIdtc26gost341012512paramSetA()
- case AlgoGOST3410512B:
- curve = gost3410.CurveIdtc26gost341012512paramSetB()
- case AlgoGOST3410512C:
- curve = gost3410.CurveIdtc26gost341012512paramSetC()
- default:
- log.Fatal("unknown curve")
- }
- return
-}
-
-func HasherByKeyAlgo(a string) hash.Hash {
- switch a {
- case AlgoGOST3410256A, AlgoGOST3410256B, AlgoGOST3410256C, AlgoGOST3410256D:
- return gost34112012256.New()
- case AlgoGOST3410512A, AlgoGOST3410512B, AlgoGOST3410512C:
- return gost34112012512.New()
- default:
- log.Fatal("unsupported algorithm")
- }
- return nil
-}
"crypto"
"errors"
"fmt"
+ "hash"
"time"
"github.com/google/uuid"
"go.cypherpunks.su/gogost/v6/gost3410"
+ "go.cypherpunks.su/gogost/v6/gost34112012256"
+ "go.cypherpunks.su/gogost/v6/gost34112012512"
"go.cypherpunks.su/yac/gyac"
+ "go.cypherpunks.su/yac/gyac/yacpki/ed25519-blake2b/ed25519"
"go.cypherpunks.su/yac/gyac/yacpki/utils"
)
}
pub := cer.Pub[0]
switch pub.A {
- case AlgoGOST3410256A, AlgoGOST3410256B, AlgoGOST3410256C, AlgoGOST3410256D, AlgoGOST3410512A, AlgoGOST3410512B, AlgoGOST3410512C:
+ case AlgoEd25519BLAKE2b:
+ if len(pub.V) != ed25519.PublicKeySize {
+ err = errors.New("invalid ed25519 public key size")
+ return
+ }
+ if !ed25519.Verify(ed25519.PublicKey(pub.V), signed, signature) {
+ err = errors.New("invalid ed25519 signature")
+ return
+ }
+ case AlgoGOST3410256A, AlgoGOST3410512C:
var pk *gost3410.PublicKey
pk, err = gost3410.NewPublicKeyBE(GOST3410CurveByName(pub.A), pub.V)
if err != nil {
return
}
- hasher := HasherByKeyAlgo(pub.A)
+ var hasher hash.Hash
+ switch pub.A {
+ case AlgoGOST3410256A:
+ hasher = gost34112012256.New()
+ case AlgoGOST3410512C:
+ hasher = gost34112012512.New()
+ }
utils.MustWrite(hasher, signed)
hsh := hasher.Sum(nil)
var valid bool
#!/bin/sh
testname=`basename "$0"`
-test_description="Check that basic functionality works"
+test_description="Check that basic GOST-related functionality works"
. $SHARNESS_TEST_SRCDIR/sharness.sh
TMPDIR=${TMPDIR:-/tmp}
+
+echo "gost3410-512C gost3410-256A
+ed25519-blake2b ed25519-blake2b" | while read caAlgo eeAlgo ; do
+
subj="-subj CN=CA -subj C=RU"
-test_expect_success "CA generation" "yacertool \
- -algo gost3410-512C \
+test_expect_success "$caAlgo: CA generation" "yacertool \
+ -algo $caAlgo \
-ku ca -ku sig $subj \
-prv $TMPDIR/ca.prv -cer $TMPDIR/ca.cer"
-test_expect_success "CA regeneration" "yacertool \
- -algo gost3410-512C \
+test_expect_success "$caAlgo: CA regeneration" "yacertool \
+ -algo $caAlgo \
-ku ca -ku sig $subj \
-prv $TMPDIR/ca.prv -cer $TMPDIR/ca.cer \
-reuse-key"
-test_expect_success "CA self-signature" "yacertool \
+test_expect_success "$caAlgo: CA self-signature" "yacertool \
-ca-cer $TMPDIR/ca.cer \
-cer $TMPDIR/ca.cer \
-verify"
subj="-subj CN=SubCA -subj C=RU"
-test_expect_success "SubCA generation" "yacertool \
+test_expect_success "$eeAlgo: SubCA generation" "yacertool \
+ -algo $eeAlgo \
-ku ca -ku sig $subj \
-prv $TMPDIR/subca.prv -cer $TMPDIR/subca.cer \
-ca-cer $TMPDIR/ca.cer -ca-prv $TMPDIR/ca.prv"
-test_expect_success "SubCA signature" "yacertool \
+test_expect_success "$eeAlgo: SubCA signature" "yacertool \
-ca-cer $TMPDIR/ca.cer \
-cer $TMPDIR/subca.cer \
-verify"
subj="-subj CN=EE -subj C=RU"
-test_expect_success "EE generation" "yacertool \
- -algo gost3410-256A $subj \
+test_expect_success "$eeAlgo: EE generation" "yacertool \
+ -algo $eeAlgo $subj \
-ca-prv $TMPDIR/subca.prv -ca-cer $TMPDIR/subca.cer \
-prv $TMPDIR/ee.prv -cer $TMPDIR/ee.cer"
-test_expect_success "EE chain" "yacertool \
+test_expect_success "$eeAlgo: EE chain" "yacertool \
-ca-cer $TMPDIR/ca.cer \
-ca-cer $TMPDIR/subca.cer \
-cer $TMPDIR/ee.cer \
-verify"
+done
+
test_done
"go.cypherpunks.su/gogost/v6/gost3410"
"go.cypherpunks.su/yac/gyac"
"go.cypherpunks.su/yac/gyac/yacpki"
+ "go.cypherpunks.su/yac/gyac/yacpki/ed25519-blake2b/ed25519"
"go.cypherpunks.su/yac/gyac/yacpki/utils"
)
}
till := since.Add(time.Duration(*lifetime) * 24 * time.Hour)
- var caPrv *gost3410.PrivateKey
+ var caPrv crypto.Signer
var caCers []*yacpki.SignedData
for _, issuingCer := range issuingCers {
var sd *yacpki.SignedData
if *issuingPrv == "" {
log.Fatal("no -ca-key is set")
}
- var signer crypto.Signer
- signer, err = yacpki.PrvParse(utils.MustReadFile(*issuingPrv))
+ caPrv, err = yacpki.PrvParse(utils.MustReadFile(*issuingPrv))
if err != nil {
log.Fatal(err)
}
- caPrv = signer.(*gost3410.PrivateKey)
}
if *verify {
log.Fatal("no -prv is set")
}
- curve := yacpki.GOST3410CurveByName(*algo)
- if curve == nil {
- log.Fatal("unknown -algo specified")
- }
- var prv *gost3410.PrivateKey
- if *reuseKey {
- var signer crypto.Signer
- signer, err = yacpki.PrvParse(utils.MustReadFile(*prvPath))
- if err != nil {
- log.Fatal(err)
- }
- prv = signer.(*gost3410.PrivateKey)
- if prv.C.Name != curve.Name {
- log.Fatal("-algo is not same with private key")
+ var prv crypto.Signer
+ var pubRaw []byte
+ switch *algo {
+ case yacpki.AlgoEd25519BLAKE2b:
+ if *reuseKey {
+ prv, err = yacpki.PrvParse(utils.MustReadFile(*prvPath))
+ if err != nil {
+ log.Fatal(err)
+ }
+ prvEd25519 := prv.(ed25519.PrivateKey)
+ pubRaw = prvEd25519[ed25519.SeedSize:]
+ } else {
+ var prvEd25519 ed25519.PrivateKey
+ var pubEd25519 ed25519.PublicKey
+ pubEd25519, prvEd25519, err = ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ log.Fatal(err)
+ }
+ prv = prvEd25519
+ pubRaw = pubEd25519[:]
+ err = os.WriteFile(*prvPath, gyac.EncodeItem(nil,
+ gyac.ItemFromGo(yacpki.AV{A: *algo, V: prvEd25519.Seed()})), 0o600)
+ if err != nil {
+ log.Fatal(err)
+ }
}
- } else {
- prvRaw := make([]byte, curve.PointSize())
- if _, err = io.ReadFull(rand.Reader, prvRaw); err != nil {
- log.Fatal(err)
+ default: // GOST
+ curve := yacpki.GOST3410CurveByName(*algo)
+ if curve == nil {
+ log.Fatal("unknown -algo specified")
}
- prv, err = gost3410.NewPrivateKeyBE(curve, prvRaw)
- if err != nil {
- log.Fatal(err)
+ var signer *yacpki.GOSTSigner
+ if *reuseKey {
+ prv, err = yacpki.PrvParse(utils.MustReadFile(*prvPath))
+ if err != nil {
+ log.Fatal(err)
+ }
+ signer = prv.(*yacpki.GOSTSigner)
+ if signer.Prv.C.Name != curve.Name {
+ log.Fatal("-algo is not same with private key")
+ }
+ } else {
+ prvRaw := make([]byte, curve.PointSize())
+ if _, err = io.ReadFull(rand.Reader, prvRaw); err != nil {
+ log.Fatal(err)
+ }
+ var prvKey *gost3410.PrivateKey
+ prvKey, err = gost3410.NewPrivateKeyBE(curve, prvRaw)
+ if err != nil {
+ log.Fatal(err)
+ }
+ raw := gyac.EncodeItem(nil,
+ gyac.ItemFromGo(yacpki.AV{A: *algo, V: prvKey.RawBE()}))
+ prv, err = yacpki.PrvParse(raw)
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = os.WriteFile(*prvPath, raw, 0o600)
+ if err != nil {
+ log.Fatal(err)
+ }
+ signer = prv.(*yacpki.GOSTSigner)
}
- err = os.WriteFile(*prvPath, gyac.EncodeItem(nil,
- gyac.ItemFromGo(yacpki.AV{A: *algo, V: prv.RawBE()})), 0o600)
+ var pub *gost3410.PublicKey
+ pub, err = signer.Prv.PublicKey()
if err != nil {
log.Fatal(err)
}
+ pubRaw = pub.RawBE()
}
- var pub *gost3410.PublicKey
- pub, err = prv.PublicKey()
- if err != nil {
- log.Fatal(err)
- }
- pubMap := yacpki.Pub{A: *algo, V: pub.RawBE()}
+ pubMap := yacpki.Pub{A: *algo, V: pubRaw}
{
- av := yacpki.AV{A: *algo, V: pub.RawBE()}
+ av := yacpki.AV{A: *algo, V: pubRaw}
pubMap.Id = av.Id()
}
cerLoad := yacpki.CerLoad{Subj: subj, Pub: []yacpki.Pub{pubMap}}
--- /dev/null
+byteorder/
+ed25519/
+edwards25519/
+go.mod
--- /dev/null
+#!/bin/sh -e
+
+exec rm -rf byteorder ed25519 edwards25519 go.mod
--- /dev/null
+--- ed25519/ed25519.go 2024-12-03 10:59:27.811011000 +0300
++++ ed25519/ed25519.go 2024-12-03 11:07:51.892841000 +0300
+@@ -20,11 +20,12 @@
+ "crypto"
+ "go.cypherpunks.su/yac/gyac/yacpki/ed25519-blake2b/edwards25519"
+ cryptorand "crypto/rand"
+- "crypto/sha512"
+ "crypto/subtle"
+ "errors"
+ "io"
+ "strconv"
++
++ "golang.org/x/crypto/blake2b"
+ )
+
+ const (
+@@ -81,13 +82,13 @@
+
+ // Sign signs the given message with priv. rand is ignored and can be nil.
+ //
+-// If opts.HashFunc() is [crypto.SHA512], the pre-hashed variant Ed25519ph is used
+-// and message is expected to be a SHA-512 hash, otherwise opts.HashFunc() must
++// If opts.HashFunc() is [crypto.BLAKE2b_512], the pre-hashed variant Ed25519ph is used
++// and message is expected to be a BLAKE2b-512 hash, otherwise opts.HashFunc() must
+ // be [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
+ // passes over messages to be signed.
+ //
+ // A value of type [Options] can be used as opts, or crypto.Hash(0) or
+-// crypto.SHA512 directly to select plain Ed25519 or Ed25519ph, respectively.
++// crypto.BLAKE2b_512 directly to select plain Ed25519 or Ed25519ph, respectively.
+ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
+ hash := opts.HashFunc()
+ context := ""
+@@ -95,8 +96,8 @@
+ context = opts.Context
+ }
+ switch {
+- case hash == crypto.SHA512: // Ed25519ph
+- if l := len(message); l != sha512.Size {
++ case hash == crypto.BLAKE2b_512: // Ed25519ph
++ if l := len(message); l != blake2b.Size {
+ return nil, errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa(l))
+ }
+ if l := len(context); l > 255 {
+@@ -122,7 +123,7 @@
+ // Options can be used with [PrivateKey.Sign] or [VerifyWithOptions]
+ // to select Ed25519 variants.
+ type Options struct {
+- // Hash can be zero for regular Ed25519, or crypto.SHA512 for Ed25519ph.
++ // Hash can be zero for regular Ed25519, or crypto.BLAKE2b_512 for Ed25519ph.
+ Hash crypto.Hash
+
+ // Context, if not empty, selects Ed25519ctx or provides the context string
+@@ -171,7 +172,7 @@
+ panic("ed25519: bad seed length: " + strconv.Itoa(l))
+ }
+
+- h := sha512.Sum512(seed)
++ h := blake2b.Sum512(seed)
+ s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
+ if err != nil {
+ panic("ed25519: internal error: setting scalar failed")
+@@ -213,14 +214,17 @@
+ }
+ seed, publicKey := privateKey[:SeedSize], privateKey[SeedSize:]
+
+- h := sha512.Sum512(seed)
++ h := blake2b.Sum512(seed)
+ s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
+ if err != nil {
+ panic("ed25519: internal error: setting scalar failed")
+ }
+ prefix := h[32:]
+
+- mh := sha512.New()
++ mh, err := blake2b.New512(nil)
++ if err != nil {
++ panic(err)
++ }
+ if domPrefix != domPrefixPure {
+ mh.Write([]byte(domPrefix))
+ mh.Write([]byte{byte(len(context))})
+@@ -228,7 +232,7 @@
+ }
+ mh.Write(prefix)
+ mh.Write(message)
+- messageDigest := make([]byte, 0, sha512.Size)
++ messageDigest := make([]byte, 0, blake2b.Size)
+ messageDigest = mh.Sum(messageDigest)
+ r, err := edwards25519.NewScalar().SetUniformBytes(messageDigest)
+ if err != nil {
+@@ -237,7 +241,10 @@
+
+ R := (&edwards25519.Point{}).ScalarBaseMult(r)
+
+- kh := sha512.New()
++ kh, err := blake2b.New512(nil)
++ if err != nil {
++ panic(err)
++ }
+ if domPrefix != domPrefixPure {
+ kh.Write([]byte(domPrefix))
+ kh.Write([]byte{byte(len(context))})
+@@ -246,7 +253,7 @@
+ kh.Write(R.Bytes())
+ kh.Write(publicKey)
+ kh.Write(message)
+- hramDigest := make([]byte, 0, sha512.Size)
++ hramDigest := make([]byte, 0, blake2b.Size)
+ hramDigest = kh.Sum(hramDigest)
+ k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
+ if err != nil {
+@@ -272,7 +279,7 @@
+ // publicKey. A valid signature is indicated by returning a nil error. It will
+ // panic if len(publicKey) is not [PublicKeySize].
+ //
+-// If opts.Hash is [crypto.SHA512], the pre-hashed variant Ed25519ph is used and
++// If opts.Hash is [crypto.BLAKE2b_512], the pre-hashed variant Ed25519ph is used and
+ // message is expected to be a SHA-512 hash, otherwise opts.Hash must be
+ // [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
+ // passes over messages to be signed.
+@@ -281,8 +288,8 @@
+ // channels, or if an attacker has control of part of the inputs.
+ func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error {
+ switch {
+- case opts.Hash == crypto.SHA512: // Ed25519ph
+- if l := len(message); l != sha512.Size {
++ case opts.Hash == crypto.BLAKE2b_512: // Ed25519ph
++ if l := len(message); l != blake2b.Size {
+ return errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa(l))
+ }
+ if l := len(opts.Context); l > 255 {
+@@ -324,7 +331,10 @@
+ return false
+ }
+
+- kh := sha512.New()
++ kh, err := blake2b.New512(nil)
++ if err != nil {
++ panic(err)
++ }
+ if domPrefix != domPrefixPure {
+ kh.Write([]byte(domPrefix))
+ kh.Write([]byte{byte(len(context))})
+@@ -333,7 +343,7 @@
+ kh.Write(sig[:32])
+ kh.Write(publicKey)
+ kh.Write(message)
+- hramDigest := make([]byte, 0, sha512.Size)
++ hramDigest := make([]byte, 0, blake2b.Size)
+ hramDigest = kh.Sum(hramDigest)
+ k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
+ if err != nil {
--- /dev/null
+#!/bin/sh -e
+# Unfortunately native crypto/ed25519 is not flexible enough and does
+# not give ability to use different hash in Ed25519.
+# That script copies the library (tested on 1.23.3) and patches it to
+# use BLAKE2b hash.
+
+modname=go.cypherpunks.su/yac/gyac/yacpki/ed25519-blake2b
+go mod init $modname
+dst=$PWD
+cd $(go env GOROOT)/src
+cp -r crypto/ed25519 crypto/internal/edwards25519 internal/byteorder $dst
+cd $dst
+
+cd ed25519
+rm -r testdata
+rm *_test.go
+cd ..
+
+cd edwards25519
+rm doc.go *_test.go
+cd ..
+
+find . -name "*.go" -exec perl -i -npe 's#^(\s+)".*/?internal/(.*)"#$1"'$modname'/$2"#' {} +
+
+cd edwards25519/field/_asm
+go mod edit -module $modname/edwards25519/field/_asm
+perl -i -npe "s#crypto/internal#$modname#" fe_amd64_asm.go
+
+cd $dst
+patch <ed25519-to-blake2b.patch
--- /dev/null
+package yacpki
+
+import (
+ "crypto"
+ "hash"
+ "io"
+ "log"
+
+ "go.cypherpunks.su/gogost/v6/gost3410"
+)
+
+type GOSTSigner struct {
+ Prv *gost3410.PrivateKey
+ hasher func() hash.Hash
+}
+
+func (s *GOSTSigner) Public() crypto.PublicKey {
+ return s.Prv.Public()
+}
+
+func (s *GOSTSigner) Sign(
+ rand io.Reader,
+ msg []byte,
+ opts crypto.SignerOpts,
+) (signature []byte, err error) {
+ h := s.hasher()
+ h.Write(msg)
+ dgst := h.Sum(nil)
+ signature, err = s.Prv.Sign(rand, dgst, opts)
+ if err != nil {
+ return
+ }
+ signature = append(signature[len(signature)/2:], signature[:len(signature)/2]...)
+ return
+}
+
+func GOST3410CurveByName(name string) (curve *gost3410.Curve) {
+ switch name {
+ case AlgoGOST3410256A:
+ curve = gost3410.CurveIdtc26gost341012256paramSetA()
+ case AlgoGOST3410512C:
+ curve = gost3410.CurveIdtc26gost341012512paramSetC()
+ default:
+ log.Fatal("unknown curve")
+ }
+ return
+}
"fmt"
"go.cypherpunks.su/gogost/v6/gost3410"
+ "go.cypherpunks.su/gogost/v6/gost34112012256"
+ "go.cypherpunks.su/gogost/v6/gost34112012512"
"go.cypherpunks.su/yac/gyac"
+ "go.cypherpunks.su/yac/gyac/yacpki/ed25519-blake2b/ed25519"
)
func PrvParse(data []byte) (prv crypto.Signer, err error) {
return
}
switch av.A {
+ case AlgoEd25519BLAKE2b:
+ prv = ed25519.NewKeyFromSeed(av.V)
+ if len(av.V) != ed25519.SeedSize {
+ err = errors.New("wrong ed25519 private key size")
+ return
+ }
case AlgoGOST3410256A:
- prv, err = gost3410.NewPrivateKeyBE(
+ signer := &GOSTSigner{hasher: gost34112012256.New}
+ signer.Prv, err = gost3410.NewPrivateKeyBE(
gost3410.CurveIdtc26gost341012256paramSetA(), av.V,
)
- case AlgoGOST3410256B:
- prv, err = gost3410.NewPrivateKeyBE(
- gost3410.CurveIdtc26gost341012256paramSetB(), av.V,
- )
- case AlgoGOST3410256C:
- prv, err = gost3410.NewPrivateKeyBE(
- gost3410.CurveIdtc26gost341012256paramSetC(), av.V,
- )
- case AlgoGOST3410256D:
- prv, err = gost3410.NewPrivateKeyBE(
- gost3410.CurveIdtc26gost341012256paramSetD(), av.V,
- )
- case AlgoGOST3410512A:
- prv, err = gost3410.NewPrivateKeyBE(
- gost3410.CurveIdtc26gost341012512paramSetA(), av.V,
- )
- case AlgoGOST3410512B:
- prv, err = gost3410.NewPrivateKeyBE(
- gost3410.CurveIdtc26gost341012512paramSetB(), av.V,
- )
+ prv = signer
case AlgoGOST3410512C:
- prv, err = gost3410.NewPrivateKeyBE(
+ signer := &GOSTSigner{hasher: gost34112012512.New}
+ signer.Prv, err = gost3410.NewPrivateKeyBE(
gost3410.CurveIdtc26gost341012512paramSetC(), av.V,
)
+ prv = signer
default:
err = fmt.Errorf("unknown private key algo: %s", av.A)
}
"github.com/google/uuid"
"go.cypherpunks.su/yac/gyac"
- "go.cypherpunks.su/yac/gyac/yacpki/utils"
)
type SignedDataLoad struct {
return
}
-func (sd *SignedData) SignWith(parent *CerLoad, prv crypto.Signer, sigTBS SigTBS) error {
+func (sd *SignedData) SignWith(
+ parent *CerLoad,
+ prv crypto.Signer,
+ sigTBS SigTBS,
+) (err error) {
if !parent.Can(KUSig) || len(parent.Pub) != 1 {
return errors.New("parent can not sign")
}
sigTBS.SID = parent.Pub[0].Id
sdTBS := SignedDataTBS{T: sd.Load.T, V: sd.Load.V, TBS: sigTBS}
sig := Sig{TBS: sigTBS}
- hasher := HasherByKeyAlgo(parent.Pub[0].A)
- utils.MustWrite(hasher, gyac.EncodeItem(nil, gyac.ItemFromGo(sdTBS)))
sig.Sign.A = parent.Pub[0].A
- s, err := prv.Sign(rand.Reader, hasher.Sum(nil), nil)
- sig.Sign.V = append(s[len(s)/2:], s[:len(s)/2]...)
+ sig.Sign.V, err = prv.Sign(
+ rand.Reader,
+ gyac.EncodeItem(nil, gyac.ItemFromGo(sdTBS)),
+ crypto.Hash(0),
+ )
if err != nil {
return err
}
@cindex cer
@section cer format
-Certificate is the @ref{signed-data} structure. Its @code{/load/t}
-equals to @code{cer}. @code{/load/v} contains @code{cer-load}:
+Certificate is the @code{@ref{signed-data}} structure.
+Its @code{/load/t} equals to @code{cer}.
+@code{/load/v} contains @code{cer-load}:
@verbatiminclude format/cer-load.cddl
@subsection cer with GOST R 34.10-2012
Same rules of serialisation must be used as with
-@ref{signed-data-gost3410, signed-data-gost3410}. Public key's
-identifier and and @code{cid} should be calculated using Streebog-256
-hash.
+@code{@ref{signed-data-gost3410}}. Public key's
+identifier and and @code{cid} should be calculated
+using big-endian Streebog-256 hash.
+
+@node cer-ed25519-blake2b
+@subsection cer with Ed25519-BLAKE2b
+
+Same calculation and serialisation rules must be used as with
+@code{@ref{signed-data-ed25519-blake2b}}.
+Public key's identifier and and @code{cid} should be calculated
+using BLAKE2b hash with 128 or 256 bit output length specified.
@code{/hash} contains the hash values for all corresponding @code{/a}
algorithms.
+@node hashed-data-blake2b
+@subsection hashed-data with BLAKE2b
+
+@url{https://www.blake2.net/, BLAKE2b} with
+512-bit output has @code{blake2b} algorithm identifier.
+
+256-bit output has @code{blake2b256} algorithm identifier.
+
+@node hashed-data-blake3
+@subsection hashed-data with BLAKE3
+
+ @url{https://github.com/BLAKE3-team/BLAKE3/, BLAKE3} with fixed
+ 256-bit output has @code{blake3} algorithm identifier.
+
+@node hashed-data-sha2
+@subsection hashed-data with SHA2
+
+ SHA2-256 has @code{sha2-256} algorithm identifier.
+
+ SHA2-512 has @code{sha2-512} algorithm identifier.
+
+@node hashed-data-shake
+@subsection hashed-data with SHAKE
+
+ @url{https://keccak.team/, SHAKE} XOF function with fixed
+ 256 (SHAKE128) or 512 (SHAKE256) bit output.
+
+ Following algorithm identifiers are acceptable:
+ @code{shake128}, @code{shake256}.
+
+@node hashed-data-skein512
+@subsection hashed-data with Skein-512
+
+ 512-bit @url{https://www.schneier.com/academic/skein/, Skein-512} hash.
+
+ @code{skein512} is acceptable algorithm identifier.
+
@node hashed-data-gost3411
@subsection hashed-data with GOST R 34.11-2012
-Streebog must be big-endian serialised.
+ Streebog must be big-endian serialised.
+
+ Following algorithm identifiers are acceptable:
+ @code{streebog256}, @code{streebog512}.
+
+@node hashed-data-xxh3-128
+@subsection hashed-data with XXH3-128
-Following algorithm identifiers are acceptable:
+ 128-bit @url{https://xxhash.com/, XXH3} hash must be big-endian encoded.
-@verbatim
-streebog256
-streebog512
-@end verbatim
+ @code{xxh3-128} is acceptable algorithm identifier.
@include format/signed-data.texi
@include format/cer.texi
@include format/hashed-data.texi
+@include format/registry.texi
Big-endian private key representation must be used.
Following algorithm identifiers are acceptable:
+@code{gost3410-256A}, @code{gost3410-512C}.
-@verbatim
-gost3410-256A
-gost3410-256B
-gost3410-256C
-gost3410-256D
-gost3410-512A
-gost3410-512B
-gost3410-512C
-@end verbatim
+@node private-key-ed25519-blake2b
+@subsection private-key with Ed25519-BLAKE2b
+
+32-byte Ed25519 private key is used, as described in
+@url{https://datatracker.ietf.org/doc/html/rfc8032, EdDSA} RFC.
+In many libraries it is called "seed".
+
+@code{ed25519-blake2b} algorithm identifier is used, however actually no
+hash is involved in private key storage.
--- /dev/null
+@node Registry
+@cindex Registry
+@section AI registry
+
+There is example registry of known algorithm identifiers.
+
+@node AI Hashes
+@subsection Hashes
+
+@table @code
+@item blake2b, blake2b256
+ @code{@ref{cer-ed25519-blake2b}},
+ @code{@ref{hashed-data-blake2b}},
+ @code{@ref{signed-data-ed25519-blake2b}}
+@item blake3
+ @code{@ref{hashed-data-blake3}}
+@item sha2-256, sha2-512
+ @code{@ref{hashed-data-sha2}}
+@item shake128, shake256
+ @code{@ref{hashed-data-shake}}
+@item skein512
+ @code{@ref{hashed-data-skein512}}
+@item streebog256, streebog512
+ @code{@ref{cer-gost3410}},
+ @code{@ref{hashed-data-gost3411}},
+ @code{@ref{signed-data-gost3410}}
+@item xxh3-128
+ @code{@ref{hashed-data-xxh3-128}}
+@end table
+
+@node AI DH
+@subsection DH
+
+@table @code
+@item ecdsa-nist256p, ecdsa-nist521p
+@item x25519
+@item x448
+@item gost3410-256A, gost3410-512C
+ @code{@ref{cer-gost3410}},
+ @code{@ref{private-key-gost3410}}
+@end table
+
+@node AI Sign
+@subsection Signatures
+
+@table @code
+@item ecdsa-nist256p, ecdsa-nist521p
+@item ed25519-blake2b
+ @code{@ref{private-key-ed25519-blake2b}}
+ @code{@ref{signed-data-ed25519-blake2b}},
+ @code{@ref{cer-ed25519-blake2b}}
+@item ed448
+@item gost3410-256A, gost3410-512C
+ @code{@ref{cer-gost3410}},
+ @code{@ref{private-key-gost3410}},
+ @code{@ref{signed-data-gost3410}}
+@end table
+
+@node AI Content types
+@subsection Content types
+
+@itemize
+@item @ref{cer, @code{cer}}
+@item @ref{signed-data, @code{data}}
+@item @ref{private-key, @code{prv}}
+@end itemize
in @code{BE(X)||BE(Y)} format. Signature is in @code{BE(R)||BE(S)}
format.
-Following algorithm identifiers are acceptable for the hash:
+Following algorithm identifiers should be used for the hash:
+@code{streebog256}, @code{streebog512}.
-@verbatim
-streebog256
-streebog512
-@end verbatim
+Following algorithm identifiers are acceptable for the public key and
+signature: @code{gost3410-256A}, @code{gost3410-512C}.
+
+@node signed-data-ed25519-blake2b
+@subsection signed-data with Ed25519-BLAKE2b
+
+@url{https://datatracker.ietf.org/doc/html/rfc8032, EdDSA} with
+Edwards25519 is used similarly as in RFC 8032.
+But BLAKE2b is used instead of SHA2-512 hash.
+
+Strict @url{https://zips.z.cash/zip-0215, ZIP-0215} validation rules
+should be used while verifying the signature.
+
+@code{ed25519-blake2b} algorithm identifier is used.
Copyright @copyright{} 2024-2025 @email{stargrave@@stargrave.org, Sergey Matveev}
@end copying
+@firstparagraphindent insert
+
@node Top
@top YAC
@include encoding/index.texi
@include schema.texi
@include format/index.texi
-@include registry.texi
@node Concepts Index
@unnumbered Concepts Index
+++ /dev/null
-@node Registry
-@cindex Registry
-@unnumbered AI registry
-
-There is example registry of known algorithm identifiers.
-
-@node AI Hashes
-@section Hashes
-
-@verbatim
-blake2b256
-blake2b512
-blake3-256
-sha2-224
-sha2-256
-sha2-384
-sha2-512
-sha3-224
-sha3-256
-sha3-384
-sha3-512
-shake128
-shake256
-skein512
-streebog256
-streebog512
-xxh3-128
-@end verbatim
-
-@node AI DH
-@section DH
-
-@verbatim
-ecdsa-nist192p
-ecdsa-nist224p
-ecdsa-nist256p
-ecdsa-nist384p
-ecdsa-nist521p
-gost3410-256A
-gost3410-256B
-gost3410-256C
-gost3410-256D
-gost3410-512A
-gost3410-512B
-gost3410-512C
-x25519
-x448
-@end verbatim
-
-@node AI Sign
-@section Signatures
-
-@verbatim
-ecdsa-nist192p
-ecdsa-nist224p
-ecdsa-nist256p
-ecdsa-nist384p
-ecdsa-nist521p
-ed25519
-ed448
-gost3410-256A
-gost3410-256B
-gost3410-256C
-gost3410-256D
-gost3410-512A
-gost3410-512B
-gost3410-512C
-@end verbatim
-
-@node AI Content types
-@section Content types
-
-@verbatim
-cer
-data
-prv
-@end verbatim