Compare commits
10 Commits
deps
...
v1.0.0-pre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35ef54f79f | ||
|
|
2f22cb9b15 | ||
|
|
a43c3af4c8 | ||
|
|
eab24207bc | ||
|
|
be01529d44 | ||
|
|
182036b055 | ||
|
|
0763d6f8b6 | ||
|
|
c7a870e9db | ||
|
|
2238f3a26c | ||
|
|
f2cd448a11 |
2
.github/workflows/pre-commit.yaml
vendored
2
.github/workflows/pre-commit.yaml
vendored
@@ -1,9 +1,7 @@
|
||||
name: pre-commit
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
# branches: [main]
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
|
||||
@@ -5,6 +5,8 @@ with limited (and soon to be deprecated) support for the `varsig` < v1.0
|
||||
specification. This is predominantly included to support the UCAN v1.0
|
||||
use-case.
|
||||
|
||||
Built with ❤️ by [Consensys](https://consensys.io/).
|
||||
|
||||
## Usage
|
||||
|
||||
Include the `go-varsig` library by running the following command:
|
||||
@@ -54,3 +56,10 @@ Since there's only one workflow, the simplest command to test it is:
|
||||
```bash
|
||||
act
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is dual-licensed under Apache 2.0 and MIT terms:
|
||||
|
||||
- Apache License, Version 2.0, ([LICENSE-APACHE](https://github.com/ucan-wg/go-varsig/blob/master/LICENSE-APACHE-2.0) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](https://github.com/ucan-wg/go-varsig/blob/master/LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
80
common.go
80
common.go
@@ -1,41 +1,73 @@
|
||||
package varsig
|
||||
|
||||
// Ed25519 produces a varsig that describes the associated algorithm defined
|
||||
// by the [IANA JOSE specification].
|
||||
//
|
||||
import "fmt"
|
||||
|
||||
// [IANA JOSE specification]: https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms
|
||||
|
||||
// Ed25519 produces a varsig for EdDSA using Ed25519 curve.
|
||||
// This algorithm is defined in [IANA JOSE specification].
|
||||
func Ed25519(payloadEncoding PayloadEncoding, opts ...Option) (EdDSAVarsig, error) {
|
||||
return NewEdDSAVarsig(CurveEd25519, HashAlgorithmSHA512, payloadEncoding, opts...)
|
||||
return NewEdDSAVarsig(CurveEd25519, HashSha2_512, payloadEncoding, opts...)
|
||||
}
|
||||
|
||||
// Ed448 produces a varsig that describes the associated algorithm defined
|
||||
// by the [IANA JOSE specification].
|
||||
//
|
||||
// [IANA JOSE specification]: https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms
|
||||
// Ed448 produces a varsig for EdDSA using Ed448 curve.
|
||||
// This algorithm is defined in [IANA JOSE specification].
|
||||
func Ed448(payloadEncoding PayloadEncoding, opts ...Option) (EdDSAVarsig, error) {
|
||||
return NewEdDSAVarsig(CurveEd448, HashAlgorithmShake256, payloadEncoding, opts...)
|
||||
return NewEdDSAVarsig(CurveEd448, HashShake_256, payloadEncoding, opts...)
|
||||
}
|
||||
|
||||
// RS256 produces a varsig that describes the associated algorithm defined
|
||||
// by the [IANA JOSE specification].
|
||||
//
|
||||
// [IANA JOSE specification]: https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms
|
||||
// RS256 produces a varsig for RSASSA-PKCS1-v1_5 using SHA-256.
|
||||
// This algorithm is defined in [IANA JOSE specification].
|
||||
func RS256(keyLength uint64, payloadEncoding PayloadEncoding, opts ...Option) (RSAVarsig, error) {
|
||||
return NewRSAVarsig(HashAlgorithmSHA256, keyLength, payloadEncoding, opts...)
|
||||
return NewRSAVarsig(HashSha2_256, keyLength, payloadEncoding, opts...)
|
||||
}
|
||||
|
||||
// RS384 produces a varsig that describes the associated algorithm defined
|
||||
// by the [IANA JOSE specification].
|
||||
//
|
||||
// [IANA JOSE specification]: https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms
|
||||
// RS384 produces a varsig for RSASSA-PKCS1-v1_5 using SHA-384.
|
||||
// This algorithm is defined in [IANA JOSE specification].
|
||||
func RS384(keyLength uint64, payloadEncoding PayloadEncoding, opts ...Option) (RSAVarsig, error) {
|
||||
return NewRSAVarsig(HashAlgorithmSHA384, keyLength, payloadEncoding, opts...)
|
||||
return NewRSAVarsig(HashSha2_384, keyLength, payloadEncoding, opts...)
|
||||
}
|
||||
|
||||
// RS512 produces a varsig that describes the associated algorithm defined
|
||||
// by the [IANA JOSE specification].
|
||||
//
|
||||
// [IANA JOSE specification]: https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms
|
||||
// RS512 produces a varsig for RSASSA-PKCS1-v1_5 using SHA-512.
|
||||
// This algorithm is defined in [IANA JOSE specification].
|
||||
func RS512(keyLength uint64, payloadEncoding PayloadEncoding, opts ...Option) (RSAVarsig, error) {
|
||||
return NewRSAVarsig(HashAlgorithmSHA512, keyLength, payloadEncoding, opts...)
|
||||
return NewRSAVarsig(HashSha2_512, keyLength, payloadEncoding, opts...)
|
||||
}
|
||||
|
||||
// ES256 produces a varsig for ECDSA using P-256 and SHA-256.
|
||||
// This algorithm is defined in [IANA JOSE specification].
|
||||
func ES256(payloadEncoding PayloadEncoding, opts ...Option) (ECDSAVarsig, error) {
|
||||
return NewECDSAVarsig(CurveP256, HashSha2_256, payloadEncoding, opts...)
|
||||
}
|
||||
|
||||
// ES256K produces a varsig for ECDSA using secp256k1 curve and SHA-256.
|
||||
// This algorithm is defined in [IANA JOSE specification].
|
||||
func ES256K(payloadEncoding PayloadEncoding, opts ...Option) (ECDSAVarsig, error) {
|
||||
return NewECDSAVarsig(CurveSecp256k1, HashSha2_256, payloadEncoding, opts...)
|
||||
}
|
||||
|
||||
// ES384 produces a varsig for ECDSA using P-384 and SHA-384.
|
||||
// This algorithm is defined in [IANA JOSE specification].
|
||||
func ES384(payloadEncoding PayloadEncoding, opts ...Option) (ECDSAVarsig, error) {
|
||||
return NewECDSAVarsig(CurveP384, HashSha2_384, payloadEncoding, opts...)
|
||||
}
|
||||
|
||||
// ES512 produces a varsig for ECDSA using P-521 and SHA-512.
|
||||
// This algorithm is defined in [IANA JOSE specification].
|
||||
func ES512(payloadEncoding PayloadEncoding, opts ...Option) (ECDSAVarsig, error) {
|
||||
return NewECDSAVarsig(CurveP521, HashSha2_512, payloadEncoding, opts...)
|
||||
}
|
||||
|
||||
// EIP191 produces a varsig for ECDSA using the Secp256k1 curve, Keccak256 and encoded
|
||||
// with the "personal_sign" format defined by [EIP191].
|
||||
// payloadEncoding must be either PayloadEncodingEIP191Raw or PayloadEncodingEIP191Cbor.
|
||||
// [EIP191]: https://eips.ethereum.org/EIPS/eip-191
|
||||
func EIP191(payloadEncoding PayloadEncoding, opts ...Option) (ECDSAVarsig, error) {
|
||||
switch payloadEncoding {
|
||||
case PayloadEncodingEIP191Raw, PayloadEncodingEIP191Cbor:
|
||||
default:
|
||||
return ECDSAVarsig{}, fmt.Errorf("%w for EIP191: %v", ErrUnsupportedPayloadEncoding, payloadEncoding)
|
||||
}
|
||||
|
||||
return NewECDSAVarsig(CurveSecp256k1, HashKeccak256, payloadEncoding, opts...)
|
||||
}
|
||||
|
||||
189
common_test.go
189
common_test.go
@@ -1,68 +1,147 @@
|
||||
package varsig_test
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ucan-wg/go-varsig"
|
||||
)
|
||||
|
||||
func TestEd25519(t *testing.T) {
|
||||
t.Parallel()
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
varsig varsig.Varsig
|
||||
dataHex string
|
||||
dataBytes []byte
|
||||
}{
|
||||
// Arbitrary use of presets
|
||||
{
|
||||
name: "Ed25519",
|
||||
varsig: must(varsig.Ed25519(varsig.PayloadEncodingDAGCBOR)),
|
||||
dataHex: "3401ed01ed011371",
|
||||
},
|
||||
{
|
||||
name: "Ed448",
|
||||
varsig: must(varsig.Ed448(varsig.PayloadEncodingDAGCBOR)),
|
||||
dataHex: "3401ed0183241971",
|
||||
},
|
||||
{
|
||||
name: "RS256",
|
||||
varsig: must(varsig.RS256(0x100, varsig.PayloadEncodingDAGCBOR)),
|
||||
dataHex: "3401852412800271",
|
||||
},
|
||||
{
|
||||
name: "RS384",
|
||||
varsig: must(varsig.RS384(0x100, varsig.PayloadEncodingDAGCBOR)),
|
||||
dataHex: "3401852420800271",
|
||||
},
|
||||
{
|
||||
name: "RS512",
|
||||
varsig: must(varsig.RS512(0x100, varsig.PayloadEncodingDAGCBOR)),
|
||||
dataHex: "3401852413800271",
|
||||
},
|
||||
{
|
||||
name: "ES256",
|
||||
varsig: must(varsig.ES256(varsig.PayloadEncodingDAGCBOR)),
|
||||
dataHex: "3401ec0180241271",
|
||||
},
|
||||
{
|
||||
name: "ES256K",
|
||||
varsig: must(varsig.ES256K(varsig.PayloadEncodingDAGCBOR)),
|
||||
dataHex: "3401ec01e7011271",
|
||||
},
|
||||
{
|
||||
name: "ES384",
|
||||
varsig: must(varsig.ES384(varsig.PayloadEncodingDAGCBOR)),
|
||||
dataHex: "3401ec0181242071",
|
||||
},
|
||||
{
|
||||
name: "ES512",
|
||||
varsig: must(varsig.ES512(varsig.PayloadEncodingDAGCBOR)),
|
||||
dataHex: "3401ec0182241371",
|
||||
},
|
||||
{
|
||||
name: "EIP191",
|
||||
varsig: must(varsig.EIP191(varsig.PayloadEncodingEIP191Raw)),
|
||||
dataHex: "3401ec01e7011b91c3035f",
|
||||
},
|
||||
|
||||
in, err := varsig.Ed25519(varsig.PayloadEncodingDAGCBOR)
|
||||
mustVarsig(t, in, err)
|
||||
out := roundTrip(t, in, "3401ed01ed011371")
|
||||
assertEdDSAEqual(t, in, out)
|
||||
// from https://github.com/hugomrdias/iso-repo/blob/main/packages/iso-ucan/test/varsig.test.js
|
||||
{
|
||||
name: "RS256+RAW",
|
||||
varsig: must(varsig.RS256(256, varsig.PayloadEncodingVerbatim)),
|
||||
dataBytes: []byte{52, 1, 133, 36, 18, 128, 2, 95},
|
||||
},
|
||||
{
|
||||
name: "ES256+RAW",
|
||||
varsig: must(varsig.ES256(varsig.PayloadEncodingVerbatim)),
|
||||
dataBytes: []byte{52, 1, 236, 1, 128, 36, 18, 95},
|
||||
},
|
||||
{
|
||||
name: "ES512+RAW",
|
||||
varsig: must(varsig.ES512(varsig.PayloadEncodingVerbatim)),
|
||||
dataBytes: []byte{52, 1, 236, 1, 130, 36, 19, 95},
|
||||
},
|
||||
{
|
||||
name: "ES256K+RAW",
|
||||
varsig: must(varsig.ES256K(varsig.PayloadEncodingVerbatim)),
|
||||
dataBytes: []byte{52, 1, 236, 1, 231, 1, 18, 95},
|
||||
},
|
||||
{
|
||||
name: "EIP191+RAW",
|
||||
varsig: must(varsig.EIP191(varsig.PayloadEncodingEIP191Raw)),
|
||||
dataBytes: []byte{52, 1, 236, 1, 231, 1, 27, 145, 195, 3, 95},
|
||||
},
|
||||
{
|
||||
name: "EIP191+DAG-CBOR",
|
||||
varsig: must(varsig.EIP191(varsig.PayloadEncodingEIP191Cbor)),
|
||||
dataBytes: []byte{52, 1, 236, 1, 231, 1, 27, 145, 195, 3, 113},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// round-trip encode and back
|
||||
data := tc.varsig.Encode()
|
||||
|
||||
if tc.dataBytes != nil {
|
||||
require.Equal(t, tc.dataBytes, data)
|
||||
}
|
||||
if tc.dataHex != "" {
|
||||
require.Equal(t, tc.dataHex, hex.EncodeToString(data))
|
||||
}
|
||||
|
||||
rt, err := varsig.Decode(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, tc.varsig.Version(), rt.Version())
|
||||
require.Equal(t, tc.varsig.Discriminator(), rt.Discriminator())
|
||||
require.Equal(t, tc.varsig.PayloadEncoding(), rt.PayloadEncoding())
|
||||
require.Equal(t, tc.varsig.Signature(), rt.Signature())
|
||||
|
||||
switch vs := tc.varsig.(type) {
|
||||
case varsig.EdDSAVarsig:
|
||||
rt := rt.(varsig.EdDSAVarsig)
|
||||
require.Equal(t, vs.Curve(), rt.Curve())
|
||||
require.Equal(t, vs.Hash(), rt.Hash())
|
||||
case varsig.ECDSAVarsig:
|
||||
rt := rt.(varsig.ECDSAVarsig)
|
||||
require.Equal(t, vs.Curve(), rt.Curve())
|
||||
require.Equal(t, vs.Hash(), rt.Hash())
|
||||
case varsig.RSAVarsig:
|
||||
rt := rt.(varsig.RSAVarsig)
|
||||
require.Equal(t, vs.Hash(), rt.Hash())
|
||||
require.Equal(t, vs.KeyLength(), rt.KeyLength())
|
||||
default:
|
||||
t.Fatalf("unexpected varsig type: %T", vs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEd448(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
in, err := varsig.Ed448(varsig.PayloadEncodingDAGCBOR)
|
||||
mustVarsig(t, in, err)
|
||||
out := roundTrip(t, in, "3401ed0183241971")
|
||||
assertEdDSAEqual(t, in, out)
|
||||
}
|
||||
|
||||
func TestRS256(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
in, err := varsig.RS256(0x100, varsig.PayloadEncodingDAGCBOR)
|
||||
mustVarsig(t, in, err)
|
||||
out := roundTrip(t, in, "3401852412800271")
|
||||
assertRSAEqual(t, in, out)
|
||||
}
|
||||
|
||||
func TestRS384(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
in, err := varsig.RS384(0x100, varsig.PayloadEncodingDAGCBOR)
|
||||
mustVarsig(t, in, err)
|
||||
out := roundTrip(t, in, "3401852420800271")
|
||||
assertRSAEqual(t, in, out)
|
||||
}
|
||||
|
||||
func TestRS512(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
in, err := varsig.RS512(0x100, varsig.PayloadEncodingDAGCBOR)
|
||||
mustVarsig(t, in, err)
|
||||
out := roundTrip(t, in, "3401852413800271")
|
||||
assertRSAEqual(t, in, out)
|
||||
}
|
||||
|
||||
func assertEdDSAEqual(t *testing.T, in, out varsig.EdDSAVarsig) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, in.Curve(), out.Curve())
|
||||
assert.Equal(t, in.HashAlgorithm(), out.HashAlgorithm())
|
||||
}
|
||||
|
||||
func assertRSAEqual(t *testing.T, in, out varsig.RSAVarsig) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, in.HashAlgorithm(), out.HashAlgorithm())
|
||||
assert.Equal(t, in.KeyLength(), out.KeyLength())
|
||||
func must[T any](v T, err error) T {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
192
constant.go
192
constant.go
@@ -8,111 +8,199 @@ import (
|
||||
// Prefix is the value for the varsig's varuint prefix byte.
|
||||
const Prefix = uint64(0x34)
|
||||
|
||||
// HashAlgorithm is the value that specifies the hash algorithm
|
||||
// Hash is the value that specifies the hash algorithm
|
||||
// that's used to reduce the signed content
|
||||
type HashAlgorithm uint64
|
||||
type Hash uint64
|
||||
|
||||
// Constant values that allow Varsig implementations to specify how
|
||||
// the payload content is hashed before the signature is generated.
|
||||
const (
|
||||
HashAlgorithmUnspecified HashAlgorithm = 0x00
|
||||
HashAlgorithmSHA256 = HashAlgorithm(0x12)
|
||||
HashAlgorithmSHA384 = HashAlgorithm(0x20)
|
||||
HashAlgorithmSHA512 = HashAlgorithm(0x13)
|
||||
HashAlgorithmShake256 = HashAlgorithm(0x19)
|
||||
HashUnspecified Hash = 0x00
|
||||
|
||||
HashSha2_224 = Hash(0x1013)
|
||||
HashSha2_256 = Hash(0x12)
|
||||
HashSha2_384 = Hash(0x20)
|
||||
HashSha2_512 = Hash(0x13)
|
||||
|
||||
HashSha3_224 = Hash(0x17)
|
||||
HashSha3_256 = Hash(0x16)
|
||||
HashSha3_384 = Hash(0x15)
|
||||
HashSha3_512 = Hash(0x14)
|
||||
|
||||
HashSha512_224 = Hash(0x1014)
|
||||
HashSha512_256 = Hash(0x1015)
|
||||
|
||||
HashBlake2s_256 = Hash(0xb260)
|
||||
HashBlake2b_256 = Hash(0xb220)
|
||||
HashBlake2b_384 = Hash(0xb230)
|
||||
HashBlake2b_512 = Hash(0xb240)
|
||||
|
||||
HashShake_256 = Hash(0x19)
|
||||
|
||||
HashKeccak256 = Hash(0x1b)
|
||||
HashKeccak512 = Hash(0x1d)
|
||||
)
|
||||
|
||||
// DecodeHashAlgorithm reads and validates the expected hash algorithm
|
||||
// (for varsig types include a variable hash algorithm.)
|
||||
func DecodeHashAlgorithm(r BytesReader) (HashAlgorithm, error) {
|
||||
func DecodeHashAlgorithm(r BytesReader) (Hash, error) {
|
||||
u, err := binary.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return HashAlgorithmUnspecified, fmt.Errorf("%w: %w", ErrUnknownHashAlgorithm, err)
|
||||
return HashUnspecified, fmt.Errorf("%w: %w", ErrUnknownHash, err)
|
||||
}
|
||||
|
||||
h := HashAlgorithm(u)
|
||||
h := Hash(u)
|
||||
|
||||
switch h {
|
||||
case HashAlgorithmSHA256,
|
||||
HashAlgorithmSHA384,
|
||||
HashAlgorithmSHA512,
|
||||
HashAlgorithmShake256:
|
||||
case HashSha2_224,
|
||||
HashSha2_256,
|
||||
HashSha2_384,
|
||||
HashSha2_512,
|
||||
HashSha3_224,
|
||||
HashSha3_256,
|
||||
HashSha3_384,
|
||||
HashSha3_512,
|
||||
HashSha512_224,
|
||||
HashSha512_256,
|
||||
HashBlake2s_256,
|
||||
HashBlake2b_256,
|
||||
HashBlake2b_384,
|
||||
HashBlake2b_512,
|
||||
HashShake_256,
|
||||
HashKeccak256,
|
||||
HashKeccak512:
|
||||
return h, nil
|
||||
default:
|
||||
return HashAlgorithmUnspecified, fmt.Errorf("%w: %x", ErrUnknownHashAlgorithm, h)
|
||||
return HashUnspecified, fmt.Errorf("%w: %x", ErrUnknownHash, h)
|
||||
}
|
||||
}
|
||||
|
||||
// PayloadEncoding specifies the encoding of the data being (hashed and)
|
||||
// signed. A canonical representation of the data is required to produce
|
||||
// consistent hashes and signatures.
|
||||
type PayloadEncoding uint64
|
||||
type PayloadEncoding int
|
||||
|
||||
// Constant values that allow Varsig implementations to specify how the
|
||||
// payload content is encoded before being hashed.
|
||||
// In varsig >= v1, only canonical encoding is allowed.
|
||||
const (
|
||||
PayloadEncodingUnspecified PayloadEncoding = 0x00
|
||||
PayloadEncodingVerbatim PayloadEncoding = 0x5f
|
||||
PayloadEncodingDAGPB = PayloadEncoding(0x70)
|
||||
PayloadEncodingDAGCBOR = PayloadEncoding(0x71)
|
||||
PayloadEncodingDAGJSON = PayloadEncoding(0x0129)
|
||||
PayloadEncodingEIP191 = PayloadEncoding(0xd191)
|
||||
PayloadEncodingJWT PayloadEncoding = 0x6a77
|
||||
PayloadEncodingUnspecified = PayloadEncoding(iota)
|
||||
PayloadEncodingVerbatim
|
||||
PayloadEncodingDAGPB
|
||||
PayloadEncodingDAGCBOR
|
||||
PayloadEncodingDAGJSON
|
||||
PayloadEncodingEIP191Raw
|
||||
PayloadEncodingEIP191Cbor
|
||||
PayloadEncodingJWT
|
||||
)
|
||||
|
||||
const (
|
||||
encodingSegmentVerbatim = uint64(0x5f)
|
||||
encodingSegmentDAGPB = uint64(0x70)
|
||||
encodingSegmentDAGCBOR = uint64(0x71)
|
||||
encodingSegmentDAGJSON = uint64(0x0129)
|
||||
encodingSegmentEIP191 = uint64(0xe191)
|
||||
encodingSegmentJWT = uint64(0x6a77)
|
||||
)
|
||||
|
||||
// DecodePayloadEncoding reads and validates the expected canonical payload
|
||||
// encoding of the data to be signed.
|
||||
func DecodePayloadEncoding(r BytesReader, vers Version) (PayloadEncoding, error) {
|
||||
u, err := binary.ReadUvarint(r)
|
||||
seg1, err := binary.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return PayloadEncodingUnspecified, fmt.Errorf("%w: %w", ErrUnsupportedPayloadEncoding, err)
|
||||
}
|
||||
|
||||
payEnc := PayloadEncoding(u)
|
||||
|
||||
switch vers {
|
||||
case Version0:
|
||||
return decodeEncodingInfoV0(payEnc)
|
||||
switch seg1 {
|
||||
case encodingSegmentVerbatim:
|
||||
return PayloadEncodingVerbatim, nil
|
||||
case encodingSegmentDAGPB:
|
||||
return PayloadEncodingDAGPB, nil
|
||||
case encodingSegmentDAGCBOR:
|
||||
return PayloadEncodingDAGCBOR, nil
|
||||
case encodingSegmentDAGJSON:
|
||||
return PayloadEncodingDAGJSON, nil
|
||||
case encodingSegmentEIP191:
|
||||
seg2, err := binary.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return PayloadEncodingUnspecified, fmt.Errorf("%w: incomplete EIP191 encoding: %w", ErrUnsupportedPayloadEncoding, err)
|
||||
}
|
||||
switch seg2 {
|
||||
case encodingSegmentVerbatim:
|
||||
return PayloadEncodingEIP191Raw, nil
|
||||
case encodingSegmentDAGCBOR:
|
||||
return PayloadEncodingEIP191Cbor, nil
|
||||
default:
|
||||
return PayloadEncodingUnspecified, fmt.Errorf("%w: version=%d, encoding=%x+%x", ErrUnsupportedPayloadEncoding, vers, seg1, seg2)
|
||||
}
|
||||
case encodingSegmentJWT:
|
||||
return PayloadEncodingJWT, nil
|
||||
default:
|
||||
return PayloadEncodingUnspecified, fmt.Errorf("%w: version=%d, encoding=%x", ErrUnsupportedPayloadEncoding, vers, seg1)
|
||||
}
|
||||
case Version1:
|
||||
return decodeEncodingInfoV1(payEnc)
|
||||
switch seg1 {
|
||||
case encodingSegmentVerbatim:
|
||||
return PayloadEncodingVerbatim, nil
|
||||
case encodingSegmentDAGCBOR:
|
||||
return PayloadEncodingDAGCBOR, nil
|
||||
case encodingSegmentDAGJSON:
|
||||
return PayloadEncodingDAGJSON, nil
|
||||
case encodingSegmentEIP191:
|
||||
seg2, err := binary.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return PayloadEncodingUnspecified, fmt.Errorf("%w: incomplete EIP191 encoding: %w", ErrUnsupportedPayloadEncoding, err)
|
||||
}
|
||||
switch seg2 {
|
||||
case encodingSegmentVerbatim:
|
||||
return PayloadEncodingEIP191Raw, nil
|
||||
case encodingSegmentDAGCBOR:
|
||||
return PayloadEncodingEIP191Cbor, nil
|
||||
default:
|
||||
return PayloadEncodingUnspecified, fmt.Errorf("%w: version=%d, encoding=%x+%x", ErrUnsupportedPayloadEncoding, vers, seg1, seg2)
|
||||
}
|
||||
default:
|
||||
return PayloadEncodingUnspecified, fmt.Errorf("%w: version=%d, encoding=%x", ErrUnsupportedPayloadEncoding, vers, seg1)
|
||||
}
|
||||
default:
|
||||
return 0, ErrUnsupportedVersion
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ChainAgnostic/varsig#4-payload-encoding
|
||||
func decodeEncodingInfoV0(payEnc PayloadEncoding) (PayloadEncoding, error) {
|
||||
switch payEnc {
|
||||
case PayloadEncodingVerbatim,
|
||||
PayloadEncodingDAGPB,
|
||||
PayloadEncodingDAGCBOR,
|
||||
PayloadEncodingDAGJSON,
|
||||
PayloadEncodingJWT,
|
||||
PayloadEncodingEIP191:
|
||||
return payEnc, nil
|
||||
// EncodePayloadEncoding returns the PayloadEncoding as serialized bytes.
|
||||
// If enc is not a valid PayloadEncoding, this function will panic.
|
||||
func EncodePayloadEncoding(enc PayloadEncoding) []byte {
|
||||
res := make([]byte, 0, 8)
|
||||
switch enc {
|
||||
case PayloadEncodingVerbatim:
|
||||
res = binary.AppendUvarint(res, encodingSegmentVerbatim)
|
||||
case PayloadEncodingDAGPB:
|
||||
res = binary.AppendUvarint(res, encodingSegmentDAGPB)
|
||||
case PayloadEncodingDAGCBOR:
|
||||
res = binary.AppendUvarint(res, encodingSegmentDAGCBOR)
|
||||
case PayloadEncodingDAGJSON:
|
||||
res = binary.AppendUvarint(res, encodingSegmentDAGJSON)
|
||||
case PayloadEncodingEIP191Raw:
|
||||
res = binary.AppendUvarint(res, encodingSegmentEIP191)
|
||||
res = binary.AppendUvarint(res, encodingSegmentVerbatim)
|
||||
case PayloadEncodingEIP191Cbor:
|
||||
res = binary.AppendUvarint(res, encodingSegmentEIP191)
|
||||
res = binary.AppendUvarint(res, encodingSegmentDAGCBOR)
|
||||
case PayloadEncodingJWT:
|
||||
res = binary.AppendUvarint(res, encodingSegmentJWT)
|
||||
default:
|
||||
return PayloadEncodingUnspecified, fmt.Errorf("%w: version=%d, encoding=%x", ErrUnsupportedPayloadEncoding, Version0, payEnc)
|
||||
panic(fmt.Sprintf("invalid encoding: %v", enc))
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/expede/varsig/blob/main/README.md#payload-encoding
|
||||
func decodeEncodingInfoV1(payEnc PayloadEncoding) (PayloadEncoding, error) {
|
||||
switch payEnc {
|
||||
case PayloadEncodingVerbatim,
|
||||
PayloadEncodingDAGCBOR,
|
||||
PayloadEncodingDAGJSON,
|
||||
PayloadEncodingEIP191:
|
||||
return payEnc, nil
|
||||
default:
|
||||
return PayloadEncodingUnspecified, fmt.Errorf("%w: version=%d, encoding=%x", ErrUnsupportedPayloadEncoding, Version1, payEnc)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Discriminator is (usually) the value representing the public key type of
|
||||
// the algorithm used to create the signature.
|
||||
//
|
||||
// There is not set list of constants here, nor is there a decode function
|
||||
// There is no set list of constants here, nor is there a decode function
|
||||
// as the author of an implementation should include the constant with the
|
||||
// implementation, and the decoding is handled by the Handler, which uses
|
||||
// the Discriminator to choose the correct implementation. Also note that
|
||||
|
||||
@@ -18,24 +18,24 @@ func TestDecodeHashAlgorithm(t *testing.T) {
|
||||
|
||||
hashAlg, err := varsig.DecodeHashAlgorithm(bytes.NewReader([]byte{0x12}))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, varsig.HashAlgorithmSHA256, hashAlg)
|
||||
require.Equal(t, varsig.HashSha2_256, hashAlg)
|
||||
})
|
||||
|
||||
t.Run("fails - truncated varsig (no bytes)", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
hashAlg, err := varsig.DecodeHashAlgorithm(bytes.NewReader([]byte{}))
|
||||
require.ErrorIs(t, err, varsig.ErrUnknownHashAlgorithm)
|
||||
require.ErrorIs(t, err, varsig.ErrUnknownHash)
|
||||
require.ErrorIs(t, err, io.EOF)
|
||||
require.Equal(t, varsig.HashAlgorithmUnspecified, hashAlg)
|
||||
require.Equal(t, varsig.HashUnspecified, hashAlg)
|
||||
})
|
||||
|
||||
t.Run("fails - unknown hash algorithm", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
hashAlg, err := varsig.DecodeHashAlgorithm(bytes.NewReader([]byte{0x42}))
|
||||
require.ErrorIs(t, err, varsig.ErrUnknownHashAlgorithm)
|
||||
require.Equal(t, varsig.HashAlgorithmUnspecified, hashAlg)
|
||||
require.ErrorIs(t, err, varsig.ErrUnknownHash)
|
||||
require.Equal(t, varsig.HashUnspecified, hashAlg)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
158
ecdsa.go
158
ecdsa.go
@@ -1,9 +1,155 @@
|
||||
package varsig
|
||||
|
||||
// Stub
|
||||
const (
|
||||
DiscriminatorECDSASecp256k1 Discriminator = 0xe7
|
||||
DiscriminatorECDSAP256 Discriminator = 0x1200
|
||||
DiscriminatorECDSAP384 Discriminator = 0x1201
|
||||
DiscriminatorECDSAP521 Discriminator = 0x1202
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// DiscriminatorECDSA is the value specifying an ECDSA signature.
|
||||
const DiscriminatorECDSA = Discriminator(0xec)
|
||||
|
||||
// ECDSACurve are values that specify which ECDSA curve is used when
|
||||
// generating the signature.
|
||||
type ECDSACurve uint64
|
||||
|
||||
// Constants describing the values for each specific ECDSA curve that can
|
||||
// be encoded into a Varsig.
|
||||
const (
|
||||
CurveSecp256k1 = ECDSACurve(0xe7)
|
||||
CurveP256 = ECDSACurve(0x1200)
|
||||
CurveP384 = ECDSACurve(0x1201)
|
||||
CurveP521 = ECDSACurve(0x1202)
|
||||
)
|
||||
|
||||
func decodeECDSACurve(r BytesReader) (ECDSACurve, error) {
|
||||
u, err := binary.ReadUvarint(r)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
switch curve := ECDSACurve(u); curve {
|
||||
case CurveSecp256k1, CurveP256, CurveP384, CurveP521:
|
||||
return curve, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("%w: %x", ErrUnknownECDSACurve, u)
|
||||
}
|
||||
}
|
||||
|
||||
var _ Varsig = ECDSAVarsig{}
|
||||
|
||||
// ECDSAVarsig is a varsig that encodes the parameters required to describe
|
||||
// an ECDSA signature.
|
||||
type ECDSAVarsig struct {
|
||||
varsig
|
||||
|
||||
curve ECDSACurve
|
||||
hashAlg Hash
|
||||
}
|
||||
|
||||
// NewECDSAVarsig creates and validates an ECDSA varsig with the provided
|
||||
// curve, hash algorithm and payload encoding.
|
||||
func NewECDSAVarsig(curve ECDSACurve, hashAlgorithm Hash, payloadEncoding PayloadEncoding, opts ...Option) (ECDSAVarsig, error) {
|
||||
options := newOptions(opts...)
|
||||
|
||||
var (
|
||||
vers = Version1
|
||||
disc = DiscriminatorECDSA
|
||||
sig []byte
|
||||
)
|
||||
|
||||
if options.ForceVersion0() {
|
||||
vers = Version0
|
||||
disc = Discriminator(curve)
|
||||
sig = options.Signature()
|
||||
}
|
||||
|
||||
v := ECDSAVarsig{
|
||||
varsig: varsig{
|
||||
vers: vers,
|
||||
disc: disc,
|
||||
payEnc: payloadEncoding,
|
||||
sig: sig,
|
||||
},
|
||||
curve: curve,
|
||||
hashAlg: hashAlgorithm,
|
||||
}
|
||||
|
||||
switch curve {
|
||||
case CurveSecp256k1, CurveP256:
|
||||
return validateSig(v, 64)
|
||||
case CurveP384:
|
||||
return validateSig(v, 96)
|
||||
case CurveP521:
|
||||
return validateSig(v, 132)
|
||||
default:
|
||||
return ECDSAVarsig{}, fmt.Errorf("%w: %x", ErrUnknownECDSACurve, curve)
|
||||
}
|
||||
}
|
||||
|
||||
// Curve returns the elliptic curve used to generate the ECDSA signature.
|
||||
func (v ECDSAVarsig) Curve() ECDSACurve {
|
||||
return v.curve
|
||||
}
|
||||
|
||||
// Hash returns the value describing the hash algorithm used to hash
|
||||
// the payload content before the signature is generated.
|
||||
func (v ECDSAVarsig) Hash() Hash {
|
||||
return v.hashAlg
|
||||
}
|
||||
|
||||
// Encode returns the encoded byte format of the ECDSAVarsig.
|
||||
func (v ECDSAVarsig) Encode() []byte {
|
||||
buf := v.encode()
|
||||
|
||||
if v.vers != Version0 {
|
||||
buf = binary.AppendUvarint(buf, uint64(v.curve))
|
||||
}
|
||||
|
||||
buf = binary.AppendUvarint(buf, uint64(v.hashAlg))
|
||||
buf = append(buf, EncodePayloadEncoding(v.payEnc)...)
|
||||
buf = append(buf, v.Signature()...)
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
func decodeECDSA(r BytesReader, vers Version, disc Discriminator) (Varsig, error) {
|
||||
curve := ECDSACurve(disc)
|
||||
if vers != Version0 {
|
||||
var err error
|
||||
|
||||
curve, err = decodeECDSACurve(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
hashAlg, err := DecodeHashAlgorithm(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := ECDSAVarsig{
|
||||
varsig: varsig{
|
||||
vers: vers,
|
||||
disc: disc,
|
||||
},
|
||||
curve: curve,
|
||||
hashAlg: hashAlg,
|
||||
}
|
||||
|
||||
v.payEnc, v.sig, err = v.decodePayEncAndSig(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch curve {
|
||||
case CurveSecp256k1, CurveP256:
|
||||
return validateSig(v, 64)
|
||||
case CurveP384:
|
||||
return validateSig(v, 96)
|
||||
case CurveP521:
|
||||
return validateSig(v, 132)
|
||||
default:
|
||||
return ECDSAVarsig{}, fmt.Errorf("%w: %x", ErrUnknownECDSACurve, curve)
|
||||
}
|
||||
}
|
||||
|
||||
38
eddsa.go
38
eddsa.go
@@ -6,12 +6,8 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Constants containing values that specify EdDSA signatures.
|
||||
const (
|
||||
DiscriminatorEdDSA = Discriminator(0xed)
|
||||
DiscriminatorEd25519 = Discriminator(0xed)
|
||||
DiscriminatorEd448 = Discriminator(0x1203)
|
||||
)
|
||||
// DiscriminatorEdDSA is the value specifying an EdDSA signature.
|
||||
const DiscriminatorEdDSA = Discriminator(0xed)
|
||||
|
||||
// EdDSACurve are values that specify which Edwards curve is used when
|
||||
// generating the signature.
|
||||
@@ -46,12 +42,12 @@ type EdDSAVarsig struct {
|
||||
varsig
|
||||
|
||||
curve EdDSACurve
|
||||
hashAlg HashAlgorithm
|
||||
hashAlg Hash
|
||||
}
|
||||
|
||||
// NewEdDSAVarsig creates and validates an EdDSA varsig with the provided
|
||||
// curve, hash algorithm and payload encoding.
|
||||
func NewEdDSAVarsig(curve EdDSACurve, hashAlgorithm HashAlgorithm, payloadEncoding PayloadEncoding, opts ...Option) (EdDSAVarsig, error) {
|
||||
func NewEdDSAVarsig(curve EdDSACurve, hashAlgorithm Hash, payloadEncoding PayloadEncoding, opts ...Option) (EdDSAVarsig, error) {
|
||||
options := newOptions(opts...)
|
||||
|
||||
var (
|
||||
@@ -77,7 +73,14 @@ func NewEdDSAVarsig(curve EdDSACurve, hashAlgorithm HashAlgorithm, payloadEncodi
|
||||
hashAlg: hashAlgorithm,
|
||||
}
|
||||
|
||||
return validateSig(v, ed25519.SignatureSize)
|
||||
switch curve {
|
||||
case CurveEd25519:
|
||||
return validateSig(v, ed25519.SignatureSize)
|
||||
case CurveEd448:
|
||||
return validateSig(v, 114)
|
||||
default:
|
||||
return EdDSAVarsig{}, fmt.Errorf("%w: %x", ErrUnknownEdDSACurve, curve)
|
||||
}
|
||||
}
|
||||
|
||||
// Curve returns the Edwards curve used to generate the EdDSA signature.
|
||||
@@ -85,9 +88,9 @@ func (v EdDSAVarsig) Curve() EdDSACurve {
|
||||
return v.curve
|
||||
}
|
||||
|
||||
// HashAlgorithm returns the value describing the hash algorithm used to hash
|
||||
// Hash returns the value describing the hash algorithm used to hash
|
||||
// the payload content before the signature is generated.
|
||||
func (v EdDSAVarsig) HashAlgorithm() HashAlgorithm {
|
||||
func (v EdDSAVarsig) Hash() Hash {
|
||||
return v.hashAlg
|
||||
}
|
||||
|
||||
@@ -100,13 +103,13 @@ func (v EdDSAVarsig) Encode() []byte {
|
||||
}
|
||||
|
||||
buf = binary.AppendUvarint(buf, uint64(v.hashAlg))
|
||||
buf = binary.AppendUvarint(buf, uint64(v.payEnc))
|
||||
buf = append(buf, EncodePayloadEncoding(v.payEnc)...)
|
||||
buf = append(buf, v.Signature()...)
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
func decodeEd25519(r BytesReader, vers Version, disc Discriminator) (Varsig, error) {
|
||||
func decodeEdDSA(r BytesReader, vers Version, disc Discriminator) (Varsig, error) {
|
||||
curve := EdDSACurve(disc)
|
||||
if vers != Version0 {
|
||||
var err error
|
||||
@@ -136,5 +139,12 @@ func decodeEd25519(r BytesReader, vers Version, disc Discriminator) (Varsig, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return validateSig(v, ed25519.SignatureSize)
|
||||
switch curve {
|
||||
case CurveEd25519:
|
||||
return validateSig(v, ed25519.SignatureSize)
|
||||
case CurveEd448:
|
||||
return validateSig(v, 114)
|
||||
default:
|
||||
return EdDSAVarsig{}, fmt.Errorf("%w: %x", ErrUnknownEdDSACurve, curve)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,14 +32,14 @@ func TestDecodeEd25519(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, v)
|
||||
assert.Equal(t, varsig.Version0, v.Version())
|
||||
assert.Equal(t, varsig.DiscriminatorEd25519, v.Discriminator())
|
||||
assert.Equal(t, varsig.DiscriminatorEdDSA, v.Discriminator())
|
||||
assert.Equal(t, varsig.PayloadEncodingDAGCBOR, v.PayloadEncoding())
|
||||
assert.Len(t, v.Signature(), 64)
|
||||
|
||||
impl, ok := v.(varsig.EdDSAVarsig)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, varsig.CurveEd25519, impl.Curve())
|
||||
assert.Equal(t, varsig.HashAlgorithmSHA512, impl.HashAlgorithm())
|
||||
assert.Equal(t, varsig.HashSha2_512, impl.Hash())
|
||||
})
|
||||
|
||||
t.Run("Encode", func(t *testing.T) {
|
||||
@@ -47,7 +47,7 @@ func TestDecodeEd25519(t *testing.T) {
|
||||
|
||||
v, err := varsig.NewEdDSAVarsig(
|
||||
varsig.CurveEd25519,
|
||||
varsig.HashAlgorithmSHA512,
|
||||
varsig.HashSha2_512,
|
||||
varsig.PayloadEncodingDAGCBOR,
|
||||
varsig.WithForceVersion0(sig),
|
||||
)
|
||||
@@ -73,15 +73,15 @@ func TestUCANExampleV1(t *testing.T) {
|
||||
v, err := varsig.Decode(example)
|
||||
require.NoError(t, err)
|
||||
|
||||
rsaV, ok := v.(varsig.EdDSAVarsig)
|
||||
ed25519V, ok := v.(varsig.EdDSAVarsig)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, varsig.Version1, rsaV.Version())
|
||||
assert.Equal(t, varsig.DiscriminatorEdDSA, rsaV.Discriminator())
|
||||
assert.Equal(t, varsig.CurveEd25519, rsaV.Curve())
|
||||
assert.Equal(t, varsig.HashAlgorithmSHA512, rsaV.HashAlgorithm())
|
||||
assert.Equal(t, varsig.PayloadEncodingDAGCBOR, rsaV.PayloadEncoding())
|
||||
assert.Len(t, rsaV.Signature(), 0)
|
||||
assert.Equal(t, varsig.Version1, ed25519V.Version())
|
||||
assert.Equal(t, varsig.DiscriminatorEdDSA, ed25519V.Discriminator())
|
||||
assert.Equal(t, varsig.CurveEd25519, ed25519V.Curve())
|
||||
assert.Equal(t, varsig.HashSha2_512, ed25519V.Hash())
|
||||
assert.Equal(t, varsig.PayloadEncodingDAGCBOR, ed25519V.PayloadEncoding())
|
||||
assert.Len(t, ed25519V.Signature(), 0)
|
||||
})
|
||||
|
||||
t.Run("Encode", func(t *testing.T) {
|
||||
@@ -89,7 +89,7 @@ func TestUCANExampleV1(t *testing.T) {
|
||||
|
||||
edDSAVarsig, err := varsig.NewEdDSAVarsig(
|
||||
varsig.CurveEd25519,
|
||||
varsig.HashAlgorithmSHA512,
|
||||
varsig.HashSha2_512,
|
||||
varsig.PayloadEncodingDAGCBOR,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
8
error.go
8
error.go
@@ -21,9 +21,9 @@ var ErrUnexpectedSignaturePresent = errors.New("unexpected signature present in
|
||||
// signing algorithm or sent via a Varsig field.
|
||||
var ErrUnexpectedSignatureSize = errors.New("unexpected signature size in varsig v0")
|
||||
|
||||
// ErrUnknownHashAlgorithm is returned when an unexpected value is provided
|
||||
// ErrUnknownHash is returned when an unexpected value is provided
|
||||
// while decoding the hashing algorithm.
|
||||
var ErrUnknownHashAlgorithm = errors.New("unknown hash algorithm")
|
||||
var ErrUnknownHash = errors.New("unknown hash algorithm")
|
||||
|
||||
// ErrUnsupportedPayloadEncoding is returned when an unexpected value is
|
||||
// provided while decoding the payload encoding field. The allowed values
|
||||
@@ -38,6 +38,10 @@ var ErrUnknownDiscriminator = errors.New("unknown signing algorithm")
|
||||
// CurveEd25519 or CurveEd448.
|
||||
var ErrUnknownEdDSACurve = errors.New("unknown Edwards curve")
|
||||
|
||||
// ErrUnknownECDSACurve is returned when the decoded uvarint isn't either
|
||||
// CurveSecp256k1, CurveP256, CurveP384 or CurveP521.
|
||||
var ErrUnknownECDSACurve = errors.New("unknown ECDSA curve")
|
||||
|
||||
// ErrUnsupportedVersion is returned when an unsupported varsig version
|
||||
// field is present.
|
||||
var ErrUnsupportedVersion = errors.New("unsupported version")
|
||||
|
||||
4
go.mod
4
go.mod
@@ -1,6 +1,8 @@
|
||||
module github.com/ucan-wg/go-varsig
|
||||
|
||||
go 1.24.4
|
||||
go 1.23.10
|
||||
|
||||
toolchain go1.24.4
|
||||
|
||||
require github.com/stretchr/testify v1.10.0
|
||||
|
||||
|
||||
13
registry.go
13
registry.go
@@ -28,12 +28,9 @@ type Registry map[Discriminator]DecodeFunc
|
||||
// signing algorithms which have an implementation within this library.
|
||||
func DefaultRegistry() Registry {
|
||||
return map[Discriminator]DecodeFunc{
|
||||
DiscriminatorRSA: decodeRSA,
|
||||
DiscriminatorEdDSA: decodeEd25519,
|
||||
DiscriminatorEd448: decodeEd25519,
|
||||
DiscriminatorECDSAP256: notYetImplementedVarsigDecoder,
|
||||
DiscriminatorECDSASecp256k1: notYetImplementedVarsigDecoder,
|
||||
DiscriminatorECDSAP521: notYetImplementedVarsigDecoder,
|
||||
DiscriminatorRSA: decodeRSA,
|
||||
DiscriminatorEdDSA: decodeEdDSA,
|
||||
DiscriminatorECDSA: decodeECDSA,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +94,3 @@ func (rs Registry) decodeVersAnddisc(r BytesReader) (Version, Discriminator, err
|
||||
|
||||
return Version(vers), Discriminator(disc), err
|
||||
}
|
||||
|
||||
func notYetImplementedVarsigDecoder(_ BytesReader, vers Version, disc Discriminator) (Varsig, error) {
|
||||
return nil, fmt.Errorf("%w: Version: %d, Discriminator: %x", ErrNotYetImplemented, vers, disc)
|
||||
}
|
||||
|
||||
11
rsa.go
11
rsa.go
@@ -13,13 +13,13 @@ var _ Varsig = RSAVarsig{}
|
||||
// an RSA signature.
|
||||
type RSAVarsig struct {
|
||||
varsig
|
||||
hashAlg HashAlgorithm
|
||||
hashAlg Hash
|
||||
sigLen uint64
|
||||
}
|
||||
|
||||
// NewRSAVarsig creates and validates an RSA varsig with the provided
|
||||
// hash algorithm, key length and payload encoding.
|
||||
func NewRSAVarsig(hashAlgorithm HashAlgorithm, keyLength uint64, payloadEncoding PayloadEncoding, opts ...Option) (RSAVarsig, error) {
|
||||
func NewRSAVarsig(hashAlgorithm Hash, keyLength uint64, payloadEncoding PayloadEncoding, opts ...Option) (RSAVarsig, error) {
|
||||
options := newOptions(opts...)
|
||||
|
||||
var (
|
||||
@@ -51,14 +51,15 @@ func (v RSAVarsig) Encode() []byte {
|
||||
buf := v.encode()
|
||||
buf = binary.AppendUvarint(buf, uint64(v.hashAlg))
|
||||
buf = binary.AppendUvarint(buf, v.sigLen)
|
||||
buf = binary.AppendUvarint(buf, uint64(v.payEnc))
|
||||
buf = append(buf, EncodePayloadEncoding(v.payEnc)...)
|
||||
buf = append(buf, v.Signature()...)
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
// HashAlgorithm returns the hash algorithm used to has the payload content.
|
||||
func (v RSAVarsig) HashAlgorithm() HashAlgorithm {
|
||||
// Hash returns the value describing the hash algorithm used to hash
|
||||
// the payload content before the signature is generated.
|
||||
func (v RSAVarsig) Hash() Hash {
|
||||
return v.hashAlg
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestRSAVarsig(t *testing.T) {
|
||||
|
||||
assert.Equal(t, varsig.Version1, rsaVs.Version())
|
||||
assert.Equal(t, varsig.DiscriminatorRSA, rsaVs.Discriminator())
|
||||
assert.Equal(t, varsig.HashAlgorithmSHA256, rsaVs.HashAlgorithm())
|
||||
assert.Equal(t, varsig.HashSha2_256, rsaVs.Hash())
|
||||
assert.Equal(t, varsig.PayloadEncodingDAGCBOR, rsaVs.PayloadEncoding())
|
||||
assert.Equal(t, uint64(keyLen), rsaVs.KeyLength())
|
||||
assert.Len(t, rsaVs.Signature(), 0)
|
||||
@@ -41,7 +41,7 @@ func TestRSAVarsig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rsaVarsig, err := varsig.NewRSAVarsig(
|
||||
varsig.HashAlgorithmSHA256,
|
||||
varsig.HashSha2_256,
|
||||
keyLen,
|
||||
varsig.PayloadEncodingDAGCBOR,
|
||||
)
|
||||
@@ -74,7 +74,7 @@ func TestUCANExampleV0(t *testing.T) {
|
||||
|
||||
assert.Equal(t, varsig.Version0, rsaVs.Version())
|
||||
assert.Equal(t, varsig.DiscriminatorRSA, rsaVs.Discriminator())
|
||||
assert.Equal(t, varsig.HashAlgorithmSHA256, rsaVs.HashAlgorithm())
|
||||
assert.Equal(t, varsig.HashSha2_256, rsaVs.Hash())
|
||||
assert.Equal(t, varsig.PayloadEncodingDAGCBOR, rsaVs.PayloadEncoding())
|
||||
assert.Equal(t, uint64(keyLen), rsaVs.KeyLength())
|
||||
assert.Len(t, rsaVs.Signature(), 0)
|
||||
@@ -84,7 +84,7 @@ func TestUCANExampleV0(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rsaVarsig, err := varsig.NewRSAVarsig(
|
||||
varsig.HashAlgorithmSHA256,
|
||||
varsig.HashSha2_256,
|
||||
keyLen,
|
||||
varsig.PayloadEncodingDAGCBOR,
|
||||
varsig.WithForceVersion0([]byte{}),
|
||||
|
||||
@@ -89,7 +89,10 @@ func (v varsig) Signature() []byte {
|
||||
}
|
||||
|
||||
func (v varsig) encode() []byte {
|
||||
var buf []byte
|
||||
// Pre-allocate to the maximum size to avoid re-allocating.
|
||||
// I think the maximum is 10 bytes, but it's all the same for go to allocate 16 (due to the small
|
||||
// size allocation class), so we might as well get some headroom for bigger varints.
|
||||
buf := make([]byte, 0, 16)
|
||||
|
||||
buf = binary.AppendUvarint(buf, Prefix)
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package varsig_test
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
@@ -157,28 +156,3 @@ func TestDecode(t *testing.T) {
|
||||
assert.NotNil(t, vs) // varsig is still returned with just "header"
|
||||
})
|
||||
}
|
||||
|
||||
func mustVarsig[T varsig.Varsig](t *testing.T, v T, err error) {
|
||||
t.Helper()
|
||||
|
||||
if err != nil && (v.Version() != varsig.Version0 || !errors.Is(err, varsig.ErrMissingSignature)) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func roundTrip[T varsig.Varsig](t *testing.T, in T, expEncHex string) T {
|
||||
data := in.Encode()
|
||||
assert.Equal(t, expEncHex, hex.EncodeToString(data))
|
||||
|
||||
out, err := varsig.Decode(in.Encode())
|
||||
if err != nil && (out.Version() != varsig.Version0 || !errors.Is(err, varsig.ErrMissingSignature)) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
assert.Equal(t, in.Version(), out.Version())
|
||||
assert.Equal(t, in.Discriminator(), out.Discriminator())
|
||||
assert.Equal(t, in.PayloadEncoding(), out.PayloadEncoding())
|
||||
assert.Equal(t, in.Signature(), out.Signature())
|
||||
|
||||
return out.(T)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user