File: x448.go

package info (click to toggle)
golang-github-protonmail-go-crypto 1.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,932 kB
  • sloc: makefile: 10
file content (107 lines) | stat: -rw-r--r-- 2,702 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
package ecc

import (
	"crypto/subtle"
	"io"

	"github.com/ProtonMail/go-crypto/openpgp/errors"
	x448lib "github.com/cloudflare/circl/dh/x448"
)

type x448 struct{}

func NewX448() *x448 {
	return &x448{}
}

func (c *x448) GetCurveName() string {
	return "x448"
}

// MarshalBytePoint encodes the public point from native format, adding the prefix.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
func (c *x448) MarshalBytePoint(point []byte) []byte {
	return append([]byte{0x40}, point...)
}

// UnmarshalBytePoint decodes a point from prefixed format to native.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6
func (c *x448) UnmarshalBytePoint(point []byte) []byte {
	if len(point) != x448lib.Size+1 {
		return nil
	}

	return point[1:]
}

// MarshalByteSecret encoded a scalar from native format to prefixed.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
func (c *x448) MarshalByteSecret(d []byte) []byte {
	return append([]byte{0x40}, d...)
}

// UnmarshalByteSecret decodes a scalar from prefixed format to native.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.6.1.2
func (c *x448) UnmarshalByteSecret(d []byte) []byte {
	if len(d) != x448lib.Size+1 {
		return nil
	}

	// Store without prefix
	return d[1:]
}

func (c *x448) generateKeyPairBytes(rand io.Reader) (sk, pk x448lib.Key, err error) {
	if _, err = rand.Read(sk[:]); err != nil {
		return
	}

	x448lib.KeyGen(&pk, &sk)
	return
}

func (c *x448) GenerateECDH(rand io.Reader) (point []byte, secret []byte, err error) {
	priv, pub, err := c.generateKeyPairBytes(rand)
	if err != nil {
		return
	}

	return pub[:], priv[:], nil
}

func (c *x448) Encaps(rand io.Reader, point []byte) (ephemeral, sharedSecret []byte, err error) {
	var pk, ss x448lib.Key
	seed, e, err := c.generateKeyPairBytes(rand)
	if err != nil {
		return nil, nil, err
	}
	copy(pk[:], point)
	x448lib.Shared(&ss, &seed, &pk)

	return e[:], ss[:], nil
}

func (c *x448) Decaps(ephemeral, secret []byte) (sharedSecret []byte, err error) {
	var ss, sk, e x448lib.Key

	copy(sk[:], secret)
	copy(e[:], ephemeral)
	x448lib.Shared(&ss, &sk, &e)

	return ss[:], nil
}

func (c *x448) ValidateECDH(point []byte, secret []byte) error {
	var sk, pk, expectedPk x448lib.Key

	copy(pk[:], point)
	copy(sk[:], secret)
	x448lib.KeyGen(&expectedPk, &sk)

	if subtle.ConstantTimeCompare(expectedPk[:], pk[:]) == 0 {
		return errors.KeyInvalidError("ecc: invalid curve25519 public point")
	}

	return nil
}